Repository navigation
fix(spec): make the declaration-parity ratchet able to fail on a spec row with no manifest component - #19270
fix(spec): make the declaration-parity ratchet able to fail on a spec row with no manifest component#19270os-bill wants to merge 2 commits into
Conversation
… pre-accepted `check:react-declaration-parity` could not fail on its loudest signal. The baseline ratchet suppressed `missing` behind `state.missing && base && !base.missing`, so a block with NO baseline row could not regress: the gate printed the "NO component in the manifest" line and exited 0. The asymmetry was unintentional — the `registryOnly` axis is already ratcheted against an absent baseline row (an empty accepted set), only `missing` carried the extra conjunct. `missing` is now judged every run, baseline or not, and `--update` refuses to write a baseline while any block is missing — so the reflex that clears a fresh red cannot mint the `missing: true` acceptance either. The failure text names the upstream cure (expose the block on the registry public tier and regenerate, or drop the spec row) and states that a baseline row is never it. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
…on the hole The exit-code fixtures fed the gate a ONE-COMPONENT manifest, so twelve of the thirteen evaluated blocks were absent from every one of them. They passed only because an absent block with no baseline row could not regress — the fixtures were resting on the very hole this branch closes. They now declare every evaluated block, with the roster read off the gate's own report rather than restated, and `omit` spells out the absence when an absence IS the subject. New pins: an absent block with no baseline row reds and names itself; a `missing: true` baseline row does not silence it; `--update` refuses to write one; and two controls — the same run with the block present exits 0, and `--update` still writes when nothing is missing. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
📓 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): |
Contract reviewServed-tier: 1/1 CONTRACT_REVIEW_TIER Evidence: the card body and its triage ruling, the PR (diff, body, check-runs, one job log), ① Serves the card, and only that — the half that can be delivered here.
②
③ Sound, and nothing is left vacuous — with one body error and two costs to name.
Measured first-hand in this act: the card's zero and its lit controls on PASS Generated by Claude Code |
|
Provenance correction to contract-review record 5748831865 (same reviewer, 2026-09-20T09:05Z) — the control TREE label, not any reading. The pinned control worktree was re-pinned under this act — its reflog reads Why the readings stand for both trees: every input of the gate is byte-identical at Generated by Claude Code |
Closed unmerged — the maintainer re-affirmed ruling 丙: the declaration-parity ratchet retires
This PR taught ⛔ Closed by the seat on the maintainer's instruction, ⛔ not merged, ⛔ nothing reverted. The branch stays for its record. Generated by Claude Code |
…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>
Part of #18407
Clause-②: no
TL;DR
Regenerating
sdui.manifest.jsondoes not produceobject-tree, and no pin bump wouldchange that — measured, byte-identically, below. What this PR lands is the other half of the
card:
check:react-declaration-paritycan now fail on a spec row whose block has nomanifest component. It goes red on
object-treetoday, and that red is the deliverable, nota mistake — the repository-side cure is upstream in objectui and is named in the failure text.
for every PR in the repo. See "What has to happen before this lands".
Leg 1 — re-measured on fetched
origin/main(7d0f911), independentlyThe parser reads names, so the zero is a reading and not a failed search.
The other half, re-measured in
objectstack-ai/objectuiat the pinned53ded82bf7a494f54e344e19099dbf00854b8694(.objectui-sha, untouched by this PR):packages/plugin-tree/src/index.tsxregisters the same renderer twice —ComponentRegistry.register('object-tree', …)at line 34 andComponentRegistry.register('tree', …)at line 41. Both carry anamespace, neither carries atier. That checkout is shallow (
git rev-parse --is-shallow-repositoryanswerstrue); thepinned commit object is present, so every reading above is a blob read at a named commit, not a
windowed history query, and none of them needed the truncated history.
Leg 2 — regeneration is a byte-identical no-op
node scripts/gen-sdui-manifest-node.mjs(the generator that writes the tracked artefact; therepo's
pnpm sdui:manifestis the browser route and needs a vendored objectui build) was runagainst published
@object-ui/*17.6.0, the version the pinned commit declares:After the run, with
git add -Aperformed FIRST andgit diff --cachedread after it, themanifest was not in the diff at all:
The only thing the run changed was
generatedAtin the provenance record,2026-09-08→2026-09-20. The artefact is unchanged, so that record still describes it accurately; thedate-only churn was reverted and the tree is clean against
origin/main. Nothing in this PRhand-edits a generated artefact, and nothing in it touches
.objectui-sha.Leg 3 — what decides it: registered, but not public
The gate's own words are "NO component in the manifest — not registered or not public".
Measured against the same published 17.6.0 install the generator used, it is the second:
PUBLIC_BLOCKShas exactly 57 entries and the manifest has exactly 57 components — the publictier IS the manifest. The file and the lines that decide it, all in objectui at the pinned sha:
packages/core/src/registry/public-blocks.tslines 26–117'object-tree'nor'tree'among thempackages/core/src/registry/Registry.tsline 821for (const tag of PUBLIC_BLOCKS) add(tag, this.getContractConfig(tag));packages/core/src/registry/Registry.tsline 824if (cfg.tier === 'public' && !key.includes(':')) add(key, cfg);packages/plugin-tree/src/index.tsxlines 34–39 / 41–46namespace+label+category+inputs, and notier⇒ Both producers — the node generator and the browser dump — faithfully serialize a registry
that genuinely does not expose
object-treeon the public tier. The artefact is correct. Thedivergence is that a spec row expects a component the public tier does not carry. This
reproduces, independently, the measurement the
domain:specseat recorded on the card.What this PR changes
check:react-declaration-paritycould not fail on its loudest signal. The baseline ratchetsuppressed the
missingaxis behindWith no baseline row there is no
base, so a spec row whose block the public registry does notcarry arrived pre-accepted: the gate printed its
✗line and exited 0, and would have keptdoing so for as long as nobody regenerated the baseline. Measured on
origin/mainbefore thechange — the same run
lint.ymlperforms on every PR:…while the very same gate in plain
--strictmode (no baseline) already exits 1 on thatsame tree. The teeth existed; only the mode CI actually runs swallowed them.
The asymmetry is what makes this a bug rather than a policy:
registryOnlywas alreadyratcheted against an absent baseline row —
baseROfalls back to the empty set, so everyregistry-only input on an unbaselined block reports as new. Only
missingcarried the extraconjunct. (The comment sitting under that loop, "a brand-new block … is fine (purely additive
coverage)", was therefore not true of the code it described.)
So:
missingis judged every run, baseline or not. Amissing: truebaseline row does notbuy silence either.
--updaterefuses to write a baseline while any block is missing, naming the block. Thatis deliberate:
--updateis the one command that can mint an acceptance, and re-running it toclear a fresh red is the reflex this gate has to survive. The row it would write is exactly
the
missing: truethe spec(ui):ComponentPropsMaphas no rows forobject-map,object-ganttandobject-tree— add them from the renderers' read points (#7751 method) so 「以协议为准」 resolves for all five ladder blocks (objectui#8348 Q1, ruled C) #18305 round declined to write, in that round's own words "that wouldbe accepting a divergence rather than reporting it" — so the producer refuses rather than
the reviewer having to remember.
registry public tier (
PUBLIC_BLOCKS, ortier: 'public'on the registration) and regeneratewith
node scripts/gen-sdui-manifest-node.mjs, or drop the spec row. ⛔ Never a baseline row.⛔ No
missing: truebaseline row is added by this PR, andpackages/spec/react-declaration-parity.baseline.jsonis not touched.The fixtures were resting on the hole
The exit-code fixtures in
check-react-blocks-declaration-parity.test.tsfed the gate aone-component manifest, so twelve of the thirteen evaluated blocks were absent from every
one of them — including the control that claims "exits 0 when the manifest matches the accepted
baseline". They passed only because an absent, unbaselined block could not regress. They now
declare every evaluated block, with the roster read off the gate's own report rather than
restated (a literal list would rot the day a
ComponentPropsMaprow lands), andomitspellsout the absence where an absence IS the subject.
Reverse verification — both legs, on-disk proof, restored byte-identically
Run through
scripts/ablation-replace.mjs, from the committed state, so the red/green numbersare trustworthy and the restore has a real restore point:
&& base && !base.missingback8bda7e2d5e7f→d4bf6f71d12a✗ object-grid: NO component in the manifestfollowed by✓ no new DECLARATION divergence)--updaterefusal predicate8bda7e2d5e7f→d81336b2a156--updatepin; the "still writes when nothing is missing" control stayed greenBoth restored with
blob == HEAD (8bda7e2d5e7f)andgit diff HEADempty. No ablationartefact is left in the tree.
Checks — real exit codes
pnpm --filter @objectstack/spec buildpnpm --filter @objectstack/spec typecheckcheck:scripts-typecheck, which compiles both changed filespnpm --filter @objectstack/spec testcheck-react-blocks-declaration-parity.test.tsaloneeslint . --no-inline-config(the whole repo, not narrowed)--format jsoncheck:react-declaration-parity --baseline … --strictnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat49f7e0d23e, then run; list and logs in the report commentcheck:dual-build-cjs-loads,check:lean-entry-closure,check:type-check-debtPREREQUISITE NOT MET … NOT a pass: nothing was measured— they read a fullpnpm buildclosure. NOT MEASURED, not findingscheck:pm-dispatch-gatesscripts/pm/dispatch-gates.mjsThe red, in full:
Blast radius is exactly one block. Of the thirteen blocks this gate evaluates, four have no
baseline row (
object-gantt,object-map,object-timeline,object-tree— the committedbaseline's last write predates #18403, which added those
ComponentPropsMaprows), and onlyobject-treeis absent from the manifest. The other three are present and stay green.What has to happen before this lands
Lint & Repo Gatesis a required context, so merging this whileobject-treehas no manifestcomponent puts a standing red in front of every PR in the repo. Two routes, neither of which is
this seat's to pick:
'object-tree'toPUBLIC_BLOCKS(ortier: 'public'on theplugin-treeregistration), release, bump.objectui-sha, regenerate the manifest — thenthis PR is green and lands with it. That is the shape AGENTS.md already prescribes for a
change that breaks against the pinned sibling: it ships together with the sibling fix and the
pin bump, or it does not ship. ⛔
.objectui-shais held by open PR sdui-parser: port inert-quick-add and member-type-mismatch from objectui, re-record the lockstep and bump the pin #18723, so this seat didnot touch it; and note a pin bump alone would not help — the pinned SOURCE lacks the entry
too, measured above.
object-treerow fromComponentPropsMap, so the spec stopsdeclaring a block the public tier does not carry. That reverses one arm of the decision landed in
feat(spec): object-map, object-gantt and object-tree get ComponentPropsMap rows, derived from the renderers' read points (objectui#8348 Q1-C) #18403, and is not a seat's call.
⛔ Deliberately not offered as a third route: writing the
missing: truebaseline row. The#18305 round declined to write one for a stated reason, and this PR makes that refusal
mechanical rather than a matter of remembering.
Acceptance notes
#17735is a different cell on the same file (the tracked manifest vs the browser dumpdisagreeing on the fields the parity gate consults) and is out of scope here — it is not
addressed by this PR and remains open. The relevant half was measured only incidentally: both
producers agree about
object-tree, because both readgetPublicConfigs().scripts/sdui-manifest.record.jsoncarries ageneratedAtthat is now older than the lastrun which reproduced the artefact byte-for-byte. Noted, not filed: nothing reads that field,
and re-recording a date under an unchanged sha256 is churn on a generated provenance record.
@objectstack/spec'sfiles[]isdist, json-schema, liveness, prompts, llms.txt, README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, api-surface-declarations, spec-changes.json;packages/spec/scripts/**is innone of them. Grepping every one of those paths after a build for
missingRegression,MISSING_IS_NEVER_RATCHETED_AWAY,fullManifestFor,evaluatedBlockTypesandstillMissingreturns 0 files each, with positive controls
ComponentPropsMap→ 38 files andPageComponentSchema→ 50 files on the same corpus. This diff publishes nothing, so it takesskip-changeset.Generated by Claude Code