@bastani/atomic 0.9.28-alpha.1 → 0.9.28-alpha.2

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 (202) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/builtin/intercom/package.json +1 -1
  3. package/dist/builtin/mcp/package.json +1 -1
  4. package/dist/builtin/subagents/package.json +1 -1
  5. package/dist/builtin/web-access/package.json +1 -1
  6. package/dist/builtin/workflows/CHANGELOG.md +23 -0
  7. package/dist/builtin/workflows/builtin/{chunk-wz8v67bn.js → chunk-aqv8ny38.js} +257 -259
  8. package/dist/builtin/workflows/builtin/{chunk-f61w0hpm.js → chunk-br4ac9a3.js} +1 -1
  9. package/dist/builtin/workflows/builtin/{chunk-tecnpe8j.js → chunk-p3xmajmj.js} +438 -39
  10. package/dist/builtin/workflows/builtin/chunk-p6jagvyf.js +8 -0
  11. package/dist/builtin/workflows/builtin/goal.js +2 -2
  12. package/dist/builtin/workflows/builtin/index.js +4 -4
  13. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  14. package/dist/builtin/workflows/package.json +1 -1
  15. package/dist/builtin/workflows/src/authoring.d.ts +14 -0
  16. package/dist/builtin/workflows/src/extension/index.bundle.mjs +107577 -106722
  17. package/dist/builtin/workflows/src/index.js +42284 -41141
  18. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +16 -11
  19. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +16 -1
  20. package/dist/cli/credential-print.d.ts +1 -1
  21. package/dist/cli/credential-print.d.ts.map +1 -1
  22. package/dist/cli/credential-print.js +2 -56
  23. package/dist/cli/credential-print.js.map +1 -1
  24. package/dist/core/agent-session-accessors.d.ts.map +1 -1
  25. package/dist/core/agent-session-accessors.js +6 -1
  26. package/dist/core/agent-session-accessors.js.map +1 -1
  27. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  28. package/dist/core/agent-session-compaction.js +20 -3
  29. package/dist/core/agent-session-compaction.js.map +1 -1
  30. package/dist/core/agent-session-events.d.ts.map +1 -1
  31. package/dist/core/agent-session-events.js +2 -1
  32. package/dist/core/agent-session-events.js.map +1 -1
  33. package/dist/core/agent-session-extension-bindings.d.ts +6 -0
  34. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  35. package/dist/core/agent-session-extension-bindings.js +87 -7
  36. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  37. package/dist/core/agent-session-methods.d.ts +2 -1
  38. package/dist/core/agent-session-methods.d.ts.map +1 -1
  39. package/dist/core/agent-session-methods.js.map +1 -1
  40. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  41. package/dist/core/agent-session-prompt.js +14 -1
  42. package/dist/core/agent-session-prompt.js.map +1 -1
  43. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  44. package/dist/core/agent-session-tool-registry.js +1 -0
  45. package/dist/core/agent-session-tool-registry.js.map +1 -1
  46. package/dist/core/agent-session-types.d.ts +1 -0
  47. package/dist/core/agent-session-types.d.ts.map +1 -1
  48. package/dist/core/agent-session-types.js.map +1 -1
  49. package/dist/core/compaction/classifier-compaction.d.ts +13 -0
  50. package/dist/core/compaction/classifier-compaction.d.ts.map +1 -0
  51. package/dist/core/compaction/classifier-compaction.js +110 -0
  52. package/dist/core/compaction/classifier-compaction.js.map +1 -0
  53. package/dist/core/compaction/compaction-boundary.d.ts.map +1 -1
  54. package/dist/core/compaction/compaction-boundary.js +2 -6
  55. package/dist/core/compaction/compaction-boundary.js.map +1 -1
  56. package/dist/core/compaction/compaction-runner.d.ts +16 -1
  57. package/dist/core/compaction/compaction-runner.d.ts.map +1 -1
  58. package/dist/core/compaction/compaction-runner.js +97 -12
  59. package/dist/core/compaction/compaction-runner.js.map +1 -1
  60. package/dist/core/compaction/compaction-types.d.ts +18 -1
  61. package/dist/core/compaction/compaction-types.d.ts.map +1 -1
  62. package/dist/core/compaction/compaction-types.js +1 -1
  63. package/dist/core/compaction/compaction-types.js.map +1 -1
  64. package/dist/core/compaction/fallback-planner.d.ts +1 -0
  65. package/dist/core/compaction/fallback-planner.d.ts.map +1 -1
  66. package/dist/core/compaction/fallback-planner.js +2 -0
  67. package/dist/core/compaction/fallback-planner.js.map +1 -1
  68. package/dist/core/compaction/index.d.ts +3 -0
  69. package/dist/core/compaction/index.d.ts.map +1 -1
  70. package/dist/core/compaction/index.js +3 -0
  71. package/dist/core/compaction/index.js.map +1 -1
  72. package/dist/core/compaction/model-resolver.d.ts +16 -0
  73. package/dist/core/compaction/model-resolver.d.ts.map +1 -0
  74. package/dist/core/compaction/model-resolver.js +18 -0
  75. package/dist/core/compaction/model-resolver.js.map +1 -0
  76. package/dist/core/compaction/morph-compaction.d.ts +14 -0
  77. package/dist/core/compaction/morph-compaction.d.ts.map +1 -0
  78. package/dist/core/compaction/morph-compaction.js +99 -0
  79. package/dist/core/compaction/morph-compaction.js.map +1 -0
  80. package/dist/core/compaction/pi-summary-fallback.d.ts +34 -0
  81. package/dist/core/compaction/pi-summary-fallback.d.ts.map +1 -0
  82. package/dist/core/compaction/pi-summary-fallback.js +357 -0
  83. package/dist/core/compaction/pi-summary-fallback.js.map +1 -0
  84. package/dist/core/compaction/planner-outcome.d.ts +10 -6
  85. package/dist/core/compaction/planner-outcome.d.ts.map +1 -1
  86. package/dist/core/compaction/planner-outcome.js +11 -4
  87. package/dist/core/compaction/planner-outcome.js.map +1 -1
  88. package/dist/core/compaction/range-planner-diagnostics.d.ts +3 -1
  89. package/dist/core/compaction/range-planner-diagnostics.d.ts.map +1 -1
  90. package/dist/core/compaction/range-planner-diagnostics.js +11 -0
  91. package/dist/core/compaction/range-planner-diagnostics.js.map +1 -1
  92. package/dist/core/compaction/range-planner.d.ts +3 -3
  93. package/dist/core/compaction/range-planner.d.ts.map +1 -1
  94. package/dist/core/compaction/range-planner.js +59 -28
  95. package/dist/core/compaction/range-planner.js.map +1 -1
  96. package/dist/core/compaction/region-trimming.d.ts.map +1 -1
  97. package/dist/core/compaction/region-trimming.js +7 -0
  98. package/dist/core/compaction/region-trimming.js.map +1 -1
  99. package/dist/core/compaction/structured-compaction-input.d.ts +19 -0
  100. package/dist/core/compaction/structured-compaction-input.d.ts.map +1 -0
  101. package/dist/core/compaction/structured-compaction-input.js +70 -0
  102. package/dist/core/compaction/structured-compaction-input.js.map +1 -0
  103. package/dist/core/compaction/transcript-serialization.d.ts +1 -0
  104. package/dist/core/compaction/transcript-serialization.d.ts.map +1 -1
  105. package/dist/core/compaction/transcript-serialization.js +26 -0
  106. package/dist/core/compaction/transcript-serialization.js.map +1 -1
  107. package/dist/core/extensions/api-types.d.ts +2 -2
  108. package/dist/core/extensions/api-types.d.ts.map +1 -1
  109. package/dist/core/extensions/api-types.js.map +1 -1
  110. package/dist/core/extensions/context-types.d.ts +1 -0
  111. package/dist/core/extensions/context-types.d.ts.map +1 -1
  112. package/dist/core/extensions/context-types.js.map +1 -1
  113. package/dist/core/extensions/loader-api.js.map +1 -1
  114. package/dist/core/extensions/runner-context.d.ts +10 -4
  115. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  116. package/dist/core/extensions/runner-context.js +47 -3
  117. package/dist/core/extensions/runner-context.js.map +1 -1
  118. package/dist/core/extensions/runner.d.ts +10 -3
  119. package/dist/core/extensions/runner.d.ts.map +1 -1
  120. package/dist/core/extensions/runner.js +31 -7
  121. package/dist/core/extensions/runner.js.map +1 -1
  122. package/dist/core/extensions/workflow-events.d.ts +49 -0
  123. package/dist/core/extensions/workflow-events.d.ts.map +1 -1
  124. package/dist/core/extensions/workflow-events.js.map +1 -1
  125. package/dist/core/extensions/workflow-run-control-hub.d.ts +16 -4
  126. package/dist/core/extensions/workflow-run-control-hub.d.ts.map +1 -1
  127. package/dist/core/extensions/workflow-run-control-hub.js +72 -1
  128. package/dist/core/extensions/workflow-run-control-hub.js.map +1 -1
  129. package/dist/core/extensions/workflow-run-control.d.ts +11 -3
  130. package/dist/core/extensions/workflow-run-control.d.ts.map +1 -1
  131. package/dist/core/extensions/workflow-run-control.js.map +1 -1
  132. package/dist/core/messages.d.ts +1 -0
  133. package/dist/core/messages.d.ts.map +1 -1
  134. package/dist/core/messages.js +5 -1
  135. package/dist/core/messages.js.map +1 -1
  136. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  137. package/dist/core/remote-catalog-provider.js +3 -0
  138. package/dist/core/remote-catalog-provider.js.map +1 -1
  139. package/dist/core/session-manager-history.d.ts.map +1 -1
  140. package/dist/core/session-manager-history.js +4 -2
  141. package/dist/core/session-manager-history.js.map +1 -1
  142. package/dist/core/settings-manager-basic-accessors.d.ts +2 -0
  143. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  144. package/dist/core/settings-manager-basic-accessors.js +29 -0
  145. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  146. package/dist/core/settings-types.d.ts +1 -0
  147. package/dist/core/settings-types.d.ts.map +1 -1
  148. package/dist/core/settings-types.js.map +1 -1
  149. package/dist/core/transcript.d.ts +58 -0
  150. package/dist/core/transcript.d.ts.map +1 -0
  151. package/dist/core/transcript.js +185 -0
  152. package/dist/core/transcript.js.map +1 -0
  153. package/dist/extensions/herdr/index.d.ts.map +1 -1
  154. package/dist/extensions/herdr/index.js +15 -10
  155. package/dist/extensions/herdr/index.js.map +1 -1
  156. package/dist/extensions/herdr/pane-owner.d.ts +6 -2
  157. package/dist/extensions/herdr/pane-owner.d.ts.map +1 -1
  158. package/dist/extensions/herdr/pane-owner.js +19 -4
  159. package/dist/extensions/herdr/pane-owner.js.map +1 -1
  160. package/dist/index.d.ts +2 -0
  161. package/dist/index.d.ts.map +1 -1
  162. package/dist/index.js +2 -0
  163. package/dist/index.js.map +1 -1
  164. package/dist/modes/interactive/components/compaction-boundary-message.d.ts +2 -0
  165. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -1
  166. package/dist/modes/interactive/components/compaction-boundary-message.js +15 -3
  167. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  168. package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
  169. package/dist/modes/interactive/components/settings-selector-items.js +43 -0
  170. package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
  171. package/dist/modes/interactive/components/settings-selector-types.d.ts +6 -0
  172. package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
  173. package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
  174. package/dist/modes/interactive/interactive-prompt-turn.js +6 -4
  175. package/dist/modes/interactive/interactive-prompt-turn.js.map +1 -1
  176. package/dist/modes/interactive/interactive-render-chat.js +13 -1
  177. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  178. package/dist/modes/interactive/interactive-selectors.js +8 -0
  179. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  180. package/dist/modes/interactive/interactive-session-runtime.js +2 -0
  181. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  182. package/dist/modes/interactive/interactive-startup.js +1 -1
  183. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  184. package/dist/utils/credential-redaction.d.ts +2 -0
  185. package/dist/utils/credential-redaction.d.ts.map +1 -0
  186. package/dist/utils/credential-redaction.js +20 -0
  187. package/dist/utils/credential-redaction.js.map +1 -0
  188. package/docs/compaction/reference.md +10 -4
  189. package/docs/compaction.md +40 -8
  190. package/docs/docs.json +1 -0
  191. package/docs/extensions/api-reference.md +4 -0
  192. package/docs/extensions/events.md +2 -2
  193. package/docs/providers.md +12 -1
  194. package/docs/sdk/reference.md +16 -1
  195. package/docs/sdk/web-server.md +325 -0
  196. package/docs/sdk.md +83 -1
  197. package/docs/security.md +1 -1
  198. package/docs/workflows/api-reference.md +71 -3
  199. package/docs/workflows/builtins.md +4 -0
  200. package/docs/workflows/operations.md +12 -4
  201. package/npm-shrinkwrap.json +32 -32
  202. package/package.json +3 -3
@@ -35,10 +35,9 @@ import {
35
35
  contradictedStopReviewLoopGap,
36
36
  consolidateFindingsBatch,
37
37
  parseFailureDiagnostics,
38
- reviewerFailureText,
39
38
  summarizeReviewConvergence,
40
39
  reverify_consolidated_batch
41
- } from "./chunk-tecnpe8j.js";
40
+ } from "./chunk-p3xmajmj.js";
42
41
  import {
43
42
  VERIFICATION_SCALE
44
43
  } from "./chunk-n1910xc4.js";
@@ -52,6 +51,12 @@ import { Type as Type2 } from "typebox";
52
51
  // dist/builtin/workflows/builtin/goal-runner.ts
53
52
  import { join as join3 } from "node:path";
54
53
 
54
+ // dist/builtin/workflows/src/runs/foreground/stage-runner-structured-output.ts
55
+ import { createStructuredOutputTool } from "@bastani/atomic";
56
+ function isWorkflowStructuredOutputContractError(error) {
57
+ return error instanceof Error && "code" in error && error.code === "ATOMIC_WORKFLOW_STRUCTURED_OUTPUT_CONTRACT";
58
+ }
59
+
55
60
  // dist/builtin/workflows/builtin/goal-schemas.ts
56
61
  import { Type } from "typebox";
57
62
  var reviewFindingSchema = Type.Object({
@@ -163,100 +168,7 @@ async function writeReviewRoundArtifact(artifactDir, reviews, consolidatedFindin
163
168
  import { randomUUID } from "node:crypto";
164
169
  import { readFile, rename, rm, writeFile as writeFile2 } from "node:fs/promises";
165
170
  import { dirname, join as join2 } from "node:path";
166
- var LEDGER_STATE_FILENAME = "goal-ledger-state.json";
167
- function withoutTurn2(value) {
168
- const copy = { ...value };
169
- delete copy.turn;
170
- return copy;
171
- }
172
- function modelVisibleLedger(ledger) {
173
- return {
174
- goal_id: ledger.goal_id,
175
- objective: ledger.objective,
176
- acceptance_criteria: ledger.acceptance_criteria,
177
- status: ledger.status,
178
- created_at: ledger.created_at,
179
- updated_at: ledger.updated_at,
180
- receipts: ledger.receipts.map(withoutTurn2),
181
- reviews: ledger.reviews.map(withoutTurn2),
182
- blockers: ledger.blockers.map(withoutTurn2),
183
- decisions: ledger.decisions.map(withoutTurn2),
184
- lifecycle: ledger.lifecycle.map(withoutTurn2),
185
- reverification: ledger.reverification ?? [],
186
- convergence: ledger.convergence ?? []
187
- };
188
- }
189
- function goalLedgerStatePath(ledgerPath) {
190
- return join2(dirname(ledgerPath), LEDGER_STATE_FILENAME);
191
- }
192
- function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
193
- ledger.lifecycle.push({
194
- turn,
195
- event,
196
- status: ledger.status,
197
- at: new Date().toISOString(),
198
- summary
199
- });
200
- }
201
- async function readExistingGoalLedger(ledgerPath) {
202
- let contents;
203
- try {
204
- contents = await readFile(goalLedgerStatePath(ledgerPath), "utf8");
205
- } catch (error) {
206
- if (error instanceof Error && "code" in error && error.code === "ENOENT")
207
- return;
208
- throw error;
209
- }
210
- try {
211
- return JSON.parse(contents);
212
- } catch {
213
- return;
214
- }
215
- }
216
- async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
217
- const ledgerPath = join2(artifactDir, LEDGER_FILENAME);
218
- const existing = await readExistingGoalLedger(ledgerPath);
219
- if (existing !== undefined)
220
- return { ledger: existing, ledgerPath, artifactDir };
221
- const goalId = randomUUID();
222
- const now = new Date().toISOString();
223
- const ledger = {
224
- goal_id: goalId,
225
- objective,
226
- acceptance_criteria: acceptanceCriteria,
227
- status: "active",
228
- turns: 0,
229
- created_at: now,
230
- updated_at: now,
231
- receipts: [],
232
- reviews: [],
233
- blockers: [],
234
- decisions: [],
235
- lifecycle: [],
236
- reverification: [],
237
- convergence: []
238
- };
239
- appendLifecycleEvent(ledger, "created", "Goal created.", 0);
240
- await writeGoalLedger(ledgerPath, ledger);
241
- return { ledger, ledgerPath, artifactDir };
242
- }
243
- async function writeGoalLedger(ledgerPath, ledger) {
244
- ledger.updated_at = new Date().toISOString();
245
- const visibleContents = `${JSON.stringify(modelVisibleLedger(ledger), null, 2)}
246
- `;
247
- const stateContents = `${JSON.stringify(ledger, null, 2)}
248
- `;
249
- const statePath = goalLedgerStatePath(ledgerPath);
250
- const pendingStatePath = `${statePath}.${randomUUID()}.tmp`;
251
- await writeFile2(pendingStatePath, stateContents, { encoding: "utf8" });
252
- try {
253
- await rename(pendingStatePath, statePath);
254
- } catch (error) {
255
- await rm(pendingStatePath, { force: true });
256
- throw error;
257
- }
258
- await writeFile2(ledgerPath, visibleContents, { encoding: "utf8" });
259
- }
171
+ import { isDeepStrictEqual } from "node:util";
260
172
 
261
173
  // dist/builtin/workflows/builtin/goal-reducer.ts
262
174
  function reducerSummary(reviews, approved, nextAction) {
@@ -379,70 +291,6 @@ function reduceGoalDecision(ledger, turnReviews, options) {
379
291
  };
380
292
  }
381
293
 
382
- // dist/builtin/workflows/builtin/goal-reports.ts
383
- function formatReviewReport(reviews) {
384
- if (reviews.length === 0)
385
- return "No reviewer decisions were recorded.";
386
- return reviews.map((review) => [
387
- `### ${review.reviewer}`,
388
- "",
389
- `Decision: ${review.decision}`,
390
- `Artifact: ${review.artifact_path}`,
391
- `Verification remaining: ${review.verification_remaining}`,
392
- "Finding alignment warning: beyond_objective and contradicts_objective findings are non-blocking and must not be folded into follow-up objectives without checking them against the acceptance criteria.",
393
- review.findings.length === 0 ? "Findings: none" : [
394
- "Findings:",
395
- ...review.findings.map((finding) => `- ${finding.objective_alignment}: ${finding.title}`)
396
- ].join(`
397
- `),
398
- review.requirements_traceability.length === 0 ? "Requirements traceability: none" : [
399
- "Requirements traceability:",
400
- ...review.requirements_traceability.map((entry) => `- ${entry.status}: ${entry.requirement} — ${entry.evidence}`)
401
- ].join(`
402
- `)
403
- ].join(`
404
- `)).join(`
405
-
406
- ---
407
-
408
- `);
409
- }
410
- function renderFinalReport(ledger, ledgerPath, remainingWork) {
411
- const receiptLines = ledger.receipts.length > 0 ? ledger.receipts.map((receipt) => `- ${receipt.summary} (artifact: ${receipt.artifact_path})`) : ["- No receipts captured."];
412
- const lastDecision = ledger.decisions.at(-1);
413
- return [
414
- "# Goal Run Final Report",
415
- "",
416
- "## Goal ID",
417
- ledger.goal_id,
418
- "",
419
- "## Objective",
420
- ledger.objective,
421
- "",
422
- "## Acceptance criteria",
423
- ledger.acceptance_criteria,
424
- "",
425
- "## Final status",
426
- ledger.status,
427
- "",
428
- "## Ledger artifact",
429
- ledgerPath,
430
- "",
431
- "## Evidence and receipts",
432
- ...receiptLines,
433
- "",
434
- "## Final decision",
435
- lastDecision?.reason ?? "No reducer decision was recorded.",
436
- "",
437
- "## Objective-alignment warning",
438
- "Review findings classified beyond_objective or contradicts_objective are non-blocking and must not be promoted into follow-up objectives without checking them against the acceptance criteria.",
439
- "",
440
- "## Remaining work if incomplete",
441
- ledger.status === "complete" ? "none" : remainingWork
442
- ].join(`
443
- `);
444
- }
445
-
446
294
  // dist/builtin/workflows/builtin/goal-review.ts
447
295
  function reviewDecisionFromResult(result) {
448
296
  return result.structured;
@@ -532,6 +380,225 @@ function reviewDecisionToRecord(args) {
532
380
  };
533
381
  }
534
382
 
383
+ // dist/builtin/workflows/builtin/goal-ledger.ts
384
+ var LEDGER_STATE_FILENAME = "goal-ledger-state.json";
385
+ function withoutTurn2(value) {
386
+ const copy = { ...value };
387
+ delete copy.turn;
388
+ return copy;
389
+ }
390
+ function modelVisibleLedger(ledger) {
391
+ return {
392
+ goal_id: ledger.goal_id,
393
+ objective: ledger.objective,
394
+ acceptance_criteria: ledger.acceptance_criteria,
395
+ status: ledger.status,
396
+ created_at: ledger.created_at,
397
+ updated_at: ledger.updated_at,
398
+ receipts: ledger.receipts.map(withoutTurn2),
399
+ reviews: ledger.reviews.map(withoutTurn2),
400
+ blockers: ledger.blockers.map(withoutTurn2),
401
+ decisions: ledger.decisions.map(withoutTurn2),
402
+ lifecycle: ledger.lifecycle.map(withoutTurn2),
403
+ reverification: ledger.reverification ?? [],
404
+ convergence: ledger.convergence ?? []
405
+ };
406
+ }
407
+ function goalLedgerStatePath(ledgerPath) {
408
+ return join2(dirname(ledgerPath), LEDGER_STATE_FILENAME);
409
+ }
410
+ function appendLifecycleEvent(ledger, event, summary, turn = ledger.turns) {
411
+ ledger.lifecycle.push({
412
+ turn,
413
+ event,
414
+ status: ledger.status,
415
+ at: new Date().toISOString(),
416
+ summary
417
+ });
418
+ }
419
+ async function readExistingGoalLedger(ledgerPath) {
420
+ let contents;
421
+ try {
422
+ contents = await readFile(goalLedgerStatePath(ledgerPath), "utf8");
423
+ } catch (error) {
424
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
425
+ return;
426
+ throw error;
427
+ }
428
+ try {
429
+ return JSON.parse(contents);
430
+ } catch {
431
+ return;
432
+ }
433
+ }
434
+ function isLegacyDatabaseInterruption(diagnostic) {
435
+ const failure = diagnostic.replace(/^(?:Orchestrator failed before producing a receipt|Reviewer execution failed before producing a decision|Reviewer execution failed while resolving its reads contract): /u, "");
436
+ return [
437
+ "Workflow database unavailable",
438
+ "Workflow database checkpoint timed out",
439
+ "Workflow database ownership generation changed",
440
+ "Managed PostgreSQL did not answer a health check in time",
441
+ "Managed PostgreSQL failed its live health check",
442
+ "managed PostgreSQL health-check failed",
443
+ "durable checkpoint timeout",
444
+ "lost DB connection"
445
+ ].some((prefix) => failure === prefix || failure.startsWith(`${prefix}.`) || failure.startsWith(`${prefix}:`) || failure.startsWith(`${prefix} `));
446
+ }
447
+ function recoverLegacyExecutionInterruption(ledger) {
448
+ const decision = ledger.decisions.at(-1);
449
+ const event = ledger.lifecycle.at(-1);
450
+ if (ledger.status !== "needs_human" || decision === undefined || event === undefined || decision.turn !== ledger.turns || !Number.isInteger(decision.turn) || decision.turn < 1 || decision.decision !== "needs_human" || decision.parsed !== false || decision.approved !== false || decision.stopReviewLoop !== false || decision.nextAction !== "needs_human" || decision.finalActionRemaining !== false || decision.complete_votes !== 0 || decision.review_quorum !== DEFAULT_REVIEW_QUORUM || decision.blocker !== undefined || event.event !== "status_decided" || event.status !== "needs_human" || event.turn !== decision.turn || event.summary !== decision.reason || ledger.decisions.slice(0, -1).some((record) => record.turn >= decision.turn || record.decision !== "continue") || ledger.lifecycle.slice(0, -1).some((record) => record.turn > decision.turn || record.turn === decision.turn && record.event === "status_decided") || ledger.blockers.some((record) => record.turn >= decision.turn)) {
451
+ return false;
452
+ }
453
+ const diagnostic = decision.diagnostics[0];
454
+ if (decision.diagnostics.length !== 1 || diagnostic === undefined)
455
+ return false;
456
+ if (!isLegacyDatabaseInterruption(diagnostic))
457
+ return false;
458
+ const turnReviews = ledger.reviews.filter((record) => record.turn >= decision.turn);
459
+ const turnReceipts = ledger.receipts.filter((record) => record.turn >= decision.turn);
460
+ const previousEvent = ledger.lifecycle.at(-2);
461
+ const orchestratorInterrupted = diagnostic.startsWith("Orchestrator failed before producing a receipt: ") && decision.reason === [diagnostic, ...convergence_escalation_evidence(ledger.convergence ?? [])].join(`
462
+ `) && turnReceipts.length === 0 && turnReviews.length === 0 && previousEvent?.event === "work_turn_started" && previousEvent.turn === decision.turn && previousEvent.status === "active" && previousEvent.summary === "Orchestrator started.";
463
+ const review = turnReviews[0];
464
+ const reviewerInterrupted = (diagnostic.startsWith("Reviewer execution failed before producing a decision: ") || diagnostic.startsWith("Reviewer execution failed while resolving its reads contract: ")) && turnReviews.length === 1 && review !== undefined && turnReceipts.length === 1 && turnReceipts[0]?.turn === decision.turn && previousEvent?.event === "reviews_recorded" && previousEvent.turn === decision.turn && previousEvent.status === "active" && previousEvent.summary === "Recorded 1 reviewer decisions." && isDeepStrictEqual(review, reviewDecisionToRecord({
465
+ turn: decision.turn,
466
+ reviewer: "reviewer-error",
467
+ artifactPath: review.artifact_path,
468
+ decision: reviewerErrorDecision(diagnostic),
469
+ parsed: false,
470
+ diagnostics: [diagnostic],
471
+ allowFinalActionRemaining: false
472
+ })) && decision.reason === [
473
+ `Reviewer execution failed before quorum could be established. Remaining work: ${collectRemainingWork([review])}`,
474
+ ...convergence_escalation_evidence(ledger.convergence ?? [])
475
+ ].join(`
476
+ `);
477
+ if (!orchestratorInterrupted && !reviewerInterrupted)
478
+ return false;
479
+ ledger.decisions.pop();
480
+ ledger.lifecycle.pop();
481
+ if (reviewerInterrupted) {
482
+ ledger.reviews = ledger.reviews.filter((record) => record !== review);
483
+ ledger.lifecycle.pop();
484
+ } else {
485
+ ledger.turns = Math.max(0, ...ledger.decisions.map((record) => record.turn));
486
+ }
487
+ ledger.status = "active";
488
+ return true;
489
+ }
490
+ async function createGoalLedger(objective, acceptanceCriteria, artifactDir) {
491
+ const ledgerPath = join2(artifactDir, LEDGER_FILENAME);
492
+ const existing = await readExistingGoalLedger(ledgerPath);
493
+ if (existing !== undefined) {
494
+ if (recoverLegacyExecutionInterruption(existing))
495
+ await writeGoalLedger(ledgerPath, existing);
496
+ return { ledger: existing, ledgerPath, artifactDir };
497
+ }
498
+ const goalId = randomUUID();
499
+ const now = new Date().toISOString();
500
+ const ledger = {
501
+ goal_id: goalId,
502
+ objective,
503
+ acceptance_criteria: acceptanceCriteria,
504
+ status: "active",
505
+ turns: 0,
506
+ created_at: now,
507
+ updated_at: now,
508
+ receipts: [],
509
+ reviews: [],
510
+ blockers: [],
511
+ decisions: [],
512
+ lifecycle: [],
513
+ reverification: [],
514
+ convergence: []
515
+ };
516
+ appendLifecycleEvent(ledger, "created", "Goal created.", 0);
517
+ await writeGoalLedger(ledgerPath, ledger);
518
+ return { ledger, ledgerPath, artifactDir };
519
+ }
520
+ async function writeGoalLedger(ledgerPath, ledger) {
521
+ ledger.updated_at = new Date().toISOString();
522
+ const visibleContents = `${JSON.stringify(modelVisibleLedger(ledger), null, 2)}
523
+ `;
524
+ const stateContents = `${JSON.stringify(ledger, null, 2)}
525
+ `;
526
+ const statePath = goalLedgerStatePath(ledgerPath);
527
+ const pendingStatePath = `${statePath}.${randomUUID()}.tmp`;
528
+ await writeFile2(pendingStatePath, stateContents, { encoding: "utf8" });
529
+ try {
530
+ await rename(pendingStatePath, statePath);
531
+ } catch (error) {
532
+ await rm(pendingStatePath, { force: true });
533
+ throw error;
534
+ }
535
+ await writeFile2(ledgerPath, visibleContents, { encoding: "utf8" });
536
+ }
537
+
538
+ // dist/builtin/workflows/builtin/goal-reports.ts
539
+ function formatReviewReport(reviews) {
540
+ if (reviews.length === 0)
541
+ return "No reviewer decisions were recorded.";
542
+ return reviews.map((review) => [
543
+ `### ${review.reviewer}`,
544
+ "",
545
+ `Decision: ${review.decision}`,
546
+ `Artifact: ${review.artifact_path}`,
547
+ `Verification remaining: ${review.verification_remaining}`,
548
+ "Finding alignment warning: beyond_objective and contradicts_objective findings are non-blocking and must not be folded into follow-up objectives without checking them against the acceptance criteria.",
549
+ review.findings.length === 0 ? "Findings: none" : [
550
+ "Findings:",
551
+ ...review.findings.map((finding) => `- ${finding.objective_alignment}: ${finding.title}`)
552
+ ].join(`
553
+ `),
554
+ review.requirements_traceability.length === 0 ? "Requirements traceability: none" : [
555
+ "Requirements traceability:",
556
+ ...review.requirements_traceability.map((entry) => `- ${entry.status}: ${entry.requirement} — ${entry.evidence}`)
557
+ ].join(`
558
+ `)
559
+ ].join(`
560
+ `)).join(`
561
+
562
+ ---
563
+
564
+ `);
565
+ }
566
+ function renderFinalReport(ledger, ledgerPath, remainingWork) {
567
+ const receiptLines = ledger.receipts.length > 0 ? ledger.receipts.map((receipt) => `- ${receipt.summary} (artifact: ${receipt.artifact_path})`) : ["- No receipts captured."];
568
+ const lastDecision = ledger.decisions.at(-1);
569
+ return [
570
+ "# Goal Run Final Report",
571
+ "",
572
+ "## Goal ID",
573
+ ledger.goal_id,
574
+ "",
575
+ "## Objective",
576
+ ledger.objective,
577
+ "",
578
+ "## Acceptance criteria",
579
+ ledger.acceptance_criteria,
580
+ "",
581
+ "## Final status",
582
+ ledger.status,
583
+ "",
584
+ "## Ledger artifact",
585
+ ledgerPath,
586
+ "",
587
+ "## Evidence and receipts",
588
+ ...receiptLines,
589
+ "",
590
+ "## Final decision",
591
+ lastDecision?.reason ?? "No reducer decision was recorded.",
592
+ "",
593
+ "## Objective-alignment warning",
594
+ "Review findings classified beyond_objective or contradicts_objective are non-blocking and must not be promoted into follow-up objectives without checking them against the acceptance criteria.",
595
+ "",
596
+ "## Remaining work if incomplete",
597
+ ledger.status === "complete" ? "none" : remainingWork
598
+ ].join(`
599
+ `);
600
+ }
601
+
535
602
  // dist/builtin/workflows/builtin/goal-prompts.ts
536
603
  var GOAL_CONTINUATION_REFERENCE = [
537
604
  "Continuation and completion:",
@@ -776,23 +843,6 @@ async function createGoalArtifactDirectory(ctx) {
776
843
  const artifactDir = await ctx.tool("artifact-root", { workflow: "goal" }, async () => workflowArtifactDirectoryPath(ctx.runId));
777
844
  return ensureWorkflowArtifactDirectory(artifactDir);
778
845
  }
779
- function reviewerExecutionFailedDecision(input) {
780
- const evidence = convergence_escalation_evidence(input.convergence ?? []);
781
- return {
782
- turn: input.turn,
783
- decision: "needs_human",
784
- reason: [input.reason, ...evidence].join(`
785
- `),
786
- complete_votes: input.reviews.filter((review) => review.decision === "complete").length,
787
- review_quorum: input.reviewQuorum,
788
- parsed: input.reviews.every((review) => review.parsed),
789
- approved: false,
790
- stopReviewLoop: false,
791
- nextAction: "needs_human",
792
- finalActionRemaining: false,
793
- diagnostics: input.reviews.flatMap((review) => review.parse_diagnostics)
794
- };
795
- }
796
846
  async function runGoalWorkflow(ctx, options) {
797
847
  const inputs = ctx.inputs;
798
848
  const createPr = options.createPr;
@@ -812,12 +862,13 @@ async function runGoalWorkflow(ctx, options) {
812
862
  let latestReviews = [];
813
863
  let latestReviewArtifactPaths = [];
814
864
  let latestReviewReportPath;
815
- let terminalRemainingWork;
816
865
  let previousOrchestratorSessionFile;
817
- const recordedTurns = ledger.turns;
818
- for (let turn = 1;turn <= maxTurns && (ledger.status === "active" || turn <= recordedTurns); turn += 1) {
819
- const replayingRecordedTurn = turn <= recordedTurns;
820
- if (!replayingRecordedTurn) {
866
+ const recordedTurns = new Set(ledger.decisions.map((decision) => decision.turn));
867
+ const lastRecordedTurn = Math.max(0, ...recordedTurns);
868
+ for (let turn = 1;turn <= maxTurns && (ledger.status === "active" || turn <= lastRecordedTurn); turn += 1) {
869
+ const replayingRecordedTurn = recordedTurns.has(turn);
870
+ const turnAlreadyStarted = ledger.lifecycle.some((event) => event.turn === turn && event.event === "work_turn_started");
871
+ if (!replayingRecordedTurn && !turnAlreadyStarted) {
821
872
  appendLifecycleEvent(ledger, "work_turn_started", "Orchestrator started.", turn);
822
873
  await writeGoalLedger(ledgerPath, ledger);
823
874
  }
@@ -830,44 +881,14 @@ async function runGoalWorkflow(ctx, options) {
830
881
  latestReviewArtifactPaths,
831
882
  workflowStartCwd
832
883
  }) : renderForkedGoalOrchestratorPrompt(ledger, ledgerPath, latestReviewArtifactPaths);
833
- let orchestrator;
834
- try {
835
- orchestrator = await ctx.task(`orchestrator-${turn}`, {
836
- prompt: orchestratorPrompt,
837
- reads: [ledgerPath, ...latestReviewArtifactPaths],
838
- output: orchestratorReceiptPath,
839
- outputMode: "file-only",
840
- ...orchestratorModelConfig,
841
- ...orchestratorForkOptions
842
- });
843
- } catch (err) {
844
- const message = err instanceof Error ? err.message : String(err);
845
- const baseReason = `Orchestrator failed before producing a receipt: ${message}`;
846
- terminalRemainingWork = baseReason;
847
- const reason = [baseReason, ...convergence_escalation_evidence(ledger.convergence ?? [])].join(`
848
- `);
849
- latestReviews = [];
850
- latestReviewArtifactPaths = [];
851
- latestReviewReportPath = undefined;
852
- ledger.turns = Math.max(ledger.turns, turn);
853
- ledger.status = "needs_human";
854
- ledger.decisions.push({
855
- turn,
856
- decision: "needs_human",
857
- reason,
858
- complete_votes: 0,
859
- review_quorum: reviewQuorum,
860
- parsed: false,
861
- approved: false,
862
- stopReviewLoop: false,
863
- nextAction: "needs_human",
864
- finalActionRemaining: false,
865
- diagnostics: [baseReason]
866
- });
867
- appendLifecycleEvent(ledger, "status_decided", reason, turn);
868
- await writeGoalLedger(ledgerPath, ledger);
869
- break;
870
- }
884
+ const orchestrator = await ctx.task(`orchestrator-${turn}`, {
885
+ prompt: orchestratorPrompt,
886
+ reads: [ledgerPath, ...latestReviewArtifactPaths],
887
+ output: orchestratorReceiptPath,
888
+ outputMode: "file-only",
889
+ ...orchestratorModelConfig,
890
+ ...orchestratorForkOptions
891
+ });
871
892
  previousOrchestratorSessionFile = orchestrator.sessionFile;
872
893
  if (!replayingRecordedTurn) {
873
894
  ledger.turns = turn;
@@ -905,34 +926,23 @@ async function runGoalWorkflow(ctx, options) {
905
926
  reviewerStep(`risk-reviewer-${turn}`, "Risk Reviewer: owns adversarial boundary checks across transition matrices, configuration precedence, feature-flag coupling, permissive inputs, and over-implementation.", "Probe state transitions, configuration paths and precedence, low-level API behavior across feature flags, and contract-permitted edge inputs. Also hunt for regressions, scope shrinkage, repository convention violations, unsafe assumptions, and blockers that are real repeated impasses rather than ordinary remaining work.")
906
927
  ];
907
928
  let reviewResults;
908
- let reviewerBatchFailed = false;
909
- let reviewerExecutionDiagnostic;
929
+ let reviewerContractError;
910
930
  try {
911
931
  reviewResults = await ctx.parallel(reviewerSteps, {
912
932
  task: objective,
913
933
  failFast: true,
914
934
  group: `goal-reviewers-turn-${turn}`
915
935
  });
916
- } catch (err) {
917
- reviewerBatchFailed = true;
918
- const failure = reviewerFailureText(err);
919
- reviewerExecutionDiagnostic = failure.includes("referenced artifact does not exist") ? `Reviewer execution failed while resolving its reads contract: ${failure}` : `Reviewer execution failed before producing a decision: ${failure}`;
920
- reviewResults = [
921
- {
922
- name: "reviewer-error",
923
- stageName: "reviewer-error",
924
- text: failure
925
- }
926
- ];
936
+ } catch (error) {
937
+ if (!isWorkflowStructuredOutputContractError(error))
938
+ throw error;
939
+ reviewerContractError = error;
940
+ reviewResults = [{ name: "reviewer-error", stageName: "reviewer-error", text: error.message }];
927
941
  }
928
942
  latestReviews = await Promise.all(reviewResults.map(async (result) => {
929
943
  const reviewerName = result.name ?? result.stageName;
930
944
  const normalizedReviewerName = reviewerName.replace(/-\d+$/u, "");
931
- const parsed = reviewerBatchFailed ? {
932
- decision: reviewerErrorDecision(reviewerExecutionDiagnostic ?? "Reviewer execution failed."),
933
- parsed: false,
934
- diagnostics: [reviewerExecutionDiagnostic ?? "Reviewer execution failed."]
935
- } : parsedReviewDecisionFromResult(result, reviewerName);
945
+ const parsed = reviewerContractError === undefined ? parsedReviewDecisionFromResult(result, reviewerName) : { decision: reviewerErrorDecision(reviewerContractError.message), parsed: false, diagnostics: [reviewerContractError.message] };
936
946
  const reviewArtifactPath = join3(artifactDir, `review-${artifactSafeName(normalizedReviewerName)}.json`);
937
947
  const record = reviewDecisionToRecord({
938
948
  turn,
@@ -974,7 +984,7 @@ async function runGoalWorkflow(ctx, options) {
974
984
  const findings = latestReviews.flatMap((review) => review.findings);
975
985
  const traceability = latestReviews.flatMap((review) => review.requirements_traceability);
976
986
  ledger.convergence ??= [];
977
- if (!replayingRecordedTurn && !reviewerBatchFailed && roundProducedDecisions) {
987
+ if (!replayingRecordedTurn && roundProducedDecisions) {
978
988
  ledger.convergence.push(record_convergence({
979
989
  unresolvedBlockingCount: reverified.batch.filter((entry) => entry.blocking).length,
980
990
  meanFindingConfidence: findings.length === 0 ? null : findings.reduce((total, finding) => total + finding.confidence_score, 0) / findings.length,
@@ -990,41 +1000,29 @@ async function runGoalWorkflow(ctx, options) {
990
1000
  if (!replayingRecordedTurn) {
991
1001
  appendLifecycleEvent(ledger, "reviews_recorded", `Recorded ${latestReviews.length} reviewer decisions.`, turn);
992
1002
  }
993
- if (reviewerBatchFailed) {
994
- terminalRemainingWork = collectRemainingWork(latestReviews);
995
- const reason = `Reviewer execution failed before quorum could be established. Remaining work: ${terminalRemainingWork}`;
996
- const decision = reviewerExecutionFailedDecision({
997
- turn,
998
- reviewQuorum,
999
- reviews: latestReviews,
1000
- reason,
1001
- convergence: ledger.convergence
1002
- });
1003
- ledger.decisions.push(decision);
1004
- ledger.status = "needs_human";
1005
- appendLifecycleEvent(ledger, "status_decided", decision.reason, turn);
1006
- await writeGoalLedger(ledgerPath, ledger);
1007
- break;
1008
- }
1009
1003
  if (replayingRecordedTurn)
1010
1004
  continue;
1011
1005
  const reducerOutcome = reduceGoalDecision(ledger, latestReviews, {
1012
1006
  turn,
1013
- maxTurns,
1007
+ maxTurns: reviewerContractError === undefined ? maxTurns : turn,
1014
1008
  reviewQuorum,
1015
1009
  blockerThreshold,
1016
1010
  nextActionOnComplete: createPr ? "pull-request" : "finish",
1017
1011
  convergence: ledger.convergence
1018
1012
  });
1013
+ const decision = reviewerContractError === undefined ? reducerOutcome.decision : {
1014
+ ...reducerOutcome.decision,
1015
+ reason: `Reviewer output contract exhausted before quorum could be established. ${reviewerContractError.message}`
1016
+ };
1019
1017
  if (reducerOutcome.blockerObservation !== undefined) {
1020
1018
  ledger.blockers.push(reducerOutcome.blockerObservation);
1021
1019
  }
1022
- ledger.decisions.push(reducerOutcome.decision);
1020
+ ledger.decisions.push(decision);
1023
1021
  ledger.status = reducerOutcome.status;
1024
- appendLifecycleEvent(ledger, "status_decided", reducerOutcome.decision.reason, turn);
1022
+ appendLifecycleEvent(ledger, "status_decided", decision.reason, turn);
1025
1023
  await writeGoalLedger(ledgerPath, ledger);
1026
1024
  }
1027
- const remainingWork = ledger.status === "complete" ? "none" : terminalRemainingWork ?? collectRemainingWork(latestReviews);
1025
+ const remainingWork = ledger.status === "complete" ? "none" : collectRemainingWork(latestReviews);
1028
1026
  const finalReport = renderFinalReport(ledger, ledgerPath, remainingWork);
1029
1027
  const reviewReport = formatReviewReport(latestReviews);
1030
1028
  let finalPrReport;
@@ -39,7 +39,7 @@ import {
39
39
  reviewerFailureText,
40
40
  summarizeReviewConvergence,
41
41
  reverify_consolidated_batch
42
- } from "./chunk-tecnpe8j.js";
42
+ } from "./chunk-p3xmajmj.js";
43
43
  import {
44
44
  fold_usage
45
45
  } from "./chunk-tgt0s5e5.js";