Skip to content

[finding] Declarations that read correctly to a human but not to the gate — two near-miss spellings measured this session, each silently costing the reading they were written to provide #16303

Description

@os-litant

⛔ Recorded for triage; no severity asserted, no domain:*, no type — routing and grading are triage's. Filed by the domain:cli execution PM seat (#6024) after hitting the same shape twice in one session on two different gates.

The shape

A seat writes a declaration the machine is supposed to read. It reads correctly to a human. The predicate that consumes it does not match, so the declaration is not there as far as the tooling is concerned — and nothing says so at the time it is written. The failure surfaces later, at landing, or not at all.

Both instances were found by an at-tier contract reviewer running the predicate, not by the seat writing the declaration and not by any gate output the author saw.

Instance 1 — Clause ②: vs Clause-②: (a space where a hyphen is required)

Measured on PR #16298 at head 83edbc55f3e. CLAUSE2_KEY_LINE requires the machine spelling Clause-②:; that PR's body writes Clause ②:. The gate says so in as many words:

· declaration line: a near miss, not a declaration — Clause ②: **yes** …

⇒ the body carries no readable declaration, and the level axis reads yes off the needs:contract-review carrier alone. Measured both ways by the implementer: with the carrier the axis reads yes; with today's four real labels and no carrier, the same event reports NOT MEASURED.

⚠️ Not harmful on that PR — the card's claim comment carries the correct spelling, so the machine path is satisfied by the card side. But a PR whose body looks declared and is not is a trap for the next reader, and the distance between correct and near-miss is one character.

Instance 2 — a Branch: named in prose instead of on its own line

Measured on PR #15675 (the lane's only priority:p1) by its contract review. The card's claim comment named its branch in prose, so governingClaim never matched it and cardDeclaration read {state: missing} — meaning the --pair predicate saw no clause-② declaration on the card at all, on a card whose clause-② grade had been yes and public for two days.

The claiming seat fixed it by posting a claim with Claim: / Branch: / Clause-②: as lines, and verified mechanically rather than by eye: {state: missing} → {state: declared, value: yes}.

⭐ Why the two together are a class rather than two typos

  1. Both are near misses, not omissions. Nobody forgot to declare. Both authors wrote the declaration, believed it was written, and were right in every sense except the one that counts.
  2. Neither author got any signal. The gate that would have told them was, in both cases, one that this seat cannot run — check-clause2-carriers returns PREREQUISITE NOT MET / HTTP 403 here, every time. ⇒ the seat that writes the declaration is systematically the one that cannot check it.
  3. Both were caught by a reviewer executing the predicate, which is luck rather than process: a reviewer is briefed on the diff, not on the declaration plumbing.
  4. The failure is silent and asymmetric. A missing declaration is loud at landing. A near-miss reads as present to every human who looks and absent to every machine that matters.

What a fix might look like — ⛔ costs only, not a recommendation

  • Have the gate name near misses as errors where it currently reports them as context. The Clause ②: case IS already detected and printed — it is called "a near miss" in the output. ⛔ Cost: it would red PRs that are substantively fine, including on the card-side-satisfied path, unless the check knows about both carriers.
  • Accept both spellings. ⛔ Cost: widening a machine format to match prose is how the format stops being machine-readable.
  • Emit the declaration from a template rather than by hand, so the spelling cannot drift. ⛔ Cost: templates for claim comments and PR bodies are a tooling surface nobody owns today.
  • Leave it and rely on review. ⛔ Cost: this is the status quo, and the status quo produced two instances in one session, one of them on a p1.

⚠️ A decision here should probably also say which carrier is authoritative — card claim comment, PR body, or either. Instance 1 is harmless only because the card side happened to be right; if the rule is "either satisfies", that should be written down, and if it is "both must", instance 1 is a live defect rather than a trap.

Provenance

Instance 1: PR #16298, head 83edbc55f3e, driven with check-changeset-no-major.mjs --base origin/main --event <live label set> and two controls. Instance 2: PR #15675, verified by importing the real cardDeclaration / governingClaim and probing before and after.

Refs: #15675 · #16298 · scripts/pm/check-clause2-carriers.mjs · CLAUSE2_KEY_LINE.

⬇ Appended by the domain:devx execution seat (#6023) when this card was filed into the decision inbox, 2026-09-18T18:08Z. ⛔ Nothing above this rule was edited — the filing seat's text stands as written. The full analysis, and the measurement that reframes the card, are in the comment that accompanies this edit.

维护者速读

一个 PR 要声明「这次改动有没有放宽接受集」。声明是给机器读的一行字。作者写对了意思、写错了排版,机器就当这行不存在 —— 没人当场被告知,问题要么在 CI 里晚一步爆出来,要么根本不爆(卡面那一侧就是这样,有一张 p1 的声明凭空消失了两天)。十天里至少八次,横跨六个 PR、三个不同的席位。

本轮实测把病因从「拼写太挑剔」改写成了另一回事:这条规则其实很干净,只有一句话 —— 装饰随便加,理由随便写,但不能又用反引号把整句包起来、又在包外继续说话。 别的写法(裸写加理由、只给键名加反引号或加粗、项目符号、引用块、缩进)全都读得出来。问题是这句话今天只存在于检查器的源码和一份已合并的 PR 正文里;作者能看到的文档只说「单独一行、行首、就这两种拼法」—— 这句是对的,但它没说清楚「我想多写一句理由」时哪些写法还活着。

⇒ 所以这不是机器太严,是契约没有发表。选项:

  • A 把所有近似写法判红,两个载体都判(会红掉一批实质没问题的 PR)
  • B 把接受集再放宽,把「整句包起来还继续说话」也收进来(每放宽一次,这个格式就离机器可读远一步)
  • C 声明改由工具产出,作者不再手写这一行(彻底消灭这个问题,但多一个今天没人负责的工具面)
  • D 只把那一句规则写进作者会看的地方,机械面一个字不改(零成本;本席推荐)
  • E 维持现状

⚠️ A、B、C 三项都踩「人工地板」(门禁增删/放宽、新增必须维护的工具面),所以本席不代裁。

请裁一个字母:A / B / C / D / E。

os-decision-facets

① 项目长远合理性:D 既不扩大也不缩小特例 —— 接受集一个字不动,只是把它发表出来;契约先行,把已经存在且自洽的规则写下来,比再造一台绕开它的机器更符合 no-workarounds。B 会让被容忍的拼法集合永久增生,是唯一明确扩大特例的选项。
② 实际业务拉动:非零且已实测 —— 十天内八次,六个 PR、三个席位,其中一次让本车道唯一的 priority:p1 卡在两天里对机器「没有声明」。⛔ 这是实例数不是速率,一轮读不出速率。
③ 防 AI 犯错:今天的失败是静默的(卡面那一侧)与迟到的响亮(PR 正文那一侧要等 CI 红)。D 把作者写之前就该知道的那句话交到他手上,是唯一在「出错之前」起作用的选项;C 更强(闭合枚举,作者根本不组装这行),A 只是把已有的迟到响亮加大音量。
④ 创业阶段不扩散:D 零新增面 —— 不新增门禁、不新增 hook、不新增工具。C 要新增一个今天没有归属的模板面,那是一份永久义务;卡面自己就把这条列为 C 的代价。
Prior rulings read: declarations,read,correctly,human,gate,near-miss,spellings,measured,session,silently,costing,reading (+2 more) → 128 hits; ADR-0076 D11, ADR-0125 D3, ADR-0056 D1, ADR-0058 D6, ADR-0062 D4, ADR-0067 D4, ADR-0069 D3, ADR-0076 D12, ADR-0090 D7

推荐:D。自检行「只看①选 D;②③④ 是否翻转:否」—— ③ 单独看更偏 C(闭合枚举优于自由结构),④ 单独看反对 C 的新增面;两者相消,都不改字母,只把 C 排成「D 发表之后仍复发才付的下一步」。回退项:C。

置信缺口:⛔ 本席没有实测卡面载体(governingClaim / cardDeclaration)那条路径 —— 上面七组读数全是正文形状经 readClause2Line,卡面那一侧是另一个谓词,卡上 instance 2 不被以上任何读数触及。⛔ 也没有数 2026-09-12 之后到今天有多少 PR 撞上这一形状:有三个被别的席位点名,那是实例不是速率。


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions