From 1721bcf6e32ef82b7a03c169deace779d7c0d2df Mon Sep 17 00:00:00 2001 From: 18628386721 <18628386721@163.com> Date: Mon, 27 Jul 2026 04:39:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE:=E5=BC=95=E6=93=8E=E4=BD=9C=E7=94=A8?= =?UTF-8?q?=E5=9F=9F=E4=B8=8D=E5=BE=97=E5=90=B8=E5=85=A5=E4=BB=96=E5=8D=95?= =?UTF-8?q?=E4=BA=8B=E5=AE=9E=20+=20=E8=AE=B0=E5=BD=95=20G2=20=E6=9C=AA?= =?UTF-8?q?=E5=88=86=E6=B5=81=E7=9A=84=E6=8E=92=E6=9F=A5=E7=BA=BF=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 任务视图铺到顶层的字段,原先取「该对象最新一行」—— 那一行很可能是**别的任务** 放行后的正式版记录。实测:NE555P 的打标读到了上一单 LM358DR 的情报 (historyDays 30 / 在产),被判成 Type A;修正后按自己的事实判成 Type B「重估后报」, 与 P-03 规则一致。 改为只铺**本任务自己写下的**草稿(读己之写),别人的事实仍在 `域.对象` 整表里、 要用得显式取。ledger 门面因此新增 `taskDrafts(taskId)` —— 与 `taskView` 的区别是 它只回我写过的那些行。 顺带记录:A1 已能 released 且节点实例正确落 terminal,但 G2 并行网关未起出 下游 A3 / A2;排查线索写进 PROGRESS.md 待办 1。 gates: tsc / eslint / depcruise(317 模块)/ 393 测试 全绿 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m --- .data/attachments/inbound/rfq-020@beta.com.eml | 12 ++++++++++++ .data/attachments/inbound/rfq-021@beta.com.eml | 12 ++++++++++++ .data/attachments/inbound/rfq-030@beta.com.eml | 12 ++++++++++++ apps/api/src/app/wiring/engines.ts | 14 ++++++++++---- apps/api/src/modules/ledger/contract.ts | 6 ++++++ .../ledger/internal/usecase/ledger-service.ts | 5 +++++ docs/PROGRESS.md | 7 ++++++- 7 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 .data/attachments/inbound/rfq-020@beta.com.eml create mode 100644 .data/attachments/inbound/rfq-021@beta.com.eml create mode 100644 .data/attachments/inbound/rfq-030@beta.com.eml diff --git a/.data/attachments/inbound/rfq-020@beta.com.eml b/.data/attachments/inbound/rfq-020@beta.com.eml new file mode 100644 index 0000000..f616782 --- /dev/null +++ b/.data/attachments/inbound/rfq-020@beta.com.eml @@ -0,0 +1,12 @@ +{ + "messageId": "rfq-020@beta.com", + "from": "buyer@beta.com", + "to": [ + "rfq@we.com" + ], + "cc": [], + "subject": "【询价】客户 C002 RFQ-20260727K 求报价", + "body": "客户编码 C002,询价单号 RFQ-20260727K。\nLM358DR TI 年用量 20000 目标价 7.90 交期 8w", + "receivedAt": "2026-07-27T11:00:00.000Z", + "attachments": [] +} \ No newline at end of file diff --git a/.data/attachments/inbound/rfq-021@beta.com.eml b/.data/attachments/inbound/rfq-021@beta.com.eml new file mode 100644 index 0000000..be8a038 --- /dev/null +++ b/.data/attachments/inbound/rfq-021@beta.com.eml @@ -0,0 +1,12 @@ +{ + "messageId": "rfq-021@beta.com", + "from": "buyer@beta.com", + "to": [ + "rfq@we.com" + ], + "cc": [], + "subject": "【询价】客户 C002 RFQ-20260727L 求报价", + "body": "客户编码 C002,询价单号 RFQ-20260727L。\nNE555P TI 年用量 6000 目标价 3.10 交期 12w", + "receivedAt": "2026-07-27T12:00:00.000Z", + "attachments": [] +} \ No newline at end of file diff --git a/.data/attachments/inbound/rfq-030@beta.com.eml b/.data/attachments/inbound/rfq-030@beta.com.eml new file mode 100644 index 0000000..5823a92 --- /dev/null +++ b/.data/attachments/inbound/rfq-030@beta.com.eml @@ -0,0 +1,12 @@ +{ + "messageId": "rfq-030@beta.com", + "from": "buyer@beta.com", + "to": [ + "rfq@we.com" + ], + "cc": [], + "subject": "【询价】客户 C003 RFQ-20260727M 求报价", + "body": "客户编码 C003,询价单号 RFQ-20260727M。\nNE555P TI 年用量 6000 目标价 3.10 交期 12w", + "receivedAt": "2026-07-27T13:00:00.000Z", + "attachments": [] +} \ No newline at end of file diff --git a/apps/api/src/app/wiring/engines.ts b/apps/api/src/app/wiring/engines.ts index 5500a5c..ffd2aa8 100644 --- a/apps/api/src/app/wiring/engines.ts +++ b/apps/api/src/app/wiring/engines.ts @@ -140,10 +140,16 @@ export function wireEngines(deps: EngineWiringDeps): EngineWiring { offset: 0, }); scope[`${address.domain}.${address.object}`] = page.rows; - const latest = page.rows[page.rows.length - 1]; - if (latest === undefined) continue; - for (const [field, value] of Object.entries(latest)) { - // 空值不盖掉已有事实:没写进去的字段不该把起单入参抹成 undefined + } + + /* + * 铺到顶层的只能是**这一单自己写下的**事实(草稿层 = 读己之写)。 + * 不能拿「该对象最新一行」来铺:那一行很可能是别的任务放行后的正式版记录, + * 一铺就把别人的结论当成了自己的输入 —— 打标会照着上一单的情报出结果。 + * 别人的事实仍在 `域.对象` 整表里,要用得显式去取。 + */ + for (const draft of await deps.ledger.taskDrafts(taskId)) { + for (const [field, value] of Object.entries({ ...draft.key, ...draft.patch })) { if (value !== null && value !== undefined) scope[field] = value; } } diff --git a/apps/api/src/modules/ledger/contract.ts b/apps/api/src/modules/ledger/contract.ts index d395fed..6573f84 100644 --- a/apps/api/src/modules/ledger/contract.ts +++ b/apps/api/src/modules/ledger/contract.ts @@ -90,6 +90,12 @@ export type LedgerService = { query(query: LedgerQuery): Promise; /** 任务视图 = 正式版 + 本任务草稿层 */ taskView(taskId: TaskId, query: LedgerQuery): Promise; + /** + * **本任务自己写的**草稿条目(读己之写的读面)。 + * 与 `taskView` 的区别:那个是「正式版 + 我的草稿」的合并视图, + * 这个只回我写过的那些行 —— 引擎求值要区分「这一单的事实」与「别人放行后的事实」。 + */ + taskDrafts(taskId: TaskId): Promise; patch: Record }>>; /** 落地预检第五项:数据冲突检查 */ checkConflicts(taskId: TaskId): Promise; discardDrafts(taskId: TaskId): Promise; diff --git a/apps/api/src/modules/ledger/internal/usecase/ledger-service.ts b/apps/api/src/modules/ledger/internal/usecase/ledger-service.ts index b182478..eef5c04 100644 --- a/apps/api/src/modules/ledger/internal/usecase/ledger-service.ts +++ b/apps/api/src/modules/ledger/internal/usecase/ledger-service.ts @@ -204,6 +204,11 @@ export function createLedgerService(deps: LedgerServiceDeps): LedgerService { return { rows, total: rows.length }; }, + async taskDrafts(taskId) { + const drafts = await deps.drafts.list(taskId); + return drafts.map((d) => ({ domain: d.domain, object: d.object, key: d.key, patch: d.patch })); + }, + async checkConflicts(taskId) { const drafts = await deps.drafts.list(taskId); if (drafts.length === 0) return []; diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 5567702..6957dc1 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -113,7 +113,12 @@ DMN 三分类规则 P-03 + 台账声明 + 样例集。depcruise 已实测拦下 ## 已知待办(按优先级) -1. **判据 ④–⑨ 逐节点端到端**:A1 释放后 G2 分流已具备条件,A3/A2(loop)、A4、AP、A6、A7 逐条跑。 +1. **判据 ④–⑨ 逐节点端到端**:A1 已能到 `released` 且节点实例正确落 `terminal`, + 但 **G2 并行网关未把下游 A3 / A2 起出来** —— 工作流停在 A1 之后。 + 已排除:投递无失败、无异常日志、`selectEdges` 对并行分叉返回全部出边、 + `dispatchOf` 对活动节点返回 start-task。下一步从 `advanceFrom` 的实际入参查起 + (`onTaskTerminal` 里 `Object.values(ports)[0]` 目前是 `{}`, + `outputPortsOf` 按输出口声明的属性名取值、与台账列名对不上,值得先看这里)。 2. **判据 ③ 的机器路径**:`JCAI_LLM_API_KEY` 现为占位符,LLM 步一律走声明给定的人兜底。 接任一 OpenAI 兼容端点即可验证机器路径;两条缝的 record/replay 也需先有一次 live 录制。 3. **编排画布的手绘编辑器**:只读态(`FlowDiagram`)已接真实流程包;