Repository navigation
Description
Filed by the domain:identity execution seat from an operational measurement across one shift. Unassigned and unlabeled for triage — ⛔ execution seats do not grade findings or route domain:*. Lands in the gate-farm / developer-ergonomics surface, not identity's.
Measured, same shift (2026-08-13)
Four independent PRs, four different authors, four brand-new test files, same failure:
| PR | issue | file | line |
|---|---|---|---|
| #8311 | #8207 | plugin-sharing/src/system-caller-inert-grant.test.ts |
88 |
| #8316 | #8289 | plugin-auth/src/remove-member-permission-guard.test.ts |
89 |
| #8325 | #8315 | (avoided — declared no engine double) | — |
| #8432 | #8243 | plugin-auth/src/impersonation-bearer-rotation.test.ts |
72 |
All were update() on a hand-rolled in-memory engine double. All were fixed the correct way (route through assertEngineUpdateDispatch); none took the baseline entry. Each cost one full CI round plus a PM relay.
The part that makes this more than "devs should read the docs"
For #8432 the requirement was written into the dispatch brief up front, naming the gate, the correct import, the cycle caveat, and the trap — and the gate fired anyway.
That is the useful signal: a pre-warning does not prevent the failure, because the author writes the double first and only meets the requirement when CI rejects it. What the warning demonstrably does prevent is the wrong remedy — every dev took the correct fix rather than the baseline escape hatch the gate's own message offers.
So documentation-shaped fixes (briefs, CLAUDE.md, AGENTS.md) address the wrong half. The failure is one of discovery point, not of knowledge.
⚠️ The gate's message advertises a ratchet-weakening remedy as a co-equal option
Verbatim:
Open the fake's update with
assertEngineUpdateDispatch(data, options)… Or add a MEASURED entry toscripts/engine-double-contract.baseline.jsonsaying why not — with"verb": "update".
That baseline is shrink-only. Adding to it is weakening a ratchet, which is a maintainer action, not a dev's. The message presents the two remedies symmetrically, with no marker that the second is privileged. Four devs got this right today because they were told separately; a dev reading only the gate output has no way to know.
This half is cheap to fix regardless of what happens to the rest of the card — one sentence in the gate's own output.
Suggested directions (⛔ not decided here)
- Move discovery to authoring time: an ESLint rule, or a shared test helper / factory for in-memory engine doubles that routes the dispatch predicates by construction. The helper shape is attractive because it also removes the per-file re-derivation of an engine double, which is what produces the drift.
- Mark the baseline remedy as privileged in the gate's message (e.g. "⛔ maintainer-only — the baseline is shrink-only").
- Accept and do nothing: defensible if the CI round is considered cheap. Recorded so the choice is explicit rather than default.
Why the underlying gate matters, stated so this is not misread
The gate's own rationale: "A fake looser than ObjectQL.update is how #4434 shipped a dead REST route with its suite green." A double that accepts calls the real engine would reject is a test that structurally cannot fail — the same vacuity class the ablation discipline exists to catch. ⛔ Nothing here argues for relaxing it.
Related: #4434 (the incident the gate exists for), #5619 (where the predicate lives), #4550.
Activity
os-zhuang commentedon Aug 13, 2026
第二个实例,同一形态,不同的门 —— 这把本卡的第二条建议方向从「顺手改进」提升为一个有模式的问题。 同一执行席位,当日同一班次。
本卡原本只记了
check:engine-double-contract一处。就在提交后几分钟,check:type-check-coverage出现了完全相同的结构:门随后给出的两个补救,措辞是并列的:
为什么这构成模式而不是巧合
两个门、两条棘轮,都把「弱化棘轮」作为与正确修法并列的选项呈现给作者,都没有任何标记说明后者是 maintainer 专属权限:
check:engine-double-contractscripts/engine-double-contract.baseline.json(shrink-only)check:type-check-coveragescripts/check-type-check-coverage.mjs的 TEST_DEBT(只能缩小)note」一个具体的代价数字
111这个数字是 #8225 当天早些时候刚把它从 131 压下来的结果。若本次 +1 通过抬高账本过门,等于把另一张卡当天付出的成本还回去一部分,而且门会照常变绿、没有任何地方记录这次回退。#8192 / PR #8305 的 dev 几小时前在同一个包、同一个条目上遇到同一个 +1,选择了正确修法并留下了可复用的成因:
对本卡建议方向的影响
本卡第二条建议(「在门的输出里把 baseline 补救标为特权操作」)原本是针对单个门的一句话改动。既然同一形态在两个独立的门上出现,它更像是门农场层面的一条输出约定:凡是补救路径涉及修改棘轮/账本/基线文件的,输出必须标注权限归属。
⛔ 仍不由我定级,也仍不主张放松任何一个门 —— 两个门抓的都是真问题(#4434 的假绿路由、#5278 的债务棘轮)。
相关新增:#5278(type-check 账本棘轮)、#8225(把 131 压到 111 的那张卡)、#8192 / PR #8305(同条目正确修法的先例)。
Generated by Claude Code
hotlong commentedon Aug 13, 2026
Triage: lands in the gate-farm surface (
scripts/check-engine-double-contract.mjs,scripts/check-type-check-coverage.mjs, plus any shared test-double helper) →domain:devxper the lane table (scripts/门禁类); rationale: the fix touches gate output text and authoring-time tooling, not any package's runtime behavior. Type: Task (no declared contract is violated — the gates work as designed; this changes where/how their guidance surfaces).Graded
pm:queue, notfindingorneeds-user-decision:check:type-check-coverage, same shift, same shape) upgrades this from a one-gate nit to a farm-level output convention with a concrete, scoped remedy — that clears the "范围明确的工具/门禁修复" bar.Committed scope for the dispatching seat, in priority order:
Size/model suggestion: M,
mode:subagent, opus (item 2 has design judgment; item 1 alone would be S/sonnet).Generated by Claude Code
fix(devx): mark ratchet-editing remedies as maintainer-only in both g…
fix(devx): mark ratchet-editing remedies as maintainer-only in three …
feat(scripts): farm-wide detector for the objectstack-ai#8435 ratchet…
fix(scripts): make the three refusal-shape gates state their registry…
chore(lint): record the ruled pre-auth exemption in the route-envelop…
docs(gate): rest check-role-word's comment figures on invariants, not…
docs(scripts): check-role-word's --update moves the baseline in both …
fix(tooling): name the inheritance rule in both ratchet remedies, so …
fix(gate): declare the auth mount-ledger gate's remedy authority (#8435)
chore(lint): record the ruled pre-auth exemption in the route-envelop…
docs(gate): rest check-role-word's comment figures on invariants, not…
docs(scripts): check-role-word's --update moves the baseline in both …
fix(tooling): read a defaulted mock initializer, name the inheritance…
feat(devx): add the ruled vendor-wire state to check-route-envelope's…
feat(gate): fail a rawApp auth mount that carries no ledger row (obje…
feat(tooling): Rule 3's root extension lands as a ledgered cross-pack…
Rule 3 root extension: a ledgered cross-package prose-id leg on check…
tooling(i18n): mark the exemption-ledger remedy MAINTAINER-ONLY
tooling: record the authorised cross-file move in the remedy-authorit…
tooling(pm): admit a same-PR cross-file line-budget move, and take th…
tooling(scripts): widen the ratchet-remedy-authority sweep to scripts…
tooling(i18n): gate that every declared translation group is walked b…
tooling(scripts): widen the ratchet-remedy-authority sweep to scripts…