Module schema_envelope
Expand description
The replicated-SQL schema envelope: what SQLite objects the public surface accepts, how a
table is introspected into ReplicatedTableSchema, and how a DDL/migration batch is applied
under the registered-table guard with an audit trail.
Split out of rindle-replica’s schema.rs, which mixed this with the engine-facing
TableSchema/discover pair. Only that pair needs rindle_sqlite::ColumnDef; everything here
is rusqlite + rindle’s value types, so it belongs on the write-plane side of the split —
the write-master validates and applies schema without running an engine.
See follow-ups/replica-writeplane-extraction.md, step 5.
Structs§
- DdlAction
Recorder - Observe-mode twin of
RegisteredTableDdlGuard(private to this module) — the same authorizer, the opposite verdict. The follower MUST apply destructive DDL (its statements are the write-master’s, already committed upstream), so nothing is denied: the destructive operations are RECORDED for the post-apply bounce/purge decisions instead of being refused. One authorizer per connection: install only on paths that do not install the deny guard (protect_registered_tables = false—Cluster::exec_ddl_with_marker, inrindle-replica, is the consumer). - DdlActions
- The destructive DDL actions observed so far (design 227, third review pass): which
main-schema tables were DROPPED or ALTERED, reported by SQLite’s authorizer as each statement was prepared. This is the real parser’s verdict, so comments between tokens, script-valued slots, quoting, and schema-qualified names are all handled by construction — the lexical scanners this replaced were evadable by each in turn. - DdlApply
Report - The full, ordered apply report of one
ddlentry. Persisted — as JSON, in the same transaction as the entry’s idempotency marker — so a replay (an in-connection retry after a later step failed, or a crash before cursor advancement) re-drives bounce decisions from durable truth instead of observing nothing. Desired-index effects normally commit in this same transaction; old reports are retained for conservative compatibility repair. - DdlStep
- One executed statement of a
ddlentry plus the destructive actions the authorizer attributed to it. Order is the EXECUTION order — load-bearing for the desired-index bookkeeping (design 227 fourth review pass): inDROP TABLE t; CREATE TABLE t; CREATE INDEX ix ON tthe index belongs to the final table, so its recording must follow the drop’s purge, not race it.
Functions§
- ensure_
embedded_ ddl_ batch - Preflight one trusted embedded schema batch before it touches SQLite.
exec_ddlhistorically accepts multiple DDL statements and boundedANALYZE, but it must not double as an unobserved DML escape hatch. Classification happens for the complete batch before the transaction begins, so a lateINSERTcannot leave an earlierCREATEcommitted. - introspect_
replicated_ table - Introspect and validate one persistent application table.
- introspect_
schema_ envelope - Introspect every public application table and validate the complete replicated SQL schema envelope. Internal bookkeeping objects remain excluded.
- transactionally_
apply_ schema - Run an already-preflighted schema operation and prove its post-state before commit.
- transactionally_
apply_ schema_ checked transactionally_apply_schemawith one caller-owned validation hook after the complete schema envelope has been introspected but before COMMIT. The generic error keeps a host’s typed policy failures intact while every connection/capture/schema failure still enters throughReplicaError.- validate_
default_ expression - Prove that a column default cannot manufacture a BLOB on a later evaluation.
- validate_
schema_ envelope - Validate the complete replicated SQL schema envelope without retaining its introspection result.
- value_
type_ of - Map a declared SQLite column type to the engine’s [
ValueType], following SQLite type-affinity rules (with BOOLEAN/JSON special-cased, and the exactBIGINT/INT8declarations mapped to the exact-i64 plane — design 226 §4.1). ReturnsNonefor BLOB and untyped columns — the engine’sOwnedValuehas noBlobvariant, so we reject rather than silently null them.