Archived
台账:两张类型字典 + P-08 主/参数(撤 createOnly、封装工艺归字典)+ 案卷两张 + P-11 主/明细 + P-06。 契约:启动只剩原 PN 与候选 PN 两格且都选填(缺了由第一步派工单补);tools 清空 —— 这是立场不是疏漏。 判据全读基座数;明细加合成列 judgement_class,因为「硬约束不符有几条」不是单列 tally 数得出来的。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
512 lines
31 KiB
TypeScript
512 lines
31 KiB
TypeScript
/**
|
||
* 活动包清单 —— ACT-WORK-05 差异评估(案例活动)。
|
||
*
|
||
* **2026-08-29 整体重写(@2.0.0)**:从「九步、两枚工具、全程 agent 驱动」改成「四步、零工具、
|
||
* 零 `guide`、AI 出场恰好一次」。设计权威:
|
||
* `docs/superpowers/specs/2026-08-29-act-work-05-rewrite-design.md`(下称「spec」)。
|
||
* 用户原话立的场:「不是把所有东西都丢给 ai 来处理…一定是系统先确定性的从数据库中取出数据后交给
|
||
* ai 分析」——`docs/ACT-WORK-05-端到端测试记录.md` 的 A–AE 发现表里,八条事故都落在
|
||
* 「本来就该是确定的」那几步(编号抄别单、判在库判错、数据工单派给在库的料…),
|
||
* 真正需要判断的只有一件事:**这一条参数,候选跟原厂比算不算事**。
|
||
*
|
||
* 这份清单是 Task 2 的产物,只动 `declarations.ledger` 与 `contract` 两段,以及 `assets`
|
||
* 里已经不自洽的那几处(spec §8 的退役清单前移到这一步,见「计划裁定 G3」)。**案例模型
|
||
* (`case-model.ts`)还是旧的九步、旧的 `guide` 文本** —— 下一个任务(Task 3)才整体重写成
|
||
* spec §4 的四步(`S1_inputs` / `S2_assess` / `S3_review` / `T_release`)+ 四道哨兵 + 零 `guide`
|
||
* (行为改由 `PlanStep.auto` 声明式配方接管)。旧剧本引用本次删掉的台账地址而导致的包内自测红,
|
||
* 已按台账逐条 `it.skip` 并注明「Task 3 会补回」,不删测试(§12.5 铁律)。
|
||
*
|
||
* ## 九张台账声明(spec §3)
|
||
* 两张新字典(`parts.chip_type` / `parts.type_param`,Task 1 已物化 + 播种)承接「约束类型按类型
|
||
* 标一次」;P-08 主记录 `parts.profile` 撤 `createOnly`(在库老料要能补上 `chip_type_id` 这一格)、
|
||
* 封装与工艺退休(它们本来就是「核心参数」,该以类型字段的身份出现在字典里);P-08 子表
|
||
* `parts.parameter` 撤 `constraint_type` 与参数名自指引用(名字对不对由 S1 配方铺格子这件事本身
|
||
* 保证,不必再靠一堵测三次都没拦住的墙)。原来的三张单据(`pn_check` / `input_gap` / `verdict`)
|
||
* 由两张顶掉:`sub_eval.part`(**一单恰两行** —— 配方 `each` 遍历「哪几颗料要建」的唯一数据源,
|
||
* 拆成两行的理由见 spec §3.3「为什么非拆成两张不可」)与 `sub_eval.case`(一单一行的案卷,
|
||
* 挂入参未就绪的原因与结论摘要)。P-11 明细加合成列 `judgement_class`(约束类型 × 四态的合成,
|
||
* 因为「硬约束不符有几条」不是任何单列 `tally` 数得出来的数)。P-01 需求主记录 / P-10 原厂资料 /
|
||
* 客户档案**本活动不碰**(它们的存在性核对与录入不再是这个活动的事)。
|
||
*
|
||
* ## 契约(spec §4.1/§4.5/§7)
|
||
* 启动只剩 `originalInternalPn` / `candidateInternalPn` 两格(单数,一次评估恰一对一候选),
|
||
* 都选填 —— 缺了由第一步的配方派数据工单补。零工具:`contract.resources.tools` 与
|
||
* `declarations.tools` 都是 `[]`,这是这次重写的立场,不是疏漏(四态改 S2 唯一一次 `analyze`
|
||
* 判定,推荐等级改配方按 spec §3.5 的规则算)。判据全部改读基座数(`域_对象_rows` / `_missing` /
|
||
* `_distinct_列` / tally 计数),没有一条读活动自己写的汇总列。
|
||
*/
|
||
import type { ActivityManifest } from '@contracts';
|
||
import { activityIdSchema } from '@contracts';
|
||
import { CMMN_XML, NARRATIVE, ASSESSMENT_PHASES, ASSESSMENT_STEPS } from './case-model.ts';
|
||
import { LEDGER_BOARD, LEDGER_BOARD_DATA } from './views/ledger-board.ts';
|
||
import { ACTIVITY_ID_TEXT, D } from './constants.ts';
|
||
|
||
export { D, RULE_VERSION } from './constants.ts';
|
||
const ACTIVITY_ID = activityIdSchema.parse(ACTIVITY_ID_TEXT);
|
||
|
||
/** 字段声明的短写(与 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 · 差异评估',
|
||
/* 重写不是改 —— 同版重装是 no-op(静默丢失,踩过) */
|
||
packageVersion: '2.0.0',
|
||
category: '需求分析与方案匹配',
|
||
sdkVersion: '0.1.0-m5',
|
||
checksum: 'dev-checksum-part-substitution-assessment',
|
||
},
|
||
|
||
/* ── 契约七件 ────────────────────────────────────────────────── */
|
||
contract: {
|
||
activityId: ACTIVITY_ID,
|
||
version: '1.0.0',
|
||
input: {
|
||
/*
|
||
* 两格,都选填(spec §4.1):库里有就选,没有就自己写一个新的 —— 启动后由第一步的
|
||
* 配方核对存在性、缺了就派数据工单补齐。运营端启动表单渲染这两格为
|
||
* 「选择 + 新增」下拉(`x-control: combo`),候选从 `parts.profile.internal_pn`
|
||
* 现读(`x-options`);`x-order` 定表单次序(清单存在 jsonb 里,书写顺序到不了运营端)。
|
||
* requestDescription / candidateInternalPns(数组)/ datasheets 三键已随重写撤下 ——
|
||
* 这一版没有「需求主记录」「N 候选并行」「预填 datasheet」这几件事。
|
||
*/
|
||
data: {
|
||
type: 'object',
|
||
required: [],
|
||
properties: {
|
||
originalInternalPn: {
|
||
type: 'string',
|
||
title: '原内部料号',
|
||
description: '差异评估基准料号;库里有就选,没有就自己写一个新的,启动后由第一步派数据工单补齐。',
|
||
examples: ['LM2596S-5.0'],
|
||
'x-control': 'combo',
|
||
'x-options': { ledger: 'parts.profile', value: 'internal_pn', label: 'internal_pn' },
|
||
'x-order': 1,
|
||
},
|
||
candidateInternalPn: {
|
||
type: 'string',
|
||
title: '候选内部料号',
|
||
description: '被评估的候选料号;库里有就选,没有就自己写一个新的,启动后由第一步派数据工单补齐。',
|
||
examples: ['XL2596S-5.0'],
|
||
'x-control': 'combo',
|
||
'x-options': { ledger: 'parts.profile', value: 'internal_pn', label: 'internal_pn' },
|
||
'x-order': 2,
|
||
},
|
||
},
|
||
},
|
||
messageAllowed: true,
|
||
messageHint: 'FAE 可在此说明客户的应用边界或验证条件',
|
||
},
|
||
output: {
|
||
/* 单一必发口:签下去 P-11 落账、P-06 落账;载荷是已落地的事实,不是待办 */
|
||
mandatory: [
|
||
{
|
||
name: 'assessment-released',
|
||
description: '差异评估结论已落账(P-11 替代关系主记录 + 差异明细、P-06 验证记录)—— 载荷即已落地的事实',
|
||
payload: {
|
||
type: 'object',
|
||
required: ['evalRef', 'relationId', 'originalPn', 'candidatePn', 'recommendationLevel', 'matchTotal', 'mismatchTotal', 'unknownTotal', 'conditionalTotal', 'validationId'],
|
||
properties: {
|
||
evalRef: { type: 'string', title: '评估案号' },
|
||
relationId: { type: 'string', title: '替代关系ID' },
|
||
originalPn: { type: 'string', title: '原内部料号' },
|
||
candidatePn: { type: 'string', title: '候选内部料号' },
|
||
recommendationLevel: { type: 'string', title: '推荐等级' },
|
||
matchTotal: { type: 'integer', title: 'MATCH 条数' },
|
||
mismatchTotal: { type: 'integer', title: 'MISMATCH 条数' },
|
||
unknownTotal: { type: 'integer', title: 'UNKNOWN 条数' },
|
||
conditionalTotal: { type: 'integer', title: 'CONDITIONAL 条数' },
|
||
validationId: { type: 'string', title: '关联验证ID' },
|
||
},
|
||
},
|
||
},
|
||
],
|
||
selective: [],
|
||
},
|
||
/* 一份成果常不止一张表:差异评估结论由明细 + 关系两张共同承载,落账内容由关系 + 验证记录承载 */
|
||
requiredDeliverables: [
|
||
{ key: 'difference-items', label: '差异评估结论', ledger: 'substitution.difference_item', ledgers: ['substitution.difference_item', 'substitution.relation'], editableAtRelease: [] },
|
||
{ key: 'landing', label: '落账内容', ledger: 'substitution.relation', ledgers: ['substitution.relation', 'validation.record'], editableAtRelease: [] },
|
||
],
|
||
/*
|
||
* 验收判据(spec §7)—— 五条机检 L1/L2 全读基座数,两条 L4 裁量,一条 L5 责任关(不上卡)。
|
||
* `input-ready` 的谓词与 S1(Task 3 待写)的 `doneWhen` 同构:两颗都在库、类型一致、参数不缺 ——
|
||
* **不写「参数行数 = 字段数×2」**,那不是基座数得出来的数(`parts_type_param_rows` 数的是
|
||
* 本单写下的字段行,不是整本字典;给判据编一个数不出来的数,是这个仓踩过六次的同一个坑)。
|
||
*/
|
||
acceptanceCriteria: [
|
||
{
|
||
key: 'input-ready',
|
||
label: '评估输入已就绪:原 PN 与候选都在库、归了同一个芯片类型、主数据与参数值都不缺必填',
|
||
level: 'L1',
|
||
predicate:
|
||
'sub_eval_part_exists_status_found = 2 and sub_eval_part_missing = 0 and sub_eval_part_distinct_chip_type_id = 1 and ' +
|
||
'parts_profile_missing = 0 and parts_parameter_missing = 0',
|
||
},
|
||
{
|
||
key: 'every-param-judged',
|
||
label: '每条核心参数都有明确状态:每条差异明细都是 MATCH / MISMATCH / UNKNOWN / CONDITIONAL 之一,没有一条缺必填',
|
||
level: 'L2',
|
||
predicate:
|
||
'substitution_difference_item_missing = 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: 'level-by-rule',
|
||
/* §3.5 的规则原样译成析取式:推荐等级只有一种取值能配上当前的 judgement_class 分布,规则说了算不是话术说了算 */
|
||
label: '推荐等级与判定分类一致:有硬约束不符的候选不能是「推荐」,等级由规则算,不由措辞改判',
|
||
level: 'L2',
|
||
predicate:
|
||
'(substitution_relation_recommendation_level_not_recommended = 1 and substitution_difference_item_judgement_class_hard_mismatch > 0) or ' +
|
||
'(substitution_relation_recommendation_level_conditional = 1 and substitution_difference_item_judgement_class_hard_mismatch = 0 and ' +
|
||
'(substitution_difference_item_judgement_class_unknown > 0 or substitution_difference_item_judgement_class_conditional > 0 or substitution_difference_item_judgement_class_soft_mismatch > 0)) or ' +
|
||
'(substitution_relation_recommendation_level_recommended = 1 and substitution_difference_item_judgement_class_hard_mismatch = 0 and ' +
|
||
'substitution_difference_item_judgement_class_unknown = 0 and substitution_difference_item_judgement_class_conditional = 0 and substitution_difference_item_judgement_class_soft_mismatch = 0)',
|
||
},
|
||
{
|
||
key: 'unknown-has-disposition',
|
||
label: '每个 UNKNOWN 都有去向:去向、影响说明、判断依据没有一条缺',
|
||
level: 'L2',
|
||
predicate: 'substitution_difference_item_missing = 0',
|
||
},
|
||
{
|
||
key: 'validation-landed',
|
||
label: '验证记录已落账:P-06 恰有一行且不缺必填(全推荐也要写「本轮无待验项」)',
|
||
level: 'L2',
|
||
predicate: 'validation_record_rows = 1 and validation_record_missing = 0',
|
||
},
|
||
{ key: 'evidence-credible', label: '证据链可信:每条差异的影响说明与判断依据站得住', level: 'L4' },
|
||
{ key: 'values-traceable', label: '参数值与原厂资料对得上:候选与原 PN 的取值来源可追溯', level: 'L4' },
|
||
/* L5 是责任关:那张卡本身就是这道关,卡面上不摆它(基座统一滤) */
|
||
{ key: 'gate03-release', label: 'ACT-GATE-03 评审放行:签下去 P-11 落账、P-06 落账,结论供下游消费', 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: '本活动只答技术可替代性:不做数量、价格、交期、采购判断' },
|
||
],
|
||
authorization: {
|
||
discretion: [],
|
||
preauthorizedActions: [],
|
||
/* 调人三次(补数据 / 审核 / 放行);零工具、AI 只出场一次 —— 预算随之从 16/90 步收紧到 8/40 步 */
|
||
humanCallBudget: 8,
|
||
},
|
||
resources: {
|
||
tools: [],
|
||
skills: [],
|
||
models: ['deepseek-v4-flash'],
|
||
roles: ['FAE/RI'],
|
||
budget: { steps: 40, tokens: 300_000, activeMinutes: 60, humanCalls: 8 },
|
||
},
|
||
},
|
||
|
||
/* ── 声明 ────────────────────────────────────────────────────── */
|
||
declarations: {
|
||
models: ['deepseek-v4-flash'],
|
||
/* 零工具 —— 这是这次重写的立场,不是疏漏(见头注) */
|
||
tools: [],
|
||
ledger: [
|
||
/* ── 两张类型字典(parts 域,与 P-08 同域;Task 1 已物化 + 播种)── */
|
||
{
|
||
domain: 'parts',
|
||
object: 'chip_type',
|
||
kind: 'master',
|
||
label: '芯片类型字典',
|
||
fields: [
|
||
col({ name: 'type_id', type: 'integer', label: '类型编号', primaryKey: true, auto: true }),
|
||
col({ name: 'type_name', type: 'text', label: '类型名称', required: true }),
|
||
col({ name: 'description', type: 'text', label: '类型说明', expect: true }),
|
||
],
|
||
},
|
||
{
|
||
domain: 'parts',
|
||
object: 'type_param',
|
||
kind: 'master',
|
||
label: '芯片类型核心参数字段',
|
||
fields: [
|
||
col({ name: 'type_id', type: 'integer', label: '所属类型', primaryKey: true, refersTo: 'parts.chip_type.type_id' }),
|
||
col({ name: 'param_name', type: 'text', label: '参数名', primaryKey: true }),
|
||
/* AI 分析时读它 —— 这一格说清「这个参数是什么意思」,是 S2 唯一一次 analyze 出场的入参之一 */
|
||
col({ name: 'param_desc', type: 'text', label: '参数说明', required: true }),
|
||
/* 约束类型按类型标一次,长在这里(不在每颗料的 `parts.parameter` 上)—— 见该表的头注 */
|
||
col({ name: 'constraint_type', type: 'text', label: '约束类型', required: true, tally: ['hard', 'soft'] }),
|
||
col({ name: 'param_unit', type: 'text', label: '参考单位', expect: true }),
|
||
],
|
||
},
|
||
/*
|
||
* P-08 芯片主数据 —— 声明后为八列,物理表其余列本活动不碰。`createOnly` 撤掉
|
||
* (spec §3.2):它当初是为了拦模型凭空建料,而配方现在按本单两颗料铺行,
|
||
* 凭空建在结构上已不可能;撤掉它换来一件必需的事 —— 给在库的老料补上
|
||
* `chip_type_id` 这一格(迁移前建的行没有类型,不许改就永远补不了)。
|
||
* package / process_technology / eol_pcn_status / application_scenarios 不声明:
|
||
* 封装和工艺本来就是「核心参数」,该以类型字段的身份出现在字典里,不在主记录上另开一列。
|
||
*/
|
||
{
|
||
domain: 'parts',
|
||
object: 'profile',
|
||
kind: 'master',
|
||
label: '芯片主数据(P-08)',
|
||
fields: [
|
||
col({ name: 'internal_pn', type: 'text', label: '内部料号', primaryKey: true }),
|
||
col({ name: 'chip_type_id', type: 'integer', label: '芯片类型', required: true, refersTo: 'parts.chip_type.type_id' }),
|
||
col({ name: 'brand_name', type: 'text', label: '品牌名称', required: true }),
|
||
col({ name: 'lifecycle_status', type: 'text', label: '生命周期状态', required: true, tally: ['active', 'nrnd', 'eol', 'discontinued', 'risk'] }),
|
||
col({ name: 'specification_description', type: 'text', label: '规格描述', expect: true }),
|
||
col({ name: 'manufacturer_name', type: 'text', label: '制造商名称', expect: true }),
|
||
col({ name: 'datasheet_ref', type: 'text', label: 'Datasheet 引用', expect: true }),
|
||
col({ name: 'datasheet_version', type: 'text', label: 'Datasheet 版本', expect: true }),
|
||
],
|
||
},
|
||
/*
|
||
* P-08 子表:标准化参数集,一行一参数。`createOnly` 撤掉(理由同上一张:在库那颗料的
|
||
* 现值要能回填进草稿层,只许建新就写不进去)。两处退休(spec §3.2):
|
||
* `constraint_type` 搬去 `parts.type_param`(同一个参数在两颗料上标法不一致这件事从结构上
|
||
* 消失);`param_name` 的自指引用墙与 `distinct` 一并退休 —— 它当初是为了硬逼两颗料用同一套
|
||
* 参数名,而字段清单现在由类型字典给、行由配方按字典铺,名字对不上根本不可能发生。
|
||
*/
|
||
{
|
||
domain: 'parts',
|
||
object: 'parameter',
|
||
kind: 'master',
|
||
label: '标准化参数集(P-08 子表)',
|
||
fields: [
|
||
col({ name: 'internal_pn', type: 'text', label: '所属料号', primaryKey: true, refersTo: 'parts.profile.internal_pn' }),
|
||
col({ name: 'param_name', type: 'text', label: '参数名', primaryKey: true }),
|
||
col({ name: 'param_value', type: 'text', label: '值', required: true }),
|
||
col({ name: 'param_unit', type: 'text', label: '单位', expect: true }),
|
||
/* 值说明,AI 也读它(spec §3.2) */
|
||
col({ name: 'param_note', type: 'text', label: '说明', expect: true }),
|
||
/*
|
||
* **约束类型不在这里** —— 它长在 `parts.type_param`(按类型标一次)。
|
||
* 从前每颗料各标一次,同一个参数在两颗料上标法不一致就成了可能;
|
||
* 而比对是逐参数对着比的,两边约束档不同,判出来的四态就没有意义。
|
||
*/
|
||
],
|
||
},
|
||
/*
|
||
* ── 活动自持两张(spec §3.3,顶掉退休的 pn_check / input_gap / verdict 三张)──
|
||
* `sub_eval.part` 是配方唯一能拿来遍历「哪几颗料要建」的数据源(`each: 'mine:sub_eval.part'
|
||
* where exists_status = absent`)—— 挤进一行案卷里就没法 `where` 过滤,而不能过滤就会给
|
||
* 已经在库的那颗料也铺一遍空参数行,这是非拆成两张不可的理由。
|
||
*/
|
||
{
|
||
domain: D,
|
||
object: 'part',
|
||
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'] }),
|
||
/*
|
||
* **「在库」是一次 lookup 的结果,不是一句断言**(spec §3.3):判 found 就必须拿得出
|
||
* 一个基座查得到的料号,`refersTo` 让查无此值当场拒。`exists_status` 与这一列**每一拍
|
||
* 由配方重算**(不设 created 档、不靠谁记账)—— 人把料建好之后自己变 found。
|
||
*/
|
||
col({ name: 'found_pn_ref', type: 'text', label: '在库核对依据', refersTo: 'parts.profile.internal_pn', requiredWhen: { column: 'exists_status', value: 'found' } }),
|
||
col({ name: 'exists_status', type: 'text', label: '在库状态', required: true, tally: ['found', 'absent'] }),
|
||
col({
|
||
name: 'chip_type_id',
|
||
type: 'integer',
|
||
label: '芯片类型',
|
||
required: true,
|
||
/*
|
||
* **`distinct`**:「两颗料是不是同一个类型」从此是基座数得出来的数
|
||
* (`sub_eval_part_distinct_chip_type_id`)—— 不同取值恰好 1 种才算一致。
|
||
* 这一条是 S1 收步与 S2 入场的硬门:两边字段清单不是同一套,逐项比对无从谈起。
|
||
*/
|
||
distinct: true,
|
||
}),
|
||
],
|
||
},
|
||
{
|
||
domain: D,
|
||
object: 'case',
|
||
kind: 'record',
|
||
caseKey: 'eval_ref',
|
||
label: '本单案卷',
|
||
fields: [
|
||
col({ name: 'eval_ref', type: 'text', label: '评估案号', primaryKey: true }),
|
||
col({ name: 'chip_type_id', type: 'integer', label: '本单锁定的芯片类型' }),
|
||
col({ name: 'gate_reason', type: 'text', label: '入参未就绪原因(件上摆的就是它)' }),
|
||
col({ name: 'summary', type: 'text', label: '结论摘要' }),
|
||
],
|
||
},
|
||
/*
|
||
* P-11 替代关系主记录 —— 一单一行。退休三列(spec §3.4):`substitution_type`(新流程里没有
|
||
* 它的定夺人)、`confidence_score`、`analysis_report_ref`;`recommendation_level` 的
|
||
* `alternate` 档一并退休(原 D02 的 configurable 来路已不存在,只剩三档)。
|
||
*/
|
||
{
|
||
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: '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: 'chip_type_id', type: 'integer', label: '芯片类型', required: true }),
|
||
col({ name: 'recommendation_level', type: 'text', label: '推荐等级', required: true, tally: ['recommended', 'conditional', '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'] }),
|
||
col({ name: 'verification_requirement', type: 'text', label: '验证要求', requiredWhen: { column: 'recommendation_level', value: 'conditional' } }),
|
||
col({ name: 'validation_id', type: 'text', label: '关联验证ID' }),
|
||
/* 固定 fae_confirmed —— 分析状态与客户批准状态分离,本活动只写这一层 */
|
||
col({ name: 'analysis_status', type: 'text', label: '分析状态', required: true }),
|
||
col({ name: 'rule_version', type: 'text', label: '差异规则版本', required: true }),
|
||
],
|
||
},
|
||
/*
|
||
* P-11 差异明细子表 —— 一参数一行。`evidence_ref` 改名 `evidence_note`「判断依据」:
|
||
* 不写 P-10 了,AI 能给的就是依据不是文件引用,名字得说实话(spec §3.4)。
|
||
*/
|
||
{
|
||
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 }),
|
||
/* 字段说明快照,归档件不必 join 回字典 */
|
||
col({ name: 'parameter_desc', type: 'text', label: '参数说明', expect: true }),
|
||
col({ name: 'constraint_type', type: 'text', label: '约束类型', required: true, tally: ['hard', 'soft'] }),
|
||
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 }),
|
||
/* AI 判:逐参数比对,S2 唯一一次 analyze 出场的出参之一 */
|
||
col({ name: 'difference_status', type: 'text', label: '差异状态', required: true, tally: ['match', 'mismatch', 'unknown', 'conditional'] }),
|
||
/*
|
||
* **`judgement_class` 是合成列**:推荐等级要数的是「**硬约束**不符有几条」,
|
||
* 而基座读数只会数单列 —— 把「约束类型 × 四态」先合成一列,规则才算得出来。
|
||
* 由配方按 §3.5 的 when 链算,不是 AI 出的。
|
||
*/
|
||
col({ name: 'judgement_class', type: 'text', label: '判定分类', required: true, tally: ['match', 'soft_mismatch', 'hard_mismatch', 'unknown', 'conditional'] }),
|
||
col({ name: 'impact_statement', type: 'text', label: '影响说明(MATCH 写「无」)', required: true }),
|
||
col({ name: 'evidence_note', type: 'text', label: '判断依据', 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: 'rule_version', type: 'text', label: '差异规则版本', required: true }),
|
||
],
|
||
},
|
||
/* P-06 验证记录:一单一行,关联的是本单案号(P-01 不在本活动里,顶掉 request_id) */
|
||
{
|
||
domain: 'validation',
|
||
object: 'record',
|
||
kind: 'master',
|
||
label: '芯片验证记录(P-06)',
|
||
fields: [
|
||
col({ name: 'validation_id', type: 'text', label: '验证ID', primaryKey: true }),
|
||
col({ name: 'eval_ref', 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', 'parametric'] }),
|
||
/* 固定 not_started */
|
||
col({ name: 'validation_status', type: 'text', label: '验证状态', required: true }),
|
||
col({ name: 'test_condition', type: 'text', label: '测试条件', expect: true }),
|
||
col({ name: 'next_validation_action', type: 'text', label: '后续验证动作', required: true }),
|
||
],
|
||
},
|
||
],
|
||
listeners: [],
|
||
harness: {
|
||
memoryWindow: 24,
|
||
stallAfter: 'PT4H',
|
||
nudge: [{ after: 'PT2H', action: 'nudge' }],
|
||
retry: { times: 2, backoff: 'PT30S' },
|
||
},
|
||
},
|
||
|
||
/* ── 资产初始版 ──────────────────────────────────────────────── */
|
||
assets: {
|
||
/*
|
||
* DMN 判定表已退役:D01(逐参数四态)改由 S2 唯一一次 analyze 判定;D02(推荐等级)的规则
|
||
* 搬进配方的 when 链(spec §3.5)—— 规则只许有一处真源,再留一份 DMN 就是同一件事两处
|
||
* 各存一份。Task 3 会把 `steps` 换成四步、`guide` 全部清空(auto 配方接管行为)。
|
||
*/
|
||
businessModel: { cmmnXml: CMMN_XML, narrative: NARRATIVE, dmn: { drd: [], tables: [] }, steps: ASSESSMENT_STEPS, phases: ASSESSMENT_PHASES },
|
||
/* 三条技能已随重写退役(全程无 agent,没有临场编排可言);skills.ts 的删除排在 Task 10 */
|
||
skills: [],
|
||
/*
|
||
* 五张旧局面全部作废(它们绑的九步与旧台账地址已经不存在),**暂时只留运营中心那张看板** ——
|
||
* 三张新件(`input-supplement` / `difference-review` / `landing-confirm`)由 Task 7–9 各自加回;
|
||
* 中途(Task 2–Task 9 之间)包不装,不会被静态审拦下。看板自己的 `data` 声明现在也引着已经
|
||
* 不存在的台账地址(`sub_eval.pn_check` 等)——Task 9「运营中心看板重绑」会把它换成新九张表。
|
||
*/
|
||
viewTemplates: [{ name: 'activity-ledger', html: LEDGER_BOARD, data: LEDGER_BOARD_DATA }],
|
||
cardSchemas: {},
|
||
/* 蒸馏钩子撤空:它是给 agent 在终态回看轨迹用的,而这个活动全程无 agent(AI 只出场一次、答一份结构化判断,没有可供归纳的多轮轨迹) */
|
||
distillHooks: [],
|
||
},
|
||
|
||
/*
|
||
* ── 样例集:五条形状真不同(常备案例即验收案例)──
|
||
* 本任务不改样例(它们仍是旧九步 / 旧入参形状的素材,Task 3 重写案例模型时一并核对)。
|
||
* 库里只播了 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' },
|
||
};
|