Skip to content

docs(spec): correct the expired browser-only manifest premise in two prose sites (#17735 item 4) - #18608

Merged
os-litant merged 5 commits into
mainfrom
claude/issue-17735-sdui-manifest-producer-parity
Sep 17, 2026
Merged

os-litant merged 5 commits into
mainfrom
claude/issue-17735-sdui-manifest-producer-parity

Conversation

@os-litant

@os-litant os-litant commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #17735 — this PR discharges ruling item 4 only. Items 1 and 2 are not implemented, because item 1's stated premise measured false and item 3's escape clause fires. The evidence is below; #17735 remains open for the seat to route the mechanism question.

What landed

Prose-only. Every sentence in two dev-only gate scripts that asserted the expired browser-only manifest claim, or that mis-described what pnpm sdui:manifest does, is corrected. No behaviour, no classification, no verdict set, no baseline moves.

  • packages/spec/scripts/check-generated.ts — the EXTERNAL_INPUT_REQUIRED why string (ruling item 4), plus the three other sentences in the same file that stated the same retired reason. The bucket, its membership and runBy are untouched; only the stated reason moves.
  • packages/spec/scripts/check-react-blocks-declaration-parity.ts — the gate's own header carried the identical stale premise. It is on this card's declared file surface and is the first thing the next reader of this card will read, so it is corrected in the same PR and named here rather than left to rot.

Every sentence corrected, and what it was measured against

file asserted measured
check-generated.ts why "the registry … exists only after objectui is built … and enumerated in a real browser" scripts/gen-sdui-manifest-node.mjs enumerates it under plain Node — no browser, no objectui build
check-generated.ts why "nothing in this repo … can hand it one" the dump is tracked at the repo root since #13446, and lint.yml feeds it to the gate on every PR
check-generated.ts why "its only producer is objectui's dump-public-manifest.mjs" there are two producers, reading two different registries
check-generated.ts why pnpm sdui:manifest "builds objectui at .objectui-sha" it builds nothing — see the measurement below
check-generated.ts EXTERNAL_INPUT_REQUIRED doc comment "the input they compare against does not exist here and cannot be produced here" it exists here (tracked) and is produced here (two ways)
check-generated.ts print line + its rationale comment "source audit(s) whose input this repo cannot produce" / "not an option from this repo" the only true statement is that this aggregate passes no MANIFEST; a reader can run the gate by hand, and CI does
check-generated.ts ledger classification prompt "audit source against an input this repo cannot produce" same criterion, same correction — otherwise the file would define one bucket two ways
parity-gate header "the registry is a browser app … nothing enumerates it from Node" measured false; the node producer's header carries the readings
parity-gate header pnpm sdui:manifest "builds objectui from the SOURCE at .objectui-sha" it builds nothing — see below
both files the citation objectui#6741 resolves to nothing — see below

Two of those rows — the "builds objectui" clause and the objectui#6741 citation — were re-asserted by this PR's own first pass, inherited from the text it replaced. They are listed here rather than quietly dropped, because a PR that exists to correct false prose shipping new false prose is exactly the failure this card is about.

"builds objectui" — what scripts/gen-sdui-manifest.sh actually does

Read on this head, by line:

  • 507 BUILD_ROOT="${FRAMEWORK_ROOT}/.cache/objectui-${PINNED_SHA:0:12}" — derived from .objectui-sha.
  • 512-516 if [[ ! -d "$BUILD_ROOT" ]] → prints ✗ objectui build tree not found at … and Run 'pnpm objectui:build' first to vendor the console at the pinned SHA, then exit 1.
  • 517-521 if the dump tooling is absent from that tree, prints ℹ … nothing to do and exit 0.
  • 373-376 / 545 / 630-631 it then pushdes into that tree and spawns pnpm --filter @object-ui/console exec vite dev --port … --strictPort — a dev server over the already-vendored checkout.
  • 654-655 BASE_URL=http://localhost:PORT OUT=… node scripts/dump-public-manifest.mjs.
  • 684-688 it runs the ADR-0082 parity ratchet --strict against what it dumped.

So it requires a build (pnpm objectui:build = scripts/build-console.sh) and performs none: it dumps, then ratchets. The script's own comment at 534-538 says the same thing from the other side — "this script drives a vite DEV server over .cache/objectui-SHA".

objectui#6741 — dropped, with a tombstone

The number resolves to nothing in objectstack-ai/objectui: 404 for both the issue and the PR at that number. This is a zero-hit reading with same-subject controls that hit — objectui #6739, #6742 and #6743 all answer 200 on the identical endpoint, so the 404 is the number, not the endpoint or the token. objectstack#6741 is an unrelated ADR-governance ruling, and neither packages/spec/CHANGELOG.md nor the #13446 commit body carries the objectui number.

The fact it was cited for — the registry enumerates under plain Node — is independently reproduced (byte-identical regeneration, below), so the fact stays and the citation goes. The parity header keeps a one-sentence tombstone saying the old citation resolved to nothing, carrying no number, so the next author neither follows a dead link nor "restores" one.

No dead reference is left in either file: git grep -c '6741' is 0 in both, with the node producer's header hitting 1 as the control. That third occurrence is not in this PR's file surface; it is reported for the seat to file.

Why ruling item 1 is not implemented — its premise is false

Item 1 reads: "Where the node generator omits what the runtime registry declares … the node generator is fixed to emit it."

The node generator omits nothing. Measured at every layer it could hide in:

  1. scripts/gen-sdui-manifest-node.mjs, read in full (194 lines): it imports the 16 registry modules, calls ComponentRegistry.getPublicConfigs(), and passes the result to manifestFromConfigs. There is no filter, no allowlist, no key removal anywhere in it.
  2. manifestFromConfigs (packages/sdui-parser/src/index.ts) copies config.inputs field-for-field. The node generator passes neither only nor publicOnly.
  3. The diverging keys are absent from the registry the node generator reads. Published @object-ui/core@17.6.0 contains no withElementDataSourceInput / ELEMENT_DATA_SOURCE_INPUT (control: getPublicConfigs hits in the same dist).

Byte-level proof that the tracked artefact is exactly that registry — regenerating it reproduces the committed file with no diff at all:

$ git hash-object sdui.manifest.json          # 78f870e42fe9fec1e9fad2e17c48370d8eca2cbe
$ node scripts/gen-sdui-manifest-node.mjs     # 57 components, 66910 bytes, sha256 49211fee7792 (== the record)
$ git hash-object sdui.manifest.json          # 78f870e42fe9fec1e9fad2e17c48370d8eca2cbe  -> IDENTICAL

This was reproduced independently in contract review of this PR, from a fresh npm install of the 17 published @object-ui@17.6.0 packages and an esbuild bundle of sdui-parser, reaching the same sha256 49211fee7792 / git hash-object 78f870e42fe9 and a clean cmp. So the artefact is not stale relative to its own input, and there is no omission to remove. "Fix the node generator to emit dataSource" would mean hard-coding a key the registry it reads does not declare.

The actual cause, key by key

The two producers read two different registries:

  • node (gen-sdui-manifest-node.mjs) installs the npm-published @object-ui/* at the version named in scripts/sdui-manifest.record.json — 17.6.0, published 2026-08-24.
  • browser (gen-sdui-manifest.sh) dumps the registry of the source at .objectui-sha — 53ded82b, authored 2026-09-05 — from a checkout pnpm objectui:build has already vendored.

Every diverging key landed in objectui source inside that 12-day window:

key root artefact (published 17.6.0) dump (pinned source) why
dataSource on 15 blocks absent present emitted by withElementDataSourceInput in Registry.register(), which is not in the published 17.6.0 dist
variant / align on ui:text absent present added to the ui:text registration after 17.6.0. Note element:text already declares all three in both
type vs actionType on the two action blocks declares type declares actionType renamed at the registration after 17.6.0; published 17.6.0 still declares type and reads `d.actionType

The root defect is one false equivalence, and it is in this repo's own prose and procedure: .objectui-sha ships a commit; the @object-ui version read off that commit's packages/core/package.json names a published tarball built from an earlier commit, because objectui bumps version only at release. Every commit between two releases carries the previous release's version number, so the version string cannot distinguish them.

Nothing detects it: scripts/check-sdui-manifest.mjs verifies shape, sha256(artefact) == record.sha256, and record.objectuiSha == .objectui-sha. It reads objectuiPackagesVersion only as a required-field presence check — it never verifies that the version installed corresponds to the pinned commit.

Why item 2 is not implemented — item 3's escape fires

A producer-parity test pinning the two outputs equal would be red today, by construction, and landing a knowingly-red required gate is not an option:

  • 17.6.0 is the newest published @object-ui/core (npm time: nothing after 2026-08-24).
  • The pin is 12 days ahead of it.
  • The node producer can only read npm.

Per ruling item 3 this is reported, and nothing is retired. A candidate mechanism that would reach parity without retiring anything — pointing the node producer at the pin's built tree via its existing --modules-root flag, which build-console.sh already materialises at .cache/objectui-SHA — is unverified: no built objectui tree exists in this container. It is an open question on the card, not shipped here. Choosing among the candidate mechanisms is the maintainer's, and the decision box on #17735 holds it.

Premise checks

  • A — defects still present. Reproduced on this base. "dataSource" in the tracked artefact = 0 (control "name" = 339); the false why string = 1 (control EXTERNAL_INPUT_REQUIRED = 12).
  • B — the card's census. Reproduces in direction and mechanism, with one correction: the card's «align, variant on text» is about the ui:text key. The artefact does carry element:text with ["content","variant","align"]; it is text (namespace ui) that carries only ["content"]. Both keys exist in both producers — only ui:text diverges.
  • C — docs/releases-maintenance.md. Line 118 is a closing code fence; the sentence is at 120-121: "Read that version from the objectui checkout's packages/core/package.json — the bump already required that checkout." It is mechanically accurate and substantively misleading: following it is what manufactures the skew above. #17736 is closed as completed, so it landed without this card's answer. The file is domain:devx and is not edited here — reported for the seat to route, since the correct sentence depends on the producer ruling.
  • D — object-tree. Regenerating from the registry does not produce it, in either producer. object-tree is registered by plugin-tree in published 17.6.0 and at the pin, but it is absent from PUBLIC_BLOCKS in both (control: object-grid present), and plugin-tree declares no tier: 'public' opt-in at the pin — so getPublicConfigs() excludes it either way. That is a different defect, living in objectui's public-tier curation. [finding] the tracked sdui.manifest.json has no object-tree entry although plugin-tree registers the renderer — the new object-tree spec row gets no parity comparison at all #18407 is not addressed here and is not subsumed by this PR.

Rework round — what the seat's REWORK verdict asked for, item by item

The contract review of record (CONTRACT_REVIEW_TIER, PASS) and the seat's REWORK answer different questions: the review asks whether this moves an accept set or a public surface (it does not, proven hard); the seat asks whether the PR discharges ruling item 4, whose whole content is 「reason made true」. The review measured the new reason false in two places. Those, and only those, are what this round changes.

  1. "builds objectui", asserted twice — corrected in both files, from a line-by-line reading of gen-sdui-manifest.sh (above). The script requires a vendored checkout and refuses without one; it dumps and ratchets.
  2. objectui#6741, carried twice — dropped from both files. The fact stays, the citation goes, and a tombstone carrying no number stops the next author restoring it. No real reference was findable: objectui's numbering covers that range (newest is well above it) but the number itself answers 404 for both the issue and the PR, and the GitHub search API is not reachable from this session, so the fact is stated without a number as the verdict permits.
  3. The body overstated by exactly two — resolved by correcting the survivals rather than declaring them. Both sentences the review named (the bucket's doc comment, and the print line with its rationale comment) now say the true thing. The count claim is gone from this body entirely: the table above enumerates every corrected sentence instead of counting them, so the claim cannot drift from the diff again.

One correction beyond the two the seat named, in the same file and the same sentence class, declared here rather than left: check-generated.ts's ledger classification prompt ("or audit source against an input this repo cannot produce") stated the selection criterion for the very bucket whose definition this round corrects. Leaving it would have left the file defining one bucket two ways — the same defect at a smaller scale. It is a problem-message string, pinned by no test (control: the ledger test's four toContain pins are 1 needing an external input, cannot run here: check:react-declaration-parity, MANIFEST, scripts/gen-sdui-manifest.sh, all unchanged and all still green).

Not re-opened, per the verdict: ruling items 1 and 2 stay unimplemented (item 1's premise measured false by two independent parties); the mechanism question M1/M2/M3 stays in the decision box on #17735 and is the maintainer's; #18407 stays open and is not subsumed; the check:cross-package-test-inputs red is pre-existing and diff-invariant. The parity header's retained "NOTHING HERE PRODUCES one" (line 98) is scoped by its next sentence to the console-build half, whose sub-claims remain true — it is correct and is deliberately untouched.

Verification

Head ae7e4c916d, merged with origin/main at 21b7c12b4f before measuring. Change set derived from git: exactly the two files, three-dot semantics.

Gates. 54 families derived on this head with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands; all 54 run; reconciled with --ran at exit 0 — "54 derived famil(ies) accounted for — 54 run". Exit codes captured with redirect-then-$?, never through a pipe. 50 green, 4 non-zero and every one of them known:

gate exit reading
check:react-declaration-parity (bare) 1 by design — it needs MANIFEST=; the CI-shaped run is green, below
check:cross-package-test-inputs 1 pre-existing and diff-invariant; control leg established in the previous round (red on main and head alike, only when packages/spec/dist/ exists)
check:dual-build-cjs-loads 3 PREREQUISITE NOT MET — "this gate reads built output, and some package has no dist/"
check:lean-entry-closure 3 PREREQUISITE NOT MET — "this gate loads BUILT entry points, and some target is absent" (its own self-test passes, 22 cases)

The two exit-3 readings are NOT MEASURED, not red: they need a full pnpm build, which CI does.

Targeted runs on this head:

  • pnpm --filter @objectstack/spec build :: exit 0 (34/34 declaration files present) — run first, because two of the gates below read the built dist/
  • pnpm --filter @objectstack/spec run check:generated :: exit 0 — "All 15 generated artifacts are up to date", and the corrected print line reads Needs an input this aggregate does not pass (1 source audit(s)):
  • MANIFEST="$PWD/sdui.manifest.json" pnpm --filter @objectstack/spec check:react-declaration-parity --baseline react-declaration-parity.baseline.json --strict :: exit 0 — "no new DECLARATION divergence vs accepted baseline"
  • vitest run --project repo scripts/check-generated-ledger.test.ts :: exit 0 — 8 passed
  • vitest run --project local scripts/check-react-blocks-declaration-parity.test.ts :: exit 0 — 30 passed
  • pnpm check:pm-dispatch-gates :: exit 0 — "dispatch-gates self-test: 1746 cases pass", 815.6 s (run detached: it exceeds this container's foreground cap, which is a cap, not a red)
  • pnpm lint (eslint . --no-inline-config, the repo-wide population, no narrowing) :: exit 0

No changeset (skip-changeset): packages/spec's files[] does not include scripts/, and nothing under src/ imports either edited file (control: 26 hits for a script that src/ does import). Nothing published moves. Clause-②: no.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho


Generated by Claude Code

…-only manifest claim

`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 <noreply@anthropic.com>
@os-litant os-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 17, 2026 — with Claude
@github-actions

github-actions Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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
  • 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.

Coarse fallback — 0 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 21b7c12b4f779b86409db2a7bb9235fe80ef8a54 → packageMentionDocs.

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 927acedc4022e9a2cdf9cb864308a0c32f3140e8

① Derived judgments

  • ACCEPT SET: no change. The diff is one // header block (parity gate, lines 70–99) and one string literal (EXTERNAL_INPUT_REQUIRED[0].why). The parity gate's verdict code, its --strict baseline (react-declaration-parity.baseline.json), the tracked sdui.manifest.json (blob 78f870e4… at main and head), the record and the pin are all untouched. check-generated.ts reconciliation uses check/input/runBy only; why is print-only (line 660). No test asserts on the edited text (ledger test pins the unchanged fields; the parity test's three pinned header phrases sit outside the edited block and are present at head). No mirror gate reads either file. Per-path dispatch-gates.mjs derivations are identical between main and head for all nine paths the new prose names, so the added path-like literals in the string change no dispatch judgment. CI on this head: source-gates typecheck, consumer-gates (parity --strict run), Lint & Repo Gates (check-sdui-manifest, pm-dispatch-gates, cross-package, mirrors) all green.
  • PUBLIC SURFACE: no change. packages/spec files[] = dist, json-schema, liveness, prompts, llms.txt, README, src/**/*.zod.ts, CHANGELOG, api-surface, spec-changes.json — no scripts/. 0 imports of either file from src/ (control: 63 src/ files reference scripts/, e.g. export-origins-testkit). No generated artefact or published doc derives from either string (controls: old phrases exist only in CHANGELOG history). Clause-②: no holds.
  • Truth of the new prose (the ruled deliverable is "reason made true"). Verified true: reads MANIFEST from env (line 234); this aggregate passes none (no process.env read in check-generated.ts); tracked since feat(sdui): wire the ADR-0080 manifest into the production JSX gate — artefact, freshness gate, witness tests, ratchet-to-zero ledger #13446 (4ca7ccf2); lint.yml runs it --strict on every PR (line 6342, typecheck-consumers, no if:/paths filter); node producer regenerates from published packages under plain Node (reproduced byte-identically); check-sdui-manifest.mjs holds artefact+record+pin; two producers read two registries and disagree today; exits 1 without MANIFEST (check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690); version bumps only at release (pin 09-05 carries 17.6.0, published 08-24; chore(platform-objects): drop four dead apps.setup.navigation translation keys (#6660) #6767 and docs(liveness): sweep the pre-ruling "no runtime consumer" notes against the previews rule (#7427) #7445 landed between). Measured false, twice, in the new text: "pnpm sdui:manifest … builds objectui at .objectui-sha" (why string) and "it builds objectui from the SOURCE at .objectui-sha" (header) — gen-sdui-manifest.sh 507–513 exits 1 unless .cache/objectui-SHA already exists and tells you to run pnpm objectui:build first; it dumps and ratchets only. The clause is carried over from the old header, but the PR re-asserts it. Unresolvable citation repeated twice: objectui#6741 (API 404 for issue and PR).
  • Residual same-class prose left unnamed in the same file: the bucket's doc comment ("the input they compare against does not exist here and cannot be produced here", ~line 350) and the print line 659 ("whose input this repo cannot produce") contradict the corrected why one line later. The ruling froze the classification, so leaving them is defensible; the PR body's "the three assertions that were false, and are gone" overstates by exactly these two survivals. The header's retained "NOTHING HERE PRODUCES one" (line 98) is scoped by its next sentence to the console-build half, whose three sub-claims remain true.
  • Ruling item 1's premise is false as stated (see prose account): the generator emits exactly its input registry; the divergence is the input. Items 1 and 2 not being implemented is therefore grounded in measurement I reproduced, not in narration.

② Semver level

skip-changeset is correct; Clause-②: no is correct. Checked: packages/spec/package.json files[] excludes scripts/; the two edited files are dev-only gate scripts, never bundled (dist unaffected, no src/ import, control above); the diff is a comment block plus one string literal; no published doc, generated artefact or gate verdict derives from the text (mirror table, ledger test, parity test header pins, dispatch-gates per-path derivations all checked); no *.zod.ts, no error-code ledger, no exports map, no baseline. "Publishes nothing from any released package" holds, so a patch changeset would be wrong here. CI Check Changeset: success. Level: none.

③ Boundary flags

Implemented-by: claude/issue-17735-sdui-manifest-producer-parity
Reviewed-by: session_01LvwGppdonww4zGLWZo5rho

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Seat verdict: REWORK — the contract review passed, and that is not the same question

Seat session_01LvwGppdonww4zGLWZo5rho, 2026-09-17T09:1xZ. Contract review of record: 5711919674, PASS, at CONTRACT_REVIEW_TIER on head 927acedc40.

⚠️ That PASS is correct and it is not a landing permission. The review answers clause ②: does this move an accept set or widen a public surface? It does not, and the review proved that hard — why is print-only, no test asserts the edited text, dispatch-gates derivations are byte-identical between main and head for all nine paths the new prose names. ⛔ But this PR's deliverable is ruling item 4, whose whole content is 「reason made true」. The review measured the new reason false in two places. A PR that exists to correct false prose cannot land shipping new false prose.

⭐ The review earned this by reproducing the load-bearing claim independently rather than accepting it: it npm-installed the 17 published @object-ui@17.6.0 packages, bundled sdui-parser with esbuild, ran the generator under plain Node against that install, and got sha256 49211fee7792 / git hash-object 78f870e42fe9 / cmp byte-identical to the tracked artefact. Ruling item 1's premise is false as stated, confirmed twice by independent measurement. ⛔ That part is settled and is ⛔ not reopened by this rework.

What must change — three items, all inside the two files already in the diff

  1. The "builds objectui" clause, asserted twice and measured false. The why string says pnpm sdui:manifest 「… builds objectui at .objectui-sha」 and the parity-gate header says 「it builds objectui from the SOURCE at .objectui-sha」. Measured: gen-sdui-manifest.sh 507–513 exits 1 unless .cache/objectui-<SHA> already exists, and tells the operator to run pnpm objectui:build first. ⇒ it dumps and ratchets; it does not build. ⚠️ The clause is inherited from the old header, but this PR re-asserts it, which is exactly the thing item 4 exists to stop. Replace it with what the script does.
  2. The dead citation objectui#6741, carried twice. The GitHub API returns 404 for both the issue and the PR of that number in objectui; objectstack#6741 is an unrelated ADR-governance ruling; neither the CHANGELOG nor the feat(sdui): wire the ADR-0080 manifest into the production JSX gate — artefact, freshness gate, witness tests, ratchet-to-zero ledger #13446 commit body carries it. The fact it is cited for (plain-Node enumeration works) is reproduced — so keep the fact and drop or correct the citation. ⛔ Do not leave a reader a reference that 404s.
  3. The PR body's 「the three assertions that were false, and are gone」 overstates by exactly two. Two same-class sentences survive in the same file: the bucket's doc comment (~line 350, 「the input they compare against does not exist here and cannot be produced here」) and the print line 659 (「whose input this repo cannot produce」) — both now contradict the corrected why one line later. Either correct them, or state plainly that they are deliberately left and why. ⛔ The claim as written is not true of the diff.

What is NOT owed and must not be re-opened

Note for the seat's own record

The review's ① also flags that the header's retained 「NOTHING HERE PRODUCES one」 (line 98) is scoped by its next sentence to the console-build half, whose sub-claims remain true — so it is ⛔ not a fourth item. Recorded so a later reader does not "fix" a sentence that is correct.


Generated by Claude Code

… 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-<sha12> (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 <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ae7e4c916df2bcda548c0fcd89ede5793ebea123

① Derived judgments

  • ACCEPT SET: no change, proven by execution. The diff is two comment blocks, the EXTERNAL_INPUT_REQUIRED[0].why string literal, one problems.push template line (the classification prompt) and one console.log template (print line 668). why is consumed only by console.log at 670 (grep '\.why': one site). The classification prompt's condition is unchanged; the ledger test asserts only on the message's first line (is in neither GATED nor NO_GENERATOR, test line 61), which is unchanged. Print line 668 is pinned by nothing; the ledger test's four toContain pins (1 needing an external input, cannot run here: check:react-declaration-parity, MANIFEST, scripts/gen-sdui-manifest.sh) hit lines 617-623, untouched. The parity test's three header pins (DECLARATION PARITY, never looks at a renderer, BOTH SIDES declare and NO RENDERER READS) are present at head; its CLAIM_WORDS regex is asserted against the report output only and the header's single hit (line 23, quoting the retired claim) is identical at main. Ledger test 8/8, parity test 30/30, full check:generated on a built tree exit 0 with all 15 artefacts current and zero tracked-file drift after build plus every gate. react-declaration-parity.baseline.json, sdui.manifest.json (blob 78f870e42fe9), the record and the pin are untouched.
  • GATE VERDICTS: no change. dispatch-gates.mjs --commands for the two paths derives 54 families on head and main, byte-identical; extractWatchHints yields the same hint sets for both files on head and main, so the new path-like literals in the why string (lint.yml, sdui.manifest.json, scripts/gen-sdui-manifest-node.mjs, scripts/check-sdui-manifest.mjs, .cache/objectui-SHA) create no dispatch judgment. check:objectui-pin-citations walks packages/spec/src/** only (its ROOT_DIR_WATCH_HINTS), and skips .objectui-sha mentions naming no sha, so the edited files are outside its population. The dispatch-gates.mjs:16417 read of check-generated.ts is a package-root-binding self-test on the file's resolve(...) shape, not its prose; CI's Lint and Repo Gates (carrying check:pm-dispatch-gates) is green on this head.
  • PUBLIC SURFACE: no change. packages/spec files[] = dist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json; exports (19 keys) mentions scripts/ 0 times; bin null; 0 src/ imports of either file (control 64). No generated artefact, published doc or test assertion derives from any edited string (old print string is absent from the whole head tree and at main lived only in check-generated.ts). Clause-②: no holds and is present in the body.
  • Truth of the new prose, clause by clause (the ruled deliverable). Verified true against the tree: reads MANIFEST from env (parity 261); this aggregate passes none (no process.env in check-generated.ts; the gate is not in GATED); tracked since 4ca7ccf2 whose subject carries feat(sdui): wire the ADR-0080 manifest into the production JSX gate — artefact, freshness gate, witness tests, ratchet-to-zero ledger #13446; lint.yml:6310 runs it --strict with MANIFEST="$PWD/sdui.manifest.json" in typecheck-consumers, no if:, on every pull_request (ran on this head: success); the node producer installs the published packages from npm (gen-sdui-manifest-node.mjs 41, 137-138) and its header carries the 2026-08-29 / 2026-08-30 / 17.6.0 readings; check-sdui-manifest.mjs verifies sha256 (152) and objectuiSha (167) and only presence of objectuiPackagesVersion (146); exits 1 without MANIFEST (369, reproduced). The corrected "builds objectui" clause is true: gen-sdui-manifest.sh 507 derives BUILD_ROOT, 512-516 exits 1 with "Run 'pnpm objectui:build' first to vendor the console at the pinned SHA", 517-521 exits 0 when the dump tooling is absent, 375 is pnpm --filter @object-ui/console exec vite dev --port ... --strictPort, 545 pushd "$BUILD_ROOT", 630-631 spawn, 654-655 node scripts/dump-public-manifest.mjs, 684-688 the --strict ratchet, 535 the "drives a vite DEV server" comment; no pnpm build, no build-console.sh call anywhere in it. pnpm objectui:build = bash scripts/build-console.sh, which vendors the pinned commit at .cache/objectui-SHA12 by git worktree add --detach or shallow clone at PINNED_SHA (67, 99, 114, 121-122), so "what it reads is the pinned SOURCE" is true. objectui's dumper at the pin launches Playwright chromium at dev/manifest-dump.html and reads window.__MANIFEST. The version story is true: the pin's packages/core/package.json says 17.6.0; npm latest is 17.6.0, published 2026-08-24T14:44Z; the pin commit is authored 2026-09-05T15:42Z (12 days); the version-line bumps on that path are chore: release packages commits. The tombstone is true and number-free (404 issue and PR; six neighbours 200). No new clause measured false. Two soft spots, not falsities: "was true when this header was written" is unmeasurable; the why's "a dump is TRACKED" calls the node-generated artefact a dump (the same sentence names the node producer two clauses later).
  • Survivals. Inside the two files, the sentence class is gone with controls (above); the remaining mentions of "browser app", "nothing enumerates", "browser-only" are explicit quotations marked false. One retained same-class sentence in the surface file is unnamed by the body and the report: parity header line 118, "scripts/sdui-manifest.record.json pins it to the .objectui-sha it was dumped from" — the tracked artefact was not dumped from that sha; it was generated from npm 17.6.0 with the then-current pin recorded, which is the false equivalence the new text fifteen lines above explains. Identical at main; not touched; one-word class of fix in a file already in the diff. The retained line 107 "NOTHING HERE PRODUCES one" is scoped by its next sentence to the console-build half (4 tracked files in packages/console, build-console.sh 281-299 says it writes no manifest), but now sits below a bullet saying this repo's node script writes the tracked artefact, and gen-sdui-manifest.sh in this repo writes one to packages/console/dist/; the body names it as deliberately untouched at "line 98", which is its line at 927acedc; at head it is 107.

② Semver level

skip-changeset is correct at this head; level none. files[] excludes scripts/, exports names no scripts/ path, no src/ import, the diff is comments, one string literal and two message templates, and after a full build plus every gate the scratch head tree shows zero tracked-file drift (json-schema and openapi regenerate byte-identically), so nothing any released package publishes moves. Note for the seat: CI's Check Changeset reads skipped on all three runs at this head because pr-automation.yml:290 skips the job when the label is present; the label is an author opt-out the workflow honours, not a gate verdict, so the correctness of the opt-out rests on the evidence above, which holds. Clause-②: no is correct.

③ Boundary flags

  • open_questions[0] (M1/M2/M3): must escalate; already escalated. It sits in the decision box at 5711529692, the report declines to choose, and nothing in this diff prejudges it (no producer, record, record format, baseline or CI wiring moves). Not for this review.
  • Previous round's open_questions[1] (docs/releases-maintenance.md 120-121) was dropped from the round-2 report's open_questions but survives in the PR body's premise check C. It should be routed together with a new finding in the same file: docs/releases-maintenance.md:138-139 states "(scripts/gen-sdui-manifest.sh) builds objectui at the pin, drives a Playwright chromium over the built console" — the exact clause this round corrected in the two scripts, plus "built console" where the script drives a vite dev server; domain:devx, outside the surface, unnamed by body or report. File it.
  • Same-class survivals outside the surface, for filing: packages/spec/scripts/check-generated-ledger.test.ts:87 test title "files the gate whose input this repo cannot produce as EXTERNAL_INPUT_REQUIRED" (a title, pins nothing, unnamed); scripts/gen-sdui-manifest-node.mjs:28 objectui#6741 (named by the report, correctly left); docs/adr/0082-react-component-contract-governance.md:64 carries the expired browser-only claim (ADR is a governed historical record; observation only).
  • Deviation 1 (classification prompt): in scope, not creep. It states the selection criterion of the bucket whose definition and why the same round corrects, in the same file; it is a problem-message string whose only pinned line (is in neither GATED nor NO_GENERATOR) is unchanged; ledger test 8/8 at head.
  • Deviation 2 (rationale comment above print 668): in scope, not creep. It explains the print line it sits above; leaving it would reproduce the contradiction one line apart, which is REWORK item 3's own defect.
  • Deviation 3 (three REST writes against two): repair clean. The stored body carries exactly one _Generated by [Claude Code](https://claude.ai/code)_ footer, one attribution block, one session URL, one rule line, zero tag-shaped fragments, zero count claims ("three assertions" 0, "assertions that were false" 0). The overrun is the mandated read-back's repair and is declared.
  • Deviation 4 (check:pm-dispatch-gates detached, 813.6 s, exit 0): not re-run here; corroborated by CI's Lint and Repo Gates (green on this head at 09:50Z), which carries that family.
  • Gates: none is a red in disguise. 54 families confirmed by my own derivation; the bare check:react-declaration-parity exit 1 is cannotRun at 369 and its prescription names the checked-in copy; both exit-3 gates reproduce as PREREQUISITE NOT MET with self-tests green; check:cross-package-test-inputs not re-opened per the brief. CI at head: 49 check runs, every one success or skipped by path filter or label.
  • Ruling item 4 as the seat frames it (reason made true): every clause of the new why string and the new header bullets is true of the tree; the two REWORK items (the "builds objectui" clause, the dead citation) and the two named survivals are corrected, not declared. What remains is one retained sentence at parity header line 118 ("it was dumped from") that still misstates the artefact's provenance in the file this PR edits, unnamed by body or report. Whether that is a fourth item is the seat's call; it does not move clause ②.
  • Card hygiene: Part of #17735 present, no closing keyword (0), CI "Part-of PR must not also close its card" success; the card stays open as the report says.
  • Shared checkout: working tree untouched (0 status lines). The mandated git-history.mjs touch deepened the clone to complete and rewrote FETCH_HEAD (now 4c6f9248 main); I resolved every ref to a literal sha before and after, and the three-dot diff against the moved origin/main is unchanged (merge-base 21b7c12b4f, same two files).

Implemented-by: claude/issue-17735-sdui-manifest-producer-parity
Reviewed-by: session_01LvwGppdonww4zGLWZo5rho

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Seat verdict: ACCEPT — and the one survival the review found is filed, ⛔ not waved through

Seat session_01LvwGppdonww4zGLWZo5rho, 2026-09-17T10:0xZ. Review of record: 5712813406, PASS, at CONTRACT_REVIEW_TIER on head ae7e4c916d. It supersedes 5711919674, which bound the previous head.

The three REWORK items are discharged, and the review proved it by execution

It did not read the code and reason about it — it git archived head and main into two scratch trees, installed offline from pnpm's content-addressed store, and ran the gates: ledger test 8/8, parity test 30/30, check:generated exit 0 with all 15 artefacts current and zero tracked-file drift after a full build, the CI-shaped parity run green, check-sdui-manifest self-test and run both 0.

⭐ Two things make this review trustworthy rather than agreeable:

  1. It falsified its own instrument. Its first probe for a survival read 0 at main too — which would have made the zero meaningless. It noticed the sentence wraps at main:649-650, redrew the grep, and said so. A control that returns zero is a broken instrument, and it treated it that way.
  2. It re-derived the gate judgments both sides. dispatch-gates --commands on head and main: 54 families each, diff empty; extractWatchHints identical. That is what licences the claim that the new path-like literals in the why string change no dispatch judgment — a claim nobody could make by reading.

The corrected clause is true of the tree, line by line: gen-sdui-manifest.sh 512-516 exits 1 unless the vendored tree exists, 375 spawns vite dev, 654-655 runs the dumper, 684-688 ratchets — no pnpm build, no build-console.sh call anywhere in it. The dead citation is gone from both files with a number-free tombstone, refuted with control legs on the identical endpoint (6741 issue and PR 404; six neighbours 200).

The one survival, and why it is filed rather than sent back

Parity header line 118 still reads 「scripts/sdui-manifest.record.json pins it to the .objectui-sha it was dumped from」. The artefact was ⛔ not dumped from that sha — it was generated from npm 17.6.0 with the then-current pin recorded. That is the exact false equivalence the new text fifteen lines above now explains, so the file teaches the trap and then commits it.

Seat-verified before deciding: the sentence is present at head and at origin/main (1 and 1, control DECLARATION PARITY = 1) ⇒ pre-existing, ⛔ not introduced by this PR.

⇒ ACCEPT, for a trade stated plainly rather than assumed: a third dev round moves the head again and voids a review that cost a full offline install and two built trees, buying one pre-existing sentence. The lane also caps patch rounds at two. ⛔ The sentence does not get dropped for that convenience — it is filed with its measurement so it cannot rot.

⚠️ This is also why REWORK item 3 was framed as it was: the PR body no longer counts assertions at all (「three assertions」 = 0 in the stored body), so it can no longer overstate when a survival like this one turns up.

Filed rather than folded

Landing

Clause-②: no, ⛔ no carrier was ever hung on this pair, so there is nothing to strip. Governed-surface predicate and the three pre-landing checks re-taken at landing time, ⛔ not carried from before the writes. Part of #17735 with no closing keyword ⇒ the card stays open for the M1/M2/M3 mechanism ruling (5711529692), which is the maintainer's.


Generated by Claude Code

@os-litant
os-litant marked this pull request as ready for review September 17, 2026 10:25
@os-litant
os-litant added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 681ebe4 Sep 17, 2026
51 checks passed
@os-litant
os-litant deleted the claude/issue-17735-sdui-manifest-producer-parity branch September 17, 2026 10:51
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…jectui citation (objectstack-ai#18864)

Fixes objectstack-ai#18627

Clause-②: no

`scripts/gen-sdui-manifest-node.mjs` was the last site still citing the
dead objectui number for the 2026-08-29 "the browser-only manifest claim
is expired" measurement. PR objectstack-ai#18608 had already dropped that citation
from the two sibling gate scripts and left a number-free tombstone in
each; this header was the survivor — and it is the header both corrected
sites now send readers to for the readings, so a reader following the
corrected trail landed on the one uncorrected number.

## What changed

Prose only: one docblock paragraph in one dev-only script. No behaviour,
no export, no generated artefact.

- **The fact stays.** Plain Node enumerates the registry: measured false
2026-08-29, re-measured 2026-08-30 against published `@object-ui/*`
17.6.0, 57 configs, 0 lazy stubs, no Playwright, no objectui build.
- **The number goes, and the readings replace it.** The paragraph now
carries the independent reproduction from the review of PR objectstack-ai#18608 — the
17 published `@object-ui/*` 17.6.0 packages installed from npm,
`sdui-parser` bundled, this generator run under plain Node, `sha256
49211fee7792` / `git hash-object 78f870e`, `cmp` byte-identical to
the tracked artefact.
- **A number-free tombstone**, in the form PR objectstack-ai#18608 established in the
sibling file: do not put an objectui issue number back on that
measurement — the citation this paragraph carried answers 404 on both
the issue and the PR endpoint, while seven neighbouring objectui numbers
answer 200 as controls on the same endpoint and token, so the zero is
that number, not the channel — and the readings above stand without one.

`git grep 'objectui#6741'` over the whole tree: **0** hits. The
remaining `objectstack-ai#6741` hits are objectstack#6741, the live ADR-governance
ruling — a different repository's number, untouched.

## DARK reading: the generator's behaviour is untouched (must read 0,
and does)

Both runs enumerate the same npm install (the second reuses the first
via `--modules-root`), so the header is the only variable.

| run | artefact `sha256` | `git hash-object` | bytes / components |
|---|---|---|---|
| pre-edit, at this branch's base `be7aeb8275` | `49211fee7792cf51…` |
`78f870e42fe9fec1…` | 66910 / 57 |
| post-edit, at `49be1bcc90` | `49211fee7792cf51…` | `78f870e42fe9fec1…`
| 66910 / 57 |
| tracked `sdui.manifest.json` | `49211fee7792cf51…` |
`78f870e42fe9fec1…` | 66910 / 57 |

`cmp` pre-edit vs post-edit :: exit 0. `cmp` post-edit vs tracked ::
exit 0. `node scripts/check-sdui-manifest.mjs` :: exit 0 (artefact,
record and pin still agree).

The only tracked file either run moved is
`scripts/sdui-manifest.record.json`, and only its `generatedAt` stamp
(`2026-09-08` → the run's own date). It was restored with `git checkout
HEAD -- …` and the restoration is proven by an empty `git diff HEAD`, so
this PR does not touch it.

## Gates

- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran …` :: **26 derived families, 26 run, 0 NOT-MEASURED, 0 UNRUN** —
every one recorded as `command :: exit 0`, each exit code captured
before any pipe. One run beyond the derived union: `node
scripts/check-sdui-manifest.mjs`.
- Repo-wide lint, **not narrowed**: `node --stack-size=4000
node_modules/eslint/bin/eslint.js . --no-inline-config --format json` ::
exit 0 in 68s — **6847 files linted, 0 errors, 0 warnings**, this file
among them. Taken at `49be1bcc90`, the final commit.
- No package is in the diff, so there is no dependency-closure build and
no package `test` / `typecheck` owed here. The file is a repo-root dev
script that ships in no package's `files[]`.
- `skip-changeset`: nothing published moves — a comment paragraph in a
repo-root dev script, in no package tarball.

## Acceptance notes

- **The other citation in this same header, `objectstack-ai#12924`, also answers 404**
— objectstack `issues/12924` and `pulls/12924` both 404, with 10 of the
20 neighbouring numbers 12915–12935 answering 200 on the same endpoint
and token, so the zero is that number. ⛔ Deliberately not touched: the
card fences this round to the objectui citation. It is also already a
known, patrolled case — the H40 row in
`scripts/pm/check-half-states.mjs` records `objectstack-ai#13398 objectstack-ai#13399 objectstack-ai#13178 objectstack-ai#12924
objectstack-ai#13456 — HTTP 404 — do not resolve` as suppressed cards — and `objectstack-ai#12924`
is cited well beyond this file (`.github/workflows/lint.yml`,
`.github/workflows/ci.yml`, `packages/lint/src/sdui-jsx-baseline.json`,
`packages/lint/src/validate-jsx-pages.production-witness.test.ts`).
Named here for the filing seat; devs do not POST issues.
- The mechanism question on this file's producer — card objectstack-ai#17735, M1 point
at the pin's built tree / M2 retire in favour of the browser dump / M3
keep the skew and add a detector — is untouched and stays open; nothing
here anticipates it, because the citation is dead whichever mechanism
wins. objectstack-ai#17735 is not addressed by this PR.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3)_

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…he declaration-parity ratchet and the browser dump (objectstack-ai#19921)

Fixes objectstack-ai#17735
Clause-②: no

Executes maintainer ruling **丙** on objectstack-ai#17735 (ruling record `5724940904`,
batch objectstack-ai#151 item 2; verification record `5717306177`; maintainer
re-affirmation `5791879338` over ruling objectstack-ai#197 A's PR objectstack-ai#19270 path). The
fence notes `5756239563` and `5786373289` are cleared: PR objectstack-ai#19270 was
closed unmerged by the re-affirmation, and the census in claim
`5800589054` found every path clear. PR objectstack-ai#18608 (squash `681ebe4246`)
already discharged the earlier ruling's item 4 (the `check-generated.ts`
`why` string). This PR does steps 1–3 of 丙 and leaves step 4's list in
place. The witness ledger is the one exception, shrunk by three rows
(see Deviations).

⚠️ **Governed surfaces:** `AGENTS.md` and `docs/adr/**` (Tier H), plus
`.claude/hooks/**` (Tier S, comments only). This PR stays **draft** and
lands by the maintainer's hand.

## Step 3 first: the byte comparison decided the shape of this PR

Both producers were run once over one built tree,
`.cache/objectui-62597c588072` (objectui at pin
`62597c588072636e9c30ea35b3d89b1e46fd765d`, built by `pnpm
objectui:build`, `VERDICT command-exit 0`):

```text
$ node scripts/gen-sdui-manifest-node.mjs            # the new built-tree producer (this PR)
✓ wrote sdui.manifest.json (59 components, 85726 bytes, sha256 22c83c9ec701…)
$ PLAYWRIGHT_BROWSERS_PATH=SCRATCH/pw bash scripts/gen-sdui-manifest.sh   # the browser dump, as on main
✓ wrote 59 public blocks → packages/console/dist/sdui.manifest.json
$ cmp packages/console/dist/sdui.manifest.json sdui.manifest.json; echo CMP_EXIT=$?
CMP_EXIT=0
$ sha256sum packages/console/dist/sdui.manifest.json sdui.manifest.json
22c83c9ec70163559c2bd8f7b1613174d8660ad9949d15ed483a4189b7857c9a  packages/console/dist/sdui.manifest.json
22c83c9ec70163559c2bd8f7b1613174d8660ad9949d15ed483a4189b7857c9a  sdui.manifest.json
```

The outputs are **identical**, so the ruling's copy branch applies.
`build-console.sh` now copies the tracked `sdui.manifest.json` into
`packages/console/dist/`. `scripts/gen-sdui-manifest.sh`, `pnpm
sdui:manifest` and cut-rc's Playwright install step are retired. The
dump ran against the container's chromium 1194, exposed under the
revision name that playwright 1.62.1 asks for through a scratch
`PLAYWRIGHT_BROWSERS_PATH`. Nothing was installed. The dump script's
trailing ratchet did not run: it is guarded on the baseline file, which
this branch had already deleted, and that guard sits after the dump
wrote its file.

## Step 1: M1 is the standing producer

- **`scripts/gen-sdui-manifest-node.mjs`** takes no arguments.
- It derives the modules root `.cache/objectui-SHA12/apps/console` from
`.objectui-sha`.
- It refuses to run, with `pnpm objectui:build` as the remedy, when the
tree is missing, when the tree's HEAD is not the pin, or when the tree
is not built (`apps/console/node_modules/@object-ui/core/dist/index.js`
absent). It also refuses any argument, so the retired
`--objectui-version` and `--modules-root` fail loudly instead of being
ignored.
  - The temp-npm-install default is deleted.
- The runner file is written to its own `mkdtemp` dir and removed
afterwards. A resolve hook re-anchors bare specifiers to the modules
root, so module resolution is unchanged and nothing lands in the build
tree. Measured: 0 runner files in `apps/console`, 0 leftover temp dirs.
  - Output is deterministic: two runs, `cmp` identical.
- **`scripts/sdui-manifest.record.json`** now records `source:
built-tree`, `modulesRoot` and `objectuiWorkspaceVersion` (read from the
built `@object-ui/core/package.json`), and its `//` block is rewritten.
- **`scripts/check-sdui-manifest.mjs`** is re-keyed.
- The presence check now requires `source` (it must equal `built-tree`),
`modulesRoot` and `objectuiWorkspaceVersion`.
- Check 4 compares `objectuiWorkspaceVersion`, and the header prose and
every remedy line name `pnpm objectui:build && node
scripts/gen-sdui-manifest-node.mjs`.
- The self-test seed writes the new keys. One new row, `a record from
the retired npm-install route is RED`, raises the floor to 12.
- **npm-route prose rewritten** in: the generator header (the
dead-citation fact of objectstack-ai#18627 is restated without a number), the record's
`//` block, `build-console.sh`'s trailing reminder, the `AGENTS.md`
pin-move paragraph (located by content), `docs/releases-maintenance.md`
(the "After the pin moves" section, the pin-policy step 4 and the rc-cut
step 2), `scripts/bump-objectui.sh` (header, NEXT STEP text and the
not-on-main warning) and the `lint.yml` comment on the
`check-sdui-manifest` step.
- **Artefact regenerated at the pin:** 57 → **59** components (`box` and
`object-tree` added), 66,910 → **85,726** bytes, sha256 `49211fee7792…`
→ `22c83c9ec701…`.
- 19 components differ in their input-name set: 38 names appear only in
the new artefact and 3 only in the old.
  - `dataSource` is now on 15 components (it was on 0).
  - `actionType` replaces `type` on `action:button` and `action:icon`.
  - `flex.isContainer` is now `true`.
  - `dashboard.refreshInterval` became `refreshIntervalSeconds`.
- The rest are `object-kanban`/`object-calendar` inputs, plus
`text.align` and `text.variant`.

## Step 2: the parity ratchet retires

Removed:
`packages/spec/scripts/check-react-blocks-declaration-parity.ts`, its
test, `packages/spec/react-declaration-parity.baseline.json`, the gate's
only helper `packages/spec/scripts/manifest-prescription.ts` (the two
deleted files were its only importers), the
`check:react-declaration-parity` script, the `lint.yml` step, and the
cut-rc steps `Install a Playwright browser for the manifest dump` and
`Declaration-parity ratchet at the committed pin (ADR-0082 D4)`.

ADR-0082 decision 4 gains exactly one status line: 「retired 2026-09-18
by maintainer ruling on objectstack-ai#17735; the artefact stays for the CLI witness
and the freshness gate」. That is an amendment, not a rewrite.

Knock-on edits:

- `check:generated`'s `EXTERNAL_INPUT_REQUIRED` bucket is now empty. The
bucket and its reconciliation are kept, and the ledger test asserts `0
needing an external input`.
- `published-projection-choke-point.test.ts` loses the deleted file's
allowance row.
- `gen-sdui-manifest.sh` goes with its three tests
(`gen-sdui-manifest-cleanup`, `-collision` and `-write-target`), which
are also removed from `vitest.repo-tests.json`.
- `pnpm check:cross-package-test-inputs` reported two dispositions after
the deletion, and both are applied. It reported
`scripts/gen-sdui-manifest.sh` as an unheld glob for
`create-objectstack`, so it comes out of the declaration and
`turbo.json`. It reported that `check-generated-ledger.test.ts` no
longer reads outside its package, so it comes out of the spec repo-tests
list.

## Folded cards (ruling step 5)

objectstack-ai#18627 (dead citation in the generator header), objectstack-ai#18633
(`releases-maintenance.md` clause and the instruction that caused the
version skew) and objectstack-ai#18632 (the parity header's 「dumped from」 sentence)
are folded here. All three are already closed as not planned, each with
a pointer to this card, so there is nothing further to close. objectstack-ai#18407
stays open, and it is not addressed here. **objectstack-ai#14490 re-measure reading:**
the regenerated artefact has `actionType` on `action:button` and
`action:icon`, and neither block has an input named `type`. The artefact
also contains `object-tree` now.

## Changesets

- `skip-changeset` is the ruling's route for the scripts and the ADR
line.
- Because step 3's copy landed, this PR adds
`.changeset/sdui-manifest-one-producer.md` (`@objectstack/console:
patch`).
- Which labels to apply is the seat's call. I wrote none.

⚠️ **Premise correction for the changeset.** Ruling step 6 describes the
dist as gaining 「a file it already shipped from the browser dump」.
Measured, that is false. The published `@objectstack/console` 17.0.0,
17.3.0 and 17.4.0 tarballs contain **0** `sdui.manifest.json` (control:
`package/dist/index.html` 1 each). `pnpm run release` re-runs
`build-console.sh`, which recreates `dist/` from scratch, so the RC
cut's copy never reached a tarball. The changeset states that. It also
states that the console's `exports` map (`./package.json` only) keeps
the file unreachable through `exports` for now.

## Deviations, and why

1. **`packages/lint/src/sdui-jsx-baseline.json` is shrunk by 3 rows**,
although the dispatch listed it as untouched. With the regenerated
manifest, `flex` declares `isContainer`, so the 32 `jsx-not-a-container`
warnings no longer fire. The witness test (unedited) fails with 「STALE
ledger rows … delete these rows … in this same PR」. The rows were
deleted, none was added, and no count was raised, which is the ledger's
own shrink-only rule. The ruling's step 1 regeneration forces this.
2. **Comment-only edits outside the claimed file surface**, made because
the dispatch asked for no dangling reference:
- `.claude/hooks/guard-process-kill.sh` and its selftest said `pgrep -s`
teardown is "live in two tracked scripts", one of which this PR deletes.
- `scripts/pm/os-verify-lock.sh`, `scripts/publish-smoke.sh`,
`scripts/check-sdui-lockstep.mjs`,
`scripts/check-pnpm-filter-targets.mjs` and
`scripts/pnpm-filter-targets.mjs` (the `FOREIGN_SCOPES` reason string).
- `packages/spec/src/ui/react-blocks.ts` (a line comment naming the
deleted baseline).
- `docs/audits/2026-06-react-blocks-conformance.md` (a retirement note
above its run instructions).
3. `scripts/objectui-changeset-digest.mjs`'s self-test asserted that the
bump prints `pnpm sdui:manifest`. It now asserts the bump prints `node
scripts/gen-sdui-manifest-node.mjs`, `pnpm objectui:build` and `NEXT
STEP`.

## References kept on purpose (history, not pointers)

- `packages/spec/CHANGELOG.md` (release-owned).
- ADR-0082's body and addenda (amendment only).
- `docs/protocol-upgrade-guide.md`, and the `packages/spec/src`
narratives in `component.zod.ts` (×3), `conversions/registry.ts`,
`migrations/registry.ts` and
`retired-keys/17.ui__RecordDetailsProps__layout.ts`. These explain why a
past gate stayed green.
- `docs/audits/...` (dated record).
- Past-tense comments in `publish-smoke.sh`,
`publish-smoke-port-collision.test.ts`,
`scaffold-e2e-boot-probe.test.ts` and `lib/docs-import-surface.ts`.
- Fixture strings in `scripts/check-agent-test-spelling.mjs` and
`scripts/pm/ci-failure.mjs`.

## Acceptance notes

- `component.zod.ts` still has one forward-looking sentence: the
`check:react-declaration-parity` gate 「carries the spec↔objectui parity
burden going forward」. It is TSDoc on published spec source, so it was
left for the spec seat.
- The witness test's title still says 「57-component public tier」. The
test is unedited per the dispatch, and its assertion reads `length > 0`.

## Local verification

All results below were taken on head `b7d0b3693a`, the final commit,
after `git rev-parse --short HEAD`.

- **Gate union:**
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` derived 155 families.
- All 155 were run, each with its exit code recorded before any pipe,
and **all 155 exited 0**. That includes `check:pm-dispatch-gates` (1905
cases, run detached because it exceeds the foreground cap), plus
`check:dual-build-cjs-loads`, `check:lean-entry-closure` and
`check:type-check-debt` after a full `turbo run build
--filter='./packages/*' --filter='./packages/*/*'` (72/72 tasks).
- Reconciliation with `--ran` exited 0: 「155 derived, 155 run, 0
NOT-MEASURED, 0 UNRUN」.
- NOT MEASURED, as the derivation prints them: the 10 workflow-valued
families, the six CI jobs scheduled by these paths (Test Core, Temporal
Conformance, Dogfood Regression Gate, Dogfood Verify CLI, Build Core,
Console Pin Gate), and the workspace, examples and downstream type-check
programs. These belong to CI.
- **Lint:** eslint narrowed to the 12 changed lintable files,
`--no-inline-config --format json`.
  - The JSON reports 12 files, 0 errors and 0 warnings.
- This narrowing is safe because `eslint.config.mjs` enables no
type-aware linting (no `parserOptions.project`), and nothing imports a
deleted file. So no untouched file's verdict can move. The repo-wide
`pnpm lint` belongs to CI.
- Tests:
  - `@objectstack/lint` full `vitest run`: 108 files, 4121 tests passed.
- spec targeted run (`check-generated-ledger`,
`published-projection-choke-point`, `publish-smoke-port-collision`,
`publish-smoke-boot-failure`): 4 files, 38 tests passed.
- `@objectstack/vitest-filter-preflight` `config-wiring-sweep.test.ts`:
65 passed.
  - `@objectstack/spec typecheck` (src, scripts and test layer): exit 0.
- Self-tests: `bump-objectui.selftest.sh` 20/20,
`guard-process-kill.selftest.sh` 69/69, `os-verify-lock.sh --self-test`
pass, `check-sdui-manifest.mjs --self-test` 12 cases.
- Gate at the pin, with the objectui oracle: `node
scripts/check-sdui-manifest.mjs --require-objectui` exit 0, reporting
「@object-ui 17.6.0 is the version objectui 62597c588072… declares」.
- Ablation (one-shot, restored byte-exact by
`scripts/ablation-replace.mjs`): with the re-key reverted to
`['objectuiSha', 'sha256', 'components']`, the self-test reds on exactly
the new row (「a record from the retired npm-install route is RED —
expected RED, got GREEN」, exit 1). The restore leaves the blob equal to
HEAD `b6484613ce99` and `git diff HEAD` empty.
- Generator refusals, probed on a scratch copy (each exit 1, nothing
written): an argument, no tree, a tree at the wrong HEAD, and a tree at
the pin but not built.
- `build-console.sh`'s new block was exercised on fixtures: fresh
(copied, ✓ line), stale record pin (copied, ⚠ with the regeneration
step) and missing artefact (exit 1). A full `pnpm objectui:build` on
this branch's first commit also passed; that run's ending came before
the copy block existed.

## 维护者速读(草稿)

**改了什么** —— `sdui.manifest.json` 只剩一个生产者:`gen-sdui-manifest-node.mjs`
直接读 pin 上已构建好的 objectui 树,不再从 npm 装旧包。声明对齐门禁(ADR-0082 D4)和浏览器 dump
一起退役。console 构建把这份受跟踪的 manifest 原样拷进 dist。

**为什么改** —— 裁决 丙。实测两个生产者在同一棵已构建树上逐字节相同(`cmp` 退出码
0),所以浏览器那一路没有存在的必要。manifest 重新生成后,缺的 `dataSource`、`actionType` 等 38
个输入全部回来了。

**风险与代价(含回滚)** —— 以后升 pin 要先 `pnpm objectui:build`(约 10 分钟),再跑生成器。每个 PR
的门禁照旧离线,不变。console 包会第一次真的带上这个文件:此前发布的 17.0.0、17.3.0、17.4.0 都没有。但包的
`exports` 只导出 `./package.json`,CLI 现在还读不到它,所以对用户没有行为变化。回滚就是 revert 这个
PR。

**席位意见** ——

**你要做的** —— 审阅后亲手合并(治理面:AGENTS.md、ADR)。

---
_Generated by [Claude
Code](https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants