From 41b3060d709cb5fe808b1ed0aae4f2502f856493 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:58:33 +0000 Subject: [PATCH] pm-dispatch: make the REST channel the default read path, land the per-operation channel map Three folded cards, one quota-family change to the pm-dispatch reference surface. Policy flip: platform-readings.md's API-quota section now states the read order as git -> REST -> MCP/GraphQL, with the container curl channel (App installation token, REST core 15,000/hr, independent bucket) as the DEFAULT path for list/dedup/card/PR reads. The GraphQL pool is reserved for the operations with no REST twin. Every measured fact and provenance date already in the file is preserved; the three channel-partition rows consolidated into two, which paid for the two new right-sized-read rows in place. New references/rest-channel.md carries the per-operation mapping (read side, write side, the GraphQL-only handful, the git zero-quota bucket, the channel boundary), each row with its measurement date, plus the queue-routing readings. Ratchet: platform-readings.md LOWERED 133 -> 130 (shrink, no ruling needed); new CEILINGS row for rest-channel.md at its landed 46, headroom 0. Data rows only - no mechanism change. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ --- .../references/platform-readings.md | 17 +++---- .../pm-dispatch/references/rest-channel.md | 46 +++++++++++++++++++ scripts/pm/check-skill-line-ratchet.mjs | 16 ++++++- 3 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 .claude/skills/pm-dispatch/references/rest-channel.md diff --git a/.claude/skills/pm-dispatch/references/platform-readings.md b/.claude/skills/pm-dispatch/references/platform-readings.md index eedc993da1..83ec6bf53c 100644 --- a/.claude/skills/pm-dispatch/references/platform-readings.md +++ b/.claude/skills/pm-dispatch/references/platform-readings.md @@ -42,28 +42,25 @@ ## API 配额 - **配额按账户计,不跨席共享;按查询复杂度计费,不按调用次数**:各席位跑在**不同 GitHub 账户**下,「所有 agent 共用一个身份」只在**席位内部**成立(一个席位派出的每个 dev 都以该席身份发言 —— 这正是认领必须在评论里写 session ID 的理由)⇒ ⛔ 不据限流报文里的 user ID 推「池子跨席共用、优化自己没用」(实测推翻),本席额度**完全由本席做法决定**,优化有效且是唯一有效手段;计费按复杂度/节点数 ⇒ 优化方向是**每次少拿**,不是少调用。实测(`/rate_limit` 前后差量,该端点自身不计费):上限 5000/时;单个 dev 子代理 ~15 分钟烧 ~5658 点;一次 `list_issues`(34 张卡、perPage=100)= 107 点;耗尽时刻 GraphQL used 10461(超上限一倍)而 REST core used 7 ⇒ **最大消耗方是派出去的 dev 子代理,PM 巡检相比之下是噪声**(2026-08-22 实测)。 -- GraphQL 配额(5000/时)极易打满,**MCP list/search 家族整个走 GraphQL 池** —— - 反复撞上的限流墙就是它;「读与评论走 REST(core 15000/时,独立计)」预设会话真有 - REST 通道:MCP 读工具无 REST 替身,直连 REST 受会话级授权门(会话起点快照,403 - `GitHub access is not enabled for this session`)与出口代理(只放 repo-scoped - 路径,`/search/*` 被拒、`/rate_limit` 例外)钳制 —— **纯 MCP 会话撞上枯竭池 = - 重置前没有任何 list 通道**,降级读法 = 下文 git 先行与 WebFetch 两行;只有无 - REST 对应物的写才花 GraphQL,`issue_write` 连查找半边都吃 —— 配额红时认领类动作排队,评论(REST 池)先行把结论发出去。 +- **perPage 按预期 population 取,⛔ 不按习惯取 100**:上条计费规则(点数 ≈ 请求节点数/100)使 perPage 成为唯一杠杆 —— 那次 107 点的读数里 34 张卡付的是 100 张的钱,一次只要 3 条的 perPage=100 读法多付约 33 倍点数;只要 `totalCount` 的健康指标取 perPage=1,只要最近 N 张就取 N(2026-08-23)。 +- **批量写 ~1 秒一发**:小时池之外还有**分钟级二级限流** —— GraphQL 端点 2,000 点/分、并发 ≤100,官方指引是**变更类请求之间停 ~1 秒**(mutation 在二级计算里按 5× 计)。双载体清标、批量重分诊这类把写挤在同一秒的扫动,会在小时池仍绿时撞上分钟墙(官方文档 2026-08-23 复核)。 +- **默认读序 git → REST → MCP/GraphQL**(2026-08-23 策略翻转:REST 通道是**默认**读路径,⛔ 不再是「降级退路」)。list/查重/卡与 PR 读/标签回读**默认走容器 curl 的 REST 通道** —— App installation token,core 15,000/时,与 GraphQL 池**独立计**(实测同一天本席 GraphQL 池两次耗尽时 REST core 余 14,938);GraphQL 池(5000/时)只留给**没有 REST 对应物**的那几件:draft 翻转、auto-merge/入队挂载、语义 `/search/*`、Projects field_values、`issue transfer`。逐操作通道归属(每条实调 ✓ 带日期)、写侧配方与队列路由三读法见 `references/rest-channel.md`,⛔ 不在本表复述。 +- **MCP list/search 家族整个走 GraphQL 稀缺池**,且服务器端无条件抓 Projects field_values —— 反复撞上的限流墙就是它;`issue_write` 连查找半边都吃。边界:直连 REST 受会话级授权门钳制(会话起点快照,403 `GitHub access is not enabled for this session`),**该门关着的纯 MCP 会话撞上枯竭池 = 重置前只剩 git 先行与 WebFetch 两行**;配额红时认领类动作排队,评论(REST 桶)先行把结论发出去。 - **`gh` CLI 的动词按传输分两桶,池枯竭时只死一半**(2026-08-24 同一分钟实测:GraphQL remaining 0 / REST core remaining 4987):porcelain 读家族全走 GraphQL —— `gh issue view` / `gh pr list` / `gh pr checks` 当场回 `API rate limit already exceeded`(`GH_DEBUG=api` 回显 `POST /graphql`);同一批事实改走 `gh api` 的 REST 路径全部照常返回(`repos/{o}/{r}/issues/{n}` 读正文、`.../issues/{n}/labels` 读标签、`.../commits/{sha}/check-runs` 读门禁结论、`.../pulls` 列 PR)⇒ **配额红的一小时里,认领/打标/评论/读门禁这条复核链整条跑得完**,⛔ 不据一次 porcelain 限流就宣布「GitHub 通道断了」而停轮。写侧同一分法:`gh pr create` 也走 GraphQL(同分钟被拒),而开 PR 有 REST 端点 —— `gh api -X POST repos/{o}/{r}/pulls -F draft=true` 同分钟成功 ⇒ 池子为 0 时 draft PR 照开得出,交付不必等重置。边界:本条取自装有 `gh` 的本机席位;容器里没有 `gh`(见「读数陷阱」),那边的分流按 MCP 通道另判。 -- **真需要等重置的只有 merge 家族**:合并本身有 REST 端点(`PUT /repos/{o}/{r}/pulls/{n}/merge`,`gh api -X PUT` 可达);**draft 翻转与 issue transfer 没有** —— REST 的 update-a-pull-request 只收 `title`/`body`/`state`/`base`/`maintainer_can_modify`(无 `draft`),issues 端点表里没有 transfer 路由,auto-merge 挂载亦无 REST 对应物(2026-08-24 核对官方 REST 文档;未逐个实调端点)⇒ `pr ready`、`issue transfer`、auto-merge 挂载是 GraphQL-only,`until remaining > 阈值` 的守候留给这三个就够。走合并队列的仓落地必经 auto-merge ⇒ 红窗里**无退路**;直合仓有。 +- **红窗调度:等重置的只有上面那几件 GraphQL-only 的**(逐件判据与官方文档核对日期住 `references/rest-channel.md`,⛔ 不在本表复述)⇒ `until remaining > 阈值` 的守候只给它们,⛔ 其余一切不为配额空等。走合并队列的仓落地必经 auto-merge ⇒ 红窗里**无退路**;直合仓有(合并本身有 REST 端点)。 - **`issue transfer` 因配额或权限拿不到 ⇒ 当轮改走多仓协调条款已载明的「在目的仓重建」配方**(出处头 + 裸 `#N` 改全名 + 关源单为 moved):该配方纯 REST、配额免疫,⛔ 不为一次转移空等重置,更不因此把跨仓卡搁成半状态。 - **两个「瘦身参数」都不省池**:`fields` 省载荷不省池 —— MCP list/search 服务器端无条件抓 Project field_values,池枯竭时**最小字段请求同样全体失败**(报错串 `failed to fetch issue field values: API rate limit already exceeded`); ⛔ **`minimal_output: true` 不裁 `list_issues` 的 `body`**(2026-08-22 实测:返回字段仍含 `body`,首条 3258 字符、整体 122,685 字符仍超单次工具输出上限被落盘)—— 工具描述的反向暗示是假的,**永不当省额度手段写进任何 skill**;只要 number/labels/title 时也没有任何参数能关掉 body:要么接受整表 107 点,要么换更窄接口(`search_issues` 点数未实测)。⚠️ 前后体积对比不作证据(两次调用相隔数小时、population 已变),站得住的是直接观察 `body` 在。 - **git 先行**:本地检出 / `git log` / `ls-remote` 不花配额,断粮期分支存在性检查照常可用,PR 文件读取同走 git(REST PR files 端点实测可瞬态 404); **零成本等价物四条**(API 两次挂掉期间实测全程可用):合并队列 `git ls-remote origin 'refs/heads/gh-readonly-queue/*'`;是否落地 `git log --format='%H %s' -40 origin/main` 按 PR 号 grep;squash 验证 `git rev-list --parents -n1`(父提交数);分支存在性 `git ls-remote origin 'refs/heads/**'`。 - 开轮先读配额(`curl` 带 Bearer `$GH_TOKEN` 打 `/rate_limit`,该端点免费;容器内**没有** `gh`,见「读数陷阱」),graphql remaining < 1000 ⇒ 本轮降级为 git 先行 + 只做必要写; + 开轮先读配额(`curl` 带 Bearer `$GH_TOKEN` 打 `/rate_limit`,该端点免费;容器内**没有** `gh`,见「读数陷阱」),graphql remaining < 1000 ⇒ 本轮读全部按默认读序走 git + REST(独立桶,不受影响),GraphQL 只花在没有 REST 对应物的那几件写上; **派 dev 之前同样先读一次**:额度不足先等重置再派 —— 中途撞限流的 dev **完不成强制查重**,只能把发现交回 PM 代为归档;限流窗口里「必须查重才能归档」的动作等待,⛔ 不盲目开卡。 打满时:待执行写**排成有序清单挂进巡逻词**(不靠记忆),恢复窗口按序连清;重试对齐整点(REST core 整点重置)优于指数退避,⛔ 绝不忙轮询; search 与 core 独立计,一侧打满另一侧可作退路;REST core 共享身份下同样会打满;文档载明、未实测:条件请求答 `304` 不计 core 池(仅当直连 REST 获准才相关)。 - **公开仓降级读法:WebFetch github.com 网页零 API 配额**(带 label 过滤的 issue 列表、issue 全文含评论、PR 页含 checks,实测撑得起整轮盘点);边界:~15 分钟缓存、列表行不含 assignee、内容是渲染层。 - **查重先 `search_issues`**(2026-08-18 23:3xZ 实测:单次调用按 issue body 内文本命中且 `total_count` 精确 ——「search API 对本会话不可用/回错误对象」的继承说法实测为**假**;继承说法不是读数,复述必须带实测日期):body 文本匹配是 repo-scoped `list` 做不到的(全量抓取再 grep 才等价),`list` + 对照组降为回退。 -- **`search_issues` 可整会话静默归零 —— 控制词一并归零**(2026-08-23 实测:某会话对**每个**查询回 `total_count: 0`,含已知必中的控制词;同时刻另一会话同工具正常 ⇒ 故障是**会话级**,不是工具/平台级)。诊断:结果可疑时先跑一个带 `repo:` 限定、已知必中的控制词;回 0 ⇒ 本会话 search 已坏,**立刻换通道,⛔ 不重试**(重试只烧配额)。正确退路 = **REST 列表端点** `GET /repos/{o}/{r}/issues?state=open&labels=a,b&per_page=100&page=N`(走 core 桶、结果**完整**;`GET /search/issues` **不是**退路 —— 出口代理按设计只放 repo-scoped 路径);⛔ **不要用 MCP `list_issues` 手扫**:它走 GraphQL 稀缺桶,且分页手扫极易半途而废(实测 226 张 open 只扫了 100 张)—— **不完整枚举比零结果更危险,它读作「搜过了,没有」**。⛔ 已推翻的候选机理,别再追:「查询串里带 GitHub 限定符(`repo:`/`is:open`)把语义 search 打成零」—— 两次实测反证:带 `repo:` 的控制词回 `total_count: 5`;另一席同工具两腿对照,`repo:… is:open …` 回 1(精确命中)而裸词回 13(语义扩散),限定符在那儿**收窄**结果而非破坏。归零机理仍未定(候选:scope 过滤层静默清空 / search 桶 403 被 MCP 层吞成空结果),要定它必须在复现会话里抓原始响应。 +- **`search_issues` 可整会话静默归零 —— 控制词一并归零**(2026-08-23 实测:某会话对**每个**查询回 `total_count: 0`,含已知必中的控制词;同时刻另一会话同工具正常 ⇒ 故障是**会话级**,不是工具/平台级)。诊断:结果可疑时先跑一个带 `repo:` 限定、已知必中的控制词;回 0 ⇒ 本会话 search 已坏,**立刻换通道,⛔ 不重试**(重试只烧配额)。换到的就是默认读序那一档 = **REST 列表端点** `GET /repos/{o}/{r}/issues?state=open&labels=a,b&per_page=N`(走 core 桶、结果**完整**,perPage 按上面的右尺寸规则取;`GET /search/issues` **不是**退路 —— 出口代理按设计只放 repo-scoped 路径);⛔ **不要用 MCP `list_issues` 手扫**:它走 GraphQL 稀缺桶,且分页手扫极易半途而废(实测 226 张 open 只扫了 100 张)—— **不完整枚举比零结果更危险,它读作「搜过了,没有」**。⛔ 已推翻的候选机理,别再追:「查询串里带 GitHub 限定符(`repo:`/`is:open`)把语义 search 打成零」—— 两次实测反证:带 `repo:` 的控制词回 `total_count: 5`;另一席同工具两腿对照,`repo:… is:open …` 回 1(精确命中)而裸词回 13(语义扩散),限定符在那儿**收窄**结果而非破坏。归零机理仍未定(候选:scope 过滤层静默清空 / search 桶 403 被 MCP 层吞成空结果),要定它必须在复现会话里抓原始响应。 - **`search_issues` 不可靠地返回分钟级新卡**:同轮发现的东西查重,搜索之外必须按创建时间列近期 issue(`list_issues` + `orderBy: CREATED_AT`)—— 实测一张 ~7 分钟大的同实例卡被关键词与语义搜索双双漏掉,靠按日期列表才逮到;边界:两次观察、索引延迟未实测,断言只到「search 可能漏掉分钟级 issue」,更硬的窗口要另测(2026-08-20 实测)。 - **会话中途轮换凭据把 GitHub MCP 服务器杀到不可恢复**:此后一切 `mcp__github__*` 回 `Streamable HTTP error: invalid session`(含几分钟前还好的工具),只有新会话 diff --git a/.claude/skills/pm-dispatch/references/rest-channel.md b/.claude/skills/pm-dispatch/references/rest-channel.md new file mode 100644 index 0000000000..3e5a66696b --- /dev/null +++ b/.claude/skills/pm-dispatch/references/rest-channel.md @@ -0,0 +1,46 @@ +# REST 通道操作对照表(references —— 按需加载) + +出处:`platform-readings.md` API 配额段(**默认读序 git → REST → MCP/GraphQL** 的策略住那里,本表是逐操作的通道归属)。做一件事之前查一行:它有没有 REST 对应物。⛔ 不引用 issue 编号 —— 每行自含边界与日期。 + +**通道边界**:容器 curl = App installation token,REST core 15,000/时、与 GraphQL 池独立计;出口代理按设计只放 **repo-scoped 路径**(`/repos/{o}/{r}/...`)加 `/rate_limit`,org 级端点未实测。下文每条 ✓ = **2026-08-23 在真实会话里实调通过**(未另标日期者同此日);⛔ 未带 ✓ 的形状不当已验证事实复述。 + +## 读侧 —— 全部可迁移(MCP list/search 家族才是 GraphQL 燃烧源) + +- ✓ 按标签/状态列卡:`GET /repos/{o}/{r}/issues?state=open&labels=a,b&per_page=N` —— `labels=` 是**真 AND**(MCP `list_issues` 的 labels 数组是 OR;语义相反那条住 `platform-readings.md`)。 +- ✓ 卡 / PR 元数据:`GET .../issues/{n}` · `GET .../pulls/{n}`(assignees、labels、body 齐全 —— MCP `list_issues` 永不返回 assignees,这条差别本身就是走 REST 的理由)。 +- ✓ 整条评论线:`GET .../issues/{n}/comments?per_page=100`。 +- ✓ Timeline 事件:`GET .../issues/{n}/timeline`(cross-ref、`added_to_merge_queue`、ready_for_review)。 +- ✓ PR diff / 文件清单:`GET .../pulls/{n}` 带 Accept `application/vnd.github.diff` · `.../pulls/{n}/files`(后者实测可瞬态 404 ⇒ PR 文件读取优先走 git)。 +- ✓ 取某 ref 上的文件:`GET .../contents/{path}?ref=...`(raw accept)。 +- ✓ 祖先 / 对比:`GET .../compare/{base}...{head}` —— 浅检出上本地祖先判据不可信时的正解。 +- ✓ 门禁 / workflow:`GET .../commits/{sha}/check-runs` · `GET .../actions/runs`。 +- ✓ 配额自读:`GET /rate_limit`(端点自身零计费,开轮先读的就是它)。 + +## 写侧 —— 全部可迁移 + +- ✓ 评论:`POST .../issues/{n}/comments`;改评论 `PATCH .../issues/comments/{id}`。 +- ✓ 标签:**加法** `POST .../issues/{n}/labels` + **定向删** `DELETE .../issues/{n}/labels/{name}` —— 比 MCP `issue_write` 的整组替换安全:加法写剥不掉并发席位刚挂的标签(整组替换按隔轮旧读数回写会静默剥标,纪律住 `platform-readings.md`)。 +- ✓ 建卡带标签 `POST .../issues` · 改正文/状态 `PATCH .../issues/{n}` · 认领 `POST .../issues/{n}/assignees`。 +- ✓ 请求复审 `POST .../pulls/{n}/requested_reviewers` · 开 PR `POST .../pulls`(带 `draft=true`;GraphQL 池为 0 的同一分钟里实测开得出 draft PR ⇒ 交付不必等重置)。 + +## 不可迁移 —— 只有这几件,围着它们排计划 + +1. **draft → ready 翻转**:GraphQL-only mutation;出口代理只放钉住的 PR-review GraphQL 集(实测拒绝)。判据 = REST 的 update-a-pull-request 只收 `title`/`body`/`state`/`base`/`maintainer_can_modify`,**无 `draft`**(下面 2 与 5 同批核对:2026-08-24 核对官方 REST 文档,未逐个实调端点)。断粮出路:等 MCP 恢复,或人工点一下。 +2. **auto-merge / 入队挂载**:GraphQL mutation(MCP `enable_pr_auto_merge`)。走合并队列的仓落地必经它 ⇒ 配额红窗**无退路**;直合仓有退路(合并本身有 REST 端点 `PUT .../pulls/{n}/merge`)。 +3. **语义搜索**:`/search/*` 被出口代理按设计拒绝。退路 = REST 列表端点 + 本地 grep(既有纪律)。 +4. **Projects field_values**:GraphQL-only —— 舰队并不需要它;MCP 服务器端**无条件**抓它才是漏点,不是需求。 +5. **`issue transfer`**(2026-08-24 官方 REST 文档核对补入;原表只列前四件):issues 端点表里没有 transfer 路由 ⇒ 同为 GraphQL-only。拿不到时当轮改走「在目的仓重建」配方(纯 REST、配额免疫),配方住 `platform-readings.md`。 + +`until remaining > 阈值` 的守候只留给这几件,⛔ 其余一切不为配额空等。 + +## 第三桶 —— git 零配额等价物(先问 git,再问 REST) + +分支存在性、合并队列分支、按内容判落地、squash 验证:四条 `ls-remote` / `git log` 拼写与各自的失效边界是 `platform-readings.md` 的既有正典行,本表只指路 —— ⛔ 不在两处各存一份。 + +## 队列路由的读法(2026-08-24 实测) + +- **`merged_by` 是入队者,⛔ 不是绕队证据**:GitHub 把队列合并归属给**入队的那个账户**,该字段对「队列合并 vs 直接合并」零分辨力。一周内三席各自把人形 `merged_by` 读成「我们绕过了队列」,实测三次全为假 —— 都是队列合并。 +- **问「本仓 auto-merge 是否经队列」,答案来自尝试动作,不来自属性字段**:① 直接合并 `PUT .../pulls/{n}/merge`,强制队列 ruleset 下回 **405 `Changes must be made through the merge queue`**;② PR 上的 `added_to_merge_queue` timeline 事件;③ 对已入队 PR 调 update-branch 回「已入合并队列的分支不能更新,要改先出队」。①② 的拼写与边界是 `platform-readings.md` 队列段的既有行,本条只把三读法归拢成一个判据。 +- ⚠️ **计数不是机理读数(本行是一次被推翻的推断的墓碑)**:「repo 级 `GET .../actions/runs?event=merge_group` 计数为 0 ⇒ required 集为空、队列什么都不校验」这条推断**提出当天即被自身推翻** —— 同一姊妹仓 2026-08-24 11:04Z 首次产出 merge_group run(0 → 8),同日再测 224(阳性对照 `event=pull_request` 全程非零)。计数答的是「至今发生过没有」,不是「机制在不在」:零计数只作**弱先验**,判 required 集为空要读 ruleset 的 required 集本身、或看队列合并是否真在等检查。⛔ 别处写下的计数值一律先复测再用。 +- **required job 名与分片矩阵的改名耦合(现行,自 2026-08-24)**:队列 required 集按 **job / check-run 名**匹配,**workflow 名从不作为 check context 出现**(所以拿 workflow 名在选择器里搜什么也搜不到);改其中任一 job 名**或 test 分片矩阵的形状**,必须**同一笔**更新队列的 required 集,否则队列静默挂起。姊妹仓 objectui 当日配置为 **9 个**:`Lint` · `Type Check` · `Test (shard 1/4 … 4/4)` · `Build & E2E` · `Build Docs` · `Changeset Declaration`。⛔ required 选择只 gate**等待**、不 gate**触发** —— 未列入的检查照跑、算力相同,红了不再挡队列(维护者当日裁定,原话:「我觉得够了」)。 +- **配 required 集时先排掉 push-only job**:`if: github.event_name == 'push'` 的 job 在 `merge_group` 构建上永不报到,列为 required 即挂死队列;未展开的矩阵名(带字面 `${{ }}` 的串)是被跳过的占位符,不是真 context。 diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index f1b9da2e73..988badbe8d 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -113,7 +113,21 @@ export const CEILINGS = new Map([ // 134 → 133: whole-text restructuring round, PR-2 (maintainer ruling // 2026-08-23) — the three write-side sanitizer rows consolidated to one // author rule + one measured-behaviour row per surface (body / comment). - ['.claude/skills/pm-dispatch/references/platform-readings.md', 133], + // 133 → 130 (LOWERED, no ruling needed — shrinking is always legitimate): + // the REST-default read-order flip (maintainer ruling 2026-08-23, 「1+2+3」) + // consolidated the three channel-partition rows into two, and the per- + // operation channel mapping moved out to references/rest-channel.md below. + // The two right-sized-reads rows the same ruling ordered were paid from that + // saving in place, and three lines came back. Headroom 0 again. + ['.claude/skills/pm-dispatch/references/platform-readings.md', 130], + // Per-operation REST/GraphQL/git channel mapping — which fleet operation has + // a REST twin (each row executed in a real session, provenance date carried + // per row), the handful that are GraphQL-only, and the queue-routing + // readings. The policy lives in platform-readings.md's quota section; this + // 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', 46], ['.claude/skills/pm-dispatch/references/review-checklist.md', 82], ['.claude/skills/pm-dispatch/references/landing-operations.md', 82], // Release-aftercare duties — what a lane PM still owes AFTER a tagged release