Archived
fix(w05): S0d 拆成 P-08/P-10 两个计划项各自绑 view;补齐 fresh() 三面旗;候选全放弃防死锁
Task 4 审查发现 S0d_master_data 固定单一 view 导致 P-10 那份件在引擎里永不可达 (剧本声明的 view 恒压过模型的 say.view),按裁决拆成 S0d_p08_master / S0d_p10_document 两个计划项,各自绑 p08-master-create / p10-document-create;caseFileModel 补 parts_profile_rows、新增哨兵 s_p08_created 串起两步的入场前提;说明书三处 itemId、 S0_bind 的 disable 提示、ASSESSMENT_PHASES 第一段随之更新。steps.test.ts 的 fresh() 补齐 input_confirmed_total / review_approved_total / landing_prepared_total 三面旗 (此前因未绑定名比较求值为假才没暴露)。S0d_p08_master 剧本加「至少留一颗候选」规则, 防止候选全被放弃导致 s_pns_resolved 永远不成立的死锁。46/46 测试与 typecheck 全绿。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
@@ -10,8 +10,8 @@ import { createMockHost } from '@sdk';
|
||||
import { manifest, D, RULE_VERSION } from '../src/manifest.ts';
|
||||
import activity from '../src/index.ts';
|
||||
|
||||
const ITEMS = ['S0_bind', 'S0d_master_data', 'S1_input_confirm', 'S2_normalize', 'S3_assess', 'S4_review', 'S5_prepare_landing', 'T_release'];
|
||||
const NO_DONE_WHEN = new Set(['S0d_master_data', 'S1_input_confirm', 'S4_review', 'T_release']);
|
||||
const ITEMS = ['S0_bind', 'S0d_p08_master', 'S0d_p10_document', 'S1_input_confirm', 'S2_normalize', 'S3_assess', 'S4_review', 'S5_prepare_landing', 'T_release'];
|
||||
const NO_DONE_WHEN = new Set(['S0d_p08_master', 'S0d_p10_document', 'S1_input_confirm', 'S4_review', 'T_release']);
|
||||
const VIEWS = ['p08-master-create', 'p10-document-create', 'eval-input-list', 'difference-review', 'landing-confirm'];
|
||||
const byAddress = (domain: string, object: string) => manifest.declarations.ledger.find((l) => l.domain === domain && l.object === object);
|
||||
const viewHtml = (name: string) => manifest.assets.viewTemplates.find((t) => t.name === name)?.html ?? '';
|
||||
@@ -124,20 +124,26 @@ describe('台账声明:授权面与《统一方案》口径', () => {
|
||||
});
|
||||
|
||||
describe('案例模型与清单的对齐', () => {
|
||||
it('八个计划项,剧本 item 与 CMMN humanTask id 一一对应', () => {
|
||||
it('九个计划项,剧本 item 与 CMMN humanTask id 一一对应', () => {
|
||||
const cmmnIds = [...manifest.assets.businessModel.cmmnXml.matchAll(/<humanTask id="([^"]+)"/g)].map((m) => m[1] ?? '');
|
||||
expect(cmmnIds).toEqual(ITEMS);
|
||||
expect((manifest.assets.businessModel.steps as ReadonlyArray<{ item: string }>).map((s) => s.item)).toEqual(ITEMS);
|
||||
});
|
||||
|
||||
it('四处不给 doneWhen(数据工单 / 输入确认 / 审核 / 放行),其余四处都给', () => {
|
||||
it('五处不给 doneWhen(两张数据工单 / 输入确认 / 审核 / 放行),其余四处都给', () => {
|
||||
for (const s of manifest.assets.businessModel.steps as ReadonlyArray<{ item: string; doneWhen?: string }>) {
|
||||
if (NO_DONE_WHEN.has(s.item)) expect(s.doneWhen, s.item).toBeUndefined();
|
||||
else expect(s.doneWhen, s.item).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it('那四项在 CMMN 里都标了人工激活', () => {
|
||||
it('两张数据工单件各自绑自己的 view(P-08 与 P-10 不共用同一份画面)', () => {
|
||||
const steps = manifest.assets.businessModel.steps as ReadonlyArray<{ item: string; view?: string }>;
|
||||
expect(steps.find((s) => s.item === 'S0d_p08_master')?.view).toBe('p08-master-create');
|
||||
expect(steps.find((s) => s.item === 'S0d_p10_document')?.view).toBe('p10-document-create');
|
||||
});
|
||||
|
||||
it('那五项在 CMMN 里都标了人工激活', () => {
|
||||
for (const id of NO_DONE_WHEN) {
|
||||
const block = new RegExp(`<humanTask id="${id}"[\\s\\S]*?</humanTask>`).exec(manifest.assets.businessModel.cmmnXml)?.[0] ?? '';
|
||||
expect(block, id).toContain('manualActivationRule');
|
||||
@@ -159,7 +165,7 @@ describe('案例模型与清单的对齐', () => {
|
||||
|
||||
it('两种决策卡骨架都在说明书里:候选放弃/创建(create/abandon)与审核(approve/reject/custom:)', () => {
|
||||
const n = manifest.assets.businessModel.narrative;
|
||||
expect(n).toContain('"kind":"decide","itemId":"S0d_master_data"');
|
||||
expect(n).toContain('"kind":"decide","itemId":"S0d_p08_master"');
|
||||
expect(n).toContain('"value":"create"');
|
||||
expect(n).toContain('"value":"abandon"');
|
||||
expect(n).toContain('"kind":"decide","itemId":"S4_review"');
|
||||
|
||||
Reference in New Issue
Block a user