@sensigo/realm 0.38.0 → 0.40.0

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 (70) hide show
  1. package/dist/engine/abandon-run.d.ts.map +1 -1
  2. package/dist/engine/abandon-run.js +5 -7
  3. package/dist/engine/abandon-run.js.map +1 -1
  4. package/dist/engine/apply-resume.d.ts.map +1 -1
  5. package/dist/engine/apply-resume.js +17 -1
  6. package/dist/engine/apply-resume.js.map +1 -1
  7. package/dist/engine/eligibility.d.ts +85 -2
  8. package/dist/engine/eligibility.d.ts.map +1 -1
  9. package/dist/engine/eligibility.js +271 -14
  10. package/dist/engine/eligibility.js.map +1 -1
  11. package/dist/engine/execution-loop.d.ts.map +1 -1
  12. package/dist/engine/execution-loop.js +172 -37
  13. package/dist/engine/execution-loop.js.map +1 -1
  14. package/dist/engine/run-health.d.ts +1 -1
  15. package/dist/engine/run-health.d.ts.map +1 -1
  16. package/dist/engine/run-health.js +89 -0
  17. package/dist/engine/run-health.js.map +1 -1
  18. package/dist/engine/settlement.d.ts +61 -6
  19. package/dist/engine/settlement.d.ts.map +1 -1
  20. package/dist/engine/settlement.js +190 -25
  21. package/dist/engine/settlement.js.map +1 -1
  22. package/dist/index.d.ts +4 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +9 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/store/failed-attempt-store.d.ts +9 -1
  27. package/dist/store/failed-attempt-store.d.ts.map +1 -1
  28. package/dist/store/failed-attempt-store.js +12 -1
  29. package/dist/store/failed-attempt-store.js.map +1 -1
  30. package/dist/store/json-file-store.d.ts +28 -4
  31. package/dist/store/json-file-store.d.ts.map +1 -1
  32. package/dist/store/json-file-store.js +133 -5
  33. package/dist/store/json-file-store.js.map +1 -1
  34. package/dist/store/per-run-artifact-store.d.ts +42 -1
  35. package/dist/store/per-run-artifact-store.d.ts.map +1 -1
  36. package/dist/store/seal-integrity.d.ts +9 -0
  37. package/dist/store/seal-integrity.d.ts.map +1 -0
  38. package/dist/store/seal-integrity.js +249 -0
  39. package/dist/store/seal-integrity.js.map +1 -0
  40. package/dist/store/store-interface.d.ts +47 -2
  41. package/dist/store/store-interface.d.ts.map +1 -1
  42. package/dist/store/trace-buffer-store.d.ts +32 -6
  43. package/dist/store/trace-buffer-store.d.ts.map +1 -1
  44. package/dist/store/trace-buffer-store.js +39 -6
  45. package/dist/store/trace-buffer-store.js.map +1 -1
  46. package/dist/types/response-envelope.d.ts +0 -1
  47. package/dist/types/response-envelope.d.ts.map +1 -1
  48. package/dist/types/run-record.d.ts +201 -6
  49. package/dist/types/run-record.d.ts.map +1 -1
  50. package/dist/types/run-record.js +25 -1
  51. package/dist/types/run-record.js.map +1 -1
  52. package/dist/types/workflow-definition.d.ts +11 -1
  53. package/dist/types/workflow-definition.d.ts.map +1 -1
  54. package/dist/types/workflow-definition.js +1 -0
  55. package/dist/types/workflow-definition.js.map +1 -1
  56. package/dist/types/workflow-error.d.ts +1 -1
  57. package/dist/types/workflow-error.d.ts.map +1 -1
  58. package/dist/types/workflow-error.js.map +1 -1
  59. package/dist/workflow/diagnostics.d.ts +39 -3
  60. package/dist/workflow/diagnostics.d.ts.map +1 -1
  61. package/dist/workflow/diagnostics.js +37 -10
  62. package/dist/workflow/diagnostics.js.map +1 -1
  63. package/dist/workflow/source-positions.d.ts +39 -0
  64. package/dist/workflow/source-positions.d.ts.map +1 -0
  65. package/dist/workflow/source-positions.js +107 -0
  66. package/dist/workflow/source-positions.js.map +1 -0
  67. package/dist/workflow/yaml-loader.d.ts.map +1 -1
  68. package/dist/workflow/yaml-loader.js +436 -117
  69. package/dist/workflow/yaml-loader.js.map +1 -1
  70. package/package.json +1 -1
@@ -13,7 +13,7 @@ export declare const DEFAULT_IDLE_THRESHOLD_MS: number;
13
13
  * renders from.
14
14
  */
15
15
  export interface RunHealthFinding {
16
- kind: 'never_claimed_idle' | 'stale_claim' | 'wedged_gate_sibling' | 'capability_block' | 'terminal_pending_finalizer' | 'terminal_with_stale_gate' | 'gate_corruption' | 'resolved_gate_with_eligible_guard' | 'completed_with_failed_steps' | 'gate_expired_awaiting_drive' | 'structured_output_downgraded';
16
+ kind: 'never_claimed_idle' | 'drive_failing' | 'stale_claim' | 'wedged_gate_sibling' | 'capability_block' | 'terminal_pending_finalizer' | 'terminal_with_stale_gate' | 'gate_corruption' | 'resolved_gate_with_eligible_guard' | 'completed_with_failed_steps' | 'gate_expired_awaiting_drive' | 'structured_output_downgraded';
17
17
  /** The affected step, when the finding is step-scoped. Absent for `never_claimed_idle` — a
18
18
  * run-level observation (no step is claimed at all). */
19
19
  step?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"run-health.d.ts","sourceRoot":"","sources":["../../src/engine/run-health.ts"],"names":[],"mappings":"AAuFA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAK1E;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,QAAsB,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EACA,oBAAoB,GACpB,aAAa,GACb,qBAAqB,GACrB,kBAAkB,GAClB,4BAA4B,GAE5B,0BAA0B,GAC1B,iBAAiB,GACjB,mCAAmC,GAGnC,6BAA6B,GAM7B,6BAA6B,GAQ7B,8BAA8B,CAAC;IACnC;6DACyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;yCAEqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf;;;;4DAIwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;kDAC8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;mEAG+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAoHD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,SAAS,EACd,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,kBAAkB,CAAA;CAAE,GAC/E,gBAAgB,EAAE,CAwKpB"}
1
+ {"version":3,"file":"run-health.d.ts","sourceRoot":"","sources":["../../src/engine/run-health.ts"],"names":[],"mappings":"AA2FA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAK1E;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,QAAsB,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EACA,oBAAoB,GACpB,eAAe,GACf,aAAa,GACb,qBAAqB,GACrB,kBAAkB,GAClB,4BAA4B,GAE5B,0BAA0B,GAC1B,iBAAiB,GACjB,mCAAmC,GAGnC,6BAA6B,GAM7B,6BAA6B,GAQ7B,8BAA8B,CAAC;IACnC;6DACyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;yCAEqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf;;;;4DAIwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;kDAC8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;mEAG+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAyMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,SAAS,EACd,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,kBAAkB,CAAA;CAAE,GAC/E,gBAAgB,EAAE,CA8KpB"}
@@ -122,6 +122,89 @@ function findStructuredOutputDowngrades(run) {
122
122
  evidence: { steps },
123
123
  };
124
124
  }
125
+ /**
126
+ * `drive_failing` (issue #401) — the run's last recorded drive attempt failed, and nothing has
127
+ * happened since.
128
+ *
129
+ * WHY THE LAST-EVENT TEST. A drive failure is only news while it is still the latest thing that
130
+ * happened to the run. If a sibling step settled afterwards, or a gate opened, the run moved on and
131
+ * the failure is history — reporting it then would train an operator to ignore the finding, which
132
+ * is how a watchdog dies. So the entry must be strictly newer than every other timestamped event,
133
+ * floored at `created_at` so a fresh run with no evidence still fires (max of an empty set is
134
+ * negative infinity, and without the floor a stale entry predating the run would fire too).
135
+ *
136
+ * The settled-step guard is the second half of the same idea: if the step the failure names has
137
+ * since landed in completed/failed/skipped, the drive that failed was retried and resolved.
138
+ *
139
+ * Record-only by construction — no definition, no I/O — so `list --stuck`, which passes neither,
140
+ * gets this finding for free.
141
+ */
142
+ function findDriveFailing(run, now) {
143
+ const field = run.drive_failures;
144
+ const lastEntry = field?.entries[field.entries.length - 1];
145
+ if (field === undefined || lastEntry === undefined)
146
+ return undefined;
147
+ if (run.terminal_state)
148
+ return undefined;
149
+ const lastAt = new Date(lastEntry.at).getTime();
150
+ const floor = new Date(run.created_at).getTime();
151
+ const gateOpened = run.pending_gate !== undefined ? new Date(run.pending_gate.opened_at).getTime() : -Infinity;
152
+ const lastEvidence = run.evidence.reduce((max, snap) => Math.max(max, new Date(snap.completed_at).getTime()), -Infinity);
153
+ // NOTE the `<=`, and what it costs: a run created and failed inside the SAME MILLISECOND is
154
+ // not reported, because its failure does not sort after its own creation instant. Real drives
155
+ // spend far longer than a millisecond reaching a provider, so this is invisible in practice —
156
+ // but an in-memory test that creates and fails in one tick will see no finding and should
157
+ // separate the two rather than conclude the predicate is broken.
158
+ if (lastAt <= Math.max(gateOpened, lastEvidence, floor))
159
+ return undefined;
160
+ const settled = new Set([...run.completed_steps, ...run.failed_steps, ...run.skipped_steps]);
161
+ if (settled.has(lastEntry.step))
162
+ return undefined;
163
+ const ago = formatAgo(now.getTime() - lastAt);
164
+ // The total suffix appears ONLY when the ring has rolled — otherwise it would repeat a number
165
+ // the entries themselves already carry.
166
+ const rolled = field.total > field.entries.length;
167
+ const suffix = rolled ? `; ${String(field.total)} failures since ${field.first_failed_at}` : '';
168
+ return {
169
+ kind: 'drive_failing',
170
+ step: lastEntry.step,
171
+ reason: `the last drive attempt failed ${ago} (${lastEntry.error_class}): ${lastEntry.message}${suffix}`,
172
+ evidence: {
173
+ step: lastEntry.step,
174
+ error_class: lastEntry.error_class,
175
+ at: lastEntry.at,
176
+ total: field.total,
177
+ first_failed_at: field.first_failed_at,
178
+ // The discriminators reach the operator only if they travel — an operator debugging a
179
+ // 429 storm needs the status and the Retry-After, not just "api_status".
180
+ ...(lastEntry.last_observed_status !== undefined
181
+ ? { last_observed_status: lastEntry.last_observed_status }
182
+ : {}),
183
+ ...(lastEntry.retry_after_observed_ms !== undefined
184
+ ? { retry_after_observed_ms: lastEntry.retry_after_observed_ms }
185
+ : {}),
186
+ ...(lastEntry.declared_per_attempt_ms !== undefined
187
+ ? { declared_per_attempt_ms: lastEntry.declared_per_attempt_ms }
188
+ : {}),
189
+ ...(lastEntry.derived_ceiling_ms !== undefined
190
+ ? { derived_ceiling_ms: lastEntry.derived_ceiling_ms }
191
+ : {}),
192
+ },
193
+ };
194
+ }
195
+ /** Renders an elapsed span the way an operator reads it: "12s ago", "4m ago", "3h ago". */
196
+ function formatAgo(ms) {
197
+ const s = Math.max(0, Math.floor(ms / 1000));
198
+ if (s < 60)
199
+ return `${String(s)}s ago`;
200
+ const m = Math.floor(s / 60);
201
+ if (m < 60)
202
+ return `${String(m)}m ago`;
203
+ const h = Math.floor(m / 60);
204
+ if (h < 24)
205
+ return `${String(h)}h ago`;
206
+ return `${String(Math.floor(h / 24))}d ago`;
207
+ }
125
208
  /**
126
209
  * Classifies a run's health into zero or more typed findings. Pure, read-only, definition-
127
210
  * optional, `now`-injectable. See the module doc above for the full branch-conditioning table
@@ -231,6 +314,12 @@ export function classifyRunHealth(run, opts) {
231
314
  const structuredOutputDowngrade = findStructuredOutputDowngrades(run);
232
315
  if (structuredOutputDowngrade !== undefined)
233
316
  findings.push(structuredOutputDowngrade);
317
+ // issue #401: drive_failing — the run's last drive attempt failed and nothing has happened
318
+ // since. Deliberately NOT exclusive with `never_claimed_idle`: from 24h onward a
319
+ // failed-then-silent run legitimately trips both, and suppressing either would hide a fact.
320
+ const driveFailing = findDriveFailing(run, now);
321
+ if (driveFailing !== undefined)
322
+ findings.push(driveFailing);
234
323
  // issue #291: gate_expired_awaiting_drive — record-fields-only (never the definition), fires
235
324
  // for BOTH an enactable gate AND a finding-only one (expires_at present, on_expiry absent) —
236
325
  // the finding-only payload names its own disposition as 'finding_only' rather than omitting
@@ -1 +1 @@
1
- {"version":3,"file":"run-health.js","sourceRoot":"","sources":["../../src/engine/run-health.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-health.js","sourceRoot":"","sources":["../../src/engine/run-health.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { RunRecord } from '../types/run-record.js';
1
+ import type { RunRecord, EvidenceSnapshot } from '../types/run-record.js';
2
2
  import type { WorkflowDefinition, FinalizerTrigger } from '../types/workflow-definition.js';
3
3
  import type { SettlementDelta, SettlementResult, SettleStepOutcome } from '../types/settlement.js';
4
4
  /**
@@ -27,22 +27,77 @@ export declare function selectFinalizers(definition: WorkflowDefinition, settled
27
27
  /**
28
28
  * Derives the full set of finalizer triggers a terminal `outcome` satisfies for `record` (issue
29
29
  * #302, design record §Mechanics-1): `{outcome}` — always — plus `'completed_with_failed_steps'`
30
- * when `outcome === 'complete' ∧ record.failed_steps.length > 0` (a "mixed complete" seal — the
31
- * SAME class #304's `completed_with_failed_steps` run-health finding already surfaces at read
32
- * time; this is the mint-time trigger, sharing that one predicate).
30
+ * when `outcome === 'complete' ∧ record.failed_steps.length > 0` (a "mixed complete" seal).
31
+ *
32
+ * TWO SURFACES, ONE SHAPE, TWO MOMENTS. #304's `completed_with_failed_steps` run-health finding
33
+ * tests the same SHAPE (completed ∧ non-empty `failed_steps`), but it tests it at READ time on
34
+ * the final record, whereas this function is evaluated at MINT time, inside
35
+ * `applyTerminalPostconditions`, before any finalizer has run. There is no shared function and no
36
+ * shared evaluation point — only a shared shape.
37
+ *
38
+ * The moment is what separates them, on a real population: a finalizer's OWN failure joins
39
+ * `failed_steps` after the seal minted (see the failed arm below, where `delta.finalizer` is
40
+ * appended), so a run that completes CLEAN and whose finalizer then fails is seen by the
41
+ * read-time finding and was never seen by this trigger — the record it read had an empty
42
+ * `failed_steps`. The divergence runs one way only: `failed_steps` only grows, so everything this
43
+ * trigger fires on the finding also reports, and the finding additionally reports post-mint
44
+ * finalizer self-failures. Tracked at #374 (P5); this comment describes what the code does today
45
+ * and does not prejudge what that issue decides.
33
46
  *
34
47
  * Uniform across epochs (design record M1, deliberate): a second-epoch complete seal whose ONLY
35
48
  * `failed_steps` scar is a PRIOR epoch's finalizer self-failure (unresumable, so it never leaves
36
49
  * `failed_steps`) still fires this trigger — no exclusion of finalizer-declared step names. The
37
50
  * alternative (excluding finalizer names from the predicate) buys mint-time purity at the cost of
38
- * diverging from the read-time #304 finding's own uniform predicate; this design keeps ONE
39
- * predicate for both surfaces, deliberately.
51
+ * making the two surfaces disagree about a shape they can both see, which is a second divergence
52
+ * on top of the one above.
40
53
  *
41
54
  * Pure; this ONE function is the seam a future authorable tolerance threshold (SFN-style: fire
42
55
  * only when `failed_steps.length` exceeds some declared N) would extend — banked, not built
43
56
  * (design record R2).
44
57
  */
45
58
  export declare function deriveEffectiveTriggers(outcome: SettleStepOutcome, record: Pick<RunRecord, 'failed_steps'>): ReadonlySet<FinalizerTrigger>;
59
+ /**
60
+ * Renders the run-level cause for a run with MORE THAN ONE distinct failed step (issue #373).
61
+ *
62
+ * PRECONDITION — callers gate on `new Set(failedSteps).size > 1`. That gate is about which
63
+ * sentence SHAPE a call site wants, not about grammar safety: the single-failure sentence is each
64
+ * call site's own template (`Step 'a' failed: …`, `Guard step 'g' failed: …`), left where it is so
65
+ * there is exactly one spelling of each. Output below is grammatical at any count.
66
+ *
67
+ * The defect it fixes: `failed_steps` is append-ordered by settlement commit, so naming one step
68
+ * as THE cause named whichever failure settled LAST — and under true concurrency the lock race
69
+ * decided the culprit. The sentence below is order-independent by construction:
70
+ *
71
+ * - **dedup, then sort lexically.** A domain step cannot appear twice today, but the post-seal
72
+ * finalizer append across resume epochs has never been executed for duplication — dedup makes
73
+ * the count honest either way. Sorting is the order rule (Tekton `sort.Strings`, rustc
74
+ * `error_codes.sort()`); array order IS settle order, the instability this fix exists to kill.
75
+ * - **count first, no culprit, terminating verb.** The count is the one fact true regardless of
76
+ * order.
77
+ * - **a missing message yields a bare step name.** Never fabricated — the string `undefined` must
78
+ * not be constructible here.
79
+ */
80
+ export declare function renderFailCause(failedSteps: readonly string[], messages: ReadonlyMap<string, string>): string;
81
+ /**
82
+ * Last-`error`-snapshot-per-step, in one linear pass — the same last-per-step idiom
83
+ * `buildSettlementNamespace` already ships. `EvidenceSnapshot.error` is stored VERBATIM by
84
+ * `captureEvidence`, so these are the real per-step messages, not a reconstruction.
85
+ *
86
+ * A step can hold several error snapshots (retries, resume epochs); the LAST one is the message
87
+ * that describes the failure the record currently carries.
88
+ */
89
+ export declare function failureMessagesFromEvidence(evidence: readonly EvidenceSnapshot[]): Map<string, string>;
90
+ /**
91
+ * The evidence walk plus the call site's OWN in-hand message for its own step.
92
+ *
93
+ * At the guard sites the overlay is now DEFENSIVE, not load-bearing (issue #373 correction): the
94
+ * guard's evidence `error` carries the unresolvable path itself, so the path survives the evidence
95
+ * walk and the post-drain re-render alike. It is kept against caller-shaped evidence that might
96
+ * arrive without it.
97
+ *
98
+ * `undefined` never clobbers an evidence message.
99
+ */
100
+ export declare function failureMessagesWithOverlay(evidence: readonly EvidenceSnapshot[], step: string, inHand: string | undefined): Map<string, string>;
46
101
  /**
47
102
  * Applies one {@link SettlementDelta} against `fresh` — pure, synchronous, no I/O, no registry
48
103
  * (design record §7 CS-purity: `options` carries VALUES only). `definition` is passed per call
@@ -1 +1 @@
1
- {"version":3,"file":"settlement.d.ts","sourceRoot":"","sources":["../../src/engine/settlement.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAEhB,iBAAiB,EAQlB,MAAM,wBAAwB,CAAC;AA4GhC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,kBAAkB,EAC9B,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,EACrC,OAAO,EAAE,iBAAiB,GAAG,WAAW,CAAC,gBAAgB,CAAC,GACzD,MAAM,EAAE,CAoBV;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,GACtC,WAAW,CAAC,gBAAgB,CAAC,CAM/B;AA8/BD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,eAAe,EACtB,UAAU,EAAE,kBAAkB,EAC9B,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAA;CAAE,GACvB,gBAAgB,CAoBlB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,QAIE,CAAC"}
1
+ {"version":3,"file":"settlement.d.ts","sourceRoot":"","sources":["../../src/engine/settlement.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,SAAS,EAAW,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAEhB,iBAAiB,EAQlB,MAAM,wBAAwB,CAAC;AA8GhC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,kBAAkB,EAC9B,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,EACrC,OAAO,EAAE,iBAAiB,GAAG,WAAW,CAAC,gBAAgB,CAAC,GACzD,MAAM,EAAE,CAoBV;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,GACtC,WAAW,CAAC,gBAAgB,CAAC,CAM/B;AAoQD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,MAAM,CAmBR;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,GACpC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAMrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,EACrC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIrB;AA21BD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,eAAe,EACtB,UAAU,EAAE,kBAAkB,EAC9B,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAA;CAAE,GACvB,gBAAgB,CAoBlB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,QAIE,CAAC"}
@@ -1,4 +1,4 @@
1
- import { deriveRunPhase, isWorkflowComplete, findEligibleSteps, findEligibleGuardSteps, propagateSkips, } from './eligibility.js';
1
+ import { assertSealMarkersAgree, assertSealOutcomeCoherent, deriveRunPhase, isWorkflowComplete, findEligibleSteps, findEligibleGuardSteps, propagateSkips, } from './eligibility.js';
2
2
  import { deriveDefaultedSteps } from './defaulted-steps.js';
3
3
  import { captureEvidence } from '../evidence/snapshot.js';
4
4
  import { omitClaim } from './claim-liveness.js';
@@ -132,16 +132,29 @@ export function selectFinalizers(definition, settledStepNames, outcome) {
132
132
  /**
133
133
  * Derives the full set of finalizer triggers a terminal `outcome` satisfies for `record` (issue
134
134
  * #302, design record §Mechanics-1): `{outcome}` — always — plus `'completed_with_failed_steps'`
135
- * when `outcome === 'complete' ∧ record.failed_steps.length > 0` (a "mixed complete" seal — the
136
- * SAME class #304's `completed_with_failed_steps` run-health finding already surfaces at read
137
- * time; this is the mint-time trigger, sharing that one predicate).
135
+ * when `outcome === 'complete' ∧ record.failed_steps.length > 0` (a "mixed complete" seal).
136
+ *
137
+ * TWO SURFACES, ONE SHAPE, TWO MOMENTS. #304's `completed_with_failed_steps` run-health finding
138
+ * tests the same SHAPE (completed ∧ non-empty `failed_steps`), but it tests it at READ time on
139
+ * the final record, whereas this function is evaluated at MINT time, inside
140
+ * `applyTerminalPostconditions`, before any finalizer has run. There is no shared function and no
141
+ * shared evaluation point — only a shared shape.
142
+ *
143
+ * The moment is what separates them, on a real population: a finalizer's OWN failure joins
144
+ * `failed_steps` after the seal minted (see the failed arm below, where `delta.finalizer` is
145
+ * appended), so a run that completes CLEAN and whose finalizer then fails is seen by the
146
+ * read-time finding and was never seen by this trigger — the record it read had an empty
147
+ * `failed_steps`. The divergence runs one way only: `failed_steps` only grows, so everything this
148
+ * trigger fires on the finding also reports, and the finding additionally reports post-mint
149
+ * finalizer self-failures. Tracked at #374 (P5); this comment describes what the code does today
150
+ * and does not prejudge what that issue decides.
138
151
  *
139
152
  * Uniform across epochs (design record M1, deliberate): a second-epoch complete seal whose ONLY
140
153
  * `failed_steps` scar is a PRIOR epoch's finalizer self-failure (unresumable, so it never leaves
141
154
  * `failed_steps`) still fires this trigger — no exclusion of finalizer-declared step names. The
142
155
  * alternative (excluding finalizer names from the predicate) buys mint-time purity at the cost of
143
- * diverging from the read-time #304 finding's own uniform predicate; this design keeps ONE
144
- * predicate for both surfaces, deliberately.
156
+ * making the two surfaces disagree about a shape they can both see, which is a second divergence
157
+ * on top of the one above.
145
158
  *
146
159
  * Pure; this ONE function is the seam a future authorable tolerance threshold (SFN-style: fire
147
160
  * only when `failed_steps.length` exceeds some declared N) would extend — banked, not built
@@ -204,13 +217,28 @@ function mintFresh(record, definition, outcome) {
204
217
  * simply the post-write value, read back explicitly (not assumed) so a future caller that ever
205
218
  * violates that precondition fails loudly via a wrong `transitioned` value rather than silently.
206
219
  */
207
- function applyTerminalPostconditions(record, definition, mintOutcome, stampDefaulted) {
220
+ function applyTerminalPostconditions(record, definition, mintOutcome, stampDefaulted,
221
+ /**
222
+ * issue #367: the ARM this settlement branch seals with — per-branch knowledge that exists
223
+ * exactly once, at the seal site, at seal time (re-inferring it later is lossy in principle:
224
+ * `guard_abort` and `handler_abort` differ only by writer-owned prose). Stamped IFF this apply
225
+ * TRANSITIONED; the eight call sites in this file are the whole settlement-transform writer
226
+ * census. A stale prior seal never survives a non-terminal fork — see the strip below.
227
+ */
228
+ seal) {
208
229
  const transitioned = record.terminal_state === true;
209
- let sealed = record;
230
+ // issue #367: strip any stale prior seal FIRST, so a non-terminal fork can never carry one out.
231
+ const { sealed_by: _priorSeal, ...base } = record;
232
+ let sealed = transitioned
233
+ ? {
234
+ ...base,
235
+ sealed_by: { arm: seal.arm, ...(seal.step !== undefined ? { step: seal.step } : {}) },
236
+ }
237
+ : base;
210
238
  if (transitioned) {
211
239
  // On terminal false→true edge: mintFresh (§4.1), same atomic write.
212
- const ledger = mintFresh(record, definition, mintOutcome);
213
- sealed = { ...record, ...(ledger !== undefined ? { finalizer_ledger: ledger } : {}) };
240
+ const ledger = mintFresh(sealed, definition, mintOutcome);
241
+ sealed = { ...sealed, ...(ledger !== undefined ? { finalizer_ledger: ledger } : {}) };
214
242
  // defaulted_steps stamped IFF a COMPLETE-terminal edge (§4.2; the FM-5/#232 guard) — never on
215
243
  // a fail/abort seal, even one that terminalizes.
216
244
  if (stampDefaulted) {
@@ -218,6 +246,11 @@ function applyTerminalPostconditions(record, definition, mintOutcome, stampDefau
218
246
  if (defaultedSteps.length > 0)
219
247
  sealed = { ...sealed, defaulted_steps: defaultedSteps };
220
248
  }
249
+ // issue #367: the two transform-scoped congruence assertions, on the record THIS function
250
+ // produces — never universal (a universal marker law reds the published TERMINAL_STATE_ONLY
251
+ // fixture by construction).
252
+ assertSealMarkersAgree(sealed);
253
+ assertSealOutcomeCoherent(sealed);
221
254
  }
222
255
  const withPhase = { ...sealed, run_phase: deriveRunPhase(sealed) };
223
256
  return { run: withPhase, transitioned };
@@ -323,7 +356,10 @@ function applyAbortEdge(fresh, withMembership, step, abort, definition, now) {
323
356
  // §4 shared postconditions: abort NEVER stamps defaulted_steps (the FM-5/#232 guard — only the
324
357
  // complete edge does); `transitioned` is always true here (isTerminal(fresh) was already
325
358
  // refused above, and `aborted.terminal_state` is unconditionally true).
326
- const { run, transitioned } = applyTerminalPostconditions(aborted, definition, 'abort', false);
359
+ const { run, transitioned } = applyTerminalPostconditions(aborted, definition, 'abort', false, {
360
+ arm: 'handler_abort',
361
+ step,
362
+ });
327
363
  return {
328
364
  applied: true,
329
365
  run,
@@ -331,6 +367,94 @@ function applyAbortEdge(fresh, withMembership, step, abort, definition, now) {
331
367
  pendingFinalizers: pendingFinalizerNames(run.finalizer_ledger),
332
368
  };
333
369
  }
370
+ // ---------------------------------------------------------------------------
371
+ // The run's one-line fail cause (issue #373)
372
+ // ---------------------------------------------------------------------------
373
+ /** Per-message cap before the truncation marker — sized from a real-corpus measurement
374
+ * (2026-08-20, n=31 evidence error messages from a live runsDir: p50=21, p95=248, max=254 — 19%
375
+ * of real messages were truncated at the previous unanchored 120; 256 keeps the whole observed
376
+ * distribution verbatim). Re-measure before changing; the 1024 sentence cap remains the global
377
+ * bound. */
378
+ const FAIL_CAUSE_MESSAGE_CAP = 256;
379
+ /** Hard cap on the WHOLE sentence, marker included — the returned string is never longer than
380
+ * this. (Tekton caps its joined validation detail at 1024 + `"..."`, i.e. 1027 out; realm's cap
381
+ * is inclusive, so an overflowing sentence lands at exactly 1024.) */
382
+ const FAIL_CAUSE_SENTENCE_CAP = 1024;
383
+ /** ASCII, not `…` — the marker travels through logs, terminals and a Postgres text column. */
384
+ const FAIL_CAUSE_TRUNCATION = '...';
385
+ /**
386
+ * Renders the run-level cause for a run with MORE THAN ONE distinct failed step (issue #373).
387
+ *
388
+ * PRECONDITION — callers gate on `new Set(failedSteps).size > 1`. That gate is about which
389
+ * sentence SHAPE a call site wants, not about grammar safety: the single-failure sentence is each
390
+ * call site's own template (`Step 'a' failed: …`, `Guard step 'g' failed: …`), left where it is so
391
+ * there is exactly one spelling of each. Output below is grammatical at any count.
392
+ *
393
+ * The defect it fixes: `failed_steps` is append-ordered by settlement commit, so naming one step
394
+ * as THE cause named whichever failure settled LAST — and under true concurrency the lock race
395
+ * decided the culprit. The sentence below is order-independent by construction:
396
+ *
397
+ * - **dedup, then sort lexically.** A domain step cannot appear twice today, but the post-seal
398
+ * finalizer append across resume epochs has never been executed for duplication — dedup makes
399
+ * the count honest either way. Sorting is the order rule (Tekton `sort.Strings`, rustc
400
+ * `error_codes.sort()`); array order IS settle order, the instability this fix exists to kill.
401
+ * - **count first, no culprit, terminating verb.** The count is the one fact true regardless of
402
+ * order.
403
+ * - **a missing message yields a bare step name.** Never fabricated — the string `undefined` must
404
+ * not be constructible here.
405
+ */
406
+ export function renderFailCause(failedSteps, messages) {
407
+ const distinct = [...new Set(failedSteps)].sort();
408
+ const rendered = distinct.map((step) => {
409
+ const message = messages.get(step);
410
+ if (message === undefined)
411
+ return step;
412
+ const capped = message.length > FAIL_CAUSE_MESSAGE_CAP
413
+ ? message.slice(0, FAIL_CAUSE_MESSAGE_CAP) + FAIL_CAUSE_TRUNCATION
414
+ : message;
415
+ return `${step} ("${capped}")`;
416
+ });
417
+ // Grammatical across the WHOLE input domain, not just the domain the call sites use — a public
418
+ // export that can emit "1 steps failed" is wrong output, precondition or no precondition
419
+ // (ninja's own discipline: "subcommand failed" / "subcommands failed").
420
+ const sentence = `${distinct.length} step${distinct.length === 1 ? '' : 's'} failed: ${rendered.join(', ')}.`;
421
+ return sentence.length > FAIL_CAUSE_SENTENCE_CAP
422
+ ? sentence.slice(0, FAIL_CAUSE_SENTENCE_CAP - FAIL_CAUSE_TRUNCATION.length) +
423
+ FAIL_CAUSE_TRUNCATION
424
+ : sentence;
425
+ }
426
+ /**
427
+ * Last-`error`-snapshot-per-step, in one linear pass — the same last-per-step idiom
428
+ * `buildSettlementNamespace` already ships. `EvidenceSnapshot.error` is stored VERBATIM by
429
+ * `captureEvidence`, so these are the real per-step messages, not a reconstruction.
430
+ *
431
+ * A step can hold several error snapshots (retries, resume epochs); the LAST one is the message
432
+ * that describes the failure the record currently carries.
433
+ */
434
+ export function failureMessagesFromEvidence(evidence) {
435
+ const messages = new Map();
436
+ for (const snapshot of evidence) {
437
+ if (snapshot.error !== undefined)
438
+ messages.set(snapshot.step_id, snapshot.error);
439
+ }
440
+ return messages;
441
+ }
442
+ /**
443
+ * The evidence walk plus the call site's OWN in-hand message for its own step.
444
+ *
445
+ * At the guard sites the overlay is now DEFENSIVE, not load-bearing (issue #373 correction): the
446
+ * guard's evidence `error` carries the unresolvable path itself, so the path survives the evidence
447
+ * walk and the post-drain re-render alike. It is kept against caller-shaped evidence that might
448
+ * arrive without it.
449
+ *
450
+ * `undefined` never clobbers an evidence message.
451
+ */
452
+ export function failureMessagesWithOverlay(evidence, step, inHand) {
453
+ const messages = failureMessagesFromEvidence(evidence);
454
+ if (inHand !== undefined)
455
+ messages.set(step, inHand);
456
+ return messages;
457
+ }
334
458
  /** complete / fail: the TWO-DISJUNCT `isComplete` predicate (execution-loop.ts :2579-2583 /
335
459
  * :2237-2241 — named, not implied). */
336
460
  function applyCompleteOrFailEdge(withMembership, step, outcome, failureMessage, definition) {
@@ -344,20 +468,30 @@ function applyCompleteOrFailEdge(withMembership, step, outcome, failureMessage,
344
468
  (withSkipped.in_progress_steps.length === 0 &&
345
469
  findEligibleSteps(definition, withSkipped).length === 0 &&
346
470
  findEligibleGuardSteps(definition, withSkipped).length === 0);
471
+ // issue #373: with MORE THAN ONE distinct failure the run has no single culprit, and naming one
472
+ // named whichever settled last. At exactly one failure the sentence is unchanged — including the
473
+ // `?? 'unknown error'` fallback, which is this site's shape and stays this site's shape.
474
+ const failCause = new Set(withSkipped.failed_steps).size > 1
475
+ ? renderFailCause(withSkipped.failed_steps, failureMessagesWithOverlay(withSkipped.evidence, step, failureMessage))
476
+ : `Step '${step}' failed: ${failureMessage ?? 'unknown error'}`;
347
477
  const draft = {
348
478
  ...withSkipped,
349
479
  terminal_state: isComplete,
350
480
  ...(isComplete
351
481
  ? {
352
482
  terminal_reason: outcome === 'complete'
353
- ? 'Workflow completed.' // eligibility.ts:47 keys deriveRunPhase's 'completed' on this
354
- : `Step '${step}' failed: ${failureMessage ?? 'unknown error'}`,
483
+ ? 'Workflow completed.' // the legacy-classifier leg keys 'completed' on this (#367)
484
+ : failCause,
355
485
  }
356
486
  : {}),
357
487
  };
358
488
  // §4 shared postconditions: defaulted_steps stamps IFF this is a COMPLETE-terminal edge — never
359
489
  // on a fail seal, even one that terminalizes.
360
- const { run, transitioned } = applyTerminalPostconditions(draft, definition, outcome, outcome === 'complete' && isComplete);
490
+ const { run, transitioned } = applyTerminalPostconditions(draft, definition, outcome, outcome === 'complete' && isComplete,
491
+ // issue #367: validation exhaustion is deliberately NOT a distinct arm — a VALIDATION_EXHAUSTED
492
+ // fail seals 'step_failure' like any other; the distinction lives in defaulted_steps and the
493
+ // step diagnostics. Never re-introduce a failure-code ternary here.
494
+ { arm: outcome === 'complete' ? 'complete' : 'step_failure', step });
361
495
  return {
362
496
  applied: true,
363
497
  run,
@@ -533,10 +667,11 @@ now) {
533
667
  const draft = {
534
668
  ...withSkipped,
535
669
  terminal_state: isComplete,
536
- // eligibility.ts:47 keys deriveRunPhase's 'completed' on this exact string.
670
+ // The legacy-classifier leg of deriveRunPhase keys 'completed' on this exact string
671
+ // for the LEGACY population only; on a stamped record the arm derives (issue #367).
537
672
  ...(isComplete ? { terminal_reason: 'Workflow completed.' } : {}),
538
673
  };
539
- const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'complete', isComplete);
674
+ const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'complete', isComplete, { arm: 'gate_resolution_complete', step: stepName });
540
675
  return {
541
676
  applied: true,
542
677
  run,
@@ -640,7 +775,7 @@ function applyExpireGate(fresh, delta, definition, now) {
640
775
  terminal_state: isComplete,
641
776
  ...(isComplete ? { terminal_reason: 'Workflow completed.' } : {}),
642
777
  };
643
- const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'complete', isComplete);
778
+ const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'complete', isComplete, { arm: 'gate_expiry_default', step: stepName });
644
779
  return {
645
780
  applied: true,
646
781
  run,
@@ -698,7 +833,10 @@ function applyExpireGate(fresh, delta, definition, now) {
698
833
  };
699
834
  // §4 shared postconditions: abort NEVER stamps defaulted_steps (the FM-5/#232 guard);
700
835
  // `transitioned` is always true (isTerminal(fresh) already refused above).
701
- const { run, transitioned } = applyTerminalPostconditions(aborted, definition, 'abort', false);
836
+ const { run, transitioned } = applyTerminalPostconditions(aborted, definition, 'abort', false, {
837
+ arm: 'gate_expiry_abort',
838
+ step: stepName,
839
+ });
702
840
  return {
703
841
  applied: true,
704
842
  run,
@@ -782,13 +920,25 @@ function applySettleGuard(fresh, delta, definition) {
782
920
  skipped_steps: propagated.skipped,
783
921
  skip_details: propagated.details,
784
922
  };
923
+ // issue #373: this site names the guard alone even when other steps had already failed
924
+ // (executed with failed_steps=["fail_a","g"]). At >1 distinct failure it renders the whole
925
+ // set; at exactly one the sentence below is byte-unchanged.
926
+ const guardPath = `unresolvable path '${resolutionError.unresolvable_path}'`;
785
927
  const draft = {
786
928
  ...withSkipped,
787
929
  terminal_state: true,
788
- // execution-loop.ts:3671 parity.
789
- terminal_reason: `Guard step '${step}' failed: unresolvable path '${resolutionError.unresolvable_path}'`,
930
+ // execution-loop.ts:4812 parity.
931
+ terminal_reason: new Set(withSkipped.failed_steps).size > 1
932
+ ? renderFailCause(withSkipped.failed_steps,
933
+ // Defensive once evidence carries the path (issue #373 correction); kept against
934
+ // caller-shaped evidence that arrives without it.
935
+ failureMessagesWithOverlay(withSkipped.evidence, step, guardPath))
936
+ : `Guard step '${step}' failed: ${guardPath}`,
790
937
  };
791
- const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'fail', false);
938
+ const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'fail', false, {
939
+ arm: 'guard_resolution_error',
940
+ step,
941
+ });
792
942
  return {
793
943
  applied: true,
794
944
  run,
@@ -820,7 +970,10 @@ function applySettleGuard(fresh, delta, definition) {
820
970
  ...(abort.abort_message !== undefined ? { abort_message: abort.abort_message } : {}),
821
971
  },
822
972
  };
823
- const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'abort', false);
973
+ const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'abort', false, {
974
+ arm: 'guard_abort',
975
+ step,
976
+ });
824
977
  return {
825
978
  applied: true,
826
979
  run,
@@ -847,11 +1000,11 @@ function applySettleGuard(fresh, delta, definition) {
847
1000
  const draft = {
848
1001
  ...withSkipped,
849
1002
  terminal_state: isComplete,
850
- // execution-loop.ts:3675-3705 parity; eligibility.ts:47 keys deriveRunPhase's 'completed' on
1003
+ // execution-loop.ts:3675-3705 parity; the legacy-classifier leg keys 'completed' on
851
1004
  // this exact string.
852
1005
  ...(isComplete ? { terminal_reason: 'Workflow completed.' } : {}),
853
1006
  };
854
- const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'complete', isComplete);
1007
+ const { run, transitioned } = applyTerminalPostconditions(draft, definition, 'complete', isComplete, { arm: 'guard_pass_complete', step });
855
1008
  return {
856
1009
  applied: true,
857
1010
  run,
@@ -999,9 +1152,21 @@ function applyMarkFinalizer(fresh, delta) {
999
1152
  failed_steps: [...fresh.failed_steps, delta.finalizer],
1000
1153
  evidence: [...fresh.evidence, delta.evidence],
1001
1154
  };
1155
+ const phase = deriveRunPhase(withLedgerAndEvidence);
1156
+ // issue #373: the finalizer's OWN failure joins `failed_steps` here, AFTER the seal minted the
1157
+ // sentence — which is how a sealed cause went stale and undercounted the record. Re-render from
1158
+ // the grown record, but ONLY on the failed arm: on the completed arm nothing grew, and a
1159
+ // re-render there would rebuild without the seal site's in-hand overlay (the guard sites' path
1160
+ // text) and silently drop it.
1161
+ const failedArmCause = delta.result !== 'completed' &&
1162
+ phase === 'failed' &&
1163
+ new Set(withLedgerAndEvidence.failed_steps).size > 1
1164
+ ? renderFailCause(withLedgerAndEvidence.failed_steps, failureMessagesFromEvidence(withLedgerAndEvidence.evidence))
1165
+ : undefined;
1002
1166
  const run = {
1003
1167
  ...withLedgerAndEvidence,
1004
- run_phase: deriveRunPhase(withLedgerAndEvidence),
1168
+ run_phase: phase,
1169
+ ...(failedArmCause !== undefined ? { terminal_reason: failedArmCause } : {}),
1005
1170
  };
1006
1171
  return {
1007
1172
  applied: true,