Skip to content

Commit 46dac81

Browse files
claude[bot]claude
andauthored
docs(agents): state the tracked root SDUI manifest and the per-PR parity run (#17733)
Fixes #15367 `AGENTS.md` carried a sentence family describing an input this tree no longer lacks: the `check:react-declaration-parity` gate was said to have objectui's browser dump as its only right-hand side, to be unrunnable here, and to be forbidden from any workflow. CI has contradicted that last clause since the manifest landed. Per the recorded ruling (decision batch #91, option A — the wiring is right and the rule is obsolete), both paragraphs are corrected, and the correction is taken only after the ruling's precondition measurement. ## The ruling's precondition, measured first The ruling conditions the correction on comparing the tracked root artefact with a real browser dump input-for-input, "because today the ratcheting half (`registryOnly`) reads 0, the configuration in which an input mismatch is least visible". Produced on `431c757` in a worktree: `bash scripts/build-console.sh` built objectui at the pinned `.objectui-sha` `53ded82bf7a494f54e344e19099dbf00854b8694`, then `bash scripts/gen-sdui-manifest.sh` drove a real Chromium over it and wrote `packages/console/dist/sdui.manifest.json` (73,194 bytes). Both ran under the shared verify lock: `os-verify-lock: VERDICT command-exit 0 · held the lock 22s` for the dump step. The first attempt failed on a Playwright build-revision lookup gap (installed `chromium_headless_shell-1194`, playwright 1.62.1 wants `1234`); the remedy already recorded in `docs/releases-maintenance.md` "If the dispatch container's Playwright browser doesn't match the revision" — a scratchpad symlink tree, never under `/opt/pw-browsers` — resolved it unchanged. ⛔ No `playwright install` was run. Compared over exactly what the gate consumes. `manifestInputs()` in `packages/spec/scripts/check-react-blocks-declaration-parity.ts` reads `manifest.components[schemaType]` (bare key, or a key ending `:schemaType`) and then `inputs[].name` — nothing else per input. So the basis is: the set of component keys, and per component the set of input names. **Verdict: DIFFERS on the consumed fields.** | basis | reading | |:--|:--| | component keys | 57 vs 57 — **0** only in root, **0** only in dump | | components whose input-name set differs | **18** of 57 | | input names only in root | **2** (`type` on `action:button` and `action:icon`) | | input names only in dump | **19** (`dataSource` on 15 components; `align`, `variant` on `text`; `actionType` on the two action blocks) | **But the gate's verdict set is identical under both inputs.** Running the CI invocation against each manifest in turn, `--baseline react-declaration-parity.baseline.json --strict`: ``` MANIFEST=.../sdui.manifest.json -> exit 0 MANIFEST=.../packages/console/dist/sdui.manifest.json -> exit 0 blocks declared-by-both spec-only registry-only node-level root artefact 9 119 90 5 2 browser dump 9 119 90 5 11 ``` Both print `✓ no new DECLARATION divergence vs accepted baseline` and `Summary: 90 spec-only divergences, 0 blocks missing from the registry`. Per block, the `declared by both` / `spec-only` / `registry-only` triples are byte-identical. The whole divergence lands in the **node-level** bucket — the nine extra entries are `dataSource`, which the gate classifies as accepted at node level and which feeds neither the ratchet nor any verdict. The remaining consumed-field differences (`text`, `action:button`, `action:icon`) sit in components the gate does not judge at all. ⇒ Nothing here narrows the `--strict` verdict set, and this PR does not touch it: that file is `domain:spec`. What the measurement does record is that the root artefact is systematically missing `dataSource` and spells `type` where the dump says `actionType`, so the two producers are not interchangeable — a future registry change on one of those names would be invisible in the artefact CI reads. That belongs to the spec lane as its own card. ## The correction Two paragraphs, both in `AGENTS.md`: - the `check:react-declaration-parity` paragraph in *Touched `packages/spec`? Regenerate its artifacts BEFORE pushing* — now names the tracked repo-root `sdui.manifest.json`, its generator, its provenance record, the freshness gate that holds it honest in the required lint job, and the per-PR `--strict` run. Kept: "exits 1 with no usable manifest — could not run is a failure, not a skip" and the prohibition on re-adding a skip. Kept as a measured fact, not dropped: `check:generated` still files the gate `EXTERNAL_INPUT_REQUIRED`, because that aggregate still hands it no manifest. Dropped: "do not wire the gate into a workflow either", which CI contradicts. - the pin-bump paragraph in *Frontend (Studio UI)* — the same false claim in the same file ("never a CI job", "the pin bump is the ratchet's trigger, and its only one"). It now names the regenerator the freshness gate actually reds on, in the spelling `scripts/check-sdui-manifest.mjs` itself prints, and keeps `pnpm sdui:manifest` as the separate browser dump it is. Correcting only the CI-job half would have left this paragraph naming a different producer than the paragraph above. `docs/releases-maintenance.md` carries the same producer confusion and is **not** touched here: it is a `domain:devx` page and gets its own card. ## Budget and gates `AGENTS.md` 1075 lines before, 1075 after (ceiling 1075, headroom 0) — net zero, paid by the deleted prohibition and the deleted cross-reference rather than by re-wrapping. `✓ check-skill-line-ratchet: AGENTS.md is 1075 lines (ceiling 1075; headroom 0).` All 14 gate families derived for this diff by `node scripts/pm/dispatch-gates.mjs --commands` ran green (exit 0 each), plus `node scripts/check-published-list-mirrors.mjs` (`OK: 1 published list mirror(s) match their constants line for line`). `node scripts/pm/check-governed-merges.mjs --test AGENTS.md` — exit 3, `⛔ GOVERNED — a human merge is the review record for this PR`. ## 维护者速读(草稿) **改了什么** — `AGENTS.md` 两段散文。一段说这个 React 声明一致性检查「在本仓根本跑不了、也不要把它接进 CI」,另一段说它「永远不是 CI 作业,只在 objectui pin 变动时按需跑」。两句都改成实况:它读的是仓库根那份 被跟踪、带防篡改记录、由必需 lint 作业守新鲜度的 `sdui.manifest.json`,并且每个 PR 都以 `--strict` 跑。 「没有可用清单就 exit 1,那是失败不是跳过」以及「⛔ 不要靠重新加 skip 来消红」两条保留。顺带把 pin 变动 那半句改成真正被门禁盯着的那条重新生成命令。 **为什么改** — 一条具约束力的规则正被 `main` 上的 CI 违反,而且已经造成实测伤害:有开发者读了同类的陈述并 把「这个检查跑不了」写进自己的 PR 说明。裁决(决策批次 #91)选了 A:接线是对的,规则过时了。 **风险与代价(含回滚)** — 纯散文,零代码、零产物、不发布任何东西,行数净增为 0。回滚 = revert 这一个提交。 唯一的判断成本是:裁决要求的前提测量结果是「两份清单在门禁读取的字段上不相等」(18/57 个组件的输入名集合 不同),但门禁的判决集在两份输入下逐块相同,差异全部落在不上棘轮的 node-level 桶里。⇒ 本 PR 不收窄判决集, 把那个不等价作为 spec 车道的独立卡记录下来。 **席位意见** — **你要做的** — 受管面:请人工合并。⛔ 没有席位会把它翻成 ready、入队或挂 auto-merge。如果你认为「两份清单 不等价」这件事应当先由 spec 车道处理完再合这段散文,请直接说,这段可以等。 --- _Generated by [Claude Code](https://claude.ai/code/session_01MCLBsUgfykL74aU716rzVK)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1ce6ad4 commit 46dac81

1 file changed

Lines changed: 13 additions & 13 deletions

File tree

‎AGENTS.md‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,11 @@ pull its build into `packages/console/`.
153153
Other scripts: `objectui:bump` (pull only), `objectui:build`, `objectui:clean`. ⛔ Never hand-edit
154154
`packages/console/dist/` or `.cache/objectui-*/` — regenerated.
155155

156-
**Moving the pin has a second half: `pnpm sdui:manifest`.** ADR-0082 D4's spec↔registry declaration-parity ratchet
157-
reads objectui's `sdui.manifest.json`, which changes only when `.objectui-sha` moves — so the pin bump is the
158-
ratchet's trigger, and its only one. It is an **on-demand gate by decision**, never a CI job; `objectui:bump` and
159-
`objectui:refresh` both print the reminder. Needs Playwright chromium. Full procedure: `docs/releases-maintenance.md`
160-
→ "After the pin moves".
156+
**Moving the pin has a second half: regenerate the committed manifest** — `node scripts/gen-sdui-manifest-node.mjs
157+
--objectui-version {the @object-ui version the new pin ships}`; `scripts/check-sdui-manifest.mjs` reds until you do.
158+
ADR-0082 D4's spec↔registry declaration-parity ratchet reads that tracked artefact, so it gates **every PR**, not a
159+
pin bump alone. `pnpm sdui:manifest` is the separate browser dump of objectui's own registry (needs Playwright
160+
chromium); `objectui:bump` and `objectui:refresh` print it. Full procedure: `docs/releases-maintenance.md`.
161161

162162
**Fast iteration on `../objectui` src (no commit/refresh loop):** run objectui's own console dev server —
163163
`cd ../objectui && pnpm --filter @object-ui/console dev` (Vite on **:5180**, HMR). Its `/api` proxy targets
@@ -748,14 +748,14 @@ Principles the wrapper encodes (its own output is the authority on detail):
748748
an implementation** — the props the spec zod schema declares vs the inputs the objectui
749749
registry config declares. A prop both sides declare and no renderer reads is, to this
750750
gate, perfect agreement. Its `spec-only` / `registry-only` / `missing` signals are real;
751-
just don't read it as proof anything renders. It is also the one gate `check:generated`
752-
cannot run at all (`EXTERNAL_INPUT_REQUIRED`): its right-hand side is objectui's
753-
`sdui.manifest.json`, produced only by `pnpm sdui:manifest` driving a real browser over
754-
objectui built at `.objectui-sha`, and it **exits 1** with no usable manifest — "could not
755-
run" is a failure, not a skip (Route & surface ownership §3). The manifest comes **not
756-
from CI**: it is an on-demand gate whose trigger is the **objectui pin bump**
757-
(`docs/releases-maintenance.md` carries the procedure). ⛔ Do not "fix" the red by
758-
re-adding a skip, and do not wire the gate into a workflow either.
751+
just don't read it as proof anything renders. Its right-hand side is the **tracked
752+
repo-root `sdui.manifest.json`**, written by `node scripts/gen-sdui-manifest-node.mjs`
753+
beside `scripts/sdui-manifest.record.json` and held honest in the required lint job by
754+
`scripts/check-sdui-manifest.mjs` (shape, sha256 vs that record, record pin ==
755+
`.objectui-sha`) — so `lint.yml` runs this gate `--strict` against it on every PR. It
756+
still **exits 1** with no usable manifest — "could not run" is a failure, not a skip
757+
(Route & surface ownership §3) — and `check:generated` files it `EXTERNAL_INPUT_REQUIRED`
758+
because that aggregate hands it none. ⛔ Do not "fix" a red by re-adding a skip.
759759

760760
Two generators have **no** gate at all — `gen:openapi` and `gen:sbom`. Nothing verifies
761761
their output is current; the wrapper reports that each run rather than staying silent.

0 commit comments

Comments
 (0)