Repository navigation
fix(metadata-core, metadata-protocol): two refusals say what 18.0 supports, not the ownership command 18.0 refuses - #24726
Conversation
…ports, not the ownership command 18.0 refuses LEGACY_ORGANIZATION_ROWS_UNREADABLE and the seed refusal for a natural key held by a row with no organization no longer prescribe `os migrate organization-ownership`. Each closes on the release sentence the CLI, the boot refusal and the upgrade entries carry. The legacy read's text also says that a fresh 18.0 install meets it only through the cause named in the detail. Codes and outcomes are unchanged. Claude-Session: https://claude.ai/code/session_01KQiKEtTxcLqE3TeLATbWFb Co-authored-by: Claude <noreply@anthropic.com>
…nership-refusal-text
📓 Docs Drift Check1 anchor(s) derived from 2 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 — 13 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 13d75ccd0c559e20b6348147a08cb23aee71ae86 && git checkout 13d75ccd0c559e20b6348147a08cb23aee71ae86
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d20bf9b09b8084c64e021e9ba8d77c03fe6195e0 396fcb9c00f498023a424c0918fc783c2127dc1b && git checkout -B drift-repro d20bf9b09b8084c64e021e9ba8d77c03fe6195e0 && git merge --no-ff 396fcb9c00f498023a424c0918fc783c2127dc1b
node scripts/docs-audit/affected-docs.mjs --json d20bf9b09b8084c64e021e9ba8d77c03fe6195e0 |
Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 ·
|
| Item | Reading |
|---|---|
| Shape | Draft PR → main. The body opens Fixes #24710. 6 files, +57/−6. Not governed: check-governed-merges matched 0 of 6 paths. |
| Scope | Two refusals stop naming os migrate organization-ownership and close on #24635's release sentence. LEGACY_ORGANIZATION_ROWS_UNREADABLE: one sentence true for both readers. Most of its throws are the driver's and reach a fresh 18.0 install too, so the text names the driver or the caller as the fix there, and says a database holding legacy rows is a v17 one. The seed's unowned-holder refusal: a row with no organization predates organization stamping, so it is a v17 database's. Codes, outcomes and every other sentence stay. |
| Seat's own read | The throws of readLegacyOrganizationRows were walked in code: only the legacy select's SEAM_NO_ANSWER_DETAIL needs the column on disk. The command's remaining mentions in both packages are descriptive comments, not remedies. The PR reads mergeable: clean. |
| Review | TIER_DEFAULT, in-seat. Record 6282345201 is PASS on this head. |
| Declaration | One changeset, patch for @objectstack/metadata-core and @objectstack/metadata-protocol, Clause-②: no (text only: …) at a line start, as on the claim and the PR body. No export, public member, error code or constructor parameter. |
| Cross-lane | domain:cli, for packages/runtime's integration test, which held the only existing pin of the old text: 6282356777 (#6024) and 6282360869 (#22648). No objection on the card or the seat posts. |
| Gates | Dev at 396fcb9c0: 65 derived, 65 run, all exit 0 (check:dual-build-cjs-loads built for and re-run). Full suites: metadata-core 776 passed, metadata-protocol 20802 passed, the runtime integration 6/6, core test:repo 82 passed. Ablation: 5 pins red, restored to HEAD. |
| CI | At this read on 396fcb9c00: ci-failure GREEN, all 40 check-runs completed, none failed. |
Disposition:
open_questions: both taken as the dev settled them, per record 6282345201 ③: one closed sentence for the legacy-row refusal (no branch ondetail); the v17 sentence for the seed refusal.deviations: all three accepted (record ③). Theruntimetest was owed: without itmainwould turn red.out_of_scope_findings: the embedder-only shape (a scopedSeedLoaderService.loadon a composition with no organization object) has no in-tree producer and meets no filing gate. It is recorded in the PR's Acceptance notes.
Order note: when PR #24681 (#24581, 18.x steps 5–6) lands and reopens the ceremony, it restates these two texts with the surfaces #24635 taught, as the card says.
Landing: ordinary queue (pr_ready + automerge_enable through the relay). Fixes #24710 then closes the card.
Generated by Claude Code
Fixes #24710
Clause-②: no (text only: no refusal code, outcome, accept set or served shape moves)
What changed
In 18.0,
os migrate organization-ownershiprefuses plan and apply on every database. Two refusals still told the operator to run it. Each now closes on PR #24635's release sentence: "18.0 supports fresh installs only and does not upgrade a v17 database: keep a v17 database on a 17.x release until the 18.x release that carries the upgrade path." The text is only made true for the readers who can actually meet each refusal on 18.0 (below).LEGACY_ORGANIZATION_ROWS_UNREADABLE(packages/metadata-core/src/legacy-organization-row.ts)os migrate organization-ownershipon this database first."packages/metadata-protocol/src/seed-loader.ts)os migrate organization-ownership, then the same command with --apply), then re-run this seed: the row is this organization's own by then, and the upsert matches it."Unchanged: both codes, "Nothing was listed or written.", the seed refusal's opening sentences (what was refused, and why), its
erroredcount, and the dropped record. There is no new export, error code or constructor parameter.Who meets each refusal on 18.0 (read before the edit)
readLegacyOrganizationRows. It throws in seven places. Each is listed with whether a fresh 18.0 install reaches it.detail)organization_idThe callers reach it on a fresh install.
protocol.ts'sfindEnvironmentRows/findEnvironmentRowrun it on every family read. Hydration inObjectQLPlugin.start()asks it even when no row came back ("Asked even when no row came back"), soos servemeets it on every SQL boot.sys-metadata-repository.tslegacyOrganizationRowIdsruns it on every addressed write.cli'ssecurity-catalog-overlays.tsruns it on theos migratestep. The old remedy was already wrong for the five driver-shaped throws: the ceremony itself refuses an unresolved dialect (dialectOfDriver's doc). So the new text does not tell a fresh-install operator to hold a v17 database on 17.x. It says a fresh install has no legacy rows, so there the named cause is the fix, and it gives the release sentence to the database that does hold them. This is one message for both readers, and the constructor is unchanged. Following the detail per throw would need a new parameter: the sharedSEAM_NO_ANSWER_DETAILis passed by both a driver-shaped throw and the database-shaped one.The seed refusal. It fires only on an organization-scoped
upsert/ignoreload (config.organizationId) whose natural key is held by anorganization_id IS NULLrow. Under ADR-0131 D9, asEngine.resolveSystemInsertOrganizationimplements it on 18.0, a system insert on a tenant-column object is stamped with the Default Organization undersingle, or refused. 18.0 refuses a walled posture on the operator's boot path. The single-posture inline seed is a system insert, so it is stamped too. The one 18.0 shape that leavesorganization_idNULL is theno-organization-objectcomposition, which registers nosys_organization. That composition has no organization insert, so no per-organization replay runs. The marketplace scoped install and the reseed pass an organization only when walled. So no in-tree producer runs a scoped load there. The reader who meets this refusal holds rows that predate stamping: a v17 database.seed-loader-null-organization-holder-real-driver.integration.test.tsmeasures the same population: "a single-posture 17.x install, every business roworganization_idNULL". The release sentence is true for that reader. The old remedy's bare--applywas refused even before 18.0.Comments beside the two texts only describe the ceremony (the module header,
dialectOfDriver's doc, the#24301note inseed-loader.ts). None of them prescribes it as an 18.0 remedy, so none moved.Pins
packages/metadata-core/src/legacy-organization-row.test.ts: a newit.eachin "fails closed" covers a driver-shaped throw (no raw seam) and the database-shaped one (column on disk, legacy select answered nothing). It assertscode === 'LEGACY_ORGANIZATION_ROWS_UNREADABLE', "Nothing was listed or written.", the fresh-install sentence, the message ending on the release sentence, andos migrate organization-ownershipabsent.packages/metadata-protocol/src/seed-loader-null-organization-holder.test.ts: the existing upsert/ignore refusal test, which already assertstotalErrored === 1and the dropped record. It now also asserts that the opening sentences stay, that the message ends on the new remedy, and thatos migrate organization-ownershipand--applyare absent.packages/runtime/src/seed-loader-null-organization-holder-real-driver.integration.test.tsassertedtoContain('os migrate organization-ownership'). It now asserts the release sentence and the command's absence. Without that change,mainwould go red.Pin sweep (
LEGACY_ORGANIZATION_ROWS_UNREADABLE, "on this database first", "Attribute the unowned rows first", "then the same command with --apply", plus the messages' other sentences) overpackages,qa,docs/qa/platform-checklistandcontent/docs. It found the runtime pin above and no other pin of either text.protocol.stored-migration.test.ts's/legacy organization rows/reads the unchanged first sentence. The hits in the generatedcontent/docs/references/api/*.mdxledgers and in releasedCHANGELOG.mdentries name only the code and do not move.Verification
@objectstack/runtime^...closure plus@objectstack/metadata-protocol, VERDICT command-exit 0. After mergingorigin/main(54159fd74, which brought PR fix(metadata-protocol): a seed replay no longer rewrites every seeded row that carries a password or secret field on every boot #24696'sseed-loader.tschange; the merge was clean), fullpnpm build --concurrency=2ran: 76/76 tasks, VERDICT command-exit 0.@objectstack/metadata-coreexit 0,@objectstack/metadata-protocolexit 0.@objectstack/metadata-core18 files / 776 tests passed.@objectstack/metadata-protocol250 files passed, 3 skipped / 20802 tests passed, 19 skipped.seed-loader-null-organization-holder-real-driver.integration.test.ts(@objectstack/runtime): 6/6 passed.pnpm --filter @objectstack/core test:repo: 6 files / 82 tests passed.@objectstack/cli: no existing pin reads either text, and none was added, so its suite is not owed.scripts/ablation-replace.mjs --hold, both texts were reverted to themainspelling. The on-disk counts moved (old1=1 new1=0, old2=1 new2=0). Both packages were rebuilt, andablation-dist-preflightfound the old markers indist/. The legacy-row pin went red (2 failed), the seed pin went red (2 failed), and the runtime pin went red (1 failed). Restored withgit checkout HEAD --:git diff HEADwas empty andgit status --porcelainwas clean. Blobs equalHEAD(e19b19399a05/67a3560d3c2c). Rebuilt,--absentpreflight passed for both packages, and the runtime pin was green again.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, run on the final head396fcb9c0): every one of the 65 derived lines exited 0.check:dual-build-cjs-loadsfirst exited 3 (PREREQUISITE NOT MET, nodist/) on the pre-merge head. It was built for and re-run, and exited 0.--ranwithCOMMAND :: exit CODErecords reported: "65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero).check-nul-bytesexited 0.Acceptance notes
no-organization-objectcomposition, and no in-tree caller runs a scoped load there. An embedder that callsSeedLoaderService.loadwith anorganizationIdagainst such a composition would read the v17 sentence for a row its own composition wrote. That reader is speculative (no producer), so it is not filed.Generated by Claude Code