Skip to content

fix(server): surface CLI resume command in web approve/reject responses#1523

Merged
Wirasm merged 1 commit into
coleam00:devfrom
blankse:fix/1522-non-web-parent-reject-resume-messaging
May 26, 2026
Merged

fix(server): surface CLI resume command in web approve/reject responses#1523
Wirasm merged 1 commit into
coleam00:devfrom
blankse:fix/1522-non-web-parent-reject-resume-messaging

Conversation

@blankse
Copy link
Copy Markdown
Contributor

@blankse blankse commented May 1, 2026

Summary

  • Problem: When a workflow run is approved/rejected via the Web UI but tryAutoResumeAfterGate skips dispatch — because there is no parent_conversation_id, the parent conversation is gone, or the parent sits on a non-web platform (Slack/Telegram/GitHub/CLI) — the success message said only "Send a message to continue" / "On-reject prompt will run on resume". A web-UI user whose run originated from a terminal has no obvious next step from that text; the run sits in failed status with metadata.rejection_reason populated and the user has to read the DB schema to discover archon workflow resume <id> exists.
  • Why it matters: Reproduced locally with a CLI-started run that was then rejected from the dashboard. Recovery required reading source.
  • What changed: Both approve and reject (on_reject branch) now include the exact archon workflow resume <runId> command in the non-auto-resumed response. The auto-resume happy path is unchanged.
  • What did NOT change: Dispatch decision logic, the parent_conversation_id-based cross-adapter guard, log events, DB writes, and the no-on_reject cancellation path are byte-identical. The Resume endpoint's CLI hints (/api/workflows/runs/:runId/resume) are covered by fix(server,web,workflows): web approval gates auto-resume + reject-with-reason dialog #1329 and are not touched here.

Scope History

This PR was rebased after #1329 (web approval auto-resume + cross-adapter guard) and #1646 (explicit resume pipeline) merged into dev. Both eliminated the original PR's larger surface (discriminated-union refactor of tryAutoResumeAfterGate and Resume-endpoint hint additions). Scope reduced on rebase to only the gate-time messaging delta that remains uncovered.

Linked Issue

Validation Evidence

bun x prettier --check packages/server/src/routes/{api.ts,api.workflow-runs.test.ts}
# All matched files use Prettier code style

bun x eslint --max-warnings 0 --no-warn-ignored \
  packages/server/src/routes/api.ts packages/server/src/routes/api.workflow-runs.test.ts
# clean

bun --filter @archon/server test packages/server/src/routes/api.workflow-runs.test.ts
# 14/14 pass (one new regression test for reject + on_reject + non-web parent)

The four pre-existing approve auto-resume-skipped tests had their substring assertion updated from "Send a message to continue" to "archon workflow resume run-paused-1". One new test covers the symmetric reject case (on_reject + non-web parent).

Security Impact

  • New permissions/capabilities? No.
  • New external network calls? No.
  • Secrets/tokens handling changed? No.
  • File system access scope changed? No.

Compatibility / Migration

  • Backward compatible? Yes — response shape unchanged, only the human-readable message text differs in the non-auto-resumed branches.
  • Config/env changes? No.
  • Database migration needed? No.

Rollback Plan

  • Fast rollback: revert this commit. Two files, ~40 lines net.
  • Feature flags: none.
  • Observable failure symptom on rollback: web-UI users seeing the old vague text again — the auto-resume happy path is unaffected.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Resume endpoints now explain when auto-resume was skipped (missing parent, deleted parent, or non-web parent) and include a clear CLI fallback hint: archon workflow resume . Wording differs for approve vs. reject flows (approve suggests CLI or replying in the original conversation; reject clarifies the on-reject prompt will run when resumed).
  • Tests
    • Tests updated to assert the explicit CLI hints and added a reject-case covering non-web parent scenarios.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 09ee2f61-8345-4e6d-94e1-eef270ec5641

📥 Commits

Reviewing files that changed from the base of the PR and between ae3a75b and b32dce3.

📒 Files selected for processing (2)
  • packages/server/src/routes/api.ts
  • packages/server/src/routes/api.workflow-runs.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/server/src/routes/api.ts

📝 Walkthrough

Walkthrough

Approve and reject handlers now return explicit CLI instructions (archon workflow resume <runId>) in success messages when auto-resume is not dispatched. Tests were updated to assert those CLI hints for approve skip cases and a new reject skip case (non-web parent).

Changes

Approve/Reject CLI hint & tests

Layer / File(s) Summary
Approve/reject success message edits
packages/server/src/routes/api.ts
Replaces generic “auto-resume did not occur” response strings with messages that include the explicit archon workflow resume <runId> CLI command and appropriate alternate instructions (approve: CLI or send message in originating conversation; reject: CLI to trigger on-reject prompt on resume).
Endpoint tests updated/added
packages/server/src/routes/api.workflow-runs.test.ts
Updated three approve tests to expect archon workflow resume run-paused-1 when dispatch is skipped; added a reject test asserting archon workflow resume run-reject-non-web for non-web parent runs and verifying no dispatch occurs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #1350 — Micro-polish to tryAutoResumeAfterGate and related messaging; this PR touches the same auto-resume/messaging surface.

Possibly related PRs

  • coleam00/Archon#1329 — Modifies the same approve/reject auto-resume control flow and message assertions in packages/server/src/routes/api.ts.

🐰
I hopped a hint into the paused run's nook,
a tiny CLI carrot for anyone to look.
No more silence when the gate stays tight —
"archon workflow resume" brings back the light.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: surfacing CLI resume commands in web-UI approve/reject response messages.
Description check ✅ Passed The PR description follows the template structure with clear problem statement, rationale, scope boundaries, validation evidence, security/compatibility confirmations, and rollback plan; all required sections are present and substantive.
Linked Issues check ✅ Passed The PR fully addresses #1522 by replacing vague non-resume messages with explicit 'archon workflow resume ' commands in approve/reject routes, covering all four non-resumed branches and both code paths.
Out of Scope Changes check ✅ Passed All changes are scoped to API-layer messaging updates in approve/reject handlers and corresponding tests; Web UI surface changes and dispatch logic remain untouched as intended.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/server/src/routes/api.ts (1)

1151-1167: ⚡ Quick win

Add exhaustive default guard to the switch to prevent silent undefined on future union extension.

All four current members of reason are handled, but without a default: never branch the function will return undefined at runtime if the union is extended — TypeScript only catches this reliably when noImplicitReturns: true is active in tsconfig.

✅ Proposed fix
     case 'dispatch_failed':
       return `Auto-resume dispatch failed. Run ${cliCommand} from a terminal to ${verb}.`;
+    default: {
+      // Exhaustive check — forces a compile error if the union grows without a matching case.
+      const _exhaustive: never = reason;
+      return `Run ${cliCommand} from a terminal to ${verb}.`;
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/server/src/routes/api.ts` around lines 1151 - 1167, The switch over
the variable `reason` currently handles four cases but lacks an exhaustive
`default`, which can lead to returning undefined if the `reason` union is
extended; modify the switch (the block that references `reason`, `cliCommand`,
and `verb`) to include a `default` branch that enforces exhaustiveness—e.g.,
assign `reason` to a `never`-typed variable or call a shared
`assertUnreachable(reason)` helper and then throw a clear Error (or return a
safe fallback message) so the compiler/runtime will catch any future unknown
`reason` values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/server/src/routes/api.ts`:
- Around line 1151-1167: The switch over the variable `reason` currently handles
four cases but lacks an exhaustive `default`, which can lead to returning
undefined if the `reason` union is extended; modify the switch (the block that
references `reason`, `cliCommand`, and `verb`) to include a `default` branch
that enforces exhaustiveness—e.g., assign `reason` to a `never`-typed variable
or call a shared `assertUnreachable(reason)` helper and then throw a clear Error
(or return a safe fallback message) so the compiler/runtime will catch any
future unknown `reason` values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f57de0a2-6e16-4a15-b160-e59c374f7ec8

📥 Commits

Reviewing files that changed from the base of the PR and between 69b2c89 and 3374fc0.

📒 Files selected for processing (2)
  • packages/server/src/routes/api.ts
  • packages/server/src/routes/api.workflow-runs.test.ts

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 4, 2026

@blankse related to #1522 — non-web resume messaging.

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 4, 2026

Review Summary

Verdict: ready-to-merge

This PR replaces the boolean return from tryAutoResumeAfterGate with a discriminated AutoResumeResult union, so the web UI can surface actionable CLI commands when approve/reject can't auto-resume a workflow run. Four branches (no parent, no platform conv, non-web parent, dispatch failed) all now give users the exact archon workflow resume <id> command to proceed. Tests cover every branch. Clean, focused fix.

Minor / nice-to-have (2 items — both style-only, non-blocking)

  • packages/server/src/routes/api.ts:1131: "instead of vague text" frames the old behavior negatively. Prefer neutral wording: "so the user gets an actionable next step."
  • packages/server/src/routes/api.ts:1593–1598: The multi-line ----- decorative border with issue number #1522 is rot-prone. Replace with a single comment: // Four non-resumed reject branches — mirrors approve tests for on_reject path.

Compliments

  • The manualResumeMessage helper with a type-exhaustive switch is a clean pattern — it avoids runtime fallback risk while keeping the code readable.
  • The comment at lines 1073–1075 explaining why literal event names are used (grepability for ops tooling) is exactly the kind of non-obvious WHY that prevents future churn.
  • Test coverage is thorough: all 4 non-resumed branches × 2 actions are exercised, including the dispatch-failed catch path.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality.

@blankse
Copy link
Copy Markdown
Contributor Author

blankse commented May 12, 2026

Rebased onto current dev (commit 21cd3ad0). This PR extends the tryAutoResumeAfterGate helper that landed in #1329 — converts its boolean return into a structured AutoResumeResult discriminated union and adds a manualResumeMessage() helper for tailored next-step hints per skip reason (no_parent, non_web_parent, no_platform_conv, dispatch_failed).

The rebase was clean (no merge conflicts) — tryAutoResumeAfterGate was untouched on dev since #1329 merged. Type-check + all api.workflow-runs.test.ts tests green.

@blankse blankse force-pushed the fix/1522-non-web-parent-reject-resume-messaging branch from 21cd3ad to ae3a75b Compare May 14, 2026 12:06
@blankse blankse changed the title fix(server): explicit manual-resume hint when web UI rejects/approves a non-web-parent run fix(server): surface CLI resume command in web approve/reject responses May 14, 2026
When a workflow run is approved/rejected via the Web UI but
`tryAutoResumeAfterGate` cannot auto-resume — because there is no
`parent_conversation_id`, the parent conversation is gone, or the parent
sits on a non-web platform (Slack/Telegram/GitHub/CLI) — the success
message said only "Send a message to continue" / "On-reject prompt will
run on resume". A web-UI user whose run originated from a terminal has
no obvious next step from that text and the run sits in `failed` status.

Both approve and reject (on_reject branch) now include the exact
`archon workflow resume <runId>` command in the non-auto-resumed
response, so the web-UI surface always carries an actionable next step.

The auto-resume happy path and the no-on_reject cancellation path are
unchanged. The Resume endpoint's CLI hints (covered by coleam00#1329) are not
touched.

Closes coleam00#1522.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@blankse blankse force-pushed the fix/1522-non-web-parent-reject-resume-messaging branch from ae3a75b to b32dce3 Compare May 21, 2026 12:19
@Wirasm Wirasm merged commit f83d1f8 into coleam00:dev May 26, 2026
4 checks passed
@blankse blankse deleted the fix/1522-non-web-parent-reject-resume-messaging branch May 26, 2026 06:10
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.

bug(web): Reject + Resume buttons dead-end silently for non-web-parent runs

2 participants