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,27 +1,45 @@
|
||||
/**
|
||||
* 活动包清单 —— 统一报价 A4 · 成本定价。
|
||||
* 活动包清单 —— 统一报价 A4 · 成本定价(案例活动)。
|
||||
*
|
||||
* 业务素材:docs/MVP示例工作流.html §1.2(S1 取价基准 → S2 逐条定价 → S3 底价自检)。
|
||||
* README《已裁定的落地决策》③:**A4 = flow** —— 取价、查表定价、自检的判断
|
||||
* **全部装进 DMN 决策表确定性求值**;一旦出现「由 AI 决定怎么办」,按 AM 2.1 上升。
|
||||
* 业务素材:`docs/MVP示例工作流.html` §1.2(S1 取价基准 → S2 逐条定价 → S3 底价自检):
|
||||
* 「BD 逐条定价:价格 = 底价 × 利润模型。提交审批前先自查底价门禁 ——
|
||||
* 超限的自己先调,不把问题留给 PM。」
|
||||
*
|
||||
* 形状与 A3 同一条(2026-08-03 重写 @3.0.0):归一算价 → 一张执行单交人 → 超限才叫人
|
||||
* 拍板 → 放行。**能算的不问人**(P-01 毛利档、P-02 底价门禁两把尺写死),
|
||||
* **该人负责的不自算**(拟报单价是必填,库内没有基准的那几行系统一个价都不编)。
|
||||
*
|
||||
* 与 @2.0.0 的差别(三处都是踩过的账):
|
||||
* ① `input.required` 从 `['rfqRef','customerCode','records']` 清空 —— 宽进严出,
|
||||
* 上游(A3)发的是 `{rfqRef, rows}`,门口拦的恰是主路;
|
||||
* ② 台账补 `required` —— 从前一个必填都没有,执行卡的闸没牙,人不填也能交卷;
|
||||
* ③ 判据与哨兵全部换成**基座读数**(`_rows` / `_missing` / `_<列>_<值>`)——
|
||||
* 从前 L1 读 `unpriced_total`、哨兵读 `draft_total`,两个都是活动自报的数。
|
||||
*/
|
||||
import type { ActivityManifest, DmnModel } from '@contracts';
|
||||
import { PRICING_SKILLS } from './skills.ts';
|
||||
import { CMMN_XML, NARRATIVE, PRICING_STEPS } from './case-model.ts';
|
||||
import { activityIdSchema } from '@contracts';
|
||||
import { PRICING_BASIS, PRICING_PRICED, PRICING_RELEASE } from './views/report.ts';
|
||||
import { PRICING_SKILLS } from './skills.ts';
|
||||
import { CMMN_XML, NARRATIVE, PRICING_PHASES, PRICING_STEPS } from './case-model.ts';
|
||||
import { PRICING_ROSTER, PRICING_WORKSHEET } from './views/report.ts';
|
||||
|
||||
const DOMAIN = 'quote_pricing';
|
||||
const D = 'quote_pricing';
|
||||
const ACTIVITY_ID = activityIdSchema.parse('quote-pricing');
|
||||
|
||||
/**
|
||||
* 利润模型 P-01 —— 品牌 × 类型 × 客户等级 × 数量档 → 目标毛利。
|
||||
* 「经验」段落不入决策表(那是技能 / 活动记忆种子:载方法不载权力)。
|
||||
* 两把尺 —— **规则本身不是数据**,随包冻结。
|
||||
*
|
||||
* · 利润模型 P-01:客户等级 × 类别 → 目标毛利区间(FIRST,行序即业务优先级);
|
||||
* · 底价门禁 P-02:相对底价线的偏离度 → 处置码。
|
||||
*
|
||||
* 出参就是台账列的取值(`disposition` 的三个大写码),模型算完照抄即可 ——
|
||||
* 「出参键名与台账列同名」是为了它拿回去直接 write(规范 §5.6)。
|
||||
* 两把尺的档位在三处出现:这张表、剧本 guide、工作单上的规则块 ——
|
||||
* 包内自测把三处钉在一起(改一处不改另两处,测就红)。
|
||||
*/
|
||||
export const P01_DMN: DmnModel = {
|
||||
drd: [
|
||||
{ decision: 'p01-margin', requires: [], inputs: ['customerGrade', 'materialType', 'volumeTier'] },
|
||||
{ decision: 'p02-floor', requires: ['p01-margin'], inputs: ['quotedPrice', 'floorPrice'] },
|
||||
{ decision: 'p01-margin', requires: [], inputs: ['customer_grade', 'type_tag'] },
|
||||
{ decision: 'p02-floor', requires: ['p01-margin'], inputs: ['deviation'] },
|
||||
],
|
||||
tables: [
|
||||
{
|
||||
@@ -29,30 +47,29 @@ export const P01_DMN: DmnModel = {
|
||||
label: '利润模型 P-01',
|
||||
hitPolicy: 'FIRST',
|
||||
inputs: [
|
||||
{ name: 'customerGrade', expression: 'customerGrade' },
|
||||
{ name: 'materialType', expression: 'materialType' },
|
||||
{ name: 'volumeTier', expression: 'volumeTier' },
|
||||
{ name: 'customer_grade', expression: 'customer_grade' },
|
||||
{ name: 'type_tag', expression: 'type_tag' },
|
||||
],
|
||||
outputs: [{ name: 'marginLow' }, { name: 'marginHigh' }],
|
||||
outputs: [{ name: 'margin_low' }, { name: 'margin_high' }],
|
||||
rules: [
|
||||
{ id: 'p01-1', when: ['"战略客户"', '"A"', '"大批量"'], then: [0.08, 0.1], annotation: '战略客户 A 类标准件大批量 8%–10%' },
|
||||
{ id: 'p01-2', when: ['"普通客户"', '"A"', '-'], then: [0.12, 0.15], annotation: '普通客户 A 类标准件 12%–15%' },
|
||||
{ id: 'p01-3', when: ['-', '"B"', '-'], then: [0.15, 0.2], annotation: 'B 类波动件 15%–20%' },
|
||||
{ id: 'p01-4', when: ['-', '"C"', '-'], then: [0.2, 0.5], annotation: 'C 类替代/EOL ≥20% 或一事一议' },
|
||||
{ id: 'p01-default', when: ['-', '-', '-'], then: [0.12, 0.15], annotation: '兜底按普通客户标准件' },
|
||||
{ id: 'p01-1', when: ['"战略客户"', '"A"'], then: [0.08, 0.1], annotation: '战略客户 A 类标准件(大批量长单)8%~10%' },
|
||||
{ id: 'p01-2', when: ['"普通客户"', '"A"'], then: [0.12, 0.15], annotation: '普通客户 A 类标准件 12%~15%' },
|
||||
{ id: 'p01-3', when: ['-', '"B"'], then: [0.15, 0.2], annotation: 'B 类波动件 15%~20%' },
|
||||
{ id: 'p01-4', when: ['-', '"C"'], then: [0.2, 0.5], annotation: 'C 类替代/停产件 20%~50%(一事一议)' },
|
||||
{ id: 'p01-default', when: ['-', '-'], then: [0.12, 0.15], annotation: '拿不准按普通客户标准件档' },
|
||||
],
|
||||
},
|
||||
{
|
||||
/** 底价门禁 P-02 —— 偏离底价 ±20% 即止 */
|
||||
/** 底价门禁 P-02 —— 偏离底价线 ±20% 即止;出参就是台账 `disposition` 的取值 */
|
||||
id: 'p02-floor',
|
||||
label: '底价门禁 P-02',
|
||||
hitPolicy: 'FIRST',
|
||||
inputs: [{ name: 'deviation', expression: 'deviation' }],
|
||||
outputs: [{ name: 'disposition' }, { name: 'passable' }],
|
||||
rules: [
|
||||
{ id: 'p02-1', when: ['>= 0'], then: ['直接放行', true], annotation: '≥底价 → 直接放行' },
|
||||
{ id: 'p02-2', when: ['[-0.20..0)'], then: ['PM 附理由放行', true], annotation: '低于底价 ≤20% → PM 附理由' },
|
||||
{ id: 'p02-3', when: ['< -0.20'], then: ['拦截 · BOSS 拍板', false], annotation: '低于底价 >20% → 拦截' },
|
||||
{ id: 'p02-1', when: ['>= 0'], then: ['PASS', true], annotation: '在底价线之上 → 直接放行' },
|
||||
{ id: 'p02-2', when: ['[-0.20..0)'], then: ['NOTE', true], annotation: '低于底价线两成以内 → 附理由放行' },
|
||||
{ id: 'p02-3', when: ['< -0.20'], then: ['BLOCK', false], annotation: '低于两成以上 → 拦截,人拍板' },
|
||||
],
|
||||
},
|
||||
],
|
||||
@@ -62,95 +79,162 @@ export const manifest: ActivityManifest = {
|
||||
identity: {
|
||||
activityId: ACTIVITY_ID,
|
||||
name: 'A4 · 成本定价',
|
||||
packageVersion: '2.0.0',
|
||||
packageVersion: '3.5.0',
|
||||
category: '统一报价',
|
||||
sdkVersion: '0.1.0-m5',
|
||||
checksum: 'dev-checksum-quote-pricing',
|
||||
},
|
||||
|
||||
/* ── 契约七件 ────────────────────────────────────────────────── */
|
||||
contract: {
|
||||
activityId: ACTIVITY_ID,
|
||||
version: '0.1.0',
|
||||
version: '1.0.0',
|
||||
input: {
|
||||
/*
|
||||
* **宽进到底:一个必填都不设**(与 A1/A2/A3 同口径 —— 宽进严出,
|
||||
* 输入契约在活动内部归一 + 补全)。
|
||||
*
|
||||
* 来路三种形状:寻源转来(rows,行上带 base_price)、受理/选型直达(records/rows,
|
||||
* 没有底价)、单飞(一段文字)。上一版必填 `rfqRef + customerCode + records`,
|
||||
* 而 A3 的 `quotation` 口发的是 `{rfqRef, rows}` —— 门口拦的恰是主路。
|
||||
*/
|
||||
data: {
|
||||
type: 'object',
|
||||
required: ['rfqRef', 'customerCode', 'records'],
|
||||
required: [],
|
||||
properties: {
|
||||
rfqRef: { type: 'string', title: '询价单号(单标识,贯穿全流程)' },
|
||||
customerCode: { type: 'string' },
|
||||
records: { type: 'array' },
|
||||
// B/C 类由 A3/A2 交回的底价与替代方案;A 类直通时为空
|
||||
floorPrices: { type: 'array' },
|
||||
customerCode: { 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: '读出来的文本' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageAllowed: true,
|
||||
messageHint: '客户等级、急单、竞对价、这一单的让价授权写这里',
|
||||
},
|
||||
output: {
|
||||
/*
|
||||
* 只有一个出口:报价草案交定价审批(流程包 E8 是无条件边)。没有选择组 ——
|
||||
* 没有去向要选,定盘就是把账写齐。
|
||||
*
|
||||
* 载荷键名照下游(A6 议价)的入参写:`rfqRef / customerCode / items` ——
|
||||
* 边读什么、下游要什么,上游就得发什么。标量都有台账列承载(自测钉着)。
|
||||
*/
|
||||
mandatory: [
|
||||
{
|
||||
name: 'draft',
|
||||
payload: {
|
||||
type: 'object',
|
||||
required: ['rfqRef', 'items'],
|
||||
properties: { rfqRef: { type: 'string' }, items: { type: 'array' } },
|
||||
properties: {
|
||||
rfqRef: { type: 'string', title: '询价单号(单标识 —— 下游台账的主键)' },
|
||||
customerCode: { type: 'string', title: '客户码' },
|
||||
items: { type: 'array', title: '报价草案(每条带拟报单价、偏离度与门禁处置)' },
|
||||
},
|
||||
},
|
||||
description: '报价草案(逐条带偏离度)',
|
||||
description: '报价草案(全条目带拟报单价与门禁处置)',
|
||||
},
|
||||
],
|
||||
selective: [],
|
||||
},
|
||||
/*
|
||||
* 必交付物**必须给 `ledger` 地址**(2026-07-31 修)。
|
||||
* 不给的话预检退回 `scope[key]` 去找 —— key 是 `benchmark-table` 这样的短横线别名,
|
||||
* 任务视图里永远没有这个键,于是「必交付物缺一不得提交放行」永远拒,
|
||||
* 活办完了也放不了行,连拒五拍熔断(实测 A2 死于此)。
|
||||
* 必交付物只有一件:**报价草案**。定价结论(verdict)是它的结论栏,
|
||||
* `ledgers` 说清这份成果由哪几张表承载(一份成果,不是两份)。
|
||||
*/
|
||||
requiredDeliverables: [
|
||||
{ key: 'quote-draft', label: '报价草案(全条目带偏离度)', ledger: `${DOMAIN}.draft` },
|
||||
{
|
||||
key: 'quote-draft',
|
||||
label: '报价草案(每条带拟报单价与门禁处置)',
|
||||
ledger: `${D}.draft`,
|
||||
/* 验收页上让 BD 就地改的两列 —— 恰是他的职权面(定价与让价理由) */
|
||||
editableAtRelease: ['quoted_price', 'price_note'],
|
||||
ledgers: [`${D}.draft`, `${D}.verdict`],
|
||||
},
|
||||
],
|
||||
/*
|
||||
* 机检谓词读的是 `verdict` 那张**汇总表**的列(照 A1 的口径)。
|
||||
* 上一版的名字(unpriced;floor-gate 更是连谓词都没有)**台账里根本没有** —— S-FEEL 拿未绑定的名字
|
||||
* 比大小求值为假,判据永远达不了标,submit 门永远拒,连拒五拍熔断。
|
||||
* 判据的名字必须落在台账上,否则「机检」是一句空话(2026-07-31 销账)。
|
||||
* 验收判据 —— **机检(L1/L2)只读基座数得出来的数**:
|
||||
* `_rows` 基座数行数、`_missing` 基座按 required 现数(与执行卡提交闸同一个数
|
||||
* 同一套算法)、`_disposition_*` 基座按值现数。
|
||||
* 上一版两条机检读活动自报的 `unpriced_total` / `unresolved_over_total` ——
|
||||
* 那不是门,是「改哪个数能过」的提示(违反史已记四次,这是第五类)。
|
||||
*/
|
||||
acceptanceCriteria: [
|
||||
{ key: 'all-priced', label: '每条都有拟报单价与毛利率', level: 'L1', predicate: 'unpriced_total = 0' },
|
||||
// 底价门禁沉为 L2 机检 —— 「约束力收缩」的终点
|
||||
{ key: 'floor-gate', label: '偏离底价 ≤±20%,超限者已回调或注明理由', level: 'L2', modelRef: 'p02-floor', predicate: 'unresolved_over_total = 0' },
|
||||
{ key: 'pm-release', label: 'BD 放行', level: 'L5' },
|
||||
{
|
||||
key: 'roster-complete',
|
||||
label: '草案齐:上游条目逐条承继,说了几条草案里就躺着几行',
|
||||
level: 'L1',
|
||||
predicate: `line_total > 0 and ${D}_draft_rows = line_total`,
|
||||
},
|
||||
{
|
||||
key: 'all-priced',
|
||||
label: '每条都有拟报单价:库内无基准价的那几行也由人定过价,缺一行放不了',
|
||||
level: 'L1',
|
||||
predicate: `${D}_draft_rows > 0 and ${D}_draft_missing = 0`,
|
||||
},
|
||||
{
|
||||
key: 'floor-gate',
|
||||
label: '底价门禁已过:处置逐条落定,没有还压在拦截档上的条目 —— 超限的要么回调、要么经人拍板附理由',
|
||||
level: 'L2',
|
||||
modelRef: 'p02-floor',
|
||||
predicate: `${D}_draft_disposition_block = 0 and ${D}_draft_disposition_pass + ${D}_draft_disposition_note + ${D}_draft_disposition_block = ${D}_draft_rows`,
|
||||
},
|
||||
/*
|
||||
* 报价来路可核是**裁量**(L3):基准是不是那个基准、让价理由站不站得住,
|
||||
* 机器数不出来。这句 label 与剧本里 judge 的 criterion **必须逐字一致**。
|
||||
*/
|
||||
{
|
||||
key: 'price-defensible',
|
||||
label: '报价的来路说得清:基准价来源、毛利档与让价理由逐条可溯,BD 对报价负责',
|
||||
level: 'L3',
|
||||
},
|
||||
/* L5 是责任关:那张卡本身就是这道关,卡面上不摆它(基座统一滤) */
|
||||
{ key: 'bd-release', label: 'BD 放行:签下去这份报价草案即定盘并交定价审批', level: 'L5' },
|
||||
],
|
||||
revisableAtRelease: [],
|
||||
prohibitions: [
|
||||
{ key: 'no-silent-override', statement: '不得静默绕开 P-02 的结论;要破线只能走「人 · 决策」' },
|
||||
{ key: 'no-stale-floor', statement: '底价超一周未更新的,先刷底价再判' },
|
||||
{ key: 'no-silent-override', statement: '不得静默绕开底价门禁的结论;要破线只能走「人 · 决策」并留下理由' },
|
||||
{ key: 'no-made-up-basis', statement: '没有成本基准的料不许编一个偏离率出来:基准空着就空着,价由人定并注明依据' },
|
||||
{ key: 'no-stale-floor', statement: '底价超一周未更新的,先刷底价再判 —— 拿过期的成本算出来的毛利是假的' },
|
||||
],
|
||||
authorization: {
|
||||
discretion: [{ key: 'margin-band', statement: '在 P-01 给出的毛利区间内自决;出区间必须调人决策' }],
|
||||
discretion: [{ key: 'margin-band', statement: '在 P-01 给出的毛利区间内自决;出区间要么回调,要么调人拍板' }],
|
||||
preauthorizedActions: [],
|
||||
humanCallBudget: 3,
|
||||
/* 一张执行单 + 可能一张决策卡 + 放行 = 三次;留一倍余量 */
|
||||
humanCallBudget: 5,
|
||||
},
|
||||
resources: {
|
||||
/*
|
||||
* `quote-pricing.basis` 已从声明里去掉(2026-07-31):工具箱里从没注册过它,
|
||||
* 装包时静态审一直报「运行时转人代办」—— 而重做后的案例模型压根不调它
|
||||
* (算价归判定表 P-01/P-02,取基准读历史价)。声明一件不存在也不用的工具,
|
||||
* 只会让每一单跑到 A4 就弹一张莫名其妙的转人卡。
|
||||
*/
|
||||
tools: [{ name: 'crm.history-price-read' }],
|
||||
skills: PRICING_SKILLS.map((s) => s.id),
|
||||
models: ['deepseek-v4-flash'],
|
||||
roles: ['BD'],
|
||||
budget: { steps: 60, tokens: 150_000, activeMinutes: 120, humanCalls: 3 },
|
||||
/* SLA <2h(MVP示例 §1.2);预算按 A3 实测(6-8 拍 / 40-50k)留一倍余量 */
|
||||
budget: { steps: 60, tokens: 400_000, activeMinutes: 120, humanCalls: 5 },
|
||||
},
|
||||
},
|
||||
|
||||
/* ── 声明 ────────────────────────────────────────────────────── */
|
||||
declarations: {
|
||||
models: ['deepseek-v4-flash'],
|
||||
tools: [{ name: 'crm.history-price-read' }],
|
||||
ledger: [
|
||||
{
|
||||
domain: DOMAIN,
|
||||
domain: D,
|
||||
object: 'draft',
|
||||
kind: 'record',
|
||||
caseKey: 'rfq_ref',
|
||||
@@ -158,82 +242,226 @@ export const manifest: ActivityManifest = {
|
||||
fields: [
|
||||
{ name: 'rfq_ref', type: 'text', primaryKey: true, masked: false, label: '询价单号' },
|
||||
{ name: 'pn', type: 'text', primaryKey: true, masked: false, label: 'PN' },
|
||||
{ name: 'quoted_price', type: 'number', primaryKey: false, masked: false, label: '拟报单价' },
|
||||
{ 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: 'lead_time', type: 'text', primaryKey: false, masked: false, label: '客户要求交期' },
|
||||
/* 客户备注承继自上游 —— 认证要求、预授权、急料标注,让价时的第一手依据 */
|
||||
{ name: 'remark', type: 'text', primaryKey: false, masked: false, label: '客户备注(约束/急料)' },
|
||||
{ name: 'type_tag', type: 'text', primaryKey: false, masked: false, label: '类别(承继)', tally: ['A', 'B', 'C'] },
|
||||
/*
|
||||
* **客户目标价标 `expect`** —— 客户该给而没给的那一问不能省(件上出橘色
|
||||
* 「建议填」胶囊)。它不拦单:`_gaps` 只喂 L4,而本活动没有 L4 判据。
|
||||
* 注意边界:我方自己写的注(price_note)**不标 expect** —— 标了 `_gaps`
|
||||
* 恒大于 0,那条判据永远绿不了(A1 的账)。
|
||||
*/
|
||||
{ name: 'target_price', type: 'number', primaryKey: false, masked: false, expect: true, label: '客户目标价' },
|
||||
/* 成本基准:上游底价或库内历史价。**取不到就空着** —— 空着不是异常,是「无基准」那一档 */
|
||||
{ name: 'base_price', type: 'number', primaryKey: false, masked: false, label: '成本基准' },
|
||||
{ name: 'price_basis', type: 'text', primaryKey: false, masked: false, label: '基准来源', tally: ['HIST', 'SOURCED'] },
|
||||
{ name: 'margin_band', type: 'text', primaryKey: false, masked: false, label: '毛利档(P-01)' },
|
||||
{ name: 'floor_price', type: 'number', primaryKey: false, masked: false, label: '底价线' },
|
||||
/*
|
||||
* **系统建议价是 AI 的活,拟报单价是人的活** —— 两列分开是**结构治**,不是措辞治。
|
||||
*
|
||||
* 实测账(2026-08-03,单飞那条案例):从前只有 `quoted_price` 一列,剧本写着
|
||||
* 「无基准的行留空,由 BD 定」—— 模型照样给两颗库里查不到的料编了价
|
||||
* (一颗抄了客户目标价,另一颗凭空写了 0.085),交代里还说着「价空着等你定」。
|
||||
* 一条要模型分辨「这行算得出/算不出」的规矩,它十次里会走岔;
|
||||
* 而「这一列你一格都不写」没有分支可走岔。
|
||||
*
|
||||
* 于是:AI 只写 `suggested_price`(算得出就给,算不出就空着),
|
||||
* **`quoted_price` 永远是人在件上定的那个数** —— 它标 `required`,
|
||||
* 件上的缺价红带、执行卡的提交闸、放行门 L1 三处同源(都数基座的 `_missing`)。
|
||||
* 不用 `requiredWhen`:每一行都要有价,没有「这一行还没轮到」的情形。
|
||||
*/
|
||||
{ name: 'suggested_price', type: 'number', primaryKey: false, masked: false, label: '系统建议价' },
|
||||
{ name: 'quoted_price', type: 'number', primaryKey: false, masked: false, required: true, label: '拟报单价(BD 定)' },
|
||||
{ name: 'margin', type: 'number', primaryKey: false, masked: false, label: '毛利率' },
|
||||
{ name: 'last_price', type: 'number', primaryKey: false, masked: false, label: '基准价' },
|
||||
{ name: 'deviation', type: 'number', primaryKey: false, masked: false, label: '偏离度' },
|
||||
{ name: 'disposition', type: 'text', primaryKey: false, masked: false, label: '门禁处置' },
|
||||
{ name: 'deviation', type: 'number', primaryKey: false, masked: false, label: '偏离底价线' },
|
||||
/*
|
||||
* **门禁处置:取值域给出来,条数由基座现数** —— PASS / NOTE / BLOCK。
|
||||
* 守恒判据、分布条、门禁徽读的全是基座读数;值是机器码,
|
||||
* 人读名(直接放行 / 附理由 / 拦截待拍板)由模版样式表翻译。
|
||||
*/
|
||||
{ name: 'disposition', type: 'text', primaryKey: false, masked: false, label: '门禁处置', tally: ['PASS', 'NOTE', 'BLOCK'] },
|
||||
{ name: 'price_note', 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: 'draft_total', type: 'integer', primaryKey: false, masked: false, label: '草案条数' },
|
||||
{ name: 'unpriced_total', type: 'integer', primaryKey: false, masked: false, label: '未定价条数' },
|
||||
{ name: 'over_total', type: 'integer', primaryKey: false, masked: false, label: '超限条数' },
|
||||
{ name: 'unresolved_over_total', type: 'integer', 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: '客户名称' },
|
||||
/* 客户等级是 P-01 的入参之一(战略客户 / 普通客户),认不出按普通客户 */
|
||||
{ name: 'customer_grade', type: 'text', primaryKey: false, masked: false, label: '客户等级' },
|
||||
{ name: 'line_total', type: 'integer', primaryKey: false, masked: false, label: '草案条目数' },
|
||||
{ name: 'basis_total', type: 'integer', primaryKey: false, masked: false, label: '有成本基准的条数' },
|
||||
/* 算价走完的凭据(0 也要写)—— 哨兵按它放交人核价那一步入场 */
|
||||
{ name: 'priced_total', type: 'integer', primaryKey: false, masked: false, label: '已算出建议价条数' },
|
||||
/* 「BD 核过价了」的凭据 —— 只在人环走完才产生 */
|
||||
{ name: 'confirmed_total', type: 'integer', primaryKey: false, masked: false, label: 'BD 已核价条数' },
|
||||
{ name: 'route_decided_total', type: 'integer', primaryKey: false, masked: false, label: '已定盘' },
|
||||
{ name: 'summary', type: 'text', primaryKey: false, masked: false, label: '定价结论' },
|
||||
],
|
||||
},
|
||||
],
|
||||
listeners: [
|
||||
{
|
||||
/** 时限过半:SLA <2h,给 BD 与负责人提个醒 —— 静态监听,时限必配 */
|
||||
origin: 'static',
|
||||
eventType: 'human',
|
||||
keyFilter: { kind: 'decision' },
|
||||
semantic: 'complete-step',
|
||||
deadline: 'PT4H',
|
||||
escalation: ['nudge', 'escalate'],
|
||||
eventType: 'time',
|
||||
keyFilter: { kind: 'half-deadline' },
|
||||
semantic: 'observe',
|
||||
deadline: 'PT1H',
|
||||
escalation: ['nudge'],
|
||||
},
|
||||
],
|
||||
// SLA <2h(MVP示例 §1.2 留痕 · SLA)
|
||||
harness: {
|
||||
memoryWindow: 20,
|
||||
memoryWindow: 22,
|
||||
// SLA <2h(MVP示例 §1.2 留痕 · SLA)
|
||||
stallAfter: 'PT2H',
|
||||
nudge: [{ after: 'PT1H', action: 'nudge' }],
|
||||
retry: { times: 2, backoff: 'PT30S' },
|
||||
},
|
||||
},
|
||||
|
||||
/* ── 资产初始版 ──────────────────────────────────────────────── */
|
||||
assets: {
|
||||
/* 资产初始版:案例模型(2026-07-29 起活动只有这一种业务模型) */
|
||||
businessModel: {
|
||||
cmmnXml: CMMN_XML,
|
||||
narrative: NARRATIVE,
|
||||
dmn: P01_DMN,
|
||||
/* 步骤剧本 —— 与 A1 同一套:doneWhen 真了引擎自己收步,不问模型 */
|
||||
steps: PRICING_STEPS,
|
||||
phases: PRICING_PHASES,
|
||||
},
|
||||
skills: PRICING_SKILLS,
|
||||
/*
|
||||
* 两个局面各一张(与 A2/A3 同款口径):
|
||||
* · `pricing-worksheet` 定价工作单 —— 算价与 BD 核价期间摆它(逐颗定价档案、
|
||||
* 两把尺、填回工作表);
|
||||
* · `pricing-roster` 报价草案清单 —— 拍板、放行、归档摆它。
|
||||
*/
|
||||
viewTemplates: [
|
||||
{ name: 'pricing-basis', html: PRICING_BASIS },
|
||||
{ name: 'pricing-priced', html: PRICING_PRICED },
|
||||
{ name: 'pricing-release', html: PRICING_RELEASE },
|
||||
{ name: 'pricing-worksheet', html: PRICING_WORKSHEET },
|
||||
{ name: 'pricing-roster', html: PRICING_ROSTER },
|
||||
],
|
||||
cardSchemas: {},
|
||||
distillHooks: [
|
||||
{
|
||||
on: 'terminal',
|
||||
prompt: '归纳本单定价的经验:哪些组合的毛利档被人回调过、底价门禁拦下的形态、破线的理由。',
|
||||
prompt: '归纳本单定价:哪些组合的毛利档被人回调过、底价门禁拦下的形态、破线的理由与拍板结果。',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
/* ── 样例集 —— 三条形状真不同(常备案例即验收案例)───────────── */
|
||||
samples: [
|
||||
{
|
||||
name: '战略客户 A 类大批量',
|
||||
input: { customerCode: 'C001', records: [{ pn: 'LM358DR', type: 'A' }] },
|
||||
/*
|
||||
* ① 寻源转来 · 常路:A3 `quotation` 口的真实形状 —— rows 里清单行(带底价与价源)
|
||||
* 混着结论行。客户目标价都在底价线之上,全 PASS,不必叫人拍板。
|
||||
*/
|
||||
name: '寻源转来 · 两条料底价齐 · 全在底价线之上(常路)',
|
||||
input: {
|
||||
rfqRef: 'RFQ MD14.1',
|
||||
customerCode: 'CU-0142',
|
||||
customer_name: 'Itelma',
|
||||
rows: [
|
||||
{
|
||||
rfq_ref: 'RFQ MD14.1',
|
||||
pn: 'BBPY00201209601Y00',
|
||||
customer_pn: '4-14-01502',
|
||||
category: '滤波器',
|
||||
brand: 'YAGEO',
|
||||
eau: 30000,
|
||||
target_price: 0.085,
|
||||
lead_time: '8周',
|
||||
type_tag: 'B',
|
||||
base_price: 0.058,
|
||||
price_basis: 'SOURCED',
|
||||
supplier: '深圳华强渠道',
|
||||
},
|
||||
{
|
||||
rfq_ref: 'RFQ MD14.1',
|
||||
pn: 'CJTB0101R6N',
|
||||
customer_pn: '4-00-04102',
|
||||
category: '集成电路',
|
||||
brand: 'Jiangsu Changjing',
|
||||
eau: 60000,
|
||||
target_price: 0.42,
|
||||
lead_time: '6周',
|
||||
type_tag: 'A',
|
||||
base_price: 0.35,
|
||||
price_basis: 'HIST',
|
||||
},
|
||||
{ rfq_ref: 'RFQ MD14.1', quote_line_total: 2, route_decided_total: 1, customer_name: 'Itelma', summary: '两条底价齐,交定价' },
|
||||
],
|
||||
},
|
||||
expect: { ports: ['draft'] },
|
||||
},
|
||||
{
|
||||
/*
|
||||
* ② 有超限条目:客户把目标价压到成本之下(0.06 对成本 0.082)——
|
||||
* 偏离底价线超过两成,门禁判 BLOCK,必须叫人拍板(决策卡)。
|
||||
*/
|
||||
name: '客户压价 · 一条低于底价线两成以上 → 决策卡叫人拍板',
|
||||
input: {
|
||||
rfqRef: 'RFQ-2026-0777',
|
||||
customerCode: 'CU-0311',
|
||||
customer_name: '青岛海洋电子',
|
||||
rows: [
|
||||
{
|
||||
rfq_ref: 'RFQ-2026-0777',
|
||||
pn: 'PESD2ETH-XR',
|
||||
category: '二极管',
|
||||
brand: 'Nexperia',
|
||||
eau: 30000,
|
||||
target_price: 0.06,
|
||||
lead_time: '8周',
|
||||
type_tag: 'B',
|
||||
base_price: 0.082,
|
||||
price_basis: 'SOURCED',
|
||||
remark: '客户明说这个价是竞对给的,要跟',
|
||||
},
|
||||
{
|
||||
rfq_ref: 'RFQ-2026-0777',
|
||||
pn: 'NE555P',
|
||||
category: '定时器',
|
||||
brand: 'TI',
|
||||
eau: 5000,
|
||||
target_price: 1.05,
|
||||
lead_time: '4周',
|
||||
type_tag: 'A',
|
||||
base_price: 0.85,
|
||||
price_basis: 'HIST',
|
||||
},
|
||||
{ rfq_ref: 'RFQ-2026-0777', quote_line_total: 2, route_decided_total: 1, customer_name: '青岛海洋电子' },
|
||||
],
|
||||
},
|
||||
expect: { ports: ['draft'] },
|
||||
},
|
||||
{
|
||||
/*
|
||||
* ③ 单飞宽进:没有单号没有清单,正文列料 —— 归一造案号;库内查不到历史价,
|
||||
* 系统一个价都不编,两行拟报单价空着交 BD 定 → **提交闸真拦**空手交卷。
|
||||
*/
|
||||
name: '单飞需求 · 正文列两颗料 · 库内无基准 → 价由人定(闸真拦)',
|
||||
input: {
|
||||
subject: '两颗料报个价',
|
||||
body: '客户要两颗料的报价:XCJ-7788T 电源模块 8K,目标价 12.5;LMR-3302QQ 稳压器 15K,没给目标价。库里应该没做过这两颗,你先出个草案。',
|
||||
},
|
||||
expect: { ports: ['draft'] },
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user