@cat-factory/orchestration 0.129.7 → 0.129.8

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.
@@ -265,6 +265,25 @@ export declare class RunDispatcher {
265
265
  */
266
266
  pollAgentJob(workspaceId: string, executionId: string): Promise<AdvanceResult>;
267
267
  private pollAgentJobInner;
268
+ /**
269
+ * Handle a `running` poll: a successful poll proves the container is up, so surface live subtask
270
+ * progress (e.g. 3/8 todos) without advancing the step. Only persist + emit when something
271
+ * actually changed so an idle poll doesn't churn storage or the event stream. Folds the poll's
272
+ * delta via {@link applyRunningFold} — a cheap pre-check against the loaded snapshot, then the
273
+ * authoritative re-apply on fresh state under CAS (idempotent for the set-to-latest folds and
274
+ * correct for the drain-on-read follow-up append). Split from {@link pollAgentJobInner} to stay
275
+ * under the statement ceiling.
276
+ */
277
+ private handleRunningPoll;
278
+ /**
279
+ * A gate whose helper INVESTIGATES instead of fixing (post-release-health → on-call) declares a
280
+ * `resolveHelperCompletion` hook. When such a helper's job settles — done OR failed — call the
281
+ * hook INSTEAD of re-probing the precheck (re-probing an investigate-don't-fix helper would just
282
+ * regress again and burn the budget) and finish the gate step with the output it returns. Returns
283
+ * the resulting {@link AdvanceResult}, or `null` when this branch doesn't apply (the caller falls
284
+ * through to the re-probe / other completion paths).
285
+ */
286
+ private resolveInvestigateHelperCompletion;
268
287
  /**
269
288
  * Fold a running poll's container signals into `step.container`: a successful poll
270
289
  * proves the container is `up`, and the harness's live phase (clone / agent / push)
@@ -357,6 +376,34 @@ export declare class RunDispatcher {
357
376
  * Shared by the inline path and the async-job poll path.
358
377
  */
359
378
  private recordStepResult;
379
+ /**
380
+ * Park a step on the durable decision-wait: pause it for input, flip the run + block to
381
+ * `blocked`, persist under CAS, emit, and report `awaiting_decision` keyed by `decisionId`.
382
+ * Shared by the raised-decision and human-approval branches of {@link recordStepResult}.
383
+ */
384
+ private parkStepAwaitingInput;
385
+ /**
386
+ * Record any PR(s) the step opened onto the block (its own-service PR + any peer-service PRs),
387
+ * and best-effort write back to the task's linked tracker issue(s) when the own-service PR is
388
+ * NEWLY opened (a retry that re-reports the same PR must not re-comment). Split from
389
+ * {@link recordStepResult} to keep it under the statement ceiling; a no-op when no PR was opened.
390
+ */
391
+ private recordOpenedPullRequests;
392
+ /**
393
+ * Run any POST-COMPLETION resolver registered for this step kind (blueprint/spec ingestion,
394
+ * task-estimate persistence). It reshapes the agent's structured result into domain state and may
395
+ * replace `step.output`. A no-op when no post-completion resolver applies. See
396
+ * {@link buildStepResolverRegistry} and {@link StepCompletionResolver.phase}.
397
+ */
398
+ private applyPostCompletionResolver;
399
+ /**
400
+ * Run any DETERMINISTIC terminal-phase resolver for this step kind (e.g. the merger performs the
401
+ * real GitHub merge with backend-held credentials), mutating `step.output` when it reshapes it.
402
+ * Position-independent: it fires whenever the step finishes, not only when it's last. Returns
403
+ * whether the resolver OWNS the block's terminal status (the merger sets `done`/`pr_ready`), so
404
+ * the advance/finalize path leaves that status alone rather than clobbering it to `in_progress`.
405
+ */
406
+ private applyTerminalStepResolver;
360
407
  /**
361
408
  * File a tracking issue/ticket for a `tracker` step from the preceding `analysis`
362
409
  * output. Non-LLM and best-effort: when no provider is wired or none is configured
@@ -1 +1 @@
1
- {"version":3,"file":"RunDispatcher.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/RunDispatcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RunDispatcher.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/RunDispatcher.ts"],"names":[],"mappings":"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"}
@@ -527,42 +527,7 @@ export class RunDispatcher {
527
527
  agentKind: step.agentKind,
528
528
  });
529
529
  if (update.state === 'running') {
530
- // A successful poll proves the container is up, so the cold-boot phase is over
531
- // (defensive: a replay may have left the flag set). Surface live subtask progress
532
- // (e.g. 3/8 todos done) without advancing the step. Only persist + emit when something
533
- // actually changed so an idle poll doesn't churn storage or the event stream.
534
- //
535
- // Fold the poll's delta onto a target instance via {@link applyRunningFold}. The captured
536
- // `update` is the source, so re-applying on a freshly-reloaded instance is idempotent for
537
- // the set-to-latest folds AND correct for the APPEND fold: the harness follow-up buffer is
538
- // drain-on-read (`runner.ts`), so those streamed items exist ONLY on this `update` — abort-
539
- // and-redrive would lose them, whereas re-applying under `mutateInstance` (which reloads a
540
- // clean base each attempt) preserves them.
541
- const foldCtx = { jobId: step.jobId, update, workspaceId };
542
- // Cheap pre-check against the loaded snapshot: skip the write entirely on an idle poll
543
- // (the common case). The mutation is discarded — the authoritative write re-applies the
544
- // same fold on fresh state under CAS below.
545
- if (await this.applyRunningFold(instance, foldCtx)) {
546
- try {
547
- const persisted = await this.runStateMachine.mutateInstance(workspaceId, executionId, async (fresh) => {
548
- await this.applyRunningFold(fresh, foldCtx);
549
- });
550
- // Progress-only fold (subtask ticks / streamed follow-ups): skip the per-run
551
- // LLM-metrics GROUP BY so a live container's poll cadence doesn't re-aggregate
552
- // the run on every tick. The rollup refreshes on the step-boundary/terminal emit.
553
- await this.runStateMachine.emitInstance(workspaceId, persisted, { rollUpMetrics: false });
554
- }
555
- catch (error) {
556
- // The run was cancelled/removed mid-poll (`NotFoundError`) or stayed hot-contended
557
- // past the retry budget (`ConflictError`) — re-drive on fresh state rather than
558
- // failing the run; the next entry no-ops on a gone/terminal run.
559
- if (error instanceof NotFoundError || error instanceof ConflictError) {
560
- throw new RunContendedError(executionId);
561
- }
562
- throw error;
563
- }
564
- }
565
- return { kind: 'awaiting_job', jobId: step.jobId, stepIndex: instance.currentStep };
530
+ return this.handleRunningPoll(workspaceId, executionId, instance, update, step.jobId);
566
531
  }
567
532
  // A gate whose helper INVESTIGATES instead of fixing (post-release-health → on-call)
568
533
  // declares a `resolveHelperCompletion` hook on its definition. When such a helper's job
@@ -571,34 +536,9 @@ export class RunDispatcher {
571
536
  // budget) and finish the gate step with the output it returns. The gate raises its own
572
537
  // `release_regression` notification + enriches any open incident inside the hook (from the
573
538
  // signals stashed at escalation); the run then completes for a human to act out-of-band.
574
- const completionGate = this.gateFor(step.agentKind);
575
- if (completionGate?.resolveHelperCompletion &&
576
- step.gate?.phase === 'working' &&
577
- (update.state === 'done' || update.state === 'failed')) {
578
- const block = await this.blockRepository.get(workspaceId, instance.blockId);
579
- step.jobId = undefined;
580
- step.subtasks = undefined;
581
- if (!block)
582
- return { kind: 'noop' };
583
- const isFinalStep = instance.currentStep === instance.steps.length - 1;
584
- const jobResult = update.state === 'done'
585
- ? { state: 'done', result: update.result }
586
- : { state: 'failed', error: update.error ?? null };
587
- const resolution = await completionGate.resolveHelperCompletion({
588
- workspaceId,
589
- instance,
590
- block,
591
- step,
592
- result: jobResult,
593
- });
594
- // Preserve the done-result's fields (usage metering etc.) while recording the gate's
595
- // resolved output; a failed investigation has no result to carry.
596
- const base = update.state === 'done' ? update.result : { output: '' };
597
- return this.recordStepResult(workspaceId, instance, step, isFinalStep, {
598
- ...base,
599
- output: resolution.output,
600
- });
601
- }
539
+ const investigated = await this.resolveInvestigateHelperCompletion(workspaceId, instance, step, update);
540
+ if (investigated)
541
+ return investigated;
602
542
  // A polling gate step's in-flight job is its helper agent (ci-fixer /
603
543
  // conflict-resolver), NOT the step's own work: when it finishes (or fails) we
604
544
  // don't record a result or advance — we drop the handle, return the gate to
@@ -702,6 +642,81 @@ export class RunDispatcher {
702
642
  step.jobId = undefined;
703
643
  return this.recordStepResult(workspaceId, instance, step, isFinalStep, update.result);
704
644
  }
645
+ /**
646
+ * Handle a `running` poll: a successful poll proves the container is up, so surface live subtask
647
+ * progress (e.g. 3/8 todos) without advancing the step. Only persist + emit when something
648
+ * actually changed so an idle poll doesn't churn storage or the event stream. Folds the poll's
649
+ * delta via {@link applyRunningFold} — a cheap pre-check against the loaded snapshot, then the
650
+ * authoritative re-apply on fresh state under CAS (idempotent for the set-to-latest folds and
651
+ * correct for the drain-on-read follow-up append). Split from {@link pollAgentJobInner} to stay
652
+ * under the statement ceiling.
653
+ */
654
+ async handleRunningPoll(workspaceId, executionId, instance, update, jobId) {
655
+ const foldCtx = { jobId, update, workspaceId };
656
+ // Cheap pre-check against the loaded snapshot: skip the write entirely on an idle poll
657
+ // (the common case). The mutation is discarded — the authoritative write re-applies the
658
+ // same fold on fresh state under CAS below.
659
+ if (await this.applyRunningFold(instance, foldCtx)) {
660
+ try {
661
+ const persisted = await this.runStateMachine.mutateInstance(workspaceId, executionId, async (fresh) => {
662
+ await this.applyRunningFold(fresh, foldCtx);
663
+ });
664
+ // Progress-only fold (subtask ticks / streamed follow-ups): skip the per-run
665
+ // LLM-metrics GROUP BY so a live container's poll cadence doesn't re-aggregate
666
+ // the run on every tick. The rollup refreshes on the step-boundary/terminal emit.
667
+ await this.runStateMachine.emitInstance(workspaceId, persisted, { rollUpMetrics: false });
668
+ }
669
+ catch (error) {
670
+ // The run was cancelled/removed mid-poll (`NotFoundError`) or stayed hot-contended
671
+ // past the retry budget (`ConflictError`) — re-drive on fresh state rather than
672
+ // failing the run; the next entry no-ops on a gone/terminal run.
673
+ if (error instanceof NotFoundError || error instanceof ConflictError) {
674
+ throw new RunContendedError(executionId);
675
+ }
676
+ throw error;
677
+ }
678
+ }
679
+ return { kind: 'awaiting_job', jobId, stepIndex: instance.currentStep };
680
+ }
681
+ /**
682
+ * A gate whose helper INVESTIGATES instead of fixing (post-release-health → on-call) declares a
683
+ * `resolveHelperCompletion` hook. When such a helper's job settles — done OR failed — call the
684
+ * hook INSTEAD of re-probing the precheck (re-probing an investigate-don't-fix helper would just
685
+ * regress again and burn the budget) and finish the gate step with the output it returns. Returns
686
+ * the resulting {@link AdvanceResult}, or `null` when this branch doesn't apply (the caller falls
687
+ * through to the re-probe / other completion paths).
688
+ */
689
+ async resolveInvestigateHelperCompletion(workspaceId, instance, step, update) {
690
+ const completionGate = this.gateFor(step.agentKind);
691
+ if (completionGate?.resolveHelperCompletion &&
692
+ step.gate?.phase === 'working' &&
693
+ (update.state === 'done' || update.state === 'failed')) {
694
+ const block = await this.blockRepository.get(workspaceId, instance.blockId);
695
+ step.jobId = undefined;
696
+ step.subtasks = undefined;
697
+ if (!block)
698
+ return { kind: 'noop' };
699
+ const isFinalStep = instance.currentStep === instance.steps.length - 1;
700
+ const jobResult = update.state === 'done'
701
+ ? { state: 'done', result: update.result }
702
+ : { state: 'failed', error: update.error ?? null };
703
+ const resolution = await completionGate.resolveHelperCompletion({
704
+ workspaceId,
705
+ instance,
706
+ block,
707
+ step,
708
+ result: jobResult,
709
+ });
710
+ // Preserve the done-result's fields (usage metering etc.) while recording the gate's
711
+ // resolved output; a failed investigation has no result to carry.
712
+ const base = update.state === 'done' ? update.result : { output: '' };
713
+ return this.recordStepResult(workspaceId, instance, step, isFinalStep, {
714
+ ...base,
715
+ output: resolution.output,
716
+ });
717
+ }
718
+ return null;
719
+ }
705
720
  /**
706
721
  * Fold a running poll's container signals into `step.container`: a successful poll
707
722
  * proves the container is `up`, and the harness's live phase (clone / agent / push)
@@ -1049,12 +1064,7 @@ export class RunDispatcher {
1049
1064
  options: [...result.decision.options],
1050
1065
  chosen: null,
1051
1066
  };
1052
- this.stepGraph.pauseStepForInput(step);
1053
- instance.status = 'blocked';
1054
- await this.runStateMachine.updateBlockProgress(workspaceId, instance, 'blocked');
1055
- await this.runStateMachine.casPersist(workspaceId, instance);
1056
- await this.runStateMachine.emitInstance(workspaceId, instance);
1057
- return { kind: 'awaiting_decision', decisionId: step.decision.id };
1067
+ return this.parkStepAwaitingInput(workspaceId, instance, step, step.decision.id);
1058
1068
  }
1059
1069
  // Completion-path interceptors short-circuit before the normal finish/advance for the
1060
1070
  // few kinds whose verdict drives run flow: a container-backed companion applies its
@@ -1095,30 +1105,7 @@ export class RunDispatcher {
1095
1105
  // (service-connections phase 3) additionally reports the PRs it opened in the
1096
1106
  // connected involved-service repos; record them beside the own-service PR (they may
1097
1107
  // even arrive when the own service was a no-op and only a peer changed).
1098
- if (result.pullRequest || result.peerPullRequests?.length) {
1099
- // Read the block before the update so we can tell whether this PR is newly
1100
- // opened (vs. the same PR re-reported by a re-run/retry of the coder step).
1101
- const priorBlock = this.issueWriteback
1102
- ? await this.blockRepository.get(workspaceId, instance.blockId)
1103
- : null;
1104
- await this.blockRepository.update(workspaceId, instance.blockId, {
1105
- ...(result.pullRequest ? { pullRequest: result.pullRequest } : {}),
1106
- ...(result.peerPullRequests?.length ? { peerPullRequests: result.peerPullRequests } : {}),
1107
- });
1108
- // Best-effort writeback: comment on the task's linked tracker issue(s) that a
1109
- // PR opened. Only for the OWN-service PR, and only when it is newly recorded — a
1110
- // retry that re-reports the same PR must not re-comment (the tracker comment is not
1111
- // idempotent). Gated inside the provider by the workspace setting + per-task
1112
- // override; fire-and-forget so a tracker outage never fails the run.
1113
- if (this.issueWriteback &&
1114
- priorBlock &&
1115
- result.pullRequest &&
1116
- priorBlock.pullRequest?.url !== result.pullRequest.url) {
1117
- await this.issueWriteback
1118
- .onPullRequestOpened(workspaceId, priorBlock, result.pullRequest)
1119
- .catch(() => { });
1120
- }
1121
- }
1108
+ await this.recordOpenedPullRequests(workspaceId, instance, result);
1122
1109
  // Run any POST-COMPLETION resolver registered for this step kind (blueprint/spec
1123
1110
  // ingestion, task-estimate persistence). It reshapes the agent's structured result into
1124
1111
  // domain state and may replace `step.output` (the estimator's readable summary). Its
@@ -1126,19 +1113,7 @@ export class RunDispatcher {
1126
1113
  // reviewable-output rendering and the follow-up/approval gates read `step.output`, so it
1127
1114
  // sits exactly where the old inline ingestion branches did. See
1128
1115
  // {@link buildStepResolverRegistry} and {@link StepCompletionResolver.phase}.
1129
- const postCompletionResolver = this.stepResolverFor(step.agentKind);
1130
- if (postCompletionResolver?.phase === 'post-completion' &&
1131
- (postCompletionResolver.applies?.(result) ?? true)) {
1132
- const resolution = await postCompletionResolver.resolve({
1133
- workspaceId,
1134
- instance,
1135
- step,
1136
- result,
1137
- isFinalStep,
1138
- });
1139
- if (resolution?.output !== undefined)
1140
- step.output = resolution.output;
1141
- }
1116
+ await this.applyPostCompletionResolver(workspaceId, instance, step, result, isFinalStep);
1142
1117
  // A producer that emits a STRUCTURED ARTIFACT (the spec doc, the blueprint tree, …)
1143
1118
  // returns its raw Pi transcript summary as `result.output` — useless for review.
1144
1119
  // Replace the step's reviewable output with a rendering of the artifact ITSELF, so
@@ -1173,12 +1148,7 @@ export class RunDispatcher {
1173
1148
  status: 'pending',
1174
1149
  proposal: step.output,
1175
1150
  };
1176
- this.stepGraph.pauseStepForInput(step);
1177
- instance.status = 'blocked';
1178
- await this.runStateMachine.updateBlockProgress(workspaceId, instance, 'blocked');
1179
- await this.runStateMachine.casPersist(workspaceId, instance);
1180
- await this.runStateMachine.emitInstance(workspaceId, instance);
1181
- return { kind: 'awaiting_decision', decisionId: step.approval.id };
1151
+ return this.parkStepAwaitingInput(workspaceId, instance, step, step.approval.id);
1182
1152
  }
1183
1153
  // Persist the agent's reported confidence whenever a step reports it, for board
1184
1154
  // transparency. Position-independent: it must NOT be tied to the final step, since a
@@ -1194,23 +1164,7 @@ export class RunDispatcher {
1194
1164
  // — so inserting a later step (post-release-health) can't silently disable it. A
1195
1165
  // resolver that owns the block's terminal status (the merger sets `done`/`pr_ready`)
1196
1166
  // tells `finalizeBlock` to leave it alone.
1197
- const resolver = this.stepResolverFor(step.agentKind);
1198
- let resolverOwnsTerminalStatus = false;
1199
- if (resolver &&
1200
- (resolver.phase ?? 'terminal') === 'terminal' &&
1201
- (resolver.applies?.(result) ?? true)) {
1202
- const resolution = await resolver.resolve({
1203
- workspaceId,
1204
- instance,
1205
- step,
1206
- result,
1207
- isFinalStep,
1208
- });
1209
- if (resolution?.output !== undefined)
1210
- step.output = resolution.output;
1211
- if (resolution?.ownsTerminalStatus)
1212
- resolverOwnsTerminalStatus = true;
1213
- }
1167
+ const resolverOwnsTerminalStatus = await this.applyTerminalStepResolver(workspaceId, instance, step, result, isFinalStep);
1214
1168
  // A registered custom kind's POST-ops run deterministic backend repo work from the
1215
1169
  // agent's structured result (coerce its JSON, render artifact files, commit them via
1216
1170
  // the checkout-free RepoFiles port — the blueprint/spec rendering that used to live in
@@ -1251,6 +1205,92 @@ export class RunDispatcher {
1251
1205
  await this.runStateMachine.emitInstance(workspaceId, instance);
1252
1206
  return { kind: 'continue' };
1253
1207
  }
1208
+ /**
1209
+ * Park a step on the durable decision-wait: pause it for input, flip the run + block to
1210
+ * `blocked`, persist under CAS, emit, and report `awaiting_decision` keyed by `decisionId`.
1211
+ * Shared by the raised-decision and human-approval branches of {@link recordStepResult}.
1212
+ */
1213
+ async parkStepAwaitingInput(workspaceId, instance, step, decisionId) {
1214
+ this.stepGraph.pauseStepForInput(step);
1215
+ instance.status = 'blocked';
1216
+ await this.runStateMachine.updateBlockProgress(workspaceId, instance, 'blocked');
1217
+ await this.runStateMachine.casPersist(workspaceId, instance);
1218
+ await this.runStateMachine.emitInstance(workspaceId, instance);
1219
+ return { kind: 'awaiting_decision', decisionId };
1220
+ }
1221
+ /**
1222
+ * Record any PR(s) the step opened onto the block (its own-service PR + any peer-service PRs),
1223
+ * and best-effort write back to the task's linked tracker issue(s) when the own-service PR is
1224
+ * NEWLY opened (a retry that re-reports the same PR must not re-comment). Split from
1225
+ * {@link recordStepResult} to keep it under the statement ceiling; a no-op when no PR was opened.
1226
+ */
1227
+ async recordOpenedPullRequests(workspaceId, instance, result) {
1228
+ if (!(result.pullRequest || result.peerPullRequests?.length))
1229
+ return;
1230
+ // Read the block before the update so we can tell whether this PR is newly
1231
+ // opened (vs. the same PR re-reported by a re-run/retry of the coder step).
1232
+ const priorBlock = this.issueWriteback
1233
+ ? await this.blockRepository.get(workspaceId, instance.blockId)
1234
+ : null;
1235
+ await this.blockRepository.update(workspaceId, instance.blockId, {
1236
+ ...(result.pullRequest ? { pullRequest: result.pullRequest } : {}),
1237
+ ...(result.peerPullRequests?.length ? { peerPullRequests: result.peerPullRequests } : {}),
1238
+ });
1239
+ // Best-effort writeback: comment on the task's linked tracker issue(s) that a
1240
+ // PR opened. Only for the OWN-service PR, and only when it is newly recorded — a
1241
+ // retry that re-reports the same PR must not re-comment (the tracker comment is not
1242
+ // idempotent). Gated inside the provider by the workspace setting + per-task
1243
+ // override; fire-and-forget so a tracker outage never fails the run.
1244
+ if (this.issueWriteback &&
1245
+ priorBlock &&
1246
+ result.pullRequest &&
1247
+ priorBlock.pullRequest?.url !== result.pullRequest.url) {
1248
+ await this.issueWriteback
1249
+ .onPullRequestOpened(workspaceId, priorBlock, result.pullRequest)
1250
+ .catch(() => { });
1251
+ }
1252
+ }
1253
+ /**
1254
+ * Run any POST-COMPLETION resolver registered for this step kind (blueprint/spec ingestion,
1255
+ * task-estimate persistence). It reshapes the agent's structured result into domain state and may
1256
+ * replace `step.output`. A no-op when no post-completion resolver applies. See
1257
+ * {@link buildStepResolverRegistry} and {@link StepCompletionResolver.phase}.
1258
+ */
1259
+ async applyPostCompletionResolver(workspaceId, instance, step, result, isFinalStep) {
1260
+ const postCompletionResolver = this.stepResolverFor(step.agentKind);
1261
+ if (postCompletionResolver?.phase !== 'post-completion' ||
1262
+ !(postCompletionResolver.applies?.(result) ?? true)) {
1263
+ return;
1264
+ }
1265
+ const resolution = await postCompletionResolver.resolve({
1266
+ workspaceId,
1267
+ instance,
1268
+ step,
1269
+ result,
1270
+ isFinalStep,
1271
+ });
1272
+ if (resolution?.output !== undefined)
1273
+ step.output = resolution.output;
1274
+ }
1275
+ /**
1276
+ * Run any DETERMINISTIC terminal-phase resolver for this step kind (e.g. the merger performs the
1277
+ * real GitHub merge with backend-held credentials), mutating `step.output` when it reshapes it.
1278
+ * Position-independent: it fires whenever the step finishes, not only when it's last. Returns
1279
+ * whether the resolver OWNS the block's terminal status (the merger sets `done`/`pr_ready`), so
1280
+ * the advance/finalize path leaves that status alone rather than clobbering it to `in_progress`.
1281
+ */
1282
+ async applyTerminalStepResolver(workspaceId, instance, step, result, isFinalStep) {
1283
+ const resolver = this.stepResolverFor(step.agentKind);
1284
+ if (!resolver ||
1285
+ (resolver.phase ?? 'terminal') !== 'terminal' ||
1286
+ !(resolver.applies?.(result) ?? true)) {
1287
+ return false;
1288
+ }
1289
+ const resolution = await resolver.resolve({ workspaceId, instance, step, result, isFinalStep });
1290
+ if (resolution?.output !== undefined)
1291
+ step.output = resolution.output;
1292
+ return resolution?.ownsTerminalStatus ?? false;
1293
+ }
1254
1294
  /**
1255
1295
  * File a tracking issue/ticket for a `tracker` step from the preceding `analysis`
1256
1296
  * output. Non-LLM and best-effort: when no provider is wired or none is configured