Show Activity Live reasoning immediately for active and review-stage tasks.
- Default thinking blocks open for in-progress and in-review tasks.
- Preserve collapsed, user-toggleable reasoning for all other task columns.
- Document behavior and cover default state and user collapse interactions.
Files changed:
.changeset/fn-8171-thinking-default-open.md | 7 ++++
docs/dashboard-guide.md | 2 +-
packages/dashboard/app/components/TaskChatTab.tsx | 20 +++++++---
.../app/components/__tests__/TaskChatTab.test.tsx | 43 ++++++++++++++++++++--
4 files changed, 63 insertions(+), 9 deletions(-)
Fusion-Task-Id: FN-8171
Fusion-Task-Lineage: 705d6ac8-0c43-47d3-84df-57e9ec55a3b5
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Make the mobile More sheet participate in navigation history so Back dismisses it before changing views.
- Register the open More sheet as a navigation modal and remove it on every close path
- Cover browser, native, gesture, keyboard, action, and provider-less dismissal flows
- Document mobile More-sheet Back behavior
Files changed:
docs/dashboard-guide.md | 2 +
packages/dashboard/app/components/MobileNavBar.tsx | 48 ++++--
.../__tests__/MobileNavBar.swipe-back.test.tsx | 190 +++++++++++++++++++++
3 files changed, 228 insertions(+), 12 deletions(-)
Fusion-Task-Id: FN-8168
Fusion-Task-Lineage: 1c5652db-5f27-4671-b4b7-676753ca4cd0
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Remove the residual mobile Feed right inset so task details use balanced body padding.
- Let the task-detail body provide the mobile right inset.
- Retain first-row clearance for overlay controls.
- Cover mobile Feed padding and attached tab behavior with regression tests.
- Add a patch changeset for the dashboard fix.
Files changed:
.../fn-8166-task-detail-mobile-right-padding.md | 7 +++
.../dashboard/app/components/TaskDetailModal.css | 8 +--
.../TaskDetailModal.attachments-and-tabs.test.tsx | 2 +-
...etailModal.responsive-and-dependencies.test.tsx | 63 +++++++++++++++++++++-
4 files changed, 74 insertions(+), 6 deletions(-)
Fusion-Task-Id: FN-8166
Fusion-Task-Lineage: ae58ae8b-4659-429f-8939-1d7e1a82d34c
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
pnpm 10.33 warns on every install and build:
[WARN] The "pnpm" field in package.json is no longer read by pnpm. The
following keys were ignored: "pnpm.onlyBuiltDependencies",
"pnpm.overrides"
The wording overstates it for the pinned version: on pnpm 10.33 the
field is still honoured, so nothing is broken today. It is a
forward-looking deprecation notice, and pnpm 11 makes it real — there
the overrides silently stop applying.
Reproduced on pnpm 11 with the workspace pins declared only in
package.json:
overrides block dropped from pnpm-lock.yaml
@types/node ^25.5.2 -> ^22.0.0 (25.5.2 -> 22.20.1)
zod 4.3.6 -> 3.25.76
@types/node fragments into 5 versions across the workspace
pnpm-workspace.yaml is the supported home and is honoured by both 10.33
and 11, so moving `overrides` there is safe on the pinned version and
correct for the next major.
Verified on pnpm 10.33: `pnpm install --lockfile-only` leaves
pnpm-lock.yaml byte-identical and its `overrides` block is now sourced
from pnpm-workspace.yaml. Verified on a minimal repro that pnpm 10.33
applies yaml overrides (ms -> 2.0.0).
Scope is deliberately limited to `overrides`. `ignoredBuiltDependencies`
and `onlyBuiltDependencies` are left in place: they are also honoured on
10.33 and ignored on 11, but the workspace list is not a superset of the
package.json one (it omits `electron`, removed in c7641f9d when electron
became a runtime dependency, and three @embedded-postgres arches outside
the `supportedArchitectures` cpu list curated in 1b9dce22). Reconciling
those is a maintainer call about intended behaviour, not a mechanical
move, so it is left for a follow-up rather than guessed at here.
No changeset: workspace/build config only, behaviour-preserving on the
pinned pnpm, and it does not affect published @runfusion/fusion.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Updated workspace dependency version overrides for improved
consistency across packages.
* Consolidated dependency configuration in the workspace settings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com>
## Summary
Adds **task-pinned worktrees** for `worktreeNaming: "task-id"`. Under
task-id naming, a task is pinned to exactly one derivable directory
`<worktreesDir>/<lowercased-task-id>` (e.g. `.worktrees/fn-7996`) for
its entire lifecycle — removing the ambiguity that let stale/foreign
`task.worktree` pointers strand a task (the FN-7996 shape).
`recycleWorktrees` stays fully functional and is **mutually exclusive**
with task-id pinning: the two can't be enabled together.
## Behavior
- **Pinned acquisition (`worktreeNaming: "task-id"`, recycling off):**
`acquireTaskWorktree` runs **derive → validate → reuse-or-recreate** at
the derived path — warm-reuse when the dir is a registered, usable
worktree on the task's own branch; otherwise reclaim-in-place
(`removeWorktree` + recreate at the SAME path, never a sibling name). A
disagreeing `task.worktree` cache self-corrects and emits a new
`worktree:pin-rederived` audit event, without consuming worktree-session
retries. The recycle pool is never consulted in pinned mode.
- **Mutual exclusivity:** enabling both `recycleWorktrees` and
`worktreeNaming: "task-id"` is rejected at the settings-write boundary —
HTTP 400 at `PUT /settings`, and an `Error` backstop in
`store.updateSettings` covering the CLI and every other writer
(`assertWorktreeNamingRecycleExclusive`). The runtime also gates pinned
mode on `!recycleWorktrees`, so a legacy on-disk config carrying both
degrades safely to recycling.
- **Settings UI:** the Settings → Worktrees panel enforces the
exclusivity bidirectionally — the *Recycle worktrees* toggle is disabled
while naming is *Task ID*, and the naming select is disabled while
recycling is on — so the conflicting state is unreachable, with help
text explaining why.
- **Byte-inert for the rest:** `random`/`task-title` naming and the
recycle pool (incl. `merger.ts` release) are unchanged;
worktrunk-managed layouts bypass pinning.
## Acceptance criteria (from the plan)
1. ✅ Pinned task dispatched N times only ever touches
`<worktreesDir>/<task-id>` on its own branch
2. ✅ No code path can hand task A's dir to task B (pool bypassed; path
derived from task id)
3. ✅ FN-7996 stale/foreign `task.worktree` self-corrects at next
dispatch (`worktree:pin-rederived`) without consuming session retries
4. ✅ Non-pinned modes with `recycleWorktrees: true|false` are
byte-identical (existing pool tests pass unchanged)
5. ✅ Stale same-name dir (crash leftover / archive→restore) reclaimed in
place, never suffixed
6. ✅ Docs updated (settings-reference, architecture, `worktreeNaming`
type doc); changeset (`minor`, `feature`); FNXC comments encode the
invariant
## Files
- `packages/engine/src/worktree-pinning.ts` — new pure helpers
(`isTaskPinnedWorktreeNaming`, `pinnedWorktreePathForTask`)
- `packages/engine/src/worktree-acquisition.ts` — pinned branch +
branch-match reclaim-in-place
- `packages/engine/src/run-audit.ts` — `worktree:pin-rederived` audit
type
- `packages/core/src/settings-validation.ts` (+ `index.ts`,
`task-store/settings-ops.ts`) — mutual-exclusion validator + wiring
- `packages/dashboard/src/routes/register-settings-memory-routes.ts` —
400 on conflict
-
`packages/dashboard/app/components/settings/sections/WorktreesSection.tsx`
(+ `packages/i18n/locales/en/app.json`) — bidirectional UI exclusivity
- `packages/core/src/types.ts`, `docs/*`, `.changeset/*`
## Verification
- New tests: engine `worktree-pinning` (5) +
`worktree-acquisition-pinned` (7); core
`worktree-naming-recycle-exclusive` (2); dashboard settings-route 400
(3) + WorktreesSection UI exclusivity (3)
- Regression sweep green: 194 engine
worktree/acquisition/pool/executor/merger-release tests, core settings
tests, dashboard i18n/settings-section tests
- `tsc --noEmit` clean for `@fusion/core` and `@fusion/engine`; changed
source files clean; eslint clean
- `pnpm verify:fast` PASS (build + scoped typecheck + boot smoke)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added Task ID worktree naming, providing each task with a stable,
deterministic worktree directory.
* Automatically reuses valid pinned worktrees and recreates stale or
conflicting ones at the same path.
* Added clear settings controls and validation for incompatible Task ID
naming and worktree recycling options.
* **Documentation**
* Updated worktree architecture, settings reference, and in-app guidance
to explain pinned worktrees and configuration constraints.
* **Bug Fixes**
* Improved recovery from stale or incorrect worktree assignments without
consuming session retries.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
## Summary
Two related changes around the plan-approval flow, plus a fix for
triage's plan-review loop that was stranding tasks at the replan cap.
### 1. Post a mailbox message when a plan needs approval (`feat`)
The ntfy push on `awaiting-approval` already existed end-to-end. This
adds the missing **durable, in-dashboard record**: a `system`-typed
mailbox message linking to the task, written whenever a task enters
`awaiting-approval`.
- Fires **before** the notifications-enabled gate, so a dashboard-only
operator (no ntfy/webhook configured) still gets the record — the whole
point of the mailbox channel.
- `system` type avoids re-triggering the `message:agent-to-user` ntfy
pipeline (no double-notify); idempotent via `sendMessageOnce` (key
`plan-approval:<taskId>`).
### 2. Help triage Plan Review converge before the replan cap (`fix`)
Investigation of three tasks that burned all 8 plan-review replans
without converging (**FN-7996, FN-8105, FN-8108**) found the reviewer
surfaced a *new, deeper* issue each cycle instead of confirming its
prior ones were fixed (goalpost movement), and reviewed specs at
implementation altitude. This addresses the root causes:
- **Feed the spec reviewer its own prior REVISE feedback + the 1-based
replan attempt** so it verifies prior issues rather than moving
goalposts. Gated to `reviewType === "spec"` and `attempt > 1` — **code
review and normal plan review are byte-for-byte unaffected**
(double-verified).
- **Reviewer prompt:** converge-on-re-review rule (don't REVISE for your
own earlier miss), severity ratchet (critical-only at attempt ≥ 3), and
a **Spec Altitude** guard so exact SQL/lock/CAS protocol design is
deferred to code review.
- **Planner prompt:** front-load exhaustive surface enumeration before
writing File Scope, and a storage-architecture ground-truth note
(Postgres-only store, composite PK `(project_id, id)`, `schema-applier`
migrations) to stop the repeated stale-fact REVISE rounds.
## Testing
- `@fusion/core` + `@fusion/engine` typecheck clean.
- Added coverage: reviewer spec-convergence wiring (attempt gating +
code/plan exclusion + severity ratchet), triage prior-feedback
derivation (incl. empty-output→notes fallback), mailbox decoupling
(fires when push disabled) + rejection safety, and assertions for all
new prompt sections.
- Affected suites green: notification-service, reviewer,
triage-plan-review-replan-cap, triage-replan-feedback, agent-prompts.
- `pnpm check:changesets` passes (2 changesets: `@runfusion/fusion`
minor + patch).
## Review
Ran a 6-persona `ce-code-review` (correctness + adversarial on Opus;
maintainability, testing, project-standards, api-contract). Guards
verified unbreakable; no P0/P1 correctness or security issues. Applied
the resulting fixes: decoupled the mailbox write from the push gate
(P2), `??`→`||` in the feedback derivation (P3), de-duplicated the
`specConvergence` ternary (P3), and closed the test-coverage gap the
review flagged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Plans transitioning to **awaiting approval** now write an idempotent,
task-linked **dashboard mailbox** message (approval reason + direct task
link), even if push/notifications are disabled.
- **Bug Fixes**
- Plan Review **replan** behavior now better **converges** on prior
REVISE feedback (including notes fallback) and stops looping at the
replan cap.
- At later attempts (attempt 3+), **REVISE** is applied to **critical**
issues while lower-severity items shift to suggestions.
- **Tests**
- Added/expanded coverage for mailbox messaging and spec-convergence
prompt wiring.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Let GitHub pull request previews refresh their current check status and comments.
- Add an accessible refresh action that bypasses the selected PR detail cache
- Prevent stale refresh responses from overwriting cached or visible PR details
- Cover refresh behavior across modal and embedded views, and document the control
- Add a minor changeset for the new GitHub import capability
Files changed:
.changeset/fn-8137-refresh-pr-checks.md | 7 ++
docs/dashboard-guide.md | 2 +-
.../dashboard/app/components/GitHubImportModal.css | 29 ++++++
.../dashboard/app/components/GitHubImportModal.tsx | 48 +++++++--
.../__tests__/GitHubImportModal.test.tsx | 115 +++++++++++++++++++++
5 files changed, 191 insertions(+), 10 deletions(-)
Fusion-Task-Id: FN-8137
Fusion-Task-Lineage: 1d4ffa9d-635c-4d59-b17c-63075f6d8c5e
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
## Summary
Follow-up after **#2164** and main’s **FN-8103 / FN-8104**
(Postgres-only data access / SQLite retirement).
Main already routes Quality through `AsyncQualityStore` +
`getAsyncLayer()`. This PR keeps the **review hardening** that was still
missing:
- **Project binding** — reject request `projectId` mismatches vs bound
AsyncDataLayer; all SQL uses bound project
- **`createRunIfNoActive`** — advisory lock so concurrent starts cannot
double-queue
- **Cancel-safe runner** — cancel slot registered before the running
write; pre-spawn cancel skips process
- **`finalizeRun`** — never overwrites a `cancelled` terminal status
- **Detached execute** — catch only execution failures; prune fail-soft
in `finally`
- Guardrail tests + Quality v2 plan doc
## Test plan
- [ ] Task QA loads under PostgreSQL (no SQLite/backend-mode error)
- [ ] Concurrent start for same task → 409 second start
- [ ] Cancel during start does not leave a live orphan process
- [ ] Cancelled run stays cancelled after process exit
- [ ] `pnpm --filter @fusion-plugin-examples/quality test` (37 tests)
The Help link is an <a class="btn"> and .btn never resets link
text-decoration, so the browser's default underline painted under the
icon+label box, reading as an overlap. Drop the icon (redundant next to
the "Help" label) and reset text-decoration on the shared
discord/help anchor-button selector. Also fold the Help button into the
same mobile 36px touch-target rule as Export/Import/Reset/Save so all
five footer buttons render at a consistent height.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Export/Import/Reset/Cancel/Save use .btn-sm, which the global mobile
touch-target rule deliberately excludes to keep dense table/card button
rows compact. That exclusion also caught the Settings footer, leaving
those buttons at ~24px tall on mobile — visibly smaller than the Help
and auth Test/Disable buttons on the same rail. Scope the 36px minimum
back to just this footer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>