feat(contracts): PlanStep.humanWrites —— 人填的表模型不许写;还欠一张卡的那一步不摆 doneWhen

柴浩实测单 6ddcecf8(连撞五拍熔断):P-10 资料记录的标题 / 版本 / 链接与台账里 `LM2596S-5.0` 那一行
**逐字相同** —— 不是幻觉,是「手边有一行看着对的就拿来用」(那一步 reads 摊开了 `parts.document`,
视野里唯一一份真资料就是原 PN 的)。行找对了、料找错了,而这份假证据会直接喂进差异比对当「硬约束有证据支持」。
三层合谋:①把 P-08 的回卡认成 P-10 的(P-10 的卡从没发过);②08-27 给这一步加的 doneWhen 把
「资料必填不缺」摆成目标、后面还跟「成立了就 finish」,**与同一份提示词里「唯一合法的动作是先发那一张卡」
直接打架**;③它顺手把 `exists_status` 改成 created,按剧本发卡名单自己空了 —— 一个合法动作都不剩。

止血两刀:
①**`PlanStep.humanWrites`**(契约,可选字段、老活动一个字不用改):声明的台账 `write` 当场拒并指路
  「去发那张卡,值由人填」;`drop` 不拦(写错了得撤得掉)。判法认点名的项,点不出退回当下在办的那一步
  (压拍时骨架写在上一步名下正好放行)。**只声明「模型永远没有来源」的表** —— 有附件时该预填的
  (P-08 的参数值从 datasheet 抽)别声明,那是它的活。
②**还欠一张卡的那一步不摆 doneWhen** —— 判据同时是摆在模型眼前的目标,而它此刻只许发卡。

W05@1.6.5 声明 `humanWrites: ['parts.document']` 并从 writes 去掉。4 测(墙 / 放行 / drop / 声明)。
**一个闲着的模型 + 一个它够得着的判据 = 它一定会去凑那个判据。**
契约变更四步:depcruise 反查下游绿、loop-engine CONTRACT.md 同步、api-report 随本提交入库、
可选字段非破坏性。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167qWjeyBwvfdGovd7FWbCu
This commit is contained in:
xcs
2026-08-28 12:38:26 +08:00
co-authored by Claude Opus 5
parent e1d8d86b16
commit 2cef6f7489
11 changed files with 157 additions and 4 deletions
+16
View File
@@ -175,6 +175,22 @@ export const planStepSchema = z.object({
* 卡上一条一枚「达标 / 不达标」开关,全部达标才能「确认通过」。
*/
acceptanceChecklist: z.array(z.string().min(1)).optional(),
/**
* **这一步的这几张台账归人填,模型不许写**(2026-08-28 用户实测逼出来的)。
*
* 数据工单要人在件上补的那几张表 —— 值只可能从人那儿来,模型没有任何来源。
* 实测:P-10 原厂技术资料那一步,模型以为卡已经答过了,又被 `doneWhen`(资料必填不缺)
* 摆成目标,就把**台账里原 PN 那一行的规格书**(标题 / 版本 / 链接逐字)抄到了候选料号头上 ——
* 行找对了、料找错了,而这份假证据会直接喂进差异比对当「硬约束有证据支持」。
*
* 一个闲着的模型 + 一个它够得着的判据 = 它一定会去凑那个判据。所以这里立墙:
* 声明了的地址,`write` 当场拒并指路「发那张卡去,值由人填」。`drop` 不拦(写错了得撤得掉)。
*
* **只声明「模型永远没有来源」的表**。有附件时该预填的(P-08 的参数值从 datasheet 抽)别声明 ——
* 那是它的活。判法认点名的项,点不出退回当下在办的那一步。
*/
/* 可选:老活动一个字都不用改(`writes`/`reads` 用 default([]) 是历史,这里不跟 —— 加默认值会逼六个包全改) */
humanWrites: z.array(z.string()).optional(),
});
export type PlanStep = z.infer<typeof planStepSchema>;