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:
2026-08-03 12:28:31 +08:00
co-authored by Claude Opus 5
parent 85466e815f
commit ade0fa5a94
90 changed files with 17969 additions and 2316 deletions
+235 -85
View File
@@ -1,132 +1,282 @@
/**
* A3 渠道寻源的案例模型 —— **一张执行单办完**(2026-07-31 用户定,与 A2 同一口径)。
* A3 寻源询价的案例模型 —— **双表示同版本**:CMMN XML(机器面)与案例说明书(叙事面)。
*
* 上一版按四种询价场景(BOM 早期 / BOM 后期 / 现货 / 样品)把流程铺开成一串计划项。
* 场景之分在业务上是真的,可它**不改变系统要管的事**:发函、收回价、比价、给结论。
* 而这四步在一次寻源里是连着做的 —— 采购不会办完「发函」就交回来等系统叫他。
* 把它切成四项,换来的只是 Agent 每一步都要跟 harness 对一次账。
* 业务出处:`docs/MVP示例工作流.html` §1.7,按 **MVP 简化口径**建模
* (2026-08-02 用户定:A3 与 A2 同为复杂活动,MVP 期间不展开大规模业务建模):
*
* 现在只有两项:
* T_source —— 派一张执行单给采购(卡面两张可编辑表:供应商回价 / 寻源比价),他填完提交;
* T_release —— 放行(触达世界,人工激活)。
* 上游(A2 的询价受理清单,或 A1 直达的 B 类受理记录)进来 → 归一成
* **目标报价清单**底表,A 类行按库内历史价预填基准 → **一张执行单**让采购(PRM)
* 在系统外完成询价、把 B 类行的货源价格填回来 → 汇稿定盘 → 放行,
* 整份目标报价清单交给成本定价。
*
* 场景之分不进模型,进**说明书**:采购自己知道 BOM 早期该广撒网、现货该问库存。
* 那是他的判断,不是系统的步。
* SOP 里接需核史 / 选渠定策 / 发询比价那几段的实质工作(圈渠道、发函、催回价、
* 验价)在 PRM 系统外;四种场景(BOM早期/后期/现货/样品)的尺度之分是他的判断,
* 不是系统的步。系统的本分:归一、预填、组卡、齐检、留痕。
*
* 上一版(@2.0.0)只有「派单 + 放行」两项,入参必填 `pn + scenario`(单料形状,
* 与上游发的整份清单对不上),两条 L2 判据读活动自报数。这一版整个置换。
*/
export const CMMN_XML = `<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL">
<case id="sourcing">
<!--
案卷项的 id **就是任务视图里的键名**。只认两样:
起单入参(pn)与「比价表写了几行」(compare_total)——
后者既是放行前提,也是这一单唯一的机检判据。
案卷项的 id **就是任务视图里的键名**。流内起单时上游载荷(rows / records)
与本活动台账列都会摊平到任务视图顶层,照它们命名。
-->
<caseFileModel>
<caseFileItem id="pn" name="型号(开案即有)"/>
<caseFileItem id="compare_total" name="比价表条数"/>
<caseFileItem id="rows" name="上游清单行(A2 载荷,流内开案即有)"/>
<caseFileItem id="records" name="上游受理记录(A1 直达时有)"/>
<caseFileItem id="quote_line_total" name="清单条目数(自报)"/>
<caseFileItem id="quote_sourcing_quote_list_rows" name="清单行数(基座现数)"/>
<caseFileItem id="pending_total" name="待补价条数"/>
<caseFileItem id="hist_priced_total" name="A 类已按历史价预填条数"/>
<caseFileItem id="sourced_total" name="PRM 已补价条数"/>
<caseFileItem id="quote_sourcing_quote_list_missing" name="缺基准价的行数(基座现数)"/>
<caseFileItem id="route_decided_total" name="已定盘"/>
</caseFileModel>
<casePlanModel id="plan" name="渠道寻源" autoComplete="true">
<sentry id="s_compared">
<onPart id="op_cp" caseFileItemRef="compare_total"><standardEvent>update</standardEvent></onPart>
<ifPart id="if_cp"><condition>compare_total &gt; 0</condition></ifPart>
<casePlanModel id="plan" name="寻源询价" autoComplete="true">
<!--
① 归一并预填完了 —— 交 PRM 那一步的入场前提。
行数两边对上(自报 = 基座现数),且 A 类预填那一轮走完
(hist_priced_total 是预填后显式写下的数;没有 A 类就是 0,
「大于等于 0」对「写过的 0」为真、对「没写过」为假)。
-->
<sentry id="s_normalized">
<onPart id="op_nm" caseFileItemRef="hist_priced_total"><standardEvent>update</standardEvent></onPart>
<ifPart id="if_nm"><condition>quote_line_total &gt; 0 and quote_sourcing_quote_list_rows = quote_line_total and hist_priced_total &gt;= 0</condition></ifPart>
</sentry>
<!--
② PRM 的答复处理过了 —— 汇稿那一步的入场前提。
sourced_total 是「人交回执行单之后」由 AI 清点写下的数(B 类行补上价的条数)——
只在人环走完才存在,它就是「经过人了」的凭据。
-->
<sentry id="s_sourced">
<onPart id="op_sc" caseFileItemRef="sourced_total"><standardEvent>update</standardEvent></onPart>
<ifPart id="if_sc"><condition>sourced_total &gt;= 0</condition></ifPart>
</sentry>
<!--
── 放行门的入场条件:**认「办完了没有」,且读基座数**────────────────
· 每行都有基准价(quote_sourcing_quote_list_missing 由基座按 required 现数,
与执行卡的提交闸、验收 L1 同一个数同一套算法);
· 价源守恒:历史价 + 货源价 = 行数(两边都是基座按值现数);
· 定盘过了(route_decided_total 是汇稿那一步显式写下的记账数)。
-->
<sentry id="s_ready">
<onPart id="op_rd" caseFileItemRef="route_decided_total"><standardEvent>update</standardEvent></onPart>
<ifPart id="if_rd"><condition>route_decided_total &gt; 0 and quote_sourcing_quote_list_rows &gt; 0 and quote_sourcing_quote_list_missing = 0 and quote_sourcing_quote_list_price_basis_hist + quote_sourcing_quote_list_price_basis_sourced = quote_sourcing_quote_list_rows</condition></ifPart>
</sentry>
<!-- 唯一的活:派一张执行单给采购,他填完提交 -->
<humanTask id="T_source" name="渠道寻源:派执行单给采购,收回供应商回价与比价结论">
<itemControl><repetitionRule id="r_src"/></itemControl>
<!-- ① 归一目标报价清单 + A 类按历史价预填基准 -->
<humanTask id="S1_normalize" name="归一目标报价清单:整份落表,A 类按历史价预填基准">
<itemControl><repetitionRule id="r_s1"/></itemControl>
</humanTask>
<!-- 放行:触达世界,必须人工激活 -->
<humanTask id="T_release" name="寻源结论验收放行">
<entryCriterion id="ec_rel" sentryRef="s_compared"/>
<!--
② 补货源价格交 PRM —— **一张执行单**(询价的实质工作在系统外)。
manualActivation + 不给 doneWhen(发卡触达真人,引擎不替人按)。
-->
<humanTask id="S2_fill" name="补货源价格交PRM:执行单上把 B 类行的供应商与底价填回来">
<entryCriterion id="ec_s2" sentryRef="s_normalized"/>
<itemControl><manualActivationRule id="m_s2"/></itemControl>
</humanTask>
<!-- ③ 汇稿定盘:价源归档、齐检、结论 -->
<humanTask id="S3_compile" name="汇稿定盘:价源归档,每行齐检,生成目标报价清单">
<entryCriterion id="ec_s3" sentryRef="s_sourced"/>
</humanTask>
<!-- 清单放行:终局唯放行 —— 触达世界,必须人工激活 -->
<humanTask id="T_release" name="目标报价清单验收放行">
<entryCriterion id="ec_rel" sentryRef="s_ready"/>
<itemControl><manualActivationRule id="m_rl"/></itemControl>
</humanTask>
</casePlanModel>
</case>
</definitions>`;
export const NARRATIVE = `§0 开案:A1 判出一条料要寻源(无近期历史价、或行情波动),这一单就到你手上。
成品只有一样:**一份能拿去定价的比价结论** —— 几家报了什么价、交期多久、推荐哪一家、为什么。
/**
* 案例说明书 —— **只写整单一以贯之的事**(逐步做法归剧本,两处不重复写同一件事)。
*/
export const NARRATIVE = `§0 开案:**一份清单要补齐每一行的价格基准**。来路三种,形状都收(宽进):
· **选型转来**:任务数据里有 \`rows\` 数组 —— 替代选型放行的全部落地行混在一起
(带 alt_pn / 现标的是清单行,带各种总数的是结论行,按 PN 归并自辨);
· **受理直达**:有 \`records\` 数组 —— 受理放行的落地行(受理记录行 + 分类表行 + 结论行);
· **单飞**:只有一段需求文字,列了几颗料要问价。
**这一单只有一步**:把寻源这件事派给采购(执行工单),他填完你收进台账,然后提交放行。
四种询价场景(BOM 早期 / BOM 后期 / 现货 / 样品)的打法差别是**采购的判断**,
不是系统要管的步 —— 你在 ask 里说清是哪种场景就够了,别替他把流程铺开。
**这个活动是复杂活动的 MVP 简化形**:询价的实质工作(圈渠道、发函、催回价、验价)
由采购(PRM)在**系统外**完成;四种场景(BOM早期/后期/现货/样品)的尺度是他的判断。
系统只负责:归一清单、**A 类行按库内历史价预填基准**、把执行单组好交给他、
收回后齐检定盘。
【T_source 派执行单】发 human 行动(workOrder="execution"),卡面 blocks 放**两张可编辑表**:
· 供应商回价:列 = 型号 / 供应商 / 回价 / MOQ / 交期 / 有效期;
· 寻源比价:列 = 型号 / 供应商 / 回价 / 结论。
两张都 editable:true;没有的值给空字符串 —— 空格子界面会自己标红「待填写」。
ask 说清要他做什么(哪颗料、什么场景、要几家、什么时候要);
basis 摆上型号、数量、目标价、客户交期要求(裸卡基座拒发)。
**成品只有一样**:一份**目标报价清单** —— 整份行都在、**每一行都有基准价**
(A 类取历史价,B 类取 PRM 问回来的货源价),价源逐行可溯。它是成本定价的直接输入。
他提交后,回传值出现在你的轨迹里:表格那一份的键是 **table:0 / table:1**(块序号),
值是整张表的 JSON —— **第一行是列名**,其余每行一条,列序与你派出去时一致。
照它 write 进 \`quote_sourcing.supplier_quote\` 与 \`quote_sourcing.compare_table\`,
并把比价表条数记进 compare_total。**写完就 finish T_source,别再发第二张单** —— 他已经答过了。
**这一单要经过人两次,不多不少**:PRM 在执行单上补货源价(那张单绑着整份清单,
必填空着按不下提交 —— 基座的闸看着,他改的格子也直接落账)、放行时 PRM 签字。
【提交放行】比价表有行了 —— **先 start T_release**(人工激活:放行触达世界,必须按一下),
然后 submit,BD 验收。终局唯放行:你不能自己宣布完成。
【一路上要说话】负责人正看着这一单。**每一拍都带一句 say** —— 说业务的话:
哪几颗料等着问价、历史价预填了几条、这单接下来到谁手上;不说系统词。
到了要找人的那一拍,先说清这一轮办完了什么、为什么现在需要他。
【一路上要说话】负责人正看着这一单。每一拍带一句 say,说**业务的话**:
哪颗料在寻源、找了几家、回价怎么样、这一单往哪走。
一两句、口语。别报「写草稿 2 行」这种系统词。`;
【怎么把一项干完 · 一拍连做】write 和 tool 都不会自动收步 —— 做完用 finish 宣告。
动作排进同一拍的 actions 串一口气给;只有调工具(出参下一拍才看得见)与
发卡 / 提交(挂起)必须停拍。**这一单常路 6-8 拍就该收口**。
§Z 结案:PRM 在验收单上签字,系统把草稿合并成正式清单并发出 quotation 口的载荷 ——
整份目标报价清单交给成本定价。`;
/**
* 步骤剧本 —— 与 A1/A2 同一套机制:`doneWhen` 为真,引擎自己收步、**不问模型**。
* 放行那一项不给 `doneWhen` —— 它触达世界,必须人按一下(铁律③)。
* 步骤剧本 —— 一个计划项一条;`doneWhen` 是「成果已存在」的判据,不是「该不该做」。
*/
export const SOURCING_STEPS = [
{
item: 'T_source',
intent: '派一张执行单给采购,收回供应商回价与比价结论',
writes: ['quote_sourcing.supplier_quote', 'quote_sourcing.compare_table', 'quote_sourcing.verdict'],
reads: [],
item: 'S1_normalize',
intent: '上游清单整份归一成目标报价清单;A 类行按库内历史价预填基准',
writes: ['quote_sourcing.quote_list', 'quote_sourcing.verdict'],
/* 上游载荷数组不声明就会被整表段的截断刀砍掉(按字符截,砍掉的恰是要归一的行) */
reads: ['rows', 'records'],
/* 归一预填与 PRM 补价期间摆**询价工作单**;汇稿定盘后才换收口那张清单 */
view: 'sourcing-worksheet',
tools: ['crm.history-price-read'],
/*
* 归一 + 预填两轮都走完才算办完:行数两边对上,且 hist_priced_total 写过
* (没有 A 类就是 0;S-FEEL 未绑定的名字参与比较为假,所以「没写过」进不来)。
*/
doneWhen: 'quote_line_total > 0 and quote_sourcing_quote_list_rows = quote_line_total and hist_priced_total >= 0',
guide: `第一件事:把这一单的**目标报价清单**落出来,并把 A 类行的基准价预填好。
【料从哪儿来】
· 选型转来(有 \`rows\`):清单行带 pn / alt_pn / type_tag(现标)—— 照抄;
带 alt_line_total 这类总数的是结论行,不是料,别落进清单。
· 受理直达(有 \`records\`):受理记录行(带 eau/brand)为准,type_tag 照抄;
分类表行与结论行不落。**按 pn 归并**,一颗料一行。
· 单飞:照正文归一,列了几颗落几行;没说类别的按 B(要问价的料本来就是 B)。
【第一拍:只做两件事 —— 落清单行 + 串尾发一次查价】
① 写 \`quote_sourcing.quote_list\`,一颗料一行(rows 收数组):
pn(**一个字符不许改**)、customer_pn、category、brand、eau、target_price、lead_time、
**remark(客户备注:认证要求、预授权、急料标注 —— 问价口径的第一手依据,一个字别丢)**、
alt_pn(上游有就承继)、type_tag(照上游现标;单飞按 B)。
supplier / base_price / moq / source_lead_time / note **全部留空** —— 价还没来。
② 串尾调 \`crm.history-price-read\`:pns 收数组,把 **A 类行的取价对象**一次传完 ——
**取价对象 = alt_pn 有值取 alt_pn,否则取 pn**(选型转来的 A 行,行情稳的是替代料)。
**这一拍不写 \`quote_sourcing.verdict\`,一列都不写** —— 尤其 hist_priced_total:
它是「预填走完了」的凭据,提前写等于把闸提前打开,引擎会在下一拍开头当场收掉这一步,
**预填从此不会发生**(实测:A 类行底价空着、执行卡照发,而交代里说着「已预填」——
台账与嘴对不上)。没有 A 类行也一样:查价那一步省掉,直接进第二拍。
【第二拍:预填 A 行基准 + 记账 + 收步,一拍连做】
① 工具出参逐行照抄:hit=true 的 A 行写 base_price = lastPrice、price_basis 写 **HIST**
(大写,一个字母不许差 —— 基座按值现数,写别的数不出来)、note 记一句
「库内历史价 <N> 天」;hit=false 的 A 行**别编价** —— base_price 留空,
当 B 类待询处理(pending_total 把它数上;type_tag 不动,那是上游的标)。
② 这时才写 \`quote_sourcing.verdict\`(一次写全):rfq_ref(入参有就原样抄,
没有从主题认,认不出才造「SRC-<型号或类型>」,从头用到尾。
**只从本单来件取材,不许从台账里已有的别单单号里挑** —— 正式表里躺着的
MD14.1 之类是别人的单,借它的号等于把两单的行混进同一个案卷)、
customer_code / customer_name(顶层有就抄)、**quote_line_total** = 清单行数、
**pending_total** = 底价还空着的条数、**hist_priced_total** = 刚预填的条数(0 也要写)。
③ finish 这一项。`,
},
{
item: 'S2_fill',
intent: '一张执行单交 PRM:照询价工作单在系统外询价,供应商与底价就地填回',
writes: ['quote_sourcing.verdict'],
reads: ['quote_sourcing.quote_list'],
view: 'sourcing-worksheet',
tools: [],
/* 不给 doneWhen —— 发卡触达真人(manualActivation),引擎不替人按 */
guide: `清单归一好、A 类基准预填了,**该 PRM 出场了** —— 这是本活动唯一的一张执行单。
工作区摆的是**寻源询价工作单**:逐颗待询料的询价档案(要素/取价对象/客户约束)、
按场景圈渠道的规则、价格验证的尺、发询纪律与时限,填回区就长在上面。
这一步标了人工激活:发卡就算启动,不必单发 start;
引擎也不会替你收 —— 人交回后要你自己 finish。
【照这个骨架发,别少字段】(卡面是纯文本,steps/standard 里**别写星号记号**):
{"kind":"human","itemId":"S2_fill","workOrder":"execution","card":{
"title":"寻源补价:<单号> 待补价 <N> 颗",
"ask":"清单里底价空着的行要补货源价格:请照工作单上的场景规则在系统外完成询价,把供应商与底价填回表里对应行;MOQ、货源交期、备注能问到就一并填。",
"steps":["底价空着的行是本单要问价的料 —— 每行必须补上:供应商、底价(未税单价按内部口径归一);取价对象是替代料一栏有值的取替代料,否则取原型号",
"圈渠道按场景走(细则见工作单):BOM早期与样品可放宽;BOM后期按主供应商、备选、贸易商的顺序圈两三家,贸易商尽量不用;现货只选有库存实拍的供应商",
"回价登记一一对应不可缺项:价格、MOQ、交期能问到就填;验价按场景的尺核过再采,不实回价或远低行情的换渠道补询,别直接采用",
"确实问不到价的料,先与负责人商定:在件上把那一行撤掉(剔出本轮),或按内部估价填并在备注写明;A 类行已按库内历史价预填,可校可改"],
"standard":"每一行都有基准价与价源可溯,渠道与验价按场景的尺走过 —— 底价缺一行,这张单按不下提交(系统的闸看着)。",
"basis":[{"k":"<待补价 PN>","v":"<类别与年用量 + 客户约束(认证/急料),取价对象标明>"}]}}
· \`basis\` 逐条列待补价的料:PN + 类别/年用量。几颗写几条,别铺全表。
· **卡上不摆表、不摆格子**(2026-08-02 用户定:填写全在工作区):整份清单就在
工作单那份件上,供应商/底价/MOQ/货源交期/备注五列都能就地改、行能撤 ——
**别往卡里塞 \`blocks\` 或 \`fields\`**,塞了就是同一张表摆两处。
· **这张卡带提交闸**:底价(必填列)还空着,他按不下提交 —— 缺几格、缺在哪行,
闸上与件上的红带都写着(与放行门 L1 同一个数同一套算法)。
发完卡这一拍就结束了(发卡挂起)。
【人交回之后 —— 件上的值基座已经替你写回了】他在件上按「保存」那一刻改动就落进了
草稿层,按「提交」只是把卡交回来。你只做两件事,然后 finish:
① 清点原本底价空着、现在有价的条数,把 **sourced_total** 写进 verdict
(他在件上撤了行也算处置过,照实清点;0 也要写);
② 别再 write 那些行 —— 值没变的写入会被「写了等于没写」拒回。
【这张卡一单只发一次】人交回来之后不许再发同一张卡 —— 必填有提交闸兜着,
卡回来时底价一定是齐的(或那几行已被他撤掉)。`,
},
{
item: 'S3_compile',
intent: '价源逐行归档,齐检定盘:目标报价清单成稿',
writes: ['quote_sourcing.quote_list', 'quote_sourcing.verdict'],
reads: ['quote_sourcing.quote_list'],
view: 'sourcing-roster',
tools: [],
/*
* 比价表有行了才算办完。**不能写 `compare_total != null`** ——
* S-FEEL 里未绑定的名字 `!= null` 求值为 true,那一步开局即被收掉(A1 踩过)。
* **收步判据与验收判据同源**:每行有价(基座按 required 现数)、价源守恒
* (基座按值现数)、定盘记账 —— 三样齐才收,松出来的那一截就是返工。
*/
doneWhen: 'compare_total > 0',
guide: `**照这个骨架发,一个字段都别少**(prose 描述不管用,直接抄):
{"kind":"human","itemId":"T_source","workOrder":"execution","card":{
"title":"…","ask":"这颗料要寻源,请找几家报价并给比价结论",
"basis":[{"k":"…","v":"…"}],
"blocks":[
{"t":"table","title":"供应商回价","cols":["型号","供应商","回价","MOQ"],"editable":true,
"rows":[["NE555P","","",""],["NE555P","","",""]]},
{"t":"table","title":"寻源比价","cols":["型号","供应商","回价","结论"],"editable":true,
"rows":[["NE555P","","",""],["NE555P","","",""]]}
]}}
**一条料至少摆 2 行** —— 判据「BOM后期每料 2~3 家渠道」机检的就是渠道数,
只问一家过不了门(型号那列你先填,供应商与价格留给采购)。
**rows 必须有行**:一条料一行,不知道的值给空字符串(界面自己标红「待填写」)。
只给 cols 不给 rows,人看到的是一排表头加一片空白,一个格子都填不了(实测栽过)。
**blocks 少了整张卡就废了** —— 基座会用当下局面兜底成一句「需要你判断下一步」,
人拿到一张没有表的空卡,这一步等于没派(实测栽过)。
doneWhen:
'quote_sourcing_quote_list_missing = 0 and quote_sourcing_quote_list_price_basis_hist + quote_sourcing_quote_list_price_basis_sourced = quote_sourcing_quote_list_rows and route_decided_total > 0',
guide: `PRM 补回来了,现在把清单**定盘**,一拍连做:
**rows 一条料一行**,型号那一列先填上;ask 说清什么场景、要几家、什么时候要;
basis 摆上型号、数量、目标价、交期要求(**裸卡基座拒发**)。
① **价源归档**:PRM 补了价的行(price_basis 还空着的),逐行写 price_basis = **SOURCED**
(大写,一个字母不许差);A 类预填的行已是 HIST,不动。
按 rfq_ref + pn 对行,主键一个字符不许改。
② 若还有行缺底价(他留空又没撤):照他备注的说明办 —— 写明剔除的用 \`drop\`
把那一行撤出本单草稿(主键照 \`_keys\` 名单**原样粘**),撤了哪几颗、为什么写进
verdict.summary,并把 quote_line_total 与 pending_total 改成撤后的实数;
什么说明都没有的,发一张**决策卡(decide)**问负责人「这几颗问不到价,剔出本轮还是退回」,
照答复办。**只问这一次**。
③ 写 verdict:**route_decided_total 记 1**、summary 一句人话
(几行历史价、几行货源价、剔了几颗、整份可交定价)。
④ finish 这一项。引擎按「每行有价 + 价源守恒 + 定盘记过」收步,三样有一样不齐都收不掉。
他提交后回传值进你的轨迹:表格的键是 **table:0 / table:1**,值是整张表的 JSON,
**第一行是列名**。照它 write 进两张台账,并把比价表条数记进 compare_total。
**同一拍再写一行 \`quote_sourcing.verdict\`**(验收机检读的就是它):
· supplier_total = 询了几家渠道(判据要 ≥2,**只问一家过不了门**);
· quoted_total / unquoted_total = 已回价 / 未回价条数(未回价要 = 0);
· compare_total = 比价表条数;recommend_supplier 推荐哪家;summary 一句人话结论。
这几个数写不对,submit 会被门挡回来 —— **它们不是台账装饰,是判据本身**。
**写完就 finish,别再发第二张单** —— 他已经答过了。
**每一行都要带 \`rfq_ref\`** —— 它是这一单的单标识(起单入参里就有,原样抄进去)。
台账主键第一列就是它:不写,这一行会和**别的单**同料号的那一行撞主键,把人家覆盖掉
(实测栽过:A4 的报价草案主键只有 pn,跑四轮只剩最后一轮的 3 行)。`,
这一单只有一个出口(交成本定价),**没有去向要选** —— 定盘就是把账写齐。`,
},
{
item: 'T_release',
intent: '比价结论已齐,提交放行交 BD 验收',
view: 'sourcing-roster',
intent: '清单已定盘,提交放行交 PRM 验收',
writes: [],
reads: [],
tools: [],
guide: `比价表有行了 —— **先 start T_release**(它标了人工激活),然后 submit,BD 验收。
/* 放行触达世界,必须人按一下 —— 引擎不自动收它(剧本里也不给 doneWhen) */
guide: `每行有价、价源守恒、定盘已记 —— 可以走放行了(T_release 人工激活:
动它就算启动,不必单发 start)。先把裁量判据裁掉,然后 submit,同一拍连做:
· judge criterion="货源与价格来源可核:B 类行的供应商与底价来自真实询价或可靠渠道,PRM 对报价负责" ——
看清单里 SOURCED 行的供应商与备注:说得出来源就 satisfied=true;
有行说不出的,satisfied=**false**,rationale 逐行写清,交签字的人定。
**裁成不满足照样能提交** —— 理由连着卡一起交给他。
criterion 照判据名**整句原样抄**,写别的名字对不上。
终局唯放行:你不能自己宣布完成。`,
},
];
/**
* 阶段 —— 进度条的刻度,只给人看。除放行外每个计划项恰属一个阶段;
* 放行那一格由基座统一加,人看到的是 x/4。
*/
export const SOURCING_PHASES = [
{ name: '归一预填', items: ['S1_normalize'] },
{ name: '补货源价', items: ['S2_fill'] },
{ name: '汇稿定盘', items: ['S3_compile'] },
];