feat(w05): S2 关系表拆两笔写、S1 自投影类型字典、e2e 跨案例隔离 —— 真跑逼出来的三处

① S2:substitution.relation 拆成两笔同主键覆盖写,中间夹 difference_item ——
   difference_item.substitution_relation_id 声明了 refersTo(要求父行已存在),
   而 relation 的等级/风险/摘要要读 difference_item 的 tally,两张表互相要对方先写。

② S1:总把选中的那一行 chip_type / type_param 原样投一遍(幂等),
   于是这一单的草稿层永不为空 —— parts.chip_type 得以放回 gateLedgers,
   新建的类型随「数据工单确认即入库」一起落进正式表,不再留悬空引用。
   (此前把它删出名单只顾了闸、没顾落地:引用它的表落了地而它自己没落。)

③ e2e:案例 0 之后做跨案例隔离(withDb + isolationCleanup,不论成败都跑、
   失败只告警不拖垮整套)—— LAND_MASTER=1 之下案例 0 为满足 distinct=1 必须把
   共享的原 PN 转挂新类型,那一改会落进主数据,案例 1 共用同一颗料就看到假的类型不一致。
   断言 expectRevised 改名 expectFinalValue:「点名驳回归属」那条对 W05 不适用
   (四步 guide 全空、唯一的 agent 调用发生在意见之前,没有轮次会读到那条观察)。

包版本 2.1.5。pnpm gates 退出码 0。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-08-30 07:06:52 +08:00
co-authored by Claude Opus 5
parent 6636abfc39
commit d420284887
5 changed files with 357 additions and 73 deletions
@@ -54,7 +54,7 @@ export const manifest: ActivityManifest = {
activityId: ACTIVITY_ID,
name: 'ACT-WORK-05 · 差异评估',
/* 重写不是改 —— 同版重装是 no-op(静默丢失,踩过) */
packageVersion: '2.1.1',
packageVersion: '2.1.5',
category: '需求分析与方案匹配',
sdkVersion: '0.1.0-m5',
checksum: 'dev-checksum-part-substitution-assessment',
@@ -179,8 +179,39 @@ export const manifest: ActivityManifest = {
level: 'L2',
predicate: 'validation_record_rows = 1 and validation_record_missing = 0',
},
{ key: 'evidence-credible', label: '证据链可信:每条差异的影响说明与判断依据站得住', level: 'L4' },
{ key: 'values-traceable', label: '参数值与原厂资料对得上:候选与原 PN 的取值来源可追溯', level: 'L4' },
/*
* **两条 L4 补了谓词**(2026-08-30,真跑 e2e 撞见的结构性发现,记入
* `docs/ACT-WORK-05-端到端测试记录.md`)——「裁量项带谓词时谓词说了算」这条纪律
* (2026-08-02 立,`engines.ts` 的 `criterionCheck`:`settledByData`)本仓已有先例,
* 从前 W05 这两条 L4 是裸的(无 `predicate`),而 T_release 全程 `auto` 驱动、
* `submit` 是五个声明式动词之一(`packages/contracts/src/auto-recipe.ts`),
* **没有第六个 `judge` 动词** —— 裁量项没谓词就只能等 `judgement`(Agent 的 `judge`
* 行动)来结算,而这个活动压根不会有 Agent 走到这一步。结果是 `submittable()`
* 对这两条永远读到 `pass:false`,`T_release` 的 `submit` 每一拍都被
* `raiseAcceptance` 拒,而拒绝不算错误(不触发 `failedAt`)、下一拍原样重来 ——
* 稳定地把步数预算耗到 `exhausted`,而不是报错崩溃,所以静态审计与包内自测都没照见它。
*
* 两条谓词只覆盖**客观、基座算得出来的那一半**(有没有值、值哪来的),
* **主观那一半(写得好不好、可信不可信)已经由人工验收清单接住**——S3 审核卡
* 第 1/4 条「逐条对过原料与候选料的参数值…」「影响说明站得住…」正是这两条 L4
* 标签里「站得住」「对得上」那两个字的着落点,人签字通过那一刻已经确认过。
* 谓词为真只说「客观前提具备」,不越权替人下「写得好」这个主观判断。
*/
{
key: 'evidence-credible',
label: '证据链可信:每条差异的影响说明与判断依据站得住',
level: 'L4',
/* 客观前提:每一行都有值(必填不缺)——写得「站不站得住」是 S3 人工验收清单的事 */
predicate: 'substitution_difference_item_missing = 0',
},
{
key: 'values-traceable',
label: '参数值与原厂资料对得上:候选与原 PN 的取值来源可追溯',
level: 'L4',
/* 客观前提:原始参数集不缺、差异明细里逐条的原值候选值也不缺 —— 两值均来自
parts.parameter 的 lookup,不是模型现编;「对不对得上」是 S3 人工验收清单的事 */
predicate: 'parts_parameter_missing = 0 and substitution_difference_item_missing = 0',
},
/* L5 是责任关:那张卡本身就是这道关,卡面上不摆它(基座统一滤) */
{ key: 'gate03-release', label: 'ACT-GATE-03 评审放行:签下去 P-11 落账、P-06 落账,结论供下游消费', level: 'L5' },
],