Repository navigation
fix(driver-sql): the boot drift line for an organization_id drop names the ownership ceremony on an uncertified database - #25188
Conversation
…s the ceremony on an uncertified database On a database the driver's reader (isTenantKeyCertified) answers not certified, the boot's [schema-drift] line for an orphaned organization_id column no longer prescribes 'os migrate apply --allow-destructive', which the drop gate refuses there; it names 'os migrate organization-ownership'. A certified database, every other column and every other drift kind print the differ's message unchanged. Claude-Session: https://claude.ai/code/session_01NQBsTsRUMvji8sjVyHJkvY Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NQBsTsRUMvji8sjVyHJkvY Co-authored-by: Claude <noreply@anthropic.com>
…ot-drift-line-names-ceremony
📓 Docs Drift Check5 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 6a5ad5e46cb82d847f2d943705b34defbc5d2637 && git checkout 6a5ad5e46cb82d847f2d943705b34defbc5d2637
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f7d740376d3953c7b4a7d22c77e0f689c77a228a 970f966b9fc2d49f623ec2ab511ac62012bd458b && git checkout -B drift-repro f7d740376d3953c7b4a7d22c77e0f689c77a228a && git merge --no-ff 970f966b9fc2d49f623ec2ab511ac62012bd458b
node scripts/docs-audit/affected-docs.mjs --json f7d740376d3953c7b4a7d22c77e0f689c77a228a |
Contract reviewServed-tier: Scope: the net diff against the merge base (4 files, +163/−0):
Read with them:
① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 ·
|
| Item | Reading |
|---|---|
| Shape | Draft PR → main. The body opens Fixes #24956. 4 files, +163/−0. Not governed: check-governed-merges matched 0 of 4 paths. |
| Scope | On a database SqlDriver.isTenantKeyCertified() answers "not certified", the boot's [schema-drift] line for an orphaned organization_id drop keeps its finding. It replaces — "os migrate apply --allow-destructive" to drop it. with the ceremony, in os migrate plan's entry wording. A certified database, every other column and every other drift kind print as before; nothing the boot applies or skips changes. |
| Seat's own read | The one source is the driver's reader from PR #24893, asked once per table and only for such a drop; there is no copy of the CLI gate. The 18.0-born, certified case still prints --allow-destructive, and stays #24638's (domain:cli). |
| Review | TIER_DEFAULT. Record 6336375080 is PASS on this head. |
| Declaration | One changeset, @objectstack/driver-sql patch, with Clause-②: no (operator log line text only) and Metadata-protocol: none at line starts, as on the PR body. |
| Cross-lane | None. The CLI's drop gate and apply-drop-gates.ts are read, not edited. @objectstack/cli passed its unit layer (4769 tests) and its integration layer (1447 tests). |
| Docs drift | The bot listed nothing: no hand-written page names the five anchors. The dev found no content/docs/** page that quotes the boot line; deployment/cli.mdx's drift table stays true. |
| Gates | Measured on a real create-objectstack@17.7.0 SQLite database. Before: 9 of 28 drift lines name --allow-destructive for organization_id, at both os serve and apply --yes. After: those 9 name the ceremony, and the other 19 diff empty against main. Dev at 970f966b9: 70 derived, 70 run, all exit 0. driver-sql passed 3748 tests, and the new pins 6/6. Ablation (the guard disabled): 2 red, 4 green, restored to HEAD. |
| CI | At this read on 970f966b9f: ci-failure GREEN, all 41 check-runs completed, none failed. git merge-tree against today's origin/main (14e7239e73) is clean. |
Disposition:
open_questions: both answered A by the seat:- the line names the ceremony, rather than printing no remedy;
- the column name is a local constant, since
driver-sqlcannot import the CLI's.
deviations: all accepted:- the moved base;
- 28 lines rather than the card's 22, with all 9 covered;
- the measurement setup;
- the extra CLI integration run;
- the AGENTS.md commit trailers.
out_of_scope_findings: orphanedorganization_idindex drops (drop_index) still name--allow-destructiveon a pre-ceremony database. The CLI gate judgesdrop_columnonly, and a run that carries those index drops on such a database carries the refused column drops too. Noted in the PR, not filed.
Landing: ordinary queue (pr_ready + automerge_enable through the relay). Fixes #24956 then closes the card.
Generated by Claude Code
Fixes #24956
Clause-②: no (operator log line text only)
Metadata-protocol: none
What changes
SqlDriver's boot reconcile (reconcileAndWarnDrift) logs each drift entry as[schema-drift] MESSAGE. When an entry is anorganization_iddrop_column, it now asks the driver's own reader,isTenantKeyCertified(), once per table and only when such a line is about to print. The reader goes through the engine-handed resolver overisOrganizationOwnershipCertified(): a birth marker, or a ceremony marker of the current shape generation. No second list is involved.driftFindingWithoutRemedy). It replaces the--allow-destructivesentence with PR fix(cli): os migrate plan names the ownership ceremony, not --allow-destructive, for the organization_id drops apply refuses #24954's vocabulary for the same entry:— a drop the organization-ownership ceremony owns, and it has not verified on this database: run "os migrate organization-ownership", which drops it itself.driftWarnedde-duplication, and the drop gate (packages/cli).Files:
packages/drivers/driver-sql/src/schema-drift.tsaddsisCeremonyOwnedColumnDropandceremonyOwnedDropFinding. They are module exports only and are not added to the package'sindex.ts, so the public surface does not change.sql-driver.tsadds the branch. There is one new test file and apatchchangeset.Measured: a real
create-objectstack@17.7.0SQLite database,OS_AUTH_SECRETsetThe fixture was scaffolded with
npx create-objectstack@17.7.0; it ran on@objectstack/*@17.7.0and booted once withobjectstack dev -d file:./v17.db. It carries 43 tables with anorganization_idcolumn. Each door ran on a fresh copy, through this tree's CLI (packages/cli/bin/run.js) and a copy of the scaffold's app withengines.protocolset to^18.main82cfaf792bdd1ac563os serve[schema-drift]lines, 9organization_iddrop lines naming--allow-destructive--allow-destructivefororganization_id, 9 namingos migrate organization-ownershipos migrate apply --yesos migrate plan[schema-drift]lines (its own renderer already names the ceremony, PR #24954)os migrate apply --yes --allow-destructive(main)sys_job.organization_idstill presentThe 9 tables are
sys_metadata,sys_metadata_history,sys_metadata_commit,sys_migration,sys_migration_journal,sys_secret,sys_flow_credential,sys_jobandsys_job_queue. The card counted 22 lines at003e41ab5; today'smainprints 28. On bothserveandapply --yes, the 19 other drift lines are identical betweenmainand this branch (diffempty).Certified control. A fresh database from this branch (birth marker
adr-0131-organization-ownershipverified), plus a hand-addedsys_user.organization_idcolumn. Its boot prints[schema-drift] sys_user.organization_id: column exists in the database but not in metadata (orphaned) — "os migrate apply --allow-destructive" to drop it., unchanged. The resolver answers "certified" at boot time.The fork the dispatch named did not occur. The driver's reader answers "not certified" for this card's population. That is the same reading the boot's
recreate_indexlines already print ("This database is not certified for the organization-ownership shape").Pins and ablation
packages/drivers/driver-sql/src/sql-driver.ceremony-owned-drop-line.test.tsruns on real SQLite throughinitObjects, with a 17.x-shaped table:organization_idline names"os migrate organization-ownership"and never--allow-destructive; the reader is asked once;legacy_codedrop is unchanged (exact);tighten_not_nullis unchanged (exact);organization_iddrop never asks the reader.Ablation (
scripts/ablation-replace.mjs): the guard was prefixed withfalse &&, so the anchor went from 1 hit to 0 and the blob from24448296bf26tocb74d2820589. Pins 1 and 2 went red; pins 3 to 6 stayed green (2 failed, 4 passed). After restore the blob equals HEAD (24448296bf26) andgit diff HEADis empty. The test imports./sql-driver.jsfromsrc, so nodistpreflight applies.Verification
pnpm --filter @objectstack/driver-sql typecheck: exit 0. The new test file is in the program (--listFilescount 1).pnpm --filter @objectstack/driver-sql test: exit 0,Test Files 231 passed | 12 skipped (243),Tests 3748 passed | 212 skipped (3960). This is on the merged head970f966b9, and again before the merge. It ran SQLite only; live PG and MySQL are left to CI.pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2: exit 0,323 passed (323)files,4769 passedtests (atbdd1ac563).pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2: exit 0,166 passed | 1 skipped (167)files,1447 passed | 9 skippedtests (atbdd1ac563). It ran locally because the diff touches the driver boot path.origin/main(6251f5905):pnpm exec turbo run build --concurrency=2exit 0 (77/77 tasks), then typecheck and the driver-sql suite as above.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat970f966b9derived 70 commands, and all 70 exit 0. The first run, atbdd1ac563, hadcheck:dual-build-cjs-loadsexit 3 (PREREQUISITE NOT MET, unbuilt packages); it exited 0 after the full build.--ran:70 derived famil(ies) accounted for — 70 run, 0 NOT-MEASURED (a DERIVED zero).Acceptance notes
content/docs/**quotes the boot line. Thedestructiverow ofdeployment/cli.mdx's drift table and its--allow-destructiverefusals list stay true, so I found no page this change falsifies.organization_idis spelled once inschema-drift.ts(CEREMONY_OWNED_DROP_COLUMN). That matches the CLI gate'sORGANIZATION_COLUMN. It names the ceremony's column, not a list of tables. The decision to hold comes fromisTenantKeyCertified()alone.isTenantKeyCertified()logs its existing one-time warning. That warning's wording is about index comparison. A database whose ledger read fails, and which has anorganization_iddrop, would now see it printed. Before, it printed only with a COALESCE-keyed index.organization_id(for exampleidx_sys_metadata_org_type, adrop_index) still name--allow-destructiveon this database, at boot and inos migrate plan. The CLI gate judgesdrop_columnonly, so those lines are not the ceremony's under today's gate. They are out of this card's scope and noted only.systemFields: { tenant: false }has no way on in 18.0 — the drift report prescribes--allow-destructive, the drop gate refuses it, and the ceremony is refused #24638'stenant: falsecase) are certified by their birth marker, and their line is unchanged. [Decision] An 18.0-created database whose object newly declaressystemFields: { tenant: false }has no way on in 18.0 — the drift report prescribes--allow-destructive, the drop gate refuses it, and the ceremony is refused #24638 is not addressed here.🤖 Generated with Claude Code
https://claude.ai/code/session_01NQBsTsRUMvji8sjVyHJkvY
Generated by Claude Code