test(桥): 四个桥的 relay-policy 必须逐字相同 + 钉住 in_reply_to 缺方向判据

## 新增 client/electron/test/cross-bridge-prompt.test.mjs(5 条,登记进 SUITE)

`relay-policy.js` 是 pi/dsh/zcode/opencode **各存一份的手抄副本**(当前
四份 md5 相同),它直接决定提示词里对模型说的话。修 `in_reply_to` 那一族
要改四个地方,**漏一个就会让分叉活到线上**。本判据就是防那个。

与 `cross-client-logic` 的分工:那边比**行为**(electron/harmony 两套类型
系统,只能跑同一张表比结果);这边比**字节**(同一个 node 运行时下的四份
JS 拷贝,没有任何语言差异要归一 ⇒ 字节相等是最便宜也最严格的判据)。
枚举挡实例、行为判据挡漂移,两者配对。

## 5 条的形状

· 4 条绿:四份 `relay-policy.js` + 四份 `relay-policy.test.mjs` 逐字相同,
  且四个桥都存在(少一个即部署事故,当场红)。
  ★ 已实测它**有牙**:往 dsh 那份尾部加一行注释,判据立刻红并指名
  `✗ dsh sha12=…`(不是笼统说"有分叉"),随后已还原、四份 md5 复验一致。
· 1 条**故意红**:`inboundHeadline` 不得只凭 `inReplyTo` 非空就宣称
  「你上一封信的回复到了」—— 按形状断言(找方向判据字段),不点名实现。

  这条红的就是 `docs/DEBTS.json` 的 `in-reply-to-ignores-direction`:
  压测线索 `stress-thread-21863-15348` 里 8 封全是 `opencode → pi`,
  投递通知却逐封宣称「回的是你那封:<上一封的 id>」,而没有任何一封是
  pi 发出的。单向续信链同样满足「有父邮件」⇒ 纯单向的链被读成双向对话。

  ★ 判据先写好、修完转绿,不写就永远没人知道还欠着 —— 与本仓
  「先钉判据再修」一致;到期动作不是「在提示词里写清楚」(本次已证明
  写清楚没用:通知里逐字写着那句,模型照样每封去核一遍再被带着走)。

## 验证

· `node test/run-all.mjs`:files=35 ran=35 checks=582 pass=571 fail=2
  **skip=9(不是通过)** red=2。
  两个红:① 本文件那条故意红的;② `build-stamp`(BUILD_INFO 记 87c55ac
  vs HEAD 359cb43)—— ★ **已在干净 HEAD 上复现,不是本次引入**,
  与 `shared-workspace-unserialized-deploy` 同一形状(产物与源码分家)。
· 手改 SUITE 登记数字 5(套件只判下界,不手改将来删掉就不红)。
· go 侧 16/16 包绿(须 `GOCACHE=.tmp/gocache`,默认 `/root/.cache/go-build`
  权限被拒)。

## 我自己踩的一个坑(第一次跑就撞上,已修)

初版裸 `readFileSync` ⇒ `criteria-hygiene` 第 2 条红
(「判据目录里不得出现裸 readFileSync」)。已改走 `prose()`。
★ 讽刺处:**本判据主题正是"手抄副本会分叉"**,而我第一版就制造了
一处新分叉(多写一个 import)。这条债说的就是这类形状。
This commit is contained in:
2026-09-28 10:17:09 +08:00
parent 359cb436c3
commit 018d5b3bd8
2 changed files with 184 additions and 0 deletions

View File

@ -100,6 +100,22 @@ const SUITE = [
* 它就是靠这个数字把"新加的判据已经进保护圈"这件事说清楚的。
*/
['test/cross-client-logic.test.mjs', ['--experimental-strip-types', '--no-warnings'], 7],
/*
* ★★ 2026-09-28 新增(显式编辑,手改数字见上面的纪律)。
*
* 四个邮件桥各存一份 `relay-policy.js`(手抄副本),本次**逐字比对**它们。
* 与 `cross-client-logic` 的区别:那边是比**行为**(两套类型系统,只能跑表),
* 这边是比**字节**(同一个 node 运行时下的四份 JS 拷贝,没有语言差异要归一)。
*
* 为它登记的债:`in-reply-to-ignores-direction` —— `inboundHeadline` 只问
* 「有没有父邮件」、不问「父邮件是不是我发的」,于是一条 8 封全单向的压测链
* 被逐封读成「对方在回我」,Agent 把「收到」当新任务,客套到撞 hop 上限。
* 修那一族要改四个地方,**漏一个就会让分叉活到线上** —— 这条判据就是防那个。
*
* ★ 5 条中 4 条当前绿、1 条**故意红**(方向判据那条):判据先写好,
* 修完转绿。不写就永远没人知道还欠着 —— 与本仓「先钉判据再修」一致。
*/
['test/cross-bridge-prompt.test.mjs', [], 5],
// 预设的**行为**判据:每一档都真的画得出来(能真跑,不需要设备 ⇒ 不进 static 欠账)。
// 与 appearance-defaults 那条「清单 id/顺序相等」配对:值判据管清单,行为判据管渲染器。
['test/harmony-presets.test.mjs', ['--experimental-strip-types', '--no-warnings'], 6],