@tea-agent/loop-agent 0.44.0-next.7 → 0.44.0-next.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/executors/dag-pi/guards.js +4 -0
  4. package/dist/executors/dag-pi/model-config.js +30 -0
  5. package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +25 -41
  6. package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
  7. package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
  8. package/dist/executors/dag-pi/tools/design-terminal-tools.js +156 -0
  9. package/dist/executors/dag-pi/tools/plan-decision-tools.js +519 -0
  10. package/dist/executors/dag-pi/tools/review-terminal-tools.js +156 -0
  11. package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
  12. package/dist/executors/dag-pi-executor.js +64 -1907
  13. package/dist/task/frontend-preflight.js +1 -1
  14. package/dist/task/source-prepare/semantic-intake.js +1 -1
  15. package/dist/task/source-prepare/source-fidelity-pi.js +1 -1
  16. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-DTuku_-7.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
  17. package/dist/worker/console/static/assets/{arc-CQbCsSqb.js → arc-dT5T4sVL.js} +1 -1
  18. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C-xUntTR.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
  19. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-DhNlwGAl.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
  20. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B7j3nx8o.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
  21. package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
  22. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-BCrcxEh2.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
  23. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CsaePDb3.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
  24. package/dist/worker/console/static/assets/{chunk-5RXB4S5H--SRQc1rN.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
  25. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C5BFY2Po.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
  26. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Caso6uN7.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
  27. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-AY2ZSAx2.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
  28. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-DiMqZQ_8.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
  29. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-gpvvriOp.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
  30. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CUdyoJhI.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
  31. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Bp1xW3T4.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
  32. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
  33. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
  34. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-D-JIcOIT.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
  35. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-C-NKFflx.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
  36. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-CSOcvOAA.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
  37. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BQSBltMy.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
  38. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B0LVC45G.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
  39. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Cypg3nqy.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
  40. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-BBDU88XJ.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
  41. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BZusLqSb.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
  42. package/dist/worker/console/static/assets/{diagram-UB23O5K3-Cfolotcr.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
  43. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CjfyUy0m.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
  44. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DJdz7txE.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
  45. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CQqgPO6y.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
  46. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-BOpGfS2m.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
  47. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-C6UCu0qx.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
  48. package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
  49. package/dist/worker/console/static/assets/{index-DWKejNVJ.js → index-CTMZsDmh.js} +98 -98
  50. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BWeaVEUB.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
  51. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-C8gmlBbk.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
  52. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DF3bm8Bp.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
  53. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-D2fG2Vxi.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
  54. package/dist/worker/console/static/assets/{linear-BGKgMc2T.js → linear-DGRlieMH.js} +1 -1
  55. package/dist/worker/console/static/assets/{mermaid.core-DF6mMPJ9.js → mermaid.core-4P9yPC9c.js} +5 -5
  56. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-AMhePheC.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
  57. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-DN1Cl0W0.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
  58. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-Cx9ngUeN.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
  59. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-BcYPTQJb.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
  60. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BqHUZWnH.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
  61. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CmqWZ0-B.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
  62. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P--4YetH1y.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
  63. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DGD4VMfD.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
  64. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-QVw9q7rh.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
  65. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-CuemV9pe.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
  66. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
  67. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-C7oKzZKs.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
  68. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
  69. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-C2Of60nT.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
  70. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DHtpQHyL.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
  71. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-COi9OhSy.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
  72. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-DPHQfRrt.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
  73. package/dist/worker/console/static/index.html +2 -2
  74. package/package.json +1 -1
  75. package/dist/worker/console/static/assets/channel-5_os7t_x.js +0 -1
  76. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-loz0n18W.js +0 -1
  77. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-loz0n18W.js +0 -1
  78. package/dist/worker/console/static/assets/index-CUT440A8.css +0 -1
  79. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BdlGdIJw.js +0 -1
  80. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DjjbHbde.js +0 -8
package/CHANGELOG.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  ### 新增
6
6
 
7
+ - main 上的 npm `next` 预发布改为跑默认测试(fast + integration),不再在每次发布时重复跑约 6 分钟的 I/O-heavy 池;完整三池仍由 PR、正式 release 线、本地推送前检查与发布前钩子承担。同时把该预发布任务的 I/O 并发从 1 调到 2,并把 npm 包可见性确认的等待窗口从约 3 分钟拉长到约 10 分钟,避免包已发出却因仓库异步处理未完成而被判失败。
8
+
7
9
  - 修复 main 分支的 next 发布链在类型检查阶段内存溢出失败的问题:完整源码与测试的类型图已超过 Node 默认约 2 GiB 堆上限,类型检查进程因此中止(exit 134),导致 `next` 发布无法完成。此前该上限只在部分验证入口生效,其余入口直接运行类型检查就会因默认堆不足而失败;现把上限固化到类型检查命令本身,各验证入口与本地开发统一生效,不再依赖各入口自行声明。
8
10
  - 数据库连接支持断线自动重连:MySQL/PostgreSQL 空闲会话被服务端超时杀掉后,下一次查询会用同一配置透明重开连接并重试一次,不再需要手动重连或重启 Console;MySQL 适配器同时吸收服务端主动断开产生的异步错误,避免未处理错误事件影响进程。
9
11
 
@@ -38,6 +40,7 @@
38
40
 
39
41
  ### 改进
40
42
 
43
+ - Operator Chat 输入框下方的会话统计对齐 DSH:长串静态文字收敛为两个可点击摘要,可分别查看模型/工具用时、TTFT、TPS 与 Token 分项;详情卡互斥并支持外部点击或 Escape 关闭,窄屏打开时不会推动输入框或消息流。
41
44
  - Operator Chat 长会话新增完整轮次轨道与按需历史定位,可从任意用户消息精确新建会话;历史图片刷新后仍可预览,仓库文件链接可直接定位到行,最终回答显示单轮 token/耗时,并支持可持久化的紧凑/完整阅读模式。图片文件与消息记录分离保存,删除、分叉和失败回滚会同步清理,附件读取重新校验类型与引用。
42
45
  - 本地分支合并默认只执行与影响面匹配的定向测试、类型检查、构建和治理检查;完整测试推迟到 push 或完整交付前,并通过 receipt、`verify:tree` 或 pre-push 在最终 tree 上只执行一次。发布与推送门禁仍包含 I/O-heavy 测试。
43
46
  - Operator Chat 重新整理消息时间线:思考、工具、重试、命令和回答按实际顺序展示,工具调用不再被误标为“未识别事件”,未知事件只显示简短摘要。
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.44.0-next.7",
4
- "gitSha": "561015cd071b2aba74c823716703e756d2236929",
5
- "builtAt": "2026-09-16T18:31:45.598Z"
3
+ "version": "0.44.0-next.8",
4
+ "gitSha": "e100bbbeba403ae8cbe6c9a93ccce76cbadf434e",
5
+ "builtAt": "2026-09-16T23:48:41.706Z"
6
6
  }
@@ -0,0 +1,4 @@
1
+ /** DAG Pi 共享类型守卫:纯叶子模块,零依赖,禁止反向依赖执行器入口。 */
2
+ export function isRecordObject(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
@@ -0,0 +1,30 @@
1
+ /** DAG Pi 模型引用解析:纯配置叶子模块,零依赖,禁止反向依赖执行器入口。 */
2
+ export const DEFAULT_DAG_PI_PROVIDER = "wizard-local";
3
+ export const DAG_PI_MODEL_PROVIDERS = {
4
+ "gpt-5.3-codex-spark": "wizard-local",
5
+ "gpt-5.5": "wizard-local",
6
+ "glm-5.2": "wizard-local",
7
+ "deepseek-v4-flash": "deepseek",
8
+ "deepseek-v4-pro": "deepseek",
9
+ };
10
+ export function resolveDagPiModelConfig(modelReference, options) {
11
+ const separatorIndex = modelReference.indexOf("/");
12
+ const qualified = separatorIndex >= 0;
13
+ const provider = qualified
14
+ ? modelReference.slice(0, separatorIndex)
15
+ : (DAG_PI_MODEL_PROVIDERS[modelReference] ?? DEFAULT_DAG_PI_PROVIDER);
16
+ const model = qualified
17
+ ? modelReference.slice(separatorIndex + 1)
18
+ : modelReference;
19
+ if (!provider || !model) {
20
+ throw new Error(`invalid DAG Pi model reference "${modelReference}": expected non-empty provider/model`);
21
+ }
22
+ const explicitThinking = options?.thinking?.trim();
23
+ const thinking = explicitThinking ??
24
+ (provider === "wizard-local" && model === "gpt-5.5" ? "low" : undefined);
25
+ return {
26
+ provider,
27
+ model,
28
+ ...(thinking ? { thinking } : {}),
29
+ };
30
+ }
@@ -1,14 +1,5 @@
1
- import { collectCanonicalStateFlowNames } from "./frontend-contract-facts.js";
2
- export function enrichFrontendPlanMissingFacts(missing) {
3
- return missing.map((item) => ({
4
- ...item,
5
- owner: "Plan",
6
- repairScope: item.kind === "state-registry" || item.kind === "mock-api"
7
- ? "global-phase"
8
- : item.requirementIds.length > 1 ? "requirement-slice" : "fact",
9
- nextAction: "replace-fact-and-finalize",
10
- }));
11
- }
1
+ /** DAG Pi plan ledger 完整性事实计算:纯类型与纯函数,禁止反向依赖执行器入口。 */
2
+ import { collectCanonicalStateFlowNames } from "../../../workflows/dag/frontend-contract-facts.js";
12
3
  export function committedFactFromPlanRecord(value) {
13
4
  if (!value || typeof value !== "object" || Array.isArray(value))
14
5
  return undefined;
@@ -76,9 +67,16 @@ export function collectFrontendPlanMissingFacts(input) {
76
67
  });
77
68
  continue;
78
69
  }
79
- const targetIds = Array.isArray(entry.verificationTargetIds)
70
+ // Verification targets are the single authoritative direction. The
71
+ // legacy requirement-side list is accepted only as a fallback while
72
+ // resuming older ledgers; new plans derive it from target.requirementIds.
73
+ const derivedTargetIds = [...verificationTargetRequirements.entries()]
74
+ .filter(([, requirementIds]) => requirementIds.has(id))
75
+ .map(([targetId]) => targetId);
76
+ const legacyTargetIds = Array.isArray(entry.verificationTargetIds)
80
77
  ? entry.verificationTargetIds.filter((value) => typeof value === "string" && value.trim().length > 0)
81
78
  : [];
79
+ const targetIds = derivedTargetIds.length > 0 ? derivedTargetIds : legacyTargetIds;
82
80
  const gap = entry.evidenceGap && typeof entry.evidenceGap === "object"
83
81
  ? entry.evidenceGap
84
82
  : undefined;
@@ -104,7 +102,7 @@ export function collectFrontendPlanMissingFacts(input) {
104
102
  }
105
103
  }
106
104
  }
107
- return enrichFrontendPlanMissingFacts(missing);
105
+ return missing;
108
106
  }
109
107
  /** Completeness checks for phases whose facts are committed incrementally. */
110
108
  export function collectFrontendPlanPhaseMissingFacts(input) {
@@ -123,54 +121,40 @@ export function collectFrontendPlanPhaseMissingFacts(input) {
123
121
  ];
124
122
  }
125
123
  if (input.phase === "ux-local") {
126
- // One snapshot per check: no cross-revision cache to invalidate.
127
- const required = new Set(input.behaviorRequiredRequirementIds ?? []);
128
- const requested = new Set(input.requirementIds.filter(id => required.has(id)));
129
- if (!requested.size)
130
- return [];
131
- const byRequirement = new Map();
132
- for (const fact of facts) {
133
- for (const id of new Set(planFactStringList(fact.scopeRequirementIds))) {
134
- if (!requested.has(id))
135
- continue;
136
- const entries = byRequirement.get(id) ?? [];
137
- entries.push(fact);
138
- byRequirement.set(id, entries);
139
- }
140
- }
141
- const liveStateFlow = collectCanonicalStateFlowNames(facts);
142
124
  const missing = [];
143
- for (const id of input.requirementIds) {
144
- if (!required.has(id))
125
+ // Evaluate each behaviour requirement independently. A fact scoped to AC-1
126
+ // must not accidentally satisfy AC-2 merely because both ids share one
127
+ // UX session; shared facts remain valid when they explicitly list both ids.
128
+ for (const requirementId of input.requirementIds) {
129
+ if (!input.behaviorRequiredRequirementIds?.includes(requirementId))
145
130
  continue;
146
- const scopedFacts = byRequirement.get(id) ?? [];
131
+ const scopedFacts = facts.filter((fact) => planFactScopeIntersects(fact, new Set([requirementId])));
147
132
  const hasChoice = scopedFacts.some((fact) => fact.kind === "component-choice" &&
148
133
  Array.isArray(fact.uiComponentChoices) &&
149
134
  fact.uiComponentChoices.length > 0);
150
135
  const canonicalStateFlow = collectCanonicalStateFlowNames(scopedFacts);
151
- const hasStateFlow = [...canonicalStateFlow.uiStateNames].some(name => liveStateFlow.uiStateNames.has(name)) ||
152
- [...canonicalStateFlow.interactionNames].some(name => liveStateFlow.interactionNames.has(name));
136
+ const hasStateFlow = canonicalStateFlow.uiStateNames.size > 0 ||
137
+ canonicalStateFlow.interactionNames.size > 0;
153
138
  if (!hasChoice) {
154
139
  missing.push({
155
140
  kind: "component-choice",
156
- requirementIds: [id],
141
+ requirementIds: [requirementId],
157
142
  reason: "behaviour-required UX slice has no committed component-choice fact",
158
143
  });
159
144
  }
160
145
  if (!hasStateFlow) {
161
146
  missing.push({
162
147
  kind: "state-flow",
163
- requirementIds: [id],
148
+ requirementIds: [requirementId],
164
149
  reason: "behaviour-required UX slice has no committed state-flow fact",
165
150
  });
166
151
  }
167
152
  }
168
- return enrichFrontendPlanMissingFacts(missing);
153
+ return missing;
169
154
  }
170
155
  const hasMockApi = facts.some((fact) => fact.kind === "mock-api");
171
- const allInteractions = collectCanonicalStateFlowNames(facts).interactionNames;
172
- const requested = new Set(input.requirementIds);
173
- const liveInteractions = new Set([...collectCanonicalStateFlowNames(facts.filter(f => !planFactStringList(f.scopeRequirementIds).length || planFactScopeIntersects(f, requested))).interactionNames].filter(name => allInteractions.has(name)));
156
+ const allInteractions = collectCanonicalStateFlowNames(input.committedFacts).interactionNames;
157
+ const liveInteractions = new Set([...collectCanonicalStateFlowNames(facts.filter(f => !planFactStringList(f.scopeRequirementIds).length || planFactScopeIntersects(f, new Set(input.requirementIds)))).interactionNames].filter(name => allInteractions.has(name)));
174
158
  const coveredInteractions = new Set(facts
175
159
  .filter((fact) => fact.kind === "data-flow")
176
160
  .flatMap((fact) => planFactStringList(fact.interactions)));
@@ -192,5 +176,5 @@ export function collectFrontendPlanPhaseMissingFacts(input) {
192
176
  reason: `interaction ${interaction} has no committed data-flow fact`,
193
177
  });
194
178
  }
195
- return enrichFrontendPlanMissingFacts(missing);
179
+ return missing;
196
180
  }
@@ -0,0 +1,55 @@
1
+ /** DAG Pi plan ledger 契约与来源继承装载:纯类型与纯函数,禁止反向依赖执行器入口。 */
2
+ import path from "node:path";
3
+ import { frontendExecutionSchema } from "../../../workflows/dag/frontend-execution-groups.js";
4
+ /**
5
+ * Source fidelity ledger (AC-005/AC-006): load the contract node's committed
6
+ * requirement facts and build a requirement-id → provenance map. The contract
7
+ * node declared sourceFragmentIds/sourceRefs from the ledger's
8
+ * requirement→fragment mapping; the plan inherits them by id so the compiled
9
+ * canonical contract carries authoritative provenance without the plan
10
+ * re-deriving (or fabricating) it. Best-effort: missing/unreadable contract
11
+ * ledger yields an empty map and the plan compiles as before (the design
12
+ * policy shell will then fail closed on missing provenance).
13
+ */
14
+ export async function loadContractRequirementInheritance(runDir) {
15
+ const { readTypedEventStoreFromJsonl } = await import("../../../workflows/dag/frontend-typed-event-store.js");
16
+ let records;
17
+ try {
18
+ records = await readTypedEventStoreFromJsonl(path.join(runDir, "frontend-contract-pi", "contract-typed-facts.jsonl"));
19
+ }
20
+ catch {
21
+ return new Map();
22
+ }
23
+ const byId = new Map();
24
+ for (const record of records) {
25
+ const fact = record.fact;
26
+ if (!fact || typeof fact !== "object")
27
+ continue;
28
+ const recordFact = fact;
29
+ if (recordFact.origin !== "contract" ||
30
+ recordFact.kind !== "requirement") {
31
+ continue;
32
+ }
33
+ // Contract requirement facts carry id/sourceFragmentIds/sourceRefs on
34
+ // the fact itself (origin=contract, kind=requirement, id, text, ...),
35
+ // not inside an `entry` wrapper.
36
+ const id = typeof recordFact.id === "string" ? recordFact.id : "";
37
+ if (!id)
38
+ continue;
39
+ const sourceFragmentIds = Array.isArray(recordFact.sourceFragmentIds)
40
+ ? recordFact.sourceFragmentIds.filter((value) => typeof value === "string")
41
+ : undefined;
42
+ const sourceRefs = Array.isArray(recordFact.sourceRefs)
43
+ ? recordFact.sourceRefs.filter((value) => typeof value === "string")
44
+ : undefined;
45
+ if (sourceFragmentIds || sourceRefs) {
46
+ byId.set(id, {
47
+ ...(typeof recordFact.text === "string" ? { text: recordFact.text } : {}),
48
+ ...(recordFact.execution !== undefined ? { execution: frontendExecutionSchema.parse(recordFact.execution) } : {}),
49
+ ...(sourceFragmentIds ? { sourceFragmentIds } : {}),
50
+ ...(sourceRefs ? { sourceRefs } : {}),
51
+ });
52
+ }
53
+ }
54
+ return byId;
55
+ }