Skip to content

Commit 078bdcd

Browse files
claude[bot]claude
andauthored
check-half-states self-test: route every nullable predicate row through a wrapper, and delete the 14 literal stray spaces (#12390)
* check-half-states self-test: route every nullable-predicate message assertion through a row-text wrapper The self-test's message assertions read `predicate(...).includes(needle)` on predicates that are three-valued by design (null when clean, a string when the row fires). The moment a change makes such a predicate go clean, that line throws `TypeError: Cannot read properties of null (reading 'includes')` while evaluating t()'s arguments — before t() runs — so the suite ABORTS there, every later case never runs, and the output names a TypeError instead of a row. Generalizes the per-predicate wrapper PR #12272 established for H34 (`const h34row = (...args) => String(fn(...args) ?? '')`) to the remaining 18 predicates, plus the two local nullable helpers (`halves`, `dead27`) that carry the same shape. 145 call sites switched; predicates themselves are unchanged and their `typeof`/`=== null` assertions deliberately stay un-wrapped. Self-test output is byte-identical to before: 1380 cases pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ * check-half-states self-test: close the variable-mediated half of the nullable-.includes population The card's table counted only DIRECT call expressions (`pred(...).includes(`). A second population reaches the same throw through a local const — `const h9NoLine = h9OnHoldNoRestartWhen(...)` then `h9NoLine.includes(...)` — which a call-expression scan cannot see. Measured on the pristine base: 108 such sites across 29 variables, spanning four predicates the card never named (h20, h21, h23, h28). This half is what actually kept the suite aborting: with population A alone fixed, the H9 ablation still died at the first `h9NoLine.includes`. Two shapes, chosen per variable: - no nullability assertion on the const -> wrap the DECLARATION in place (19 variables, zero call-site churn) - `typeof X` / `X === null` asserted -> keep the raw const and add a `XRow` sibling (10 variables, 56 sites switched), because stringifying in place would make those assertions trivially true Audit now reports 0 unsafe receivers in both populations. Self-test output remains byte-identical: 1380 cases pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ * pm-dispatch corpus: delete the 14 literal stray spaces after a Han-adjacent ASCII mark #12081 measured a LINE-END event (a soft break after an ASCII , ; : between Han characters). A faithful re-wrap preserves that space as a literal ", " in source, where the line-end predicate can no longer see it — so the defect migrates rather than disappears. Re-derived on this tree with the card's predicate (literal Han + ASCII ,;: + space + Han, one line, excluding fenced / front-matter / multi-line ruling regions via the ratchet's own state machine): 7 + 6 + 1 = 14, reproducing the card's table exactly. All 14 deleted. Each site has a same-line sibling using the identical mark with NO space (实测存在,churn · 判据的,PM · 哈希:空 · 它不是,它), which is what makes the judgment mechanical rather than stylistic. The enumeration-marker family (semicolon + space + a circled mark such as U+2462 / U+2463) is left untouched — measured, it falls OUTSIDE the predicate by construction (the successor is not Han), so all 6 such sites survive unchanged. Byte delta is exactly -14; line counts are unchanged, so no CEILINGS row moves and no table row widens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e18c870 commit 078bdcd

4 files changed

Lines changed: 306 additions & 238 deletions

File tree

.claude/agents/os-dev.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ push,都在新 head 上重跑并集 —— 至少 ratchet 族 —— **然后**
207207
dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分区、单卡条款、当日变动)。实
208208
:prompt 与本文件冲突时以本文件为准——无条件条款住在这里,错了也在这里改;遇到冲突
209209
就在报告里点明,而不是悄悄选边。下列条款无论 prompt 是否提及都生效——prompt 的沉默是
210-
常态, 不是许可:
210+
常态,不是许可:
211211

212212
- **判断任何事之前先 build。** 过期的 `dist/*.d.ts` 两个方向都撒谎:假红烧掉几轮,去追一个不
213213
存在的问题;假绿让收窄后的导出类型读成「消费者都干净」,而消费者根本没见过新的
@@ -229,7 +229,7 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分
229229
⛔ 永不 `git stash`(共享一个 LIFO 栈,两个 agent 同时 stash 互换条目;机制与 hook 见 AGENTS.md);取
230230
出修复用临时 commit 或 patch 文件,都在自己 worktree 内: `git commit -am wip`
231231
`git reset --soft HEAD~1`;`git diff > /tmp/wip.patch && git checkout -- <paths>``git apply /tmp/wip.patch`。⛔
232-
`origin/main` 是共享指针, 别的 agent 一次 fetch 就推进它:`git reset --soft origin/main` 把你分支点
232+
`origin/main` 是共享指针,别的 agent 一次 fetch 就推进它:`git reset --soft origin/main` 把你分支点
233233
之后**他人已合并的文件**整批 stage 成你的(实测一次四个 agent 的合并文件,commit 前才逮
234234
住)。「我从哪开始」的 reset/diff/log/rebase 一律锚基本规则 1 记录的 `"$BASE"`
235235
- **要做反向验证(「回退修复,看诊断变化」)?先 commit 修复。** 已 commit,恢复只是
@@ -250,7 +250,7 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分
250250
顺序说死:trap 只是崩溃路径上的便利,字节/哈希比对才是证明**; trap 触发只证明 shell 跑了
251251
一个函数,不证明那个函数的效果。④ **空哈希读作 FAILURE,不是「没得比」** ——
252252
`git hash-object` 对解析不到的路径输出的是****,不是另一个哈希。比对对象是该路径的
253-
**HEAD blob** 哈希:空或缺失 ⇒ 失败;不匹配 ⇒ 响亮地非零退出并停下, 别让本轮继续在变异
253+
**HEAD blob** 哈希:空或缺失 ⇒ 失败;不匹配 ⇒ 响亮地非零退出并停下,别让本轮继续在变异
254254
树上测量。
255255
- **拒收类用例断言信封,不断言 throw 本身。** 最小断言集:错误的 **`code``status`** (ADR-0112
256256
信封)。单独的 `expect(...).toThrow()` 不是拒收测试 —— 实测两个方向都致盲:未修复的 driver
@@ -260,7 +260,7 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分
260260
`unrecognized_keys`;守「某个****的判定」→ 要求完整 `safeParse` 绿。对刻意跑在 parse 之前的
261261
规则要求全 parse 绿,是删掉合法覆盖;在判值的规则上只满足于 `unrecognized_keys`,是纵容幻影
262262
检查。拒键与拒值是两个不同的事实。
263-
- **Fixture triage —— 三种处置,不是一把批量改拼写。** 你的改动删掉一个 alias 分支时, 拼着
263+
- **Fixture triage —— 三种处置,不是一把批量改拼写。** 你的改动删掉一个 alias 分支时,拼着
264264
它的每个 fixture 都要逐个重判:**改拼写**(它只是用了 alias);**补声明**(改拼写暴露它从来就
265265
不是 spec 合法);**整个换掉**(它 pin 的恰是你删的那个分支 —— 它的断言持续通过,*正因为
266266
什么都不再产出*)。**按规则的消费半径扫 fixture,不按被编辑的包** —— 其它包的 fixture
@@ -334,7 +334,7 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分
334334
- **报告在 draft PR 时点交付 —— CI 收敛等待归 PM,不归你**(维护者 2026-08-10 拍板)。分支一推
335335
上、draft PR 一开出,立刻交报告;门禁状态如实记录 —— `in_progress` 是诚实值。⛔ draft PR 开
336336
出后永不 sleep、定时等待或空转轮询 CI(实测:空转轮询烧掉的恰是一个红门禁需要的预
337-
算);你报告之后才转红的门禁,会作为同一认领上的补丁轮回来。逐卡例外: 派发词明
337+
算);你报告之后才转红的门禁,会作为同一认领上的补丁轮回来。逐卡例外:派发词明
338338
示「本单等 CI」只为那一张卡恢复等待 —— 以前台轮询,永不用后台 watcher。**本派发契约
339339
压过平台注入的 PR 订阅姿态**(维护者 2026-08-11 裁决):云会话被自动订阅到自己的 PR、注入
340340
了驻留指令时,仍以本文件为准;只有涉及标准文本之外的内容,才在 `open_questions` 记一笔冲
@@ -373,7 +373,7 @@ dispatch prompt 只携带每单增量(裁决引文、裁决 / PM-机制假设分
373373
敛,不是你本地的覆盖面。未申报的收窄不在此列,那是漏跑。 **反轮询与不停轮由同一个
374374
形状同时满足,而且只有这一个:一次前台阻塞等待**(Monitor 带 until 条件,或干脆在前台把那
375375
套件跑完)。⛔ **结束一轮永远不是反轮询的解法** —— 实测一个 agent 正是为了
376-
守「别在 sleep 循环里轮询」才停的轮,把停轮当成了合规的替代路径: 它不是,它恰是本条
376+
守「别在 sleep 循环里轮询」才停的轮,把停轮当成了合规的替代路径:它不是,它恰是本条
377377
明令禁止的那个终点。「主动等」与「被动停」的分界不在你怎么形容这次等待,而在这
378378
一轮还活着没有。⛔ 后台 monitor 不会唤醒你:完成通知是「已无活跃子任务」的声
379379
明,它**作为**停轮触发,而不在被等的活儿之后 —— 一天之内两个座位上四次同形停摆都

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ fire 一轮烟测,判据取**GitHub 上的产出**;③ 每 fire 一轮:读座位
124124
runbook 全序节)。
125125
- **跨仓解锁的判据是「消费方可安装」,不是「上游已合并」**:消费仓以**发布包**消费该上
126126
游(而非 git SHA pin)时,解锁扫描放回前先验证修复已进入消费方可安装的发行版(安装面探
127-
针: 装上的包是否接受新键/新行为);未发版 ⇒ 转 `pm:on-hold` + `Restart-when:` 加消费方安装面
127+
针:装上的包是否接受新键/新行为);未发版 ⇒ 转 `pm:on-hold` + `Restart-when:` 加消费方安装面
128128
判据,⛔ 不回 `pm:queue` —— 回队烧掉的派发注定以 premise-false 收场;发行与依赖升级是人工
129129
动作,hold 评论预写唤醒后的派发形状。pin 消费的仓不适用本条 —— pin 移动即可安装,照
130130
旧走 pin 滞后读数(多仓协调 2)。

.claude/skills/pm-dispatch/references/platform-readings.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# 平台读数事实表(references —— 按需加载)
22

33
出处:主文件「平台读数纪律」。本表 = GitHub API / 工具行为的**实测事实**,做对应操作的那
4-
一刻查阅; 原则住主文件。⛔ 不引用 issue 编号 —— 每条自含失效模式与边界。
4+
一刻查阅;原则住主文件。⛔ 不引用 issue 编号 —— 每条自含失效模式与边界。
55

66
## 队列成员资格与 auto-merge
77

@@ -52,7 +52,7 @@
5252
死假说:auto-merge **不会**在已绿 PR 上静默空转(恢复窗口里两个全绿 PR 挂上即合)。
5353
- enable 后的验证序列:① 先验队列分支(给条目 ~20–30s 建出);② 分支在 ⇒ 结束,⛔ 不翻转;
5454
③ 等待后仍缺席**且队列已见 churn**(更新的条目建出了分支而你的没有 —— 截断下单纯
55-
缺席不充分; 首挂静默不入队实测存在,churn 后翻转即愈)⇒ 翻转一次(`disable``enable`),仍
55+
缺席不充分;首挂静默不入队实测存在,churn 后翻转即愈)⇒ 翻转一次(`disable``enable`),仍
5656
以 timeline 事件验证; ④ ⛔ enable 与它的队列验证之间永不插 `disable` ——「入队」webhook 可
5757
能乱序迟到,armed 窗口里补的 disable 会撤掉已发生的真实入队。
5858
- **队列踢出先认签名再决定重投**:已知 flaky 核对失败签名一致 ⇒ 原样重投;止血修复合入
@@ -195,7 +195,7 @@
195195

196196
- **读数五坑**:`cd X && cmd` 会短路(路径不存在时命令在当前仓继续执行,产出假读数)—— 跨
197197
仓一律 `git -C <path>`; `git grep -c <pat> | wc -l` 数文件数不是命中数;裸名 grep 被幸存家族当子
198-
串命中 —— 退役核验带引号精确名, 更硬判据是查声明
198+
串命中 —— 退役核验带引号精确名,更硬判据是查声明
199199
式(`^(export )?(const|type|interface) <Name>\b`)而非查提及;浅检出上的历史读数不可信
200200
(`merge-base --is-ancestor` 假「非祖先」、`rev-list --count` 截断、`branch -r --contains` 零输出)——
201201
`--deepen` 再判,或走 REST `compare`; **容器里没有 `gh`**(实测 `command -v gh` 退出 1,两个标准路
@@ -271,9 +271,9 @@
271271
两侧收据做算术;双方占同一编号是常态(各取当时 max+1),重编号后进侧。
272272
- **容器重启杀死在飞 dev,现场三态判读**:① 分支已推 + PR 已开 ⇒ 只欠验收(CI 重跑 + 复
273273
核,不动代码); ② 死在 regen 中途(未提交全是生成物、merge commit 已在)⇒ PM 直接续作 ——
274-
build → 整链 regen → 生成物门禁全绿 → 提交推送, 恢复 commit 带 `Recovery commit:` 前缀留审
274+
build → 整链 regen → 生成物门禁全绿 → 提交推送,恢复 commit 带 `Recovery commit:` 前缀留审
275275
计;⚠️ 有的现场 regen 一件没跑,推送前先跑生成物门禁别赌; ③ 死在源码编辑中途 ⇒ 先
276-
读 diff 判完整性 —— docblock 写全动机/失效模式/判据的,PM 可代跑终验后提交, 写一半意图
276+
读 diff 判完整性 —— docblock 写全动机/失效模式/判据的,PM 可代跑终验后提交,写一半意图
277277
不明的 ⛔ 不代提交、记进交接;dev 临时目录(`.os-scratch/` 一类)是工作物不是交付物,清
278278
掉,⛔ 不进 feature PR。
279279
- **零提交的探针分支不是在飞工作**:容器发不出分支删除 refspec(实测
@@ -303,12 +303,12 @@
303303
`out of scope: #N` / `#N remains open`)。实测边界三条:关键词只绑**同一行**`#N`;动名
304304
词(closing/fixing)不是关键词;行内反引号里的关键词不触发(code span 实测不建闭合链接;围栏
305305
块未独立实测,按同规则对待但留待复测)。
306-
- **PR body 与 squash commit message 是两个独立解析源**(commit 干净 ≠ body 干净, 只查 commit 会
306+
- **PR body 与 squash commit message 是两个独立解析源**(commit 干净 ≠ body 干净,只查 commit 会
307307
漏);误关的卡以 `completed` 状态对一切「只看 open」的过滤与巡检隐身,无任何机械守卫覆盖
308308
这条路径 —— 消费侧检查 = 合并后读 `closed_by_pull_requests`(在复核清单)。
309309

310310
## 断粮检测与跨墙恢复细则(5 小时用量墙)
311311

312312
原则、定时器选型(⛔ 不用 send_later 链)与恢复 playbook 在主文件;事实补遗:`npx ccusage blocks`
313-
器内可用(读本地会话记录),报当前 5 小时窗口边界/剩余与燃烧率; 盲区:窗口起点是本地推
313+
器内可用(读本地会话记录),报当前 5 小时窗口边界/剩余与燃烧率;盲区:窗口起点是本地推
314314
断的近似值;撞墙报文形如「limit reached, resets at HH:MM」(重置时刻只在此刻可得)。

0 commit comments

Comments
 (0)