cool-workflow 0.1.98 → 0.2.1

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 (315) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +18 -7
  4. package/apps/architecture-review/app.json +2 -2
  5. package/apps/architecture-review/workflow.js +12 -12
  6. package/apps/architecture-review-fast/app.json +1 -1
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/cli/dispatch.js +236 -0
  12. package/dist/cli/entry.js +120 -0
  13. package/dist/cli/io.js +21 -4
  14. package/dist/cli/parseargv.js +157 -0
  15. package/dist/cli.js +6 -33
  16. package/dist/core/capability-table.js +3518 -0
  17. package/dist/core/format/help.js +314 -0
  18. package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
  19. package/dist/core/hash.js +137 -0
  20. package/dist/core/multi-agent/candidate-scoring.js +219 -0
  21. package/dist/core/multi-agent/collaboration.js +481 -0
  22. package/dist/core/multi-agent/coordinator.js +515 -0
  23. package/dist/core/multi-agent/eval-replay.js +306 -0
  24. package/dist/core/multi-agent/runtime.js +929 -0
  25. package/dist/core/multi-agent/topology.js +298 -0
  26. package/dist/core/multi-agent/trust-policy.js +197 -0
  27. package/dist/core/pipeline/commit-gate.js +320 -0
  28. package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
  29. package/dist/core/pipeline/dispatch.js +103 -0
  30. package/dist/core/pipeline/drive-decide.js +227 -0
  31. package/dist/core/pipeline/error-feedback.js +161 -0
  32. package/dist/core/pipeline/loop-expansion.js +124 -0
  33. package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
  34. package/dist/core/pipeline/runner.js +230 -0
  35. package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
  36. package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
  37. package/dist/core/state/node-projection.js +95 -0
  38. package/dist/core/state/node-snapshot.js +230 -0
  39. package/dist/core/state/run-paths.js +93 -0
  40. package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
  41. package/dist/core/state/schema.js +50 -0
  42. package/dist/core/state/state-explosion/digest.js +243 -0
  43. package/dist/core/state/state-explosion/graph.js +527 -0
  44. package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
  45. package/dist/core/state/state-explosion/report.js +187 -0
  46. package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
  47. package/dist/{state-node.js → core/state/state-node.js} +90 -113
  48. package/dist/core/state/types.js +19 -0
  49. package/dist/{validation.js → core/state/validation.js} +64 -131
  50. package/dist/core/trust/evidence-grounding.js +134 -0
  51. package/dist/core/trust/ledger.js +199 -0
  52. package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
  53. package/dist/core/trust/telemetry-ledger.js +127 -0
  54. package/dist/core/types.js +20 -0
  55. package/dist/core/version.js +16 -0
  56. package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
  57. package/dist/mcp/dispatch.js +104 -0
  58. package/dist/mcp/server.js +144 -0
  59. package/dist/mcp-server.js +6 -84
  60. package/dist/{agent-config.js → shell/agent-config.js} +118 -71
  61. package/dist/shell/app-run-cli.js +88 -0
  62. package/dist/shell/audit-cli.js +259 -0
  63. package/dist/shell/audit-provenance.js +83 -0
  64. package/dist/shell/candidate-scoring-io.js +459 -0
  65. package/dist/shell/collaboration-io.js +264 -0
  66. package/dist/shell/commit-summary.js +104 -0
  67. package/dist/shell/commit.js +290 -0
  68. package/dist/shell/coordinator-io.js +476 -0
  69. package/dist/shell/demo-cli.js +19 -0
  70. package/dist/shell/dispatch.js +162 -0
  71. package/dist/shell/doctor.js +292 -0
  72. package/dist/shell/drive.js +885 -0
  73. package/dist/shell/error-feedback-io.js +305 -0
  74. package/dist/shell/eval-io.js +473 -0
  75. package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
  76. package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
  77. package/dist/shell/exec-backend-cli.js +88 -0
  78. package/dist/shell/execution-backend/agent.js +507 -0
  79. package/dist/shell/execution-backend/ci.js +15 -0
  80. package/dist/shell/execution-backend/container.js +69 -0
  81. package/dist/shell/execution-backend/envelopes.js +55 -0
  82. package/dist/shell/execution-backend/local.js +113 -0
  83. package/dist/shell/execution-backend/probes.js +175 -0
  84. package/dist/shell/execution-backend/registry.js +402 -0
  85. package/dist/shell/execution-backend/remote.js +128 -0
  86. package/dist/shell/execution-backend/types.js +11 -0
  87. package/dist/shell/feedback-cli.js +81 -0
  88. package/dist/shell/feedback-operations.js +48 -0
  89. package/dist/shell/fs-atomic.js +276 -0
  90. package/dist/shell/harness.js +98 -0
  91. package/dist/shell/ledger-cli.js +212 -0
  92. package/dist/shell/ledger-io.js +169 -0
  93. package/dist/shell/man-cli.js +89 -0
  94. package/dist/shell/metrics-cli.js +100 -0
  95. package/dist/shell/multi-agent-cli.js +1002 -0
  96. package/dist/shell/multi-agent-host.js +563 -0
  97. package/dist/shell/multi-agent-io.js +387 -0
  98. package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
  99. package/dist/shell/node-store.js +124 -0
  100. package/dist/{observability/format.js → shell/observability-format.js} +7 -1
  101. package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
  102. package/dist/{observability.js → shell/observability.js} +159 -332
  103. package/dist/{onramp.js → shell/onramp.js} +11 -0
  104. package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
  105. package/dist/shell/operator-ux.js +431 -0
  106. package/dist/shell/orchestrator.js +231 -0
  107. package/dist/shell/pipeline-cli.js +667 -0
  108. package/dist/shell/pipeline.js +217 -0
  109. package/dist/shell/reclamation-io.js +1366 -0
  110. package/dist/shell/registry-cli.js +344 -0
  111. package/dist/{remote-source.js → shell/remote-source.js} +2 -2
  112. package/dist/shell/report-cli.js +101 -0
  113. package/dist/shell/report-view-cli.js +117 -0
  114. package/dist/{orchestrator → shell}/report.js +289 -282
  115. package/dist/shell/reporter.js +62 -0
  116. package/dist/shell/run-export-cli.js +106 -0
  117. package/dist/shell/run-export.js +680 -0
  118. package/dist/shell/run-registry-io.js +1014 -0
  119. package/dist/shell/run-store.js +164 -0
  120. package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
  121. package/dist/{scheduler.js → shell/scheduler-io.js} +257 -48
  122. package/dist/shell/scheduling-io.js +321 -0
  123. package/dist/shell/state-cli.js +181 -0
  124. package/dist/shell/state-explosion-cli.js +197 -0
  125. package/dist/shell/telemetry-cli.js +85 -0
  126. package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
  127. package/dist/shell/telemetry-ledger-io.js +132 -0
  128. package/dist/{term.js → shell/term.js} +36 -46
  129. package/dist/shell/topology-io.js +361 -0
  130. package/dist/shell/trust-audit.js +472 -0
  131. package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
  132. package/dist/shell/verifier.js +48 -0
  133. package/dist/shell/workbench-host.js +258 -0
  134. package/dist/shell/workbench-text.js +18 -0
  135. package/dist/shell/workbench.js +170 -0
  136. package/dist/shell/worker-cli.js +124 -0
  137. package/dist/shell/worker-isolation.js +852 -0
  138. package/dist/shell/workflow-app-loader.js +650 -0
  139. package/docs/agent-delegation-drive.7.md +4 -0
  140. package/docs/cli-mcp-parity.7.md +282 -219
  141. package/docs/contract-migration-tooling.7.md +4 -0
  142. package/docs/control-plane-scheduling.7.md +4 -0
  143. package/docs/durable-state-and-locking.7.md +4 -0
  144. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  145. package/docs/execution-backends.7.md +4 -0
  146. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  147. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  148. package/docs/multi-agent-operator-ux.7.md +4 -0
  149. package/docs/node-snapshot-diff-replay.7.md +4 -0
  150. package/docs/observability-cost-accounting.7.md +6 -1
  151. package/docs/project-index.md +137 -71
  152. package/docs/real-execution-backends.7.md +4 -0
  153. package/docs/release-and-migration.7.md +4 -0
  154. package/docs/release-tooling.7.md +4 -0
  155. package/docs/remote-source-review.7.md +4 -4
  156. package/docs/report-verifiable-bundle.7.md +1 -1
  157. package/docs/run-registry-control-plane.7.md +4 -0
  158. package/docs/run-retention-reclamation.7.md +25 -0
  159. package/docs/security-trust-hardening.7.md +3 -1
  160. package/docs/state-explosion-management.7.md +4 -0
  161. package/docs/team-collaboration.7.md +4 -0
  162. package/docs/web-desktop-workbench.7.md +15 -1
  163. package/manifest/plugin.manifest.json +1 -1
  164. package/manifest/source-context-profiles.json +9 -13
  165. package/package.json +1 -1
  166. package/scripts/agents/agent-adapter-core.js +22 -2
  167. package/scripts/agents/claude-p-agent.js +8 -3
  168. package/scripts/agents/cw-attest-wrap.js +2 -2
  169. package/scripts/agents/gemini-agent.js +5 -1
  170. package/scripts/agents/opencode-agent.js +5 -1
  171. package/scripts/bump-version.js +4 -3
  172. package/scripts/canonical-apps.js +4 -4
  173. package/scripts/dogfood-architecture-review.js +2 -3
  174. package/scripts/dogfood-release.js +3 -3
  175. package/scripts/gen-parity-doc.js +15 -2
  176. package/scripts/golden-path.js +4 -4
  177. package/scripts/onramp-check.js +1 -1
  178. package/scripts/parity-check.js +38 -21
  179. package/scripts/release-flow.js +2 -2
  180. package/scripts/sync-project-index.js +51 -27
  181. package/scripts/validate-run-state-schema.js +2 -2
  182. package/scripts/version-sync-check.js +30 -30
  183. package/dist/candidate-scoring.js +0 -729
  184. package/dist/capability-core.js +0 -1189
  185. package/dist/capability-registry.js +0 -885
  186. package/dist/cli/command-surface.js +0 -494
  187. package/dist/cli/format.js +0 -56
  188. package/dist/cli/handlers/audit.js +0 -82
  189. package/dist/cli/handlers/blackboard.js +0 -81
  190. package/dist/cli/handlers/candidate.js +0 -40
  191. package/dist/cli/handlers/clones.js +0 -34
  192. package/dist/cli/handlers/collaboration.js +0 -61
  193. package/dist/cli/handlers/eval.js +0 -40
  194. package/dist/cli/handlers/ledger.js +0 -169
  195. package/dist/cli/handlers/maintenance.js +0 -107
  196. package/dist/cli/handlers/multi-agent.js +0 -165
  197. package/dist/cli/handlers/node.js +0 -41
  198. package/dist/cli/handlers/operational.js +0 -155
  199. package/dist/cli/handlers/operator.js +0 -146
  200. package/dist/cli/handlers/registry.js +0 -68
  201. package/dist/cli/handlers/run.js +0 -153
  202. package/dist/cli/handlers/scheduling.js +0 -132
  203. package/dist/cli/handlers/workbench.js +0 -41
  204. package/dist/cli/handlers/worker.js +0 -45
  205. package/dist/cli/run-summary.js +0 -45
  206. package/dist/clones.js +0 -162
  207. package/dist/collaboration.js +0 -726
  208. package/dist/commit.js +0 -592
  209. package/dist/compare.js +0 -18
  210. package/dist/coordinator/classify.js +0 -45
  211. package/dist/coordinator/paths.js +0 -42
  212. package/dist/coordinator/util.js +0 -126
  213. package/dist/coordinator.js +0 -990
  214. package/dist/daemon.js +0 -44
  215. package/dist/dispatch.js +0 -250
  216. package/dist/doctor.js +0 -212
  217. package/dist/drive.js +0 -864
  218. package/dist/error-feedback.js +0 -419
  219. package/dist/evidence-grounding.js +0 -184
  220. package/dist/execution-backend/agent.js +0 -354
  221. package/dist/execution-backend/probes.js +0 -112
  222. package/dist/execution-backend/util.js +0 -47
  223. package/dist/execution-backend.js +0 -961
  224. package/dist/gates.js +0 -48
  225. package/dist/harness.js +0 -61
  226. package/dist/ledger.js +0 -313
  227. package/dist/loop-expansion.js +0 -60
  228. package/dist/mcp/tool-call.js +0 -470
  229. package/dist/mcp/tool-definitions.js +0 -1066
  230. package/dist/mcp-surface.js +0 -30
  231. package/dist/multi-agent/graph.js +0 -84
  232. package/dist/multi-agent/helpers.js +0 -141
  233. package/dist/multi-agent/ids.js +0 -20
  234. package/dist/multi-agent/paths.js +0 -22
  235. package/dist/multi-agent-eval/normalize.js +0 -51
  236. package/dist/multi-agent-eval.js +0 -678
  237. package/dist/multi-agent-host.js +0 -777
  238. package/dist/multi-agent.js +0 -984
  239. package/dist/node-projection.js +0 -59
  240. package/dist/node-snapshot.js +0 -260
  241. package/dist/operator-ux.js +0 -631
  242. package/dist/orchestrator/app-operations.js +0 -211
  243. package/dist/orchestrator/audit-operations.js +0 -182
  244. package/dist/orchestrator/candidate-operations.js +0 -117
  245. package/dist/orchestrator/cli-options.js +0 -294
  246. package/dist/orchestrator/collaboration-operations.js +0 -86
  247. package/dist/orchestrator/feedback-operations.js +0 -81
  248. package/dist/orchestrator/host-operations.js +0 -78
  249. package/dist/orchestrator/lifecycle-operations.js +0 -650
  250. package/dist/orchestrator/migration-operations.js +0 -44
  251. package/dist/orchestrator/multi-agent-operations.js +0 -362
  252. package/dist/orchestrator/topology-operations.js +0 -84
  253. package/dist/orchestrator.js +0 -925
  254. package/dist/pipeline-runner.js +0 -285
  255. package/dist/reclamation/hash.js +0 -72
  256. package/dist/reclamation.js +0 -812
  257. package/dist/reporter.js +0 -67
  258. package/dist/run-export.js +0 -815
  259. package/dist/run-registry/derive.js +0 -175
  260. package/dist/run-registry/format.js +0 -124
  261. package/dist/run-registry/gc.js +0 -251
  262. package/dist/run-registry/policy.js +0 -16
  263. package/dist/run-registry/queue.js +0 -115
  264. package/dist/run-registry.js +0 -850
  265. package/dist/run-state-schema.js +0 -68
  266. package/dist/scheduling.js +0 -184
  267. package/dist/state-explosion.js +0 -1014
  268. package/dist/state.js +0 -367
  269. package/dist/telemetry-ledger.js +0 -196
  270. package/dist/topology.js +0 -565
  271. package/dist/triggers.js +0 -184
  272. package/dist/trust-audit.js +0 -644
  273. package/dist/types/blackboard.js +0 -2
  274. package/dist/types/candidate.js +0 -2
  275. package/dist/types/collaboration.js +0 -2
  276. package/dist/types/core.js +0 -2
  277. package/dist/types/drive.js +0 -10
  278. package/dist/types/error-feedback.js +0 -2
  279. package/dist/types/evidence-reasoning.js +0 -2
  280. package/dist/types/execution-backend.js +0 -2
  281. package/dist/types/multi-agent.js +0 -2
  282. package/dist/types/observability.js +0 -2
  283. package/dist/types/pipeline.js +0 -2
  284. package/dist/types/reclamation.js +0 -8
  285. package/dist/types/report-bundle.js +0 -6
  286. package/dist/types/result.js +0 -2
  287. package/dist/types/run-registry.js +0 -2
  288. package/dist/types/run.js +0 -2
  289. package/dist/types/sandbox.js +0 -2
  290. package/dist/types/schedule.js +0 -2
  291. package/dist/types/state-node.js +0 -2
  292. package/dist/types/topology.js +0 -2
  293. package/dist/types/trust.js +0 -2
  294. package/dist/types/workbench.js +0 -2
  295. package/dist/types/worker.js +0 -2
  296. package/dist/types/workflow-app.js +0 -2
  297. package/dist/types.js +0 -44
  298. package/dist/util/fingerprint.js +0 -19
  299. package/dist/util/fingerprint.test.js +0 -27
  300. package/dist/verifier.js +0 -78
  301. package/dist/version.js +0 -8
  302. package/dist/workbench-host.js +0 -192
  303. package/dist/workbench.js +0 -192
  304. package/dist/worker-accept/acceptance.js +0 -114
  305. package/dist/worker-accept/blackboard-fanout.js +0 -80
  306. package/dist/worker-accept/blackboard-linkage.js +0 -19
  307. package/dist/worker-accept/context.js +0 -2
  308. package/dist/worker-accept/telemetry-ledger.js +0 -126
  309. package/dist/worker-accept/validation.js +0 -77
  310. package/dist/worker-accept/verifier-completion.js +0 -73
  311. package/dist/worker-isolation/helpers.js +0 -51
  312. package/dist/worker-isolation/paths.js +0 -46
  313. package/dist/worker-isolation.js +0 -656
  314. package/dist/workflow-api.js +0 -131
  315. /package/dist/{types → core/types}/boundary.js +0 -0
@@ -1,218 +1,183 @@
1
1
  "use strict";
2
- // Report rendering for workflow runs extracted from orchestrator.ts.
2
+ // shell/report.ts report.md generation (the byte-exact section
3
+ // headers/fallback lines from the spec), the actual file write.
3
4
  //
4
- // Pure projection of a WorkflowRun into the human-readable run report and the
5
- // RunSummary view model. No orchestration state, no I/O beyond writing the
6
- // report file. The orchestrator re-imports the two public entry points
7
- // (writeReport, summarizeRun); every render*/format* helper here is private.
8
- var __importDefault = (this && this.__importDefault) || function (mod) {
9
- return (mod && mod.__esModule) ? mod : { "default": mod };
10
- };
5
+ // MILESTONE 6+7 (combined), EXTENDED at MILESTONE 11 (reporting/
6
+ // observability) with the four sections that were deferred while their
7
+ // own subsystems' milestones (8/9/4) had not yet landed: State Size &
8
+ // Compaction (state-explosion, milestone 4), Sandbox Profiles (milestone
9
+ // 5), Trust Audit (milestone 8), Acceptance Rationale (commit-gate,
10
+ // milestone 6+7). Byte-exact port of
11
+ // plugins/cool-workflow/src/orchestrator/report.ts's renderX helpers for
12
+ // each.
13
+ //
14
+ // Evidence: SPEC/reporting-ux.md "report.md (written by writeReport)";
15
+ // plugins/cool-workflow/src/orchestrator/report.ts:1-397 (byte-exact
16
+ // source).
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
11
50
  Object.defineProperty(exports, "__esModule", { value: true });
12
51
  exports.writeReport = writeReport;
13
- exports.summarizeRun = summarizeRun;
14
- const node_fs_1 = __importDefault(require("node:fs"));
15
- const dispatch_1 = require("../dispatch");
16
- const worker_isolation_1 = require("../worker-isolation");
17
- const candidate_scoring_1 = require("../candidate-scoring");
18
- const error_feedback_1 = require("../error-feedback");
19
- const multi_agent_1 = require("../multi-agent");
20
- const coordinator_1 = require("../coordinator");
21
- const trust_audit_1 = require("../trust-audit");
22
- const telemetry_ledger_1 = require("../telemetry-ledger");
23
- const state_explosion_1 = require("../state-explosion");
24
- function writeReport(run) {
25
- (0, dispatch_1.updatePhaseStatuses)(run);
26
- const workerSummary = (0, worker_isolation_1.summarizeWorkers)(run);
27
- const candidateSummary = (0, candidate_scoring_1.summarizeCandidates)(run);
28
- // A research run reads a local folder of files, not a code repo — label its source line
29
- // "Source". Skip the relabel when the run ALSO carries a remote-provenance "- Source: <url>"
30
- // line below (run.inputs.sourceUrl set by a --link/URL), so a report never shows two
31
- // "- Source:" lines. Every other app keeps the byte-identical "Repository:" (POLA).
32
- const sourceLabel = run.workflow.app?.metadata?.domain === "research" && !run.inputs.sourceUrl ? "Source" : "Repository";
33
- const report = [
34
- `# ${run.workflow.title}`,
35
- "",
36
- `- Run: ${run.id}`,
37
- `- Workflow: ${run.workflow.id}`,
38
- ...(run.workflow.app
39
- ? [
40
- `- Workflow App: ${run.workflow.app.id}@${run.workflow.app.version}`,
41
- `- Workflow App Source: ${run.workflow.app.source?.manifestPath || run.workflow.app.source?.entrypointPath || run.workflow.app.source?.path || ""}`
42
- ]
43
- : []),
44
- `- Created: ${run.createdAt}`,
45
- `- Updated: ${run.updatedAt}`,
46
- `- ${sourceLabel}: ${String(run.inputs.repo || run.cwd)}`,
47
- // Remote provenance (v0.1.91): when the repo was materialized from a --link/URL, record
48
- // the sanitized origin + resolved commit so the report itself says where the code came
49
- // from. Conditional — absent for a local-repo run, so existing reports stay byte-identical.
50
- ...(run.inputs.sourceUrl
51
- ? [`- Source: ${String(run.inputs.sourceUrl)}${run.inputs.sourceCommit ? `@${String(run.inputs.sourceCommit)}` : ""}`]
52
- : []),
53
- `- Question: ${String(run.inputs.question || "")}`,
54
- `- Invariants: ${formatInputList(run.inputs.invariant)}`,
55
- `- Loop Stage: ${run.loopStage}`,
56
- "",
57
- "## Phase Status",
58
- "",
59
- "| Phase | Status | Completed | Total |",
60
- "| --- | --- | ---: | ---: |",
61
- ...run.phases.map((phase) => {
62
- const phaseTasks = run.tasks.filter((task) => phase.taskIds.includes(task.id));
63
- const completed = phaseTasks.filter((task) => task.status === "completed").length;
64
- return `| ${phase.name} | ${phase.status} | ${completed} | ${phaseTasks.length} |`;
65
- }),
66
- "",
67
- "## State Commits",
68
- "",
69
- ...renderCommits(run),
70
- "",
71
- "## Error Feedback",
72
- "",
73
- ...renderFeedback(run),
74
- "",
75
- "## Workers",
76
- "",
77
- ...renderWorkers(workerSummary),
78
- "",
79
- "## State Size & Compaction",
80
- "",
81
- ...renderStateSize(run),
82
- "",
83
- "## Multi-Agent Runtime",
84
- "",
85
- ...renderMultiAgent(run),
86
- "",
87
- "## Blackboard / Coordinator",
88
- "",
89
- ...renderBlackboard(run),
90
- "",
91
- "## Sandbox Profiles",
92
- "",
93
- ...renderSandboxProfiles(run),
94
- "",
95
- "## Trust Audit",
96
- "",
97
- ...renderTrustAudit(run),
98
- "",
99
- "## Acceptance Rationale",
100
- "",
101
- ...renderAcceptanceRationale(run),
102
- "",
103
- "## Candidates",
104
- "",
105
- ...renderCandidates(candidateSummary),
106
- "",
107
- "## Pending Tasks",
108
- "",
109
- ...renderPendingTasks(run),
110
- "",
111
- "## Results",
112
- "",
113
- ...renderResults(run)
114
- ].join("\n");
115
- node_fs_1.default.writeFileSync(run.paths.report, report, "utf8");
116
- return run.paths.report;
117
- }
118
- function summarizeRun(run) {
119
- (0, dispatch_1.updatePhaseStatuses)(run);
120
- const workerSummary = (0, worker_isolation_1.summarizeWorkers)(run);
121
- const createdAtMs = Date.parse(run.createdAt);
122
- const updatedAtMs = Date.parse(run.updatedAt);
123
- const durationMs = Number.isFinite(createdAtMs) && Number.isFinite(updatedAtMs) ? Math.max(0, updatedAtMs - createdAtMs) : undefined;
124
- return {
125
- runId: run.id,
126
- workflowId: run.workflow.id,
127
- app: run.workflow.app,
128
- phases: run.phases,
129
- tasks: {
130
- total: run.tasks.length,
131
- pending: run.tasks.filter((task) => task.status === "pending").length,
132
- running: run.tasks.filter((task) => task.status === "running").length,
133
- failed: run.tasks.filter((task) => task.status === "failed").length,
134
- completed: run.tasks.filter((task) => task.status === "completed").length
135
- },
136
- loopStage: run.loopStage,
137
- durationMs,
138
- progressPercent: run.tasks.length ? Math.round((run.tasks.filter((t) => t.status === "completed").length / run.tasks.length) * 100) : 0,
139
- next: (0, dispatch_1.firstRunnablePhase)(run)?.name || null,
140
- reportPath: run.paths.report,
141
- commits: run.commits,
142
- workers: {
143
- total: workerSummary.total,
144
- byStatus: workerSummary.byStatus
145
- }
146
- };
52
+ const fs = __importStar(require("node:fs"));
53
+ const dispatch_1 = require("../core/pipeline/dispatch");
54
+ const state_explosion_cli_1 = require("./state-explosion-cli");
55
+ const state_explosion_text_1 = require("../core/format/state-explosion-text");
56
+ const candidate_scoring_io_1 = require("./candidate-scoring-io");
57
+ const trust_audit_1 = require("./trust-audit");
58
+ const telemetry_ledger_io_1 = require("./telemetry-ledger-io");
59
+ const multi_agent_io_1 = require("./multi-agent-io");
60
+ const coordinator_io_1 = require("./coordinator-io");
61
+ const multi_agent_operator_ux_1 = require("./multi-agent-operator-ux");
62
+ function formatInputList(value) {
63
+ if (Array.isArray(value))
64
+ return value.join("; ");
65
+ return value ? String(value) : "";
147
66
  }
148
- function renderPendingTasks(run) {
149
- const pending = run.tasks.filter((task) => task.status === "pending" || task.status === "running");
150
- if (!pending.length)
151
- return ["No pending tasks."];
152
- return pending.map((task) => `- ${task.id} (${task.phase}, ${task.status}): ${task.taskPath}`);
67
+ function formatCounts(counts) {
68
+ const entries = Object.entries(counts).sort(([a], [b]) => a.localeCompare(b));
69
+ if (!entries.length)
70
+ return "none";
71
+ return entries.map(([k, v]) => `${k}=${v}`).join(", ");
153
72
  }
154
- function renderResults(run) {
155
- const completed = run.tasks.filter((task) => task.status === "completed");
156
- if (!completed.length)
157
- return ["No completed results yet."];
158
- const lines = [];
159
- for (const task of completed) {
160
- lines.push(`### ${task.id}`, "", `Result: ${task.resultPath}`, "");
161
- if (task.resultPath && node_fs_1.default.existsSync(task.resultPath)) {
162
- lines.push(node_fs_1.default.readFileSync(task.resultPath, "utf8").trim(), "");
163
- }
164
- else {
165
- lines.push("_Result file is not present on this host; state metadata remains inspectable._", "");
166
- }
73
+ function countBy(values, key) {
74
+ const counts = {};
75
+ for (const value of values) {
76
+ const bucket = key(value);
77
+ counts[bucket] = (counts[bucket] || 0) + 1;
167
78
  }
168
- return lines;
79
+ return counts;
169
80
  }
170
81
  function renderCommits(run) {
171
82
  if (!run.commits.length)
172
83
  return ["No state commits yet."];
173
84
  return run.commits.map((commit) => {
174
85
  const kind = commit.verifierGated ? "verifier-gated commit" : "checkpoint";
175
- const gate = commit.verifierGated ? formatCommitGate(commit) : "verifierGated=false";
86
+ const gate = commit.verifierGated ? `verifier=${commit.verifierNodeId || "unknown"}, evidence=${commit.evidence?.length || 0}` : "verifierGated=false";
176
87
  return `- ${commit.id}: ${commit.reason} [${commit.loopStage}; ${kind}; ${gate}] (${commit.snapshotPath})`;
177
88
  });
178
89
  }
179
- function renderFeedback(run) {
180
- const summary = (0, error_feedback_1.summarizeFeedback)(run);
181
- if (!summary.total)
182
- return ["No feedback records."];
90
+ /** `## State Size & Compaction` — milestone 4's state-explosion report,
91
+ * rendered with its own dedicated text formatter (always non-empty; no
92
+ * "no records" fallback in the old build either). */
93
+ function renderStateSize(run) {
94
+ const index = (0, state_explosion_cli_1.loadStateExplosionSummaryIndex)(run);
95
+ const report = (0, state_explosion_cli_1.buildStateExplosionReport)(run, { index, operator: (0, multi_agent_operator_ux_1.operatorDigestInput)(run) });
96
+ return (0, state_explosion_text_1.stateExplosionReportLines)(report);
97
+ }
98
+ /** `## Sandbox Profiles` — byte-exact port of the old build's
99
+ * renderSandboxProfiles (src/orchestrator/report.ts:277-287). */
100
+ function renderSandboxProfiles(run) {
101
+ const profiles = run.sandboxProfiles || [];
102
+ if (!profiles.length)
103
+ return ["No sandbox profiles selected yet."];
104
+ return profiles.map((profile) => [
105
+ `- ${profile.id}: read=${profile.readPaths.length}, write=${profile.writePaths.length}, execute=${profile.execute.mode}, network=${profile.network.mode}`,
106
+ ` enforcedByCW=${profile.enforcement.enforcedByCW.join("; ")}`,
107
+ ` hostRequired=${profile.enforcement.hostRequired.join("; ")}`,
108
+ ].join("\n"));
109
+ }
110
+ /** `## Trust Audit` — byte-exact port of the old build's renderTrustAudit
111
+ * + renderTelemetryAttestation (src/orchestrator/report.ts:301-355). */
112
+ function renderTrustAudit(run) {
113
+ const summary = (0, trust_audit_1.summarizeTrustAudit)(run);
114
+ const integrity = summary.integrity;
183
115
  return [
184
- `- Total: ${summary.total}`,
185
- `- By status: ${formatCounts(summary.byStatus)}`,
186
- `- By severity: ${formatCounts(summary.bySeverity)}`,
187
- `- By classification: ${formatCounts(summary.byClassification)}`,
188
- "",
189
- ...summary.artifacts.map((artifact) => `- ${artifact}`)
116
+ `- Events: ${summary.eventCount}`,
117
+ `- Chain integrity: ${integrity ? (integrity.verified ? "verified" : "FAILED") : "n/a"}` +
118
+ `${integrity ? ` (${integrity.chained} chained, ${integrity.unchained} legacy${integrity.corruptLines ? `, ${integrity.corruptLines} corrupt` : ""})` : ""}`,
119
+ ...(integrity && !integrity.verified
120
+ ? [` !! TRUST-AUDIT CHAIN TAMPER DETECTED: ${integrity.checks.filter((c) => !c.pass).map((c) => c.code).join(", ")}`]
121
+ : []),
122
+ `- Decisions: ${formatCounts(summary.byDecision)}`,
123
+ `- Sources: ${formatCounts(summary.bySource)}`,
124
+ `- Sandbox profiles: ${formatCounts(summary.bySandboxProfile)}`,
125
+ `- Event log: ${summary.eventLogPath}`,
126
+ `- Summary: ${summary.summaryPath}`,
127
+ `- Index: ${summary.indexPath}`,
128
+ ...renderTelemetryAttestation(run),
190
129
  ];
191
130
  }
192
- function renderWorkers(summary) {
193
- if (!summary.total)
194
- return ["No worker scopes yet."];
131
+ /** Telemetry attestation coverage + a LOUD list of any `unattested`
132
+ * usage, byte-exact port of the old build's renderTelemetryAttestation. */
133
+ function renderTelemetryAttestation(run) {
134
+ const delegations = (0, trust_audit_1.listTrustAuditEvents)(run).filter((event) => event.kind === "worker.agent-delegation" && event.metadata && event.metadata.telemetryAttestation);
135
+ if (!delegations.length)
136
+ return [];
137
+ const statusOf = (event) => String(event.metadata.telemetryAttestation);
138
+ const attested = delegations.filter((event) => statusOf(event) === "attested").length;
139
+ const unattested = delegations.filter((event) => statusOf(event) === "unattested");
140
+ const absent = delegations.filter((event) => statusOf(event) === "absent").length;
195
141
  const lines = [
196
- `- Total: ${summary.total}`,
197
- `- By status: ${formatCounts(summary.byStatus)}`,
198
- "",
199
- ...summary.manifestPaths.map((artifact) => `- ${artifact}`)
142
+ `- Telemetry attestation: ${attested}/${delegations.length} attested` +
143
+ (unattested.length ? `, ${unattested.length} UNATTESTED` : "") +
144
+ (absent ? `, ${absent} absent` : ""),
200
145
  ];
201
- if (summary.failed.length) {
202
- lines.push("", "Failed or rejected:");
203
- for (const worker of summary.failed) {
204
- lines.push(`- ${worker.id} (${worker.status}) feedback=${worker.feedbackIds.join(",") || "none"}`);
205
- }
146
+ for (const event of unattested) {
147
+ const reason = event.metadata.telemetryAttestationReason;
148
+ lines.push(` - ⚠️ UNATTESTED usage — worker=${event.workerId || "?"} task=${event.taskId || "?"}: ${reason || "signature unverified"}`);
149
+ }
150
+ const ledger = (0, telemetry_ledger_io_1.verifyTelemetryLedger)(run);
151
+ if (ledger.present) {
152
+ lines.push(ledger.verified
153
+ ? `- Attestation ledger: ${ledger.records.length} records, chain verified (tamper-evident)`
154
+ : ` - ⚠️ ATTESTATION LEDGER CHAIN BROKEN — a recorded verdict/usage was edited after the fact (${ledger.checks.filter((c) => !c.pass).map((c) => c.name).join(", ")})`);
206
155
  }
207
156
  return lines;
208
157
  }
209
- function renderStateSize(run) {
210
- const index = (0, state_explosion_1.loadStateExplosionSummaryIndex)(run);
211
- const report = (0, state_explosion_1.buildStateExplosionReport)(run, { index });
212
- return (0, state_explosion_1.stateExplosionReportLines)(report);
158
+ /** `## Acceptance Rationale` — byte-exact port of the old build's
159
+ * renderAcceptanceRationale (src/orchestrator/report.ts:357-374). */
160
+ function renderAcceptanceRationale(run) {
161
+ const lines = [];
162
+ for (const selectionRaw of run.candidateSelections || []) {
163
+ const selection = selectionRaw;
164
+ const rationale = selection.acceptanceRationale;
165
+ if (!rationale)
166
+ continue;
167
+ lines.push(`- Selection ${selection.id}: candidate=${rationale.selectedCandidateId || selection.candidateId}, score=${rationale.scoreId || "none"}, verifier=${rationale.verifierNodeId || "none"}, evidence=${rationale.evidenceCount}, sandbox=${rationale.sandboxProfileId || "none"}, worker=${rationale.workerId || "none"}`);
168
+ }
169
+ for (const commit of run.commits || []) {
170
+ if (!commit.acceptanceRationale)
171
+ continue;
172
+ const rationale = commit.acceptanceRationale;
173
+ lines.push(`- Commit ${commit.id}: gate=${rationale.commitGateResult || "unknown"}, candidate=${rationale.selectedCandidateId || commit.candidateId || "none"}, score=${rationale.scoreId || "none"}, verifier=${rationale.verifierNodeId || commit.verifierNodeId || "none"}, evidence=${rationale.evidenceCount}, sandbox=${rationale.sandboxProfileId || "none"}, worker=${rationale.workerId || "none"}`);
174
+ }
175
+ return lines.length ? lines : ["No accepted candidate or verifier-gated commit rationale yet."];
213
176
  }
177
+ /** `## Multi-Agent Runtime` — byte-exact port of the old build's
178
+ * renderMultiAgent (src/orchestrator/report.ts:217-242). */
214
179
  function renderMultiAgent(run) {
215
- const summary = (0, multi_agent_1.summarizeMultiAgent)(run);
180
+ const summary = (0, multi_agent_io_1.summarizeMultiAgent)(run);
216
181
  if (!summary.totalRuns)
217
182
  return ["No multi-agent runtime records yet."];
218
183
  const lines = [
@@ -221,7 +186,7 @@ function renderMultiAgent(run) {
221
186
  `- Groups: ${summary.groups} (${formatCounts(summary.groupsByStatus)})`,
222
187
  `- Memberships: ${summary.memberships} (${formatCounts(summary.membershipsByStatus)})`,
223
188
  `- Fanouts: ${summary.fanouts}`,
224
- `- Fanins: ${summary.fanins} (${formatCounts(summary.faninsByStatus)})`
189
+ `- Fanins: ${summary.fanins} (${formatCounts(summary.faninsByStatus)})`,
225
190
  ];
226
191
  if (summary.blockedReasons.length) {
227
192
  lines.push("", "Blocked:");
@@ -240,8 +205,10 @@ function renderMultiAgent(run) {
240
205
  lines.push("", `Next multi-agent action: ${summary.nextAction}`);
241
206
  return lines;
242
207
  }
208
+ /** `## Blackboard / Coordinator` — byte-exact port of the old build's
209
+ * renderBlackboard (src/orchestrator/report.ts:244-275). */
243
210
  function renderBlackboard(run) {
244
- const summary = (0, coordinator_1.summarizeBlackboard)(run);
211
+ const summary = (0, coordinator_io_1.summarizeBlackboard)(run);
245
212
  if (!summary.blackboardId)
246
213
  return ["No blackboard records yet."];
247
214
  const lines = [
@@ -254,7 +221,7 @@ function renderBlackboard(run) {
254
221
  `- Decisions: ${summary.decisions}`,
255
222
  `- Ready for fanin: ${summary.readyForFanin ? "yes" : "no"}`,
256
223
  `- Index: ${summary.indexPath || "none"}`,
257
- `- Latest snapshot: ${summary.latestSnapshotPath || "none"}`
224
+ `- Latest snapshot: ${summary.latestSnapshotPath || "none"}`,
258
225
  ];
259
226
  if (summary.openQuestions.length) {
260
227
  lines.push("", "Open questions:");
@@ -276,17 +243,10 @@ function renderBlackboard(run) {
276
243
  lines.push("", `Next coordinator action: ${summary.nextAction}`);
277
244
  return lines;
278
245
  }
279
- function renderSandboxProfiles(run) {
280
- const profiles = run.sandboxProfiles || [];
281
- if (!profiles.length)
282
- return ["No sandbox profiles selected yet."];
283
- return profiles.map((profile) => [
284
- `- ${profile.id}: read=${profile.readPaths.length}, write=${profile.writePaths.length}, execute=${profile.execute.mode}, network=${profile.network.mode}`,
285
- ` enforcedByCW=${profile.enforcement.enforcedByCW.join("; ")}`,
286
- ` hostRequired=${profile.enforcement.hostRequired.join("; ")}`
287
- ].join("\n"));
288
- }
289
- function renderCandidates(summary) {
246
+ /** `## Candidates` — byte-exact port of the old build's renderCandidates
247
+ * (src/orchestrator/report.ts:289-299). */
248
+ function renderCandidatesSection(run) {
249
+ const summary = (0, candidate_scoring_io_1.summarizeCandidates)(run);
290
250
  if (!summary.total)
291
251
  return ["No candidates yet."];
292
252
  return [
@@ -295,94 +255,141 @@ function renderCandidates(summary) {
295
255
  `- By kind: ${formatCounts(summary.byKind)}`,
296
256
  `- Selections: ${summary.selections}`,
297
257
  `- Index: ${summary.indexPath}`,
298
- `- Ranking: ${summary.rankingPath}`
258
+ `- Ranking: ${summary.rankingPath}`,
299
259
  ];
300
260
  }
301
- function renderTrustAudit(run) {
302
- const summary = (0, trust_audit_1.summarizeTrustAudit)(run);
303
- const integrity = summary.integrity;
261
+ function renderFeedback(run) {
262
+ const records = (run.feedback || []);
263
+ if (!records.length)
264
+ return ["No feedback records."];
304
265
  return [
305
- `- Events: ${summary.eventCount}`,
306
- `- Chain integrity: ${integrity ? (integrity.verified ? "verified" : "FAILED") : "n/a"}` +
307
- `${integrity ? ` (${integrity.chained} chained, ${integrity.unchained} legacy${integrity.corruptLines ? `, ${integrity.corruptLines} corrupt` : ""})` : ""}`,
308
- // An auditable control-plane never lets a broken decision-log chain pass
309
- // silently — name the failing checks loudly, same as the telemetry chain.
310
- ...(integrity && !integrity.verified
311
- ? [` !! TRUST-AUDIT CHAIN TAMPER DETECTED: ${integrity.checks.filter((c) => !c.pass).map((c) => c.code).join(", ")}`]
312
- : []),
313
- `- Decisions: ${formatCounts(summary.byDecision)}`,
314
- `- Sources: ${formatCounts(summary.bySource)}`,
315
- `- Sandbox profiles: ${formatCounts(summary.bySandboxProfile)}`,
316
- `- Event log: ${summary.eventLogPath}`,
317
- `- Summary: ${summary.summaryPath}`,
318
- `- Index: ${summary.indexPath}`,
319
- ...renderTelemetryAttestation(run)
266
+ `- Total: ${records.length}`,
267
+ `- By status: ${formatCounts(countBy(records, (r) => r.status))}`,
268
+ `- By severity: ${formatCounts(countBy(records, (r) => r.severity))}`,
269
+ `- By classification: ${formatCounts(countBy(records, (r) => r.classification))}`,
320
270
  ];
321
271
  }
322
- /** Track 1: telemetry attestation coverage + a LOUD list of any `unattested`
323
- * usage. An auditable control-plane never lets unverified telemetry pass
324
- * silently — every reported-but-unverified usage is named here with its reason. */
325
- function renderTelemetryAttestation(run) {
326
- const delegations = (0, trust_audit_1.listTrustAuditEvents)(run).filter((event) => event.kind === "worker.agent-delegation" && event.metadata && event.metadata.telemetryAttestation);
327
- if (!delegations.length)
328
- return [];
329
- const statusOf = (event) => String(event.metadata.telemetryAttestation);
330
- const attested = delegations.filter((event) => statusOf(event) === "attested").length;
331
- const unattested = delegations.filter((event) => statusOf(event) === "unattested");
332
- const absent = delegations.filter((event) => statusOf(event) === "absent").length;
333
- const lines = [
334
- `- Telemetry attestation: ${attested}/${delegations.length} attested` +
335
- (unattested.length ? `, ${unattested.length} UNATTESTED` : "") +
336
- (absent ? `, ${absent} absent` : "")
337
- ];
338
- for (const event of unattested) {
339
- const reason = event.metadata.telemetryAttestationReason;
340
- lines.push(` - ⚠️ UNATTESTED usage — worker=${event.workerId || "?"} task=${event.taskId || "?"}: ${reason || "signature unverified"}`);
341
- }
342
- // Tamper-evidence: re-prove the hash-chained ledger. A broken chain means a
343
- // recorded verdict/usage was edited after the fact — surfaced LOUDLY.
344
- const ledger = (0, telemetry_ledger_1.verifyTelemetryLedger)(run);
345
- if (ledger.present) {
346
- lines.push(ledger.verified
347
- ? `- Attestation ledger: ${ledger.records.length} records, chain verified (tamper-evident)`
348
- : ` - ⚠️ ATTESTATION LEDGER CHAIN BROKEN — a recorded verdict/usage was edited after the fact (${ledger.checks.filter((c) => !c.pass).map((c) => c.name).join(", ")})`);
272
+ function renderWorkers(run) {
273
+ const workers = run.workers || [];
274
+ if (!workers.length)
275
+ return ["No worker scopes yet."];
276
+ const lines = [`- Total: ${workers.length}`, `- By status: ${formatCounts(countBy(workers, (w) => w.status))}`];
277
+ const failed = workers.filter((w) => w.status === "failed" || w.status === "rejected");
278
+ if (failed.length) {
279
+ lines.push("", "Failed or rejected:");
280
+ for (const w of failed)
281
+ lines.push(`- ${w.id} (${w.status}) feedback=${w.feedbackIds.join(",") || "none"}`);
349
282
  }
350
283
  return lines;
351
284
  }
352
- function renderAcceptanceRationale(run) {
285
+ function renderPendingTasks(run) {
286
+ const pending = run.tasks.filter((t) => t.status === "pending" || t.status === "running");
287
+ if (!pending.length)
288
+ return ["No pending tasks."];
289
+ return pending.map((t) => `- ${t.id} (${t.phase}, ${t.status}): ${t.taskPath}`);
290
+ }
291
+ function renderResults(run) {
292
+ const completed = run.tasks.filter((t) => t.status === "completed");
293
+ if (!completed.length)
294
+ return ["No completed results yet."];
353
295
  const lines = [];
354
- for (const selection of run.candidateSelections || []) {
355
- const rationale = selection.acceptanceRationale;
356
- if (!rationale)
357
- continue;
358
- lines.push(`- Selection ${selection.id}: candidate=${rationale.selectedCandidateId || selection.candidateId}, score=${rationale.scoreId || "none"}, verifier=${rationale.verifierNodeId || "none"}, evidence=${rationale.evidenceCount}, sandbox=${rationale.sandboxProfileId || "none"}, worker=${rationale.workerId || "none"}`);
359
- }
360
- for (const commit of run.commits || []) {
361
- if (!commit.acceptanceRationale)
362
- continue;
363
- const rationale = commit.acceptanceRationale;
364
- lines.push(`- Commit ${commit.id}: gate=${rationale.commitGateResult || "unknown"}, candidate=${rationale.selectedCandidateId || commit.candidateId || "none"}, score=${rationale.scoreId || "none"}, verifier=${rationale.verifierNodeId || commit.verifierNodeId || "none"}, evidence=${rationale.evidenceCount}, sandbox=${rationale.sandboxProfileId || "none"}, worker=${rationale.workerId || "none"}`);
296
+ for (const task of completed) {
297
+ lines.push(`### ${task.id}`, "", `Result: ${task.resultPath}`, "");
298
+ if (task.resultPath && fs.existsSync(task.resultPath)) {
299
+ lines.push(fs.readFileSync(task.resultPath, "utf8").trim(), "");
300
+ }
301
+ else {
302
+ lines.push("_Result file is not present on this host; state metadata remains inspectable._", "");
303
+ }
365
304
  }
366
- return lines.length ? lines : ["No accepted candidate or verifier-gated commit rationale yet."];
367
- }
368
- function formatCommitGate(commit) {
369
- return [
370
- `verifier=${commit.verifierNodeId || "unknown"}`,
371
- commit.candidateId ? `candidate=${commit.candidateId}` : "",
372
- commit.selectionId ? `selection=${commit.selectionId}` : "",
373
- `evidence=${commit.evidence?.length || 0}`
374
- ]
375
- .filter(Boolean)
376
- .join(", ");
377
- }
378
- function formatCounts(counts) {
379
- const entries = Object.entries(counts).sort(([left], [right]) => left.localeCompare(right));
380
- if (!entries.length)
381
- return "none";
382
- return entries.map(([key, value]) => `${key}=${value}`).join(", ");
305
+ return lines;
383
306
  }
384
- function formatInputList(value) {
385
- if (Array.isArray(value))
386
- return value.join("; ");
387
- return value ? String(value) : "";
307
+ /** writeReport — renders report.md and writes it. Returns the path. */
308
+ function writeReport(run) {
309
+ (0, dispatch_1.updatePhaseStatuses)(run);
310
+ const workflowApp = run.workflow.app;
311
+ // A research run reads a local folder of files, not a code repo — label
312
+ // its source line "Source". Skip the relabel when the run ALSO carries a
313
+ // remote-provenance "- Source: <url>" line below (run.inputs.sourceUrl
314
+ // set by a --link/URL), so a report never shows two "- Source:" lines.
315
+ // Every other app keeps the byte-identical "Repository:" (POLA).
316
+ const sourceLabel = workflowApp?.metadata?.domain === "research" && !run.inputs.sourceUrl ? "Source" : "Repository";
317
+ const report = [
318
+ `# ${run.workflow.title}`,
319
+ "",
320
+ `- Run: ${run.id}`,
321
+ `- Workflow: ${run.workflow.id}`,
322
+ ...(workflowApp
323
+ ? [`- Workflow App: ${workflowApp.id}@${workflowApp.version}`, `- Workflow App Source: ${workflowApp.source?.manifestPath || workflowApp.source?.entrypointPath || workflowApp.source?.path || ""}`]
324
+ : []),
325
+ `- Created: ${run.createdAt}`,
326
+ `- Updated: ${run.updatedAt}`,
327
+ `- ${sourceLabel}: ${String(run.inputs.repo || run.cwd)}`,
328
+ ...(run.inputs.sourceUrl
329
+ ? [`- Source: ${String(run.inputs.sourceUrl)}${run.inputs.sourceCommit ? `@${String(run.inputs.sourceCommit)}` : ""}`]
330
+ : []),
331
+ `- Question: ${String(run.inputs.question || "")}`,
332
+ `- Invariants: ${formatInputList(run.inputs.invariant)}`,
333
+ `- Loop Stage: ${run.loopStage}`,
334
+ "",
335
+ "## Phase Status",
336
+ "",
337
+ "| Phase | Status | Completed | Total |",
338
+ "| --- | --- | ---: | ---: |",
339
+ ...run.phases.map((phase) => {
340
+ const phaseTasks = run.tasks.filter((t) => phase.taskIds.includes(t.id));
341
+ const completed = phaseTasks.filter((t) => t.status === "completed").length;
342
+ return `| ${phase.name} | ${phase.status} | ${completed} | ${phaseTasks.length} |`;
343
+ }),
344
+ "",
345
+ "## State Commits",
346
+ "",
347
+ ...renderCommits(run),
348
+ "",
349
+ "## Error Feedback",
350
+ "",
351
+ ...renderFeedback(run),
352
+ "",
353
+ "## Workers",
354
+ "",
355
+ ...renderWorkers(run),
356
+ "",
357
+ "## State Size & Compaction",
358
+ "",
359
+ ...renderStateSize(run),
360
+ "",
361
+ "## Multi-Agent Runtime",
362
+ "",
363
+ ...renderMultiAgent(run),
364
+ "",
365
+ "## Blackboard / Coordinator",
366
+ "",
367
+ ...renderBlackboard(run),
368
+ "",
369
+ "## Sandbox Profiles",
370
+ "",
371
+ ...renderSandboxProfiles(run),
372
+ "",
373
+ "## Trust Audit",
374
+ "",
375
+ ...renderTrustAudit(run),
376
+ "",
377
+ "## Acceptance Rationale",
378
+ "",
379
+ ...renderAcceptanceRationale(run),
380
+ "",
381
+ "## Candidates",
382
+ "",
383
+ ...renderCandidatesSection(run),
384
+ "",
385
+ "## Pending Tasks",
386
+ "",
387
+ ...renderPendingTasks(run),
388
+ "",
389
+ "## Results",
390
+ "",
391
+ ...renderResults(run),
392
+ ].join("\n");
393
+ fs.writeFileSync(run.paths.report, report, "utf8");
394
+ return run.paths.report;
388
395
  }