From af0a8e5db6d3ac69083bb6879dd994359c8817d9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 15:04:30 +0000 Subject: [PATCH 1/2] skills(pm): refuse the issues-list cursor and require a count cross-check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The list-cards row prescribed an endpoint but asserted nothing about the completeness of what it returns. Measured 2026-08-31/09-01 in two repos, a walk that follows `Link: rel="next"` reports itself exhausted at 102 items while the page-number walk on the identical query returns 287 / 448 and matches `open_issues_count`. The failure is silent and toward the dangerous side, and a keyword positive control is structurally blind to it: a known-hit card sitting in the first page answers correctly over a truncated corpus. Lands both refusals (do not follow the cursor; an enumeration whose total was never cross-checked is not a reading), the `&page=N` short-page termination condition, the `open_issues_count`-minus-open-PRs cross-check, the cause-unknown boundary (GitHub's cursor vs the egress proxy rewriting the header — the prescription removes the dependency, it does not explain it), and the keyword-control blind-spot note. Paid in place: the red-window restatement is retired and its pointer folded into the section heading at zero line cost, so the red-window rule now has exactly one home in platform-readings.md's quota section. The ceiling moves 87 -> 93 on the maintainer ruling quoted verbatim beside the row. --- .../pm-dispatch/references/rest-channel.md | 9 ++++--- scripts/pm/check-skill-line-ratchet.mjs | 24 ++++++++++++++++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/.claude/skills/pm-dispatch/references/rest-channel.md b/.claude/skills/pm-dispatch/references/rest-channel.md index 17e8b35514..116c675451 100644 --- a/.claude/skills/pm-dispatch/references/rest-channel.md +++ b/.claude/skills/pm-dispatch/references/rest-channel.md @@ -17,6 +17,11 @@ payload → REST → MCP/GraphQL** 的策略住那里,本表是逐操作的通 - ✓ 按标签/状态列卡:`GET /repos/{o}/{r}/issues?state=open&labels=a,b&per_page=N` —— `labels=` 是**真 AND**(MCP `list_issues` 的 labels 数组是 OR;语义相反那条住 `platform-readings.md`)。 +- ⛔ 完整性自证,**不跟 `Link: rel="next"`**:2026-08-31/09-01 两仓实测,游标自称枯竭停在 102,页号走 + 法得 287/448、与 `open_issues_count` 符 ⇒ 改走 `&page=N` 到短页为止,再用 `GET /repos/{o}/{r}` 的 + `open_issues_count`(含 PR,减开放 PR)核总数;⛔ 未核总数的枚举不是读数。⚠️ 成因未知(GitHub + 游标 vs 出口代理改写 `Link`):处方**不依赖该头**,⛔ 不把「已修」写成「已解释」。⚠️ + 关键词阳性对照**结构上**看不见本类(必中卡落在首页照样绿),只有计数核对逮得住。 - ✓ 卡 / PR 元数据:`GET .../issues/{n}` · `GET .../pulls/{n}`(assignees、labels、body 齐全 —— MCP `list_issues` 永不返回 assignees,这条差别本身就是走 REST 的理由)。 - ✓ 整条评论线:`GET .../issues/{n}/comments?per_page=100`。 @@ -40,7 +45,7 @@ payload → REST → MCP/GraphQL** 的策略住那里,本表是逐操作的通 - ✓ 请求复审 `POST .../pulls/{n}/requested_reviewers` · 开 PR `POST .../pulls`(带 `draft=true`;GraphQL 池为 0 的同一分钟里实测开得出 draft PR ⇒ 交付不必等重置)。 -## 不可迁移 —— 只有这几件,围着它们排计划 +## 不可迁移 —— 只有这几件,围着它们排计划(红窗守候规则住 `platform-readings.md` 配额段) 1. **draft → ready 翻转**:GraphQL-only mutation;出口代理只放钉住的 PR-review GraphQL 集(实测拒绝)。 判据 = REST update-a-pull-request 只收 `title`/`body`/`state`/`base`/`maintainer_can_modify`,**无 `draft`** @@ -55,8 +60,6 @@ payload → REST → MCP/GraphQL** 的策略住那里,本表是逐操作的通 GraphQL-only。拿不到时当轮改走「在目的仓重建」配方 —— 纯 REST、配额免疫,配方住 `platform-readings.md`。 -`until remaining > 阈值` 的守候只留给这几件,⛔ 其余一切不为配额空等。 - ## 第三桶 —— git 零配额等价物(先问 git,再问 REST) 分支存在性、合并队列分支、按内容判落地、squash 验证:四条 `ls-remote` / `git log` 拼写与各自 diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index 8269d5a018..395c6a595f 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -311,7 +311,29 @@ export const CEILINGS = new Map([ // file is the lookup table it points at, so the policy flip did not have to // grow the hot file. Set at landed line count (headroom 0, same convention // as the entries above). - ['.claude/skills/pm-dispatch/references/rest-channel.md', 87], + // Raised 87 → 93 by a maintainer ruling (2026-09-01, 总监批 #22) that names + // this ceiling and orders its own encoding — the ratchet's own legitimate + // exit, and the raising PR quotes the ruling comment. Verbatim and + // untranslated (one quotation, wrapped only to fit this comment): + // 「**B 获授权**:`rest-channel.md` 天花板 87 → **≤93 行**,提额 PR 引用本裁决 + // 评论(棘轮自己的合法出口);两条处方按 dev 已测的忠实版落(两个拒绝 + + // `&page=N` 短页终止条件 + `open_issues_count` 减开放 PR 交叉核对 + 成因未知 + // 边界 + 关键词对照结构性盲区注记)」 + // and, same batch, the content-ownership call that says what is paid in place: + // 「**C 同批**:退役 L58 对红窗常设规则的复述 —— 内容归属裁定:**红窗规则由 + // `platform-readings.md` 配额段独家持有**,`rest-channel.md` 只留指路」 + // Paid in place: that restatement and its adjacent blank are retired (−2), and + // the pointer the ruling permits is folded into the 不可迁移 heading at zero + // line cost — so the red-window rule now has exactly one home. Spent: +8, the + // two enumeration-completeness prescriptions (both refusals, the `&page=N` + // short-page termination, the `open_issues_count`-minus-open-PRs cross-check, + // the cause-unknown boundary, and the note that a keyword positive control is + // structurally blind to this class) plus the closed-inclusive dedup obligation + // the same batch ruled onto this file (「提额预算一次用足」). Could not be paid + // by re-wrap: the file measures zero reclaimable lines under this gate's own + // wrapLine, and re-wrap funding is refused per the 2026-08-17 rule in any + // case. Landed count, headroom 0, same convention. + ['.claude/skills/pm-dispatch/references/rest-channel.md', 93], ['.claude/skills/pm-dispatch/references/review-checklist.md', 84], ['.claude/skills/pm-dispatch/references/landing-operations.md', 80], // Release-aftercare duties — what a lane PM still owes AFTER a tagged release From b7c2e8413ab953b11624e8f4c056fd08040b0c55 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 15:04:41 +0000 Subject: [PATCH 2/2] skills(pm): make the dedup prescription state that dedup includes closed cards Dedup asks whether a subject has been carded before, and that answer lives disproportionately in closed cards, so an open-scoped scan is blind by construction rather than by malfunction. Measured 2026-08-31 in both directions on one day: an open-scoped dedup missed a same-subject card that had been ruled and closed six hours earlier and a duplicate was filed and dispatched; a dedup that included closed cards hit a same-shape closed card and no duplicate was opened. The obligation lands in the prescription text itself -- zero new quota and no new mechanism -- so open-scoped dedup becomes an exception that has to be declared rather than the default. The state and label listing reads keep `state=open` untouched: that convention governs state reads, where a closed card is archive, and dedup is not a state read. --- .claude/skills/pm-dispatch/references/rest-channel.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.claude/skills/pm-dispatch/references/rest-channel.md b/.claude/skills/pm-dispatch/references/rest-channel.md index 116c675451..e68aff7548 100644 --- a/.claude/skills/pm-dispatch/references/rest-channel.md +++ b/.claude/skills/pm-dispatch/references/rest-channel.md @@ -22,6 +22,9 @@ payload → REST → MCP/GraphQL** 的策略住那里,本表是逐操作的通 `open_issues_count`(含 PR,减开放 PR)核总数;⛔ 未核总数的枚举不是读数。⚠️ 成因未知(GitHub 游标 vs 出口代理改写 `Link`):处方**不依赖该头**,⛔ 不把「已修」写成「已解释」。⚠️ 关键词阳性对照**结构上**看不见本类(必中卡落在首页照样绿),只有计数核对逮得住。 +- ⛔ **查重必须含 closed**:卡刚关闭时最易被重开(2026-08-31 双向实测:开域查重漏掉 6 小时前 + 刚关闭的同题卡 ⇒ 重复派发;含闭卡那次命中已关闭同形卡 ⇒ 免开重复)。开域查重 + 是**要申报的例外**,不是默认;状态 / 标签列卡读仍 `state=open` —— 那是状态读,不是查重。 - ✓ 卡 / PR 元数据:`GET .../issues/{n}` · `GET .../pulls/{n}`(assignees、labels、body 齐全 —— MCP `list_issues` 永不返回 assignees,这条差别本身就是走 REST 的理由)。 - ✓ 整条评论线:`GET .../issues/{n}/comments?per_page=100`。