Skip to content

feat(workflow): add fn_workflow_step_resume operator escape hatch for stuck pending merge-review steps - #3339

Open
ischindl wants to merge 4 commits into
Runfusion:mainfrom
ischindl:pr/stas-032-resume-workflow-step
Open

feat(workflow): add fn_workflow_step_resume operator escape hatch for stuck pending merge-review steps#3339
ischindl wants to merge 4 commits into
Runfusion:mainfrom
ischindl:pr/stas-032-resume-workflow-step

Conversation

@ischindl

@ischindl ischindl commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an operator-only escape hatch for a card stranded in-review (or in-progress) with a workflow step permanently stuck in pending status — the leading real-world cause being a dispatched prompt node (e.g. code-review) whose verdict callback was never received (see #1946). Transitions the stuck pending pre-merge step to status: "failed" with resume audit metadata, so the existing fn_task_bypass_review escape hatch can then clear the merge blocker.

What changed

  • WorkflowStepResult gains resume audit fields: resumedBy, resumedAt, resumeReason, resumedFromStatus. They are pure audit trail and do not participate in merge-blocking (getTaskMergeBlocker).
  • findPendingPreMergeStep (new helper, exported from @fusion/core) summarizes the stuck-pending pre-merge state for operator tooling. Ignores post-merge steps; returns the newest pending pre-merge result.
  • TaskStore.resumeWorkflowStep(id, { stepId, reason, actor }) — the store primitive (eligibility-gated: task must be in-review/in-progress, not paused; step must exist and be pending; a mandatory non-blank reason and stepId are required). Runs under withTaskLock, writes the resume as a terminal failed result, appends a task-log breadcrumb, and emits the new task:resume-step run-audit event.
  • fn_workflow_step_resume — new CLI/pi-extension tool registered only on the operator surface (deliberately not wired into executor/reviewer/triage agent tool lists). Accepts { id, stepId, reason }; the actor defaults to cli-operator.
  • Run-audit: new task:resume-step DatabaseMutationType member.

Why

A prompt-node verdict callback can be lost (dispatched prompt never receives a verdict), leaving the step pending forever. Previously the only recourse was fn_task_bypass_review, which requires a terminal failed pre-merge step to clear the blocker — a permanently pending step could not be bypassed. This PR bridges that gap: resume (pending → failed) then bypass (failed merge-blocker cleared).

Verification

  • Typecheck: @fusion/core, @fusion/engine, @runfusion/fusion all clean.
  • task-merge-bypass.test.ts: 15/15 pass (incl. 5 new findPendingPreMergeStep cases).
  • store-resume-step.test.ts (new, PG-backed): 9/9 pass — eligibility gating, resume rewrite + audit fields, run-audit event, non-pending/non-found/blank-argument rejection, in-progress column support, property preservation.
  • extension.test.ts: 75/75 pass (expected-tool registration includes the new tool).

Files

  • packages/core/src/types/workflow/workflow-steps.ts
  • packages/core/src/merge/task-merge.ts
  • packages/core/src/store.ts
  • packages/core/src/index.ts
  • packages/core/src/__tests__/store-resume-step.test.ts (new)
  • packages/core/src/__tests__/task-merge-bypass.test.ts
  • packages/engine/src/util/run-audit.ts
  • packages/cli/src/extension.ts
  • packages/cli/src/__tests__/extension.test.ts
  • .changeset/stas-032-resume-workflow-step.md (minor, feature)

Summary by CodeRabbit

  • New Features
    • Added an operator-only workflow recovery tool for permanently pending pre-merge steps.
    • Operators can mark eligible pending steps as failed by providing a required audit reason.
    • Recovery actions record operator details, timestamps, reasons, prior status, task logs, and audit events.
  • Bug Fixes
    • Improved selection of the latest pending pre-merge workflow step while excluding post-merge steps.
    • Added validation to prevent recovery of paused, invalid, or out-of-scope workflow steps.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4719dc25-62e9-4aa1-845a-4320abfad2e1

📥 Commits

Reviewing files that changed from the base of the PR and between 5532019 and 67ab7b3.

📒 Files selected for processing (10)
  • .changeset/stas-032-resume-workflow-step.md
  • packages/cli/src/__tests__/extension.test.ts
  • packages/cli/src/extension.ts
  • packages/core/src/__tests__/store-resume-step.test.ts
  • packages/core/src/__tests__/task-merge-bypass.test.ts
  • packages/core/src/index.ts
  • packages/core/src/merge/task-merge.ts
  • packages/core/src/store.ts
  • packages/core/src/types/workflow/workflow-steps.ts
  • packages/engine/src/util/run-audit.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/cli/src/tests/extension.test.ts
  • .changeset/stas-032-resume-workflow-step.md
  • packages/core/src/merge/task-merge.ts
  • packages/core/src/index.ts
  • packages/core/src/types/workflow/workflow-steps.ts
  • packages/core/src/tests/store-resume-step.test.ts
  • packages/engine/src/util/run-audit.ts
  • packages/core/src/store.ts
  • packages/core/src/tests/task-merge-bypass.test.ts

📝 Walkthrough

Walkthrough

This change adds the operator-only fn_workflow_step_resume tool. It validates and resumes eligible pending pre-merge steps by marking them failed, recording audit metadata, persisting the task, and emitting an update.

Changes

Workflow step resume

Layer / File(s) Summary
Step selection and audit contracts
packages/core/src/types/workflow/workflow-steps.ts, packages/core/src/merge/task-merge.ts, packages/core/src/index.ts, packages/core/src/__tests__/task-merge-bypass.test.ts
Adds resume audit fields and exports findPendingPreMergeStep, which selects the newest pending non-post-merge step.
Store recovery and persistence
packages/core/src/store.ts, packages/engine/src/util/run-audit.ts, packages/core/src/__tests__/store-resume-step.test.ts
Validates task and step eligibility, marks the step failed, clears lease fields, records metadata and audit data, persists the task, updates the cache, and emits task:updated.
Operator tool exposure and release
packages/cli/src/extension.ts, packages/cli/src/__tests__/extension.test.ts, .changeset/stas-032-resume-workflow-step.md
Adds the operator-only tool, structured success and error responses, registration coverage, and a changeset.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant fn_workflow_step_resume
  participant TaskStore
  participant RunAudit
  Operator->>fn_workflow_step_resume: Provide task ID, step ID, and reason
  fn_workflow_step_resume->>TaskStore: Call resumeWorkflowStep
  TaskStore->>TaskStore: Validate and mark pending step failed
  TaskStore->>RunAudit: Record task:resume-step
  TaskStore-->>fn_workflow_step_resume: Return updated task or error
  fn_workflow_step_resume-->>Operator: Return structured result
Loading

Possibly related PRs

Suggested reviewers: gsxdsm

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the new operator-only resume tool and its purpose of recovering stuck pending merge-review steps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/core/src/merge/task-merge.ts (1)

576-591: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Remove findPendingPreMergeStep if no production call site exists.

findPendingPreMergeStep, resumeWorkflowStep, and fn_workflow_step_resume are documented as operator-only and not exposed to executor/reviewer/triage agent surfaces, but there is no active production call site for this helper. If the helper is only tested as a unit, remove it from packages/core/src/index.ts to avoid exposing it as part of the public core API.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/merge/task-merge.ts` around lines 576 - 591, Remove
findPendingPreMergeStep and its export from packages/core/src/index.ts if it has
no active production callers, retaining only necessary test references. Do not
alter resumeWorkflowStep or fn_workflow_step_resume, which are unrelated context
symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/extension.ts`:
- Around line 2580-2632: The withheld-tool guard is missing from
fn_workflow_step_resume, allowing agent sessions to invoke this operator-only
tool. Add "fn_workflow_step_resume" to WITHHELD_FROM_AGENT_EXTENSION_TOOLS, call
denyWithheldToolForAgentPrincipal first in its execute method following
fn_task_bypass_review, and prefix the surrounding comment with the required
FNXC:<Area> <timestamp>: format.

In `@packages/core/src/store.ts`:
- Around line 1723-1727: Update resumeWorkflowStep to resolve the task’s
workflow IR and derive the review lane via
resolveReviewColumns/declaresAnyLifecycleTrait and the in-progress lane via
resolveNodeOverrideLanes or columnsWithFlag(ir, "countsTowardWip"), then
validate task.column against those resolved lanes instead of hardcoded literals.
Preserve the existing error behavior when the task matches neither resolved
lane.
- Around line 1746-1754: Update the resumed record construction in
resumeWorkflowStep to explicitly remove leaseOwner and leaseNodeId after
spreading target, alongside the existing terminal-state cleanup. Preserve the
resulting failed record’s other fields while ensuring no lease fields remain
when a pending step is resumed.
- Around line 1732-1743: The resumeWorkflowStep validation currently permits
pending post-merge results. Update the target lookup or validation in
resumeWorkflowStep so only pending pre-merge entries are accepted, while
preserving the existing errors for missing or non-pending workflow steps.

---

Nitpick comments:
In `@packages/core/src/merge/task-merge.ts`:
- Around line 576-591: Remove findPendingPreMergeStep and its export from
packages/core/src/index.ts if it has no active production callers, retaining
only necessary test references. Do not alter resumeWorkflowStep or
fn_workflow_step_resume, which are unrelated context symbols.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4c9e9aa-a7ff-4755-849f-16abddeeeec5

📥 Commits

Reviewing files that changed from the base of the PR and between 001bd2b and bad3e23.

📒 Files selected for processing (10)
  • .changeset/stas-032-resume-workflow-step.md
  • packages/cli/src/__tests__/extension.test.ts
  • packages/cli/src/extension.ts
  • packages/core/src/__tests__/store-resume-step.test.ts
  • packages/core/src/__tests__/task-merge-bypass.test.ts
  • packages/core/src/index.ts
  • packages/core/src/merge/task-merge.ts
  • packages/core/src/store.ts
  • packages/core/src/types/workflow/workflow-steps.ts
  • packages/engine/src/util/run-audit.ts

Comment thread packages/cli/src/extension.ts
Comment thread packages/core/src/store.ts Outdated
Comment thread packages/core/src/store.ts
Comment thread packages/core/src/store.ts
schindler and others added 2 commits August 6, 2026 21:06
…wStep operator escape hatch

Operator-only CLI/pi-extension escape hatch for in-review/in-progress tasks
with a workflow step permanently stuck in 'pending' status (Runfusion/
Fusion#1946 dispatched verdict callback never received). Transitions the
stuck pending step to 'failed' with resume audit metadata so the existing
fn_task_bypass_review escape hatch can clear the merge blocker.

- Add resume audit fields to WorkflowStepResult (resumedBy/resumedAt/
  resumeReason/resumedFromStatus)
- Add findPendingPreMergeStep helper to summarize the stuck-pending state
- Add TaskStore.resumeWorkflowStep primitive (eligibility-gated, lock-held,
  run-audit-logged via 'task:resume-step')
- Register fn_workflow_step_resume operator tool on the CLI/pi surface only
- Add engine 'task:resume-step' run-audit mutation type
- Add PG-backed store-resume-step tests + findPendingPreMergeStep unit tests
- Withhold fn_workflow_step_resume from agent sessions (WITHHELD_FROM_AGENT_EXTENSION_TOOLS
  + denyWithheldToolForAgentPrincipal guard in execute), FNXC comment on registration.
- Resolve review/WIP lanes from the task's workflow IR (resolveWorkflowIrForTask +
  resolveReviewColumns / declaresAnyLifecycleTrait + countsTowardWip) instead of hardcoded
  'in-review'/'in-progress' literals.
- Restrict resumable steps to pending PRE-MERGE steps only; findPendingPreMergeStep now has a
  production caller (named in the not-found error).
- Clear leaseOwner/leaseNodeId on the terminal 'failed' resumed result.
- Tests: post-merge rejection, lease cleanup, updated lane/not-found error regexes.
@ischindl
ischindl force-pushed the pr/stas-032-resume-workflow-step branch from bad3e23 to 67ab7b3 Compare August 6, 2026 19:09
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants