## Summary
- Add explicit `sourceMetadata.externalReviewCheckout` review routing
with fail-closed validation.
- Log the selected review checkout so operator/runtime tasks can verify
where review ran.
- Cover metadata extraction, invalid metadata fallback,
`fn_review_step`, and workflow `stepReview` routing.
## Test Plan
- `cd packages/engine && corepack pnpm exec vitest run
src/__tests__/review-checkout.test.ts
src/__tests__/reviewer-workspace.test.ts`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Review routing now supports explicit external checkout overrides via
review checkout metadata, using the resolved external checkout as the
review working directory when valid.
* Logging now highlights the selected review routing target and warns
when external checkout metadata is present but invalid.
* **Bug Fixes**
* Missing/blank/invalid/relative/nonexistent/non-git paths now fail
closed to the task worktree instead of falling back.
* Metadata priority is enforced strictly (custom fields → branch context
→ source metadata → root), preventing lower-priority fallback when
higher-priority data is invalid.
* **Tests**
* Added/expanded automated coverage for override and fail-closed
behavior, including workspace-mode routing semantics.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Problem
Claude **subscription** (Max/Pro) chats fail with a rotating `404 / 502
/ 429` cascade — the same symptom as #1857, which was reported fixed.
Raw `ANTHROPIC_API_KEY` and explicit Claude CLI usage work; direct OAuth
does not.
## Root cause (proven against git history)
- **v0.51.0 (worked):** `packages/core/src/anthropic-models.ts` didn't
exist. `getApiKey("anthropic")` returned the subscription **OAuth**
access token and pi-ai's built-in `anthropic` provider POSTed it to
`api.anthropic.com/v1` with **Claude Code identity headers** (`Bearer` +
`anthropic-beta: claude-code-20250219,oauth-2025-04-20`). Direct OAuth
worked — **not** via the CLI.
- **The regression chain:** #1857 mis-concluded "0.51.0 uses the CLI /
OAuth is blocked on /v1" (its `grep` missed the runtime-appended `/v1`;
a naive curl repro lacked pi-ai's full impersonation). FN-7291 → FN-7391
→ FN-7396 were built on that wrong premise. FN-7396's
`registerAnthropicSubscriptionProvider` rerouted subscription OAuth to a
new `anthropic-subscription` provider **still pointed at
`api.anthropic.com/v1`** — reintroducing #1857.
## Fix — restore the v0.51.0 path (three independent surfaces, no
rerouting)
- **`auth-storage.ts`** — `getApiKey("anthropic")` resolves
subscription/legacy OAuth again (raw API key still takes precedence), so
the built-in provider receives the token.
- **`pi.ts`** — remove the runtime reroute and the `/v1`-based
`anthropic-subscription` execution provider; `anthropic/*` selections
stay on the built-in OAuth-capable provider.
- **`register-model-routes.ts`** — advertise `anthropic` in the picker
for OAuth users so direct OAuth is selectable.
- Result: **direct OAuth**, **raw `ANTHROPIC_API_KEY`** (precedence),
and **explicit `pi-claude-cli`** all work independently.
## Verification
- `packages/engine`: `auth-storage.test.ts` +
`pi-create-fn-agent.test.ts` — **137 passed** (assertions restored to
the correct invariant; the FN-7391/FN-7396 tests encoded the bug).
- `packages/dashboard`: `routes-auth.test.ts` + `usage.test.ts` — **352
passed**.
- `pnpm --filter @fusion/engine build` clean.
- Docs (`settings-reference.md`, `dashboard-guide.md`) + changeset
updated.
Fixes#1857🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Restored Anthropic Claude subscription chat reliability by reverting
the OAuth execution behavior to the expected direct runtime flow.
* Improved Anthropic credential precedence and provider visibility
across direct API key, subscription OAuth, and Claude CLI modes.
* Reinstated Claude Sonnet 5 in the model picker with correct
catalog/pricing.
* **Documentation**
* Updated the OAuth re-login banner guide and settings reference to
clarify Anthropic credential behavior and precedence.
* **Tests**
* Updated authentication, model discovery, session routing, and pricing
expectations for Anthropic scenarios.
* **Chores**
* Tightened peer dependency version constraints for the Claude CLI
package.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The vendored pi-claude-cli extension declared `@earendil-works/pi-ai` and
`pi-coding-agent` as `*` peers, so its dev/workspace resolution drifted to
0.77.0 while the rest of the workspace is on ^0.80.3. Pin both peers to
^0.80.3 so the extension's `getModels("anthropic")` catalog (which feeds the
pi-claude-cli picker rows) matches the engine/cli — 0.80.3 ships
claude-sonnet-5 natively. Behavior-preserving; the bundled CLI already
provided 0.80.3 at runtime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sonnet 5 had disappeared from every surface: pi-ai 0.79.9 (the installed
version) lacks it, and FN-7374 removed the static row expecting the live
registry to carry it. Live-verified that claude-sonnet-5 returns 200 on
api.anthropic.com/v1 with a raw ANTHROPIC_API_KEY and runs via the Claude
CLI (it 403s on subscription-OAuth /v1 — scope-gated; runtime fallback
applies). Note: pi-ai 0.80.3 ships sonnet-5 natively, so this SUPPLEMENTAL
row dedupes once the install catches up.
- core: re-add claude-sonnet-5 to SUPPLEMENTAL_ANTHROPIC_PROVIDER_REGISTRATION
and restore its static pricing (revert FN-7374); update pricing tests.
- engine/dashboard tests: flip the FN-7374 "withheld" assertions to the
restored "advertised" behavior.
PR feedback:
- Trim the two FNXC comments (auth-storage.ts, pi.ts) to concise
requirement prose per coding guidelines (CodeRabbit).
- Replace the now-inert getApiKey mock in two subscription routing tests
with a clarifying note (Greptile).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude subscription (Max/Pro) chats regressed to 404/502/429 because
FN-7396 rerouted subscription OAuth to a /v1-based `anthropic-subscription`
runtime provider — reintroducing issue #1857 that FN-7391 had fixed. Both
routed the OAuth token to api.anthropic.com/v1, the surface that broke.
Proven in code that v0.51.0 (working) sent subscription OAuth directly to
/v1 via pi-ai's built-in `anthropic` provider (Claude Code impersonation:
Bearer + anthropic-beta oauth headers), NOT through the CLI. Restore that:
- auth-storage: getApiKey("anthropic") resolves subscription/legacy OAuth
again (raw API key still wins), so the built-in provider gets the token.
- pi.ts: remove the runtime reroute and the /v1 `anthropic-subscription`
execution provider so anthropic/* selections stay on the built-in provider.
- register-model-routes: advertise `anthropic` for OAuth users so direct
OAuth is selectable in the picker.
Three independent surfaces, no rerouting: direct OAuth, raw ANTHROPIC_API_KEY
(precedence), and explicit pi-claude-cli.
Fixes#1857
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep Claude Sonnet 5 visible only through eligible provider catalogs without duplicate picker rows.
- Dedupe API model rows by provider/model after registry and supplemental catalog merges.
- Cover Claude CLI Sonnet 5 visibility, disabled-toggle filtering, and duplicate suppression in API tests.
- Add dropdown coverage for stale direct-Anthropic favorite shells when Claude CLI Sonnet 5 is selected.
- Add a patch changeset for the model picker fix.
Files changed:
.changeset/fn-7389-sonnet-5-model-list.md | 7 +++++
.../__tests__/CustomModelDropdown.test.tsx | 33 ++++++++++++++++++++++
.../dashboard/src/__tests__/routes-auth.test.ts | 15 ++++++++--
.../dashboard/src/routes/register-model-routes.ts | 12 ++++++++
4 files changed, 65 insertions(+), 2 deletions(-)
Fusion-Task-Id: FN-7389
Fusion-Task-Lineage: d41b422e-60f9-46c3-9c6f-d115a86e9e2a
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Keep Anthropic OAuth subscription credentials away from the direct /v1 provider while preserving raw API-key routing.
- Treat direct anthropic auth as raw API-key-only in auth storage and model discovery.
- Re-route persisted anthropic model selections to the Claude CLI provider when no raw Anthropic API key is configured.
- Add regression coverage for OAuth-only routing, raw API-key preservation, and provider list separation.
- Document the distinct raw API key, OAuth subscription, and Claude CLI routes.
Files changed:
.../fn-7391-anthropic-subscription-cli-routing.md | 7 ++
docs/settings-reference.md | 2 +-
.../dashboard/src/__tests__/routes-auth.test.ts | 74 ++++++++++++++
.../dashboard/src/routes/register-model-routes.ts | 27 +++++-
packages/engine/src/__tests__/auth-storage.test.ts | 108 +++++++--------------
.../src/__tests__/pi-create-fn-agent.test.ts | 100 +++++++++++++++++++
packages/engine/src/auth-storage.ts | 45 ++++-----
packages/engine/src/pi.ts | 61 ++++++++++++
8 files changed, 319 insertions(+), 105 deletions(-)
Fusion-Task-Id: FN-7391
Fusion-Task-Lineage: d1fecc2d-7f31-408c-bf65-0e65b7fd88b1
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
## Summary
- add an opt-in `allowAnswerQuestionIdDrift` flag for interactive AI
sessions
- keep strict question-id validation by default
- enable the tolerance only for Compound Engineering recovered sessions
so persisted session rows can answer after dashboard
restarts/non-deterministic rehydration
## Test Plan
- `corepack pnpm --filter @fusion/engine exec vitest run
src/__tests__/interactive-ai-session.test.ts --silent=passed-only
--reporter=dot`
- `corepack pnpm --filter @fusion/engine typecheck`
- `corepack pnpm --filter @fusion-plugin-examples/compound-engineering
build`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved interactive session recovery so persisted answers can
continue after dashboard restarts, even if the question ID changes
during rehydration.
* Keeps strict question-ID validation by default; mismatches still fail
unless drift is explicitly allowed.
* **New Features**
* Added `allowAnswerQuestionIdDrift` option to permit accepting the
persisted question ID during recovered session answering.
* **Tests**
* Added/updated coverage for strict mismatch error behavior and the
successful completion path when drift is enabled.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
The step execution engine was already gone (runWorkflowSteps deleted,
workflow_steps table dropped in migration 132). This removes what remained:
the linear step compiler (compileWorkflowToSteps/validateLinearity/
WorkflowCompileError), which survived only as a validator + step-preview
generator.
parseWorkflowIr/validateV2 (which accepts branching graphs) is now the sole
workflow validity gate at save/select/refine and in the graph task runner.
Custom branching workflows are now selectable and run on the graph
interpreter instead of being rejected as non-linear.
- core: delete workflow-compiler.ts; rework store.validateWorkflowCompilable
onto parseWorkflowIr; move MERGE_REGION_NODE_KINDS into
workflow-lifecycle-validation; retag workflow-steps-to-ir as legacy lowering
- engine: drop the compiler double-validation in workflow-graph-task-runner
- dashboard: remove POST /api/workflows/:id/compile + client wrapper; drop the
interpreterOnly response field and editor banner; no post-save compile check
- i18n: remove the orphaned workflowNodes.interpreterOnly key across locales
- tests: reframe two workflow-selection tests whose premise inverted; fix a
pre-existing red in builtin-lead-generation (completion-summary node)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task context menus now place destructive actions after safer task operations.
- Reorder shared task action descriptors so Reset and Delete render at the bottom, with Delete last.
- Update context-menu model coverage for lifecycle, GitHub tracking, pause, and workflow column states.
- Add a patch changeset for the published Fusion CLI package.
Files changed:
.changeset/fn-7387-context-menu-action-order.md | 7 ++++++
.../dashboard/app/components/TaskContextMenu.tsx | 24 +++++++++++--------
.../components/__tests__/TaskContextMenu.test.tsx | 27 +++++++++++++---------
3 files changed, 38 insertions(+), 20 deletions(-)
Fusion-Task-Id: FN-7387
Fusion-Task-Lineage: f320ed96-d5e7-48f4-9151-59357ae12de7
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Hide failed-task alert chrome while the task planner chat is maximized.
- Gate the failed-task banner on Planner Chat expansion state so the expanded conversation gets the full detail surface.\n- Preserve failed-banner visibility for normal detail, collapsed Planner Chat, and expanded Activity views.\n- Add dashboard regression coverage and a patch changeset for the published CLI package.\n\nFiles changed:\n .changeset/fn-7377-planner-chat-failed-banner.md | 7 ++\n .../dashboard/app/components/TaskDetailModal.tsx | 7 +-\n .../components/__tests__/TaskDetailModal.test.tsx | 101 +++++++++++++++++++++\n 3 files changed, 114 insertions(+), 1 deletion(-)
Fusion-Task-Id: FN-7377
Fusion-Task-Lineage: 5cd8c846-a27d-4040-8124-ecf547300c78
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Planning Mode confirm prompts can now preserve a user-authored Other answer instead of forcing Yes or No.
- Add an Other option with a textarea to confirm-style Planning Mode questions.
- Submit confirm Other answers with the shared `_other` payload and render them in agent/history formatting.
- Cover confirm Other behavior in modal flow and formatter tests.
- Add a patch changeset for the published CLI package.
Files changed:
.changeset/fn-7369-confirm-other.md | 7 ++
.../dashboard/app/components/PlanningModeModal.css | 10 ++
.../dashboard/app/components/PlanningModeModal.tsx | 74 +++++++++---
.../PlanningModeModal.planning-flow.test.tsx | 125 +++++++++++++++++++++
.../planning-interview-formatters.test.ts | 27 +++++
packages/dashboard/src/planning.ts | 10 +-
6 files changed, 234 insertions(+), 19 deletions(-)
Fusion-Task-Id: FN-7369
Fusion-Task-Lineage: 67b4d943-8ff3-4502-bca1-7e74eb95ac06
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Keep the task Activity view selector visible without blanking the mobile tab strip.
- Portal the Activity view menu to the document body and clamp its fixed position to the visual viewport.
- Close and refocus the menu safely across task changes, scrolling, resizing, keyboard selection, and outside clicks.
- Add regression coverage for mobile clipping, tab-strip preservation, and the changeset release note.
Files changed:
.changeset/fn-7375-activity-dropdown-overlay.md | 7 +
.../dashboard/app/components/TaskDetailModal.css | 15 +-
.../dashboard/app/components/TaskDetailModal.tsx | 186 ++++++++++++++++++---
.../__tests__/TaskDetailModal.css.test.ts | 7 +-
...etailModal.responsive-and-dependencies.test.tsx | 12 +-
.../TaskDetailModal.task-activity-chat.test.tsx | 61 +++++++
6 files changed, 254 insertions(+), 34 deletions(-)
Fusion-Task-Id: FN-7375
Fusion-Task-Lineage: 5999507a-edd3-4485-935a-885f7c143ed4
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Planner chat now resumes active generations when task detail is reopened.\n\n- Rehydrate in-flight planner chat snapshots and reattach to the session stream after tab/modal remounts.\n- Preserve accepted optimistic user turns across provider failures while rolling back pre-acceptance failures.\n- Add regression coverage for remount reattachment, attached completion/error refresh, and accepted error reconciliation.\n- Add a patch changeset for the published Fusion package.\n\nFiles changed:\n .changeset/fn-7366-planner-chat-resume.md | 7 +\n .../app/components/TaskPlannerChatTab.tsx | 334 +++++++++++++--------\n .../__tests__/TaskPlannerChatTab.test.tsx | 189 +++++++++++-\n 3 files changed, 382 insertions(+), 148 deletions(-)
Fusion-Task-Id: FN-7366
Fusion-Task-Lineage: b13b9c5e-9295-461f-b44b-f2b5a9008b4f
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Auto-merge finalization now ignores stale branch-only residue once durable merge proof exists, so squash-landed tasks do not stay stuck in review because their task branch history is noisy.
Fusion-Task-Id: FN-7360