/** * ACT-WORK-05 差异评估的两枚纯工具契约(活动私有作用域)。 * 两处消费:`seed-mvp.ts`(db:seed 全套播种)与 `seed-activities.ts`(activities:install 装活动时顺带注册 —— * 「安装即用」包含它声明过的纯工具能调得动;从前 E04 的工具只在 db:seed 里注册,开发机上只跑 * activities:install 的人第一次跑活动就撞「工具不存在」)。 */ const PURE = { effect: 'read' as const, errors: [] as Array<{ code: string; retryable: boolean; message: string }>, idempotent: true, timeoutMs: 5_000, retries: 0, connectionKeys: [] as string[], pure: true, ownerActivityId: 'part-substitution-assessment', }; /** 逐参数比对 —— 出参键与台账列同名(difference_status / risk_level),模型照抄 */ export const COMPARE_PARAMETERS_TOOL = { ...PURE, name: 'part-substitution-assessment.compare-parameters', displayName: '替代料逐参数比对', /* * 1.1.0(2026-08-27):客户约束原 PN 自己也不满足、候选与原 PN 相等或盖住时不再判 mismatch —— 那是需求边界,不是替代差异。 * 1.2.0(同日):**比对入参由基座从台账取** —— 给 originalInternalPn + candidates[].candidateInternalPn,参数 / 封装 / 生命周期 / * 证据引用从 parts.* 现读,模型只译客户约束(requirements);老形状(自带 pairs)照旧接。出参每项带 originalValue / candidateValue / evidenceRef。 */ version: '1.3.0', description: '按硬/软约束逐参数比对原 PN 与候选 PN,输出四态 difference_status(match/mismatch/unknown/conditional)、' + '**值的读法**:「下限~上限」一律是范围(4.5~40 = 4.5 到 40 的整段;-40~+85 = -40 到 85 的整段,不是两个数),' + '分隔符认 ~ - … 至 到 to,单位写进值里也认;「≥45 / 45 以上」「≤40 / 40 以内」是单边界;只有一个数是定值。出参每项 readAs 摆出两边各读成了什么。' + 'compare_result、risk_level 与各候选的计数。**推荐用法**:只给 originalInternalPn 与 candidates[].candidateInternalPn,' + '参数行从 parts.parameter、封装与生命周期从 parts.profile、证据引用从 parts.document 由工具现读(本单草稿层也算),模型不抄值;' + 'candidates[].requirements 是客户给了边界的参数 {参数名: ">= 40" / "-40~85"}。也接老形状(candidates[].pairs 自带值)。' + '硬约束没有证据引用不判 match。候选不比原 PN 差(相等 / 盖住)而客户约束原 PN 自己也不满足的,不算替代差异:仍按比对结果判、备注点名需求边界。规则版本 R-2026.07。', input: { type: 'object', properties: { originalInternalPn: { type: 'string', description: '原 PN(内部料号);按料号从台账取参数时必填' }, candidates: { type: 'array', description: '[{candidateInternalPn, requirements?: {参数名: 约束}, evidenceRef?}](从台账取值) 或 ' + '[{candidateInternalPn, pairs:[{parameterName, originalValue, candidateValue, unit?, constraintType:"hard"|"soft", requirement?, evidenceRef?}]}](自带值)', }, }, }, output: { type: 'object', properties: { ruleVersion: { type: 'string' }, results: { type: 'array', description: '[{candidateInternalPn, source:"ledger"|"pairs", items:[{parameterName, originalValue, candidateValue, readAs:{original,candidate}, unit, constraintType, requirement, evidenceRef, compareResult, differenceStatus, riskLevel, note}], counts:{match,mismatch,unknown,conditional,hardMismatch,softMismatch,configurable}, extraCandidateParams?}]', }, }, }, }; /** 推荐定级 —— 出参 recommendationLevel / riskLevel / reason 直接落 P-11 */ export const RECOMMEND_TOOL = { ...PURE, name: 'part-substitution-assessment.recommend', displayName: '替代推荐定级', version: '1.0.0', description: '按每个候选的比对计数定推荐等级:硬约束 mismatch>0 → not_recommended;unknown>0 → conditional;' + '只有可调配成(configurable)→ alternate;其余 conditional → conditional;全 match → recommended。', input: { type: 'object', properties: { candidates: { type: 'array', description: '[{candidateInternalPn, counts:{match,mismatch,unknown,conditional,hardMismatch,softMismatch,configurable}}]' }, }, }, output: { type: 'object', properties: { ruleVersion: { type: 'string' }, results: { type: 'array', description: '[{candidateInternalPn, recommendationLevel, riskLevel, reason}]' }, }, }, }; export const W05_TOOLS = [COMPARE_PARAMETERS_TOOL, RECOMMEND_TOOL] as const; /** 试运行审的样例(两件共用一份:并集覆盖各家入参) */ export const W05_TOOL_SAMPLE = { input: { candidates: [ { candidateInternalPn: 'XL2596S-5.0', pairs: [{ parameterName: '输出电压', originalValue: '5.0', candidateValue: '5.0', unit: 'V', constraintType: 'hard', evidenceRef: 'P-08' }], counts: { match: 1, mismatch: 0, unknown: 0, conditional: 0, hardMismatch: 0, softMismatch: 0, configurable: 0 }, }, ], }, expectShape: { type: 'object' }, };