@urateam/core 0.1.54 → 0.1.56

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 (225) hide show
  1. package/dist/__tests__/auth-monitor.test.js +119 -20
  2. package/dist/__tests__/auth-monitor.test.js.map +1 -1
  3. package/dist/__tests__/bec-238-repro.test.d.ts +2 -0
  4. package/dist/__tests__/bec-238-repro.test.d.ts.map +1 -0
  5. package/dist/__tests__/bec-238-repro.test.js +116 -0
  6. package/dist/__tests__/bec-238-repro.test.js.map +1 -0
  7. package/dist/__tests__/bec146-repro.test.d.ts +2 -0
  8. package/dist/__tests__/bec146-repro.test.d.ts.map +1 -0
  9. package/dist/__tests__/bec146-repro.test.js +153 -0
  10. package/dist/__tests__/bec146-repro.test.js.map +1 -0
  11. package/dist/__tests__/db-migrations.test.js +7 -3
  12. package/dist/__tests__/db-migrations.test.js.map +1 -1
  13. package/dist/__tests__/decision-artifact-schema.test.d.ts +2 -0
  14. package/dist/__tests__/decision-artifact-schema.test.d.ts.map +1 -0
  15. package/dist/__tests__/decision-artifact-schema.test.js +45 -0
  16. package/dist/__tests__/decision-artifact-schema.test.js.map +1 -0
  17. package/dist/__tests__/decisions-parser.test.d.ts +2 -0
  18. package/dist/__tests__/decisions-parser.test.d.ts.map +1 -0
  19. package/dist/__tests__/decisions-parser.test.js +59 -0
  20. package/dist/__tests__/decisions-parser.test.js.map +1 -0
  21. package/dist/__tests__/decisions-store.test.d.ts +2 -0
  22. package/dist/__tests__/decisions-store.test.d.ts.map +1 -0
  23. package/dist/__tests__/decisions-store.test.js +68 -0
  24. package/dist/__tests__/decisions-store.test.js.map +1 -0
  25. package/dist/__tests__/decisions-table-migration.test.d.ts +2 -0
  26. package/dist/__tests__/decisions-table-migration.test.d.ts.map +1 -0
  27. package/dist/__tests__/decisions-table-migration.test.js +56 -0
  28. package/dist/__tests__/decisions-table-migration.test.js.map +1 -0
  29. package/dist/__tests__/execute-stage-session-opts.test.js +1 -0
  30. package/dist/__tests__/execute-stage-session-opts.test.js.map +1 -1
  31. package/dist/__tests__/executor-issue-id.test.js +1 -0
  32. package/dist/__tests__/executor-issue-id.test.js.map +1 -1
  33. package/dist/__tests__/extract-handoff-decisions.test.d.ts +2 -0
  34. package/dist/__tests__/extract-handoff-decisions.test.d.ts.map +1 -0
  35. package/dist/__tests__/extract-handoff-decisions.test.js +26 -0
  36. package/dist/__tests__/extract-handoff-decisions.test.js.map +1 -0
  37. package/dist/__tests__/force-push-agent-branches.test.js +38 -15
  38. package/dist/__tests__/force-push-agent-branches.test.js.map +1 -1
  39. package/dist/__tests__/github-webhook.test.js +117 -0
  40. package/dist/__tests__/github-webhook.test.js.map +1 -1
  41. package/dist/__tests__/implement-template-decisions.test.d.ts +2 -0
  42. package/dist/__tests__/implement-template-decisions.test.d.ts.map +1 -0
  43. package/dist/__tests__/implement-template-decisions.test.js +41 -0
  44. package/dist/__tests__/implement-template-decisions.test.js.map +1 -0
  45. package/dist/__tests__/migrator.test.js +137 -39
  46. package/dist/__tests__/migrator.test.js.map +1 -1
  47. package/dist/__tests__/pipeline-runner.test.js +118 -0
  48. package/dist/__tests__/pipeline-runner.test.js.map +1 -1
  49. package/dist/__tests__/pm-conflict.test.js +145 -5
  50. package/dist/__tests__/pm-conflict.test.js.map +1 -1
  51. package/dist/__tests__/preflight-claude-auth.test.js +3 -2
  52. package/dist/__tests__/preflight-claude-auth.test.js.map +1 -1
  53. package/dist/__tests__/ralph-review-fix-regression.test.js +1 -0
  54. package/dist/__tests__/ralph-review-fix-regression.test.js.map +1 -1
  55. package/dist/__tests__/ralph.test.js +1 -0
  56. package/dist/__tests__/ralph.test.js.map +1 -1
  57. package/dist/__tests__/release-manager-qarun-query.test.d.ts +2 -0
  58. package/dist/__tests__/release-manager-qarun-query.test.d.ts.map +1 -0
  59. package/dist/__tests__/release-manager-qarun-query.test.js +233 -0
  60. package/dist/__tests__/release-manager-qarun-query.test.js.map +1 -0
  61. package/dist/__tests__/release-manager-scheduler.test.js +62 -0
  62. package/dist/__tests__/release-manager-scheduler.test.js.map +1 -1
  63. package/dist/__tests__/session-lazy-creation.test.js +1 -0
  64. package/dist/__tests__/session-lazy-creation.test.js.map +1 -1
  65. package/dist/__tests__/session-resolver.test.d.ts +13 -0
  66. package/dist/__tests__/session-resolver.test.d.ts.map +1 -0
  67. package/dist/__tests__/session-resolver.test.js +152 -0
  68. package/dist/__tests__/session-resolver.test.js.map +1 -0
  69. package/dist/__tests__/session-resume-fallback.test.js +1 -0
  70. package/dist/__tests__/session-resume-fallback.test.js.map +1 -1
  71. package/dist/__tests__/stage-models.test.js +1 -0
  72. package/dist/__tests__/stage-models.test.js.map +1 -1
  73. package/dist/__tests__/surgical-review-fix-prompt.test.d.ts +2 -0
  74. package/dist/__tests__/surgical-review-fix-prompt.test.d.ts.map +1 -0
  75. package/dist/__tests__/surgical-review-fix-prompt.test.js +71 -0
  76. package/dist/__tests__/surgical-review-fix-prompt.test.js.map +1 -0
  77. package/dist/__tests__/surgical-review-fix-runner.test.d.ts +2 -0
  78. package/dist/__tests__/surgical-review-fix-runner.test.d.ts.map +1 -0
  79. package/dist/__tests__/surgical-review-fix-runner.test.js +171 -0
  80. package/dist/__tests__/surgical-review-fix-runner.test.js.map +1 -0
  81. package/dist/__tests__/validate-run-mode.test.js +1 -0
  82. package/dist/__tests__/validate-run-mode.test.js.map +1 -1
  83. package/dist/__tests__/validate.test.js +1 -0
  84. package/dist/__tests__/validate.test.js.map +1 -1
  85. package/dist/audit/auth-error-messages.d.ts +6 -0
  86. package/dist/audit/auth-error-messages.d.ts.map +1 -0
  87. package/dist/audit/auth-error-messages.js +18 -0
  88. package/dist/audit/auth-error-messages.js.map +1 -0
  89. package/dist/audit/events.d.ts +22 -4
  90. package/dist/audit/events.d.ts.map +1 -1
  91. package/dist/audit/events.js +34 -5
  92. package/dist/audit/events.js.map +1 -1
  93. package/dist/audit/index.d.ts +1 -0
  94. package/dist/audit/index.d.ts.map +1 -1
  95. package/dist/audit/index.js +1 -0
  96. package/dist/audit/index.js.map +1 -1
  97. package/dist/db/client.d.ts.map +1 -1
  98. package/dist/db/client.js +10 -0
  99. package/dist/db/client.js.map +1 -1
  100. package/dist/db/decisions-store.d.ts +25 -0
  101. package/dist/db/decisions-store.d.ts.map +1 -0
  102. package/dist/db/decisions-store.js +56 -0
  103. package/dist/db/decisions-store.js.map +1 -0
  104. package/dist/db/index.d.ts +1 -1
  105. package/dist/db/index.d.ts.map +1 -1
  106. package/dist/db/index.js +1 -1
  107. package/dist/db/index.js.map +1 -1
  108. package/dist/db/migrations/postgres/008_sso.sql +9 -20
  109. package/dist/db/migrations/postgres/009_review_model_runs.sql +9 -18
  110. package/dist/db/migrations/postgres/009_sso.sql +20 -0
  111. package/dist/db/migrations/postgres/010_release_manager.sql +9 -38
  112. package/dist/db/migrations/postgres/010_review_model_runs.sql +18 -0
  113. package/dist/db/migrations/postgres/011_qa_run_columns.sql +9 -8
  114. package/dist/db/migrations/postgres/011_release_manager.sql +38 -0
  115. package/dist/db/migrations/postgres/012_qa_gap_issues.sql +9 -18
  116. package/dist/db/migrations/postgres/012_qa_run_columns.sql +8 -0
  117. package/dist/db/migrations/postgres/013_qa_gap_issues.sql +18 -0
  118. package/dist/db/migrations/postgres/013_stage_runs_cache_tokens.sql +11 -6
  119. package/dist/db/migrations/postgres/014_missing_indexes.sql +9 -28
  120. package/dist/db/migrations/postgres/014_stage_runs_cache_tokens.sql +6 -0
  121. package/dist/db/migrations/postgres/015_missing_indexes.sql +28 -0
  122. package/dist/db/migrations/postgres/015_triage_results.sql +9 -11
  123. package/dist/db/migrations/postgres/016_triage_results.sql +11 -0
  124. package/dist/db/migrations/sqlite/007_sso.sql +9 -20
  125. package/dist/db/migrations/sqlite/008_review_model_runs.sql +9 -18
  126. package/dist/db/migrations/sqlite/008_sso.sql +20 -0
  127. package/dist/db/migrations/sqlite/009_release_manager.sql +9 -43
  128. package/dist/db/migrations/sqlite/009_review_model_runs.sql +18 -0
  129. package/dist/db/migrations/sqlite/010_qa_run_columns.sql +9 -9
  130. package/dist/db/migrations/sqlite/010_release_manager.sql +43 -0
  131. package/dist/db/migrations/sqlite/011_qa_gap_issues.sql +9 -22
  132. package/dist/db/migrations/sqlite/011_qa_run_columns.sql +9 -0
  133. package/dist/db/migrations/sqlite/012_qa_gap_issues.sql +22 -0
  134. package/dist/db/migrations/sqlite/012_stage_runs_cache_tokens.sql +11 -6
  135. package/dist/db/migrations/sqlite/013_missing_indexes.sql +10 -28
  136. package/dist/db/migrations/sqlite/013_stage_runs_cache_tokens.sql +6 -0
  137. package/dist/db/migrations/sqlite/013_triage_results.sql +10 -11
  138. package/dist/db/migrations/sqlite/014_missing_indexes.sql +28 -0
  139. package/dist/db/migrations/sqlite/015_triage_results.sql +11 -0
  140. package/dist/db/migrator.d.ts +45 -2
  141. package/dist/db/migrator.d.ts.map +1 -1
  142. package/dist/db/migrator.js +113 -29
  143. package/dist/db/migrator.js.map +1 -1
  144. package/dist/db/schema.d.ts +125 -0
  145. package/dist/db/schema.d.ts.map +1 -1
  146. package/dist/db/schema.js +13 -0
  147. package/dist/db/schema.js.map +1 -1
  148. package/dist/executor/auth-monitor.d.ts.map +1 -1
  149. package/dist/executor/auth-monitor.js +39 -30
  150. package/dist/executor/auth-monitor.js.map +1 -1
  151. package/dist/executor/deep-review.d.ts.map +1 -1
  152. package/dist/executor/deep-review.js +14 -79
  153. package/dist/executor/deep-review.js.map +1 -1
  154. package/dist/executor/executor.d.ts +21 -0
  155. package/dist/executor/executor.d.ts.map +1 -1
  156. package/dist/executor/executor.js +41 -90
  157. package/dist/executor/executor.js.map +1 -1
  158. package/dist/executor/extract-handoff.d.ts +9 -0
  159. package/dist/executor/extract-handoff.d.ts.map +1 -1
  160. package/dist/executor/extract-handoff.js +48 -0
  161. package/dist/executor/extract-handoff.js.map +1 -1
  162. package/dist/executor/handoff.d.ts +10 -1
  163. package/dist/executor/handoff.d.ts.map +1 -1
  164. package/dist/executor/handoff.js +7 -1
  165. package/dist/executor/handoff.js.map +1 -1
  166. package/dist/executor/index.d.ts +1 -0
  167. package/dist/executor/index.d.ts.map +1 -1
  168. package/dist/executor/index.js +1 -0
  169. package/dist/executor/index.js.map +1 -1
  170. package/dist/executor/prompt/templates.d.ts +12 -1
  171. package/dist/executor/prompt/templates.d.ts.map +1 -1
  172. package/dist/executor/prompt/templates.js +64 -0
  173. package/dist/executor/prompt/templates.js.map +1 -1
  174. package/dist/executor/session-resolver.d.ts +51 -0
  175. package/dist/executor/session-resolver.d.ts.map +1 -0
  176. package/dist/executor/session-resolver.js +83 -0
  177. package/dist/executor/session-resolver.js.map +1 -0
  178. package/dist/index.d.ts +1 -1
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js +1 -1
  181. package/dist/index.js.map +1 -1
  182. package/dist/notifier/composite.js +1 -1
  183. package/dist/notifier/composite.js.map +1 -1
  184. package/dist/notifier/linear.d.ts +1 -1
  185. package/dist/notifier/linear.d.ts.map +1 -1
  186. package/dist/notifier/linear.js +49 -9
  187. package/dist/notifier/linear.js.map +1 -1
  188. package/dist/pipeline/run-surgical-review-fix.d.ts +29 -0
  189. package/dist/pipeline/run-surgical-review-fix.d.ts.map +1 -0
  190. package/dist/pipeline/run-surgical-review-fix.js +48 -0
  191. package/dist/pipeline/run-surgical-review-fix.js.map +1 -0
  192. package/dist/pipeline/runner.d.ts.map +1 -1
  193. package/dist/pipeline/runner.js +132 -36
  194. package/dist/pipeline/runner.js.map +1 -1
  195. package/dist/pm/conflict.d.ts +2 -0
  196. package/dist/pm/conflict.d.ts.map +1 -1
  197. package/dist/pm/conflict.js +59 -9
  198. package/dist/pm/conflict.js.map +1 -1
  199. package/dist/pm/scheduler.d.ts +2 -0
  200. package/dist/pm/scheduler.d.ts.map +1 -1
  201. package/dist/pm/scheduler.js +51 -43
  202. package/dist/pm/scheduler.js.map +1 -1
  203. package/dist/pm/slack.d.ts +11 -0
  204. package/dist/pm/slack.d.ts.map +1 -1
  205. package/dist/pm/slack.js +48 -5
  206. package/dist/pm/slack.js.map +1 -1
  207. package/dist/release-manager/release-helpers.d.ts +19 -2
  208. package/dist/release-manager/release-helpers.d.ts.map +1 -1
  209. package/dist/release-manager/release-helpers.js +22 -3
  210. package/dist/release-manager/release-helpers.js.map +1 -1
  211. package/dist/release-manager/release-tick.d.ts.map +1 -1
  212. package/dist/release-manager/release-tick.js +20 -8
  213. package/dist/release-manager/release-tick.js.map +1 -1
  214. package/dist/release-manager/state.d.ts.map +1 -1
  215. package/dist/release-manager/state.js +25 -18
  216. package/dist/release-manager/state.js.map +1 -1
  217. package/dist/types.d.ts +232 -13
  218. package/dist/types.d.ts.map +1 -1
  219. package/dist/types.js +52 -0
  220. package/dist/types.js.map +1 -1
  221. package/dist/webhook/github-handler.d.ts +2 -2
  222. package/dist/webhook/github-handler.d.ts.map +1 -1
  223. package/dist/webhook/github-handler.js +18 -6
  224. package/dist/webhook/github-handler.js.map +1 -1
  225. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/pipeline/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/pipeline/runner.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { ResumePayloadSchema } from "../types.js"; // value import — cannot be `import type`
1
2
  import { pipelineRuns, stageRuns, reviewModelRuns } from "../db/schema.js";
2
3
  import { formatPRCostSummary, } from "./cost-summary.js";
3
4
  import { executeStage } from "../executor/executor.js";
@@ -16,7 +17,7 @@ import { DEFAULT_AGENT_CLAUDE_MD } from "../executor/agent-config.js";
16
17
  import { generatePRDescription } from "./pr-description.js";
17
18
  import { maybePostChangeSummary } from "./pr-change-summary.js";
18
19
  import { access, writeFile, appendFile } from "node:fs/promises";
19
- import { join, resolve } from "node:path";
20
+ import { join, resolve, sep } from "node:path";
20
21
  import { homedir } from "node:os";
21
22
  import { execFile as execFileCb } from "node:child_process";
22
23
  import { promisify } from "node:util";
@@ -48,12 +49,30 @@ import { runTypecheck } from "./typecheck-gate.js";
48
49
  import { checkSpecVsImpl } from "./spec-vs-impl-gate.js";
49
50
  import { countNewPublicExports, shouldAutoDeepReview, DEFAULT_AUTO_DEEP_REVIEW_THRESHOLDS, } from "./auto-deep-review.js";
50
51
  import { startFeedbackPipeline, } from "./feedback-pipeline.js";
52
+ import { runSurgicalReviewFix } from "./run-surgical-review-fix.js";
51
53
  // Re-export from extracted module so existing callers (including tests) still
52
54
  // find buildReviewFeedbackContext at pipeline/runner.js without changing their
53
55
  // import paths.
54
56
  export { buildReviewFeedbackContext } from "./feedback-pipeline.js";
55
57
  // Module-level logger (no runId yet — used for pre-run messages)
56
58
  const log = createLogger({ component: "PipelineRunner" });
59
+ /**
60
+ * Serialise a resume payload to the JSON string stored in
61
+ * `pipeline_runs.resume_payload`. Both the await-approval pause path and the
62
+ * transient-failure retry path use this helper so their serialization stays in
63
+ * sync with `ResumePayloadSchema` — a single place to update if the schema
64
+ * evolves.
65
+ */
66
+ function buildResumePayload(handoff, pipelineConfig, repoConfig, sanitizedIssue, worktreePath, currentStageIndex) {
67
+ return JSON.stringify({
68
+ handoff,
69
+ pipelineConfig,
70
+ repoConfig,
71
+ sanitizedIssue,
72
+ worktreePath,
73
+ currentStageIndex,
74
+ });
75
+ }
57
76
  export class PipelineRunner {
58
77
  queue;
59
78
  /** Push queue: concurrency=1 serialises push+PR creation within this process.
@@ -181,15 +200,16 @@ export class PipelineRunner {
181
200
  .where(eq(pipelineRuns.id, existingRunId));
182
201
  return;
183
202
  }
184
- // Look up a paused run in the DB for this issue
203
+ // Look up a paused or retriable run in the DB for this issue.
204
+ // "paused" = awaiting approval; "retriable" = transient failure awaiting manual retry.
185
205
  const db = this.db;
186
206
  const rows = await db
187
207
  .select()
188
208
  .from(pipelineRuns)
189
- .where(and(eq(pipelineRuns.issueId, issueId), eq(pipelineRuns.status, "paused")))
209
+ .where(and(eq(pipelineRuns.issueId, issueId), inArray(pipelineRuns.status, ["paused", "retriable"])))
190
210
  .limit(1);
191
211
  if (rows.length === 0) {
192
- resumeLog.info("resume() called but no paused run found in DB — no-op");
212
+ resumeLog.info("resume() called but no paused or retriable run found in DB — no-op");
193
213
  return;
194
214
  }
195
215
  const pausedRun = rows[0];
@@ -197,6 +217,15 @@ export class PipelineRunner {
197
217
  const runLog = createLogger({ component: "PipelineRunner", runId, issueId });
198
218
  // Claim the slot immediately to prevent concurrent resume() calls
199
219
  this.activeRuns.set(issueId, runId);
220
+ // For retriable runs: flip status to "paused" so the PM tick's
221
+ // recoverRetriableRuns() won't find and double-recover this run while
222
+ // execution is queued. The paused-run execution path is identical.
223
+ if (pausedRun.status === "retriable") {
224
+ await db
225
+ .update(pipelineRuns)
226
+ .set({ status: "paused" })
227
+ .where(eq(pipelineRuns.id, runId));
228
+ }
200
229
  // Validate that the run has a full resume payload (saved at await-approval)
201
230
  if (pausedRun.currentStageIndex == null || !pausedRun.resumePayload) {
202
231
  runLog.error("resume payload missing — cannot resume pipeline; marking as failed");
@@ -211,9 +240,22 @@ export class PipelineRunner {
211
240
  this.activeRuns.delete(issueId);
212
241
  return;
213
242
  }
214
- let payload;
243
+ // Parse and validate the resume payload using the Zod schema.
244
+ // This replaces the former hand-rolled property-existence checks and catches
245
+ // schema mismatches from older DB rows (e.g. missing handoff, wrong types)
246
+ // before any git or executor operations run.
247
+ //
248
+ // BC: paused runs created before currentStageIndex was added to the payload
249
+ // schema (BEC-192) only have it on the DB row. Inject it from the DB column
250
+ // so those existing in-flight runs don't get falsely failed on first resume
251
+ // after deploy.
252
+ let parsed;
215
253
  try {
216
- payload = JSON.parse(pausedRun.resumePayload);
254
+ const raw = JSON.parse(pausedRun.resumePayload);
255
+ if (raw.currentStageIndex === undefined && pausedRun.currentStageIndex != null) {
256
+ raw.currentStageIndex = pausedRun.currentStageIndex;
257
+ }
258
+ parsed = ResumePayloadSchema.safeParse(raw);
217
259
  }
218
260
  catch {
219
261
  runLog.error("resume payload is invalid JSON — failing run");
@@ -228,26 +270,33 @@ export class PipelineRunner {
228
270
  this.activeRuns.delete(issueId);
229
271
  return;
230
272
  }
231
- const { handoff, pipelineConfig, repoConfig, sanitizedIssue, worktreePath } = payload;
232
- // Structural validation of deserialized payload
233
- if (typeof worktreePath !== "string" ||
234
- !pipelineConfig?.stages ||
235
- !sanitizedIssue?.id) {
236
- runLog.error("resume payload has invalid structure — failing run");
273
+ if (!parsed.success) {
274
+ const zodErrors = parsed.error.issues
275
+ .map((e) => `${e.path.join(".") || "(root)"}: ${e.message}`)
276
+ .join("; ");
277
+ runLog.error({ zodErrors }, "resume payload failed schema validation — failing run");
237
278
  await db
238
279
  .update(pipelineRuns)
239
280
  .set({
240
281
  status: "failed",
241
282
  completedAt: new Date(),
242
- errorMessage: "Invalid resume payload structure — cannot resume",
283
+ errorMessage: `Invalid resume payload structure — cannot resume: ${zodErrors}`,
243
284
  })
244
285
  .where(eq(pipelineRuns.id, runId));
245
286
  this.activeRuns.delete(issueId);
246
287
  return;
247
288
  }
248
- // Path containment check worktreePath must be within agentRunDir
289
+ const { handoff, pipelineConfig, repoConfig, sanitizedIssue, worktreePath, currentStageIndex } = parsed.data;
290
+ // Path containment check — worktreePath must be within agentRunDir.
291
+ // We append sep to agentRunDir before the startsWith check so that a
292
+ // crafted path like /home/ura/data/runs-evil cannot slip past as a prefix match
293
+ // of /home/ura/data/runs. An exact match (resolvedPath === this.agentRunDir)
294
+ // is also accepted for symmetry, even though real worktrees are always subdirs.
249
295
  const resolvedPath = resolve(worktreePath); // canonicalize — collapses .. segments
250
- if (!resolvedPath.startsWith(this.agentRunDir)) {
296
+ const normalizedBase = this.agentRunDir.endsWith(sep)
297
+ ? this.agentRunDir
298
+ : this.agentRunDir + sep;
299
+ if (!resolvedPath.startsWith(normalizedBase) && resolvedPath !== this.agentRunDir) {
251
300
  runLog.error({ worktreePath, agentRunDir: this.agentRunDir }, "resume: worktreePath outside agentRunDir — failing run");
252
301
  await db
253
302
  .update(pipelineRuns)
@@ -306,13 +355,13 @@ export class PipelineRunner {
306
355
  this.activeRuns.delete(issueId);
307
356
  return;
308
357
  }
309
- runLog.info({ stageIndex: pausedRun.currentStageIndex, worktreePath }, "resuming pipeline — re-queuing execution from stage after await-approval");
358
+ runLog.info({ stageIndex: currentStageIndex, worktreePath }, "resuming pipeline — re-queuing execution from stage after await-approval");
310
359
  this.queue.enqueue(async () => {
311
360
  if (!this.activeRuns.has(issueId))
312
361
  return;
313
362
  try {
314
363
  await runWithLogContext({ runId, issueId }, () => this.executePipeline(runId, run, pipelineConfig, repoConfig, sanitizedIssue, pausedRun.branch, {
315
- startStageIndex: pausedRun.currentStageIndex,
364
+ startStageIndex: currentStageIndex,
316
365
  worktreePath,
317
366
  initialHandoff: handoff ?? undefined,
318
367
  // BEC-227 — carry the per-run SDK session id across the
@@ -672,13 +721,7 @@ export class PipelineRunner {
672
721
  // Save the full resume context so resume() can re-attach the worktree
673
722
  // and continue from the next stage with the correct handoff artifact.
674
723
  const stageIndex = config.stages.indexOf(stage);
675
- const resumePayload = JSON.stringify({
676
- handoff: handoff ?? null,
677
- pipelineConfig: config,
678
- repoConfig,
679
- sanitizedIssue,
680
- worktreePath: worktreePath,
681
- });
724
+ const resumePayload = buildResumePayload(handoff ?? null, config, repoConfig, sanitizedIssue, worktreePath, stageIndex);
682
725
  await db
683
726
  .update(pipelineRuns)
684
727
  .set({
@@ -820,6 +863,11 @@ export class PipelineRunner {
820
863
  agentSessionId: runAgentSessionId,
821
864
  isFirstResumableStage: isFirstResumableStageForRalph,
822
865
  suppressHandoff: suppressRalphHandoff,
866
+ // BEC-227 Phase 4 / Track D — RALPH iteration counter (1..N)
867
+ // surfaces in pipeline_run_decisions.iteration so operators
868
+ // can correlate persisted decisions with the RALPH loop pass
869
+ // that produced them.
870
+ iteration,
823
871
  });
824
872
  // Accumulate each RALPH iteration's tokens
825
873
  run.totalInputTokens += result.inputTokens;
@@ -933,6 +981,11 @@ export class PipelineRunner {
933
981
  const validation = await validateHandoff(stage, {
934
982
  artifact: result.handoffArtifact,
935
983
  structured: result.handoffIsStructured ?? false,
984
+ // BEC-227 Phase 4 / Track D — validator doesn't consume the
985
+ // decisions artifact (Track B's review-fix loop does). The
986
+ // executor already persisted it before returning; we don't
987
+ // need to thread it through validateHandoff.
988
+ decisions: null,
936
989
  }, sanitizedIssue, repoConfig, worktreePath, mainStageRunMode);
937
990
  validationPassed = validation.valid;
938
991
  let lastValidationIssues = validation.issues;
@@ -971,6 +1024,8 @@ export class PipelineRunner {
971
1024
  const retryValidation = await validateHandoff(stage, {
972
1025
  artifact: result.handoffArtifact,
973
1026
  structured: result.handoffIsStructured ?? false,
1027
+ // BEC-227 Phase 4 / Track D — see main-stage call above.
1028
+ decisions: null,
974
1029
  }, sanitizedIssue, repoConfig, worktreePath, valRetryRunMode);
975
1030
  if (retryValidation.valid) {
976
1031
  validationPassed = true;
@@ -1070,6 +1125,32 @@ export class PipelineRunner {
1070
1125
  runLog.info({ rfIteration, maxIterations: reviewFixIterations, blockingFindings: blockingCount }, "review-fix loop: re-running stages to address blocking findings");
1071
1126
  for (const fixStage of fixStages) {
1072
1127
  runLog.info({ stage: fixStage, rfIteration }, "review-fix: executing stage");
1128
+ // BEC-227 Phase 4 / Track B — for the implement fixStage, decide
1129
+ // surgical vs legacy review-fix. Surgical = the per-run SDK session
1130
+ // is intact (JSONL on disk) so we can send a focused
1131
+ // findings-plus-prior-decisions prompt instead of re-running the
1132
+ // full implement template. The audit event fires inside
1133
+ // runSurgicalReviewFix for BOTH paths so operators can monitor
1134
+ // fallback rates.
1135
+ let surgicalPrompt;
1136
+ let surgicalSuppressHandoff = false;
1137
+ if (fixStage === "implement") {
1138
+ const blocking = (handoff?.context?.reviewFindings ?? []).filter((f) => f.severity === "blocking");
1139
+ if (blocking.length > 0) {
1140
+ const decision = await runSurgicalReviewFix({
1141
+ db: this.db,
1142
+ runId,
1143
+ issueId: sanitizedIssue.id,
1144
+ agentSessionId: runAgentSessionId,
1145
+ worktreePath,
1146
+ blockingFindings: blocking,
1147
+ });
1148
+ if (decision.path === "surgical") {
1149
+ surgicalPrompt = decision.prompt;
1150
+ surgicalSuppressHandoff = true;
1151
+ }
1152
+ }
1153
+ }
1073
1154
  const isFirstResumableStageForFix = claimFirstResumableStage(fixStage);
1074
1155
  const fixResult = await executeStage({
1075
1156
  runId,
@@ -1085,6 +1166,16 @@ export class PipelineRunner {
1085
1166
  stageModels: config.stageModels,
1086
1167
  agentSessionId: runAgentSessionId,
1087
1168
  isFirstResumableStage: isFirstResumableStageForFix,
1169
+ // BEC-227 Phase 4 / Track D — review-fix iteration counter
1170
+ // (1..N) for the implement fixStage's decision artifact. Other
1171
+ // fixStages (test/review) don't emit decisions, so the value
1172
+ // is harmless when unused.
1173
+ iteration: rfIteration,
1174
+ // BEC-227 Phase 4 / Track B — undefined when the surgical
1175
+ // decision returned `legacy` (or fixStage !== "implement"),
1176
+ // which preserves the legacy assembled-prompt path.
1177
+ promptOverride: surgicalPrompt,
1178
+ suppressHandoff: surgicalSuppressHandoff,
1088
1179
  });
1089
1180
  // BEC-134: track latest review stage_run id for fanout persistence.
1090
1181
  if (fixStage === "review") {
@@ -1118,7 +1209,12 @@ export class PipelineRunner {
1118
1209
  : isFirstResumableStageForFix
1119
1210
  ? "first-resumed"
1120
1211
  : "resumed";
1121
- const validation = await validateHandoff(fixStage, { artifact: fixResult.handoffArtifact, structured: fixResult.handoffIsStructured ?? false }, sanitizedIssue, repoConfig, worktreePath, fixStageRunMode);
1212
+ const validation = await validateHandoff(fixStage, {
1213
+ artifact: fixResult.handoffArtifact,
1214
+ structured: fixResult.handoffIsStructured ?? false,
1215
+ // BEC-227 Phase 4 / Track D — see main-stage call above.
1216
+ decisions: null,
1217
+ }, sanitizedIssue, repoConfig, worktreePath, fixStageRunMode);
1122
1218
  if (!validation.valid) {
1123
1219
  runLog.warn({ stage: fixStage, rfIteration, issues: validation.issues }, "review-fix: handoff validation failed");
1124
1220
  }
@@ -1716,6 +1812,11 @@ export class PipelineRunner {
1716
1812
  }
1717
1813
  else {
1718
1814
  runLog.warn("push queue: rebase conflicts detected, running implement pass to resolve");
1815
+ // Abort the in-progress rebase so the worktree HEAD returns to the
1816
+ // named branch ref before the agent starts writing new commits.
1817
+ // Without this, HEAD stays detached on the tentative rebase commit
1818
+ // and verifyBranchMatch() (BEC-99 guard) will reject the push.
1819
+ await abortRebase(wtPath);
1719
1820
  const isFirstResumableStageForResolve = claimFirstResumableStage("implement");
1720
1821
  const resolveResult = await executeStage({
1721
1822
  runId,
@@ -1736,8 +1837,7 @@ export class PipelineRunner {
1736
1837
  run.totalInputTokens += resolveResult.inputTokens;
1737
1838
  run.totalOutputTokens += resolveResult.outputTokens;
1738
1839
  if (resolveResult.status !== "completed") {
1739
- runLog.warn("push queue: conflict resolution failed — aborting rebase and force-pushing for human review");
1740
- await abortRebase(wtPath);
1840
+ runLog.warn("push queue: conflict resolution failed — force-pushing for human review");
1741
1841
  rebaseConflict = true;
1742
1842
  }
1743
1843
  else {
@@ -1769,9 +1869,11 @@ export class PipelineRunner {
1769
1869
  const [qualityResult, agentCommits] = await Promise.all([
1770
1870
  (async () => {
1771
1871
  try {
1772
- const stored = await getTriageResult(this.db, sanitizedIssue.id);
1872
+ const [stored, actualFiles] = await Promise.all([
1873
+ getTriageResult(this.db, sanitizedIssue.id),
1874
+ getChangedFiles(wtPath, repoConfig.defaultBranch),
1875
+ ]);
1773
1876
  const predicted = stored?.affectedFiles;
1774
- const actualFiles = await getChangedFiles(wtPath, repoConfig.defaultBranch);
1775
1877
  const quality = computeAffectedFilesPredictionQuality(predicted, actualFiles);
1776
1878
  await logAuditEvent(this.db, pmTriageQualityScoreEvent({
1777
1879
  runId,
@@ -2437,13 +2539,6 @@ export class PipelineRunner {
2437
2539
  context.pipelineConfig &&
2438
2540
  context.repoConfig &&
2439
2541
  context.sanitizedIssue) {
2440
- const resumePayload = JSON.stringify({
2441
- handoff: context.handoff ?? null,
2442
- pipelineConfig: context.pipelineConfig,
2443
- repoConfig: context.repoConfig,
2444
- sanitizedIssue: context.sanitizedIssue,
2445
- worktreePath: context.worktreePath,
2446
- });
2447
2542
  // Store currentStageIndex - 1 so the existing resume path's
2448
2543
  // `slice(startStageIndex + 1)` lands back on the failed stage.
2449
2544
  // (await-approval stores the completed stage index; we need to re-run the failed one.)
@@ -2451,6 +2546,7 @@ export class PipelineRunner {
2451
2546
  // re-runs the full stage list. The await-approval path stores the completed
2452
2547
  // stage index; we store failedIndex - 1 so the same +1 offset re-runs the failed stage.
2453
2548
  const resumeStageIndex = (context.currentStageIndex ?? 0) - 1;
2549
+ const resumePayload = buildResumePayload(context.handoff ?? null, context.pipelineConfig, context.repoConfig, context.sanitizedIssue, context.worktreePath, resumeStageIndex);
2454
2550
  await db
2455
2551
  .update(pipelineRuns)
2456
2552
  .set({