@mediadatafusion/pi-workflow-suite 0.0.8 → 0.0.10

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.
@@ -737,7 +737,7 @@ function effectiveStandardModelRole(settings: ReturnType<typeof loadWorkflowSett
737
737
 
738
738
  let workflowScheduledAgentTurns = 0;
739
739
 
740
- const WORKFLOW_AGENT_TURN_RETRY_DELAYS_MS = [250, 750, 1500] as const;
740
+ const WORKFLOW_AGENT_TURN_RETRY_DELAYS_MS = [250, 750, 1500, 3000, 5000, 8000, 13000] as const;
741
741
 
742
742
  function workflowTurnSendErrorMessage(error: unknown): string {
743
743
  return error instanceof Error ? error.message : String(error ?? "");
@@ -771,14 +771,7 @@ function queueAgentTurn(pi: ExtensionAPI, content: string, customType: string):
771
771
  }
772
772
 
773
773
  function queueNativeFinalSummary(pi: ExtensionAPI, summary: string, customType: "workflow-plan-final-summary" | "workflow-mission-final-summary"): void {
774
- workflowScheduledAgentTurns += 1;
775
- setTimeout(() => {
776
- try {
777
- pi.sendMessage({ customType, content: `Print this comprehensive final deliverable summary exactly as written. Do not call tools. Do not shorten it. Do not replace it with a status receipt. Do not add Workflow Suite card wrappers or hidden handoff commentary. Preserve the provided simple section headings exactly so the terminal can render styled headings without showing raw hashtag markers. Use professional presentation only: no emoji, no Markdown tables, no box-art tables, and no dash-bullet lists.\n\n${professionalFinalSummaryMarkdown(summary)}`, display: false }, { triggerTurn: true, deliverAs: "followUp" });
778
- } finally {
779
- workflowScheduledAgentTurns = Math.max(0, workflowScheduledAgentTurns - 1);
780
- }
781
- }, 0);
774
+ queueAgentTurn(pi, `Print this comprehensive final deliverable summary exactly as written. Do not call tools. Do not shorten it. Do not replace it with a status receipt. Do not add Workflow Suite card wrappers or hidden handoff commentary. Preserve the provided simple section headings exactly so the terminal can render styled headings without showing raw hashtag markers. Use professional presentation only: no emoji, no Markdown tables, no box-art tables, and no dash-bullet lists.\n\n${professionalFinalSummaryMarkdown(summary)}`, customType);
782
775
  }
783
776
 
784
777
  function visibleDeferredHandoffFailure(label: string): boolean {
@@ -1770,7 +1763,14 @@ Approved plan is the execution contract. Do only this plan. No unrelated refacto
1770
1763
 
1771
1764
  Before editing, restate the approved plan, list expected files to change, and run the required/appropriate execution sub-agents. Do not edit until forced sub-agent requirements are satisfied. Then implement the plan. After implementation, summarize changed files, sub-agent findings used, and recommend validation.
1772
1765
 
1773
- Before your final execution summary, call workflow_execution_result with status, completedSteps, changedFiles, commands, blockers, and summary. The typed tool result is the primary handoff control plane. Your final execution summary must be validator-grade evidence, not just prose. Include Acceptance criteria coverage, exact files changed, Commands run with exit status, Checks skipped with reason, remaining manual verification, and any evidence from execution sub-agents.
1766
+ Plan progress tracking is mandatory for every numbered approved Plan step:
1767
+ - Before starting a step, call workflow_progress with that step number and status "active".
1768
+ - After completing a step, call workflow_progress with that step number and status "completed".
1769
+ - If a step fails or blocks, call workflow_progress with that step number and status "failed" or "blocked" and stop with the blocker.
1770
+ - For full-plan execution, progress through the approved steps in order so Current and Next advance visibly.
1771
+ - For per-step gated execution, track only the current allowed step and stop after that step.
1772
+
1773
+ Before your final execution summary, call workflow_execution_result with status, completedSteps, changedFiles, commands, blockers, and summary. completedSteps must list every approved Plan step number completed in this execution turn. The typed tool result is the primary handoff control plane. Your final execution summary must be validator-grade evidence, not just prose. Include Acceptance criteria coverage, exact files changed, Commands run with exit status, Checks skipped with reason, remaining manual verification, and any evidence from execution sub-agents.
1774
1774
 
1775
1775
  Execution scope:
1776
1776
  - ${stepExecutionGuidance}
@@ -1841,10 +1841,10 @@ ${requiredSubagentPreflightSection(preflightBlock)}
1841
1841
  - When validationPolicy is auto, deep, or maximum, validation sub-agents are expected for non-trivial work; prefer quality-validation for independent diff/risk/build-test review.
1842
1842
  - ${preflightSatisfied && policy === "forced" ? "Forced validation policy was satisfied by Workflow Suite preflight; do not rerun required workers solely for policy compliance." : "If validationPolicy is forced, required sub-agents must run before verdict, or stop with: Sub-agent policy is forced, but sub-agent execution is unavailable because <reason>."}
1843
1843
  - PASS only when the approved plan is fully satisfied with no blocking unresolved risk.
1844
- - PARTIAL PASS when implementation appears mostly plan-compliant but manual/visual/browser verification remains or evidence is incomplete without a concrete repairable issue.
1845
- - FAIL only for concrete missing requirements, unexpected changes, regressions, broken checks, or unsafe/out-of-scope work that needs repair.
1844
+ - FAIL when concrete missing requirements, unexpected changes, regressions, broken checks, unsafe/out-of-scope work, or concrete code/content/citation/source/file/metadata/artifact fixes remain.
1845
+ - PARTIAL PASS is only for manual/visual/browser verification caveats or evidence gaps without a concrete repairable issue.
1846
1846
  - Manual visual-verification caveats alone are not repairable failures; classify them as PARTIAL PASS and recommend manual QA/revalidation, not repair.
1847
- - If PARTIAL PASS includes concrete repairable issues in code, content, citations, sources, generated files, indexes, metadata, or validation artifacts, list them clearly under Missing Requirements or Recommended Next Action so repair mode can address them.
1847
+ - If concrete repairable issues remain in code, content, citations, sources, generated files, indexes, metadata, artifacts, or validation artifacts, mark Concrete Repairable Issue: yes, list them clearly under Missing Requirements or Recommended Next Action, and prefer FAIL over PARTIAL PASS.
1848
1848
  - Evidence gaps are not repairable defects unless you identify a concrete missing requirement or artifact. Mark Evidence Gap: yes and Concrete Repairable Issue: no when the correct next action is evidence collection or revalidation rather than repair.
1849
1849
 
1850
1850
  Project rules priority:
@@ -2755,7 +2755,7 @@ Forced Policy Rule: forced is a hard requirement and uses the Maximum / Forced t
2755
2755
  }
2756
2756
 
2757
2757
  function renderPermissionSummary(settings: ReturnType<typeof loadWorkflowSettings>): string {
2758
- const repoLock = settings.safety.repoLockEnabled === true ? "enabled for this project - built-in path tools are scoped to the current repository plus the Pi runtime directory for installed tools/skills; bash uses conservative path guardrails; sub-agent child processes are guided but not OS-sandboxed" : "disabled for this project - tools may access paths allowed by Pi and the active process permissions";
2758
+ const repoLock = settings.safety.repoLockEnabled === true ? "enabled for this project - normal file tools, conservative bash path checks, and sub-agents are scoped to the current repository; project .pi is readable for context but protected from normal edits; sub-agent child processes inherit the repository boundary but are not OS-sandboxed" : "disabled for this project - tools may access paths allowed by Pi and the active process permissions";
2759
2759
  return `Repo Lock: ${repoLock}
2760
2760
  Main Plan Permissions: read-only; bash ${settings.safety.disableBashInPlanMode === false ? "allowed for safe commands" : "blocked"}; edit/write blocked
2761
2761
  Main Execution Permissions: read/edit/write/safe bash; destructive bash ${settings.safety.blockDestructiveCommands !== false ? "blocked" : "allowed by setting"}
@@ -3075,7 +3075,7 @@ Note: Parallel File Edits controls simultaneous file writes only. It must not di
3075
3075
 
3076
3076
  ## Global Safety
3077
3077
  Repo Lock (Project): ${settings.safety.repoLockEnabled === true ? "enabled" : "disabled"}
3078
- Repo Lock Scope: project override only; toggling writes to the active repo .pi/workflow-settings.json; file tools are limited to the active repo plus Pi runtime tools/skills/prompts
3078
+ Repo Lock Scope: project override only; toggling writes to the active repo .pi/workflow-settings.json; normal file tools and sub-agents are limited to the active repo, while protected project .pi paths are read-only through normal tools
3079
3079
  Disable Bash In Plan Mode: ${settings.safety.disableBashInPlanMode !== false ? "enabled" : "disabled"}
3080
3080
  Disable Bash In Validator Mode: ${settings.safety.disableBashInValidatorMode !== false ? "enabled" : "disabled"}
3081
3081
  Block Destructive Commands: ${settings.safety.blockDestructiveCommands !== false ? "enabled" : "disabled"}
@@ -3246,7 +3246,7 @@ function planValidationState(state: WorkflowState): PlanValidationStatus {
3246
3246
  if (state.planProgress?.validationStatus) return state.planProgress.validationStatus;
3247
3247
  if (state.mode === "validating" || state.mode === "revalidating") return "running";
3248
3248
  if (state.validationVerdict === "PASS") return "pass";
3249
- if (state.validationVerdict === "PARTIAL PASS") return "unknown";
3249
+ if (state.validationVerdict === "PARTIAL PASS") return "partial pass";
3250
3250
  if (state.validationVerdict === "FAIL") return "fail";
3251
3251
  if (state.validationVerdict === "UNKNOWN") return "unknown";
3252
3252
  return "pending";
@@ -6788,14 +6788,14 @@ function missionRuntimePrompt(mission: MissionState, settings: ReturnType<typeof
6788
6788
  const last = mission.checkpoints[mission.checkpoints.length - 1];
6789
6789
  const policy = settings.subagents.executionPolicy ?? "auto";
6790
6790
  const subagentPolicyBlock = phasePromptPolicyBlock(settings, "Execution", "Mission Execution", preflightBlock);
6791
- return `You are PI MISSION MODE RUNTIME.\n\n${professionalOutputGuidance("Mission runtime")}\n\nMISSION MODE ACTIVE\n\nMission ID: ${mission.id}\nMission goal:\n${mission.goal}\n\nAutonomy: ${mission.autonomy}\nMission status: ${mission.status}\nCurrent milestone index: ${mission.currentMilestoneIndex}\nCurrent milestone: ${milestone ? `${milestone.id} — ${milestone.title}` : "none"}\nCurrent milestone objective: ${milestone?.objective ?? "none"}\n\nMilestone steps:\n${(milestone?.steps ?? []).map((s) => `- ${s}`).join("\n") || "- none recorded"}\n\nCompleted milestones:\n${completed.map((m) => `- ${m.id}: ${m.title}`).join("\n") || "- none"}\n\nRemaining milestones:\n${remaining.map((m) => `- ${m.id}: ${m.title} (${m.status})`).join("\n") || "- none"}\n\nLast checkpoint: ${last ? `${last.id} at ${last.timestamp} — ${last.summary}` : "none"}\nLast stop reason: ${mission.lastStopReason || "none"}\nLast block reason: ${mission.lastBlockReason || "none"}\nNext action: ${mission.nextAction || missionNextActionText(mission, settings)}\n\nSafety rules:\n- This is Mission Mode, not Plan Mode. Do not produce a generic implementation plan.\n- Execute only the current approved mission milestone.\n- Do not continue to later milestones unless Mission Mode starts them.\n- Stop on unexpected risk, destructive action, secret/auth/session/log/runtime-state edit, deployment, push, database mutation, or out-of-scope work.\n- Never edit auth files, sessions, logs, .env, .factory, .cursor, or mission runtime state.\n- Keep file writes sequential unless settings explicitly allow safe scoped parallel edits.\n- Use execution sub-agents aggressively for speed, read-only inspection, risk discovery, implementation strategy, and validation preparation when consistent with executionPolicy=${policy}; if forced, do not edit until required workers have reported.\n\n${subagentPolicyBlock}${requiredSubagentPreflightSection(preflightBlock)}\n\nDiagram guidance:\n${workflowMermaidGuidance()}\n\nWeb research guidance:\n${workflowRuntimeWebResearchGuidance()}\n\nCheckpoint requirements:\n- Produce a checkpoint-ready summary with files changed, risks, validation needs, and next action.\n- Include validator-grade evidence: Acceptance criteria coverage, Commands run with exit status, Checks skipped with reason, files changed/inspected, and remaining manual verification.\n- Do not edit mission runtime state directly; Mission Mode will checkpoint through the workflow runtime.\n\nValidation requirements:\n${(milestone?.validation ?? []).map((s) => `- ${s}`).join("\n") || "- Produce validation-ready execution summary for the mission validator."}\n\n${missionRunPlan(mission)}`;
6791
+ return `You are PI MISSION MODE RUNTIME.\n\n${professionalOutputGuidance("Mission runtime")}\n\nMISSION MODE ACTIVE\n\nMission ID: ${mission.id}\nMission goal:\n${mission.goal}\n\nAutonomy: ${mission.autonomy}\nMission status: ${mission.status}\nCurrent milestone index: ${mission.currentMilestoneIndex}\nCurrent milestone: ${milestone ? `${milestone.id} — ${milestone.title}` : "none"}\nCurrent milestone objective: ${milestone?.objective ?? "none"}\n\nMilestone steps:\n${(milestone?.steps ?? []).map((s) => `- ${s}`).join("\n") || "- none recorded"}\n\nCompleted milestones:\n${completed.map((m) => `- ${m.id}: ${m.title}`).join("\n") || "- none"}\n\nRemaining milestones:\n${remaining.map((m) => `- ${m.id}: ${m.title} (${m.status})`).join("\n") || "- none"}\n\nLast checkpoint: ${last ? `${last.id} at ${last.timestamp} — ${last.summary}` : "none"}\nLast stop reason: ${mission.lastStopReason || "none"}\nLast block reason: ${mission.lastBlockReason || "none"}\nNext action: ${mission.nextAction || missionNextActionText(mission, settings)}\n\nSafety rules:\n- This is Mission Mode, not Plan Mode. Do not produce a generic implementation plan.\n- Execute only the current approved mission milestone.\n- Do not continue to later milestones unless Mission Mode starts them.\n- Stop on unexpected risk, destructive action, secret/auth/session/log/runtime-state edit, deployment, push, database mutation, or out-of-scope work.\n- Never edit auth files, sessions, logs, .env, .factory, .cursor, or mission runtime state.\n- Keep file writes sequential unless settings explicitly allow safe scoped parallel edits.\n- Use execution sub-agents aggressively for speed, read-only inspection, risk discovery, implementation strategy, and validation preparation when consistent with executionPolicy=${policy}; if forced, do not edit until required workers have reported.\n\n${subagentPolicyBlock}${requiredSubagentPreflightSection(preflightBlock)}\n\nDiagram guidance:\n${workflowMermaidGuidance()}\n\nWeb research guidance:\n${workflowRuntimeWebResearchGuidance()}\n\nCheckpoint requirements:\n- Before your final milestone summary, call mission_milestone_result with milestoneId, status, summary, blockers, and evidence. The typed tool result is the primary Mission execution handoff.\n- Produce a checkpoint-ready summary with files changed, risks, validation needs, and next action.\n- Include validator-grade evidence: Acceptance criteria coverage, Commands run with exit status, Checks skipped with reason, files changed/inspected, and remaining manual verification.\n- Do not edit mission runtime state directly; Mission Mode will checkpoint through the workflow runtime.\n\nValidation requirements:\n${(milestone?.validation ?? []).map((s) => `- ${s}`).join("\n") || "- Produce validation-ready execution summary for the mission validator."}\n\n${missionRunPlan(mission)}`;
6792
6792
  }
6793
6793
 
6794
6794
  function missionValidationPrompt(mission: MissionState, settings: ReturnType<typeof loadWorkflowSettings>, executionSummary?: string, preflightBlock?: string): string {
6795
6795
  const milestone = mission.milestones[mission.currentMilestoneIndex];
6796
6796
  const last = mission.checkpoints[mission.checkpoints.length - 1];
6797
6797
  const subagentPolicyBlock = phasePromptPolicyBlock(settings, "Validation", "Mission Validation", preflightBlock);
6798
- return `You are PI MISSION MODE VALIDATOR.\n\n${professionalOutputGuidance("Mission validation")}\n\nValidate the completed work against the current mission milestone only. Use read-only tools only. Do not edit or write. You may run safe read-only bash evidence commands such as git status, git diff, git log, package-script discovery, and existing typecheck/test/build commands when appropriate and safe. Do not run mutating, install, deploy, push, reset, clean, database, secret, or settings/state commands. You are the independent validator, not the mission executor; do not repair and do not accept executor claims without evidence.\n\nMission ID: ${mission.id}\nMission goal:\n${mission.goal}\n\nAutonomy: ${mission.autonomy}\nMission status: ${mission.status}\nCurrent milestone: ${milestone ? `${milestone.id} — ${milestone.title}` : "none"}\nMilestone objective: ${milestone?.objective ?? "none"}\nValidation retry: ${mission.currentValidationRetry ?? 0} of ${maxValidationRetries(mission, settings)} per milestone\nMission validation repair retries: ${missionValidationRetryCount(mission)} of ${maxMissionValidationRetries(mission, settings)} total\nLast validation failure: ${mission.lastValidationFailure || "none"}\nLast repair attempt: ${mission.lastRepairAttempt || "none"}\n\n${subagentPolicyBlock}${requiredSubagentPreflightSection(preflightBlock)}\n\nMilestone validation requirements:\n${(milestone?.validation ?? []).map((s) => `- ${s}`).join("\n") || "- Validate milestone completion and risks."}\n\nLast checkpoint: ${last ? `${last.id} at ${last.timestamp} — ${last.summary}` : "none"}\nLast stop reason: ${mission.lastStopReason || "none"}\nLast block reason: ${mission.lastBlockReason || "none"}\nNext action: ${mission.nextAction || missionNextActionText(mission, settings)}\n\nExecution summary:\n${executionSummary ?? "(none recorded)"}\n\nDiagram guidance:\n${workflowMermaidGuidance()}\n\nWeb research guidance:\n${workflowRuntimeWebResearchGuidance()}\n\nVerdict guidance:\n- PASS only when the milestone is fully satisfied with no blocking unresolved risk.\n- PARTIAL PASS when the work appears mostly milestone-compliant but manual/visual/browser verification remains or evidence is incomplete without a concrete repairable issue.\n- FAIL only for concrete missing requirements, unexpected changes, regressions, broken checks, or unsafe/out-of-scope work that needs repair.\n- Manual visual-verification caveats alone are not repairable failures; recommend manual QA/revalidation instead of repair. If PARTIAL PASS includes concrete repairable issues in code, content, citations, sources, generated files, indexes, metadata, or validation artifacts, list them clearly under Missing Requirements or Recommended Next Action so repair mode can address them.\n- Evidence gaps are not repairable defects unless you identify a concrete missing requirement or artifact. Mark Evidence Gap: yes and Concrete Repairable Issue: no when the correct next action is evidence collection or revalidation rather than repair.\n\nOutput exactly:\n# Validation Report\n## Verdict\nPASS, PARTIAL PASS, or FAIL\n## Reason\n## Mission Coverage\n## Milestone Requirements Reviewed\n## Changed Files Reviewed\n## Commands Run With Exit Status\n## Checks Skipped With Reason\n## Concrete Repairable Issue\nyes/no and short reason\n## Evidence Gap\nyes/no and exact missing evidence\n## Manual Verification Required\nyes/no and exact manual check\n## Missing Requirements\n## Unexpected Changes\n## Regression Risks\n## Test And Build Status\n## Recommended Next Action`;
6798
+ return `You are PI MISSION MODE VALIDATOR.\n\n${professionalOutputGuidance("Mission validation")}\n\nValidate the completed work against the current mission milestone only. Use read-only tools only. Do not edit or write. You may run safe read-only bash evidence commands such as git status, git diff, git log, package-script discovery, and existing typecheck/test/build commands when appropriate and safe. Do not run mutating, install, deploy, push, reset, clean, database, secret, or settings/state commands. You are the independent validator, not the mission executor; do not repair and do not accept executor claims without evidence.\n\nMission ID: ${mission.id}\nMission goal:\n${mission.goal}\n\nAutonomy: ${mission.autonomy}\nMission status: ${mission.status}\nCurrent milestone: ${milestone ? `${milestone.id} — ${milestone.title}` : "none"}\nMilestone objective: ${milestone?.objective ?? "none"}\nValidation retry: ${mission.currentValidationRetry ?? 0} of ${maxValidationRetries(mission, settings)} per milestone\nMission validation repair retries: ${missionValidationRetryCount(mission)} of ${maxMissionValidationRetries(mission, settings)} total\nLast validation failure: ${mission.lastValidationFailure || "none"}\nLast repair attempt: ${mission.lastRepairAttempt || "none"}\n\n${subagentPolicyBlock}${requiredSubagentPreflightSection(preflightBlock)}\n\nMilestone validation requirements:\n${(milestone?.validation ?? []).map((s) => `- ${s}`).join("\n") || "- Validate milestone completion and risks."}\n\nLast checkpoint: ${last ? `${last.id} at ${last.timestamp} — ${last.summary}` : "none"}\nLast stop reason: ${mission.lastStopReason || "none"}\nLast block reason: ${mission.lastBlockReason || "none"}\nNext action: ${mission.nextAction || missionNextActionText(mission, settings)}\n\nExecution summary:\n${executionSummary ?? "(none recorded)"}\n\nDiagram guidance:\n${workflowMermaidGuidance()}\n\nWeb research guidance:\n${workflowRuntimeWebResearchGuidance()}\n\nVerdict guidance:\n- PASS only when the milestone is fully satisfied with no blocking unresolved risk.\n- FAIL when concrete missing requirements, unexpected changes, regressions, broken checks, unsafe/out-of-scope work, or concrete code/content/citation/source/file/metadata/artifact fixes remain.\n- PARTIAL PASS is only for manual/visual/browser verification caveats or evidence gaps without a concrete repairable issue.\n- Manual visual-verification caveats alone are not repairable failures; recommend manual QA/revalidation instead of repair.\n- If concrete repairable issues remain in code, content, citations, sources, generated files, indexes, metadata, artifacts, or validation artifacts, mark Concrete Repairable Issue: yes, list them clearly under Missing Requirements or Recommended Next Action, and prefer FAIL over PARTIAL PASS.\n- Evidence gaps are not repairable defects unless you identify a concrete missing requirement or artifact. Mark Evidence Gap: yes and Concrete Repairable Issue: no when the correct next action is evidence collection or revalidation rather than repair.\n\nOutput exactly:\n# Validation Report\n## Verdict\nPASS, PARTIAL PASS, or FAIL\n## Reason\n## Mission Coverage\n## Milestone Requirements Reviewed\n## Changed Files Reviewed\n## Commands Run With Exit Status\n## Checks Skipped With Reason\n## Concrete Repairable Issue\nyes/no and short reason\n## Evidence Gap\nyes/no and exact missing evidence\n## Manual Verification Required\nyes/no and exact manual check\n## Missing Requirements\n## Unexpected Changes\n## Regression Risks\n## Test And Build Status\n## Recommended Next Action`;
6799
6799
  }
6800
6800
 
6801
6801
  function missionFinalValidationPrompt(mission: MissionState, settings: ReturnType<typeof loadWorkflowSettings>, executionSummary?: string, preflightBlock?: string): string {
@@ -6838,7 +6838,7 @@ Last checkpoint: ${last ? `${last.id} at ${last.timestamp} — ${last.summary}`
6838
6838
  Execution summary:
6839
6839
  ${executionSummary ?? "(none recorded)"}
6840
6840
 
6841
- Validate the complete mission goal across all milestones, not just the last milestone. Confirm milestone results compose into the original mission outcome. Surface integration gaps, missing cross-milestone requirements, regressions, and unresolved repair risks. Use PASS only for complete success, PARTIAL PASS for manual/visual/browser verification caveats or evidence gaps without concrete repairable issues, and FAIL only for concrete repairable defects or unsafe/out-of-scope work. Evidence gaps are not repairable defects unless a concrete missing requirement or artifact is identified.
6841
+ Validate the complete mission goal across all milestones, not just the last milestone. Confirm milestone results compose into the original mission outcome. Surface integration gaps, missing cross-milestone requirements, regressions, and unresolved repair risks. Use PASS only for complete success. Use FAIL when concrete code/content/citation/source/file/metadata/artifact fixes, concrete repairable defects, or unsafe/out-of-scope work remain. Use PARTIAL PASS only for manual/visual/browser verification caveats or evidence gaps without concrete repairable issues. Evidence gaps are not repairable defects unless a concrete missing requirement or artifact is identified.
6842
6842
 
6843
6843
  Output exactly:
6844
6844
  # Final Mission Validation Report
@@ -7248,11 +7248,12 @@ export default function workflowModes(pi: ExtensionAPI): void {
7248
7248
  const completedSteps = normalizePlanCompletedSteps(params.completedSteps);
7249
7249
  const validationAvailable = planValidationModelAvailable(settings);
7250
7250
  const validateAfterExecution = planAutoValidationEnabled(settings);
7251
+ const executedStepIndex = typeof state.planExecutionStepIndex === "number" ? state.planExecutionStepIndex : state.planProgress?.currentStepIndex;
7251
7252
  const progressEnabled = workflowPlanProgressEnabled(settings);
7252
7253
  const progressedPlanProgress = progressEnabled ? planProgressWithCompletedSteps(state, settings, completedSteps) : state.planProgress;
7253
7254
  const progressedState = progressedPlanProgress ? { ...state, planProgress: progressedPlanProgress } : state;
7254
7255
  if (status !== "completed") {
7255
- updateState({ mode: state.reviewerReport ? "reviewed" : "plan_approved", executionSummary: summary, planProgress: progressEnabled && progressedPlanProgress ? mergePlanProgress(progressedState, settings, { lifecycleStatus: "blocked", validationStatus: "pending", nextAction: "continue execution" }) : state.planProgress }, ctx);
7256
+ updateState({ mode: state.reviewerReport ? "reviewed" : "plan_approved", executionSummary: summary, planExecutionStepIndex: undefined, planProgress: progressEnabled && progressedPlanProgress ? mergePlanProgress(progressedState, settings, { lifecycleStatus: "blocked", validationStatus: "pending", nextAction: "continue execution" }) : state.planProgress }, ctx);
7256
7257
  queuePlanTerminalSummary(ctx, "blocked", "Plan execution stopped", { reason: summary });
7257
7258
  showBlockedPlanRecoveryMenu(ctx);
7258
7259
  return { ...typedToolAck(), details: { accepted: true, status, validationStarted: false } };
@@ -7264,7 +7265,7 @@ export default function workflowModes(pi: ExtensionAPI): void {
7264
7265
  queueAgentTurn(pi, `The workflow_execution_result handoff was incomplete for Plan progress tracking. Do not redo work. Do not edit, write, patch, or run mutating commands. Submit a corrected workflow_execution_result now. Include status and completedSteps for every approved Plan step that was completed, plus changedFiles, commands, blockers, and summary. Reason: ${reason}`, "workflow-execution-handoff-correction");
7265
7266
  return { ...typedToolAck(false), details: { accepted: false, status, validationStarted: false, reason }, isError: true };
7266
7267
  }
7267
- updateState({ mode: "executed", executionSummary: summary, planProgress: progressEnabled ? mergePlanProgress({ ...progressedState, mode: "executed" }, settings, { lifecycleStatus: "executing", nextAction: validationAvailable && validateAfterExecution ? "validator" : "finish workflow" }) : progressedPlanProgress }, ctx);
7268
+ updateState({ mode: "executed", executionSummary: summary, planStepValidationIndex: settings.workflow.validateAfterEachStep === true ? executedStepIndex : state.planStepValidationIndex, planExecutionStepIndex: undefined, planProgress: progressEnabled ? mergePlanProgress({ ...progressedState, mode: "executed" }, settings, { lifecycleStatus: "executing", nextAction: validationAvailable && validateAfterExecution ? "validator" : "finish workflow" }) : progressedPlanProgress }, ctx);
7268
7269
  if (validationAvailable && validateAfterExecution) deferWorkflowAction(pi, "begin validation after typed execution", async () => { await beginValidation(ctx, true); });
7269
7270
  else if (!planValidationGateActive(settings)) deferWorkflowAction(pi, "complete plan after typed execution without validation", () => completePlanWithoutValidation(ctx, validationAvailable ? "Validation skipped: validation is disabled by workflow settings." : "Validation skipped: validator disabled or not configured."));
7270
7271
  else deferWorkflowAction(pi, "show post execution menu after typed execution", () => showPostExecutionMenu(ctx, validationAvailable));
@@ -7302,6 +7303,17 @@ export default function workflowModes(pi: ExtensionAPI): void {
7302
7303
  if (typeof params.concreteRepairableIssue === "boolean") lines.push(`Concrete Repairable Issue: ${params.concreteRepairableIssue ? "yes" : "no"}`);
7303
7304
  if (typeof params.evidenceGap === "boolean") lines.push(`Evidence Gap: ${params.evidenceGap ? "yes" : "no"}`);
7304
7305
  if (typeof params.manualVerificationRequired === "boolean") lines.push(`Manual Verification Required: ${params.manualVerificationRequired ? "yes" : "no"}`);
7306
+ const issues = Array.isArray(params.issues) ? params.issues : [];
7307
+ if (issues.length > 0) {
7308
+ lines.push("Issues:");
7309
+ for (const issue of issues) {
7310
+ const item = issue && typeof issue === "object" ? issue as Record<string, unknown> : {};
7311
+ const title = typeof item.title === "string" && item.title.trim() ? item.title.trim() : "Validation issue";
7312
+ const detail = typeof item.detail === "string" && item.detail.trim() ? ` — ${item.detail.trim()}` : "";
7313
+ const repairable = typeof item.repairable === "boolean" ? ` Repairable: ${item.repairable ? "yes" : "no"}.` : "";
7314
+ lines.push(`- ${title}${detail}${repairable}`);
7315
+ }
7316
+ }
7305
7317
  return lines.join("\n");
7306
7318
  };
7307
7319
 
@@ -7514,6 +7526,12 @@ export default function workflowModes(pi: ExtensionAPI): void {
7514
7526
  }
7515
7527
  if (state.mode === "validating" || state.mode === "revalidating" || state.mode === "repairing") {
7516
7528
  const settings = loadWorkflowSettings(ctx.cwd);
7529
+ if (state.mode === "repairing" && repairTextIndicatesRevalidationReady(stoppedText)) {
7530
+ updateState({ mode: "revalidating", executionSummary: `${state.executionSummary ?? ""}\n\nRepair summary:\n${stoppedText}`.trim(), lastRepairStatus: "completed", lastRepairAttempt: compact(stoppedText, 1200), repairHistory: appendWorkflowRepairHistory({ timestamp: new Date().toISOString(), retry: state.currentValidationRetry ?? 0, status: "completed", validationFailure: compact(state.lastValidationFailure ?? state.validationReport ?? "", 800), repairSummary: compact(stoppedText, 800), nextAction: "Revalidate interrupted completed repair." }), planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "revalidating", lastRepairStatus: "completed" }, settings, { lifecycleStatus: "revalidating", validationStatus: "running", repairStatus: "completed", nextAction: "validation result" }, state.approvedPlan) : state.planProgress }, ctx);
7531
+ deferWorkflowAction(pi, "begin revalidation after interrupted plan repair", async () => { await beginValidation(ctx, true, true); });
7532
+ recordWorkflowInternalEvent(ctx, "Plan repair interruption recovered as completed repair pending revalidation.");
7533
+ return true;
7534
+ }
7517
7535
  updateState({ mode: "plan_approved", validationReport: state.mode === "validating" || state.mode === "revalidating" ? stoppedText : state.validationReport, lastRepairAttempt: state.mode === "repairing" ? stoppedText : state.lastRepairAttempt, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "plan_approved" }, settings, { lifecycleStatus: "approved", nextAction: "rerun stopped gate" }, state.approvedPlan) : state.planProgress }, ctx);
7518
7536
  queuePlanTerminalSummary(ctx, "blocked", "Plan workflow gate stopped", { validationText: state.mode === "validating" || state.mode === "revalidating" ? stoppedText : state.validationReport, reason: "Workflow gate stopped before completion." });
7519
7537
  recordWorkflowInternalEvent(ctx, "Workflow gate stopped before completion.");
@@ -7599,6 +7617,23 @@ export default function workflowModes(pi: ExtensionAPI): void {
7599
7617
  updateState({ mode: "mission_blocked", activeMissionId: blocked.id, task: blocked.goal, originalTask: blocked.goal, draftPlan: stoppedText }, ctx);
7600
7618
  return true;
7601
7619
  }
7620
+ if (state.mode === "mission_repairing" && repairTextIndicatesRevalidationReady(stoppedText)) {
7621
+ const repaired = saveActiveMission({
7622
+ ...mission,
7623
+ status: "revalidating",
7624
+ lastStopReason: "",
7625
+ lastRepairStatus: "completed",
7626
+ lastRepairAttempt: compact(stoppedText, 1200),
7627
+ nextAction: `Revalidate ${milestone?.id ?? "current milestone"} after interrupted completed repair.`,
7628
+ lastSummary: `Mission repair completed for ${milestone?.id ?? "current milestone"}; interrupted output recovered for revalidation.`,
7629
+ repairHistory: appendRepairHistory(mission, { timestamp: new Date().toISOString(), milestoneId: milestone?.id, retry: mission.currentValidationRetry ?? 0, status: "completed", repairSummary: compact(stoppedText, 800), nextAction: "Revalidate interrupted completed repair." }),
7630
+ });
7631
+ checkpointMission(repaired, `Mission repair interruption recovered as completed for ${milestone?.id ?? "current milestone"}. ${compact(stoppedText, 500)}`, "Revalidation started after interrupted repair.", milestone?.id, { validationResult: repaired.lastValidationResult });
7632
+ updateState({ mode: "mission_revalidating", activeMissionId: repaired.id, task: repaired.goal, originalTask: repaired.goal, executionSummary: stoppedText }, ctx);
7633
+ deferWorkflowAction(pi, "begin mission revalidation after interrupted repair", () => beginMissionValidation(ctx, true, true));
7634
+ recordWorkflowInternalEvent(ctx, "Mission repair interruption recovered as completed repair pending revalidation.");
7635
+ return true;
7636
+ }
7602
7637
  const paused = saveActiveMission({
7603
7638
  ...mission,
7604
7639
  status: "paused",
@@ -7647,6 +7682,12 @@ export default function workflowModes(pi: ExtensionAPI): void {
7647
7682
  if (i === index) return { ...step, status };
7648
7683
  return step;
7649
7684
  });
7685
+ if (status === "completed" || status === "skipped") {
7686
+ const nextOpen = steps.findIndex((step, i) => i > index && step.status === "pending");
7687
+ if (nextOpen >= 0 && settings.workflow.validateAfterEachStep !== true && settings.workflow.requireApprovalPerStep !== true) {
7688
+ steps[nextOpen] = { ...steps[nextOpen], status: "active" as PlanStepStatus };
7689
+ }
7690
+ }
7650
7691
  updateState({ planProgress: { ...progress, steps, currentStepIndex: currentStepIndexForSteps(steps, index), nextAction: planNextActionText(state) } }, ctx);
7651
7692
  return true;
7652
7693
  };
@@ -8265,6 +8306,7 @@ ${reportExcerpt(validation, 2400)}
8265
8306
  repairHistory: undefined,
8266
8307
  lastRepairStatus: "none",
8267
8308
  planStepValidationIndex: undefined,
8309
+ planExecutionStepIndex: undefined,
8268
8310
  planRuntime: undefined,
8269
8311
  planProgress: undefined,
8270
8312
  lastCompletedPlanSummary: completedPlanSummary,
@@ -8551,6 +8593,12 @@ ${renderMissionProgress(mission, settings)}
8551
8593
  return;
8552
8594
  }
8553
8595
  if (mission.status === "paused" || mission.status === "stopped") {
8596
+ if (missionRepairCompletedPendingRevalidation(mission)) {
8597
+ const revalidating = saveActiveMission({ ...mission, status: "revalidating", lastRepairStatus: mission.lastRepairStatus === "blocked" ? "completed" : (mission.lastRepairStatus ?? "completed"), lastStopReason: "", nextAction: `Revalidate ${mission.milestones[mission.currentMilestoneIndex]?.id ?? "current milestone"} after completed repair.`, lastSummary: "Mission resumed to revalidation after completed repair." });
8598
+ checkpointMission(revalidating, "Mission resume detected completed repair pending revalidation.", "Resume current mission revalidation gate.", mission.milestones[mission.currentMilestoneIndex]?.id, { validationResult: revalidating.lastValidationResult });
8599
+ await beginMissionValidation(ctx, true, true);
8600
+ return;
8601
+ }
8554
8602
  const approved = saveActiveMission({ ...mission, status: "approved", lastStopReason: "", nextAction: "Run /mission continue to proceed.", lastSummary: "Mission resumed by user." });
8555
8603
  const checkpointed = checkpointMission(approved, "Mission resume requested from resume menu.", "Resume current mission milestone in Mission Mode.");
8556
8604
  await beginMissionRun(ctx, checkpointed, "resume");
@@ -8965,9 +9013,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
8965
9013
  return;
8966
9014
  }
8967
9015
  updateState({ modelsUsed: { ...(state.modelsUsed ?? {}), executor: modelLabel(route), planner: running.modelsUsed?.planner } }, ctx);
8968
- if (auto) {
8969
- queueAgentTurn(pi, `Execute current mission milestone ${milestone.id}: ${milestone.title}.`, "mission-run-trigger");
8970
- } else queueWorkflowPrompt(pi, missionRuntimePrompt(running, settings, phasePreflightBlocks.Execution));
9016
+ queueAgentTurn(pi, missionRuntimePrompt(running, settings, phasePreflightBlocks.Execution), auto ? "mission-run-trigger" : "mission-run-manual-trigger");
8971
9017
  }
8972
9018
 
8973
9019
  async function handleMissionApprovalHandoff(ctx: ExtensionContext, mission: MissionState, source: "menu" | "command" = "command") {
@@ -9157,7 +9203,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9157
9203
  const forcedSubagentTaskText = (phase: SubagentPhase, agent: string, index: number, required: number, context: ForcedSubagentPreflightContext): string => {
9158
9204
  const label = context.label ?? phase;
9159
9205
  const mission = context.mission;
9160
- const repoLock = loadWorkflowSettings().safety.repoLockEnabled === true ? " Repo Lock is enabled: keep project file discovery and commands inside the current repository. Access to the Pi runtime directory is allowed for installed Workflow Suite tools, agents, skills, and prompts only; do not inspect sibling repositories or unrelated home-directory paths." : "";
9206
+ const repoLock = loadWorkflowSettings().safety.repoLockEnabled === true ? " Repo Lock is enabled: keep project file discovery and commands inside the current repository. Project .pi files may be read for context, but do not edit protected .pi control/config paths through normal tools. Do not inspect sibling repositories, unrelated home-directory paths, or the live Pi runtime." : "";
9161
9207
  const base = `Forced ${label} sub-agent preflight worker ${index + 1}/${required}. You are running before the main ${label} agent. Stay read-only unless your agent contract explicitly allows otherwise; do not edit, commit, push, deploy, mutate databases, or touch secrets/runtime state.${repoLock} Return concise findings for the main ${label} agent.`;
9162
9208
  if (phase === "Planning") return `${base}\n\nPlanning target:\n${context.task ?? mission?.goal ?? state.task ?? state.originalTask ?? "(not recorded)"}\n\n${mission ? `Mission ID: ${mission.id}\nAutonomy: ${mission.autonomy}\nExisting milestones: ${mission.milestones.length}\n` : ""}\nFocus for ${agent}: identify project rules, likely files/systems, ambiguity, risks, validation needs, off-limits files, and specific recommendations for the final plan.`;
9163
9209
  if (phase === "Execution") return `${base}\n\nApproved execution contract:\n${context.approvedPlan ?? state.approvedPlan ?? (mission ? missionRunPlan(mission) : "(not recorded)")}\n\nFocus for ${agent}: inspect likely files, identify implementation hazards, propose safe edit order, regression risks, and validation checks. Do not perform the implementation.`;
@@ -9466,6 +9512,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9466
9512
  repairHistory: undefined,
9467
9513
  lastRepairStatus: "none",
9468
9514
  planStepValidationIndex: undefined,
9515
+ planExecutionStepIndex: undefined,
9469
9516
  planRuntime: undefined,
9470
9517
  planProgress: undefined,
9471
9518
  planHistoryId: undefined,
@@ -9512,6 +9559,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9512
9559
  repairHistory: undefined,
9513
9560
  lastRepairStatus: "none",
9514
9561
  planStepValidationIndex: undefined,
9562
+ planExecutionStepIndex: undefined,
9515
9563
  planProgress: workflowPlanProgressEnabled(settings) ? createPlanProgress(planText, settings, "approved") : undefined,
9516
9564
  }, ctx);
9517
9565
  persistCurrentPlan(ctx, "approved", saveReason);
@@ -9543,7 +9591,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9543
9591
  }, ctx);
9544
9592
  if (!options.planningPreflightSatisfied && !beginForcedSubagentPhase(ctx, "Planning", settings)) {
9545
9593
  pi.setActiveTools(planToolsFor(settings));
9546
- updateState({ mode: "plan_draft", activePlanId, draftPlan: "Planning blocked before the planner could run: forced planning sub-agent requirements are unavailable.", approvedPlan: undefined, lastReviewFailure: "Forced planning sub-agent requirements are unavailable.", executionSummary: undefined, validationReport: undefined, validationVerdict: undefined, reviewerReport: undefined, reviewerVerdict: undefined, currentReviewRetry: 0, workflowReviewRetryCount: 0, maxReviewRetriesPerPlan: undefined, maxReviewRetriesPerWorkflow: undefined, lastReviewAttempt: undefined, lastReviewRepairStatus: "none", reviewHistory: undefined, reviewRepairInProgress: undefined, repairRetryState: undefined, currentValidationRetry: 0, workflowValidationRetryCount: 0, lastRepairStatus: "none", planStepValidationIndex: undefined, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "validated", draftPlan: undefined, approvedPlan: undefined }, settings, { lifecycleStatus: "blocked", nextAction: "fix planning sub-agent policy or revise planning", steps: [] }, undefined) : undefined, lastCompletedPlanSummary: undefined }, ctx);
9594
+ updateState({ mode: "plan_draft", activePlanId, draftPlan: "Planning blocked before the planner could run: forced planning sub-agent requirements are unavailable.", approvedPlan: undefined, lastReviewFailure: "Forced planning sub-agent requirements are unavailable.", executionSummary: undefined, validationReport: undefined, validationVerdict: undefined, reviewerReport: undefined, reviewerVerdict: undefined, currentReviewRetry: 0, workflowReviewRetryCount: 0, maxReviewRetriesPerPlan: undefined, maxReviewRetriesPerWorkflow: undefined, lastReviewAttempt: undefined, lastReviewRepairStatus: "none", reviewHistory: undefined, reviewRepairInProgress: undefined, repairRetryState: undefined, currentValidationRetry: 0, workflowValidationRetryCount: 0, lastRepairStatus: "none", planStepValidationIndex: undefined, planExecutionStepIndex: undefined, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "validated", draftPlan: undefined, approvedPlan: undefined }, settings, { lifecycleStatus: "blocked", nextAction: "fix planning sub-agent policy or revise planning", steps: [] }, undefined) : undefined, lastCompletedPlanSummary: undefined }, ctx);
9547
9595
  return;
9548
9596
  }
9549
9597
  const route = await applyModelForRole(pi, ctx, "planner", { cwd: ctx.cwd });
@@ -9616,7 +9664,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9616
9664
  const steps = settings.workflow.validateAfterEachStep === true || settings.workflow.requireApprovalPerStep === true
9617
9665
  ? baseSteps.map((step, index) => index === activeIndex ? { ...step, status: "active" as PlanStepStatus } : step.status === "active" ? { ...step, status: "pending" as PlanStepStatus } : step)
9618
9666
  : baseSteps;
9619
- updateState({ mode: "executing", planProgress: { ...currentProgress, steps, currentStepIndex: currentStepIndexForSteps(steps, activeIndex) } }, ctx);
9667
+ updateState({ mode: "executing", planExecutionStepIndex: activeIndex, planProgress: { ...currentProgress, steps, currentStepIndex: currentStepIndexForSteps(steps, activeIndex) } }, ctx);
9620
9668
  if (!beginForcedSubagentPhase(ctx, "Execution", settings)) {
9621
9669
  const reason = "Execution blocked by forced sub-agent policy availability gate.";
9622
9670
  updateState({ mode: previousMode === "reviewed" ? "reviewed" : "plan_approved", planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: previousMode === "reviewed" ? "reviewed" : "plan_approved" }, settings, { lifecycleStatus: "blocked", nextAction: "fix execution policy blocker" }, state.approvedPlan) : state.planProgress }, ctx);
@@ -9630,11 +9678,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9630
9678
  return false;
9631
9679
  }
9632
9680
  updateState({ modelsUsed: { ...(state.modelsUsed ?? {}), executor: modelLabel(route) } }, ctx);
9633
- if (auto) {
9634
- queueAgentTurn(pi, "Execute the approved plan. Follow each step precisely.", "workflow-execute-trigger");
9635
- } else {
9636
- queueWorkflowPrompt(pi, executePrompt(state, settings, phasePreflightBlocks.Execution));
9637
- }
9681
+ queueAgentTurn(pi, executePrompt(state, settings, phasePreflightBlocks.Execution), auto ? "workflow-execute-trigger" : "workflow-execute-manual-trigger");
9638
9682
  return true;
9639
9683
  }
9640
9684
 
@@ -9959,6 +10003,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
9959
10003
  currentValidationRetry: 0,
9960
10004
  workflowValidationRetryCount: 0,
9961
10005
  planStepValidationIndex: undefined,
10006
+ planExecutionStepIndex: undefined,
9962
10007
  planRuntime: undefined,
9963
10008
  planProgress: workflowPlanProgressEnabled(settings) ? createPlanProgress(plan.finalPlan, settings, "approved") : undefined,
9964
10009
  }, ctx);
@@ -10045,7 +10090,7 @@ Use /mission status, /mission resume, /mission continue, or /mission retry.`);
10045
10090
 
10046
10091
  const reusePlan = async (plan: SavedWorkflowPlan, amend: boolean): Promise<void> => {
10047
10092
  activeMission = undefined;
10048
- updateState({ mode: "awaiting_plan_input", activeMissionId: undefined, task: plan.originalTask ?? "Reuse saved plan", originalTask: plan.originalTask ?? "Reuse saved plan", draftPlan: undefined, approvedPlan: undefined, validationReport: undefined, validationVerdict: undefined, executionSummary: undefined, reviewerReport: undefined, clarifyingQuestions: undefined, clarifyingAnswers: undefined, clarificationAlreadyAsked: undefined, clarificationRequiredBeforePlan: undefined, clarificationRequirementReason: undefined, clarificationSkipReason: undefined, clarificationQualityRetryCount: undefined, planHistoryId: undefined, approvedPlanHistoryId: undefined, planStepValidationIndex: undefined, planRuntime: undefined, planProgress: undefined }, ctx);
10093
+ updateState({ mode: "awaiting_plan_input", activeMissionId: undefined, task: plan.originalTask ?? "Reuse saved plan", originalTask: plan.originalTask ?? "Reuse saved plan", draftPlan: undefined, approvedPlan: undefined, validationReport: undefined, validationVerdict: undefined, executionSummary: undefined, reviewerReport: undefined, clarifyingQuestions: undefined, clarifyingAnswers: undefined, clarificationAlreadyAsked: undefined, clarificationRequiredBeforePlan: undefined, clarificationRequirementReason: undefined, clarificationSkipReason: undefined, clarificationQualityRetryCount: undefined, planHistoryId: undefined, approvedPlanHistoryId: undefined, planStepValidationIndex: undefined, planExecutionStepIndex: undefined, planRuntime: undefined, planProgress: undefined }, ctx);
10049
10094
  await beginPlanning(ctx, plan.originalTask ?? "Reuse saved plan", plan.finalPlan, amend ? "Amend this saved plan into a new approval-ready plan. Keep what still applies and update what should change." : "Reuse this saved plan as the starting point for a new approval-ready plan.");
10050
10095
  };
10051
10096
 
@@ -10490,16 +10535,6 @@ ${renderMissionStatus(activeMission ?? paused)}`);
10490
10535
  showBlockedMissionRecoveryMenu(ctx);
10491
10536
  return;
10492
10537
  }
10493
- if (verdict === "PARTIAL PASS" && failureClass === "ambiguous" && !simplePresetActive(settings)) {
10494
- const reason = "Mission validation returned PARTIAL PASS with incomplete evidence but no concrete repairable issue. Automatic repair is not appropriate for this preset.";
10495
- const blocked = saveActiveMission({ ...failed, status: "blocked", lastRepairStatus: "none", lastBlockReason: reason, nextAction: "Clarify the validation gap, perform manual verification, or run /mission revalidate.", lastSummary: "Mission blocked pending clearer partial-pass validation evidence." });
10496
- checkpointMission(blocked, `Mission validation PARTIAL PASS needs clearer evidence for ${milestone?.id ?? "current milestone"}. Reason: ${reason}`, blocked.nextAction ?? "Clarify validation evidence or revalidate.", milestone?.id, { validationResult: verdict });
10497
- updateState({ mode: "mission_blocked", activeMissionId: blocked.id, validationReport: validationText, validationVerdict: verdict, lastMissionStopSummary: buildMissionStopSummary(ctx, blocked, "blocked", "Mission blocked", { validationText, verdict, reason }) }, ctx);
10498
- queueMissionTerminalSummary(ctx, blocked, "blocked", "Mission blocked", { validationText, verdict, reason });
10499
- recordWorkflowInternalEvent(ctx, "Mission validation evidence blocker suppressed from transcript.");
10500
- showBlockedMissionRecoveryMenu(ctx);
10501
- return;
10502
- }
10503
10538
  const unsafe = validationFailureRequiresApproval(failure, settings);
10504
10539
  const shouldBlock = mission.autonomy === "manual"
10505
10540
  || settings.missions.autoRepairValidationFailures === false
@@ -13804,7 +13839,7 @@ Public workflow commands:
13804
13839
  const archivedId = archiveCurrentPlanIfPresent(ctx, reason);
13805
13840
  const settings = loadWorkflowSettings(ctx.cwd);
13806
13841
  pi.setActiveTools(planToolsFor(settings));
13807
- updateState({ mode: "awaiting_plan_input", activeMissionId: undefined, task: undefined, originalTask: undefined, draftPlan: undefined, approvedPlan: undefined, reviewerReport: undefined, reviewerVerdict: undefined, currentReviewRetry: 0, workflowReviewRetryCount: 0, maxReviewRetriesPerPlan: undefined, maxReviewRetriesPerWorkflow: undefined, lastReviewFailure: undefined, lastReviewAttempt: undefined, lastReviewRepairStatus: "none", reviewHistory: undefined, reviewRepairInProgress: undefined, repairRetryState: undefined, executionSummary: undefined, validationReport: undefined, validationVerdict: undefined, clarifyingQuestions: undefined, clarifyingAnswers: undefined, clarificationAlreadyAsked: undefined, clarificationRequiredBeforePlan: undefined, clarificationRequirementReason: undefined, clarificationSkipReason: undefined, clarificationQualityRetryCount: undefined, currentValidationRetry: 0, workflowValidationRetryCount: 0, maxValidationRetriesPerPlan: undefined, maxValidationRetriesPerWorkflow: undefined, lastValidationFailure: undefined, lastRepairAttempt: undefined, repairHistory: undefined, lastRepairStatus: "none", planStepValidationIndex: undefined, planRuntime: undefined, planProgress: undefined, planHistoryId: archivedId ?? state.planHistoryId, approvedPlanHistoryId: undefined, modelsUsed: undefined }, ctx);
13842
+ updateState({ mode: "awaiting_plan_input", activeMissionId: undefined, task: undefined, originalTask: undefined, draftPlan: undefined, approvedPlan: undefined, reviewerReport: undefined, reviewerVerdict: undefined, currentReviewRetry: 0, workflowReviewRetryCount: 0, maxReviewRetriesPerPlan: undefined, maxReviewRetriesPerWorkflow: undefined, lastReviewFailure: undefined, lastReviewAttempt: undefined, lastReviewRepairStatus: "none", reviewHistory: undefined, reviewRepairInProgress: undefined, repairRetryState: undefined, executionSummary: undefined, validationReport: undefined, validationVerdict: undefined, clarifyingQuestions: undefined, clarifyingAnswers: undefined, clarificationAlreadyAsked: undefined, clarificationRequiredBeforePlan: undefined, clarificationRequirementReason: undefined, clarificationSkipReason: undefined, clarificationQualityRetryCount: undefined, currentValidationRetry: 0, workflowValidationRetryCount: 0, maxValidationRetriesPerPlan: undefined, maxValidationRetriesPerWorkflow: undefined, lastValidationFailure: undefined, lastRepairAttempt: undefined, repairHistory: undefined, lastRepairStatus: "none", planStepValidationIndex: undefined, planExecutionStepIndex: undefined, planRuntime: undefined, planProgress: undefined, planHistoryId: archivedId ?? state.planHistoryId, approvedPlanHistoryId: undefined, modelsUsed: undefined }, ctx);
13808
13843
  setWorkflowUi(ctx, state, activeSubagents);
13809
13844
  show(pi, `# Plan Archived\n\n${archivedId ? `Archived Plan ID: ${archivedId}\n\n` : ""}Plan Mode is ready for a new planning request.`);
13810
13845
  }
@@ -13812,7 +13847,7 @@ Public workflow commands:
13812
13847
  async function startFreshPlanFromInput(ctx: ExtensionContext, task: string) {
13813
13848
  const archivedId = archiveCurrentPlanIfPresent(ctx, "previous plan archived before starting a new plan");
13814
13849
  activeMission = undefined;
13815
- updateState({ mode: "awaiting_plan_input", activeMissionId: undefined, task, originalTask: task, draftPlan: undefined, approvedPlan: undefined, clarifyingQuestions: undefined, clarifyingAnswers: undefined, clarificationAlreadyAsked: undefined, clarificationRequiredBeforePlan: undefined, clarificationRequirementReason: undefined, clarificationSkipReason: undefined, clarificationQualityRetryCount: undefined, planningDepth: undefined, clarificationMode: undefined, reviewerReport: undefined, reviewerVerdict: undefined, currentReviewRetry: 0, workflowReviewRetryCount: 0, maxReviewRetriesPerPlan: undefined, maxReviewRetriesPerWorkflow: undefined, lastReviewFailure: undefined, lastReviewAttempt: undefined, lastReviewRepairStatus: "none", reviewHistory: undefined, reviewRepairInProgress: undefined, repairRetryState: undefined, executionSummary: undefined, validationReport: undefined, validationVerdict: undefined, currentValidationRetry: 0, workflowValidationRetryCount: 0, maxValidationRetriesPerPlan: undefined, maxValidationRetriesPerWorkflow: undefined, lastValidationFailure: undefined, lastRepairAttempt: undefined, repairHistory: undefined, lastRepairStatus: "none", planStepValidationIndex: undefined, planRuntime: undefined, planProgress: undefined, lastCompletedPlanSummary: state.lastCompletedPlanSummary, modelsUsed: undefined, planHistoryId: undefined, approvedPlanHistoryId: undefined }, ctx);
13850
+ updateState({ mode: "awaiting_plan_input", activeMissionId: undefined, task, originalTask: task, draftPlan: undefined, approvedPlan: undefined, clarifyingQuestions: undefined, clarifyingAnswers: undefined, clarificationAlreadyAsked: undefined, clarificationRequiredBeforePlan: undefined, clarificationRequirementReason: undefined, clarificationSkipReason: undefined, clarificationQualityRetryCount: undefined, planningDepth: undefined, clarificationMode: undefined, reviewerReport: undefined, reviewerVerdict: undefined, currentReviewRetry: 0, workflowReviewRetryCount: 0, maxReviewRetriesPerPlan: undefined, maxReviewRetriesPerWorkflow: undefined, lastReviewFailure: undefined, lastReviewAttempt: undefined, lastReviewRepairStatus: "none", reviewHistory: undefined, reviewRepairInProgress: undefined, repairRetryState: undefined, executionSummary: undefined, validationReport: undefined, validationVerdict: undefined, currentValidationRetry: 0, workflowValidationRetryCount: 0, maxValidationRetriesPerPlan: undefined, maxValidationRetriesPerWorkflow: undefined, lastValidationFailure: undefined, lastRepairAttempt: undefined, repairHistory: undefined, lastRepairStatus: "none", planStepValidationIndex: undefined, planExecutionStepIndex: undefined, planRuntime: undefined, planProgress: undefined, lastCompletedPlanSummary: state.lastCompletedPlanSummary, modelsUsed: undefined, planHistoryId: undefined, approvedPlanHistoryId: undefined }, ctx);
13816
13851
  if (archivedId) recordWorkflowInternalEvent(ctx, `Previous plan archived: ${archivedId}`);
13817
13852
  await beginPlanning(ctx, task);
13818
13853
  }
@@ -14571,14 +14606,24 @@ Public workflow commands:
14571
14606
  applyPlanProgressMarkers(ctx, text);
14572
14607
  const allTrackedStepsCompleted = planProgressAllStepsCompleted(state);
14573
14608
  if (!allTrackedStepsCompleted && blockIfForcedSubagentsMissing(ctx, "Execution")) {
14574
- updateState({ mode: "plan_approved", executionSummary: text, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "validated" }, settings, { lifecycleStatus: "blocked", nextAction: "execution blocked by forced sub-agent policy" }) : state.planProgress }, ctx);
14609
+ const reason = "Execution stopped before all approved Plan steps were tracked and the forced execution worker requirement was not satisfied.";
14610
+ updateState({ mode: "validated", executionSummary: text, validationReport: reason, validationVerdict: "UNKNOWN", planExecutionStepIndex: undefined, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "validated", validationVerdict: "UNKNOWN" }, settings, { lifecycleStatus: "blocked", validationStatus: "unknown", nextAction: "fix execution progress/sub-agent blocker then /plan continue" }) : state.planProgress }, ctx);
14611
+ queuePlanTerminalSummary(ctx, "blocked", "Plan execution blocked", { validationText: reason, verdict: "UNKNOWN", reason });
14612
+ return;
14613
+ }
14614
+ if (!allTrackedStepsCompleted && settings.workflow.validateAfterEachStep !== true && settings.workflow.requireApprovalPerStep !== true && workflowPlanProgressEnabled(settings) && state.planProgress?.steps.length) {
14615
+ const reason = "Execution summary ended without workflow_progress markers or workflow_execution_result completedSteps for every approved Plan step.";
14616
+ updateState({ mode: "validated", executionSummary: text, validationReport: reason, validationVerdict: "UNKNOWN", planExecutionStepIndex: undefined, planProgress: mergePlanProgress({ ...state, mode: "validated", validationVerdict: "UNKNOWN" }, settings, { lifecycleStatus: "blocked", validationStatus: "unknown", nextAction: "submit corrected workflow_execution_result or rerun /plan continue" }) }, ctx);
14617
+ queuePlanTerminalSummary(ctx, "blocked", "Plan execution progress missing", { validationText: reason, verdict: "UNKNOWN", reason });
14618
+ queueAgentTurn(pi, `The Plan execution summary was not accepted because approved Plan step progress was incomplete. Do not redo work or edit files. Submit a corrected workflow_execution_result now with status, completedSteps for every approved Plan step completed, changedFiles, commands, blockers, and summary. Reason: ${reason}`, "workflow-execution-progress-correction");
14575
14619
  return;
14576
14620
  }
14577
14621
  const stepValidationEnabled = settings.workflow.validateAfterEachStep === true;
14578
14622
  const stepApprovalEnabled = settings.workflow.requireApprovalPerStep === true;
14579
- const stepValidationIndex = stepValidationEnabled ? state.planProgress?.currentStepIndex ?? 0 : undefined;
14623
+ const executedStepIndex = typeof state.planExecutionStepIndex === "number" ? state.planExecutionStepIndex : state.planProgress?.currentStepIndex ?? 0;
14624
+ const stepValidationIndex = stepValidationEnabled ? executedStepIndex : undefined;
14580
14625
  const validationGateActive = planValidationGateActive(settings);
14581
- updateState({ mode: "executed", executionSummary: text, planStepValidationIndex: stepValidationIndex, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "executed" }, settings, { lifecycleStatus: "executing", nextAction: validationGateActive ? "validator" : "finish workflow" }) : state.planProgress }, ctx);
14626
+ updateState({ mode: "executed", executionSummary: text, planStepValidationIndex: stepValidationIndex, planExecutionStepIndex: undefined, planProgress: workflowPlanProgressEnabled(settings) ? mergePlanProgress({ ...state, mode: "executed" }, settings, { lifecycleStatus: "executing", nextAction: validationGateActive ? "validator" : "finish workflow" }) : state.planProgress }, ctx);
14582
14627
  const mission = isMissionWorkflowMode(state) ? activeMission ?? loadMissionState(state.activeMissionId ?? "latest") : undefined;
14583
14628
  if (mission?.status === "running") {
14584
14629
  const milestone = mission.milestones[mission.currentMilestoneIndex];
@@ -14708,6 +14753,7 @@ Public workflow commands:
14708
14753
  updateState({
14709
14754
  mode: "reviewed",
14710
14755
  planStepValidationIndex: undefined,
14756
+ planExecutionStepIndex: undefined,
14711
14757
  validationVerdict: undefined,
14712
14758
  planProgress: { ...progress, currentStepIndex: nextIndex, validationStatus: "pending", nextAction: "executor" },
14713
14759
  }, ctx);
@@ -14721,7 +14767,7 @@ Public workflow commands:
14721
14767
  });
14722
14768
  return;
14723
14769
  }
14724
- updateState({ planStepValidationIndex: undefined }, ctx);
14770
+ updateState({ planStepValidationIndex: undefined, planExecutionStepIndex: undefined }, ctx);
14725
14771
  if (returnToPlan) {
14726
14772
  deferWorkflowAction(pi, "complete plan workflow after step validation", () => completePlanWorkflow(ctx, text, verdict));
14727
14773
  } else {
@@ -204,7 +204,8 @@ export function formatAnswersForPlanner(questions: ClarificationQuestion[], answ
204
204
 
205
205
  export function planValidationStatusForVerdict(verdict: WorkflowState["validationVerdict"]): PlanValidationStatus {
206
206
  if (verdict === "PASS") return "pass";
207
- if (verdict === "UNKNOWN" || verdict === "PARTIAL PASS") return "unknown";
207
+ if (verdict === "PARTIAL PASS") return "partial pass";
208
+ if (verdict === "UNKNOWN") return "unknown";
208
209
  return "fail";
209
210
  }
210
211
 
@@ -93,7 +93,7 @@ export interface StandardRuntimeState {
93
93
 
94
94
  export type PlanLifecycleStatus = "planning" | "awaiting_clarification" | "plan_ready" | "approved" | "reviewing" | "executing" | "validating" | "repairing" | "revalidating" | "completed" | "blocked";
95
95
  export type PlanStepStatus = "pending" | "active" | "completed" | "failed" | "blocked" | "skipped";
96
- export type PlanValidationStatus = "pending" | "running" | "pass" | "fail" | "unknown";
96
+ export type PlanValidationStatus = "pending" | "running" | "pass" | "partial pass" | "fail" | "unknown";
97
97
 
98
98
  export interface PlanProgressStep {
99
99
  id: string;
@@ -235,6 +235,7 @@ export interface WorkflowState {
235
235
  repairHistory?: WorkflowRepairHistoryEntry[];
236
236
  lastRepairStatus?: "none" | "running" | "completed" | "failed" | "blocked";
237
237
  planStepValidationIndex?: number;
238
+ planExecutionStepIndex?: number;
238
239
  planRuntime?: PlanRuntimeState;
239
240
  planProgress?: PlanProgressState;
240
241
  standardRuntime?: StandardRuntimeState;