cool-workflow 0.1.80 → 0.1.82

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 (122) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +42 -2
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/end-to-end-golden-path/app.json +1 -1
  7. package/apps/pr-review-fix-ci/app.json +1 -1
  8. package/apps/release-cut/app.json +1 -1
  9. package/apps/research-synthesis/app.json +1 -1
  10. package/dist/agent-config.js +21 -7
  11. package/dist/candidate-scoring.js +62 -48
  12. package/dist/capability-core.js +152 -96
  13. package/dist/capability-registry.js +160 -174
  14. package/dist/cli.js +90 -100
  15. package/dist/collaboration.js +5 -6
  16. package/dist/commit.js +232 -209
  17. package/dist/compare.js +18 -0
  18. package/dist/coordinator/classify.js +45 -0
  19. package/dist/coordinator/paths.js +42 -0
  20. package/dist/coordinator/util.js +126 -0
  21. package/dist/coordinator.js +127 -300
  22. package/dist/dispatch.js +46 -3
  23. package/dist/drive.js +7 -7
  24. package/dist/error-feedback.js +8 -4
  25. package/dist/evidence-reasoning.js +5 -2
  26. package/dist/execution-backend/agent.js +294 -0
  27. package/dist/execution-backend/probes.js +96 -0
  28. package/dist/execution-backend/util.js +47 -0
  29. package/dist/execution-backend.js +77 -450
  30. package/dist/gates.js +48 -0
  31. package/dist/mcp-server.js +34 -173
  32. package/dist/multi-agent/graph.js +84 -0
  33. package/dist/multi-agent/helpers.js +141 -0
  34. package/dist/multi-agent/ids.js +20 -0
  35. package/dist/multi-agent/paths.js +22 -0
  36. package/dist/multi-agent-eval/format.js +194 -0
  37. package/dist/multi-agent-eval/normalize.js +51 -0
  38. package/dist/multi-agent-eval.js +63 -242
  39. package/dist/multi-agent-host.js +53 -40
  40. package/dist/multi-agent-operator-ux.js +2 -1
  41. package/dist/multi-agent-trust.js +5 -5
  42. package/dist/multi-agent.js +125 -314
  43. package/dist/node-projection.js +59 -0
  44. package/dist/node-snapshot.js +11 -21
  45. package/dist/observability/format.js +61 -0
  46. package/dist/observability/intake.js +98 -0
  47. package/dist/observability.js +14 -160
  48. package/dist/operator-ux/format.js +364 -0
  49. package/dist/operator-ux.js +22 -363
  50. package/dist/orchestrator/lifecycle-operations.js +22 -1
  51. package/dist/orchestrator/report.js +8 -0
  52. package/dist/orchestrator.js +41 -10
  53. package/dist/reclamation.js +32 -55
  54. package/dist/run-export.js +138 -14
  55. package/dist/run-registry/derive.js +172 -0
  56. package/dist/run-registry/format.js +124 -0
  57. package/dist/run-registry/gc.js +251 -0
  58. package/dist/run-registry/policy.js +16 -0
  59. package/dist/run-registry/queue.js +116 -0
  60. package/dist/run-registry.js +78 -593
  61. package/dist/run-state-schema.js +1 -0
  62. package/dist/sandbox-profile.js +43 -2
  63. package/dist/scheduler.js +34 -4
  64. package/dist/state-explosion/format.js +159 -0
  65. package/dist/state-explosion/helpers.js +82 -0
  66. package/dist/state-explosion.js +65 -283
  67. package/dist/state-node.js +19 -4
  68. package/dist/telemetry-attestation.js +55 -0
  69. package/dist/telemetry-demo.js +15 -3
  70. package/dist/telemetry-ledger.js +60 -15
  71. package/dist/topology.js +50 -12
  72. package/dist/triggers.js +33 -14
  73. package/dist/trust-audit.js +215 -71
  74. package/dist/validation.js +328 -0
  75. package/dist/version.js +1 -1
  76. package/dist/worker-isolation/helpers.js +51 -0
  77. package/dist/worker-isolation/paths.js +46 -0
  78. package/dist/worker-isolation.js +182 -173
  79. package/docs/agent-delegation-drive.7.md +14 -0
  80. package/docs/cli-mcp-parity.7.md +5 -0
  81. package/docs/contract-migration-tooling.7.md +3 -0
  82. package/docs/control-plane-scheduling.7.md +3 -0
  83. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
  84. package/docs/durable-state-and-locking.7.md +5 -0
  85. package/docs/evidence-adoption-reasoning-chain.7.md +3 -0
  86. package/docs/execution-backends.7.md +3 -0
  87. package/docs/index.md +1 -0
  88. package/docs/launch/launch-kit.md +46 -23
  89. package/docs/launch/pre-launch-checklist.md +14 -14
  90. package/docs/multi-agent-cli-mcp-surface.7.md +5 -0
  91. package/docs/multi-agent-eval-replay-harness.7.md +3 -0
  92. package/docs/multi-agent-operator-ux.7.md +3 -0
  93. package/docs/multi-agent-trust-policy-audit.7.md +27 -0
  94. package/docs/node-snapshot-diff-replay.7.md +3 -0
  95. package/docs/observability-cost-accounting.7.md +3 -0
  96. package/docs/project-index.md +23 -6
  97. package/docs/real-execution-backends.7.md +3 -0
  98. package/docs/release-and-migration.7.md +5 -0
  99. package/docs/release-tooling.7.md +35 -2
  100. package/docs/run-registry-control-plane.7.md +55 -8
  101. package/docs/run-retention-reclamation.7.md +5 -0
  102. package/docs/state-explosion-management.7.md +3 -0
  103. package/docs/team-collaboration.7.md +3 -0
  104. package/docs/trust-model.md +267 -0
  105. package/docs/vendor-manifest-loadability.7.md +43 -0
  106. package/docs/web-desktop-workbench.7.md +3 -0
  107. package/manifest/plugin.manifest.json +1 -1
  108. package/manifest/source-context-profiles.json +1 -1
  109. package/package.json +4 -2
  110. package/scripts/agents/builtin-templates.json +7 -0
  111. package/scripts/bump-version.js +5 -11
  112. package/scripts/canonical-apps-list.js +64 -0
  113. package/scripts/canonical-apps.js +19 -4
  114. package/scripts/children/batch-delegate-child.js +58 -0
  115. package/scripts/children/http-delegate-child.js +39 -0
  116. package/scripts/dogfood-release.js +1 -1
  117. package/scripts/golden-path.js +4 -4
  118. package/scripts/parity-check.js +5 -0
  119. package/scripts/release-check.js +5 -1
  120. package/scripts/release-flow.js +181 -5
  121. package/scripts/version-sync-check.js +5 -8
  122. package/dist/capability-dispatcher.js +0 -86
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TRUST_AUDIT_SCHEMA_VERSION = void 0;
6
+ exports.CORRELATION_ID_FIELDS = exports.TRUST_AUDIT_SCHEMA_VERSION = void 0;
7
+ exports.trustAuditGenesis = trustAuditGenesis;
8
+ exports.verifyTrustAudit = verifyTrustAudit;
7
9
  exports.ensureTrustAudit = ensureTrustAudit;
8
10
  exports.recordTrustAuditEvent = recordTrustAuditEvent;
9
11
  exports.recordSandboxPathDecision = recordSandboxPathDecision;
@@ -22,17 +24,198 @@ const node_fs_1 = __importDefault(require("node:fs"));
22
24
  const node_path_1 = __importDefault(require("node:path"));
23
25
  const state_1 = require("./state");
24
26
  const evidence_grounding_1 = require("./evidence-grounding");
27
+ const execution_backend_1 = require("./execution-backend");
28
+ const telemetry_attestation_1 = require("./telemetry-attestation");
25
29
  exports.TRUST_AUDIT_SCHEMA_VERSION = 1;
30
+ // ---- Tamper-evidence chain (v0.1.81) --------------------------------------
31
+ // Same discipline as telemetry-ledger.ts / reclamation.ts: the event log is
32
+ // hash-chained in APPEND order, and verifyTrustAudit recomputes every hash
33
+ // independently (never trusts a stored value), so an edited or removed event is
34
+ // detected. Durability (fsync) only guards against power loss; this guards
35
+ // against post-hoc edits — the threat an external auditor actually cares about.
36
+ //
37
+ // THREAT MODEL (be honest about the limit): the genesis is sha256(runId), so this
38
+ // detects casual/partial tampering, accidental corruption, truncation, removal,
39
+ // and forged-unchained lines — but NOT a determined local writer who re-chains the
40
+ // WHOLE log with this module's own sha256 after an edit. That is the same limit
41
+ // reclamation.ts's tombstone chain has, and it is INHERENT to a local, self-
42
+ // recomputable chain: closing it needs an anchor the writer cannot reproduce.
43
+ // CW cannot self-sign that anchor — by design CW holds NO private key (see
44
+ // telemetry-attestation.ts: "CW never holds the private key"; the AGENT signs its
45
+ // usage, CW only VERIFIES with the operator-provisioned public half). The single
46
+ // cryptographic anchor that exists is therefore the agent's telemetry signature,
47
+ // which binds agent-reported USAGE (worker-isolation cross-links the chain into it)
48
+ // — it does NOT cover CW-only sandbox/policy/commit-gate decisions, which have no
49
+ // external signer. For those, the only stronger guarantee is operational: commit
50
+ // events.jsonl to an external append-only medium (git history / a remote log) the
51
+ // local writer cannot rewrite. The chain is a strict upgrade over a bare append-
52
+ // only log, not a substitute for an external anchor — and that anchor is not
53
+ // something CW can mint for itself.
54
+ /** Single source of truth for a run's audit-paths object: the schemaVersion plus
55
+ * the three derived file paths under auditRoot(run). ensureTrustAudit /
56
+ * refreshTrustAudit spread this, and createEventId reads .eventLogPath from it, so
57
+ * the path-derivation rule lives in exactly one place. */
58
+ function trustAuditPaths(run) {
59
+ const dir = auditRoot(run);
60
+ return {
61
+ schemaVersion: exports.TRUST_AUDIT_SCHEMA_VERSION,
62
+ eventLogPath: node_path_1.default.join(dir, "events.jsonl"),
63
+ summaryPath: node_path_1.default.join(dir, "summary.json"),
64
+ indexPath: node_path_1.default.join(dir, "index.json")
65
+ };
66
+ }
67
+ /** Genesis prevHash for a run's chain (no prior event). */
68
+ function trustAuditGenesis(runId) {
69
+ return (0, execution_backend_1.sha256)(`cw-trust-audit:${runId}`);
70
+ }
71
+ /** Canonical bytes the eventHash binds: every field EXCEPT eventHash itself
72
+ * (prevEventHash included, so the chain link is bound).
73
+ *
74
+ * The hash binds the PERSISTED form. `stableStringify` keeps an undefined-valued
75
+ * key as `"k":null`, but the `JSON.stringify` that writes events.jsonl DROPS such
76
+ * keys — so without this round-trip the record-time hash (over the in-memory event,
77
+ * which can carry nested undefined like an absent dispatchId in worker-sandbox
78
+ * metadata) would never match the verify-time hash (over the parsed-from-disk
79
+ * event), false-failing legitimate worker events as `trust-audit-digest-mismatch`.
80
+ * Round-tripping makes record-time == verify-time. It is identity for events with
81
+ * no undefined fields, so existing intact chains hash unchanged. */
82
+ function computeEventHash(event) {
83
+ const { eventHash, ...rest } = event;
84
+ return (0, execution_backend_1.sha256)((0, telemetry_attestation_1.stableStringify)(JSON.parse(JSON.stringify(rest))));
85
+ }
86
+ /** The hash to chain the NEXT event to: the stored eventHash, or a recompute for
87
+ * a legacy event written before the chain existed. */
88
+ function chainHashOf(event) {
89
+ return event.eventHash || computeEventHash(event);
90
+ }
91
+ /** Read events in FILE (append) order, tolerating corrupt lines — one bad line
92
+ * must not brick the whole audit read surface (it is counted, not thrown). The
93
+ * chain links append order, so this is the order verification walks. */
94
+ function readEventsRaw(eventLogPath) {
95
+ if (!node_fs_1.default.existsSync(eventLogPath))
96
+ return { events: [], corruptLines: 0 };
97
+ let corruptLines = 0;
98
+ const events = [];
99
+ for (const line of node_fs_1.default.readFileSync(eventLogPath, "utf8").split(/\n/g)) {
100
+ const trimmed = line.trim();
101
+ if (!trimmed)
102
+ continue;
103
+ try {
104
+ events.push(JSON.parse(trimmed));
105
+ }
106
+ catch {
107
+ corruptLines += 1;
108
+ }
109
+ }
110
+ return { events, corruptLines };
111
+ }
112
+ /** Re-prove the run's trust-audit chain: prevEventHash linkage (append order) +
113
+ * per-event hash recompute. A corrupt line, an edited event, or a removed event
114
+ * flips verified=false. Legacy events without a hash are reported as `unchained`
115
+ * (skipped), NOT treated as a forgery — they predate the chain. */
116
+ function verifyTrustAudit(run) {
117
+ const audit = ensureTrustAudit(run);
118
+ const { events, corruptLines } = readEventsRaw(audit.eventLogPath);
119
+ const checks = [];
120
+ let verified = corruptLines === 0;
121
+ if (corruptLines > 0)
122
+ checks.push({ name: "parse", pass: false, code: "trust-audit-corrupt-line" });
123
+ let chained = 0;
124
+ let unchained = 0;
125
+ let expectedPrev = trustAuditGenesis(run.id);
126
+ for (let i = 0; i < events.length; i++) {
127
+ const event = events[i];
128
+ const recomputed = computeEventHash(event);
129
+ if (event.eventHash === undefined) {
130
+ unchained += 1;
131
+ expectedPrev = recomputed; // advance the chain over legacy events
132
+ continue;
133
+ }
134
+ chained += 1;
135
+ if (event.eventHash !== recomputed) {
136
+ verified = false;
137
+ checks.push({ name: `event-hash[${i}]`, pass: false, code: "trust-audit-digest-mismatch" });
138
+ }
139
+ if (event.prevEventHash !== undefined && event.prevEventHash !== expectedPrev) {
140
+ verified = false;
141
+ checks.push({ name: `chain-link[${i}]`, pass: false, code: "trust-audit-chain-broken" });
142
+ }
143
+ expectedPrev = event.eventHash;
144
+ }
145
+ // A log with ANY chained event must have EVERY event chained: a single run is
146
+ // written by one code version, so it is all-chained (chain era) or all-legacy
147
+ // (pre-chain). An unchained (eventHash-less) line mixed into a chained log is a
148
+ // forgery attempt — drop the hash to be waved through as "legacy" — so it fails.
149
+ if (chained > 0 && unchained > 0) {
150
+ verified = false;
151
+ checks.push({ name: "unchained-events", pass: false, code: "trust-audit-unchained-event" });
152
+ }
153
+ return { present: events.length > 0, verified, eventCount: events.length, chained, unchained, corruptLines, checks };
154
+ }
155
+ // ---- Correlation-id fields (single source of truth, F12) -------------------
156
+ // These id fields are plain pass-throughs that flow input -> persisted event ->
157
+ // summary index unchanged. They were previously re-listed by hand in three
158
+ // places (recordTrustAuditEvent, the index writer, and partially in
159
+ // multi-agent-trust), so adding a new correlation id meant editing every list and
160
+ // silently dropping it from the index when one was missed. They now live in ONE
161
+ // array; both spread sites pick from it via pickCorrelationIds, so a new id is
162
+ // added in exactly one place.
163
+ //
164
+ // SERIALIZATION-PRESERVING by design: this is a plain key-copy with NO transform,
165
+ // so the persisted JSON for these keys is byte-identical to the old hand-spread
166
+ // (compact() still drops the undefined ones). The hash chain that binds these
167
+ // fields is therefore unaffected. Fields needing derivation/normalization
168
+ // (feedbackIds, sandboxProfileId, policyRef, multiAgentPolicyRef, normalizedPath,
169
+ // envVars, …) are intentionally NOT here — they keep their bespoke handling at the
170
+ // call site.
171
+ exports.CORRELATION_ID_FIELDS = [
172
+ "candidateId",
173
+ "scoreId",
174
+ "selectionId",
175
+ "commitId",
176
+ "multiAgentRunId",
177
+ "agentRoleId",
178
+ "agentGroupId",
179
+ "agentMembershipId",
180
+ "agentFanoutId",
181
+ "agentFaninId",
182
+ "blackboardId",
183
+ "blackboardTopicId",
184
+ "blackboardMessageId",
185
+ "blackboardContextId",
186
+ "blackboardArtifactRefId",
187
+ "blackboardSnapshotId",
188
+ "coordinatorDecisionId",
189
+ "topologyId",
190
+ "topologyRunId"
191
+ ];
192
+ /** Copy exactly the correlation-id keys (and no others) from `source`, preserving
193
+ * each value verbatim (including `undefined`, which compact()/JSON.stringify drop
194
+ * identically to the prior per-key spread). Spread the result; do not transform. */
195
+ function pickCorrelationIds(source) {
196
+ const picked = {};
197
+ for (const field of exports.CORRELATION_ID_FIELDS)
198
+ picked[field] = source[field];
199
+ return picked;
200
+ }
201
+ // The summary index has always carried every correlation id EXCEPT scoreId (the
202
+ // per-candidate score lives in the candidates[] rows, not the flat event index).
203
+ // Pin that exception in ONE place so the index stays byte-identical while still
204
+ // inheriting any NEW id from CORRELATION_ID_FIELDS automatically.
205
+ const INDEX_OMITTED_CORRELATION_IDS = new Set(["scoreId"]);
206
+ /** Correlation ids for the summary index: the full pick minus the keys the index
207
+ * has historically omitted (see INDEX_OMITTED_CORRELATION_IDS). */
208
+ function indexCorrelationIds(event) {
209
+ const picked = pickCorrelationIds(event);
210
+ for (const field of INDEX_OMITTED_CORRELATION_IDS)
211
+ delete picked[field];
212
+ return picked;
213
+ }
26
214
  function ensureTrustAudit(run) {
27
215
  const auditDir = auditRoot(run);
28
216
  node_fs_1.default.mkdirSync(auditDir, { recursive: true });
29
217
  run.paths.auditDir = auditDir;
30
- const audit = {
31
- schemaVersion: exports.TRUST_AUDIT_SCHEMA_VERSION,
32
- eventLogPath: node_path_1.default.join(auditDir, "events.jsonl"),
33
- summaryPath: node_path_1.default.join(auditDir, "summary.json"),
34
- indexPath: node_path_1.default.join(auditDir, "index.json")
35
- };
218
+ const audit = { ...trustAuditPaths(run) };
36
219
  run.audit = audit;
37
220
  if (!node_fs_1.default.existsSync(audit.eventLogPath))
38
221
  node_fs_1.default.writeFileSync(audit.eventLogPath, "", "utf8");
@@ -53,25 +236,11 @@ function recordTrustAuditEvent(run, input) {
53
236
  taskId: input.taskId,
54
237
  nodeId: input.nodeId,
55
238
  feedbackIds: input.feedbackIds?.filter(Boolean).sort(),
56
- candidateId: input.candidateId,
57
- scoreId: input.scoreId,
58
- selectionId: input.selectionId,
59
- commitId: input.commitId,
60
- multiAgentRunId: input.multiAgentRunId,
61
- agentRoleId: input.agentRoleId,
62
- agentGroupId: input.agentGroupId,
63
- agentMembershipId: input.agentMembershipId,
64
- agentFanoutId: input.agentFanoutId,
65
- agentFaninId: input.agentFaninId,
66
- blackboardId: input.blackboardId,
67
- blackboardTopicId: input.blackboardTopicId,
68
- blackboardMessageId: input.blackboardMessageId,
69
- blackboardContextId: input.blackboardContextId,
70
- blackboardArtifactRefId: input.blackboardArtifactRefId,
71
- blackboardSnapshotId: input.blackboardSnapshotId,
72
- coordinatorDecisionId: input.coordinatorDecisionId,
73
- topologyId: input.topologyId,
74
- topologyRunId: input.topologyRunId,
239
+ // Plain correlation-id pass-throughs (candidateId … topologyRunId) come from the
240
+ // single CORRELATION_ID_FIELDS list. Key order is preserved (the list is in the
241
+ // same order the keys used to be hand-written), so the persisted JSON — and thus
242
+ // the eventHash chain — is byte-identical.
243
+ ...pickCorrelationIds(input),
75
244
  sandboxProfileId: input.sandboxProfileId || input.policySnapshot?.id,
76
245
  policyRef: input.policyRef || (input.policySnapshot?.id ? `run.sandboxProfiles.${input.policySnapshot.id}` : undefined),
77
246
  multiAgentPolicyRef: input.policyRef,
@@ -90,6 +259,12 @@ function recordTrustAuditEvent(run, input) {
90
259
  parentEventIds: unique(input.parentEventIds || []).sort(),
91
260
  metadata: scrubMetadata(input.metadata || {})
92
261
  });
262
+ // Tamper-evidence chain: link this event to the prior one (append order) and
263
+ // bind its content with eventHash BEFORE persisting. verifyTrustAudit recomputes
264
+ // both independently, so a later edit or removal is detectable.
265
+ const prior = readEventsRaw(audit.eventLogPath).events;
266
+ event.prevEventHash = prior.length ? chainHashOf(prior[prior.length - 1]) : trustAuditGenesis(run.id);
267
+ event.eventHash = computeEventHash(event);
93
268
  // DURABLE append (v0.1.40 self-audit P1): the audit log is the one artifact
94
269
  // whose loss breaks audit-completeness, so fsync it before returning — never a
95
270
  // bare appendFileSync, which can drop the last event on power loss.
@@ -127,15 +302,7 @@ function recordHostAttestation(run, input) {
127
302
  }
128
303
  function listTrustAuditEvents(run) {
129
304
  const audit = ensureTrustAudit(run);
130
- if (!node_fs_1.default.existsSync(audit.eventLogPath))
131
- return [];
132
- return node_fs_1.default
133
- .readFileSync(audit.eventLogPath, "utf8")
134
- .split(/\n/g)
135
- .map((line) => line.trim())
136
- .filter(Boolean)
137
- .map((line) => JSON.parse(line))
138
- .sort(compareEvents);
305
+ return readEventsRaw(audit.eventLogPath).events.sort(compareEvents);
139
306
  }
140
307
  /** Search audit events by kind, worker, or candidate (v0.1.65).
141
308
  * Filters are AND-ed; empty filters match all. */
@@ -159,6 +326,7 @@ function summarizeTrustAudit(run) {
159
326
  runId: run.id,
160
327
  generatedAt: new Date().toISOString(),
161
328
  eventCount: events.length,
329
+ integrity: verifyTrustAudit(run),
162
330
  eventLogPath: audit.eventLogPath,
163
331
  indexPath: audit.indexPath,
164
332
  summaryPath: audit.summaryPath,
@@ -228,24 +396,11 @@ function summarizeTrustAudit(run) {
228
396
  source: event.source,
229
397
  workerId: event.workerId,
230
398
  taskId: event.taskId,
231
- candidateId: event.candidateId,
232
- selectionId: event.selectionId,
233
- commitId: event.commitId,
234
- multiAgentRunId: event.multiAgentRunId,
235
- agentRoleId: event.agentRoleId,
236
- agentGroupId: event.agentGroupId,
237
- agentMembershipId: event.agentMembershipId,
238
- agentFanoutId: event.agentFanoutId,
239
- agentFaninId: event.agentFaninId,
240
- blackboardId: event.blackboardId,
241
- blackboardTopicId: event.blackboardTopicId,
242
- blackboardMessageId: event.blackboardMessageId,
243
- blackboardContextId: event.blackboardContextId,
244
- blackboardArtifactRefId: event.blackboardArtifactRefId,
245
- blackboardSnapshotId: event.blackboardSnapshotId,
246
- coordinatorDecisionId: event.coordinatorDecisionId,
247
- topologyId: event.topologyId,
248
- topologyRunId: event.topologyRunId,
399
+ // Same single CORRELATION_ID_FIELDS list the record path uses, so the index
400
+ // can never silently omit a correlation id that the event carries. (The index
401
+ // historically omitted scoreId; that is preserved below by deleting it after
402
+ // the pick, keeping this writer's output byte-identical.)
403
+ ...indexCorrelationIds(event),
249
404
  sandboxProfileId: event.sandboxProfileId,
250
405
  policyRef: event.policyRef,
251
406
  multiAgentPolicyRef: event.multiAgentPolicyRef
@@ -255,12 +410,7 @@ function summarizeTrustAudit(run) {
255
410
  return summary;
256
411
  }
257
412
  function refreshTrustAudit(run) {
258
- const audit = {
259
- schemaVersion: exports.TRUST_AUDIT_SCHEMA_VERSION,
260
- eventLogPath: node_path_1.default.join(auditRoot(run), "events.jsonl"),
261
- summaryPath: node_path_1.default.join(auditRoot(run), "summary.json"),
262
- indexPath: node_path_1.default.join(auditRoot(run), "index.json")
263
- };
413
+ const audit = { ...trustAuditPaths(run) };
264
414
  node_fs_1.default.mkdirSync(node_path_1.default.dirname(audit.eventLogPath), { recursive: true });
265
415
  if (!node_fs_1.default.existsSync(audit.eventLogPath))
266
416
  node_fs_1.default.writeFileSync(audit.eventLogPath, "", "utf8");
@@ -365,15 +515,7 @@ function auditRoot(run) {
365
515
  return run.paths.auditDir || node_path_1.default.join(run.paths.runDir, "audit");
366
516
  }
367
517
  function readEvents(eventLogPath) {
368
- if (!node_fs_1.default.existsSync(eventLogPath))
369
- return [];
370
- return node_fs_1.default
371
- .readFileSync(eventLogPath, "utf8")
372
- .split(/\n/g)
373
- .map((line) => line.trim())
374
- .filter(Boolean)
375
- .map((line) => JSON.parse(line))
376
- .sort(compareEvents);
518
+ return readEventsRaw(eventLogPath).events.sort(compareEvents);
377
519
  }
378
520
  function workerRows(events, run) {
379
521
  const workerIds = unique([...(run.workers || []).map((worker) => worker.id), ...events.map((event) => event.workerId || "")]).sort();
@@ -419,9 +561,11 @@ function commitRows(events, run) {
419
561
  });
420
562
  }
421
563
  function createEventId(run, kind) {
422
- const stamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\..+/, "Z");
423
- const count = readEvents(node_path_1.default.join(auditRoot(run), "events.jsonl")).length + 1;
424
- return `audit-${(0, state_1.safeFileName)(kind)}-${stamp}-${String(count).padStart(4, "0")}`;
564
+ // Deterministic (FreeBSD-audit L12/L13): chain-local sequence (event-log length),
565
+ // no wall-clock stamp — event.id is bound into the eventHash chain (computeEventHash),
566
+ // so a stable id keeps the chain reproducible on replay.
567
+ const count = readEvents(trustAuditPaths(run).eventLogPath).length + 1;
568
+ return `audit-${(0, state_1.safeFileName)(kind)}-${String(count).padStart(4, "0")}`;
425
569
  }
426
570
  function redactPolicy(policy) {
427
571
  if (!policy)