From c3ab236f703e0b4c078c6c720132d0c2eba69f5c Mon Sep 17 00:00:00 2001 From: xcs Date: Thu, 27 Aug 2026 00:33:27 +0800 Subject: [PATCH] =?UTF-8?q?fix(w05):=20s=5Fbound=20=E5=93=A8=E5=85=B5?= =?UTF-8?q?=E5=8F=AA=E5=9C=A8=E7=9C=9F=E6=9C=89=E6=96=99=E5=8F=B7=E4=B8=8D?= =?UTF-8?q?=E5=9C=A8=E5=BA=93=E6=97=B6=E5=BC=80=E9=97=A8;=E5=85=A8?= =?UTF-8?q?=E5=8C=85=E6=B8=85=E6=8E=89=20disable=20=E6=95=99=E5=AD=A6;vers?= =?UTF-8?q?ion=201.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 浏览器全流程走查(样例 1「都在库·常路」)熔断,根因两条:①disable 在本引擎里不可达 (Disabled 只能从 Enabled 来,普通计划项一直停在 Available,disable 恒被拒);②s_bound 在每条路上都开(只看 demand_request_rows/sub_eval_pn_check_rows 两个恒真的读数),都在库 时把两个数据工单项照样推进「当下可为」,逼模型去 disable 它们、连拒五拍。 修:s_bound 的 onPart/ifPart 都改盯 sub_eval_pn_check_exists_status_absent > 0 —— 都在库时门不开,两项静静停在 Available、不进「当下可为」、根本用不上 disable;有缺库时 门照常开。S0_bind 的 guide 与其余各处教 disable 的句子全部清掉,改写清楚「都在库你什么 都不用做」,并明写「任何时候都不要对计划项用 disable」。s_p08_created 未动(都在库时 parts_profile_rows 本就是 0,它本来就不开)。 steps.test.ts 补两条回归测试:s_bound 条件文本含 sub_eval_pn_check_exists_status_absent > 0(退回旧写法会红);NARRATIVE 与全部 ASSESSMENT_STEPS[].guide 里不出现「disable + 计划 项 id」这种祈使形(正则只逮教模型真去调用的句子,不误伤「不要用 disable」这类禁止句)。 manifest.ts 的 identity.packageVersion 1.0.0 → 1.0.1(安装恒新增,不升版本改动装不进去); pnpm activities:install 已重装,静态审无提示(零发现,清单行未追加 findings 后缀)。 48/48 测试(steps.test.ts 18 + activity.test.ts 30)与 typecheck 全绿。 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh --- .../__tests__/steps.test.ts | 20 +++++++++++-- .../src/case-model.ts | 28 ++++++++++--------- .../src/manifest.ts | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/activities/part-substitution-assessment/__tests__/steps.test.ts b/activities/part-substitution-assessment/__tests__/steps.test.ts index 41549fc..a6a68f2 100644 --- a/activities/part-substitution-assessment/__tests__/steps.test.ts +++ b/activities/part-substitution-assessment/__tests__/steps.test.ts @@ -154,14 +154,30 @@ describe('说明书与剧本的骨架', () => { expect(s3).toContain('工具调用后同拍其余动作作废'); }); - it('S0 剧本写明库里都有就 disable S0d 两项;S0d_p08_master 剧本写明候选 ≥2 才问、=1 必建、原 PN 硬阻塞', () => { + it('S0 剧本写明都在库时数据工单两项本就不会进「当下可为」;S0d_p08_master 剧本写明候选 ≥2 才问、=1 必建、原 PN 硬阻塞', () => { const s0 = ASSESSMENT_STEPS.find((s) => s.item === 'S0_bind')?.guide ?? ''; - expect(s0).toContain('disable S0d_p08_master'); + expect(s0).toContain('当下可为'); + expect(s0).toContain('不要对计划项用'); const s0d = ASSESSMENT_STEPS.find((s) => s.item === 'S0d_p08_master')?.guide ?? ''; expect(s0d).toContain('硬阻塞'); expect(s0d).toContain('候选只有 1 颗'); }); + it('s_bound 哨兵真的检查了「有料号不在库」这件事(都在库时门不该开;退回旧写法会红)', () => { + expect(CMMN_XML).toContain('sub_eval_pn_check_exists_status_absent > 0'); + const sBoundBlock = /[\s\S]*?<\/sentry>/.exec(CMMN_XML)?.[0] ?? ''; + expect(sBoundBlock).toContain('caseFileItemRef="sub_eval_pn_check_exists_status_absent"'); + expect(sBoundBlock).toContain('sub_eval_pn_check_exists_status_absent > 0'); + }); + + it('说明书与全部剧本里不会教模型对计划项调用 disable(允许出现在「不要 disable」这类禁止句里)', () => { + // 只逮「disable + 计划项 id」这种祈使形(教模型真的去调用它); + // 「不要…用 `disable`」「Disabled 只能从 Enabled 来」这类禁止句/状态名不含「disable + id」,不会被误伤。 + const disableCallPattern = /disable\s+(S\d[a-zA-Z_]*|T_release)/; + expect(NARRATIVE).not.toMatch(disableCallPattern); + for (const step of ASSESSMENT_STEPS) expect(step.guide, step.item).not.toMatch(disableCallPattern); + }); + it('S0d 拆成两项各自绑自己的 view(P-10 那份件不会永远推不出来),两项都没有 doneWhen', () => { const p08 = ASSESSMENT_STEPS.find((s) => s.item === 'S0d_p08_master'); const p10 = ASSESSMENT_STEPS.find((s) => s.item === 'S0d_p10_document'); diff --git a/activities/part-substitution-assessment/src/case-model.ts b/activities/part-substitution-assessment/src/case-model.ts index 701ec80..a70c194 100644 --- a/activities/part-substitution-assessment/src/case-model.ts +++ b/activities/part-substitution-assessment/src/case-model.ts @@ -9,8 +9,8 @@ * 工作区件,不能共用同一个 view): * 启动期 → S0_bind(AI:铸案号、建 P-01 V1、锁规则版本、逐个 PN 查库、写存在性核对表) * 0.5a 等待数据(建主数据)→ S0d_p08_master(人:数据工单 P-08;候选 ≥2 缺库先决策卡; - * 库里都有就 disable 这一项) - * 0.5b 等待数据(建资料)→ S0d_p10_document(人:数据工单 P-10;库里都有就 disable 这一项) + * 都在库时哨兵不开,这一项与下一项都不会进「当下可为」) + * 0.5b 等待数据(建资料)→ S0d_p10_document(人:数据工单 P-10;都在库时同样不会进「当下可为」) * 1 建立评估上下文 → S1_input_confirm(人:执行工单 01,评估输入清单,件上补缺口) * 2 读取并标准化 → S2_normalize(AI:P-11 主记录骨架 + 差异明细对照行) * 3 逐项差异评估 → S3_assess(AI + 两枚工具:四态 / 风险 / 证据 / 影响 / 推荐等级 / 验证任务) @@ -61,10 +61,10 @@ export const CMMN_XML = ` - + - update - demand_request_rows > 0 and sub_eval_pn_check_rows > 0 + update + demand_request_rows > 0 and sub_eval_pn_check_rows > 0 and sub_eval_pn_check_exists_status_absent > 0 @@ -108,13 +108,13 @@ export const CMMN_XML = ` - + - + @@ -181,7 +181,7 @@ export const NARRATIVE = `§0 开案:**判断候选料号在技术上能不能 **存在性检查与数据工单**:启动时逐个料号在 \`parts.profile\` 里查(原 PN + 每个候选)。查无记录 = 「完全没有」, 要人从零建整条主数据 —— 发**数据工单**(一张表一张单:P-08 一张、P-10 一张);PN 在库但个别字段缺 = 「有而不全」, 归执行工单 01 补。原 PN 缺 = 硬阻塞必须建;候选缺:候选 ≥2 时先问人放弃还是创建,候选 = 1 时必须建。 -**库里都有就把 S0d_p08_master 与 S0d_p10_document 两项都 disable 掉**(此单不走这条),别发空单。 +**库里都有的话这两项的入场前提本就不成立**(此单不走这条),不会出现在你的「当下可为」里,别发空单。 **六步走**:绑定与存在性核对 → (等待数据)→ 人补评估输入 → 标准化对照表 → 逐项评估 → 人审结论(可循环)→ 拟落账 → 人放行。 @@ -298,8 +298,10 @@ current_stage = "assessing"。application_scenario / bom_position **这一步不 【写 \`${D}.verdict\` 一行】eval_ref、request_id、rule_version = "${RULE_VERSION}"、original_internal_pn、candidate_total = 候选数组长度。 -写完引擎自己收这一项。收完先看 \`${D}.pn_check\`:有 absent 的 → 下一项是 S0d_p08_master(数据工单);一个 absent 都没有 → -**disable S0d_p08_master 与 S0d_p10_document 两项**(reason 写「原 PN 与全部候选都在库,无需建主数据」),然后等 S1 那一项 Enabled。`, +写完这一项就结束。有 absent 的 → 下一项是 S0d_p08_master(数据工单),照常往下办。 +**都在库的话你什么都不用做** —— 数据工单那两项的入场前提本就不成立,它们不会出现在你的「当下可为」里, +下一拍你会直接看到「评估输入与资料补齐确认」那一步。**任何时候都不要对计划项用 \`disable\`**: +本引擎里 \`Disabled\` 只能从 \`Enabled\` 来,而普通计划项一直停在 \`Available\`,disable 一定被拒。`, }, { item: 'S0d_p08_master', @@ -309,7 +311,7 @@ current_stage = "assessing"。application_scenario / bom_position **这一步不 view: 'p08-master-create', tools: [], /* 触达人,不给 doneWhen;人工激活:发卡就算启动 */ - guide: `这一项只在 \`${D}.pn_check\` 里有 absent 行时走;都在库就由 S0_bind 把这一项与下一项 S0d_p10_document 一起 disable 掉。**先分岔,再动作**: + guide: `这一项只在 \`${D}.pn_check\` 里有 absent 行时走 —— 都在库时入场前提本就不成立,这一项与下一项 S0d_p10_document 都不会进你的「当下可为」。**先分岔,再动作**: 【先看轨迹】这一项里已经发过哪些卡、人答了什么(【当前这一步】下面那行引擎事实说得清楚): · 原 PN absent → **硬阻塞**,不问人,直接进入「建」的名单; @@ -341,8 +343,8 @@ current_stage = "assessing"。application_scenario / bom_position **这一步不 view: 'p10-document-create', tools: [], /* 触达人,不给 doneWhen;人工激活:发卡就算启动 */ - guide: `这一项只在 \`${D}.pn_check\` 里有 absent 行时走(要走到这一步,S0d_p08_master 必然已经收完);都在库就由 S0_bind 把这一项与 -S0d_p08_master 一起 disable 掉。 + guide: `这一项只在 \`${D}.pn_check\` 里有 absent 行时走(要走到这一步,S0d_p08_master 必然已经收完);都在库时入场前提本就不成立, +这一项与 S0d_p08_master 都不会进你的「当下可为」。 【发 P-10 数据工单】「建」的名单就是 \`${D}.pn_check\` 里仍是 exists_status = "absent" 的那几行(候选 ≥2 时被放弃的那些, S0d_p08_master 那一步已经把它们改成 "abandoned",不在这份名单里)。同一拍照说明书④发那张 P-10 数据工单(title 里列全料号,只发一次), diff --git a/activities/part-substitution-assessment/src/manifest.ts b/activities/part-substitution-assessment/src/manifest.ts index 1dad0f8..4d32c57 100644 --- a/activities/part-substitution-assessment/src/manifest.ts +++ b/activities/part-substitution-assessment/src/manifest.ts @@ -84,7 +84,7 @@ export const manifest: ActivityManifest = { identity: { activityId: ACTIVITY_ID, name: 'ACT-WORK-05 · 差异评估', - packageVersion: '1.0.0', + packageVersion: '1.0.1', category: '需求分析与方案匹配', sdkVersion: '0.1.0-m5', checksum: 'dev-checksum-part-substitution-assessment',