Skip to content

fix(metadata-protocol,metadata): the legacy-organization read seam's loose ends: paged reads, the loader's count, the rollback's named refusal (ADR-0131 D6/D7) - #23778

Merged
objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-23609-legacy-org-read-seam
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 8 commits into
mainfrom
claude/issue-23609-legacy-org-read-seam

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #23609

Clause-②: no

Six of the card's seven items are closed here, one commit each, measured on main first. Item 2 is measured but stopped: its fix needs files outside the claimed surface (below). Every path matters only on an unmigrated (v17-shape) database, which os serve refuses to boot until os migrate organization-ownership has verified. Each fix acts only where legacy organization rows are present, and each pin runs beside a migrated CONTROL whose answer does not change.

The items come from the PASS record on PR #23469 (#23429, C7b S2 + S5); neither is closed by this PR.

Items

  1. Done here (0546039d). findServedOverlayRow's legacy filter gets its own pin: the _lock case in meta-stored-legacy-organization.integration.test.ts now asserts that the served item is not the organization's body.
    • H1 held on main 2906cd8. With only that filter removed (the raw findOne, rebuilt, marker verified in dist/), the file stayed 7/7 green.
    • With the pin, the same ablation turns only the new assertion red (expected 'Org A locked' not to be 'Org A locked', 1 failed / 6 passed).
  2. Measured, NOT done: stopped at the claim's file surface. H2 holds.
    • On a v17-shape SQLite file, protocol.publishPackageDrafts for a package with one draft had not answered after a 25 s bound.
    • CONTROL: the same file with the column dropped published in 97 ms (outcome: published).
    • ObjectQL exposes no ambient-transaction accessor to a raw read. txStore and privilegedReadDriverOptions are private, and engine.execute does not thread the ambient handle.
    • So the narrow route (take the ambient transaction inside legacyOrganizationRowsOf) needs a public ObjectQL accessor in packages/objectql, outside the claim.
    • Threading trxCtx instead goes through promoteDraftForPublish, its lock read and the repository's get / promoteDraft draft reads. repo.get alone keeps the hang, because the repository's own legacy read has the same gap. Those are outside the claimed surface, and next to the promote door's D9.9 call.
    • The route and its trade-offs are in the report's open_questions.
    • Seat ruling 6206299338: C. Left latent. The seam is transitional code for a database os serve refuses, and no caller reaches the path. A future reader of the family inside an ambient transaction off the served boot carries the fix (route A) in its own card. So this PR closes the card. (Body edit by the domain:engine seat, 2026-10-16T01:58Z.)
  3. Done here (a6f23cd9). A paged family read leaves the legacy rows out before the page is cut. This covers auditMetaItem, listCommits, revertStoredPackage's limit: 1 probe (it answered 409 "never been published") and the repository's list({ limit }).
    • When the page holds a legacy row, or an offset could have counted one, the read is repeated with id $nin of them in the query. Otherwise the single read is the answer, unchanged.
    • Ablations: (a) send every paged read down the old post-filter path, and the 4 v17-shape protocol cases go red (audit, commits, revert, offset); (b) the repository's list, and its 1 v17-shape case goes red. The control cases stay green in both.
  4. Done here (7a52179d). DatabaseLoader._count counts what _find serves. Before, exists() answered true where load() answered null, and queryHistory's total counted legacy rows.
    • It counts first. Only a non-zero count over a table holding legacy rows is re-counted with them excluded, so the unprovisioned-table discrimination in exists() is untouched.
    • Ablation: both v17-shape cases red, controls green.
  5. Done here (c39c8c8e). rollbackToPackageCommit answers a legacy commit with revertCommit's named refusal (NOT_OVERRIDABLE, 403, the same sentence) instead of COMMIT_NOT_FOUND (404).
    • Both doors read the commit through one helper, readRevertableCommit. revertCommit's behaviour is unchanged: the same read, refusal and text, moved.
    • Ablation: put the rollback's read back through findEnvironmentRow with its old 404, and only the v17-shape "one answer from both doors" case goes red.
  6. Done here (8052436a). The inert plumbing is removed: mergePackageAwareOverlay's rowsRead, ServedOverlayRowCandidate.scope / organizationId, StoredRowPlace.organizationId, and the always-null orgId / itemOrgId locals.
    • Correction to the card: rowsRead was a presence flag, not dead. It is dropped because every caller that passed it also sends each record's stored place, and every caller that omitted it sends none. servedStoredRow returns undefined over records with no place, so the merge's answer is identical.
    • Proof: the full @objectstack/metadata-protocol suite gives 237 files passed / 3 skipped, 20593 tests passed / 19 skipped, both with this commit and with protocol.ts restored to its parent (blob ea9fa58d).
    • Left in place: StoredOverlayEntry.organizationId and the organizationId parameters of restoreArtifactRegistryView / hydrateOverlayIntoRegistry. They are the An org-scoped metadata DELETE evicts the ENV-WIDE registry entry for every org — restoreArtifactRegistryView is (type, name)-addressed and org-blind #6780 registry-scope API and outside the card's list.
  7. Done here (6bdaa0e0; changeset 042ba4c5). Prose only.
    • The four 18.sys-metadata{,-audit,-commit,-history}-organization-column-retired entries and metadata-lifecycle.mdx name the ceremony's reviewed apply: --out PLAN, then --apply --plan-file PLAN.
    • os migrate apply's E1 sentence now reads "a drop the organization-ownership ceremony owns, and the ceremony has not verified on this database". Its --json payload is unchanged.
    • No entry id, category, version or engine-read field changes. pnpm --filter @objectstack/spec check:generated reports all 14 artifacts up to date, so nothing checked in derives from the entries' prose.

Verification (head 81aa285d)

  • @objectstack/metadata-protocol: full suite 237 files passed / 3 skipped, 20593 tests passed / 19 skipped; typecheck exit 0. The new file protocol.legacy-organization-read-seam.test.ts passes 16/16.
  • @objectstack/metadata: full suite 63 files, 892/892 passed; typecheck exit 0. The new file database-loader.legacy-organization-count.test.ts passes 4/4.
  • @objectstack/cli:
    • --project unit: 297 files, 4377/4377 passed;
    • --project integration: meta-stored-legacy-organization 7/7, and apply-organization-ownership-gate + organization-ownership-platform-global-column-drop 11/11 (on a rebuilt dist/);
    • typecheck exit 0.
  • @objectstack/spec: build + check:generated exit 0 (14/14 up to date); typecheck exit 0.
  • Derived gates (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths, after the last commit): 123 derived; --ran gives 119 run, 4 NOT MEASURED, 0 unrun (exit 0).
    • The first run went over the tree at 042ba4c5. It found one real failure, check:engine-double-contract: the loader pin's fake findOne skipped assertEngineFindOnePredicate, and the ledger lacked the new doubles. 81aa285d fixes both.
    • At 81aa285d, every family reading the two files that commit changed was re-run, plus the 8 the new scripts/ path adds: 13/13 exit 0.
    • NOT MEASURED (each exited 3, PREREQUISITE NOT MET, on packages this diff does not touch; CI runs them): check-plugin-teardown-shape --self-test (needs unshallow history), spec check:skill-examples (client-react unbuilt), check:dual-build-cjs-loads (whole-workspace build) and check:i18n-coverage (connector-slack unbuilt).
  • Every ablation ran through scripts/ablation-replace.mjs: anchor hit, blob moved, restore proved blob == HEAD and git diff HEAD empty. The CLI ablation (item 1) also passed ablation-dist-preflight on both legs.

Acceptance notes

  • DatabaseLoader.queryHistory's page read (_find with limit + offset) still filters after the cut, the item 3 shape on the loader. It is not in the claimed surface (_count only), and it is latent like every item here. Carrier: none.
  • listCommits passes limit with no orderBy and sorts afterwards, so its limit picks store-order rows, not the newest. This predates the card and is unrelated to the legacy filter.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg


Generated by Claude Code

…ts own

The _lock case asserted only lock and editable, which overlayLockLayerAt
selects apart from the content; with findServedOverlayRow's filter alone
removed, getMetaItem served the organization's body and every case stayed
green. It now asserts the served item is not the organization's body.

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
…n rows out before the page is cut

auditMetaItem, listCommits, revertStoredPackage's limit: 1 probe and the
repository's list({ limit }) filtered the legacy organization rows after
limit, so a page they sat in came back short, and the probe answered 409
"never been published" when its one row was an organization's. When a paged
read's page holds a legacy row (or an offset could have counted one), it is
re-read with them excluded in the query itself. A migrated or fresh store
holds none, and its single read is unchanged (ADR-0131 D6/D7).

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
…out, as its reads do

exists() answered true for an address only a legacy organization row held
while load() answered null, and queryHistory's total counted rows no page
serves. The count is re-taken with the legacy rows excluded in the query only
when it is not zero and the table holds any; a migrated store's count is
unchanged (ADR-0131 D6/D7).

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
…nization commit by name

It read the commit through the environment-only seam, which leaves a legacy
organization's commit out, and answered COMMIT_NOT_FOUND (404) for a commit
that is there. revertCommit and rollbackToPackageCommit now read the commit
through one helper, readRevertableCommit, so a legacy commit gets the same
NOT_OVERRIDABLE refusal from both doors. A migrated store holds no legacy
commit and answers as before (ADR-0131 D6/D7).

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
…ng every row has outgrown

Every row that reaches these is the environment's since the family reads
leave a legacy organization's rows out (ADR-0131 D6/D7), so they carried
nothing: mergePackageAwareOverlay's rowsRead flag (the records' own stored
place already says it), ServedOverlayRowCandidate.scope / organizationId,
StoredRowPlace.organizationId, and the always-null orgId / itemOrgId locals
in applyRemoteMetadataMutation, revertCommit, rollbackMetaItem and
deleteMetaItem. Behaviour-neutral.

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
…lan-file; E1's refusal reads straight

The four sys_metadata-family ADR-0087 entries and metadata-lifecycle.mdx
named os migrate organization-ownership --apply without --plan-file, which
the ceremony requires (18.cli-organization-ownership-apply-plan-file-required).
They now name the plan run and the reviewed apply. os migrate apply's E1
refusal sentence ("which the organization-ownership ceremony owns that
drop") is made grammatical. Prose only: no entry id, category, version or
field the migration engine reads changes.

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
… hold ObjectQL's findOne contract and are pinned

The DatabaseLoader count pin's engine double opens findOne with
assertEngineFindOnePredicate, and the engine-double ledger records the
doubles both new pin files declare (check:engine-double-contract --write).

Claude-Session: https://claude.ai/code/session_01TekAoE8QbLrxFVJsdNuRgg
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/cli, @objectstack/metadata-protocol, @objectstack/metadata, @objectstack/spec, touching 23 documentable anchor(s).

24 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 4fe8b3def02ff9803a52c2fb8b97778d5bf45597.

⛔ 8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 150 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 4fe8b3def02ff9803a52c2fb8b97778d5bf45597 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 2b2e1def086b0ec6f67b96f198282ff2434f0656 — the merge of head 81aa285d588f9eb7e7a42209bb19c34a3d2cdc97 into base 4fe8b3def02ff9803a52c2fb8b97778d5bf45597, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 2b2e1def086b0ec6f67b96f198282ff2434f0656 && git checkout 2b2e1def086b0ec6f67b96f198282ff2434f0656
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4fe8b3def02ff9803a52c2fb8b97778d5bf45597 81aa285d588f9eb7e7a42209bb19c34a3d2cdc97 && git checkout -B drift-repro 4fe8b3def02ff9803a52c2fb8b97778d5bf45597 && git merge --no-ff 81aa285d588f9eb7e7a42209bb19c34a3d2cdc97

node scripts/docs-audit/affected-docs.mjs --json 4fe8b3def02ff9803a52c2fb8b97778d5bf45597

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 4fe8b3def02ff9803a52c2fb8b97778d5bf45597 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 81aa285d588f9eb7e7a42209bb19c34a3d2cdc97
Local-runs: none
Scope: packages/spec/src/migrations/entries/semantic/18.sys-metadata-audit-organization-column-retired.ts, packages/spec/src/migrations/entries/semantic/18.sys-metadata-commit-organization-column-retired.ts, packages/spec/src/migrations/entries/semantic/18.sys-metadata-history-organization-column-retired.ts, packages/spec/src/migrations/entries/semantic/18.sys-metadata-organization-column-retired.ts + packages/cli/src/commands/migrate/organization-ownership.ts, packages/cli/src/commands/migrate/organization-ownership.apply-flags.test.ts, packages/cli/src/commands/migrate/apply.ts, packages/cli/src/commands/migrate/apply-organization-ownership-gate.integration.test.ts, packages/spec/src/migrations/entries/semantic/18.cli-organization-ownership-apply-plan-file-required.ts, packages/spec/src/migrations/types.ts, packages/spec/src/migrations/spec-changes.ts, packages/spec/scripts/build-migration-registry.ts, packages/spec/scripts/build-upgrade-guide.ts, packages/spec/scripts/check-generated.ts, packages/spec/src/migrations/migrations.test.ts, .gitignore, content/docs/concepts/metadata-lifecycle.mdx, .changeset/23609-legacy-org-read-seam.md

Read: card #23609 (body; claim 6204823952, dispatch 6204866593, os-dev-report 6205946408, seat ruling 6206299338), PR #23778 (body as edited by the seat, 14-file list, net diff against merge base 2906cd8d of pr/23778), and the 48 check-runs on the head (every completed run success or skipped; the Check Changeset re-run after the body edit completed success at 02:00:06Z). The head was confirmed unmoved by git ls-remote before the read. Judged against ADR-0087 D3 (the entry fields: reason the one load-bearing prose field, replacement and acceptanceCriteria the structured TODO's prose) and its D4 amendment of 2026-10-09 (#22449 B-prime, #22485: both projections leave git and are generated at publish and at docs build), and ADR-0131 D6 (the overlay axis retired), D7 (the sys_metadata family carries no organization column) and D10 (the ceremony: read-only plan written to a file the operator keeps; backup the operator's act the apply asks about; apply in fate order with column drops last; a v18 runtime refuses an unmigrated database).

① Derived judgments

  1. The new prescription sentence in all four entries, "run the v18 ceremony, os migrate organization-ownership --out PLAN to write its plan for review, then os migrate organization-ownership --apply --plan-file PLAN, which promotes or reports the legacy organization rows and then drops the physical column", is TRUE against the CLI on this head. organization-ownership.ts: the plan arm writes the plan to resolve(flags.out ?? organization-ownership-plan-TIMESTAMP.json) with flag: 'wx' (the out flag, "Where to write the plan"); runApply refuses --apply without --plan-file first, reason plan-file-required ("Refused: --apply executes only a plan you reviewed ..."), before the backup question and the boot. No other flag is required: --backup-taken is optional. Without it the run asks at the prompt (confirm, which answers false only when stdin is not a TTY or under --json) and refuses backup-unacknowledged only for a non-interactive run. The pin organization-ownership.apply-flags.test.ts fixes exactly this order (plan-file first, backup second). So the prescription as written is accepted at an operator's terminal, which is the reader D10 item 2 names. Right.
  2. The new acceptance sentence, "On a legacy database, after os migrate organization-ownership --apply --plan-file PLAN the column is gone and the boot no longer reports it orphaned", is TRUE: the apply's column-drops step is the last fate (D10 item 3, the command's own header), and the verified marker it records is what the boot guard and the E1 gate read. Right.
  3. Against the existing entry 18.cli-organization-ownership-apply-plan-file-required.ts: its acceptance criteria say "Every invocation of os migrate organization-ownership --apply passes --plan-file". The four entries now comply; on main they prescribed the bare --apply that entry retires. Its own replacement also spells --backup-taken; the four entries, the E1 sentence and the mdx omit it. The omission is not a falsity (the prompt answers it), so it is a consistency note, not a defect. Right.
  4. Nothing a machine reads moved. Each entry declares id, surface, replacement, reason, acceptanceCriteria and nothing else (no conversionIds, no relevance key); the hunks touch only replacement and acceptanceCriteria, both plain strings. id (read by check-adr-0087-registration.mjs and the registry generator), surface (rendered by build-upgrade-guide.ts in a code span) and reason are byte-identical. migrations.test.ts asserts only that acceptanceCriteria is non-empty for these entries and pins no sentence of theirs. Right.
  5. No generated artifact is owed or left stale, and the dev's reason is right in substance though narrower than the truth. The entries feed three gitignored outputs, not one: registry.ts (built by gen:migration-registry at install and build; .gitignore names it), spec-changes.json (spec-changes.ts projects replacement verbatim; written into the package at publish by the release lane, gitignored) and content/docs/protocol-upgrade/ (build-upgrade-guide.ts renders replacement and acceptanceCriteria; generated at docs build, gitignored). check-generated.ts records that check:spec-changes and check:upgrade-guide generate in memory and never report stale, so "14/14 up to date" is the expected answer, not evidence of a regeneration. The claim comment's "with their regenerated artifacts" is satisfied by there being nothing to regenerate, per the D4 amendment. The check-runs that carry these gates on the head (Type Check - source gates, Lint & Repo Gates, Spec property liveness) are success. Right.
  6. Public surface: the strings ship in @objectstack/spec/migrations (MIGRATIONS_BY_MAJOR) and in the published spec-changes.json projection, so the change is published prose; no type, schema, export, accept set or error vocabulary moves. On the whole-PR Clause-②: no line, the item-6 narrowing of ServedOverlayRowCandidate and StoredRowPlace is on module-private interfaces in protocol.ts (declared without export; index.ts exports neither), so no public surface narrows there either. Right.
  7. The cited files say the same thing as the entries. apply.ts E1 now reads "a drop the organization-ownership ceremony owns, and the ceremony has not verified on this database" and goes on to name --out PLAN then --apply --plan-file PLAN; its --json payload (refused_organization_ownership_unmigrated, detail naming --apply --plan-file FILE) is unchanged, and the pin apply-organization-ownership-gate.integration.test.ts matches payload.detail on the command name, which still holds. metadata-lifecycle.mdx names "ADR-0131 C7: os migrate organization-ownership --out PLAN, then --apply --plan-file PLAN". Right.

② Semver level

.changeset/23609-legacy-org-read-seam.md declares @objectstack/spec: patch (with metadata-protocol, metadata and cli at patch) and the line Clause-②: no; the PR body carries the same line. The spec hunk is published content (judgment 6), so a changeset is owed and skip-changeset would be wrong; it retires nothing, widens nothing and narrows nothing, so patch is the level, and the body's bullet for @objectstack/spec describes the hunk exactly ("No id, category, version or field the migration engine reads changes"). Check Changeset is success on this head, twice. Clause-②: no, matched.

③ Boundary flags

  1. open_questions[0] (item 2, the seam's raw read inside publishPackageDrafts' ambient transaction): answered by the seat's ruling 6206299338, option C, left latent with a dedupe line. The ruling touches none of the four entries' claims: they describe the ceremony's plan, apply and column drop, not the protocol's transaction handling, and every sentence judged above stays true under C. The seat's body edit (Fixes #23609 plus the ruling line) re-ran the card gates, all success. Closed.
  2. Dev deviation "spec regeneration" (the claim and dispatch expected regenerated artifacts): nothing checked in derives from the entries (judgment 5). Closed.
  3. Dev deviation "derived-gate union run at 042ba4c5, 13 families re-run at 81aa285d": the check-runs on the head are the verdict and are all success. Closed.
  4. Dev's two out_of_scope_findings (DatabaseLoader.queryHistory's page cut; listCommits' store-order limit): ruled into the PR's Acceptance notes by the seat; neither concerns the entries. Closed.
  5. Reviewer's own note, not blocking: the bare --apply spelling the card retired in the four entries still stands in content/docs/permissions/capabilities.mdx and content/docs/permissions/permission-sets.mdx (mentions of what the ceremony does, not step-by-step prescriptions), in the sys-metadata*.object.ts comments in packages/metadata-core, and in docs/qa/platform-checklist/areas/access-security.json. Item 7 named only the four entries and metadata-lifecycle.mdx, so these are outside this PR; a wording card is the carrier if the seat wants them aligned. CHANGELOG and changeset history correctly record the pre---plan-file shape and are not edited.
  6. Reviewer's own note, not blocking: the sibling entries 18.cli-organization-ownership-apply-plan-file-required.ts and 18.ups-permission-set-id-column-retired.ts spell --apply --backup-taken --plan-file plan.json; the four entries omit --backup-taken as the E1 sentence and the mdx do. Both spellings run (judgment 1).

Implemented-by: session_01TekAoE8QbLrxFVJsdNuRgg
Reviewed-by: session_01GP3comALHRcRBixS2TEnLF

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · domain:engine seat 1 · session_01GP3comALHRcRBixS2TEnLF · 2026-10-16T02:06Z · ACCEPT

Head: 81aa285d588f9eb7e7a42209bb19c34a3d2cdc97.

Item Reading
Shape PR → main. The body opens Fixes #23609 (the seat's edit, after the item-2 ruling 6206299338), its only closing keyword. #23429 / PR #23469 are named without one.
Scope 14 files (+564 / −126). Engine: protocol.ts (the legacy-organization read seam only: findEnvironmentRows, readRevertableCommit shared by revertCommit and rollbackToPackageCommit, and the inert plumbing), sys-metadata-repository.ts (list's limit only), database-loader.ts (_count only), two new pin files, and the engine-double ledger the gate wrote. Cross-lane, as declared on #6024, #18883 and #20163: one cli assertion, the cli E1 sentence, four spec entries' prose, and one docs line. That is the claim's surface (6204823952). saveMetaItem, the D9.9 calls and the draft address are untouched. No governed path (check-governed-merges.mjs --pr 23778: 0 of 14). 690 lines, under the 3,000-line threshold.
Items 1, 3, 4, 5, 6 and 7 done, each measured on main first. Item 2 is measured (a 25 s stall on a v17-shape file against 97 ms migrated) and ruled C by the seat, left latent (6206299338). The seat read the engine diff: a paged read re-reads with id $nin only when the page held a legacy row or an offset could have counted one; _count re-counts only a non-zero count over a table that holds legacy rows; the rollback reads the commit through the one helper revertCommit already used. On a migrated or fresh store, every path takes the single original read.
Pins and controls protocol.legacy-organization-read-seam.test.ts (16 cases) and database-loader.legacy-organization-count.test.ts (4 cases) run each fix on a legacy-shape store beside a migrated CONTROL, whose answer does not change. Item 1's new assertion is red under the filter-only ablation; the file was 7/7 green there before. Ablations for items 1, 3 (two legs), 4 and 5 each turn exactly their own cases red and restore clean. Item 6 is proved by an identical full suite with and without the commit (237 files, 20593 tests).
Contract review The four packages/spec migration entries are the reviewFace hits: record 6206405366 at CONTRACT_REVIEW_TIER, PASS on this head. The rest of the diff is this table, the seat's review of record at TIER_DEFAULT.
Clause-② no, in the claim, the PR body and the changeset. The answers change only on an unmigrated database (rollbackToPackageCommit's 404 becomes revertCommit's named 403; pages and counts agree with the environment-only reads). No accept set widens, and no export moves: the removed fields are module-private. patch for metadata-protocol, metadata, cli and spec.
Gates The dev's derived union at 81aa285d: 123 derived, 119 run, 4 NOT MEASURED (shallow-clone and dist prerequisites; CI hosts those families). One real red on the first run (check:engine-double-contract) was fixed in 81aa285d. CI on this head: 48 check-runs, 41 success, 7 skipped, none failed. Build Docs ran for the docs line and is green. The skips are the path-filtered roster (Console Pin Gate, the Dogfood shards, Dogfood Verify CLI, Temporal Conformance, Packed-tarball smoke) and the body-edit re-runs of Auto Label and Check PR Size, each of which also has a success run.

Disposition:

  • open_questions[0] (item 2): C, ruled in 6206299338. It is transitional code for a database os serve refuses, no caller reaches the path, and A's public engine accessor would widen the public surface for code meant to retire. A future reader of the family inside an ambient transaction, off the served boot, carries route A in its own card.
  • out_of_scope_findings: both go to Acceptance notes, not filed (6206299338). queryHistory's page cut is latent like the card. listCommits' limit has no in-repo caller and no spec declaration.
  • The record's note: the bare --apply spelling stands elsewhere (content/docs/permissions/*.mdx, sys-metadata*.object.ts comments, docs/qa). This is outside item 7's surface. It goes to Acceptance notes, not filed: the CLI refuses that spelling with plan-file-required, which names the missing flag.
  • deviations: accepted. Model-free trailers per AGENTS.md; the PR left unsubscribed (the seat holds it); the checkout detached for the worktree; item 3's ablation legs run outside the verify lock; 106 gate results from 042ba4c5, which differs from the head only in one test fake and the ledger; the exit codes read from vitest's own Tests line.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 16, 2026 02:07
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 16, 2026 02:07
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 8684079 Oct 16, 2026
49 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23609-legacy-org-read-seam branch October 16, 2026 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants