@osolmaz/pi-workflows 0.13.0 → 0.13.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 (84) hide show
  1. package/README.md +11 -9
  2. package/dist/builtins/autodoc.workflow.d.ts +191 -4
  3. package/dist/builtins/autodoc.workflow.js +156 -30
  4. package/dist/builtins/autodoc.workflow.js.map +1 -1
  5. package/dist/builtins/autoimplement-command-batches.d.ts +1 -0
  6. package/dist/builtins/autoimplement-command-batches.js +29 -31
  7. package/dist/builtins/autoimplement-command-batches.js.map +1 -1
  8. package/dist/builtins/autoimplement.workflow.d.ts +1259 -29
  9. package/dist/builtins/autoimplement.workflow.js +416 -153
  10. package/dist/builtins/autoimplement.workflow.js.map +1 -1
  11. package/dist/builtins/autoplan.workflow.d.ts +6 -0
  12. package/dist/builtins/autoplan.workflow.js +68 -32
  13. package/dist/builtins/autoplan.workflow.js.map +1 -1
  14. package/dist/builtins/catalog.js +5 -5
  15. package/dist/builtins/catalog.js.map +1 -1
  16. package/dist/builtins/change-verification.workflow.d.ts +110 -0
  17. package/dist/builtins/change-verification.workflow.js +860 -0
  18. package/dist/builtins/change-verification.workflow.js.map +1 -0
  19. package/dist/builtins/monitor.workflow.js +4 -3
  20. package/dist/builtins/monitor.workflow.js.map +1 -1
  21. package/dist/builtins/plain-summary.workflow.js +35 -24
  22. package/dist/builtins/plain-summary.workflow.js.map +1 -1
  23. package/dist/builtins/plan-change.workflow.d.ts +361 -6
  24. package/dist/builtins/plan-change.workflow.js +26 -0
  25. package/dist/builtins/plan-change.workflow.js.map +1 -1
  26. package/dist/builtins/sanity-check.workflow.js +19 -22
  27. package/dist/builtins/sanity-check.workflow.js.map +1 -1
  28. package/dist/builtins/workspace-preparation.workflow.d.ts +75 -0
  29. package/dist/builtins/workspace-preparation.workflow.js +498 -0
  30. package/dist/builtins/workspace-preparation.workflow.js.map +1 -0
  31. package/dist/controllers/sqlite.js +16 -51
  32. package/dist/controllers/sqlite.js.map +1 -1
  33. package/dist/extension/decision-channels.js +45 -7
  34. package/dist/extension/decision-channels.js.map +1 -1
  35. package/dist/extension/executor.js +1 -4
  36. package/dist/extension/executor.js.map +1 -1
  37. package/dist/extension/index.js +2 -15
  38. package/dist/extension/index.js.map +1 -1
  39. package/dist/extension/recorder.d.ts +1 -1
  40. package/dist/extension/recorder.js +8 -8
  41. package/dist/extension/recorder.js.map +1 -1
  42. package/dist/state/schema.js +22 -3
  43. package/dist/state/schema.js.map +1 -1
  44. package/dist/viewer/session-reducer.d.ts +0 -1
  45. package/dist/viewer/session-reducer.js +2 -24
  46. package/dist/viewer/session-reducer.js.map +1 -1
  47. package/dist/workflows/engine.js +4 -3
  48. package/dist/workflows/engine.js.map +1 -1
  49. package/dist/workflows/store.d.ts +6 -1
  50. package/dist/workflows/store.js +286 -33
  51. package/dist/workflows/store.js.map +1 -1
  52. package/dist/workflows/types.d.ts +1 -1
  53. package/docs/SQLITE_STATE.md +20 -14
  54. package/docs/WORKFLOW_COMPOSITION.md +8 -0
  55. package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +1 -1
  56. package/docs/plans/2026-08-24-change-scoped-verification-plan.md +419 -0
  57. package/docs/plans/2026-08-25-autoplan-user-intent-capture-plan.md +107 -0
  58. package/docs/session-event-journal.md +2 -3
  59. package/docs/workflows.md +43 -21
  60. package/herdr-plugin.toml +1 -1
  61. package/package.json +1 -1
  62. package/skills/autodoc/SKILL.md +7 -0
  63. package/skills/autoimplement/SKILL.md +4 -0
  64. package/src/builtins/autodoc.workflow.ts +184 -33
  65. package/src/builtins/autoimplement-command-batches.ts +39 -33
  66. package/src/builtins/autoimplement.workflow.ts +483 -175
  67. package/src/builtins/autoplan.workflow.ts +80 -32
  68. package/src/builtins/catalog.ts +5 -5
  69. package/src/builtins/change-verification.workflow.ts +1143 -0
  70. package/src/builtins/monitor.workflow.ts +6 -3
  71. package/src/builtins/plain-summary.workflow.ts +38 -40
  72. package/src/builtins/plan-change.workflow.ts +35 -0
  73. package/src/builtins/sanity-check.workflow.ts +19 -22
  74. package/src/builtins/workspace-preparation.workflow.ts +668 -0
  75. package/src/controllers/sqlite.ts +19 -53
  76. package/src/extension/decision-channels.ts +47 -7
  77. package/src/extension/executor.ts +1 -4
  78. package/src/extension/index.ts +2 -15
  79. package/src/extension/recorder.ts +10 -8
  80. package/src/state/schema.ts +22 -3
  81. package/src/viewer/session-reducer.ts +2 -29
  82. package/src/workflows/engine.ts +4 -3
  83. package/src/workflows/store.ts +397 -43
  84. package/src/workflows/types.ts +0 -1
@@ -27,15 +27,25 @@ import {
27
27
  type PublishedRepository,
28
28
  type VerificationCommandPlan,
29
29
  } from "./autoimplement-command-batches.js";
30
+ import changeVerificationWorkflow, {
31
+ type ChangeVerificationInput,
32
+ type VerificationCheck,
33
+ } from "./change-verification.workflow.js";
30
34
  import { parsePlanApprovalPolicy, type PlanApprovalPolicy } from "./plan-approval.workflow.js";
31
35
  import planChangeWorkflow, { type NormalizedPlanChangeInput } from "./plan-change.workflow.js";
36
+ import workspacePreparationWorkflow, {
37
+ parsePreparedWorkspace,
38
+ type PreparedWorkspace,
39
+ type WorkspaceMode,
40
+ type WorkspacePreparationInput,
41
+ } from "./workspace-preparation.workflow.js";
32
42
 
33
43
  export type AutoimplementInput = {
34
44
  task: string;
35
45
  plan?: unknown;
36
46
  scope?: string;
37
47
  constraints?: string[];
38
- repository?: string;
48
+ repository: string;
39
49
  baseBranch?: string;
40
50
  merge?: boolean;
41
51
  documents?: string[];
@@ -46,6 +56,10 @@ export type AutoimplementInput = {
46
56
  };
47
57
  approval?: PlanApprovalPolicy;
48
58
  concurrency?: Partial<AutoimplementConcurrency>;
59
+ workspaceMode?: WorkspaceMode;
60
+ directDefaultBranchAuthorized?: boolean;
61
+ preparedWorkspace?: PreparedWorkspace;
62
+ verificationChecks?: VerificationCheck[];
49
63
  };
50
64
 
51
65
  export type ExistingPlanDiscovery = {
@@ -106,6 +120,16 @@ export type AutoimplementBlocked = {
106
120
  evidence: unknown;
107
121
  };
108
122
 
123
+ type BlockerStage =
124
+ | "planDiscovery"
125
+ | "documentation"
126
+ | "implementation"
127
+ | "repair"
128
+ | "review"
129
+ | "ci"
130
+ | "delivery"
131
+ | "redesign";
132
+
109
133
  type BlockerChallenge = {
110
134
  route: "continue" | "blocked";
111
135
  blockingNow: boolean;
@@ -113,10 +137,26 @@ type BlockerChallenge = {
113
137
  canProceed: boolean;
114
138
  reason: string;
115
139
  nextAction: string;
140
+ nextStage: BlockerStage | null;
116
141
  alternativesChecked: string[];
117
142
  evidence: string[];
118
143
  };
119
144
 
145
+ type BlockerClaim = {
146
+ schema: "pi-workflows.blocker-claim.v1";
147
+ sourceNode: string;
148
+ attemptId: string;
149
+ route: string;
150
+ reason: string;
151
+ evidence: unknown;
152
+ failedCommands: unknown[];
153
+ relatedFailures: unknown[];
154
+ unrelatedFailures: unknown[];
155
+ recoveryAttempts: unknown[];
156
+ alternativesChecked: string[];
157
+ authorityFact: string;
158
+ };
159
+
120
160
  const MAX_BLOCKER_CHALLENGES = 3;
121
161
  const MAX_CHALLENGE_ITEMS = 5;
122
162
  const MAX_CHALLENGE_TEXT = 500;
@@ -133,6 +173,7 @@ const TIMEOUT_FALLBACK_SOURCES = [
133
173
  "inspectComments",
134
174
  "inspectCi",
135
175
  "opportunisticTest",
176
+ "finalizeDefaultBranch",
136
177
  "finalizeDelivery",
137
178
  ] as const;
138
179
 
@@ -152,6 +193,7 @@ const TIMEOUT_FALLBACK_ROUTES: Record<TimeoutFallbackSource, readonly TimeoutFal
152
193
  inspectComments: ["retry", "review", "ci", "replan", "blocked"],
153
194
  inspectCi: ["retry", "ci", "deliver", "replan", "blocked"],
154
195
  opportunisticTest: ["retry", "ci", "deliver", "replan", "blocked"],
196
+ finalizeDefaultBranch: ["retry", "replan", "blocked"],
155
197
  finalizeDelivery: ["retry", "deliver", "replan", "blocked"],
156
198
  };
157
199
 
@@ -175,6 +217,12 @@ function requireString(value: unknown, label: string): string {
175
217
  return value.trim();
176
218
  }
177
219
 
220
+ function requireAbsolutePath(value: unknown, label: string): string {
221
+ const result = requireString(value, label);
222
+ if (!path.isAbsolute(result)) throw new Error(`${label} must be absolute`);
223
+ return path.resolve(result);
224
+ }
225
+
178
226
  function requireStringArray(value: unknown, label: string): string[] {
179
227
  if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
180
228
  throw new Error(`${label} must be an array of strings`);
@@ -202,9 +250,14 @@ function isTimeoutFallbackSource(nodeId: string): nodeId is TimeoutFallbackSourc
202
250
  function latestTimedOutStep(context: WorkflowNodeContext) {
203
251
  for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
204
252
  const step = context.state.steps[index];
205
- if (step?.outcome === "timed_out" && isTimeoutFallbackSource(step.nodeId)) return step;
253
+ if (
254
+ (step?.outcome === "timed_out" || step?.outcome === "failed") &&
255
+ isTimeoutFallbackSource(step.nodeId)
256
+ ) {
257
+ return step;
258
+ }
206
259
  }
207
- throw new Error("No supported timed-out Autoimplement step is available");
260
+ throw new Error("No supported failed Autoimplement step is available");
208
261
  }
209
262
 
210
263
  function latestStepIndex(
@@ -302,7 +355,7 @@ function timeoutFallbackTarget(context: WorkflowNodeContext): { route: string }
302
355
  const fallback = context.outputs.timeoutFallback as TimeoutFallbackResult;
303
356
  if (fallback.route !== "retry") {
304
357
  const routes: Record<Exclude<TimeoutFallbackRoute, "retry">, string> = {
305
- verify: "planVerification",
358
+ verify: "selectVerificationPath",
306
359
  review: "selectReviewCommands",
307
360
  ci: "inspectCi",
308
361
  deliver: "finalizeDelivery",
@@ -321,7 +374,11 @@ function timeoutFallbackGuard(context: WorkflowNodeContext) {
321
374
  ).length;
322
375
  if (attempts >= MAX_TIMEOUT_FALLBACKS) {
323
376
  const timeouts = context.state.steps
324
- .filter((step) => step.outcome === "timed_out" && isTimeoutFallbackSource(step.nodeId))
377
+ .filter(
378
+ (step) =>
379
+ (step.outcome === "timed_out" || step.outcome === "failed") &&
380
+ isTimeoutFallbackSource(step.nodeId),
381
+ )
325
382
  .map((step) => ({
326
383
  nodeId: step.nodeId,
327
384
  attemptId: step.attemptId,
@@ -349,16 +406,6 @@ function timeoutFallbackGuard(context: WorkflowNodeContext) {
349
406
  };
350
407
  }
351
408
 
352
- function throwLatestSupportedFailure(context: WorkflowNodeContext): never {
353
- for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
354
- const step = context.state.steps[index];
355
- if (step?.outcome === "failed" && isTimeoutFallbackSource(step.nodeId)) {
356
- throw new Error(step.error ?? `Autoimplement node failed: ${step.nodeId}`);
357
- }
358
- }
359
- throw new Error("No supported failed Autoimplement step is available");
360
- }
361
-
362
409
  function parseBlockerChallenge(value: unknown): BlockerChallenge {
363
410
  const result = requireRecord(value, "blocker challenge");
364
411
  if (result.route !== "continue" && result.route !== "blocked") {
@@ -385,6 +432,20 @@ function parseBlockerChallenge(value: unknown): BlockerChallenge {
385
432
  `blocker challenge nextAction must be at most ${MAX_CHALLENGE_TEXT} characters`,
386
433
  );
387
434
  }
435
+ const stages: BlockerStage[] = [
436
+ "planDiscovery",
437
+ "documentation",
438
+ "implementation",
439
+ "repair",
440
+ "review",
441
+ "ci",
442
+ "delivery",
443
+ "redesign",
444
+ ];
445
+ const nextStage = result.nextStage === null ? null : result.nextStage;
446
+ if (nextStage !== null && !stages.includes(nextStage as BlockerStage)) {
447
+ throw new Error(`blocker challenge nextStage must be one of ${stages.join(", ")} or null`);
448
+ }
388
449
  const alternativesChecked = boundedChallengeItems(
389
450
  result.alternativesChecked,
390
451
  "blocker challenge alternativesChecked",
@@ -397,6 +458,7 @@ function parseBlockerChallenge(value: unknown): BlockerChallenge {
397
458
  outsideAuthority !== true ||
398
459
  canProceed !== false ||
399
460
  nextAction.length > 0 ||
461
+ nextStage !== null ||
400
462
  alternativesChecked.length === 0 ||
401
463
  evidence.length === 0
402
464
  ) {
@@ -404,8 +466,10 @@ function parseBlockerChallenge(value: unknown): BlockerChallenge {
404
466
  "blocked challenge requires blockingNow=true, outsideAuthority=true, canProceed=false, an empty nextAction, and concrete alternatives and evidence",
405
467
  );
406
468
  }
407
- } else if (canProceed !== true || nextAction.length === 0) {
408
- throw new Error("continue challenge requires canProceed=true and a practical nextAction");
469
+ } else if (canProceed !== true || nextAction.length === 0 || nextStage === null) {
470
+ throw new Error(
471
+ "continue challenge requires canProceed=true, a practical nextAction, and nextStage",
472
+ );
409
473
  }
410
474
 
411
475
  return {
@@ -415,6 +479,7 @@ function parseBlockerChallenge(value: unknown): BlockerChallenge {
415
479
  canProceed,
416
480
  reason,
417
481
  nextAction,
482
+ nextStage: nextStage as BlockerStage | null,
418
483
  alternativesChecked,
419
484
  evidence,
420
485
  };
@@ -463,14 +528,36 @@ function parseInput(value: unknown): AutoimplementInput {
463
528
  }
464
529
  const concurrency = parseAutoimplementConcurrency(input.concurrency);
465
530
  const approval = parsePlanApprovalPolicy(input.approval);
531
+ let workspaceMode: WorkspaceMode | undefined;
532
+ if (input.workspaceMode !== undefined) {
533
+ if (
534
+ input.workspaceMode !== "auto" &&
535
+ input.workspaceMode !== "branch" &&
536
+ input.workspaceMode !== "worktree" &&
537
+ input.workspaceMode !== "defaultBranch"
538
+ ) {
539
+ throw new Error(
540
+ "autoimplement workspaceMode must be auto, branch, worktree, or defaultBranch",
541
+ );
542
+ }
543
+ workspaceMode = input.workspaceMode;
544
+ }
545
+ const preparedWorkspace =
546
+ input.preparedWorkspace === undefined
547
+ ? undefined
548
+ : parsePreparedWorkspace(input.preparedWorkspace);
549
+ if (input.verificationChecks !== undefined && !Array.isArray(input.verificationChecks)) {
550
+ throw new Error("autoimplement verificationChecks must be an array");
551
+ }
552
+ if (Array.isArray(input.verificationChecks) && input.verificationChecks.length === 0) {
553
+ throw new Error("autoimplement verificationChecks must be non-empty when supplied");
554
+ }
466
555
  return {
467
556
  task: requireString(input.task, "autoimplement task"),
468
557
  ...(input.plan !== undefined ? { plan: input.plan } : {}),
469
558
  ...(input.scope !== undefined ? { scope: requireString(input.scope, "scope") } : {}),
470
559
  ...(constraints !== undefined ? { constraints: [...constraints] as string[] } : {}),
471
- ...(input.repository !== undefined
472
- ? { repository: requireString(input.repository, "repository") }
473
- : {}),
560
+ repository: requireAbsolutePath(input.repository, "repository"),
474
561
  ...(input.baseBranch !== undefined
475
562
  ? { baseBranch: requireString(input.baseBranch, "baseBranch") }
476
563
  : {}),
@@ -479,6 +566,14 @@ function parseInput(value: unknown): AutoimplementInput {
479
566
  ...(documentation !== undefined ? { documentation } : {}),
480
567
  approval,
481
568
  concurrency,
569
+ ...(workspaceMode === undefined ? {} : { workspaceMode }),
570
+ ...(input.directDefaultBranchAuthorized === undefined
571
+ ? {}
572
+ : { directDefaultBranchAuthorized: input.directDefaultBranchAuthorized === true }),
573
+ ...(preparedWorkspace === undefined ? {} : { preparedWorkspace }),
574
+ ...(input.verificationChecks === undefined
575
+ ? {}
576
+ : { verificationChecks: input.verificationChecks as VerificationCheck[] }),
482
577
  };
483
578
  }
484
579
 
@@ -619,32 +714,100 @@ function currentPlan(context: WorkflowNodeContext): unknown {
619
714
  return (context.input as AutoimplementInput).plan;
620
715
  }
621
716
 
717
+ function preparedWorkspace(context: WorkflowNodeContext): PreparedWorkspace {
718
+ const request = context.input as AutoimplementInput;
719
+ if (request.preparedWorkspace !== undefined) return request.preparedWorkspace;
720
+ const result = includedResult(workspacePreparationWorkflow, context.outputs.workspace);
721
+ if (result.exit !== "ready") throw new Error("autoimplement workspace is not ready");
722
+ return result.output;
723
+ }
724
+
622
725
  function blockerChallenges(context: WorkflowNodeContext): BlockerChallenge[] {
623
726
  return context.state.steps
624
727
  .filter((step) => step.nodeId === "challengeBlocker" && step.outcome === "ok")
625
728
  .map((step) => step.output as BlockerChallenge);
626
729
  }
627
730
 
628
- function latestBlockerClaim(context: WorkflowNodeContext): unknown {
629
- const ids = [
630
- "classifyImplementation",
631
- "classifyVerification",
632
- "repairReviewCommand",
633
- "inspectComments",
634
- "inspectCi",
635
- "repairCiCommand",
636
- "assessTrackedCi",
637
- "classifyCi",
638
- "finalizeDelivery",
639
- "timeoutFallback",
640
- ];
731
+ function latestBlockerClaim(context: WorkflowNodeContext): BlockerClaim {
641
732
  for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
642
733
  const step = context.state.steps[index];
643
- if (step && ids.includes(step.nodeId)) {
644
- return { source: step.nodeId, result: step.output };
734
+ if (step?.nodeId === "createBlockerClaim" && step.outcome === "ok") {
735
+ return step.output as BlockerClaim;
736
+ }
737
+ }
738
+ throw new Error("No durable blocker claim is available to challenge");
739
+ }
740
+
741
+ function unwrapResult(value: unknown): Record<string, unknown> {
742
+ const record = requireRecord(value, "blocker source output");
743
+ const output = record.output;
744
+ return output !== null && typeof output === "object" && !Array.isArray(output)
745
+ ? (output as Record<string, unknown>)
746
+ : record;
747
+ }
748
+
749
+ function createBlockerClaim(context: WorkflowNodeContext): BlockerClaim {
750
+ const source = [...context.state.steps].reverse().find((step) => {
751
+ if (step.nodeId === "createBlockerClaim") return false;
752
+ if (step.error !== undefined) return true;
753
+ if (step.output === null || typeof step.output !== "object" || Array.isArray(step.output)) {
754
+ return false;
755
+ }
756
+ const result = unwrapResult(step.output);
757
+ return (
758
+ typeof result.reason === "string" ||
759
+ typeof result.summary === "string" ||
760
+ typeof result.blocker === "string"
761
+ );
762
+ });
763
+ if (source === undefined) throw new Error("No blocker source step is available");
764
+ const result = unwrapResult(source.output ?? { reason: source.error ?? "Step failed" });
765
+ const reasonValue = result.reason ?? result.summary ?? result.blocker ?? source.error;
766
+ const reason =
767
+ typeof reasonValue === "string" && reasonValue.trim().length > 0
768
+ ? reasonValue.trim()
769
+ : `Autoimplement could not continue after ${source.nodeId}.`;
770
+ const commands = result.candidateCommands ?? result.commands;
771
+ const failedCommands =
772
+ commands !== null && typeof commands === "object" && !Array.isArray(commands)
773
+ ? (((commands as { items?: unknown }).items as unknown[] | undefined) ?? [])
774
+ : [];
775
+ return {
776
+ schema: "pi-workflows.blocker-claim.v1",
777
+ sourceNode:
778
+ typeof result.sourceNode === "string" && result.sourceNode.length > 0
779
+ ? result.sourceNode
780
+ : source.nodeId,
781
+ attemptId: source.attemptId,
782
+ route: typeof result.route === "string" ? result.route : source.outcome,
783
+ reason,
784
+ evidence:
785
+ typeof result.sourceNode === "string"
786
+ ? result
787
+ : (result.evidence ?? source.output ?? source.error),
788
+ failedCommands,
789
+ relatedFailures: Array.isArray(result.relatedFailures) ? result.relatedFailures : [],
790
+ unrelatedFailures: Array.isArray(result.unrelatedFailures) ? result.unrelatedFailures : [],
791
+ recoveryAttempts: Array.isArray(result.repairAttempts) ? result.repairAttempts : [],
792
+ alternativesChecked: [],
793
+ authorityFact: `scope=${(context.input as AutoimplementInput).scope ?? "unspecified"}; merge=${(context.input as AutoimplementInput).merge === true}`,
794
+ };
795
+ }
796
+
797
+ function challengeTarget(context: WorkflowNodeContext): { route: string } {
798
+ const challenge = context.outputs.challengeBlocker as BlockerChallenge;
799
+ if (challenge.route === "blocked" || challenge.nextStage === null) return { route: "blocked" };
800
+ if (challenge.nextStage !== "planDiscovery" && currentPlan(context) === undefined) {
801
+ return { route: "planDiscovery" };
802
+ }
803
+ if (["documentation", "implementation", "repair", "redesign"].includes(challenge.nextStage)) {
804
+ try {
805
+ preparedWorkspace(context);
806
+ } catch {
807
+ return { route: "workspace" };
645
808
  }
646
809
  }
647
- throw new Error("No model-generated blocker claim is available to challenge");
810
+ return { route: challenge.nextStage };
648
811
  }
649
812
 
650
813
  function recentWorkflowAttempts(context: WorkflowNodeContext): unknown[] {
@@ -690,30 +853,31 @@ function parseVerificationForContext(
690
853
  context: WorkflowNodeContext,
691
854
  ): VerificationCommandPlan {
692
855
  const plan = parseVerificationCommandPlan(value);
693
- const implementation = latestOutput<Record<string, unknown>>(context, ["implement"]);
694
- const reported = Array.isArray(implementation.repositories)
695
- ? implementation.repositories.filter((entry): entry is string => typeof entry === "string")
696
- : [];
697
- const request = context.input as AutoimplementInput;
698
- const roots = new Set(
699
- (reported.length > 0 ? reported : [request.repository ?? process.cwd()]).map((entry) =>
700
- path.resolve(entry),
701
- ),
702
- );
856
+ const root = preparedWorkspace(context).worktreePath ?? preparedWorkspace(context).repository;
703
857
  for (const command of plan.commands) {
704
- const cwd = path.resolve(command.cwd);
705
- if (!roots.delete(cwd)) {
706
- throw new Error(
707
- `verification command cwd was not reported by implementation: ${command.cwd}`,
708
- );
858
+ if (path.resolve(command.cwd) !== path.resolve(root)) {
859
+ throw new Error(`verification command cwd must match the prepared workspace: ${root}`);
709
860
  }
710
861
  }
711
- if (roots.size > 0) {
712
- throw new Error(`verification plan is missing reported repositories: ${[...roots].join(", ")}`);
713
- }
714
862
  return plan;
715
863
  }
716
864
 
865
+ function parsePublishedForContext(
866
+ value: unknown,
867
+ context: WorkflowNodeContext,
868
+ ): PublishedRepositories {
869
+ const result = parsePublishedRepositories(value);
870
+ const workspace = preparedWorkspace(context);
871
+ const expected = path.resolve(workspace.worktreePath ?? workspace.repository);
872
+ if (result.repositories[0]?.repository !== expected) {
873
+ throw new Error(`publication repository must match the prepared workspace: ${expected}`);
874
+ }
875
+ if (result.repositories.some((repository) => repository.repository !== expected)) {
876
+ throw new Error("publication cannot include an unprepared repository");
877
+ }
878
+ return result;
879
+ }
880
+
717
881
  function currentPublishedRepositories(context: WorkflowNodeContext): PublishedRepositories {
718
882
  return latestOutput<PublishedRepositories>(context, ["verifyP2", "publish"]);
719
883
  }
@@ -1090,7 +1254,15 @@ function ciForOutput(context: WorkflowNodeContext): unknown {
1090
1254
  }
1091
1255
 
1092
1256
  function latestBlockedReason(context: WorkflowNodeContext): { reason: string; evidence: unknown } {
1257
+ for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
1258
+ const step = context.state.steps[index];
1259
+ if (step?.nodeId === "createBlockerClaim" && step.outcome === "ok") {
1260
+ const claim = step.output as BlockerClaim;
1261
+ return { reason: claim.reason, evidence: claim };
1262
+ }
1263
+ }
1093
1264
  const candidates = [
1265
+ "createBlockerClaim",
1094
1266
  "timeoutFallbackGuard",
1095
1267
  "timeoutFallback",
1096
1268
  "challengeBlockerGuard",
@@ -1130,8 +1302,28 @@ export const autoimplementWorkflow = defineWorkflow({
1130
1302
  presentationPrompt:
1131
1303
  "Summarize what was implemented, the review rounds by severity, the CI result, the PR or merge result, and any remaining limitation. Include exact validation commands.",
1132
1304
  startAt: "prepare",
1133
- maxSteps: 240,
1305
+ maxSteps: 320,
1134
1306
  includes: {
1307
+ workspace: includeWorkflow(workspacePreparationWorkflow, {
1308
+ input: (context): WorkspacePreparationInput => {
1309
+ const request = context.input as AutoimplementInput;
1310
+ if (request.repository === undefined) {
1311
+ throw new Error("autoimplement workspace preparation requires an absolute repository");
1312
+ }
1313
+ return {
1314
+ repository: request.repository,
1315
+ ...(request.baseBranch === undefined ? {} : { baseBranch: request.baseBranch }),
1316
+ ...(request.scope === undefined ? {} : { scope: request.scope }),
1317
+ ...(request.workspaceMode === undefined ? {} : { workspaceMode: request.workspaceMode }),
1318
+ ...(request.directDefaultBranchAuthorized === undefined
1319
+ ? {}
1320
+ : { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
1321
+ ...(request.preparedWorkspace === undefined
1322
+ ? {}
1323
+ : { preparedWorkspace: request.preparedWorkspace }),
1324
+ };
1325
+ },
1326
+ }),
1135
1327
  documentation: includeWorkflow(autodocWorkflow, {
1136
1328
  input: (context): AutodocInput => {
1137
1329
  const request = context.input as AutoimplementInput;
@@ -1142,12 +1334,51 @@ export const autoimplementWorkflow = defineWorkflow({
1142
1334
  task: request.task,
1143
1335
  plan,
1144
1336
  ...(request.repository !== undefined ? { repository: request.repository } : {}),
1337
+ ...(request.baseBranch !== undefined ? { baseBranch: request.baseBranch } : {}),
1338
+ ...(request.scope !== undefined ? { scope: request.scope } : {}),
1339
+ ...(request.directDefaultBranchAuthorized === undefined
1340
+ ? {}
1341
+ : { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
1342
+ preparedWorkspace: preparedWorkspace(context),
1343
+ ...(request.verificationChecks === undefined
1344
+ ? {}
1345
+ : { verificationChecks: request.verificationChecks }),
1145
1346
  documents:
1146
1347
  request.documents ?? request.documentation?.documents ?? discovery?.documents ?? [],
1147
1348
  evidence: latestIssue(context),
1148
1349
  };
1149
1350
  },
1150
1351
  }),
1352
+ localVerification: includeWorkflow(changeVerificationWorkflow, {
1353
+ input: (context): ChangeVerificationInput => {
1354
+ const request = context.input as AutoimplementInput;
1355
+ const plan =
1356
+ request.verificationChecks === undefined
1357
+ ? latestOutput<VerificationCommandPlan>(context, ["planVerification"])
1358
+ : { commands: [], untested: [] };
1359
+ const implementation = latestOutput<Record<string, unknown>>(context, ["implement"]);
1360
+ return {
1361
+ originatingWorkflow: "autoimplement",
1362
+ qualifiedNode: "autoimplement/localVerification",
1363
+ workspace: preparedWorkspace(context),
1364
+ checks:
1365
+ request.verificationChecks ??
1366
+ plan.commands.map((command) => ({
1367
+ ...command,
1368
+ readOnly: true,
1369
+ baseEligible: true,
1370
+ changedFileScope: false,
1371
+ findingFormat: "text" as const,
1372
+ })),
1373
+ changedFiles: Array.isArray(implementation.files)
1374
+ ? implementation.files.filter((file): file is string => typeof file === "string")
1375
+ : [],
1376
+ untested: plan.untested,
1377
+ plan: currentPlan(context),
1378
+ maxConcurrency: concurrency(context).verification,
1379
+ };
1380
+ },
1381
+ }),
1151
1382
  redesign: includeWorkflow(planChangeWorkflow, {
1152
1383
  input: (context): NormalizedPlanChangeInput => {
1153
1384
  const request = context.input as AutoimplementInput;
@@ -1155,7 +1386,14 @@ export const autoimplementWorkflow = defineWorkflow({
1155
1386
  task: request.task,
1156
1387
  ...(request.scope !== undefined ? { scope: request.scope } : {}),
1157
1388
  ...(request.constraints !== undefined ? { constraints: request.constraints } : {}),
1158
- ...(request.repository !== undefined ? { repository: request.repository } : {}),
1389
+ repository: request.repository,
1390
+ preparedWorkspace: preparedWorkspace(context),
1391
+ ...(request.directDefaultBranchAuthorized === undefined
1392
+ ? {}
1393
+ : { directDefaultBranchAuthorized: request.directDefaultBranchAuthorized }),
1394
+ ...(request.verificationChecks === undefined
1395
+ ? {}
1396
+ : { verificationChecks: request.verificationChecks }),
1159
1397
  documents: request.documents ?? request.documentation?.documents ?? [],
1160
1398
  ...(currentPlan(context) !== undefined ? { previousPlan: currentPlan(context) } : {}),
1161
1399
  newEvidence: latestIssue(context),
@@ -1178,14 +1416,7 @@ export const autoimplementWorkflow = defineWorkflow({
1178
1416
  prepare: compute({
1179
1417
  run: ({ input }) => {
1180
1418
  const request = input as AutoimplementInput;
1181
- return {
1182
- route:
1183
- request.plan === undefined
1184
- ? "find"
1185
- : request.documentation?.status === "current"
1186
- ? "ready"
1187
- : "document",
1188
- };
1419
+ return { route: request.plan === undefined ? "find" : "workspace" };
1189
1420
  },
1190
1421
  }),
1191
1422
  findPlan: agent({
@@ -1214,13 +1445,27 @@ export const autoimplementWorkflow = defineWorkflow({
1214
1445
  return { route: "blocked", reason: discovered.reason, evidence: discovered.evidence };
1215
1446
  }
1216
1447
  return {
1217
- route: discovered.documentation === "current" ? "ready" : "document",
1448
+ route: "workspace",
1218
1449
  plan: discovered.plan,
1450
+ documentation: discovered.documentation,
1219
1451
  reason: discovered.reason,
1220
1452
  evidence: discovered.evidence,
1221
1453
  };
1222
1454
  },
1223
1455
  }),
1456
+ routeWorkspace: compute({
1457
+ run: ({ input, outputs }) => {
1458
+ const request = input as AutoimplementInput;
1459
+ const discovered = outputs.findPlan as ExistingPlanDiscovery | undefined;
1460
+ return {
1461
+ route:
1462
+ request.documentation?.status === "current" || discovered?.documentation === "current"
1463
+ ? "implement"
1464
+ : "document",
1465
+ workspace: preparedWorkspace({ input, outputs } as WorkflowNodeContext),
1466
+ };
1467
+ },
1468
+ }),
1224
1469
  adoptPlan: compute({
1225
1470
  run: ({ outputs }) => {
1226
1471
  const result = includedResult(planChangeWorkflow, outputs.redesign);
@@ -1247,10 +1492,10 @@ export const autoimplementWorkflow = defineWorkflow({
1247
1492
  .filter((step) => step.nodeId === "timeoutFallback" && step.outcome === "ok")
1248
1493
  .map((step) => step.output);
1249
1494
  return [
1250
- "A bounded Autoimplement agent step timed out. Choose the safest existing workflow stage to run next instead of ending the run blindly.",
1495
+ "A bounded Autoimplement step failed or timed out. Choose the safest existing workflow stage to run next instead of ending the run blindly.",
1251
1496
  "This is a read-only fallback step. Inspect state, but do not edit files, run mutating commands, commit, push, open or update a pull request, post comments, merge, deploy, or release.",
1252
1497
  "Inspect the current repository worktree, branch, diff, and commits. Inspect the remote branch, pull request, review, CI, merge, and final report when they exist and affect the next route.",
1253
- "Do not assume that the timed-out step failed or completed. Use accepted workflow outputs and durable repository or pull-request state.",
1498
+ "Do not assume that a mutating step failed or completed. Observe durable repository or pull-request state first, adopt an effect that already completed, and retry only a missing effect.",
1254
1499
  "Before any forward route, confirm that its accepted output belongs to the current work attempt and that observed local and remote heads match the accepted publication. Otherwise retry, replan, or block.",
1255
1500
  "Choose retry only when the timed-out stage must run again. Choose verify when accepted implementation output exists and verification is next. Choose review when accepted publication output exists. Choose ci only after comment inspection routed to CI. Choose deliver only after CI is green or classified unrelated. Choose replan when evidence invalidates the approved plan. Choose blocked only when no safe route exists.",
1256
1501
  "Do not skip required implementation, verification, review, CI, authorization, or delivery checks.",
@@ -1269,9 +1514,6 @@ export const autoimplementWorkflow = defineWorkflow({
1269
1514
  routeTimeoutFallback: compute({
1270
1515
  run: timeoutFallbackTarget,
1271
1516
  }),
1272
- propagateSupportedFailure: compute({
1273
- run: throwLatestSupportedFailure,
1274
- }),
1275
1517
  routeVerifyP2Result: compute({
1276
1518
  run: ({ outputs }) => outputs.verifyP2,
1277
1519
  }),
@@ -1294,6 +1536,8 @@ export const autoimplementWorkflow = defineWorkflow({
1294
1536
  `Plan: ${JSON.stringify(currentPlan(context))}`,
1295
1537
  `Authorized scope: ${request.scope ?? request.repository ?? "the current repository and task"}`,
1296
1538
  `Constraints: ${JSON.stringify(request.constraints ?? [])}`,
1539
+ `Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
1540
+ "Use the prepared absolute workspace path for every read, edit, command, and report. Do not fall back to the Pi process working directory.",
1297
1541
  "Before changing files, inspect the current worktree, diff, commits, branch, remote state, and matching pull request. Continue existing work and do not repeat completed effects.",
1298
1542
  "Follow repository instructions and use the most elegant long-term production-ready implementation without unnecessary work.",
1299
1543
  "If implementation exposes a new design or scope problem, report it precisely instead of forcing the old plan.",
@@ -1323,6 +1567,17 @@ export const autoimplementWorkflow = defineWorkflow({
1323
1567
  "implementation assessment",
1324
1568
  ),
1325
1569
  }),
1570
+ createBlockerClaim: compute({
1571
+ run: createBlockerClaim,
1572
+ }),
1573
+ routeBlockerClaim: compute({
1574
+ run: ({ outputs }) => {
1575
+ const claim = outputs.createBlockerClaim as BlockerClaim;
1576
+ return {
1577
+ route: claim.sourceNode === "challengeBlockerGuard" ? "blocked" : "challenge",
1578
+ };
1579
+ },
1580
+ }),
1326
1581
  challengeBlockerGuard: compute({
1327
1582
  run: (context) => {
1328
1583
  const challenges = blockerChallenges(context);
@@ -1354,7 +1609,8 @@ export const autoimplementWorkflow = defineWorkflow({
1354
1609
  "A local test failure, stale package, packaging or artifact mismatch, rollback preparation, or deployment procedure is not by itself outside authority.",
1355
1610
  "If a safe deployment and rollback path is already authorized, a supported cutover is work to do, not a blocker.",
1356
1611
  "Confirm blocked only when the issue blocks progress now, is outside authority, and has no safe practical path forward.",
1357
- "Return continue with the next practical action when work can proceed. Keep text concise, with at most five alternatives and five evidence items.",
1612
+ "Return continue with the next practical action and its exact nextStage: planDiscovery, documentation, implementation, repair, review, ci, delivery, or redesign.",
1613
+ "Keep text concise, with at most five alternatives and five evidence items.",
1358
1614
  `Task: ${request.task}`,
1359
1615
  `Approved plan: ${JSON.stringify(currentPlan(context))}`,
1360
1616
  `Current result and claimed blocker: ${JSON.stringify(latestBlockerClaim(context))}`,
@@ -1365,71 +1621,64 @@ export const autoimplementWorkflow = defineWorkflow({
1365
1621
  `Recent workflow attempts: ${JSON.stringify(recentWorkflowAttempts(context))}`,
1366
1622
  ].join("\n");
1367
1623
  },
1368
- expectedOutput: `{ "route": "continue" | "blocked", "blockingNow": true | false, "outsideAuthority": true | false, "canProceed": true | false, "reason": "concise reason", "nextAction": "practical action or empty when blocked", "alternativesChecked": ["checked alternative"], "evidence": ["concrete evidence"] }`,
1624
+ expectedOutput: `{ "route": "continue" | "blocked", "blockingNow": true | false, "outsideAuthority": true | false, "canProceed": true | false, "reason": "concise reason", "nextAction": "practical action or empty when blocked", "nextStage": "planDiscovery" | "documentation" | "implementation" | "repair" | "review" | "ci" | "delivery" | "redesign" | null, "alternativesChecked": ["checked alternative"], "evidence": ["concrete evidence"] }`,
1369
1625
  validate: parseBlockerChallenge,
1370
1626
  }),
1627
+ routeChallenge: compute({ run: challengeTarget }),
1628
+ selectVerificationPath: compute({
1629
+ run: ({ input }) => ({
1630
+ route: (input as AutoimplementInput).verificationChecks === undefined ? "plan" : "verify",
1631
+ }),
1632
+ }),
1371
1633
  planVerification: agent({
1372
1634
  timeoutMs: 15 * 60_000,
1373
1635
  statusDetail: "planning independent verification commands",
1374
- prompt: () =>
1636
+ prompt: (context) =>
1375
1637
  [
1376
- "Select the required local verification commands for the implementation.",
1377
- "Return one command per independent repository working directory.",
1638
+ "Select all required local verification commands for the implementation.",
1639
+ "Return one or more commands for the prepared repository workspace.",
1378
1640
  "Use exact executables and argument arrays without shell wrappers, environment overrides, stdin, Git or GitHub mutations, package publication, deployment, merge, or release commands.",
1379
- "Use absolute repository paths, explicit timeouts no longer than 2700000ms, and maxOutputChars no larger than 1000000.",
1641
+ "Use the prepared absolute workspace path as cwd for every command, explicit timeouts no longer than 2700000ms, and maxOutputChars no larger than 1000000.",
1380
1642
  "List checks that cannot run locally under untested.",
1643
+ `Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
1381
1644
  ].join("\n"),
1382
1645
  expectedOutput: `{ "commands": [{ "id": "stable-id", "command": "npm", "args": ["run", "check"], "cwd": "/absolute/repository", "timeoutMs": 2700000, "maxOutputChars": 1000000 }], "untested": ["remaining check"] }`,
1383
1646
  validate: parseVerificationForContext,
1384
1647
  }),
1385
- runVerification: action({
1386
- timeoutMs: (context) => {
1387
- const plan = latestOutput<VerificationCommandPlan>(context, ["planVerification"]);
1388
- return commandBatchTimeoutMs(plan.commands, concurrency(context).verification);
1389
- },
1390
- statusDetail: "running independent verification commands",
1391
- run: async (context) => {
1392
- const plan = latestOutput<VerificationCommandPlan>(context, ["planVerification"]);
1393
- return await runAutoimplementBatch(
1394
- context,
1395
- "verification",
1396
- plan.commands,
1397
- concurrency(context).verification,
1398
- );
1399
- },
1648
+ routeVerifiedWorkspace: compute({
1649
+ run: (context) => ({
1650
+ route:
1651
+ preparedWorkspace(context).mode === "defaultBranch" ? "defaultBranch" : "pullRequest",
1652
+ }),
1400
1653
  }),
1401
- verify: agent({
1402
- timeoutMs: 20 * 60_000,
1403
- statusDetail: "assessing verification",
1404
- prompt: (context) =>
1405
- [
1406
- "Assess the completed local verification commands.",
1407
- "Set passed true only when every required command succeeded without truncated output.",
1408
- "Report exact command outcomes, failures, and checks that still need remote verification.",
1409
- `Command plan: ${JSON.stringify(latestOutput(context, ["planVerification"]))}`,
1410
- `Command results: ${JSON.stringify(latestOutput(context, ["runVerification"]))}`,
1411
- ].join("\n"),
1412
- expectedOutput: `{ "passed": true | false, "commands": [{ "command": "exact command", "outcome": "result" }], "failures": ["failure"], "untested": ["remaining check"] }`,
1413
- validate: (value) => requireRecord(value, "verification result"),
1654
+ routeFinalizeDefaultBranchResult: compute({
1655
+ run: ({ outputs }) => outputs.finalizeDefaultBranch,
1414
1656
  }),
1415
- classifyVerification: agent({
1416
- statusDetail: "classifying verification",
1417
- prompt: ({ outputs }) =>
1418
- [
1419
- "Classify the verification result.",
1420
- "Choose publish when required local checks passed.",
1421
- "Choose redesign for evidence that invalidates the plan.",
1422
- "Choose fix for a local implementation or test issue.",
1423
- "Choose blocked only when the work cannot continue in scope.",
1424
- `Verification: ${JSON.stringify(outputs.verify)}`,
1425
- ].join("\n"),
1426
- expectedOutput: `{ "route": "publish" | "redesign" | "fix" | "blocked", "summary": "reason", "evidence": "evidence" }`,
1427
- validate: (value) =>
1428
- parseRoute(
1429
- value,
1430
- ["publish", "redesign", "fix", "blocked"] as const,
1431
- "verification assessment",
1432
- ),
1657
+ finalizeDefaultBranch: agent({
1658
+ timeoutMs: 30 * 60_000,
1659
+ statusDetail: "finalizing default-branch work",
1660
+ prompt: (context) => {
1661
+ const request = context.input as AutoimplementInput;
1662
+ return [
1663
+ "Finalize verified work in the explicitly authorized default-branch workspace.",
1664
+ "Never open a pull request from the default branch to itself.",
1665
+ "Commit and push only when the authorized scope explicitly allows each action. Otherwise leave the verified local change and report it.",
1666
+ "Do not merge, release, or deploy.",
1667
+ `Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
1668
+ `Authorized scope: ${request.scope}`,
1669
+ ].join("\n");
1670
+ },
1671
+ expectedOutput: `{ "status": "completed" | "blocked", "committed": true | false, "pushed": true | false, "merged": false, "pr": "none", "reportComment": "summary", "reason": "result" }`,
1672
+ validate: (value) => {
1673
+ const result = requireRecord(value, "default-branch delivery");
1674
+ if (result.status !== "completed" && result.status !== "blocked") {
1675
+ throw new Error("default-branch delivery status must be completed or blocked");
1676
+ }
1677
+ if (result.merged !== false || result.pr !== "none") {
1678
+ throw new Error("default-branch delivery cannot merge or open a pull request to itself");
1679
+ }
1680
+ return result;
1681
+ },
1433
1682
  }),
1434
1683
  fix: agent({
1435
1684
  timeoutMs: 45 * 60_000,
@@ -1440,6 +1689,7 @@ export const autoimplementWorkflow = defineWorkflow({
1440
1689
  "Inspect the current diff and commits first. Continue any partial fix and change only work that is still missing.",
1441
1690
  `Issue: ${JSON.stringify(latestIssue(context))}`,
1442
1691
  `Current plan: ${JSON.stringify(currentPlan(context))}`,
1692
+ `Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
1443
1693
  "Stop after the fix so verification can run again.",
1444
1694
  ].join("\n"),
1445
1695
  expectedOutput: `{ "fixed": "what changed", "files": ["changed file"] }`,
@@ -1448,8 +1698,8 @@ export const autoimplementWorkflow = defineWorkflow({
1448
1698
  publish: agent({
1449
1699
  timeoutMs: 30 * 60_000,
1450
1700
  statusDetail: "committing and pushing",
1451
- prompt: ({ input }) => {
1452
- const request = input as AutoimplementInput;
1701
+ prompt: (context) => {
1702
+ const request = context.input as AutoimplementInput;
1453
1703
  return [
1454
1704
  "Commit and push the verified implementation before review.",
1455
1705
  "Inspect the branch, local and remote heads, and matching pull requests first. Do not push an already-pushed head or create a second pull request for the same branch and base.",
@@ -1458,11 +1708,12 @@ export const autoimplementWorkflow = defineWorkflow({
1458
1708
  "Report every repository that received a pushed pull request with its absolute repository path, branch, base branch, pushed head revision, and PR URL.",
1459
1709
  "Include dependencyFingerprint only when a declared dependency result is relevant to review reuse.",
1460
1710
  `Requested base branch: ${request.baseBranch ?? "discover each repository default branch"}.`,
1711
+ `Prepared workspace: ${JSON.stringify(preparedWorkspace(context))}`,
1461
1712
  "Do not merge yet.",
1462
1713
  ].join("\n");
1463
1714
  },
1464
1715
  expectedOutput: `{ "repositories": [{ "repository": "/absolute/repository", "branch": "branch", "baseBranch": "base", "headRevision": "revision", "pr": "URL", "pushed": true, "dependencyFingerprint": "optional digest" }] }`,
1465
- validate: parsePublishedRepositories,
1716
+ validate: parsePublishedForContext,
1466
1717
  }),
1467
1718
  selectReviewCommands: compute({
1468
1719
  run: selectReviewCommands,
@@ -1710,10 +1961,23 @@ export const autoimplementWorkflow = defineWorkflow({
1710
1961
  task: request.task,
1711
1962
  plan: currentPlan(context),
1712
1963
  implementation: latestOutput(context, ["implement"]),
1713
- verification: latestOutput(context, ["verifyP2", "verify"]),
1714
- reviewRounds: reviewRoundsForOutput(context),
1715
- ci: ciForOutput(context),
1716
- delivery: latestOutput(context, ["finalizeDelivery"]),
1964
+ verification:
1965
+ context.outputs.localVerification === undefined
1966
+ ? latestOutput(context, ["verifyP2"])
1967
+ : includedResult(changeVerificationWorkflow, context.outputs.localVerification)
1968
+ .output,
1969
+ reviewRounds:
1970
+ context.outputs.finalizeDefaultBranch === undefined
1971
+ ? reviewRoundsForOutput(context)
1972
+ : [],
1973
+ ci:
1974
+ context.outputs.finalizeDefaultBranch === undefined
1975
+ ? ciForOutput(context)
1976
+ : {
1977
+ route: "notApplicable",
1978
+ reason: "Direct default-branch work has no pull request.",
1979
+ },
1980
+ delivery: latestOutput(context, ["finalizeDefaultBranch", "finalizeDelivery"]),
1717
1981
  } satisfies AutoimplementCompleted;
1718
1982
  },
1719
1983
  }),
@@ -1721,33 +1985,41 @@ export const autoimplementWorkflow = defineWorkflow({
1721
1985
  edges: [
1722
1986
  {
1723
1987
  from: "prepare",
1724
- switch: {
1725
- on: "$.route",
1726
- cases: { find: "findPlan", document: "documentation", ready: "implement" },
1727
- },
1988
+ switch: { on: "$.route", cases: { find: "findPlan", workspace: "workspace" } },
1728
1989
  },
1729
1990
  {
1730
1991
  from: "findPlan",
1731
- switch: { on: "$.route", cases: { found: "routeFoundPlan", blocked: "blocked" } },
1992
+ switch: {
1993
+ on: "$.route",
1994
+ cases: { found: "routeFoundPlan", blocked: "createBlockerClaim" },
1995
+ },
1732
1996
  },
1733
1997
  {
1734
1998
  from: "routeFoundPlan",
1735
1999
  switch: {
1736
2000
  on: "$.route",
1737
- cases: { ready: "implement", document: "documentation", blocked: "blocked" },
2001
+ cases: { workspace: "workspace", blocked: "createBlockerClaim" },
1738
2002
  },
1739
2003
  },
2004
+ { from: "workspace.ready", to: "routeWorkspace" },
2005
+ { from: "workspace.blocked", to: "createBlockerClaim" },
2006
+ {
2007
+ from: "routeWorkspace",
2008
+ switch: { on: "$.route", cases: { implement: "implement", document: "documentation" } },
2009
+ },
1740
2010
  { from: "redesign.ready", to: "adoptPlan" },
1741
2011
  { from: "redesign.blocked", to: "blocked" },
1742
2012
  { from: "adoptPlan", to: "implement" },
1743
2013
  { from: "documentation.ready", to: "implement" },
1744
- { from: "documentation.blocked", to: "blocked" },
2014
+ { from: "documentation.blocked", to: "createBlockerClaim" },
1745
2015
  {
1746
2016
  from: "timeoutFallbackGuard",
1747
- switch: { on: "$.route", cases: { recover: "timeoutFallback", blocked: "blocked" } },
2017
+ switch: {
2018
+ on: "$.route",
2019
+ cases: { recover: "timeoutFallback", blocked: "createBlockerClaim" },
2020
+ },
1748
2021
  },
1749
2022
  { from: "timeoutFallback", to: "routeTimeoutFallback" },
1750
- { from: "propagateSupportedFailure", to: "blocked" },
1751
2023
  {
1752
2024
  from: "routeTimeoutFallback",
1753
2025
  switch: {
@@ -1755,7 +2027,6 @@ export const autoimplementWorkflow = defineWorkflow({
1755
2027
  cases: {
1756
2028
  implement: "implement",
1757
2029
  planVerification: "planVerification",
1758
- verify: "verify",
1759
2030
  fix: "fix",
1760
2031
  publish: "publish",
1761
2032
  addressP2: "addressP2",
@@ -1763,10 +2034,11 @@ export const autoimplementWorkflow = defineWorkflow({
1763
2034
  inspectComments: "inspectComments",
1764
2035
  inspectCi: "inspectCi",
1765
2036
  opportunisticTest: "opportunisticTest",
2037
+ finalizeDefaultBranch: "finalizeDefaultBranch",
1766
2038
  finalizeDelivery: "finalizeDelivery",
1767
2039
  selectReviewCommands: "selectReviewCommands",
1768
2040
  redesign: "redesign",
1769
- blocked: "blocked",
2041
+ blocked: "createBlockerClaim",
1770
2042
  },
1771
2043
  },
1772
2044
  },
@@ -1777,7 +2049,7 @@ export const autoimplementWorkflow = defineWorkflow({
1777
2049
  cases: {
1778
2050
  ok: "classifyImplementation",
1779
2051
  timed_out: "timeoutFallbackGuard",
1780
- failed: "propagateSupportedFailure",
2052
+ failed: "timeoutFallbackGuard",
1781
2053
  },
1782
2054
  },
1783
2055
  },
@@ -1786,64 +2058,100 @@ export const autoimplementWorkflow = defineWorkflow({
1786
2058
  switch: {
1787
2059
  on: "$.route",
1788
2060
  cases: {
1789
- verify: "planVerification",
2061
+ verify: "selectVerificationPath",
1790
2062
  redesign: "redesign",
1791
2063
  fix: "fix",
1792
- blocked: "challengeBlockerGuard",
2064
+ blocked: "createBlockerClaim",
1793
2065
  },
1794
2066
  },
1795
2067
  },
2068
+ { from: "createBlockerClaim", to: "routeBlockerClaim" },
2069
+ {
2070
+ from: "routeBlockerClaim",
2071
+ switch: {
2072
+ on: "$.route",
2073
+ cases: { challenge: "challengeBlockerGuard", blocked: "blocked" },
2074
+ },
2075
+ },
1796
2076
  {
1797
2077
  from: "challengeBlockerGuard",
1798
- switch: { on: "$.route", cases: { challenge: "challengeBlocker", blocked: "blocked" } },
2078
+ switch: {
2079
+ on: "$.route",
2080
+ cases: { challenge: "challengeBlocker", blocked: "createBlockerClaim" },
2081
+ },
1799
2082
  },
1800
2083
  {
1801
2084
  from: "challengeBlocker",
1802
- switch: { on: "$.route", cases: { continue: "redesign", blocked: "blocked" } },
2085
+ switch: { on: "$.route", cases: { continue: "routeChallenge", blocked: "blocked" } },
1803
2086
  },
1804
2087
  {
1805
- from: "planVerification",
2088
+ from: "routeChallenge",
1806
2089
  switch: {
1807
- on: "$result.outcome",
2090
+ on: "$.route",
1808
2091
  cases: {
1809
- ok: "runVerification",
1810
- timed_out: "timeoutFallbackGuard",
1811
- failed: "propagateSupportedFailure",
2092
+ planDiscovery: "findPlan",
2093
+ workspace: "workspace",
2094
+ documentation: "documentation",
2095
+ implementation: "implement",
2096
+ repair: "fix",
2097
+ review: "selectReviewCommands",
2098
+ ci: "inspectCi",
2099
+ delivery: "finalizeDelivery",
2100
+ redesign: "redesign",
2101
+ blocked: "blocked",
1812
2102
  },
1813
2103
  },
1814
2104
  },
1815
- { from: "runVerification", to: "verify" },
1816
2105
  {
1817
- from: "verify",
2106
+ from: "selectVerificationPath",
2107
+ switch: { on: "$.route", cases: { plan: "planVerification", verify: "localVerification" } },
2108
+ },
2109
+ {
2110
+ from: "planVerification",
1818
2111
  switch: {
1819
2112
  on: "$result.outcome",
1820
2113
  cases: {
1821
- ok: "classifyVerification",
2114
+ ok: "localVerification",
1822
2115
  timed_out: "timeoutFallbackGuard",
1823
- failed: "propagateSupportedFailure",
2116
+ failed: "timeoutFallbackGuard",
1824
2117
  },
1825
2118
  },
1826
2119
  },
2120
+ { from: "localVerification.ready", to: "routeVerifiedWorkspace" },
2121
+ { from: "localVerification.blocked", to: "createBlockerClaim" },
1827
2122
  {
1828
- from: "classifyVerification",
2123
+ from: "routeVerifiedWorkspace",
1829
2124
  switch: {
1830
2125
  on: "$.route",
2126
+ cases: { pullRequest: "publish", defaultBranch: "finalizeDefaultBranch" },
2127
+ },
2128
+ },
2129
+ {
2130
+ from: "finalizeDefaultBranch",
2131
+ switch: {
2132
+ on: "$result.outcome",
1831
2133
  cases: {
1832
- publish: "publish",
1833
- redesign: "redesign",
1834
- fix: "fix",
1835
- blocked: "challengeBlockerGuard",
2134
+ ok: "routeFinalizeDefaultBranchResult",
2135
+ timed_out: "timeoutFallbackGuard",
2136
+ failed: "timeoutFallbackGuard",
1836
2137
  },
1837
2138
  },
1838
2139
  },
2140
+ {
2141
+ from: "routeFinalizeDefaultBranchResult",
2142
+ switch: {
2143
+ on: "$.status",
2144
+ cases: { completed: "finalize", blocked: "createBlockerClaim" },
2145
+ },
2146
+ },
1839
2147
  {
1840
2148
  from: "fix",
1841
2149
  switch: {
1842
2150
  on: "$result.outcome",
1843
2151
  cases: {
1844
- ok: "planVerification",
2152
+ ok: "selectVerificationPath",
1845
2153
  timed_out: "timeoutFallbackGuard",
1846
- failed: "propagateSupportedFailure",
2154
+ failed: "timeoutFallbackGuard",
1847
2155
  },
1848
2156
  },
1849
2157
  },
@@ -1854,7 +2162,7 @@ export const autoimplementWorkflow = defineWorkflow({
1854
2162
  cases: {
1855
2163
  ok: "selectReviewCommands",
1856
2164
  timed_out: "timeoutFallbackGuard",
1857
- failed: "propagateSupportedFailure",
2165
+ failed: "timeoutFallbackGuard",
1858
2166
  },
1859
2167
  },
1860
2168
  },
@@ -1870,7 +2178,7 @@ export const autoimplementWorkflow = defineWorkflow({
1870
2178
  from: "repairReviewCommand",
1871
2179
  switch: {
1872
2180
  on: "$.route",
1873
- cases: { retry: "runReview", blocked: "challengeBlockerGuard" },
2181
+ cases: { retry: "runReview", blocked: "createBlockerClaim" },
1874
2182
  },
1875
2183
  },
1876
2184
  {
@@ -1896,7 +2204,7 @@ export const autoimplementWorkflow = defineWorkflow({
1896
2204
  cases: {
1897
2205
  ok: "verifyP2",
1898
2206
  timed_out: "timeoutFallbackGuard",
1899
- failed: "propagateSupportedFailure",
2207
+ failed: "timeoutFallbackGuard",
1900
2208
  },
1901
2209
  },
1902
2210
  },
@@ -1907,7 +2215,7 @@ export const autoimplementWorkflow = defineWorkflow({
1907
2215
  cases: {
1908
2216
  ok: "routeVerifyP2Result",
1909
2217
  timed_out: "timeoutFallbackGuard",
1910
- failed: "propagateSupportedFailure",
2218
+ failed: "timeoutFallbackGuard",
1911
2219
  },
1912
2220
  },
1913
2221
  },
@@ -1922,7 +2230,7 @@ export const autoimplementWorkflow = defineWorkflow({
1922
2230
  cases: {
1923
2231
  ok: "routeInspectCommentsResult",
1924
2232
  timed_out: "timeoutFallbackGuard",
1925
- failed: "propagateSupportedFailure",
2233
+ failed: "timeoutFallbackGuard",
1926
2234
  },
1927
2235
  },
1928
2236
  },
@@ -1934,7 +2242,7 @@ export const autoimplementWorkflow = defineWorkflow({
1934
2242
  redesign: "redesign",
1935
2243
  fix: "fix",
1936
2244
  ci: "inspectCi",
1937
- blocked: "challengeBlockerGuard",
2245
+ blocked: "createBlockerClaim",
1938
2246
  },
1939
2247
  },
1940
2248
  },
@@ -1945,7 +2253,7 @@ export const autoimplementWorkflow = defineWorkflow({
1945
2253
  cases: {
1946
2254
  ok: "routeInspectCiResult",
1947
2255
  timed_out: "timeoutFallbackGuard",
1948
- failed: "propagateSupportedFailure",
2256
+ failed: "timeoutFallbackGuard",
1949
2257
  },
1950
2258
  },
1951
2259
  },
@@ -1957,7 +2265,7 @@ export const autoimplementWorkflow = defineWorkflow({
1957
2265
  green: "finalizeDelivery",
1958
2266
  failed: "classifyCi",
1959
2267
  pending: "trackCi",
1960
- unavailable: "challengeBlockerGuard",
2268
+ unavailable: "createBlockerClaim",
1961
2269
  },
1962
2270
  },
1963
2271
  },
@@ -1969,7 +2277,7 @@ export const autoimplementWorkflow = defineWorkflow({
1969
2277
  from: "repairCiCommand",
1970
2278
  switch: {
1971
2279
  on: "$.route",
1972
- cases: { retry: "trackCi", blocked: "challengeBlockerGuard" },
2280
+ cases: { retry: "trackCi", blocked: "createBlockerClaim" },
1973
2281
  },
1974
2282
  },
1975
2283
  {
@@ -1980,7 +2288,7 @@ export const autoimplementWorkflow = defineWorkflow({
1980
2288
  green: "finalizeDelivery",
1981
2289
  failed: "classifyCi",
1982
2290
  pending: "opportunisticTest",
1983
- unavailable: "challengeBlockerGuard",
2291
+ unavailable: "createBlockerClaim",
1984
2292
  },
1985
2293
  },
1986
2294
  },
@@ -1991,7 +2299,7 @@ export const autoimplementWorkflow = defineWorkflow({
1991
2299
  cases: {
1992
2300
  ok: "inspectCi",
1993
2301
  timed_out: "timeoutFallbackGuard",
1994
- failed: "propagateSupportedFailure",
2302
+ failed: "timeoutFallbackGuard",
1995
2303
  },
1996
2304
  },
1997
2305
  },
@@ -2003,7 +2311,7 @@ export const autoimplementWorkflow = defineWorkflow({
2003
2311
  redesign: "redesign",
2004
2312
  fix: "fix",
2005
2313
  unrelated: "finalizeDelivery",
2006
- blocked: "challengeBlockerGuard",
2314
+ blocked: "createBlockerClaim",
2007
2315
  },
2008
2316
  },
2009
2317
  },
@@ -2014,7 +2322,7 @@ export const autoimplementWorkflow = defineWorkflow({
2014
2322
  cases: {
2015
2323
  ok: "routeFinalizeDeliveryResult",
2016
2324
  timed_out: "timeoutFallbackGuard",
2017
- failed: "propagateSupportedFailure",
2325
+ failed: "timeoutFallbackGuard",
2018
2326
  },
2019
2327
  },
2020
2328
  },
@@ -2022,7 +2330,7 @@ export const autoimplementWorkflow = defineWorkflow({
2022
2330
  from: "routeFinalizeDeliveryResult",
2023
2331
  switch: {
2024
2332
  on: "$.status",
2025
- cases: { completed: "finalize", blocked: "challengeBlockerGuard" },
2333
+ cases: { completed: "finalize", blocked: "createBlockerClaim" },
2026
2334
  },
2027
2335
  },
2028
2336
  ],