test(metadata): #19246 does not reproduce — a packages[] artifact's top-level-only docs DO register - #19375
Conversation
…s register #19246 was filed NOT MEASURED, on a static reading taken twice independently: that a multi-package artifact's top-level-only `docs` — the flat `src/docs/` that #18431's ruling keeps at the top level — register nowhere at boot. Measured instead of read. `os build` on the #18431 e2e fixture emits top-level `docs: ['pkgdocs_index']` with the package doc `ord_playbook` on the orders body alone; booting that artifact and asking `GET /api/v1/meta/doc` as an authenticated caller returns BOTH, `pkgdocs_index` stamped with the artifact's own manifest id. The registrar is `MetadataPlugin._parseAndRegisterArtifact`'s residual sweep, which neither reading reached. The new block pins that measurement against the same real door: the body doc as the lit control, the top-level-only doc as the subject, an absence arm that proves the instrument can report a missing doc, and the door's own warning. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCdUBjM47SxioST9z5Zwdf
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
Seat grading — ACCEPT. The card does not reproduce, and the correction is the deliverable.⭐ This is the outcome the dispatch named as complete: "if it does NOT reproduce, that is a finding worth writing down too — and it is a complete, acceptable outcome for this round." ⛔ No defect was manufactured to justify the round, and ⛔ the repro was not quietly widened until something broke. What the seat verified independently on
|
| claim | check | result |
|---|---|---|
| the registrar neither reading reached | packages/metadata/src/plugin.ts |
_parseAndRegisterArtifact at :894, carriesPackages at :974, the if (carriesPackages) residual sweep at :1013, its warning at :1039 — present as described |
| static reading 2 was right about itself | app-plugin.ts |
registers collections.docs 0 times — and mentions collections 33 times, so that grep was live, ⛔ not a dead zero |
| static reading 1 was right about itself | core/src/artifact-packages.ts |
resolveArtifactPackageOrder present |
| scope | GET /pulls/19375/files |
1 file, +130/−0, packages/metadata/** |
| the fence held | diff scanned | packages/cli/src/utils/collect-docs.ts untouched — it was claimed by PR #19352 at dispatch time |
| CI | both layers | 0 failed runs, 0 failed suites |
⭐ Why two independent readings agreed and were both wrong
Both were correct about the files they read. resolveArtifactPackageOrder really does walk bodies only when packages is present; app-plugin.ts really does register no collections.docs. The conclusion was wrong because the registration happens in a third file neither reading opened.
⇒ ⭐ agreement between two static readings is only evidence when they looked in different places. These looked at the same two, so the second reading added confidence without adding coverage. That is the same failure shape as a lit control that certifies the instrument but not the question (#18755).
The measurement, and the fake zero it caught
Booted the card's own two-package fixture through a real os build + os dev --fresh, then asked the live surface. Authenticated GET /api/v1/meta/doc returned both the top-level-only pkgdocs_index and the lit control ord_playbook, each stamped with its own _packageId and each carrying a marker written into exactly one file on disk.
Two things make that a measurement rather than a green light:
- an absence arm that can show absence —
src/docsdeleted, rebuilt, rebooted → the same query returned 2 docs withpkgdocs_indexgone. ⇒ the query is capable of reporting a missing doc, so its earlier "present" was not a query that always says yes. - ⭐ the dev found and recorded a fake zero of its own: anonymous
GETreturnsitems: []by audience design. It named that as a fake zero rather than reporting it. ⛔ An unauthenticated empty answer here would have "confirmed" the card.
The ablation closes it: forcing the residual sweep's carriesPackages guard false turned the two new cases red (plus a pre-existing orphan case) while the control kept registering and the absence arm correctly stayed green; restore proven by blob hash back to 0bdb14843b86 with an empty git diff HEAD.
⭐ The pin is what makes a negative result durable
+130/−0 in packages/metadata/src/plugin-artifact-packages-attribution.test.ts. ⛔ A non-reproduction reported only in prose decays the moment someone edits that path — the next reader gets a third static reading. This one leaves a measurement that goes red if the registration ever does break the way the card predicted.
Disposition of #19246
The card is not reproduced. Its two static readings are corrected on the card itself, and the pin carries the correction forward. ⛔ It was never a defect, so nothing is "fixed" — the round discharged the question it was filed to ask.
Generated by Claude Code
Fixes #19246
Verdict: the card does not reproduce
#19246 was filed NOT MEASURED, on a static reading taken twice independently (review flag D of
5747199582, and the #18431 dev): that a multi-package artifact's top-level-onlydocsregister nowhere at boot. This round booted it. They register.Both static readings were correct about the two places they looked, and wrong about the conclusion drawn from them:
resolveArtifactPackageOrder(packages/core/src/artifact-packages.ts) does return package bodies only whenpackagesis present — confirmed, unchanged.packages/runtime/src/app-plugin.tsdoes not registercollections.docs— confirmed, its onlydocsmention is theAPP_CATEGORY_KEYSpresence list.Neither file is the registrar. The registrar is
MetadataPlugin._parseAndRegisterArtifact's residual sweep (packages/metadata/src/plugin.ts), which runs after the package walk and registers every top-level(type, name)slot that no package body claimed, stamped with the artifact's own manifest identity. Neither reading reached it.The measurement
Fixture — the card's own e2e multi fixture (
packages/cli/test/build-package-docs-attachment.e2e.test.ts, replicated outside that claimed directory), two packages with different namespaces, a flatsrc/docs/pkgdocs_index.mdand a package-directorysrc/orders/docs/ord_playbook.md, each carrying a distinct marker string written into exactly one file on disk.os buildemitted the shape under test:Boot —
os dev --fresh -p PORTon that artifact, real process, real kernel (29 plugins), better-sqlite3 driver, seeded dev admin.Query —
GET /api/v1/meta/docas an authenticated caller (both docs' effective audience isorg, so an anonymous caller is filtered to[]by design — that empty answer is a fake zero, not a reading):With
?include=content, pedigree holds in both directions:pkgdocs_indexcarriesMARKER-flat-doc-18431(written only intosrc/docs/pkgdocs_index.md) andord_playbookcarriesMARKER-package-doc-18431(written only intosrc/orders/docs/ord_playbook.md). Neither item is an echo of the other, and a third doc from the platform's owncom.objectstack.setuppackage rode along as an unplanned second control.Instrument absence arm — the same fixture rebuilt with
src/docs/deleted, booted on a second port and queried identically, returnsord_playbookandsetup_overviewand notpkgdocs_index. The query can report a missing doc, so the presence above is a reading rather than a shape that always answers yes.The boot says it out loud. The residual sweep is not silent — it warns, naming the count, the owner it fell back to and a remedy:
That remedy was checked rather than assumed: moving
src/docs/pkgdocs_index.mdtosrc/core/docs/and rebuilding puts the doc on the core body (2 collected (2 from 2 package directories)) and the top-leveldocskey disappears from the artifact. The warning is actionable.What this PR lands
One regression pin, in
packages/metadata/src/plugin-artifact-packages-attribution.test.ts— the existing home for this door's attribution pins, whoseload()harness drives the real_parseAndRegisterArtifact. Four cases: a premise guard on the fixture shape, the measurement (lit control asserted first, in the same load, with marker pedigree on both), the absence arm, and the warning.No production code changes.
packages/cli/src/utils/collect-docs.tswas not touched — the fence held, and nothing the measurement showed needed it.The fixture's docs half is positioned by hand and the test header says why:
composeStacks(…, { manifest: 'preserve' })is not the producer for this one key —os build's docs collector places docs after composition, per #18431's ruling — so composing adocs-carrying stack would produce the additive both-places shape, which is precisely not the shape under test. The placement is the one read off the real build above.Reverse verification
Both legs run from the committed state, with the mutation proved on disk by anchor/injection counts and blob hash, and restored byte-identically (
git hash-objectback to the HEAD blob,git diff HEADempty).if (carriesPackages) {forced false, package walk untouchedregisters BOTH …,says out loud …, and the pre-existingkeeps a top-level item that NO package body declaresThe narrow leg is the discriminating one. The new
registers BOTHcase goes red while the absence arm stays green (with the sweep off, the doc-absent world is unchanged) and the controlord_playbookkeeps registering through the package walk — so the pin fails on the subject, not on the harness. A blunter first leg (replacing the call itself, which throws) took 8 of 11 down and is recorded here only as the reason the narrow one was run.Local verification
pnpm --filter @objectstack/metadata exec vitest run --maxWorkers=2 src/plugin-artifact-packages-attribution.test.ts— 11 passed (11), at2cc69a66.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackagainst this tree (1 changed path, +130/-0) and run: 50 of 51 green.pnpm check:dual-build-cjs-loadsansweredPREREQUISITE NOT MET — this gate reads built output, and some package has no dist/(13 packages unbuilt in this worktree). NOT MEASURED, not a failure and not a pass; it needs a whole-repopnpm build, and this diff is one test file that changes nodist/.pnpm lintand the CI-shell job stepsdispatch-gateslists as unmeasurable locally) are CI's run, not this branch's.Changeset
skip-changeset. Measured, not assumed:@objectstack/metadatashipsfiles: ["dist","README.md","CHANGELOG.md"]; a symbol unique to the new test (pkgdocs_index) has 0 hits across those paths, while the positive control — a string fromplugin.tsthat does ship — has 4. Asrc/*.test.tsfile publishes nothing.Clause-②: no
Acceptance notes
src/docs/boots with that warning, because cli: read package docs from each package directory under an ADR-0130 layout — the widening half of #18170, blocked on two contract questions #18431 deliberately keeps those docs at the top level while the compiler puts package-directory docs on bodies. The warning is correct and its remedy works (measured above), but the platform's own emitter is what produces the shape it warns about. Noted, not filed: the behaviour is right, the docs register, and the next reader now finds a pin. The card itself names who meets it — the clause-5 acceptance for cli: read package docs from each package directory under an ADR-0130 layout — the widening half of #18170, blocked on two contract questions #18431 on hotcrm, which keeps a flatsrc/docs/today; that acceptance will see the warning and should not read it as a defect.docsas "filesystem input" (packages/runtime/src/option-b-reader-probe.ts), which is why this path carried no pin. Whether that exclusion should move is that ledger's card, not this one.#18431 is not addressed here.维护者速读(草稿)
改了什么 — 只加了一个测试。没有改任何生产代码。
为什么改 — #19246 是一张「没人实测过」的卡:两位评审各自静态读代码,都得出「多包制品的顶层 docs 在启动时哪里都没注册」。这一轮真的把它跑起来了:用卡里点名的 e2e fixture 编译出制品、启动真实服务、带登录态查
/api/v1/meta/doc,顶层那篇 doc 在,并且同一次查询里那篇「一定会注册」的分包 doc 作为对照也在。两位评审看的两个文件都没错,只是注册它的既不是那两个文件,而是packages/metadata里的 residual sweep。所以卡的结论被推翻,这个 PR 把这次测量钉成回归测试,免得下一个人得出第三次静态结论。风险与代价(含回滚) — 风险接近零:新增的是测试文件,不进任何 npm 包(已实测
files[]里零命中)。回滚就是 revert 这一个提交。代价是往一个已有测试文件里加了约 130 行。席位意见 — (留空)
你要做的 — 确认一件事就够了:#19246 应当以「不复现」关闭,而不是继续当 bug 排期。另外 #18431 在 hotcrm 上的 clause-5 验收会看到一条启动 warning(顶层 docs 无包认领),那是设计如此、且有可执行的补救,不是缺陷。
Generated by Claude Code