fix(w05): s_bound 哨兵只在真有料号不在库时开门;全包清掉 disable 教学;version 1.0.1

浏览器全流程走查(样例 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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
xcs
2026-08-27 00:33:27 +08:00
co-authored by Claude Fable 5
parent 148d16a1b7
commit c3ab236f70
3 changed files with 34 additions and 16 deletions
@@ -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 &gt; 0');
const sBoundBlock = /<sentry id="s_bound">[\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 &gt; 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');