Skip to content

check:react-declaration-parity refuses to run for want of a manifest that is now checked in at the repo root #15367

Closed

Description

@os-justin

Found while measuring evidence sources for #14897 (not fixed there — that card's scope is the replacedBy reader guard). Recording only; no assignee.

The shape

packages/spec/scripts/check-react-blocks-declaration-parity.ts treats a missing manifest as a hard failure (EXTERNAL_INPUT_REQUIRED), and its header states the reason as a measured fact:

// This repository carries no manifest to fall back on. Measured, so the next reader

AGENTS.md repeats it: the manifest's "only producer" is objectui's browser dump, the gate "is the one gate check:generated cannot run at all", and it must not be wired into a workflow.

That is no longer true of this tree. A tracked sdui.manifest.json sits at the repo root, landed by #13446:

$ git ls-files --error-unmatch sdui.manifest.json
sdui.manifest.json
$ git log --oneline -1 -- sdui.manifest.json
4ca7ccf2f feat(sdui): wire the ADR-0080 manifest into the production JSX gate ... (#13446)

It is of exactly the shape the gate parses (manifestInputs reads manifest.components[schemaType].inputs):

$ node -e "const m=require('./sdui.manifest.json'); console.log(m.components['list-view'].inputs.map(i=>i.name).join(', '))"
objectName, viewType, columns, filter, sort, options

and it is pin-anchored rather than rotting: scripts/check-sdui-manifest.mjs asserts absence/shape, a sha256 tamper record, and that the record's objectuiSha equals .objectui-sha, so a pin bump goes red until it is regenerated. It runs offline in the required lint job (.github/workflows/lint.yml, step "SDUI manifest is present, intact and fresh at the objectui pin").

Why it matters

The gate's refusal is correct behaviour for a genuinely absent input — the point of #4690 was that a skip is worse than a red. But the input is no longer absent, so the refusal now rests on a premise the tree contradicts, and a comparison that could run per-PR runs only on demand at a pin bump. Two prose sources assert the stale premise, which is how the next reader re-derives the wrong conclusion.

Not asserted here

Whether the root artefact and the browser dump are input-for-input equal is not measured above. They are produced by different routes — scripts/gen-sdui-manifest-node.mjs from the published packages the pin ships, vs manifestFromConfigs(getPublicConfigs()) driven in a browser — and the gate's registry-only / spec-only / missing verdicts would be only as good as that equality. That comparison is the first step for whoever picks this up, and it is the thing that decides whether the answer is "wire it up", "wire it up with a narrowed verdict set", or "keep the refusal and correct the two prose sources".

Whatever the outcome, the header sentence and the AGENTS.md paragraph need to stop stating an absence that is no longer there.

Dedup

search_issues on the parity gate refusing while a checked-in root manifest exists: 0 results (control query in the same session returned #14897 and #14559, so the empty read is a reading, not a dead channel). REST was 403 for this session; the search went through the MCP channel.

Refs: #14897 · #13446 · #4690

Activity

  1. added
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    domain:specDomain lane — seat card indexed by label:pm:seat
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Sep 4, 2026
  2. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    分诊路由(本评论来自分诊座位)· R+154 · date -u 实测 2026-09-04T23:31:12Z

    domain:spec · tooling + finding · priority:p2。

    三条中心事实本席逐条复验(同一次调用,origin/main):

    git ls-files --error-unmatch sdui.manifest.json                    →  sdui.manifest.json      ← 根清单确实被跟踪
    packages/spec/scripts/check-react-blocks-declaration-parity.ts:80  // This repository carries no manifest to fall back on. Measured, …
    AGENTS.md                                                          →  2 处同义句
    

    ⇒ 前提被树本身推翻,而且是在两处散文里。

    域:门禁文件在 packages/spec/scripts/ ⇒ domain:spec(与本席今晚对 #14985 的判据一致:check: 脚本定义在哪个包就归哪条车道)。⚠️ 但 AGENTS.md 那两句在 skills 车道且是受管面 ⇒ 两半合并路径不同(普通合并 vs draft PR + 人工合并)。⇒ 认领方要么分两个 PR,要么与 skills 席协调;⛔ 别把 AGENTS.md 的改动混进普通 PR 里。

    p2 判据:⛔ 不是 p1(没有错误行为:对真正缺失的输入而言,拒绝是正确的 —— #4690 的要点正是「skip 比 red 更坏」)。⛔ 不是 p3:① 一个本可以每 PR 跑的比较,现在只在 pin bump 时按需跑;② 两处散文断言一个已被推翻的前提,而那正是下一个读者重新推出错误结论的机制。

    ⭐ 你自己划的那条「未断言」是本卡的第一步,请照做:根产物与浏览器 dump 是否逐输入相等未测 —— 两者产出路径不同(scripts/gen-sdui-manifest-node.mjs 从 pin 所发布的包 vs 浏览器里跑 manifestFromConfigs(getPublicConfigs())),而门禁的 registry-only / spec-only / missing 判决只会和那个相等性一样好。⇒ 先做那次比较,它决定答案是「接上」「接上但收窄判决集」还是「保留拒绝、只改两处散文」。

    ⭐ 顺带记一句本席认可的读数:你指出根清单不是在腐烂而是被钉住的 —— scripts/check-sdui-manifest.mjs 断言其存在/形状、一条 sha256 防篡改记录,以及该记录的 objectuiSha 等于 .objectui-sha(⇒ pin bump 会红到它被重新生成),且它在必需的 lint 作业里离线运行。⇒ 这条把「输入存在」从偶然变成了有维护的,是「接上它」这一支的主要论据。

    ⚠️ 你的查重带对照(0 结果,而同一会话的对照返回 #14897 与 #14559)⇒ 那个零是读数。⛔ 本席不重跑。


    Generated by Claude Code

  3. huangyiirene commented on Sep 7, 2026

    @huangyiirene
    Collaborator

    Routed from a contract review on PR #16562 — one of this card's three candidate outcomes has already happened, and it puts CI in direct conflict with a binding AGENTS.md rule

    Surfaced by the at-tier reviewer of PR #16562 (which touches component.zod.ts and named this gate as its own risk), then re-measured by me against primary sources. No fix attempted here.

    The gate is not on-demand. It runs on every PR, and it has since #13446.

    This card says "a comparison that could run per-PR runs only on demand at a pin bump." That was already false when the card was filed.

    .github/workflows/lint.yml:5496
      run: MANIFEST="$PWD/sdui.manifest.json" pnpm --filter @objectstack/spec \
           check:react-declaration-parity --baseline react-declaration-parity.baseline.json --strict
    
    $ git log --oneline -S 'MANIFEST="$PWD/sdui.manifest.json"' -- .github/workflows/lint.yml
    4ca7ccf2f3 feat(sdui): wire the ADR-0080 manifest into the production JSX gate … (#13446)
    

    It is the same commit this card already cites for landing the manifest. #13446 added the artefact and wired the gate in one change; this card read the first half and not the second.

    It also passes. The #16562 reviewer ran that exact invocation in a detached worktree at PR head: object-kanban: 2 declared by both, 12 spec-only, 0 registry-only — "no new DECLARATION divergence vs accepted baseline", exit 0.

    ⚠️ Line-number note: the reviewer cites lint.yml:5645, I read :5496. My checkout is at a4816a79d0, behind origin/main (90e7e6de11); the invocation is byte-identical, only the offset differs. Two independent readings of the same line, not one reading twice.

    So this card's decision is narrower than it looks — but the residue is on the governed surface

    The card offered three outcomes: "wire it up", "wire it up with a narrowed verdict set", or "keep the refusal and correct the two prose sources." The first is done. What remains is the prose — and that is where this stops being routine:

    1. The script header (packages/spec/scripts/check-react-blocks-declaration-parity.ts) still reads:

    This repository carries no manifest to fall back on. Measured, so the next reader does not have to re-derive it

    A comment-only fix. It is also demonstrably costly: the author of PR #16562 read that header, believed it, and wrote "cannot run in this repo" into their PR body about a gate that in fact runs and passes. The sentence's own promise — that the next reader will not have to re-derive it — is what made the error.

    2. ⛔ AGENTS.md (~:729) does not merely go stale. It forbids what CI does.

    It is also the one gate check:generated cannot run at all (EXTERNAL_INPUT_REQUIRED) … The manifest comes not from CI: it is an on-demand gate whose trigger is the objectui pin bump … ⛔ Do not "fix" the red by re-adding a skip, and do not wire the gate into a workflow either.

    lint.yml:5496 is the gate wired into a workflow. That is not a description that drifted; it is a prohibition the tree violates, and has violated since #13446.

    Why I am not resolving this

    Two readings are available and I have deliberately not adjudicated between them:

    AGENTS.md is governed surface (GOVERNED_APPROVERS: os-zhuang, hotlong), so this PM seat may not write, approve or merge either remedy — and picking between (a) and (b) is a policy call, not an engineering one. ⇒ This needs a maintainer ruling before it is a dev card. I have not applied a pm: state label; this card carries none today and I am not claiming it into the dispatch lane while its remedy is a decision.

    One thing still genuinely unmeasured — and it is now less urgent, not more

    The card's open question stands: whether the root artefact and the browser dump are input-for-input equal. But the practical stakes have shifted. The gate runs --strict against a baseline that ratchets only registryOnly (per the baseline's own _comment), and the live reading shows 0 registry-only with 12 spec-only — and spec-only is soft. So the half of the verdict set that can block is currently empty, which is exactly the configuration in which an input-equality mismatch would be least visible. Worth stating plainly rather than leaving as reassurance.

    ⛔ Not fixed here, not ridden into PR #16562 — that PR's diff is a single limit key on ObjectKanbanPropsSchema and this has nothing to do with it.


    Generated by Claude Code

  4. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Sep 8, 2026
  5. added theissue type on Sep 8, 2026
  6. os-zhuang commented on Sep 8, 2026

    @os-zhuang
    Contributor

    分诊:补状态 needs-user-decision —— ⛔ 这不是推翻上一席,是给它自己的结论一个机器可读的形

    标签 tooling finding domain:spec needs-user-decision priority:p2(维持)· 类型 Task

    本卡被无状态扫描命中。⭐ 它的无状态是刻意的,5568954745 写得很清楚:

    I have not applied a pm: state label; this card carries none today and I am not claiming it into the dispatch lane while its remedy is a decision.

    ⇒ 那个判断是对的,我不推翻。但同一段的前一句已经写出了正确的状态名:

    ⇒ This needs a maintainer ruling before it is a dev card.

    「需要维护者裁定」的六态就是 needs-user-decision。它不是派发车道 —— 派发车道是 pm:queue(SKILL.md:58,backlog 过滤默认 label:pm:queue;:104 可派发 = open + 队列标签 + 无 assignee)。⇒ 挂 needs-user-decision 不会把本卡送进派发,恰恰相反:它把「等裁定」这件事变成决策箱里可被看见的一项。

    ⚠️ 而无状态是有实际代价的,这正是我在扫的东西:SKILL.md:325 明列「析取 ③:有 domain:* 无 pm-state」为待清项。一张无状态的卡既不在派发队列里,也不在决策箱里 —— 它不在任何清单上。上一席想避免的是前者;代价是后者也一并失去了。


    复量:那条冲突我逐条独立复核,成立

    ⛔ 我没有采信 5568954745 的读数,重跑于 origin/main **c5ea982d**:

    断言 复核
    门被接进了工作流 ✅ .github/workflows/lint.yml:5825 —— MANIFEST="$PWD/sdui.manifest.json" pnpm --filter @objectstack/spec check:react-declaration-parity --baseline … --strict
    AGENTS.md 禁止接进工作流 ✅ AGENTS.md:751 —— 「…and do not wire the gate into a workflow either.」
    AGENTS.md 称它根本跑不了 ✅ AGENTS.md:745 —— 「cannot run at all (EXTERNAL_INPUT_REQUIRED)」
    脚本头仍说本仓没有清单 ✅ check-react-blocks-declaration-parity.ts:80

    ⇒ **一条具约束力的 AGENTS.md 禁令,今天正被 main 上的 CI 违反。**这不是散文腐烂,是规则与树相反。

    ⭐ 行号第三次移动,而内容不变:立卡席读 :5496(在 a4816a79d0),5568954745 引 :5645,我读 :5825。⇒ 三次独立读数、三个偏移、同一行字节相同。读行,别读行号 —— 这张卡上已经有三个人各自证明了这一点。


    决策

    待答问题

    check:react-declaration-parity 接进 lint 工作流,与 AGENTS.md:751 的禁令直接冲突。哪一边改?

    选项 A —— 接线是对的,规则过时了

    禁令的自述理由是:右手边只以浏览器 dump 形式存在,CI 没有可信输入。⭐ 那个理由已经消失 —— #13446 把清单变成了被跟踪、sha256 防篡改、且由 scripts/check-sdui-manifest.mjs 断言其 objectuiSha 等于 .objectui-sha 的产物(pin bump 会红到它被重新生成),并在必需的 lint 作业里离线运行。⇒ 输入从「偶然存在」变成「有维护的」。

    • 代价:改 AGENTS.md,受管面,draft PR + 人工合并。

    选项 B —— 规则仍是既定政策,#13446 违规接了线

    四棱卡面

    ① 项目长远合理性 —— 现状是唯一不自洽的一个:规则说「跑不了、别接」,CI 每 PR 都在跑且通过。A 与 B 各自自洽。⇒ 不动是三者中最差的。

    ② 实际业务拉动 —— 门今天在挡真实的 declaration 分歧(#16562 的复审就是靠它作答的)。B 会取消这份拉动。

    ③ 防 AI 犯错 —— ⭐ 这一棱已经有实测伤害,不是预测。PR #16562 的作者读了那句脚本头、相信了它,并把「cannot run in this repo」写进了 PR 正文 —— 描述一个实际在跑且通过的门。⇒ 那句话自己许诺「so the next reader does not have to re-derive it」,而它正是造成这次错误的东西。一句写错的「已测量」比没有注释更贵。

    ④ 创业阶段不扩散 —— A 改两处散文;B 拆一条 CI 线并放弃覆盖。A 更小。

    强制置信缺口

    仍未测:根产物与浏览器 dump 是否逐输入相等。⚠️ 而 5568954745 指出这件事的利害变了方向,值得裁决者看到:门以 --strict 跑,但 baseline 只对 registryOnly 上棘轮,实测 0 registry-only / 12 spec-only,而 spec-only 是软的。⇒ 能拦人的那半个判决集当前是空的 —— 这恰恰是输入不等价最不可能被发现的配置。⛔ 不要把「门是绿的」读成「输入是等价的」。

    推荐

    A,理由是 ③ 已有实测伤害且禁令的自述理由已消失。⛔ 但这是政策判断不是工程判断,本席不裁(本会话 claude-opus-5,CONTRACT_REVIEW_TIER 要求 fable),且 AGENTS.md 是受管面(GOVERNED_APPROVERS:os-zhuang、hotlong)。

    维护者速读

    我们有一个检查,用来比对 React 组件的声明和实际注册是否一致。规则文件里白纸黑字写着「这个检查在本仓根本跑不了,也不要把它接进 CI」;而 CI 里它每个 PR 都在跑,并且是通过的。

    规则当初这么写是有道理的:那时比对需要的数据只能从浏览器里导出,CI 拿不到。后来有人把这份数据做成了仓里一个带防篡改校验的文件,问题就没了 —— 但规则没人改。

    已经有人吃过亏:一位开发者读了代码里那句「本仓没有这个数据」,信了,把「这个检查跑不了」写进了自己的 PR 说明,而它其实在跑。

    请选一个:A(承认接线是对的,改规则)还是 B(维持规则,拆掉这条 CI 线)?


    ⛔ 围栏

    1. ⛔ 三处散文必须同笔改,无论选 A 还是 B:AGENTS.md:745、AGENTS.md:751、check-react-blocks-declaration-parity.ts:80。⚠️ 前两处在受管面 ⇒ 与脚本头不能进同一个普通 PR(合并路径不同:draft PR + 人工合并 vs 普通队列)。⇒ 认领方要么分两个 PR,要么与 skills 席协调 —— 这是上一次分诊(5547640290)已写下的,我原样保留。
    2. ⛔ 本卡的第一支「wire it up」已经完成,而且是同一个 commit 4ca7ccf2f3 干的:feat(sdui): wire the ADR-0080 manifest into the production JSX gate — artefact, freshness gate, witness tests, ratchet-to-zero ledger #13446 既落了产物又接了线。⇒ 卡面读了前一半没读后一半。⛔ 不要再去「接线」。
    3. ⛔ 输入等价性仍未测,且如上所述其利害是「最不可能被发现」的那种。⇒ 谁接手都该先做那次比较,它决定 A 之下判决集要不要收窄。

    **等级 p2 维持。**⛔ 不升 p1:没有错误行为 —— 门在跑、在通过,对真正缺失的输入而言拒绝本身是正确的(#4690 的要点是「skip 比 red 更坏」)。⛔ 不降 p3:一条具约束力的规则正被 CI 违反,且已造成一次实测的误述。

    Refs:#14897 · #13446(既落产物又接线的那一个)· #4690 · PR #16562(实测伤害的出处)

    ⛔ 分诊席边界:不认领、不派发、不写码、不合并、⛔ 不裁决。


    Generated by Claude Code

  7. os-zhuang commented on Sep 8, 2026

    @os-zhuang
    Contributor

    Ruling recorded — A: the wiring is right and the rule is obsolete; AGENTS.md:745 / :751 and the script header are corrected, after the root-artefact-vs-browser-dump equality is measured (director seat, decision batch #91, 2026-09-08)

    Provenance (who / verbatim / where): maintainer, live PM chat with the director seat (session_01TezFG8ZMrNH6n5VTNpPpdH), standing delegation 「继续决策」 — rule per the presented recommendation; reversible by the maintainer. Recommendation adopted: triage 5583898338 (A; the earlier seat reading 5568954745 measured the gate wired and passing since #13446).

    Ruled. The prohibition's stated reason — no trustworthy input in CI — dissolved when #13446 made the manifest a tracked, sha256-anchored, pin-fresh artefact checked offline in the required lint job. A binding sentence CI has contradicted since then, and a script header that already misled one PR author, are corrected: AGENTS.md:745 ("cannot run at all") and :751 ("do not wire the gate into a workflow") are rewritten to state the artefact, its freshness gate and that the parity check runs per PR; the check-react-blocks-declaration-parity.ts:80 header loses "carries no manifest". ⛔ B refused: tearing out a passing per-PR gate to honour a sentence whose reason is gone.

    Precondition, measured first: compare the root sdui.manifest.json with a browser dump input-for-input once; the result decides whether the --strict verdict set stays as is or is narrowed — and it is recorded because today the ratcheting half (registryOnly) reads 0, the configuration in which an input mismatch is least visible.

    Execution: two PRs by merge path — the script header (domain:spec, ordinary queue, Clause-②: no) and the AGENTS.md paragraphs (governed, draft, maintainer merge); ⛔ not one PR.


    Generated by Claude Code

  8. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Sep 8, 2026
  9. claude commented on Sep 8, 2026

    @claude
    Contributor

    Evidence for this card: a third prose source says pnpm sdui:manifest owns the root manifest — docs/releases-maintenance.md:113-121

    domain:spec execution seat, session session_016N6xmWt5hYm94ffVEwGH8x, 2026-09-08T10:57:01Z. ⛔ Evidence only — no grade, no domain:*, no pm:* touched. ⛔ Nothing here closes or re-scopes this card.

    This card already names two prose sources for the stale "the manifest only exists at console-build time" premise. PR #16847's two at-tier contract reviews turned up a third, and a live consequence:

    • docs/releases-maintenance.md:113-121 presents pnpm sdui:manifest as the objectui bump's mandatory "second half" and never names the node regenerator. Measured: pnpm sdui:manifest is bash scripts/gen-sdui-manifest.sh, whose only manifest write is OUT="${TARGET}/sdui.manifest.json" with TARGET="${FRAMEWORK_ROOT}/packages/console/dist" — it never writes the repo-root artefact and never touches scripts/sdui-manifest.record.json. The committed pair is written by node scripts/gen-sdui-manifest-node.mjs (OUT_PATH/RECORD_PATH), which the record's own generator field and scripts/check-sdui-manifest.mjs both name.
    • ⚠️ For a pin bump specifically, check-sdui-manifest.mjs:172 prints node scripts/gen-sdui-manifest-node.mjs --objectui-version <new> — the flag matters, because the bare call reuses record.objectuiPackagesVersion while stamping the new pin.

    ⭐ The consequence is measured, not hypothetical: a dev on PR #16847 inherited this wording and wrote it into its fix as fact. The at-tier review caught it as a BINDING finding, and the dev's own report names AGENTS.md:156-159 and docs/releases-maintenance.md:111-118 as where it took the sentence from. ⇒ This card's "two prose sources" is an undercount, and the sources are actively propagating into new code.

    ⛔ PR #16847 deliberately did not touch any of them: AGENTS.md is governed (a hit there makes the whole diff human-merge-only), and the dispatch answered fold-or-serial as SERIAL for this card. The script half of this card is subsumed by #16847; the prose sources are not.


    Generated by Claude Code

  10. self-assigned this
    on Sep 10, 2026
  11. 11 remaining items

  12. changed the issue type fromtoon Sep 10, 2026
  13. os-litant commented on Sep 10, 2026

    @os-litant
    Contributor

    Skills seat, dispatch scheduling on a card the triage seat re-routed here graded (p2 Bug, pm:queue): received. The surviving half is one sentence family in AGENTS.md (:745 / :751 / :752 per the ruling and the re-measurement) — a governed surface on the lane's AGENTS.md hot serial: PR #17415 (#16973) at the human terminal → then this card takes the chain by the total order (p2 Bug ahead of the p3 cards #17405 · #17280 · #17104 · #17370). The dispatch will carry the ruling's precondition verbatim as its first work item — the root-artefact-vs-browser-dump equality is measured BEFORE the sentence is corrected (decision batch #91) — and the governed four-piece terminal. ⛔ Not dispatchable until PR #17415 merges; no label change. Skills seat, session session_01YKEjmbYNvYWJvWGSWx26zK, 2026-09-10T22:39Z.


    Generated by Claude Code

  14. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 12, 2026
  15. claude commented on Sep 12, 2026

    @claude
    Contributor

    Claim: PM loop round 1
    Session: session_01MCLBsUgfykL74aU716rzVK (GitHub os-sales, skills seat), claimed at 2026-09-12T00:41Z
    Branch: claude/issue-15367-agents-parity-gate-sentences
    Worktree: objectstack-issue-15367
    Domain: domain:skills (re-routed from domain:spec by the triage seat, comment 5626298722; p2 Bug; the spec half is already done on main)
    File surface (region-declared): AGENTS.md — the check:react-declaration-parity paragraph inside 「Touched packages/spec? Regenerate its artifacts BEFORE pushing」 (the sentence family the ruling names as :745 / :751 / :752 — locate by text, ⛔ not by line number) plus the density payment if the 1075-line ceiling binds; measurement artefacts stay in the scratchpad; ⛔ not packages/spec/scripts/** (spec lane; its header sentence is already gone), ⛔ not docs/releases-maintenance.md (a domain:devx page — report the third prose source, do not edit it), ⛔ not sdui.manifest.json / scripts/sdui-manifest.record.json / .objectui-sha (read-only inputs of the measurement; H17 hold #14490 declares the latter two as its trigger files — named here because the measurement READS them, nothing edits them) (stop on breach; explain in the report)
    Container & model: M (a root-artefact-vs-browser-dump equality measurement precedes a small governed prose edit), mode:subagent, model: opus — default tier: node scripts/pm/dispatch-gates.mjs --tier AGENTS.md on 431c757 prints no path mandate; the skills seat reviews at the contract-review tier; governed (AGENTS.md) ⇒ draft at the human terminal
    Clause-②: no
    Thread-read: 5626387593
    Serial constraints cleared: the AGENTS.md chain head is free — PR #17415 (#16973) MERGED 2026-09-11T07:29:50Z as 155b875d; no open PR touches AGENTS.md (the 10 open PRs' file lists read 2026-09-12T00:39Z); #17405 · #17280 · #17104 · #17370 wait behind this card (SERIAL: different sentence families, gate ① fails); verify lock free at 00:27Z; H17 index ∩ the EDITED face = ∅ (the read-only overlap with #14490 is named above).


    Generated by Claude Code

  16. claude commented on Sep 12, 2026

    @claude
    Contributor

    Dispatched — R1 wave 1 (second slot), 2026-09-12T00:48Z, mode:subagent, build tier opus (no path mandate on AGENTS.md), skills-seat review at the contract-review tier. Claim 5642247617 is the dev's identity; branch claude/issue-15367-agents-parity-gate-sentences, cut from origin/main at dispatch (431c757). Deliverable: the ruling's AGENTS.md half only (5583992946) — the parity-gate sentence family corrected to the measured facts (tracked root artefact written by gen-sdui-manifest-node.mjs, sha256-anchored by check-sdui-manifest.mjs, the per-PR run in lint.yml; the «exits 1 without a manifest = failure, not a skip» clause and the no-skip prohibition kept), AFTER the ruling's precondition — the root-artefact-vs-browser-dump equality measured first, its diff recorded, ⛔ no verdict-set change here (spec lane if it differs). Readings carried: the spec header sentence is gone on main; the Frontend section's «never a CI job» paragraph read as the same claim (the dev measures); docs/releases-maintenance.md is devx's — reported, not edited; H17 hold #14490's trigger files are read-only inputs here. Terminal: governed ⇒ draft at the human terminal. In flight on the lane: 3.


    Generated by Claude Code

  17. claude commented on Sep 12, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 15367,
      "status": "done",
      "branch": "claude/issue-15367-agents-parity-gate-sentences",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/17733",
      "premise_still_valid": true,
      "summary": "Ruling A executed on the AGENTS.md half only, after the ruling's precondition measurement was TAKEN. Two paragraphs corrected: the check:react-declaration-parity paragraph in 'Touched packages/spec' (now names the tracked repo-root sdui.manifest.json, its generator scripts/gen-sdui-manifest-node.mjs, its provenance record scripts/sdui-manifest.record.json, the freshness gate scripts/check-sdui-manifest.mjs in the required lint job, and the per-PR --strict run; keeps 'exits 1 with no usable manifest = failure, not a skip' and the no-skip prohibition; keeps the still-true statement that check:generated files it EXTERNAL_INPUT_REQUIRED; drops 'do not wire the gate into a workflow either'), and the pin-bump paragraph in 'Frontend (Studio UI)' (same false claim - 'never a CI job' / 'the pin bump is the ratchet's trigger, and its only one' - now names the regenerator the freshness gate actually reds on, keeping pnpm sdui:manifest as the separate browser dump). Net zero lines: 1075 before, 1075 after, ceiling 1075. Card body is NOT truncated (ends with the Refs line); all 9 comments read; newest Claim 5642247617 names this branch - match. Assignee os-sales (the PM) left untouched. The spec half is confirmed already on main.",
      "measurement": {
        "precondition": "root sdui.manifest.json vs browser dump, input-for-input over the fields the gate consumes",
        "consumed_field_basis": "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. Basis = set of component keys + per component the set of input names.",
        "commands": [
          "bash scripts/pm/os-verify-lock.sh -c 'cd /home/user/objectstack-issue-15367 && bash scripts/build-console.sh && bash scripts/gen-sdui-manifest.sh' (detached, PID 4096, waited with tail --pid=4096 -f /dev/null)",
          "bash scripts/pm/os-verify-lock.sh -c 'cd /home/user/objectstack-issue-15367 && bash scripts/gen-sdui-manifest.sh' (detached, PID 10523, same wait form)",
          "node compare.mjs (scratchpad) over the two manifests",
          "MANIFEST=$PWD/sdui.manifest.json pnpm --filter @objectstack/spec check:react-declaration-parity --baseline react-declaration-parity.baseline.json --strict",
          "MANIFEST=$PWD/packages/console/dist/sdui.manifest.json pnpm --filter @objectstack/spec check:react-declaration-parity --baseline react-declaration-parity.baseline.json --strict"
        ],
        "lock_verdict_lines": [
          "run 1 (build + dump): os-verify-lock: VERDICT command-exit 1 - held the lock 586s (9m46s) - waited 0s. The objectui build at pin 53ded82bf7a494f54e344e19099dbf00854b8694 SUCCEEDED; the failure was the browser launch only: browserType.launch: Executable doesn't exist at /opt/pw-browsers/chromium_headless_shell-1234/... (installed build is 1194, playwright 1.62.1 wants 1234).",
          "run 2 (dump only, after the documented symlink remedy): os-verify-lock: VERDICT command-exit 0 - held the lock 22s - waited 0s"
        ],
        "browser": "Remedy applied verbatim from docs/releases-maintenance.md 'If the dispatch container's Playwright browser doesn't match the revision': a scratchpad symlink tree at SCRATCH/pw/chromium_headless_shell-1234/chrome-headless-shell-linux64 pointing at /opt/pw-browsers/chromium_headless_shell-1194/chrome-linux, PLAYWRIGHT_BROWSERS_PATH set to SCRATCH/pw for that one invocation. Nothing under /opt/pw-browsers was touched. No playwright install was run.",
        "artefacts": "root sdui.manifest.json 66,910 bytes (tracked); packages/console/dist/sdui.manifest.json 73,194 bytes (browser dump, gitignored, deleted afterwards)",
        "component_keys": "57 root vs 57 dump; 0 only in root; 0 only in dump",
        "components_with_differing_input_name_sets": 18,
        "input_names_only_in_root": "2 - 'type' on action:button and action:icon",
        "input_names_only_in_dump": "19 - 'dataSource' on 15 components (embeddable-form, list-view, object-calendar, object-chart, object-form, object-gantt, object-grid, object-kanban, object-map, object-master-detail-form, object-metric, object-pivot, object-timeline, record:line_items, record:related_list); 'align' and 'variant' on text; 'actionType' on action:button and action:icon",
        "verdict": "DIFFERS on the consumed fields",
        "gate_verdict_set_under_each_input": "IDENTICAL on every judging axis. Both runs exit 0 and both print '✓ no new DECLARATION divergence vs accepted baseline' and 'Summary: 90 spec-only divergences, 0 blocks missing from the registry'. Totals over the 9 judged blocks: declared-by-both 119, spec-only 90, registry-only 5 under BOTH manifests; per block the declared-by-both / spec-only / registry-only triples are byte-identical (diff of the two streams on those three fields is empty). The ONLY difference is the node-level bucket: 2 (root) vs 11 (dump), the 9 extra entries all being dataSource, which the gate classifies as accepted at node level and which feeds neither the ratchet nor any verdict. text / action:button / action:icon are not among the 9 blocks the gate judges, so their differences reach no verdict at all.",
        "consequence_for_the_ruling": "Nothing measured here narrows the --strict verdict set, and this PR does not touch it (packages/spec/scripts = domain:spec). What IS recorded: the two producers are not interchangeable - the root artefact is systematically missing dataSource and spells 'type' where the dump says 'actionType' - so a future registry change on one of those names would be invisible in the artefact CI reads. That is the spec-lane follow-up."
      },
      "tests": "No code changed, so no package test/typecheck is owed. Gate families derived on the final diff with 'node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack' (exit 0; header line: gate list derived from the tree of 'objectstack-ai/objectstack' at commit 431c75712; change set = 1 path, AGENTS.md, three-dot). The 14 derived commands ALL ran, each exit 0: node scripts/check-closing-keyword-parity.mjs; node scripts/check-closing-keyword-parity.mjs --self-test; node scripts/check-comment-mask-corpus.mjs; pnpm check:agent-test-spelling; pnpm check:docs-audit-scope; pnpm check:driver-memory-census; pnpm check:nul-bytes; pnpm check:pm-governed-merges; pnpm check:pm-governed-prose; pnpm check:pm-skill-id-lint; pnpm check:pm-skill-ratchet; pnpm check:refd-timer-probe; pnpm check:required-contexts; pnpm check:watch-hint-literal. Verdict lines quoted: '✓ check-skill-line-ratchet: AGENTS.md is 1075 lines (ceiling 1075; headroom 0).' and '✓ check-skill-line-ratchet: AGENTS.md: widest table row is 768 bytes (pin 768; headroom 0).' and '✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.'. Extra, from the dispatch hint: 'pnpm check:published-list-mirrors' is NOT a package.json script (ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL, exit 254 - NOT MEASURED, a name error, not a red); re-run as 'node scripts/check-published-list-mirrors.mjs' -> exit 0, 'OK: 1 published list mirror(s) match their constants line for line. AGENTS.md <- scripts/check-cross-package-test-inputs.mjs -> RECOGNISED_PATH_SPELLINGS'. Control-character self-scan beyond the gate: grep -naP over AGENTS.md -> no match (exit 1). Repo-wide scans (pnpm lint and the rest) are CI's, not run here. No ablation is applicable: the change is prose with no executable behaviour.",
      "gates": [
        "node scripts/pm/check-governed-merges.mjs --test AGENTS.md -> exit 3; 'governed-surface predicate: 1 of 1 path(s) hit the register (5 surfaces, repo-agnostic).' / '⛔ GOVERNED - a human merge is the review record for this PR (#9495 regime).'",
        "node scripts/pm/check-clause2-carriers.mjs --pair 17733 -> exit 0; '✓ check-clause2-carriers: PR #17733 / card #15367 - the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell.'"
      ],
      "line_budget": {
        "file": "AGENTS.md",
        "lines_before": 1075,
        "lines_after": 1075,
        "ceiling": 1075,
        "net": 0,
        "paid_by": "deleted CONTENT in the same paragraphs - the obsolete prohibition 'and do not wire the gate into a workflow either', the 'The manifest comes not from CI / on-demand gate whose trigger is the objectui pin bump' clause, the '(docs/releases-maintenance.md carries the procedure)' cross-reference and the '→ \"After the pin moves\"' anchor. No re-wrap was used as payment: each replaced block has exactly the same line count as the block it replaced (site A 8 -> 8, site B 5 -> 5).",
        "changed_line_bytes_utf8_without_newline": {
          "156": 116, "157": 116, "158": 117, "159": 110, "160": 107,
          "749": 85, "750": 88, "751": 82, "752": 86, "753": 86, "754": 78, "755": 87, "756": 86
        }
      },
      "files_changed": ["AGENTS.md"],
      "pr_head_sha": "82b83613f6ee480358db008d65679b3b015e8a70",
      "pr_labels_read_back": ["size/s", "skip-changeset"],
      "pr_body_read_back": "byte-identical to what was sent except a trailing newline GitHub strips; first line 'Fixes #15367'; the session-URL attribution footer survived as one block with its rule line",
      "mcp_calls": "0 - every GitHub read and write went through repo-scoped REST (probe GET /repos/.../issues/15367 -> HTTP 200) plus git; no MCP GitHub tool was invoked",
      "releases_maintenance_113_121_verbatim": "The bump has a second half, and it is not optional:\n\n```bash\npnpm sdui:manifest    # rebuild objectui at the new pin, dump sdui.manifest.json, run the ratchet\n```\n\n`sdui.manifest.json` is objectui's registry-inputs dump — the right-hand side of\nADR-0082 D4's spec↔registry **declaration-parity ratchet** (`scripts/gen-sdui-manifest.sh`\nproduces it and runs the ratchet against it; note it is *not* `scripts/build-console.sh`,",
      "deviations": [
        "Region extension, declared: the Claim comment's file surface named only the check:react-declaration-parity paragraph (the ':745 / :751 / :752' family). The dispatch word's zone 2 item 1 (b) and zone 3 additionally name the 'Frontend (Studio UI)' pin-bump paragraph in the SAME file, and I measured it as carrying the SAME false claim ('never a CI job'; 'the pin bump is the ratchet's trigger, and its only one'), so I corrected it. Beyond the CI-job half I also corrected that paragraph's producer clause (it named `pnpm sdui:manifest` as the pin bump's second half) because leaving it would have made AGENTS.md name two different producers for the same artefact - an inconsistency created by my own edit. Landing point is still AGENTS.md only.",
        "Dispatch item: 'node scripts/pm/check-clause2-carriers.mjs --pair 15367' - `--pair` takes a PR number, not a card number; with 15367 it reported 'PR #15367 is not open ... ⛔ Not a clearance' at exit 2. Re-run as --pair 17733 (the PR this card produced) -> exit 0.",
        "Dispatch hint 'pnpm check:published-list-mirrors' does not exist as a package.json script; the real invocation is 'node scripts/check-published-list-mirrors.mjs'.",
        "The precondition measurement needed two runs: the first died on the Playwright build-revision lookup gap already documented in docs/releases-maintenance.md, not on a missing browser.",
        "Shallow checkout (git rev-parse --is-shallow-repository -> true). No ancestry claim in this report depends on a negative `merge-base --is-ancestor` reading, so no control leg was needed."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: docs/releases-maintenance.md :113-121 presents `pnpm sdui:manifest` as the pin bump's mandatory second half and never names `node scripts/gen-sdui-manifest-node.mjs`, which is what `scripts/check-sdui-manifest.mjs` actually reds on and what its remedy at :172 prints. The exact current text is in this report's releases_maintenance_113_121_verbatim field. domain:devx page, explicitly excluded from this PR by the dispatch. Successor: the PM, who reserved the sibling card for itself.",
        "noted, not filed: the root-artefact-vs-browser-dump inequality measured above (18 of 57 components, 19 input names only in the dump, 2 only in the root) is a domain:spec finding about the two producers, not about AGENTS.md. The ruling's narrowing question goes to the spec lane. Successor: the PM, per the dispatch's zone 2 item 3.",
        "noted, not filed: packages/spec/scripts/check-generated.ts EXTERNAL_INPUT_REQUIRED still carries a `why` string asserting the stale premise verbatim - 'nothing in this repo (console dist is gitignored, the published console ships no sdui.manifest.json) can hand it one' - while the tracked repo-root sdui.manifest.json does exactly that. The CLASSIFICATION is still correct (check:generated does not run the gate), only its stated reason is false, which is the same defect class as this card. A fourth prose source, in the spec lane. Successor: the spec-lane card the PM files for the inequality above - same file tree, same round.",
        "noted, not filed: scripts/bump-objectui.sh (header :10-15, :414, :700, :718) and scripts/build-console.sh (:281-289) print `pnpm sdui:manifest` as the pin bump's second half and likewise never name the node regenerator. Same producer confusion as the docs page, in scripts rather than prose. Successor: the same devx/spec sibling card - naming it here keeps the sweep from stopping at the .md file.",
        "noted, not filed: the CI step the corrected sentence describes lives in lint.yml's `typecheck-consumers` job (line 6126 on 431c757), which reaches the merge queue through the required 'TypeScript Type Check' aggregate, while `check-sdui-manifest.mjs` runs in the `lint` job ('Lint & Repo Gates', line 806). The corrected AGENTS.md text deliberately says 'lint.yml' and 'the required lint job' without naming either required context, so that a future context rename does not add a stale site here (scripts/check-required-contexts.mjs counts those names in AGENTS.md). Observation only, nothing to fix."
      ]
    }

    Generated by Claude Code

  18. claude commented on Sep 12, 2026

    @claude
    Contributor

    Follow-ups from the ACCEPT above, filed by this seat as finding for the triage seat's routing (the two noted, not filed items whose 承接者 was the PM): #17735 (spec lane — the root-artefact-vs-browser-dump inequality on the gate's consumed fields + the stale why string in check-generated.ts) · #17736 (devx lane — the docs page and the two scripts naming pnpm sdui:manifest as the pin bump's second half). Skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T01:09Z.


    Generated by Claude Code

  19. claude commented on Sep 12, 2026

    @claude
    Contributor

    ACCEPT — PR #17733 (head 82b83613) reviewed in-seat at the contract-review tier; governed ⇒ four-piece at the human terminal (skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T01:09Z).

    • Implemented-by: os-dev subagent on claude/issue-15367-agents-parity-gate-sentences (claim 5642247617; build tier opus; mode:subagent; report 5642401563). Reviewed-by: session_01MCLBsUgfykL74aU716rzVK (the skills seat) — independence pair holds.
    • Ruling A (batch Auto-organize documentation by zod source files #91, 5583992946) executed in order: the precondition was TAKEN before the edit — root sdui.manifest.json vs a real browser dump (build-console.sh + gen-sdui-manifest.sh under the verify lock, the documented Playwright revision-symlink remedy, no playwright install) compared over exactly the fields manifestInputs() consumes: 57/57 component keys, 18 components with differing input-name sets (dataSource absent from the root artefact on 15 components; type vs actionType on the two action blocks; align/variant on text) ⇒ DIFFERS on the consumed fields, while the gate's verdict set is byte-identical under both inputs (9 judged blocks: 119 / 90 / 5 both ways; the whole difference lands in the node-level bucket). ⛔ The --strict verdict set is untouched here — the narrowing question is the spec lane's: filed as [finding] the tracked root sdui.manifest.json and the browser dump differ on the fields the parity gate consumes (18 of 57 components; dataSource missing on 15 in the root artefact) — the gate's verdict set is identical under both today, which is the configuration in which the drift is least visible #17735.
    • PR shape: draft; base main; first line Fixes #15367; skip-changeset + documentation + size/s; one session-URL footer; a 维护者速读(草稿) with 席位意见 blank. Changed files: AGENTS.md only (13/13) — the claim's declared face plus the same-file 「Frontend」 pin-bump paragraph the dispatch named in zone 2/3, measured by the dev as the same false claim and corrected; the deviation is declared in the report and accepted (same file, same sentence family, same ruling).
    • Path face by this seat at 82b83613: check-governed-merges.mjs --test AGENTS.md ⇒ GOVERNED (exit 3, the printed verdict line) ⇒ human terminal; ⛔ this seat never flips ready, enqueues or approves. check-clause2-carriers.mjs --pair 17733 exit 0 (the claim declares Clause-②: no; my dispatch spelled the card number — the dev corrected it; the reading above is the PR-number run).
    • Diff read whole by this seat: site A (the parity-gate paragraph, 8 → 8 lines) now states the tracked root artefact, its generator + record, the freshness gate in the required lint job, the per-PR --strict run; keeps «exits 1 with no usable manifest — a failure, not a skip» and the no-skip prohibition; keeps check:generated's EXTERNAL_INPUT_REQUIRED as a still-true fact; drops only the CI-contradicted «do not wire the gate into a workflow either». Site B (the pin-bump paragraph, 5 → 5 lines) names the regenerator in the spelling check-sdui-manifest.mjs line 172 prints (the --objectui-version remedy line, verified verbatim against the script), states that the ratchet gates every PR, and keeps pnpm sdui:manifest as the separate browser dump. Re-measured by this seat on a detached worktree at the head: check:pm-skill-ratchet exit 0 (1075/1075, widest table row 768/768), check:pm-skill-id-lint exit 0, check:pm-governed-prose exit 0 (2 surfaces name all 5), node scripts/check-published-list-mirrors.mjs exit 0 (my hint pnpm check:published-list-mirrors is not a script — the dev's correction stands), changed-line bytes 78–117. Gates: 14 derived / 14 run / 0 NOT-MEASURED on the dev's --ran reconciliation. CI on 82b83613 at this ACCEPT: 16 success / 12 skipped / 1 in progress (Lint & Repo Gates) — re-read at the next check-in; not a flip input here.
    • noted, not filed — filed by this seat (承接者 was the PM): [finding] the tracked root sdui.manifest.json and the browser dump differ on the fields the parity gate consumes (18 of 57 components; dataSource missing on 15 in the root artefact) — the gate's verdict set is identical under both today, which is the configuration in which the drift is least visible #17735 (spec lane: the root-vs-dump inequality + the stale why string in check-generated.ts); [finding] docs/releases-maintenance.md :113–:121, scripts/bump-objectui.sh and scripts/build-console.sh present pnpm sdui:manifest as the pin bump's mandatory second half — the committed artefact the freshness gate reds on is written by node scripts/gen-sdui-manifest-node.mjs, which none of them names #17736 (devx lane: docs/releases-maintenance.md :113–:121, scripts/bump-objectui.sh, scripts/build-console.sh naming pnpm sdui:manifest as the pin bump's second half). The lint.yml job-name observation: accepted as noted, nothing to fix.
    • Terminal: governed four-piece — this ACCEPT; the PR stays draft; needs-user-decision on the PR; 速读终稿 on the PR (5642428943); reviewers os-zhuang + hotlong requested by REST (read back). On MERGED: landing record here + pm:dispatched / assignee cleared in one write with read-back.

    Generated by Claude Code

  20. claude commented on Sep 12, 2026

    @claude
    Contributor

    Landing record — PR #17733 MERGED 2026-09-12T03:28Z through the merge queue as 46dac81c, merged by os-zhuang (the human merge is the review record for the governed surface; four-piece was on the PR; skills-seat ACCEPT 5642433729, 速读 5642428943). Ruling A (batch #91) executed on the AGENTS.md half: the parity-gate paragraph and the Frontend pin-bump paragraph now name the tracked root sdui.manifest.json, its generator and its provenance record, after the ruling's precondition measurement was TAKEN (root manifest vs browser dump DIFFER on 18/57 components while the gate's verdict set is identical — the spec-lane finding #17735 and the devx-lane finding #17736 carry the two halves that are not this card's). Content verified on origin/main by git at 2026-09-12T03:28Z (git grep on AGENTS.md finds the generator and record names; the merge sha is an ancestor of origin/main). Residue cleared in this same act: pm:dispatched and the assignee removed. Chain: AGENTS.md is free ⇒ #17405 is the next card on it by the total order. Skills seat, session session_01MCLBsUgfykL74aU716rzVK, 2026-09-12T03:28Z.


    Generated by Claude Code

  21. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 12, 2026
  22. added a commit that references this issue on Sep 17, 2026
    46dac81
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:skillsDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions