Skip to content

fix(db): make schema-terminal assumptions version-agnostic - #2177

Open
ohdearquant wants to merge 4 commits into
mainfrom
fix/schema-terminal-version-agnostic
Open

fix(db): make schema-terminal assumptions version-agnostic#2177
ohdearquant wants to merge 4 commits into
mainfrom
fix/schema-terminal-version-agnostic

Conversation

@ohdearquant

Copy link
Copy Markdown
Owner

Problem

Several sites assume V21 (attachments_first_class) is the last migration in the chain. Each breaks the moment a V22 lands:

  • The blob-GC cutover fence required MAX(version) = 21 in its ledger predicate, so any later migration silently disarms the completed-cutover fast path.
  • attachment_cutover_status treated a complete marker beside a ledger above V21 as an impossible pair; only a ledger below V21 is one — later migrations record on top of a completed cutover in the normal course.
  • validate_schema_is_current ran the physical cutover-state check only when the ledger was exactly 21, so a later version would skip cutover validation entirely.
  • Test fixtures pinned terminal-version literals (21, and 22 for the ahead-of-build fixture).

Change

  • Ledger predicates become >= 21; the physical facts the reject matrix removes one at a time continue to carry the safety, and the accept-path tests running at the latest schema are the positive control for the semantics.
  • New migrations::latest_schema_version() derives the terminal version from the migration chain; terminal-version assertions and the ahead-of-build fixture use it instead of literals, so they stay correct when a migration is added.

No behavior changes at the current schema head: every predicate evaluates identically while V21 is the latest migration.

Testing

  • cargo test -p khive-db — all suites green (lib 817 passed).
  • cargo test -p kkernel — all suites green (lib 444 passed, integration suites included).
  • cargo fmt --check and cargo clippy --all-targets --all-features -p khive-db -p kkernel clean.

Several sites assume V21 is the last migration, which breaks the moment a
V22 lands:

- The blob-GC cutover fence required MAX(version) = 21 in its ledger
  predicate, so any later migration would silently disarm the completed-
  cutover fast path. Later migrations record on top of a completed cutover
  without disturbing the fencing set, so the predicate is now >= 21; the
  physical facts the reject matrix removes one at a time carry the safety.
- attachment_cutover_status treated a complete marker beside a ledger above
  V21 as an impossible pair; only a ledger BELOW V21 is one.
- validate_schema_is_current exempted the cutover-state check on any ledger
  version other than exactly 21, so a later version would skip physical
  cutover validation entirely.
- Terminal-version test assertions pinned the literal 21 (or 22 for the
  ahead-of-build fixture). They now derive from the migration chain via a
  new migrations::latest_schema_version(), so the fixtures stay correct
  when a migration is added instead of decaying into wrong claims.

No behavior changes at the current schema head; every predicate evaluates
identically while V21 is the latest migration.

@ohdearquant ohdearquant left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge by itself.

Verdict on head 3ecd3ed: REQUEST-CHANGES, 1 blocking finding. Finding details are delivered to the review's recipients rather than posted here. Do not merge this head while blocking findings are outstanding; a pipeline comment on a newer head supersedes this one.

…ob GC

The destructive blob-GC gate accepted any ledger with MAX(version) >= 21,
so an older binary could enter the deletion path against a database
migrated by a newer build — a schema epoch whose attachment/liveness
semantics the older build never validated. ADR-160 requires that epoch to
fail closed.

The ledger predicate is now MAX(version) BETWEEN 21 AND
latest_schema_version(): migrations this binary applied on top of the
completed cutover keep the gate open, while an ahead-of-binary ledger
refuses. New regression gate_rejects_ledger_ahead_of_binary_latest ADDS a
future ledger row to a passing fixture and requires refusal, with the
untouched fixture as positive control; under the old >= 21 predicate the
same fixture passes, so the test is pinned to the fix.

Also renames rejects_pre_consolidation_ledger to
rejects_ledger_ahead_of_binary_latest — the fixture is computed from the
live chain and exercises any ahead ledger, not the historical
pre-consolidation shape its old name described.

@ohdearquant ohdearquant left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge by itself.

Verdict on head 94ea178: REQUEST-CHANGES, 1 blocking finding. Finding details are delivered to the review's recipients rather than posted here. Do not merge this head while blocking findings are outstanding; a pipeline comment on a newer head supersedes this one.

ADR-160 scopes Phase-4a sweep admission to an exact completed V21 epoch:
any ledger above V21 — ahead of this binary or applied by it — belongs
to a schema epoch whose attachment/liveness semantics the gate never
validated, and fails closed with the existing typed refusal. A future
migration's author extends the gate in the change that proves the new
epoch's liveness set, never by default. General schema validation keeps
accepting later versions on top of a completed cutover; the exact-epoch
rule binds destructive GC admission only.

Also folds the two remaining independent terminal-version derivations
onto latest_schema_version().

@ohdearquant ohdearquant left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge by itself.

Verdict on head 389435c: REQUEST-CHANGES, 1 blocking finding. Finding details are delivered to the review's recipients rather than posted here. Do not merge this head while blocking findings are outstanding; a pipeline comment on a newer head supersedes this one.

… gate

The completed-V21 predicate checked only for the named V21 row and
MAX(version) = 21, so a ledger with its below-V21 rows deleted — an
incomplete migration history whose physical schema the gate never
validated — still opened destructive GC. The predicate now also requires
COUNT(*) = 21 and MIN(version) = 1: with version as the table's PRIMARY
KEY those three facts hold iff the ledger is exactly the contiguous set
{1..21}. Name-level canonicality of below-terminal rows remains boot's
job (validate_applied_migration_ledger); the gate enforces the
structural contiguity destructive admission rests on.

Tests: a dedicated regression deletes every row below V21 while
asserting the named V21 row and MAX(version) = 21 survive, so its
rejection can only come from the contiguity clause (removing the clause
turns it and the new acceptance-matrix case red — verified by temporary
mutation, then restored by snapshot). The acceptance matrix gains the
below-V21-deletion case, its stale BETWEEN-based comment now describes
the shipped predicate, the shared V21 fixture asserts the pinned V21
epoch instead of the moving latest version (a future migration fails
loudly at the fixture instead of silently invalidating GC tests), and
the ahead-of-V21 fixture row now matches the shape run_migrations
records.

@ohdearquant ohdearquant left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review. Posted by this repository's automated pull-request review pipeline; this is not a human read and does not gate the merge.

Verdict on current head: APPROVE, zero blocking findings. This is a comment, not an approval — a human reviewer decides whether to approve and merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant