Skip to content

Commit 8cfa07a

Browse files
os-elon-muskclaude
andauthored
feat(pm): the Prior rulings read: line covers the card’s own thread — tool corpus half and charter :339 in one batch (#19021)
Fixes #18993 Clause-②: no `scripts/pm/check-prior-rulings.mjs` answered the `Prior rulings read:` line out of three tree corpora (`docs/adr/**`, `AGENTS.md`, `packages/spec/src/**`) while `SKILL.md:339` required it to cover 「已裁卡」 — a card's own thread, where the cheapest ruling lives, was in no corpus. Measured consequence on #17518: a director-seat ruling (5651572469, 2026-09-13) was followed by a retriage that re-presented the card as unruled, a second maintainer ruling with a different prescription (5716259259, 2026-09-17), and a dispatch round that ended with zero diff. This PR makes the card's own thread a corpus half of the tool and rewrites the charter line in the same batch, so the requirement and the tool never diverge again. ## What changed **`scripts/pm/check-prior-rulings.mjs`** (report-only, no write path, unchanged exit register) - Every `--card` run now reads the card's comment thread over the board route the file already uses (its own proxy re-exec guard, taken once, never on `--self-test`), one paged `GET …/issues/{n}/comments?per_page=100&page=P` walked by page number to a short page, bounded at `MAX_THREAD_PAGES` (50), reconciled against the card's `comments` field. - A ruling comment is recognised by the **shape of its first content line**, three measured shapes: the charter's `Ruling: batch #n item k …` (`ruling-line`), the pre-charter `## Ruling recorded — …` heading (`ruling-recorded`, the shape 5651572469 is written in), and `Ruling addendum …` (`ruling-addendum`). Every hit prints its id, author, timestamp and shape. - Two measured near-misses are pinned OUT and listed uncounted (`**Ruling C landing step** — …`, `## Ruling A's patch is falsified …`). - The paste line gains a `thread:` clause with three spellings kept apart: `thread: 2 ruling(s) (id, id)`; `thread: none` (read, no ruling); `thread: not read (no --card)` (a `--terms`-only run). A thread that could not be read is the WHOLE line `unresolved`, exit 3, exactly as an unreadable corpus — never `none`. - The report prints the read's cost (pages, bytes, ms) and, when a ruling stands, the 〈升级与决策〉③ warning; with two or more rulings it says to read every one and to return a disagreement to the director seat. - Self-test: 99 → 144 cases (the three shapes, the near-misses, first-content-line anchoring, the fixture thread with two rulings oldest-first, `none` / `not read` / `unresolved`, and an offline paged board: two pages, one page, a 403, no token, the page bound, a network failure, a malformed page; plus a structural pin that no `Link` header is followed). `check-half-states.mjs`'s source-text pin on the line's writer (H62) still holds: 4963 cases pass. **`.claude/skills/pm-dispatch/SKILL.md` :339** — rewritten in place, net 0, 120 bytes → 120 bytes, 812 / 812 lines before and after: > before: `- 方向落在 ADR/已裁卡/不可重裁规则:贴 `check-prior-rulings.mjs` 的 `Prior rulings read:` 行,或不点。` > after: `- 方向在 ADR/本卡裁决/不可重裁规则:贴 `check-prior-rulings.mjs` 的 `Prior rulings read:` 行,或不点。` The three places a direction may already be ruled now read exactly as the tool's line covers them: an ADR, a ruling on this card, a non-re-rulable rule. **`.claude/skills/pm-dispatch/references/decision-analysis.md` :45** — the human-facing statement of the same line shape (the tool's `formatPasteLine` docblock names it as the twin), rewritten in place, 113 → 120 bytes, 50 / 50 lines: ``` before: - 四棱后一行:`Prior rulings read: TERMS → N hits; ADR-xxxx Dn|none`;未搜成整行写 unresolved。 after: - 四棱后:`Prior rulings read: TERMS → N hits; ADR Dn|none; thread: K|none`;未搜成整行写 unresolved。 ``` (The file spells the placeholders in angle brackets; they are written as capitals here because the platform mutates angle-bracket fragments in a body.) This file was not in the dispatch's named surface; it is included because it states the line's shape and would otherwise be the next 「a requirement and a tool that cannot answer it」 pair. No open PR touches it (file lists of the 14 skills-lane PRs read 2026-09-18T11:3xZ). ## Hypotheses measured 1. **Ruling shape is stable; author is not.** Census over 1,100 comments (REST, reads only): 2026-09-11T06Z–09-13T21Z (600): `## Ruling recorded — …` 22 (os-tesla 19, claude[bot] 3), `Ruling: …` 4 (os-tesla 2, claude[bot] 2); 2026-09-18T04Z–11Z (500): `Ruling: …` 26 (hotlong 26), `Ruling addendum` 2 (hotlong). The charter line (`director.md`: 「裁决评论首行固定一条:`Ruling: batch #N item K · letter X · maintainer 「VERBATIM」 UTC`」 — placeholders capitalised here, the file spells them in angle brackets) landed 32a3214 2026-09-13T11:27Z; the heading shape is the same seat's earlier spelling. The fallback the dispatch named — 「every comment by a `GOVERNED_APPROVERS` login」 — is falsified: it would have missed every 2026-09-13 ruling, 5651572469 included. A quoted 「同意」/「agreed」 predicate hits 63 of 500 recent comments (claims, ledgers, dev reports) and names nothing. 2. **Cost, the tool's own meter** (node `fetch` on the re-exec'd route, pages serial, 2026-09-18T11:3xZ): | thread | comments | pages | bytes | thread read | whole run | rulings / near-misses | |---|---:|---:|---:|---:|---:|---| | #17518 (the incident) | 17 | 1 | 141,623 | 347–369 ms | 2,353 ms (before: 2,001 ms) | 2 / 0 | | #12708 (director seat post) | 372 | 4 | 2,212,674 | 1,984 ms | 3,669 ms | 0 / 0 | | #6015 (longest thread on the board) | 962 | 10 | 7,365,556 | 4,431 ms | 6,254 ms | 0 / 0 | `curl` on the same pages reads ~10% more bytes (156,874 on #17518): GitHub pretty-prints for a `curl/*` User-Agent and minifies for any other, measured directly; the tool reports what its own route pays. The fixed cost per dedupe on the incident card is one page and about a third of a second. 3. **The line, before / after, on `--card 17518` through the proxy** (exit 0 both): ``` before: Prior rulings read: spec,assembledpackagebodyschema,declares,callable,custom,branches,inert-json,artifact,hold,schema,embedding,loses (+1 more) → 117 hits; ADR-0087 D4, ADR-0130 D4, ADR-0029 D6, ADR-0039 D7, ADR-0056 D5, ADR-0076 D3, ADR-0076 D9, ADR-0087 D1, ADR-0087 D3, ADR-0087 D7 after: Prior rulings read: spec,assembledpackagebodyschema,declares,callable,custom,branches,inert-json,artifact,hold,schema,embedding,loses (+1 more) → 117 hits; ADR-0087 D4, ADR-0130 D4, ADR-0029 D6, ADR-0039 D7, ADR-0056 D5, ADR-0076 D3, ADR-0076 D9, ADR-0087 D1, ADR-0087 D3, ADR-0087 D7; thread: 2 ruling(s) (5651572469, 5716259259) ``` and the report's thread block: ``` the card's own comment thread (ruling comments, by first-line shape): 2 ruling(s) of 17 comment(s) — read in 1 page(s), 141,623 bytes, 347 ms 5651572469 os-tesla 2026-09-13T06:10:22Z [ruling-recorded] Ruling recorded — B: `packages/spec` declares the inert-JSON artifact stage; the read A… 5716259259 hotlong 2026-09-17T14:41:18Z [ruling-line] Ruling: batch #149 item 1 · letter B (artifact-stage JSON-only variants of `FlowFunctio… ``` 4. `--terms single,posture,tenant` (no card): exit 0, line ends `; thread: not read (no --card)`. ## Gates Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` from the worktree (three-dot change set: the three files above): 40 families, every one run, exit codes captured redirect-then-`$?`, reconciled with `--ran` (`40 derived, 40 run` after the one PREREQUISITE NOT MET was cleared by its declared build: `check:doc-formula-expressions` exited 3 for an unbuilt `@objectstack/formula`; built under the verify lock, re-run, exit 0). `check:pm-dispatch-gates` exceeds the foreground cap and ran detached (`tail --pid`): 779 s, `1849 cases pass`, exit 0. Also: `node scripts/pm/check-prior-rulings.mjs --self-test` 144 pass; `check:pm-skill-ratchet` ✓ (812 / 812, 50 / 50, widest rows unchanged); `check:pm-skill-id-lint` ✓ 27 files clean; `check:nul-bytes` ✓; `check-governed-merges.mjs --test` over the three paths: GOVERNED (2 of 3 on the register — expected, `.claude/**`); eslint on the edited script: 1 file, 0 errors, 0 warnings (`--no-inline-config`, the root flat config's `**/*.mjs` block; no type-aware rules, so the diff moves no untouched file's verdict). Readings taken at `cba931995`, the branch head. The same derivation from a throwaway worktree at `origin/main` 64de4c5 (five commits past this branch's base, four of them touching family-defining files) yields the identical 40 families — none new, none gone. This branch is deliberately not merged with `main` here: the incoming range carries four `merge=os-regen` artifacts whose driver debt would hold the push on a PR that touches no spec file; the seat's `update-branch` is the right instrument if a refresh is wanted before landing. No published package moves (`scripts/pm/**` and `.claude/**` ship in no `files[]`): `skip-changeset`. ## Acceptance notes - noted, not filed: the file's self-test keeps a flat case list with the verdict handshake and no battery-name floor (the AGENTS.md `--self-test` section's floor rule is stated for writing a new one); the 2026-09 self-test shape census owns that class — carrier: whoever works that census; not this card. - noted, not filed: `readCard` still uses the global `fetch` while `readThread` takes an injectable one; symmetry only, no behaviour — carrier: none. - Boundary kept: no merge with #18963 / PR #18981 (grading-time dedupe by file) — same class, different mechanism; #18963 is not addressed here. ## 维护者速读(草稿) **改了什么**:查重工具 `check-prior-rulings.mjs` 多读一处 —— 被查那张卡自己评论线上的裁决评论;贴进卡面的那一行 `Prior rulings read:` 多出一段 `thread: …`,写明本卡已有几条裁决、评论 id 是哪几条;读不到线程时整行仍写 `unresolved`,绝不写成「没有」。章程 `SKILL.md:339` 与 `decision-analysis.md:45` 各原位改一行,行数不变,同一批落地。 **为什么改**:#17518 上四天内出现两条互相矛盾的维护者裁决,一整轮派发白跑 —— 原因是重新分诊的席位没看到卡上四天前的那条裁决,而工具即使跑了也查不到:卡的评论线不在它任何语料里。这次把「已裁卡」这半边做成机械面,并把章程那句话改成工具真能答的范围。 **风险与代价(含回滚)**:每次查重固定多一次线程读取 —— 事故卡 1 页、约 0.35 秒;全板最长线程(962 条评论)10 页、约 4.4 秒,已实测。识别靠裁决评论首行的固定写法(三种实测形态),不靠作者身份;写法漂移会以「近似项」在报告里显形而不是静默漏掉。回滚 = revert 本 PR 三个文件,无发布物、无数据迁移。 **席位意见**:(留空) **你要做的**:确认三种裁决写法的识别边界可接受;若同意,按受管面流程合并。 --- _Generated by [Claude Code](https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e15870f commit 8cfa07a

3 files changed

Lines changed: 432 additions & 48 deletions

File tree

‎.claude/skills/pm-dispatch/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报
337337
- bump 单单张封顶:先查同题 open 单,已有就追评刷新;工具链新形态只提请不扩面。
338338
- 分类动作每张三选一,外加一个修复通道。
339339
- ⛔ 不挂 `needs:contract-review`:随 draft PR 或 `Clause-②: yes` 认领;裁定写方向、给六态之一。
340-
- 方向落在 ADR/已裁卡/不可重裁规则:贴 `check-prior-rulings.mjs` 的 `Prior rulings read:` 行,或不点。
340+
- 方向在 ADR/本卡裁决/不可重裁规则:贴 `check-prior-rulings.mjs` 的 `Prior rulings read:` 行,或不点。
341341
- `pm:queue` = 有具名落点或复现的具体缺陷,或范围明确的工具/门禁修复,无可问之事。
342342
- `pm:queue` 也收恢复不变量的 finding、test-only pin,与实现未被裁错的说明书脱节(修文档)。
343343
- `needs-user-decision` = 设计卡、feature/契约形状提案、需要 appetite 的多周程序。

‎.claude/skills/pm-dispatch/references/decision-analysis.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
- ② 实际业务拉动:今天谁撞上;零拉动默认 defer 或 remove。
4343
- ③ 防 AI 犯错:闭合枚举优于自由结构,响亮拒绝优于静默容忍。
4444
- ④ 创业阶段不扩散:remove 优于 declare-and-maintain,每个已声明的键都是永久义务。
45-
- 四棱后一行:`Prior rulings read: <terms> → <n> hits; <ADR-xxxx Dn|none>`;未搜成整行写 unresolved。
45+
- 四棱后:`Prior rulings read: <terms> → <n> hits; <ADR Dn|none>; thread: <k>|none`;未搜成整行写 unresolved。
4646
- 末尾推荐行 + 字母选项带自检「只看①选 X;②③④ 是否翻转:…」,再一行置信缺口。
4747

4848
## 应用仓推荐序特例

0 commit comments

Comments
 (0)