Archived
A2-A7 全部补齐到验收线;顺手把几处「门拦住却不给路」的坑填了
活动:A2 选型 / A3 寻源 / A4 定价 / A6 议价 / A7 归档五件各补成真活动包 —— 契约宽进(input.required 空,归一在活动内)、台账必填声明(含行级 requiredWhen)、 入场哨兵与 L1/L2 判据一律读基座数、两份件(在办可编辑 + 办结静态快照)、 三案例常备、包内自测。e2e 各三案例 released、行动被拒 0、发口正确、提交闸每单真拦。 基座(共享面,改一处影响所有活动,故每处都带回归): · 重发判断走在站上场之前 —— 人答完那步常已收掉,readyToWork 先抛「不能再往它上面挂活」, 于是「重发已答过的卡 = 无事发生」这条唯一活路在最需要时够不着,A1 基线当场熔断; · 决策卡补幂等兜底(与执行工单同一把尺):头两次无事发生,第三次起才算被拒; · 输出没成形先就地重问一次,原话进工作日志、不再摆上卡面; · 工具调用读数 tool_<名>_calls —— 「机检只读基座数」这条纪律第一次覆盖到工具; · 执行卡 steps/standard 补进出参 schema(从前能到卡面全靠厂商 JSON 模式宽松); · 件的就地更新改逐节点 morph,保存先把新值镜像进只读那份 —— 不闪、不等回声。 A1(基线,全程守住):措辞三档对齐(必填/建议/选填)、禁止拿历史价当客户目标价、 卡骨架从步骤剧本搬进说明书(压成一拍连做时剧本没摊开,会发出没有指导书的裸卡)。 契约两处**新增可选字段**(非破坏):FieldDeclaration.requiredWhen、工单 finalHtml; api-report 同批更新。docs/adr 与 docs/archive 的 13 份文件在工作树里不见了, 本次予以恢复而非提交删除。 门禁:typecheck / lint / depcruise / test(1366)全绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,185 +1,265 @@
|
||||
/**
|
||||
* 活动包清单 —— 统一报价 A3 · 渠道寻源(**案例活动 · loop**)。
|
||||
* 活动包清单 —— 统一报价 A3 · 寻源询价(案例活动 · MVP 简化形)。
|
||||
*
|
||||
* 业务素材:docs/MVP示例工作流.html §1.5。按 README《归一化对照表》映射:
|
||||
* 案例图 → CMMN XML;案例说明书 → 同版本叙事面;
|
||||
* `!必做` → entryCriterion 常项;`看情况` → discretionary(planningTable);
|
||||
* `#可反复` → repetitionRule;`▶需拍板` → manualActivation + 放行;
|
||||
* `⏱时限/回价到期` → 时间监听(**时限必配**)。
|
||||
* 业务素材:`docs/MVP示例工作流.html` §1.7,按 2026-08-02 用户改盘的口径归一:
|
||||
* **A3 与 A2 同为复杂活动(需要大规模业务建模),MVP 期间不展开** —— 只做一张精美的
|
||||
* HTML 验收报告 + 一张执行单:AI 归一目标报价清单、A 类行按库内历史价预填基准,
|
||||
* 采购(PRM)在系统外询价、把 B 类行的货源价格填回来,汇稿定盘后放行 ——
|
||||
* **生成最终的目标报价清单**交给成本定价。提交就是输出。
|
||||
*
|
||||
* ── 这里**去掉了 `STRATEGY_DMN`(采用策略判定表)**(2026-08-02)────────────────
|
||||
* 它声明着 scenario / priceDrift / quoteCount 三个入参,台账上没有任何列承载、
|
||||
* 剧本里也没有一步调它 —— 一张没有求值器的判定表不是资产,是错觉。
|
||||
* 四种场景(BOM早期/后期/现货/样品)的尺度之分是 PRM 系统外的判断,
|
||||
* MVP 口径下系统不假装接得住。
|
||||
*/
|
||||
import type { ActivityManifest, DmnModel } from '@contracts';
|
||||
import { SOURCING_SKILLS } from './skills.ts';
|
||||
import { SOURCING_CASE } from './views/report.ts';
|
||||
import { activityIdSchema } from '@contracts';
|
||||
import { CMMN_XML, NARRATIVE, SOURCING_STEPS } from './case-model.ts';
|
||||
import { SOURCING_SKILLS } from './skills.ts';
|
||||
import { SOURCING_ROSTER, SOURCING_WORKSHEET } from './views/report.ts';
|
||||
import { CMMN_XML, NARRATIVE, SOURCING_PHASES, SOURCING_STEPS } from './case-model.ts';
|
||||
|
||||
const DOMAIN = 'quote_sourcing';
|
||||
const D = 'quote_sourcing';
|
||||
const ACTIVITY_ID = activityIdSchema.parse('quote-sourcing');
|
||||
|
||||
/** 采用策略 —— 「能算的不问 LLM」:场景 × 历史情形 → 直采 / 重询 */
|
||||
export const STRATEGY_DMN: DmnModel = {
|
||||
drd: [{ decision: 'sourcing-strategy', requires: [], inputs: ['scenario', 'priceDrift', 'quoteCount'] }],
|
||||
tables: [
|
||||
{
|
||||
id: 'sourcing-strategy',
|
||||
label: '采用策略判定',
|
||||
hitPolicy: 'FIRST',
|
||||
inputs: [
|
||||
{ name: 'scenario', expression: 'scenario' },
|
||||
{ name: 'priceDrift', expression: 'priceDrift' },
|
||||
{ name: 'quoteCount', expression: 'quoteCount' },
|
||||
],
|
||||
outputs: [{ name: 'strategy' }, { name: 'needNewQuote' }],
|
||||
rules: [
|
||||
{ id: 'st-spot', when: ['"现货","样品"', '-', '-'], then: ['一律重询', true] },
|
||||
{ id: 'st-early-direct', when: ['"BOM早期"', '<= 0.10', '-'], then: ['直采', false] },
|
||||
{ id: 'st-early-avg', when: ['"BOM早期"', '[0.10..0.20]', '-'], then: ['取均价', false] },
|
||||
{ id: 'st-late-direct', when: ['"BOM后期"', '-', '>= 3'], then: ['历史最低直采', false] },
|
||||
{ id: 'st-default', when: ['-', '-', '-'], then: ['重询', true] },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
/** MVP 口径:A3 没有判定表(见文件头注释)—— 取价规则写死在剧本,价源逐行落表 */
|
||||
export const SOURCING_DMN: DmnModel = { drd: [], tables: [] };
|
||||
|
||||
export const manifest: ActivityManifest = {
|
||||
identity: {
|
||||
activityId: ACTIVITY_ID,
|
||||
name: 'A3 · 渠道寻源',
|
||||
packageVersion: '2.0.0',
|
||||
name: 'A3 · 寻源询价',
|
||||
packageVersion: '3.7.0',
|
||||
category: '统一报价',
|
||||
sdkVersion: '0.1.0-m5',
|
||||
checksum: 'dev-checksum-quote-sourcing',
|
||||
},
|
||||
|
||||
/* ── 契约七件 ────────────────────────────────────────────────── */
|
||||
contract: {
|
||||
activityId: ACTIVITY_ID,
|
||||
version: '0.1.0',
|
||||
version: '1.0.0',
|
||||
input: {
|
||||
/*
|
||||
* **宽进到底:一个必填都不设**(2026-08-02 用户定:宽进严出,
|
||||
* 输入契约在活动内部归一 + 补全)。
|
||||
*
|
||||
* 来路三种形状:A2 转来(rows)、A1 直达(records)、单飞(一段文字)。
|
||||
* 上一版必填 `rfqRef + pn + scenario` 是**单料形状** —— 上游发的是整份清单,
|
||||
* 门口拦的恰是主路。
|
||||
*/
|
||||
data: {
|
||||
type: 'object',
|
||||
required: ['rfqRef', 'pn', 'scenario'],
|
||||
required: [],
|
||||
properties: {
|
||||
rfqRef: { type: 'string', title: '询价单号(单标识,贯穿全流程)' },
|
||||
pn: { type: 'string' },
|
||||
scenario: { type: 'string' },
|
||||
quantity: { type: 'integer' },
|
||||
targetPrice: { type: 'number' },
|
||||
rfqRef: { type: 'string', title: '询价单号' },
|
||||
rows: { type: 'array', title: '询价受理清单(选型转来)' },
|
||||
records: { type: 'array', title: '上游受理记录(受理直达)' },
|
||||
subject: { type: 'string', title: '需求主题' },
|
||||
body: { type: 'string', title: '需求正文' },
|
||||
attachments: {
|
||||
type: 'array',
|
||||
format: 'file',
|
||||
title: '附件',
|
||||
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: '急料、客户特殊要求写这里',
|
||||
messageHint: '急料、场景(BOM早期/后期/现货/样品)、客户特殊要求写这里',
|
||||
},
|
||||
output: {
|
||||
/*
|
||||
* 只有一个出口:目标报价清单交成本定价(流程包 E7 是无条件边)。
|
||||
* 没有选择组 —— 没有去向要选,定盘就是把账写齐。
|
||||
*/
|
||||
mandatory: [
|
||||
{
|
||||
name: 'compare',
|
||||
payload: { type: 'object', required: ['rows'], properties: { rows: { type: 'array' } } },
|
||||
description: '寻源比价表(多渠道横比定底)',
|
||||
name: 'quotation',
|
||||
payload: {
|
||||
type: 'object',
|
||||
required: ['rfqRef', 'rows'],
|
||||
properties: {
|
||||
rfqRef: { type: 'string', title: '询价单号(单标识 —— 下游台账的主键)' },
|
||||
rows: { type: 'array', title: '目标报价清单(每行带基准价与价源)' },
|
||||
},
|
||||
},
|
||||
description: '目标报价清单(每行带基准价与价源)',
|
||||
},
|
||||
],
|
||||
selective: [],
|
||||
},
|
||||
/*
|
||||
* 必交付物**必须给 `ledger` 地址**(2026-07-31 修)。
|
||||
* 不给的话预检退回 `scope[key]` 去找 —— key 是 `benchmark-table` 这样的短横线别名,
|
||||
* 任务视图里永远没有这个键,于是「必交付物缺一不得提交放行」永远拒,
|
||||
* 活办完了也放不了行,连拒五拍熔断(实测 A2 死于此)。
|
||||
* 必交付物只有一件:**目标报价清单**。寻源结论(verdict)是它的结论栏,
|
||||
* `ledgers` 说清这份成果由哪几张表承载。
|
||||
*/
|
||||
requiredDeliverables: [
|
||||
{ key: 'compare-table', label: '寻源比价表', ledger: `${DOMAIN}.compare_table` },
|
||||
{
|
||||
key: 'quotation-roster',
|
||||
label: '目标报价清单(每行带基准价)',
|
||||
ledger: `${D}.quote_list`,
|
||||
/* 验收页上让 PRM 就地改的那几列 —— 恰是他的职权面(价格五列) */
|
||||
editableAtRelease: ['supplier', 'base_price', 'moq', 'source_lead_time', 'note'],
|
||||
ledgers: [`${D}.quote_list`, `${D}.verdict`],
|
||||
},
|
||||
],
|
||||
/*
|
||||
* 机检谓词读的是 `verdict` 那张**汇总表**的列(照 A1 的口径)。
|
||||
* 上一版的名字(unquoted / channelsPicked)**台账里根本没有** —— S-FEEL 拿未绑定的名字
|
||||
* 比大小求值为假,判据永远达不了标,submit 门永远拒,连拒五拍熔断。
|
||||
* 判据的名字必须落在台账上,否则「机检」是一句空话(2026-07-31 销账)。
|
||||
* 验收判据 —— **机检(L1/L2)只读基座数得出来的数**:
|
||||
* `_rows` 基座数行数、`_missing` 基座按 required 现数(与执行卡提交闸同一个数
|
||||
* 同一套算法)、`_price_basis_hist/_sourced` 基座按值现数。
|
||||
* 上一版两条 L2 读活动自报的 verdict 列(unquoted_total / supplier_total)——
|
||||
* 那不是门,是「改哪个数能过」的提示。
|
||||
*/
|
||||
acceptanceCriteria: [
|
||||
{ key: 'each-has-quote', label: '每料有有效报价或明确无货', level: 'L2', predicate: 'unquoted_total = 0' },
|
||||
{ key: 'channels-enough', label: 'BOM后期每料 2~3 家渠道', level: 'L2', predicate: 'supplier_total >= 2' },
|
||||
{ key: 'cross-check', label: '价格验证按场景规则做过', level: 'L3' },
|
||||
{ key: 'prm-release', label: '采购放行', level: 'L5' },
|
||||
{
|
||||
key: 'roster-complete',
|
||||
label: '清单齐:上游清单逐条承继,说了几条清单里就躺着几行',
|
||||
level: 'L1',
|
||||
predicate: 'quote_line_total > 0 and quote_sourcing_quote_list_rows = quote_line_total',
|
||||
},
|
||||
{
|
||||
key: 'price-complete',
|
||||
label: '每行有基准价:A 类历史价、B 类货源价,缺一行放不了',
|
||||
level: 'L1',
|
||||
predicate: 'quote_sourcing_quote_list_rows > 0 and quote_sourcing_quote_list_missing = 0',
|
||||
},
|
||||
{
|
||||
key: 'basis-conserved',
|
||||
label: '价源守恒:历史价条数加货源价条数恰等于总行数,逐行留徽可溯',
|
||||
level: 'L2',
|
||||
predicate:
|
||||
'quote_sourcing_quote_list_price_basis_hist + quote_sourcing_quote_list_price_basis_sourced = quote_sourcing_quote_list_rows',
|
||||
},
|
||||
/*
|
||||
* 来源可核是**裁量**(L3):供应商靠不靠谱、价问没问真,机器数不出来。
|
||||
* 这句 label 与剧本里 judge 的 criterion **必须逐字一致**。
|
||||
*/
|
||||
{
|
||||
key: 'source-verifiable',
|
||||
label: '货源与价格来源可核:B 类行的供应商与底价来自真实询价或可靠渠道,PRM 对报价负责',
|
||||
level: 'L3',
|
||||
},
|
||||
/* L5 是责任关:那张卡本身就是这道关,卡面上不摆它(基座统一滤) */
|
||||
{ key: 'prm-release', label: 'PRM 放行:签下去这份清单即定盘并交成本定价', level: 'L5' },
|
||||
],
|
||||
revisableAtRelease: [],
|
||||
prohibitions: [
|
||||
{ key: 'no-made-up-price', statement: '问不到的价不许编:要么剔出本轮,要么按内部估价填并在备注写明' },
|
||||
{ key: 'no-stockless-trader', statement: '现货场景不得选无库存转单商' },
|
||||
{ key: 'no-unverified', statement: '不实回价或远低行情的,必须换渠道补询,不得直接采用' },
|
||||
],
|
||||
authorization: {
|
||||
discretion: [{ key: 'channel-band', statement: '按场景放宽或收紧渠道尺度;贸易商尽量不用' }],
|
||||
preauthorizedActions: [{ tool: 'mail.send', operation: 'inquiry', limit: '询价模板' }],
|
||||
humanCallBudget: 8,
|
||||
discretion: [
|
||||
{ key: 'channel-band', statement: 'PRM 按场景放宽或收紧渠道尺度;贸易商尽量不用' },
|
||||
],
|
||||
/*
|
||||
* 空着不是省事:这个字段全仓没有一个消费者(债 ⑨)。
|
||||
* 上一版这里写着 `mail.send` 的预授权 —— 写了也不会被执行,一并撤掉。
|
||||
*/
|
||||
preauthorizedActions: [],
|
||||
humanCallBudget: 4,
|
||||
},
|
||||
resources: {
|
||||
tools: [{ name: 'mail.send' }, { name: 'crm.history-price-read' }],
|
||||
/*
|
||||
* 只留历史价一件工具(A 类预填的取数口)。上一版还声明 `mail.send` ——
|
||||
* MVP 口径下发询在 PRM 系统外,系统不代发,声明它只是白占白名单。
|
||||
*/
|
||||
tools: [{ name: 'crm.history-price-read' }],
|
||||
skills: SOURCING_SKILLS.map((s) => s.id),
|
||||
models: ['deepseek-v4-flash'],
|
||||
roles: ['PRM'],
|
||||
budget: { steps: 120, tokens: 300_000, activeMinutes: 480, humanCalls: 8 },
|
||||
/* PRM 系统外询价,按场景时限 BOM后期 3~9 日 —— activeMinutes 给足等待 */
|
||||
budget: { steps: 50, tokens: 250_000, activeMinutes: 480, humanCalls: 4 },
|
||||
},
|
||||
},
|
||||
|
||||
/* ── 声明 ────────────────────────────────────────────────────── */
|
||||
declarations: {
|
||||
models: ['deepseek-v4-flash'],
|
||||
tools: [{ name: 'mail.send' }, { name: 'crm.history-price-read' }],
|
||||
tools: [{ name: 'crm.history-price-read' }],
|
||||
ledger: [
|
||||
/*
|
||||
* ── 这里**去掉了 `supplier_quote` / `compare_table` 两张表**(2026-08-02)──
|
||||
*
|
||||
* MVP 口径下逐家回价与横比都不在系统内产出 —— 询价的实质工作在 PRM 系统外,
|
||||
* 系统收的是**结论**(定盘的供应商与底价),落在清单行的价格五列上。
|
||||
* 撤掉声明不 drop 物理表(物化只增不破坏),历史行还在库里。
|
||||
*/
|
||||
{
|
||||
domain: DOMAIN,
|
||||
object: 'supplier_quote',
|
||||
domain: D,
|
||||
object: 'quote_list',
|
||||
kind: 'record',
|
||||
caseKey: 'rfq_ref',
|
||||
label: '供应商回价单',
|
||||
label: '目标报价清单',
|
||||
fields: [
|
||||
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
||||
{ name: 'pn', type: 'text', primaryKey: true, masked: false },
|
||||
{ name: 'supplier', type: 'text', primaryKey: true, masked: false, label: '供应商' },
|
||||
{ name: 'price', type: 'number', primaryKey: false, masked: false, label: '回价' },
|
||||
{ name: 'moq', type: 'integer', primaryKey: false, masked: false, label: 'MOQ' },
|
||||
{ name: 'lead_time', type: 'text', primaryKey: false, masked: false, label: '交期' },
|
||||
{ name: 'valid_until', type: 'date', primaryKey: false, masked: false, label: '有效期' },
|
||||
{ name: 'grade', type: 'text', primaryKey: false, masked: false, label: '渠道等级' },
|
||||
{ name: 'pn', type: 'text', primaryKey: true, masked: false, label: 'PN' },
|
||||
{ name: 'customer_pn', type: 'text', primaryKey: false, masked: false, label: '客户料号' },
|
||||
{ name: 'category', type: 'text', primaryKey: false, masked: false, label: '品类' },
|
||||
{ name: 'brand', type: 'text', primaryKey: false, masked: false, label: '制造商' },
|
||||
{ name: 'eau', type: 'integer', primaryKey: false, masked: false, label: '年用量 EAU' },
|
||||
{ name: 'target_price', type: 'number', primaryKey: false, masked: false, label: '目标价' },
|
||||
{ name: 'lead_time', type: 'text', primaryKey: false, masked: false, label: '客户要求交期' },
|
||||
/* 客户备注承继自上游 —— 认证要求、预授权、急料标注都在这一格,是问价口径的第一手依据 */
|
||||
{ name: 'remark', type: 'text', primaryKey: false, masked: false, label: '客户备注(约束/急料)' },
|
||||
/* 选型转来的行带替代料 —— 取价对象是它;受理直达与单飞的行此列空着 */
|
||||
{ name: 'alt_pn', type: 'text', primaryKey: false, masked: false, label: '替代料 PN' },
|
||||
{ name: 'type_tag', type: 'text', primaryKey: false, masked: false, label: '类别(承继)', tally: ['A', 'B', 'C'] },
|
||||
{ name: 'supplier', type: 'text', primaryKey: false, masked: false, label: '供应商' },
|
||||
/*
|
||||
* **底价是必填** —— 标了 `required`,基座就数得出「缺基准价的有几行」
|
||||
* (读数 `quote_sourcing_quote_list_missing` / `_missing_keys`)。
|
||||
* 这个数同时喂三处:件上的缺价红带、执行卡的提交闸、放行门 L1 ——
|
||||
* 同一个数、同一套算法,三处永远说同一句话(同源纪律)。
|
||||
*/
|
||||
{ name: 'base_price', type: 'number', primaryKey: false, masked: false, required: true, label: '底价' },
|
||||
/* MOQ 常带单位与档位(1K / 2500+),按文本收,不硬转数值 */
|
||||
{ name: 'moq', type: 'text', primaryKey: false, masked: false, label: 'MOQ' },
|
||||
{ name: 'source_lead_time', type: 'text', primaryKey: false, masked: false, label: '货源交期' },
|
||||
/*
|
||||
* **价源:取值域给出来,条数由基座现数** —— HIST(库内历史价)/ SOURCED(本单问回)。
|
||||
* 价源守恒判据、分布条、价源徽读的全是基座读数;值是机器码,
|
||||
* 人读名(历史价/货源价)由模版样式表翻译。
|
||||
*/
|
||||
{ name: 'price_basis', type: 'text', primaryKey: false, masked: false, label: '价源', tally: ['HIST', 'SOURCED'] },
|
||||
/* 备注是我方写的注,不标 expect(标了 `_gaps` 恒大于 0,门就废了 —— A1 的账) */
|
||||
{ name: 'note', type: 'text', primaryKey: false, masked: false, label: '备注' },
|
||||
],
|
||||
},
|
||||
{
|
||||
domain: DOMAIN,
|
||||
object: 'compare_table',
|
||||
kind: 'record',
|
||||
caseKey: 'rfq_ref',
|
||||
label: '寻源比价表',
|
||||
fields: [
|
||||
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
||||
{ name: 'pn', type: 'text', primaryKey: true, masked: false },
|
||||
{ name: 'supplier', type: 'text', primaryKey: false, masked: false },
|
||||
{ name: 'price', type: 'number', primaryKey: false, masked: false },
|
||||
{ name: 'conclusion', type: 'text', primaryKey: false, masked: false, label: '结论' },
|
||||
],
|
||||
},
|
||||
{
|
||||
/*
|
||||
* 寻源结论 —— 一单一行的**汇总表**,验收机检谓词的入参就在这儿。
|
||||
* 汇总列与逐行列**故意不同名**:任务视图把草稿行摊平到顶层是「后写的赢」,
|
||||
* 拿逐行列求值只会验到最后写的那一行,那不叫机检、叫抽样(A1 的教训)。
|
||||
*/
|
||||
domain: DOMAIN,
|
||||
/* 寻源结论 —— 一单一行:汇总数(哨兵与报告读)、一句人话结论 */
|
||||
domain: D,
|
||||
object: 'verdict',
|
||||
kind: 'record',
|
||||
caseKey: 'rfq_ref',
|
||||
label: '寻源结论',
|
||||
fields: [
|
||||
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
||||
{ name: 'pn', type: 'text', primaryKey: false, masked: false, label: '型号' },
|
||||
{ name: 'supplier_total', type: 'integer', primaryKey: false, masked: false, label: '已询渠道数' },
|
||||
{ name: 'quoted_total', type: 'integer', primaryKey: false, masked: false, label: '已回价条数' },
|
||||
{ name: 'unquoted_total', type: 'integer', primaryKey: false, masked: false, label: '未回价条数' },
|
||||
{ name: 'compare_total', type: 'integer', primaryKey: false, masked: false, label: '比价条数' },
|
||||
{ name: 'recommend_supplier', type: 'text', primaryKey: false, masked: false, label: '推荐供应商' },
|
||||
{ name: 'customer_code', type: 'text', primaryKey: false, masked: false, label: '客户码' },
|
||||
{ name: 'customer_name', type: 'text', primaryKey: false, masked: false, label: '客户名称' },
|
||||
{ name: 'quote_line_total', type: 'integer', primaryKey: false, masked: false, label: '清单条目数' },
|
||||
{ name: 'pending_total', type: 'integer', primaryKey: false, masked: false, label: '待补价条数' },
|
||||
/* A 类预填走完的凭据(0 也要写)—— 哨兵按它放 PRM 那一步入场 */
|
||||
{ name: 'hist_priced_total', type: 'integer', primaryKey: false, masked: false, label: 'A 类已按历史价预填条数' },
|
||||
/* 「PRM 的答复处理过了」的凭据 —— 只在人环走完才产生 */
|
||||
{ name: 'sourced_total', type: 'integer', primaryKey: false, masked: false, label: 'PRM 已补价条数' },
|
||||
{ name: 'route_decided_total', type: 'integer', primaryKey: false, masked: false, label: '已定盘' },
|
||||
{ name: 'summary', type: 'text', primaryKey: false, masked: false, label: '寻源结论' },
|
||||
],
|
||||
},
|
||||
],
|
||||
listeners: [
|
||||
{
|
||||
// 回价到期:临过期提醒复核确认,过期触发重询 —— 时限必配
|
||||
/** 供应商回价到达:记一笔观察(PRM 在系统外收回价,这里只接得到通道转进来的) */
|
||||
origin: 'static',
|
||||
eventType: 'data',
|
||||
keyFilter: { kind: 'supplier-quote' },
|
||||
@@ -188,6 +268,7 @@ export const manifest: ActivityManifest = {
|
||||
escalation: ['nudge', 'escalate'],
|
||||
},
|
||||
{
|
||||
/** 回价临过期:提醒复核确认 —— 时限必配 */
|
||||
origin: 'static',
|
||||
eventType: 'time',
|
||||
keyFilter: { kind: 'quote-expiry' },
|
||||
@@ -196,35 +277,124 @@ export const manifest: ActivityManifest = {
|
||||
escalation: ['nudge', 'reroute'],
|
||||
},
|
||||
],
|
||||
// 按场景时限:BOM早期/现货 1~4 日、样品 1~3 日、BOM后期 3~9 日 —— 取最宽做停滞阈值
|
||||
harness: {
|
||||
memoryWindow: 30,
|
||||
memoryWindow: 24,
|
||||
// PRM 在系统外询价,按场景时限最宽 BOM后期 3~9 日 —— 停滞阈值放到两天
|
||||
stallAfter: 'P2D',
|
||||
nudge: [{ after: 'P1D', action: 'nudge' }],
|
||||
retry: { times: 2, backoff: 'PT5M' },
|
||||
},
|
||||
},
|
||||
|
||||
/* ── 资产初始版 ──────────────────────────────────────────────── */
|
||||
assets: {
|
||||
businessModel: {
|
||||
cmmnXml: CMMN_XML,
|
||||
// 双表示同版本:XML 是机器面,说明书是叙事面 —— 不允许分叉
|
||||
narrative: NARRATIVE,
|
||||
dmn: STRATEGY_DMN,
|
||||
/* 步骤剧本 —— 与 A1 同一套:doneWhen 真了引擎自己收步,不问模型 */
|
||||
dmn: SOURCING_DMN,
|
||||
steps: SOURCING_STEPS,
|
||||
phases: SOURCING_PHASES,
|
||||
},
|
||||
skills: SOURCING_SKILLS,
|
||||
viewTemplates: [{ name: 'case-overview', html: SOURCING_CASE }],
|
||||
/*
|
||||
* 两个局面各一张(与 A2 同款口径,2026-08-02):
|
||||
* · `sourcing-worksheet` 寻源询价工作单 —— 归一预填与 PRM 补价期间摆它:
|
||||
* 逐颗待询料的询价档案、按场景圈渠道的规则、价格验证的尺、发询纪律与时限,
|
||||
* 填回区就长在上面(素材出处 docs/MVP示例工作流.html §1.7,只作文字参考);
|
||||
* · `sourcing-roster` 目标报价清单 —— 汇稿定盘后与放行、归档摆它。
|
||||
*/
|
||||
viewTemplates: [
|
||||
{ name: 'sourcing-worksheet', html: SOURCING_WORKSHEET },
|
||||
{ name: 'sourcing-roster', html: SOURCING_ROSTER },
|
||||
],
|
||||
cardSchemas: {},
|
||||
/*
|
||||
* distillHooks 只留 terminal —— 上一版还有 `milestone: 'M_quotes'`,
|
||||
* 而案例模型里从来没有这个里程碑(死链,钩子永不触发)。
|
||||
*/
|
||||
distillHooks: [
|
||||
{ on: 'milestone', milestone: 'M_quotes', prompt: '归纳各渠道的回价节奏与配合度。' },
|
||||
{ on: 'terminal', prompt: '归纳本单寻源:哪些渠道靠谱、哪些场景的价格验证规则该收紧。' },
|
||||
{
|
||||
on: 'terminal',
|
||||
prompt: '归纳本单寻源:哪些料历史价可用、货源价与历史价的偏离形态、剔单的原因分布。',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
/* ── 样例集 —— 三条形状真不同(常备案例即验收案例)───────────── */
|
||||
samples: [
|
||||
{ name: 'BOM后期询价', input: { pn: 'LM358DR', scenario: 'BOM后期', quantity: 5000 }, expect: { ports: ['compare'] } },
|
||||
{
|
||||
/*
|
||||
* ① 选型转来:A2 放行载荷的真实形状 —— rows 里清单行(带 alt_pn 与现标)
|
||||
* 混着结论行;A 类行的取价对象是替代料。
|
||||
*/
|
||||
name: '选型转来 · 一颗转 B 的替代料要问价(A 类行历史价预填)',
|
||||
input: {
|
||||
rfqRef: 'RFQ MD14.1',
|
||||
customer_code: 'CU-0142',
|
||||
customer_name: 'Itelma',
|
||||
rows: [
|
||||
{
|
||||
rfq_ref: 'RFQ MD14.1',
|
||||
pn: 'BBPY00201209601Y00',
|
||||
customer_pn: '4-14-01502',
|
||||
category: '滤波器',
|
||||
brand: 'YAGEO',
|
||||
eau: 30000,
|
||||
alt_pn: 'PBY201209T-601Y-N',
|
||||
orig_type: 'C',
|
||||
type_tag: 'B',
|
||||
basis: '替代料 PBY201209T-601Y-N 库内无历史 → 转 B',
|
||||
},
|
||||
{
|
||||
rfq_ref: 'RFQ MD14.1',
|
||||
pn: 'CJTB0101R6N',
|
||||
customer_pn: '4-00-04102',
|
||||
category: '集成电路',
|
||||
brand: 'Jiangsu Changjing',
|
||||
eau: 60000,
|
||||
orig_type: 'A',
|
||||
type_tag: 'A',
|
||||
},
|
||||
{
|
||||
rfq_ref: 'RFQ MD14.1',
|
||||
alt_line_total: 2,
|
||||
c_total: 1,
|
||||
need_sourcing: true,
|
||||
route_decided_total: 1,
|
||||
customer_name: 'Itelma',
|
||||
},
|
||||
],
|
||||
},
|
||||
expect: { ports: ['quotation'] },
|
||||
},
|
||||
{
|
||||
/*
|
||||
* ② 受理直达(E3 那条路):A1 载荷形状 —— records 混行,B 类两颗要问价,
|
||||
* A 类一颗历史价预填。
|
||||
*/
|
||||
name: '受理直达 · 两颗 B 类要问价(records 混行形状)',
|
||||
input: {
|
||||
rfqRef: 'RFQ-2026-0555',
|
||||
customer_name: '青岛海洋电子',
|
||||
records: [
|
||||
{ rfq_ref: 'RFQ-2026-0555', pn: 'PESD2ETH-XR', category: '二极管', brand: 'Nexperia', eau: 30000, type_tag: 'B' },
|
||||
{ rfq_ref: 'RFQ-2026-0555', pn: 'PESD2ETH-XR', history_days: 9999, market_stable: false, lifecycle: '未知', type_tag: 'B', basis: '无历史/过期/波动 → B' },
|
||||
{ rfq_ref: 'RFQ-2026-0555', pn: 'NE555P', category: '定时器', brand: 'TI', eau: 5000, type_tag: 'B' },
|
||||
{ rfq_ref: 'RFQ-2026-0555', pn: 'UMW AO6604', category: '晶体管', brand: 'UMW', eau: 30000, type_tag: 'A' },
|
||||
{ rfq_ref: 'RFQ-2026-0555', line_total: 3, type_a_total: 1, type_b_total: 2, type_c_total: 0, need_sourcing: true },
|
||||
],
|
||||
},
|
||||
expect: { ports: ['quotation'] },
|
||||
},
|
||||
{
|
||||
/* ③ 单飞宽进:没有单号没有清单,正文列料 —— 归一造案号,全按 B 待询 */
|
||||
name: '单飞需求 · 正文列两颗料要问底价(宽进归一)',
|
||||
input: {
|
||||
subject: '两颗现货料问底价',
|
||||
body: '帮忙问两颗料的现货底价:SS8050 三极管 20K,XC6206P332MR LDO 10K。现货场景,只要有库存实拍的供应商。',
|
||||
},
|
||||
expect: { ports: ['quotation'] },
|
||||
},
|
||||
],
|
||||
|
||||
entry: { file: 'index.js', checksum: 'dev-entry-quote-sourcing' },
|
||||
|
||||
Reference in New Issue
Block a user