From 030460296eb4f4e636ed9ac74b05030c4ff2fcad Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 07:58:55 +0000 Subject: [PATCH 1/2] docs(spec): correct the two prose sites asserting the expired browser-only manifest claim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check-generated.ts`'s EXTERNAL_INPUT_REQUIRED `why` string asserted that the registry "exists only after objectui is built at .objectui-sha and enumerated in a real browser" and that "nothing in this repo can hand it one". Both halves are false: `scripts/gen-sdui-manifest-node.mjs` enumerates the registry under plain Node, and the artefact it writes has been tracked at the repo root since #13446, where lint.yml feeds it to the gate on every PR. The classification is unchanged — the aggregate genuinely passes no MANIFEST — only the stated reason is made true. The gate's own header carried the same expired premise ("its only producer is objectui's dump-public-manifest.mjs ... nothing enumerates it from Node") and is corrected alongside it, with what the two producers actually read. Claude-Session: https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho Co-authored-by: Claude --- packages/spec/scripts/check-generated.ts | 15 ++++++--- .../check-react-blocks-declaration-parity.ts | 32 +++++++++++++++---- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/packages/spec/scripts/check-generated.ts b/packages/spec/scripts/check-generated.ts index e72da19b926..f3a33c06549 100644 --- a/packages/spec/scripts/check-generated.ts +++ b/packages/spec/scripts/check-generated.ts @@ -380,10 +380,17 @@ const EXTERNAL_INPUT_REQUIRED: ReadonlyArray<{ runBy: 'scripts/gen-sdui-manifest.sh', why: 'compares the spec schema props against the registry-declared inputs (two declarations, no renderer: #4472). ' + - 'The registry is a browser app, so its manifest exists only after objectui is built at .objectui-sha and ' + - 'enumerated in a real browser — nothing in this repo (console dist is gitignored, the published console ships ' + - 'no sdui.manifest.json) can hand it one. `pnpm sdui:manifest` produces it and runs the ratchet; without it the ' + - 'gate now exits 1 rather than skipping (#4690)', + 'It reads its manifest from MANIFEST= and THIS AGGREGATE PASSES NONE — that, and only that, is what ' + + '"cannot run here" means for this entry. The input is NOT unavailable in the repo: since #13446 a dump is ' + + 'TRACKED at the repo root as sdui.manifest.json, and lint.yml runs the gate --strict against it on every PR ' + + '(MANIFEST="$PWD/sdui.manifest.json"), so the gate is neither unrun nor unrunnable — it is unrun BY THIS ' + + 'AGGREGATE. Nor does producing one require a browser: scripts/gen-sdui-manifest-node.mjs regenerates the ' + + 'tracked artefact under plain Node from the PUBLISHED @object-ui/* packages (the browser-only claim was ' + + 'measured false in objectui#6741), and scripts/check-sdui-manifest.mjs holds artefact, record and pin ' + + 'together. `pnpm sdui:manifest` (runBy) is the other producer: it builds objectui at .objectui-sha and dumps ' + + 'the registry from a real browser, then runs this ratchet against THAT. ⚠️ The two producers read two ' + + 'different registries — published packages vs the pinned checkout\'s source — and do not agree today (#17735). ' + + 'Without a MANIFEST the gate exits 1 rather than skipping (#4690)', }, ]; diff --git a/packages/spec/scripts/check-react-blocks-declaration-parity.ts b/packages/spec/scripts/check-react-blocks-declaration-parity.ts index b7c17775392..3f850968117 100644 --- a/packages/spec/scripts/check-react-blocks-declaration-parity.ts +++ b/packages/spec/scripts/check-react-blocks-declaration-parity.ts @@ -67,15 +67,33 @@ // // So the accepted set per block is node-level keys ∪ per-block props ∪ overlay. // -// WHERE THE MANIFEST COMES FROM — AND WHY NOTHING HERE CAN PRODUCE ONE (#4690). +// WHERE THE MANIFEST COMES FROM — TWO PRODUCERS, TWO REGISTRIES (#4690, #17735). // // The right-hand side is objectui's registry-inputs manifest (sdui.manifest.json). -// Its only producer is objectui's `scripts/dump-public-manifest.mjs`, which drives a -// real browser (Playwright chromium) at the built console's `dev/manifest-dump.html` -// and reads `window.__MANIFEST`: the registry is a browser app (plugin-map / charts -// pull browser-only deps), so nothing enumerates it from Node. `pnpm sdui:manifest` -// (scripts/gen-sdui-manifest.sh) is the wrapper that builds objectui at -// `.objectui-sha`, dumps the manifest, and then runs THIS gate against it. +// It has TWO producers, and they do not read the same registry — which is the whole +// of #17735, so do not reason from either one alone: +// +// browser objectui's `scripts/dump-public-manifest.mjs` drives a real browser +// (Playwright chromium) at the built console's `dev/manifest-dump.html` +// and reads `window.__MANIFEST`. `pnpm sdui:manifest` +// (scripts/gen-sdui-manifest.sh) is the wrapper: it builds objectui +// from the SOURCE at `.objectui-sha`, dumps, then runs THIS gate on it. +// node `scripts/gen-sdui-manifest-node.mjs` writes the TRACKED repo-root +// artefact under plain Node — no browser, no objectui build. It +// enumerates the PUBLISHED `@object-ui/*` packages at the version named +// in `scripts/sdui-manifest.record.json`. +// +// ⚠️ "The registry is a browser app so nothing enumerates it from Node" was true +// when this header was written and is now FALSE — measured in objectui#6741 and +// re-measured on 2026-08-30; the node producer's header carries the readings. +// +// ⚠️ The two producers disagree TODAY, and the reason is the input, not the code: +// objectui bumps its `version` only at release, so the version read off the pinned +// commit's `packages/core/package.json` names the PREVIOUS release's tarball. The +// node route therefore describes the registry of the last PUBLISHED release, while +// the browser route describes the PINNED SOURCE — and `check-sdui-manifest.mjs` +// cannot see the gap, because it verifies the record's sha and pin, never that the +// version installed corresponds to the pinned commit (#17735). // // NOTHING HERE PRODUCES one — but since #13446 one is CHECKED IN. The production // half is unchanged and still measured: `packages/console/dist/` is gitignored (the From 2298170853e3f9e848c5e9842c204c3a16d1fe01 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 17 Sep 2026 09:24:05 +0000 Subject: [PATCH 2/2] docs(spec): the sdui:manifest wrapper dumps and ratchets, it does not build objectui Rework of the prose this branch already corrected: the replacement text re-asserted two things that are themselves false, and one bucket definition still contradicted the corrected reason one line below it. 1. "builds objectui at .objectui-sha" (check-generated.ts `why`) and "it builds objectui from the SOURCE at `.objectui-sha`" (parity-gate header). Measured: scripts/gen-sdui-manifest.sh computes BUILD_ROOT=.cache/objectui- (507) and exits 1 unless that directory already exists (512-516), printing "Run 'pnpm objectui:build' first to vendor the console at the pinned SHA". It then serves that vendored tree with a vite dev server (sdui_dev_server_cmd, 373-376; pushd 545), drives objectui's dumper against it (654-655) and runs the ADR-0082 ratchet on the result (684-688). It requires a build; it performs none. 2. The citation `objectui#6741`, carried in both files. It resolves to nothing: 404 for both the issue and the PR at that number, while objectui 6739 / 6742 / 6743 answer 200 as controls. The fact it was cited for -- the registry enumerates under plain Node -- is reproduced and stays; the number is dropped and the parity header carries a tombstone so nobody restores it. 3. The same-class sentences that survived the first pass, all in check-generated.ts: the EXTERNAL_INPUT_REQUIRED doc comment ("the input they compare against does not exist here and cannot be produced here"), the print line ("source audit(s) whose input this repo cannot produce") with its rationale comment, and the ledger's classification prompt for the same bucket. All four said the input cannot be produced here; the corrected `why` one line away says it is tracked here and CI feeds it to the gate on every PR. The bucket, its membership, `runBy` and every verdict are untouched -- only the stated reason moves, which is the ruling's item 4. Claude-Session: https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho Co-authored-by: Claude --- packages/spec/scripts/check-generated.ts | 35 ++++++++++++------- .../check-react-blocks-declaration-parity.ts | 21 +++++++---- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/packages/spec/scripts/check-generated.ts b/packages/spec/scripts/check-generated.ts index f3a33c06549..a16bf68bffc 100644 --- a/packages/spec/scripts/check-generated.ts +++ b/packages/spec/scripts/check-generated.ts @@ -347,14 +347,18 @@ const NO_GENERATOR: ReadonlyArray<{ check: string; why: string }> = [ ]; /** - * Source audits that CANNOT RUN from this repository at all, because the input - * they compare against does not exist here and cannot be produced here. + * Source audits THIS AGGREGATE cannot run, because each needs an input handed to + * it on the command line and this aggregate hands none over. That, and only that, + * is the claim — ⛔ NOT that the input is unavailable here: for the entry below it + * is TRACKED in this repo and CI feeds it to the gate on every PR (that entry's + * `why` carries the reading). * * A separate bucket from `NO_GENERATOR` because the two say different things to a - * reader, and #4690 is what conflating them cost. `NO_GENERATOR` means "runnable, - * deliberately not run in this aggregate — run it yourself and it will answer". - * This one means "you cannot run it here at all, and here is the input it wants - * and who produces it". Sitting in the first list, `check:react-declaration-parity` + * reader, and #4690 is what conflating them cost. `NO_GENERATOR` means "runnable + * as it stands, deliberately not run in this aggregate — run it yourself and it + * will answer". This one means "running it takes an input this aggregate does not + * pass, so here is that input and who does pass it" — still runnable by hand, and + * the `why` says with what. Sitting in the first list, `check:react-declaration-parity` * read as the former for the entire time it was the latter: it was wired into no * workflow, and a manual run without `MANIFEST` printed a `⚠` and exited 0, so no * path existed on which the gate could go red. Whoever read "deliberately not run" @@ -386,9 +390,12 @@ const EXTERNAL_INPUT_REQUIRED: ReadonlyArray<{ '(MANIFEST="$PWD/sdui.manifest.json"), so the gate is neither unrun nor unrunnable — it is unrun BY THIS ' + 'AGGREGATE. Nor does producing one require a browser: scripts/gen-sdui-manifest-node.mjs regenerates the ' + 'tracked artefact under plain Node from the PUBLISHED @object-ui/* packages (the browser-only claim was ' + - 'measured false in objectui#6741), and scripts/check-sdui-manifest.mjs holds artefact, record and pin ' + - 'together. `pnpm sdui:manifest` (runBy) is the other producer: it builds objectui at .objectui-sha and dumps ' + - 'the registry from a real browser, then runs this ratchet against THAT. ⚠️ The two producers read two ' + + 'measured false on 2026-08-29, re-measured 2026-08-30 against published 17.6.0, and reproduced ' + + 'byte-identically in review of #18608), and scripts/check-sdui-manifest.mjs holds artefact, record and pin ' + + 'together. `pnpm sdui:manifest` (runBy) is the other producer, and it does NOT build objectui: it REQUIRES ' + + 'a checkout already vendored at .cache/objectui- by `pnpm objectui:build`, exits 1 telling you to run ' + + 'that first (gen-sdui-manifest.sh 507-516), then serves that tree with a vite dev server and dumps the ' + + 'registry from a real browser, running this ratchet against THAT. ⚠️ The two producers read two ' + 'different registries — published packages vs the pinned checkout\'s source — and do not agree today (#17735). ' + 'Without a MANIFEST the gate exits 1 rather than skipping (#4690)', }, @@ -488,7 +495,7 @@ function reconcileLedger(scripts: Record): void { if (name.startsWith('check:') && !declaredChecks.has(name)) { problems.push(` \`${name}\` exists in package.json but is in neither GATED nor NO_GENERATOR (nor EXTERNAL_INPUT_REQUIRED).\n` + ` Classify it: does it compare a checked-in artifact against a generator, audit source,\n` + - ` or audit source against an input this repo cannot produce (name where it DOES run)?`); + ` or audit source against an input THIS AGGREGATE does not pass (name who does pass it)?`); } if (name.startsWith('gen:') && !declaredGens.has(name)) { problems.push(` \`${name}\` exists in package.json but no GATED entry names it and it is not in UNGATED_GENERATORS.\n` + @@ -653,10 +660,12 @@ for (const entry of GATED) { console.log(`\nNot run here (${NO_GENERATOR.length} source audits with no artifact to regenerate): ` + NO_GENERATOR.map((n) => n.check).join(', ')); // Narrowing is never silent, part three — and this one is a different sentence: -// "deliberately not run" invites the reader to run it, which for these is not an -// option from this repo. Say what the missing input is and who supplies it. +// "deliberately not run" invites the reader to run it AS IT STANDS, which for +// these does not work: each needs an input on the command line that this +// aggregate does not pass. Say what that input is and who does pass it, so the +// reader can run it by hand — for the entry below the input is tracked here. if (EXTERNAL_INPUT_REQUIRED.length) { - console.log(`Cannot run here (${EXTERNAL_INPUT_REQUIRED.length} source audit(s) whose input this repo cannot produce):`); + console.log(`Needs an input this aggregate does not pass (${EXTERNAL_INPUT_REQUIRED.length} source audit(s)):`); for (const e of EXTERNAL_INPUT_REQUIRED) { console.log(` ${e.check} — needs ${e.input}\n runs in ${e.runBy}; ${e.why}`); } diff --git a/packages/spec/scripts/check-react-blocks-declaration-parity.ts b/packages/spec/scripts/check-react-blocks-declaration-parity.ts index 3f850968117..ff757322d8c 100644 --- a/packages/spec/scripts/check-react-blocks-declaration-parity.ts +++ b/packages/spec/scripts/check-react-blocks-declaration-parity.ts @@ -74,18 +74,27 @@ // of #17735, so do not reason from either one alone: // // browser objectui's `scripts/dump-public-manifest.mjs` drives a real browser -// (Playwright chromium) at the built console's `dev/manifest-dump.html` -// and reads `window.__MANIFEST`. `pnpm sdui:manifest` -// (scripts/gen-sdui-manifest.sh) is the wrapper: it builds objectui -// from the SOURCE at `.objectui-sha`, dumps, then runs THIS gate on it. +// (Playwright chromium) at `dev/manifest-dump.html` and reads +// `window.__MANIFEST`. `pnpm sdui:manifest` +// (scripts/gen-sdui-manifest.sh) is the wrapper — and it does NOT +// build objectui. It REQUIRES a checkout already vendored at +// `.cache/objectui-` by `pnpm objectui:build`, and exits 1 +// telling you to run that first (gen-sdui-manifest.sh 507-516). It +// then serves THAT tree with a vite dev server, dumps, and runs THIS +// gate on the result — so what it reads is the pinned SOURCE. // node `scripts/gen-sdui-manifest-node.mjs` writes the TRACKED repo-root // artefact under plain Node — no browser, no objectui build. It // enumerates the PUBLISHED `@object-ui/*` packages at the version named // in `scripts/sdui-manifest.record.json`. // // ⚠️ "The registry is a browser app so nothing enumerates it from Node" was true -// when this header was written and is now FALSE — measured in objectui#6741 and -// re-measured on 2026-08-30; the node producer's header carries the readings. +// when this header was written and is now FALSE — measured 2026-08-29, +// re-measured 2026-08-30 against published `@object-ui/*` 17.6.0, and reproduced +// byte-identically in review of #18608; the node producer's header carries the +// readings. ⛔ Do not put an issue number back on this line: the objectui +// citation this used to carry resolves to nothing — 404 for both the issue and +// the PR at that number, with three neighbouring objectui numbers answering 200 +// as controls — and the readings above stand without one. // // ⚠️ The two producers disagree TODAY, and the reason is the input, not the code: // objectui bumps its `version` only at release, so the version read off the pinned