Repository navigation
fix(metadata-protocol): the reconcile census reads every protocol-*.ts module, and the package-less overlay move heals the registry after its delete - #30257
Conversation
…s module, and the package-less overlay move heals the registry after its delete The stored-row write census read protocol.ts and the codemod's modules only, so a writer the hand series moved into a protocol-*.ts module was neither routed nor counted. Widened to every non-test protocol-*.ts module, it finds one: migratePackagelessOverlays deleted the unbound row through a second SysMetadataRepository and ran no heal. The delete now takes the one repository and is followed by restoreArtifactRegistryView for an active row, as the delete door's is. Claude-Session: https://claude.ai/code/session_01Utp6CaYnLnm2honH3ermsi Co-authored-by: Claude <noreply@anthropic.com>
…om the source instead of crashing on it Claude-Session: https://claude.ai/code/session_01Utp6CaYnLnm2honH3ermsi Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 10 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 5d33f262827f7a0a46c542a32f8dcf30a2f4a344 && git checkout 5d33f262827f7a0a46c542a32f8dcf30a2f4a344
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc 4feb0ac6d9ac9bb48235b7c587f2094e26038952 && git checkout -B drift-repro 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc && git merge --no-ff 4feb0ac6d9ac9bb48235b7c587f2094e26038952
node scripts/docs-audit/affected-docs.mjs --json 771b2db20ac08d78b7fec5c2bd1ee30de9aa26dc
|
|
domain:server#3 · os-bill · session_01Utp6CbPxYq1wQmUNWvMZkC 席位核对ACCEPT · head
|
Requested by Bill · project thread
domain:server#3 · os-bill · session_01Utp6CaYnLnm2honH3ermsi
Fixes #30000
Clause-②: no
Metadata-protocol: none
维护者速读
protocol.view-expansion-reconcile-call-sites.test.ts)从「protocol.ts+ codemod 模块」扩到全部非测试protocol-*.ts;扩后只多找到一处写入:os migrate packageless-overlays --apply删未绑定行。该删除改走唯一仓库getOverlayRepo(),删后对 active 行跑删除门同款的restoreArtifactRegistryView自愈。@objectstack/metadata-protocolpatch。回滚即撤 PR。protocol-packageless-overlay-migration.ts第 4 步 delete 后的自愈一行;普查测试的MODULES与新增WRITES行;protocol.ts宿主对象新增两项。pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.view-expansion-reconcile-call-sites.test.ts13/13 通过;把迁移模块换回 main 版本再跑,4 条转红并点名migratePackagelessOverlays。What changes
protocol.view-expansion-reconcile-call-sites.test.tsbuilt its population fromprotocol.tsand theprotocol-*.tsmodules whose header names the Codemod split: generate the rest of the metadata-protocol protocol.ts split with a deterministic script, verified byte-identical #29985 codemod. The earlier hand series' modules were left out, so a writer moved there was neither routed nor counted. The header filter is gone: every non-testprotocol-*.tsmodule is scanned (ruling 6597555122 item 3: a test that reads a file by path reads the module a body moves to). A new case pins the population to the directory listing and pins that the one hand-series write is in it; the codemod non-vacuity case is kept.migratePackagelessOverlays(protocol-packageless-overlay-migration.ts) built its ownnew SysMetadataRepository({ engine, orgLabel: 'env' })and calledrepository.delete(…)on the unbound row after step 3's read-back, with no heal after it.const repo = this.getOverlayRepo();, which builds the sameSysMetadataRepositoryover the same engine withorgLabel: 'env'), and for an active row it is followed byawait this.restoreArtifactRegistryView(row.type, row.name, null, row.member), the heal the delete door runs after its ownrepo.delete. A draft row heals nothing, as the door's draft discard does not. The heal reconciles the container's expansion record to the empty set, lifts the unbound row's registration, and registers the pair row saved in step 2 again from the store. The census records the write asmigratePackagelessOverlays: repo.delete(→restoreArtifactRegistryView; it has no exception kind and gains none.PackagelessOverlayMigrationHostgainsgetOverlayRepoandrestoreArtifactRegistryView;ObjectStackProtocolImplementation#migratePackagelessOverlayswires both. The heal forwarder awaits the call (async (...a) => { await … }), because the census requires every call into the chain to be awaited.expect(found, 'MEMBER: VERB is in the source').toBeDefined()) instead of crashing onundefined.scanned.@objectstack/metadata-protocolpatch, with both declaration lines.The card's unmeasured item, measured
The card left open whether a served view container keeps a stale expansion after the migration. Measured over the real
ObjectQLengine andSchemaRegistry(the harness ofprotocol-packageless-overlay-migration.test.ts), onmain'sdist/before the fix:showcase_taskcontainer row (alistViewsmember the base does not ship) is listedmovable, but step 2's save is refused:view/showcase_task failed spec validation: … Unrecognized key(s) on this view container: `overrides`. The outcome isfailed, the unbound row stays, and before the run, after the run and after a restart, the registry, the list door and the by-name reads were identical. So no stale expansion: the move never deletes a container row. That refusal is its own finding (below).showcase_task.defaultrow moves (moved, basedOn1.2.0). After the run, the registry held two entries of the name (the unbound row'stitle,priorityand the base's), while a restart over the same rows held one (the base's). The five reads servedtitle,priorityin all three states, so no door answered differently. With the fix, the registry after the run equals the restart's.Pinned in
protocol-packageless-overlay-migration.test.tsas a new top-leveldescribein the existing harness: after the move, the registry entries of the name equal a restart's (new engine and protocol over the same rows, pair ensured,loadMetaFromDb), the unbound row's registration is gone, and the five reads equal the restart's.Tests
Local, on the merged head (
mainmerged at6f095b9c):pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.view-expansion-reconcile-call-sites.test.ts→ 13/13.pnpm --filter @objectstack/objectql exec vitest run src/protocol-packageless-overlay-migration.test.ts→ 29/29 (afterpnpm --filter @objectstack/metadata-protocol build; the suite reads the protocol'sdist/).Ablation (once). At
5b9b737f,protocol-packageless-overlay-migration.tswas put back tomain's bytes (git restore --source=5fa9375e; on disk:new SysMetadataRepository(1, the heal 0). The census went red, 4 of 13:Restored with
git checkout HEAD -- PATH: blob8f4617e1before and after,git diff HEADempty, 13/13 again. Before the widening, the samemainmodule was outside the census, which was green.The registry pin's red leg is the measurement above:
main'sdist/left the unbound row's registration in place after the move, and the fixeddist/does not.Acceptance notes
os migrate packageless-overlays --applycannot move a view container. Step 2 saves{ ...body, overrides: { package, basedOn } }into the pair, and the view-container schema refusesoverridesas an unrecognized key, so every package-less container row of a packaged view is listedmovableand then fails, every run. Reach: the ceremony's--applythroughmigratePackagelessOverlays, measured above. Dedupe words:packageless overlays view container overrides,Unrecognized key overrides view container,declared override view container,ADR-0146 D11 container. For the seat to file.repo.spelling and holds that spelling with its one-acquisition check (new SysMetadataRepository(only ingetOverlayRepo,getOverlayRepo()only asconst repo = …). A repository handed in as a parameter under another name would write past both; none exists today.Verification
All readings on head
4feb0ac6(the two commits plus a merge ofmainat6f095b9c; the four commitsmaingained since touch neither package).Package suites and typechecks (under os-verify-lock.sh)
Derived gates: dispatch-gates --commands, 61 families, reconciled with --ran
node scripts/check-plugin-teardown-shape.mjs --self-testfirst exited 3 on the shallow clone; aftergit fetch origin 621a4876…it exits 0, and that run is the one recorded.pnpm check:dual-build-cjs-loadsexits 3, PREREQUISITE NOT MET: it needs every package'sdist/, and only the@objectstack/objectqlclosure is built here. NOT MEASURED locally; CI'sLint & Repo Gatesruns it.dispatch-gates --ran:✓ 61 derived famil(ies) accounted for — 60 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).pnpm lint :: exit 0.Generated by Claude Code