/** * 活动包清单 —— ACT-WORK-05 差异评估(案例活动)。 * * 业务出处:`docs/SS02-ACT-WORK-05-html/`(活动流程与工单说明 / 一键启动入参说明 / * 《SS02-SS03-SS04_Demo台账字段细化与统一方案》/ 四份目标件 / 全流程分支图)。 * 骨架照 E04 / I01 已验证的样子:双级入参 → 活动自持单据 + 共享主数据 → decide 循环做中间审核 → * 终局放行。三处与前两个活动刻意不同,写在这里免得下一个读者当成疏漏: * ① **主数据是六张(P-08/P-10/P-01/P-11 主+子/P-06)**,物理表由平台基线 * (`apps/api/src/app/seed-mvp-data.ts`)物化,这里只**追加**本活动要用的列与标记 * (required / tally / refersTo / requiredWhen 是活动的授权面;声明合并是纯 add-column)。 * ② **数据工单**(PN 不在库时让人从零建整条主数据)= 零输入执行工单 + 工作区的件 * (`mine:parts.profile` / `mine:parts.document` 可加行),确认落草稿层、放行并入正式表 * (守铁律②;文档里「确认即入库」在本平台落成「无审核环节、放行并入」)。一张表一张单。 * ③ 逐项四态与推荐等级**由两枚纯工具算**(规则同时以 D01/D02 两张 DMN 随包冻结当文档), * 模型只负责对照表、证据与影响说明 —— 硬约束 MISMATCH 不可能被措辞改判。 */ import type { ActivityManifest, DmnModel } from '@contracts'; import { activityIdSchema } from '@contracts'; import { ASSESSMENT_SKILLS } from './skills.ts'; import { CMMN_XML, NARRATIVE, ASSESSMENT_PHASES, ASSESSMENT_STEPS } from './case-model.ts'; import { P08_MASTER_CREATE, P10_DOCUMENT_CREATE, EVAL_INPUT_LIST, DIFFERENCE_REVIEW, LANDING_CONFIRM } from './views/report.ts'; import { ACTIVITY_ID_TEXT, D, TOOL_COMPARE, TOOL_RECOMMEND } from './constants.ts'; export { D, RULE_VERSION, TOOL_COMPARE, TOOL_RECOMMEND } from './constants.ts'; const ACTIVITY_ID = activityIdSchema.parse(ACTIVITY_ID_TEXT); /** * 两张判定表 —— **文档形态**(求值器在 `apps/api/src/app/tools/first-party.ts`,与这里同一份规则): * D01 逐参数四态、D02 推荐等级。都是 FIRST:规则从上往下第一条命中即出结论,顺序就是优先级。 */ export const D01_DMN: DmnModel['tables'][number] = { id: 'd01-difference-status', label: '差异四态 D01(R-2026.07)', hitPolicy: 'FIRST', inputs: [ { name: 'compare_result', expression: 'compare_result' }, { name: 'constraint_type', expression: 'constraint_type' }, { name: 'evidence_present', expression: 'evidence_present' }, ], outputs: [{ name: 'difference_status' }, { name: 'risk_level' }], rules: [ { id: 'd01-u', when: ['"unknown"', '-', '-'], then: ['unknown', 'medium'], annotation: '一侧未披露 → UNKNOWN,挂验证任务' }, { id: 'd01-m0', when: ['"equal","covers"', '"hard"', 'false'], then: ['conditional', 'medium'], annotation: '硬约束缺证据不判 MATCH' }, { id: 'd01-m', when: ['"equal","covers"', '-', '-'], then: ['match', 'low'], annotation: '一致或候选范围盖住原范围' }, { id: 'd01-c', when: ['"configurable","partial"', '-', '-'], then: ['conditional', 'medium'], annotation: '可调配成 / 部分重叠 → 条件' }, { id: 'd01-x', when: ['"narrower","differs"', '"hard"', '-'], then: ['mismatch', 'high'], annotation: '硬约束不一致' }, { id: 'd01-s', when: ['"narrower","differs"', '"soft"', '-'], then: ['conditional', 'medium'], annotation: '软约束不一致 → 评估影响' }, ], }; export const D02_DMN: DmnModel['tables'][number] = { id: 'd02-recommendation', label: '推荐等级 D02(R-2026.07)', hitPolicy: 'FIRST', inputs: [ { name: 'hard_mismatch_total', expression: 'hard_mismatch_total' }, { name: 'unknown_total', expression: 'unknown_total' }, { name: 'configurable_total', expression: 'configurable_total' }, { name: 'conditional_total', expression: 'conditional_total' }, ], outputs: [{ name: 'recommendation_level' }], rules: [ { id: 'd02-n', when: ['> 0', '-', '-', '-'], then: ['not_recommended'], annotation: '硬约束失败直接不推荐' }, { id: 'd02-u', when: ['0', '> 0', '-', '-'], then: ['conditional'], annotation: '有 UNKNOWN → 等验证闭环' }, { id: 'd02-a', when: ['0', '0', '> 0', '-'], then: ['alternate'], annotation: '只靠改外围配得成 → 备选' }, { id: 'd02-c', when: ['0', '0', '0', '> 0'], then: ['conditional'], annotation: '其余条件项 → 条件推荐' }, { id: 'd02-r', when: ['0', '0', '0', '0'], then: ['recommended'], annotation: '全 MATCH → 推荐' }, ], }; export const ASSESSMENT_DMN: DmnModel = { drd: [ { decision: 'd01-difference-status', requires: [], inputs: ['compare_result', 'constraint_type', 'evidence_present'] }, { decision: 'd02-recommendation', requires: [], inputs: ['hard_mismatch_total', 'unknown_total', 'configurable_total', 'conditional_total'] }, ], tables: [D01_DMN, D02_DMN], }; /** 字段声明的短写(与 E04 同一套写法:显式 primaryKey / masked,其余按需) */ type F = { name: string; type: 'text' | 'number' | 'integer' | 'boolean' | 'date' | 'timestamp' | 'json'; label: string; primaryKey?: boolean; required?: boolean; expect?: boolean; tally?: string[]; auto?: boolean; distinct?: boolean; refersTo?: string; requiredWhen?: { column: string; value: string } }; const col = (f: F) => ({ primaryKey: false, masked: false, ...f }); export const manifest: ActivityManifest = { identity: { activityId: ACTIVITY_ID, name: 'ACT-WORK-05 · 差异评估', packageVersion: '1.0.0', category: '需求分析与方案匹配', sdkVersion: '0.1.0-m5', checksum: 'dev-checksum-part-substitution-assessment', }, /* ── 契约七件 ────────────────────────────────────────────────── */ contract: { activityId: ACTIVITY_ID, version: '1.0.0', input: { /* * 一键启动只收 4 项(文档《一键启动入参说明》极简原则):客户 / 客户需求 / 原 PN / 候选 PN 数组。 * 应用场景、BOM 位、替代类型、规则版本、负责人期限**不是入参** —— 启动后在执行工单 01 里补。 * datasheet 选填文件:传了 AI 在数据工单件上预填,没传人全填(文档 0c:同为合法路径)。 * `customerName` 只在客户不在库(分支 0a)时用:S0 发数据录入卡建档,名字先摆上去让人核。 */ data: { type: 'object', required: ['customerCode', 'requestDescription', 'originalInternalPn', 'candidateInternalPns'], properties: { customerCode: { type: 'string', title: '客户编码(L-02 客户主台账)', examples: ['CU-0142'] }, customerName: { type: 'string', title: '客户名称(仅客户不在库时填,启动后先建档)', examples: ['深圳恒星电源有限公司'] }, requestDescription: { type: 'string', title: '客户需求(原始描述 —— 据此新建 P-01 需求主记录 · 版本 V1)', examples: ['工业电源项目在用 LM2596S-5.0(TI,12V→5V),原厂 PCN 转 NRND,客户要求验证替代料'], }, originalInternalPn: { type: 'string', title: '原内部料号(P-08)', examples: ['LM2596S-5.0'] }, candidateInternalPns: { type: 'array', title: '候选内部料号(数组,≥1;不在库的启动后经数据工单创建)', items: { type: 'string' }, examples: [['XL2596S-5.0', 'LM2596S-ADJ']], }, datasheets: { type: 'array', format: 'file', title: '候选 datasheet(选填;传了 AI 在数据工单里预填,没传人全填)', items: { type: 'object', properties: { name: { type: 'string', title: '文件名' }, contentType: { type: 'string', title: '类型' }, size: { type: 'integer', title: '字节数' }, ref: { type: 'string', title: '存档号' }, text: { type: 'string', title: '读出来的文本' }, note: { type: 'string', title: '读取说明' }, }, }, }, }, }, messageAllowed: true, messageHint: 'FAE 可在此说明客户的应用边界、验证条件或本轮评估的特殊要求', }, output: { /* 单一必发口:本活动终点是 ACT-GATE-03 评审放行;下游 ACT-WORK-08 尚未实现,按「契约先立」声明 */ mandatory: [ { name: 'assessment-released', description: '差异评估结论已落账(P-11 替代关系主记录 + 差异明细、P-01 回写)—— 供 ACT-WORK-08 证据归集消费;当前无消费者,载荷 = 已落地事实', payload: { type: 'object', required: ['evalRef', 'requestId', 'relationTotal'], properties: { evalRef: { type: 'string', title: '评估案号' }, requestId: { type: 'string', title: '需求编号(P-01)' }, relationTotal: { type: 'integer', title: '落账的替代关系条数' }, recommendedTotal: { type: 'integer', title: '推荐' }, conditionalTotal: { type: 'integer', title: '条件推荐' }, alternateTotal: { type: 'integer', title: '备选' }, notRecommendedTotal: { type: 'integer', title: '不推荐' }, }, }, }, ], selective: [], }, requiredDeliverables: [ { key: 'eval-input', label: '评估输入清单', ledger: `${D}.input_gap`, ledgers: [`${D}.input_gap`, `${D}.pn_check`, `${D}.verdict`], editableAtRelease: [] }, { key: 'difference-items', label: '差异评估结论(P-11 差异明细)', ledger: 'substitution.difference_item', ledgers: ['substitution.difference_item', 'substitution.relation'], editableAtRelease: [] }, { key: 'landing', label: '拟落账内容(P-11 主记录 + P-01 回写)', ledger: 'substitution.relation', ledgers: ['substitution.relation', 'demand.request'], editableAtRelease: [] }, ], /* * 验收判据 —— L1/L2 只读基座读数;L4 三条是文档验收工单 01/02 里留给人的裁量; * 「推荐等级与明细一致」「硬约束不判 MATCH」机器已由工具守住,这里仍留 L4 让签字的人过目。 */ acceptanceCriteria: [ { key: 'input-confirmed', label: '评估输入已经 PW 补齐确认:执行工单 01 已交回,缺口行的补充内容都有,补不了的留了 UNKNOWN', level: 'L1', predicate: `input_confirmed_total > 0 and ${D}_input_gap_rows > 0 and ${D}_input_gap_missing = 0`, }, { key: 'review-approved', label: '差异评估结论已经 FAE/RI 审核通过:验收工单 01 已过,不处在驳回待改状态', level: 'L1', predicate: 'review_approved_total > 0 and substitution_difference_item_rows > 0 and substitution_difference_item_missing = 0', }, { key: 'every-candidate-assessed', label: '每个未放弃的候选都有一条替代关系记录(N 候选 = N 条 P-11,并行独立落账)', level: 'L2', predicate: `substitution_relation_rows > 0 and substitution_relation_rows + ${D}_pn_check_exists_status_abandoned + 1 = ${D}_pn_check_rows`, }, { key: 'every-item-has-status', label: '关键参数差异均有明确状态:每条明细都是 MATCH / MISMATCH / UNKNOWN / CONDITIONAL 之一', level: 'L2', predicate: 'substitution_difference_item_rows > 0 and substitution_difference_item_difference_status_match + substitution_difference_item_difference_status_mismatch + ' + 'substitution_difference_item_difference_status_unknown + substitution_difference_item_difference_status_conditional = substitution_difference_item_rows', }, { key: 'unknown-has-disposition', label: 'UNKNOWN 项均有去向:每个 UNKNOWN 都挂了验证任务或补来源动作,影响说明与证据引用逐条齐全', level: 'L2', predicate: 'substitution_difference_item_missing = 0', }, { key: 'judged-by-rule', label: '四态与推荐等级由规则算出:逐参数比对工具与推荐定级工具都真调过', level: 'L2', predicate: `tool_part_substitution_assessment_compare_parameters_calls > 0 and tool_part_substitution_assessment_recommend_calls > 0`, }, { key: 'analysis-status-confirmed', label: '分析状态与客户批准状态分离:每条 P-11 只写分析层 analysis_status = FAE 确认,规则版本已锁定随结论落账', level: 'L2', predicate: 'substitution_relation_analysis_status_fae_confirmed = substitution_relation_rows and substitution_relation_missing = 0', }, { key: 'p01-writeback-complete', label: '回写 P-01 字段完整:风险等级、验证要求、输出链接、下一步动作、当前阶段五项齐全', level: 'L2', predicate: 'demand_request_rows > 0 and demand_request_missing = 0', }, { key: 'evidence-credible', label: '证据链可信:每条结论都能追溯到 P-08 / P-10 / P-06 的具体记录,或本单数据工单的创建记录(人工录入)', level: 'L4' }, { key: 'hard-not-auto-match', label: '硬约束项未被自动判 MATCH:封装 / 工艺 / 电气边界等硬约束的 MATCH 都有证据支持', level: 'L4' }, { key: 'recommendation-consistent', label: '推荐等级与差异明细一致:存在 UNKNOWN / CONDITIONAL 的候选没有给「推荐」', level: 'L4' }, /* L5 是责任关:那张卡本身就是这道关,卡面上不摆它(基座统一滤) */ { key: 'gate03-release', label: 'ACT-GATE-03 评审放行:签下去 P-11 落账、P-01 回写,结论供下游消费', level: 'L5' }, ], revisableAtRelease: [], prohibitions: [ { key: 'no-fabricated-parameter', statement: 'UNKNOWN 是一等公民:查不到的参数值必须显式写「未披露」并记去向,不得伪造、不得用估计值或空串冒充' }, { key: 'no-override-hard-mismatch', statement: '硬约束 MISMATCH 不得被任何措辞改判 MATCH;要改只能补证据后重比' }, { key: 'no-customer-approval-write', statement: '客户批准状态由独立审批流维护,本活动不写 customer_approval_status(没有这一列的写权)' }, { key: 'no-commercial-judgement', statement: '本活动只答技术可替代性:不做数量、价格、交期、采购判断' }, { key: 'no-rebind', statement: '启动绑定的 4 项(客户 / 需求 / 原 PN / 候选数组)工单内不可改;绑错只能退回触发方重新启动' }, { key: 'no-external-write', statement: '放行前不得触达外部系统 —— 触达世界的动作集中在放行那一刻' }, ], authorization: { discretion: [], preauthorizedActions: [], /* * 基线:数据工单 ≤2 + 候选放弃/创建决策 ≤2 + 新客户录入卡 1 + 执行单 01 + 审核决策 1 + 放行 1 = 8; * 审核循环预留两轮(+4)= 12。cap 必须严格大于最后一次拍板时的实际次数(E04 实测栽过),留到 16。 */ humanCallBudget: 16, }, resources: { tools: [{ name: TOOL_COMPARE }, { name: TOOL_RECOMMEND }], skills: ASSESSMENT_SKILLS.map((s) => s.id), models: ['deepseek-v4-flash'], roles: ['FAE/RI'], budget: { steps: 90, tokens: 600_000, activeMinutes: 120, humanCalls: 16 }, }, }, /* ── 声明 ────────────────────────────────────────────────────── */ declarations: { models: ['deepseek-v4-flash'], tools: [{ name: TOOL_COMPARE }, { name: TOOL_RECOMMEND }], ledger: [ /* L-02 客户主台账:只在分支 0a(客户不在库)由数据录入卡建一行 —— 录入卡写的列都得声明 */ { domain: 'customer', object: 'profile', kind: 'master', label: '客户档案', fields: [ col({ name: 'customer_code', type: 'text', label: '客户编码', primaryKey: true }), col({ name: 'name', type: 'text', label: '客户名称', required: true }), col({ name: 'industry', type: 'text', label: '所属行业', expect: true }), col({ name: 'region', type: 'text', label: '区域', expect: true }), ], }, /* P-08 芯片主数据:数据工单建整条;参数集是它的一个字段(一张表,不建子表) */ { domain: 'parts', object: 'profile', kind: 'master', label: '芯片主数据(P-08)', fields: [ col({ name: 'internal_pn', type: 'text', label: '内部料号', primaryKey: true }), col({ name: 'brand_name', type: 'text', label: '品牌名称', required: true }), col({ name: 'manufacturer_name', type: 'text', label: '制造商名称', expect: true }), col({ name: 'specification_description', type: 'text', label: '规格描述', required: true }), col({ name: 'normalized_parameter_set', type: 'text', label: '标准化参数集(一行一参数:参数名 | 值 | 单位 | hard/soft | 说明)', required: true }), col({ name: 'package', type: 'text', label: '封装', required: true }), col({ name: 'process_technology', type: 'text', label: '工艺', expect: true }), col({ name: 'lifecycle_status', type: 'text', label: '生命周期状态', required: true, tally: ['active', 'nrnd', 'eol', 'discontinued', 'risk'] }), col({ name: 'eol_pcn_status', type: 'text', label: 'EOL/PCN 状态', expect: true }), col({ name: 'datasheet_ref', type: 'text', label: 'Datasheet 引用', expect: true }), col({ name: 'datasheet_version', type: 'text', label: 'Datasheet 版本', expect: true }), col({ name: 'application_scenarios', type: 'text', label: '适配应用场景', expect: true }), ], }, /* P-10 原厂技术资料库:数据工单建;评估时只读做证据回链 */ { domain: 'parts', object: 'document', kind: 'master', label: '原厂技术资料库(P-10)', fields: [ col({ name: 'internal_pn', type: 'text', label: '关联内部料号', primaryKey: true }), col({ name: 'doc_seq', type: 'text', label: '资料序号(同一料号下 01/02…)', primaryKey: true }), col({ name: 'document_type', type: 'text', label: '资料类型', required: true, tally: ['datasheet', 'app_note', 'reference_design', 'white_paper', 'sample_doc', 'commitment_letter', 'other'] }), col({ name: 'brand_name', type: 'text', label: '品牌名称', expect: true }), col({ name: 'document_title', type: 'text', label: '资料标题', required: true }), col({ name: 'document_version', type: 'text', label: '资料版本', required: true }), col({ name: 'document_ref', type: 'text', label: '资料文件链接', required: true }), col({ name: 'citation_locator', type: 'text', label: '证据定位(页码/章节/表格)', expect: true }), col({ name: 'document_status', type: 'text', label: '资料状态', required: true, tally: ['valid', 'expired', 'pending', 'void'] }), ], }, /* P-01 需求主记录:S0 新建 V1,放行时回写五项(current_stage = gate03 那一刻五项必填) */ { domain: 'demand', object: 'request', kind: 'master', label: '客户需求主记录(P-01)', fields: [ col({ name: 'request_id', type: 'text', label: '需求编号', primaryKey: true }), col({ name: 'customer_code', type: 'text', label: '客户编码', required: true, refersTo: 'customer.profile.customer_code' }), col({ name: 'requirement_version', type: 'text', label: '需求版本', required: true }), col({ name: 'request_type', type: 'text', label: '需求类型', required: true }), col({ name: 'request_description', type: 'text', label: '需求描述', required: true }), col({ name: 'input_snapshot_ref', type: 'text', label: '输入快照', required: true }), col({ name: 'original_internal_pn', type: 'text', label: '原内部料号', required: true }), col({ name: 'bom_position', type: 'text', label: 'BOM 位', expect: true }), col({ name: 'application_scenario', type: 'text', label: '应用场景', expect: true }), col({ name: 'technical_constraints', type: 'text', label: '技术约束' }), col({ name: 'risk_level', type: 'text', label: '风险等级', tally: ['low', 'medium', 'high', 'critical'], requiredWhen: { column: 'current_stage', value: 'gate03' } }), col({ name: 'verification_requirement', type: 'text', label: '验证/复测/确认要求', requiredWhen: { column: 'current_stage', value: 'gate03' } }), col({ name: 'request_status', type: 'text', label: '需求状态', required: true, tally: ['pending', 'responded', 'won', 'abandoned', 'closed'] }), col({ name: 'current_activity', type: 'text', label: '当前 Activity', requiredWhen: { column: 'current_stage', value: 'gate03' } }), col({ name: 'current_stage', type: 'text', label: '当前阶段' }), col({ name: 'next_action', type: 'text', label: '下一步动作', requiredWhen: { column: 'current_stage', value: 'gate03' } }), col({ name: 'output_ref', type: 'text', label: '标准输出链接', requiredWhen: { column: 'current_stage', value: 'gate03' } }), ], }, /* P-11 替代关系主记录:一候选一条;两枚 PN 都是引用墙(查无此料当场拒 —— 存在性检查的硬门) */ { domain: 'substitution', object: 'relation', kind: 'master', label: '替代关系主记录(P-11)', fields: [ col({ name: 'substitution_relation_id', type: 'text', label: '替代关系ID', primaryKey: true }), col({ name: 'eval_ref', type: 'text', label: '评估案号', required: true }), col({ name: 'request_id', type: 'text', label: '关联需求编号', required: true }), col({ name: 'bom_position', type: 'text', label: '关联 BOM 位', expect: true }), col({ name: 'original_internal_pn', type: 'text', label: '原内部料号', required: true, refersTo: 'parts.profile.internal_pn' }), col({ name: 'candidate_internal_pn', type: 'text', label: '候选内部料号', required: true, refersTo: 'parts.profile.internal_pn' }), col({ name: 'substitution_type', type: 'text', label: '替代类型', required: true, tally: ['pin_to_pin', 'functional', 'parametric', 'other'] }), col({ name: 'recommendation_level', type: 'text', label: '推荐等级', required: true, tally: ['recommended', 'conditional', 'alternate', 'not_recommended'] }), col({ name: 'recommendation_reason', type: 'text', label: '推荐理由', required: true }), col({ name: 'difference_summary', type: 'text', label: '差异摘要', required: true }), col({ name: 'risk_level', type: 'text', label: '替代风险等级', required: true, tally: ['low', 'medium', 'high', 'critical'] }), col({ name: 'verification_requirement', type: 'text', label: '验证要求', requiredWhen: { column: 'recommendation_level', value: 'conditional' } }), col({ name: 'validation_id', type: 'text', label: '关联验证ID' }), col({ name: 'analysis_status', type: 'text', label: '分析状态', required: true, tally: ['ai_draft', 'fae_confirmed', 'pending_customer', 'customer_approved', 'rejected', 'void'] }), col({ name: 'analysis_report_ref', type: 'text', label: '替代分析报告', expect: true }), col({ name: 'confidence_score', type: 'number', label: '证据可信度', expect: true }), col({ name: 'rule_version', type: 'text', label: '差异规则版本', required: true }), ], }, /* P-11 差异明细子表:一条参数一条记录;relation id 上 distinct 让基座数「几条关系有明细」 */ { domain: 'substitution', object: 'difference_item', kind: 'master', label: '差异明细(P-11 子表)', fields: [ col({ name: 'substitution_relation_id', type: 'text', label: '替代关系ID', primaryKey: true, distinct: true, refersTo: 'substitution.relation.substitution_relation_id' }), col({ name: 'difference_item_id', type: 'text', label: '差异明细ID', primaryKey: true }), col({ name: 'parameter_name', type: 'text', label: '标准参数名', required: true }), col({ name: 'original_value', type: 'text', label: '原物料参数值', required: true }), col({ name: 'candidate_value', type: 'text', label: '候选物料参数值', required: true }), col({ name: 'parameter_unit', type: 'text', label: '参数单位', expect: true }), col({ name: 'constraint_type', type: 'text', label: '约束类型', required: true, tally: ['hard', 'soft'] }), col({ name: 'compare_result', type: 'text', label: '比对结果(工具出参)', expect: true }), col({ name: 'difference_status', type: 'text', label: '差异状态', required: true, tally: ['match', 'mismatch', 'unknown', 'conditional'] }), col({ name: 'impact_statement', type: 'text', label: '影响说明(MATCH 写「无」)', required: true }), col({ name: 'unknown_disposition', type: 'text', label: 'UNKNOWN 去向(验证任务号 / 补来源动作)', requiredWhen: { column: 'difference_status', value: 'unknown' } }), col({ name: 'risk_level', type: 'text', label: '风险等级', required: true, tally: ['low', 'medium', 'high'] }), col({ name: 'evidence_ref', type: 'text', label: '差异证据引用', required: true }), col({ name: 'confidence', type: 'number', label: 'AI 置信度', expect: true }), col({ name: 'rule_version', type: 'text', label: '差异规则版本', required: true }), ], }, /* P-06 验证记录:事实类 —— 本活动只写「验证要求」(状态 not_started),不经数据工单建 */ { domain: 'validation', object: 'record', kind: 'master', label: '芯片验证记录(P-06)', fields: [ col({ name: 'validation_id', type: 'text', label: '验证ID', primaryKey: true }), col({ name: 'request_id', type: 'text', label: '关联需求编号', required: true }), col({ name: 'validation_internal_pn', type: 'text', label: '验证内部料号', required: true, refersTo: 'parts.profile.internal_pn' }), col({ name: 'validation_type', type: 'text', label: '验证类型', required: true, tally: ['pin_to_pin', 'functional', 'reliability', 'certification', 'retest'] }), col({ name: 'validation_status', type: 'text', label: '验证状态', required: true, tally: ['not_started', 'in_progress', 'passed', 'failed', 'conditional', 'pending_evidence'] }), col({ name: 'test_condition', type: 'text', label: '测试条件', expect: true }), col({ name: 'next_validation_action', type: 'text', label: '后续验证动作', required: true }), col({ name: 'evidence_ref', type: 'text', label: '验证证据引用', expect: true }), ], }, /* ── 活动自持单据(record,caseKey eval_ref)── */ { domain: D, object: 'pn_check', kind: 'record', caseKey: 'eval_ref', label: '料号存在性核对', fields: [ col({ name: 'eval_ref', type: 'text', label: '评估案号', primaryKey: true }), col({ name: 'internal_pn', type: 'text', label: '内部料号', primaryKey: true }), col({ name: 'role', type: 'text', label: '角色', required: true, tally: ['original', 'candidate'] }), col({ name: 'exists_status', type: 'text', label: '在库状态', required: true, tally: ['found', 'absent', 'created', 'abandoned'] }), col({ name: 'abandon_reason', type: 'text', label: '放弃原因', requiredWhen: { column: 'exists_status', value: 'abandoned' } }), col({ name: 'note', type: 'text', label: '备注' }), ], }, { domain: D, object: 'input_gap', kind: 'record', caseKey: 'eval_ref', label: '评估输入清单', fields: [ col({ name: 'eval_ref', type: 'text', label: '评估案号', primaryKey: true }), col({ name: 'item_key', type: 'text', label: '输入项键', primaryKey: true }), col({ name: 'input_item', type: 'text', label: '输入项', required: true }), col({ name: 'source_ledger', type: 'text', label: '来源台账', expect: true }), col({ name: 'status', type: 'text', label: '状态', required: true, tally: ['gap', 'default', 'ok'] }), col({ name: 'detail', type: 'text', label: '绑定值 / 缺口说明', expect: true }), col({ name: 'supplement', type: 'text', label: '补充内容', requiredWhen: { column: 'status', value: 'gap' } }), col({ name: 'origin', type: 'text', label: '来源(ai/human-added)' }), ], }, { domain: D, object: 'verdict', kind: 'record', caseKey: 'eval_ref', label: '本次评估结论', fields: [ col({ name: 'eval_ref', type: 'text', label: '评估案号', primaryKey: true }), col({ name: 'request_id', type: 'text', label: '需求编号' }), col({ name: 'rule_version', type: 'text', label: '规则版本' }), col({ name: 'original_internal_pn', type: 'text', label: '原内部料号' }), col({ name: 'candidate_total', type: 'integer', label: '候选数' }), col({ name: 'input_confirmed_total', type: 'integer', label: '评估输入已确认' }), col({ name: 'review_approved_total', type: 'integer', label: '差异结论已审核通过' }), col({ name: 'landing_prepared_total', type: 'integer', label: '拟落账已备好' }), col({ name: 'relation_total', type: 'integer', label: '替代关系条数' }), col({ name: 'recommended_total', type: 'integer', label: '推荐' }), col({ name: 'conditional_total', type: 'integer', label: '条件推荐' }), col({ name: 'alternate_total', type: 'integer', label: '备选' }), col({ name: 'not_recommended_total', type: 'integer', label: '不推荐' }), col({ name: 'summary', type: 'text', label: '本次评估结论' }), ], }, ], listeners: [], harness: { memoryWindow: 24, stallAfter: 'PT4H', nudge: [{ after: 'PT2H', action: 'nudge' }], retry: { times: 2, backoff: 'PT30S' }, }, }, /* ── 资产初始版 ──────────────────────────────────────────────── */ assets: { businessModel: { cmmnXml: CMMN_XML, narrative: NARRATIVE, dmn: ASSESSMENT_DMN, steps: ASSESSMENT_STEPS, phases: ASSESSMENT_PHASES }, skills: ASSESSMENT_SKILLS, /* * 五个局面各一张: * · `p08-master-create` —— S0d 摆,数据工单(P-08),件上可加行、可编辑; * · `p10-document-create` —— S0d 摆,数据工单(P-10),同上; * · `eval-input-list` —— S1 摆,评估输入清单:绑定区只读 + 缺口表可编辑; * · `difference-review` —— S2/S3/S4 摆,差异明细 + 各候选推荐等级,只读; * · `landing-confirm` —— S5/T_release 摆,拟写 P-11 / 拟回写 P-01,只读;放行后即归档件。 */ viewTemplates: [ { name: 'p08-master-create', html: P08_MASTER_CREATE }, { name: 'p10-document-create', html: P10_DOCUMENT_CREATE }, { name: 'eval-input-list', html: EVAL_INPUT_LIST }, { name: 'difference-review', html: DIFFERENCE_REVIEW }, { name: 'landing-confirm', html: LANDING_CONFIRM }, ], cardSchemas: {}, distillHooks: [{ on: 'terminal', prompt: '归纳本次差异评估:哪些候选、各自推荐等级与关键依据、UNKNOWN 挂了什么验证任务、审核是否被驳回过(为什么)、数据工单建了哪些主数据。' }], }, /* * ── 样例集:五条形状真不同(常备案例即验收案例)── * 第一条满载且走「候选缺库 → 数据工单」那条最长的路(测试台落地即预填的是它);样例名 ≤14 字。 * 库里只播了 LM2596S-5.0 / LM2596S-ADJ 两颗(见 seed-mvp-data.ts),XL2596S-5.0 / CN-DCDC-32V / LM2596S-3.3 刻意不在库。 */ samples: [ { name: '候选缺库·派数据工单', input: { customerCode: 'CU-0142', requestDescription: '工业电源项目在用 LM2596S-5.0(TI,12V→5V),原厂 PCN 转 NRND,客户要求验证替代料;应用 12V→5V、工业温域、输入上限 40V', originalInternalPn: 'LM2596S-5.0', candidateInternalPns: ['XL2596S-5.0', 'LM2596S-ADJ'], }, expect: { ports: ['assessment-released'] }, }, { name: '都在库·常路', input: { customerCode: 'CU-0142', requestDescription: 'LM2596S-5.0 转 NRND,客户先评估同族可调版 LM2596S-ADJ 能否替代(愿意改外围);应用 12V→5V、工业温域', originalInternalPn: 'LM2596S-5.0', candidateInternalPns: ['LM2596S-ADJ'], }, expect: { ports: ['assessment-released'] }, }, { name: '原PN缺库·硬阻塞', input: { customerCode: 'CU-0142', requestDescription: '客户另一块板在用 LM2596S-3.3(3.3V 固定版),同批 PCN,要求评估 LM2596S-ADJ 替代;应用 12V→3.3V', originalInternalPn: 'LM2596S-3.3', candidateInternalPns: ['LM2596S-ADJ'], }, expect: { ports: ['assessment-released'] }, }, { name: '三候选·含硬约束不推荐', input: { customerCode: 'CU-0142', requestDescription: '工业电源 12V→5V,输入上限 40V,工业温域;三个候选:XL2596S-5.0、LM2596S-ADJ、国产 CN-DCDC-32V(输入上限只有 32V)', originalInternalPn: 'LM2596S-5.0', candidateInternalPns: ['XL2596S-5.0', 'LM2596S-ADJ', 'CN-DCDC-32V'], }, expect: { ports: ['assessment-released'] }, }, { name: '新客户·先建档', input: { customerCode: 'CU-9001', customerName: '深圳恒星电源有限公司', requestDescription: '新客户口述:工业电源 12V→5V 在用 LM2596S-5.0,想评估 LM2596S-ADJ', originalInternalPn: 'LM2596S-5.0', candidateInternalPns: ['LM2596S-ADJ'], }, expect: { ports: ['assessment-released'] }, }, ], entry: { file: 'index.js', checksum: 'dev-entry-part-substitution-assessment' }, };