Commit Graph

12151 Commits

Author SHA1 Message Date
gsxdsm
127b640b3f chore(release): v0.73.0
Version bump via changesets.
2026-07-23 22:43:43 -07:00
gsxdsm
593f38249c chore(release): v0.73.0-beta.6
Version bump via changesets.
2026-07-23 22:16:37 -07:00
gsxdsm
0a6f84bbdf fix(dashboard): index the FN-8348 Report row in settings search; re-green backfill test lane
Product fixes surfaced by the drift guards:
- GeneralSection.search.ts: FN-8348 added the Report row (bug/feedback/idea/help)
  without a search-index entry, so settings search could not find it.
- WorkflowNodeEditor.css: FN-8526 introduced the undefined deprecated alias
  --text-secondary; substitute the FN-8043 migration token --text-muted.

Stale-test alignment (no assertions weakened):
- settings-sections: builtin:coding-ideas is no longer deprecated post-#2378.
- TaskDetailModal workflow/oversight suites: mocked workflows gain the columns
  array FN-8476 metadata resolution requires; rerender-refetch tests use
  persistent mocks since the board-workflows effect now keys on task identity.
- ChatView.chat-commands: sendMessage gained the FN-8502 delivery-callback arg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:13:25 -07:00
gsxdsm
1d4cd27c73 fix(tests): give PG-harness plugin suites the 15s timeout the golden-template harness budgets for
The shared pg-test-harness pays the golden schema-template cold start inside
the first PG test of each vitest invocation and is budgeted against core's 15s
testTimeout, but the six PG-consuming plugin packages ran at vitest's 5s
default — on saturated CI runners the first PG test (e.g. whatsapp-chat
persistence.pg) timed out before its assertions ran. Propagate the 15s budget
to all six plugin configs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 22:09:51 -07:00
gsxdsm
d8b5ef62db fix(dashboard): key Chat, Missions, and GitHub Import by project against cross-project leaks
Audit follow-up to the Planning/subtask project-switch fixes — three more
surfaces had the same bug class:

- Embedded ChatView survived a project swap when both projects last used
  the chat view: useChat refetched the session list on projectId change
  but never reset activeSession/messages or closed the live stream, so
  project A's conversation kept rendering (and streaming) under project B.
  Now keyed by project like Quick Chat's FN-8257 FloatingWindow key.
- MissionManager's nested always-mounted MissionInterviewModal (and the
  interviewTarget-driven MilestoneSliceInterviewModal) reconnected the
  previous project's interview session under the new projectId and saved
  the goal draft under the new project's kb-mission-last-goal key.
  MissionManager is now keyed by project; the interview modal saves an
  un-started goal draft on unmount under its own project id.
- Always-mounted GitHubImportModal's persist effect depends on projectId,
  so a swap re-fired it with the old project's provider/labels/repo
  selections and wrote them under the new project's storage key. Now
  keyed by project (the embedded Import Tasks view already unmounted).

Verified SAFE without changes: TaskDetail/Group/Files/WorkflowNodeEditor
(conditionally rendered + closed on swap), Settings/Usage/Schedules/
Agents (cross-project by design or self-correcting projectId-keyed
hydration), and the remaining embedded views (projectId-keyed fetch
hooks, no streams or scoped drafts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:59:55 -07:00
gsxdsm
0dd34cd306 fix(chat): don't wipe task-bound planner chat history on /new or /clear
With showTaskChatsInCommonFeed enabled, task-planner sessions appear in the
common Direct feed, so /new//clear there hit ChatView's generic intercept and
createSession orphaned the task's planner history behind a fresh session.
Consume the command with a warning toast for task-bound sessions instead.

Also updates 6 stale ChatView.core.test.tsx sendMessage assertions broken by
FN-8502's onDelivered/onFailed options argument.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:58:21 -07:00
gsxdsm
049c36c9ae fix(chat): narrate task-chat step numbers 1-based to match the card's step count
The proactive status narration printed the internal 0-based step index, so the
final step of a 13-step task announced "Starting Step 12" next to a card
showing "12/13". Display now uses index + 1 in both the engine builders and
the store-side updateStep narration; the 0-based tool/PROMPT.md contract is
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:43:58 -07:00
gsxdsm
345dccbe7d fix(dashboard): consume seeded Planning initial plan on auto-start to stop duplicate sessions
The seeded initialPlan lived in modalManager state while embedded Planning
fully unmounts on main-content navigation, wiping its in-component auto-start
guard — so every navigate-back remount (and the project-switch remount key)
auto-started a duplicate planning session and abandoned the one in flight.
The payload is now a one-shot handoff: PlanningModeModal calls the new
onInitialPlanConsumed the moment auto-start fires, useModalManager clears
planningInitialPlan, and remounts take the stored-active-session restore path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:43:47 -07:00
gsxdsm
b007de5f94 fix(ci,tests): repair binary release pipeline and re-green the full suite
Binary Release (v0.73.0-beta.5 was fully red):
- bun compile: mark chromium-bidi external — playwright-core@1.60 (feature-video)
  optionally requires it and bun fails closed on unresolvable requires.
- Windows desktop EXE: quote -c.publish.channel=beta in release.yml; PowerShell
  tokenizes the bare flag into `-c` + a path and electron-builder ENOENTs on it.

Full suite (all 4 shards red from stale-test drift, no product bugs found):
- engine: align mock stores/assertions with atomic store.moveTaskIf dispatch
  (#2371), the fail-closed non-empty PROMPT.md artifact gate (#2390), oldest-
  first admission (FN-8453), alreadyClaimed graph routing (#2393), startStep
  step projection (#2403/FN-8464), structured retry presentation (FN-8503),
  provider-lane pause reasons (#2339), typed column-boundary entry (#2378),
  Type.Integer in CAS document schemas (#2375), bounded model-registry refresh.
- engine-no-blocking-shellout: re-pin 17 drifted allowlist line numbers and drop
  the stale REBASE_HEAD entry whose execSync was removed.
- core: schema-applier expectations track migrations 0033-0035 (96 tables) and
  the synthetic 0000 fixture gains workflow_work_items/mission_contract_assertions;
  work-item terminal state is "succeeded" post-#2378.

Known follow-up (not addressed here): self-healing starved-refinement escalation
bumps task.priority, which FN-8453 oldest-first admission no longer consults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:43:00 -07:00
gsxdsm
336b0cf95d fix(dashboard): key subtask breakdown by project to stop cross-project draft leaks
Same bug class as the Planning project-switch fix: on a project swap the
SubtaskBreakdownModal survived as the same instance, so the isOpen=false
reset ran with the NEW projectId and persisted the old project's draft
description under the new project's storage key (and kept it in memory),
making the breakdown reopen in project B with project A's draft.

- AppModals keys SubtaskBreakdownModal by project id so a swap remounts it.
- Unmount cleanup now saves the in-progress draft under the instance's own
  project key (constant per keyed instance), so the old project's draft is
  preserved instead of dropped or misfiled.
- Dismissal on swap was already covered by closeProjectScopedModals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:37:11 -07:00
gsxdsm
86f56b5cdc fix(dashboard): auto-start terminal sessions when the server host is not Windows
The wt.exe auto-create guard was keyed on the browser UA, forcing Windows
browsers pointed at mac/linux-hosted dashboards through the manual "Start
terminal" screen. Windows-UA clients now probe GET /api/system/info once and
only keep the skip when the SERVER platform is win32 (or the probe fails,
conservatively). Non-Windows browsers never probe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:33:55 -07:00
gsxdsm
07541f78e2 fix(dashboard): reset project-scoped modals and remount Planning on project switch
Switching projects left the previous project's modals (task detail, group,
subtask, git manager, ...) open over the new project, and the embedded
Planning view kept the old project's running plan, session list, and
persisted active session (the durable-session effect re-fired with the new
projectId while the old session was selected, contaminating the new
project's storage key).

- modalManager.closeProjectScopedModals() closes project-scoped modals and
  clears planning/subtask payloads; settings/schedules/usage/agents/setup
  wizard/model onboarding stay open. Called from handleSelectProject (only
  on an actual project change), handleViewAllProjects, handleSetupComplete.
- Embedded PlanningModeModal is keyed by project id so a project swap
  remounts it: stream closed by unmount cleanup, fresh session list, and
  the new project's own persisted draft/active session restored.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:29:54 -07:00
gsxdsm
3b55502d48 fix(ci): full-suite bookkeeping v32 — AgentsView heartbeat mock (#2432)
## Summary

Restore main full-suite green after AgentsView started calling
`isAgentHeartbeatEnabled` / `withAgentHeartbeatEnabled`.

- **Root cause:** `agents-view-mobile.test.tsx` wholesale-mocks
`../../api` without those exports → uncaught exception → empty DOM →
missing Board/List/Controls queries.
- **Fix:** add heartbeat helpers to the mock (same contract as
AgentDetailView helpers).

## Context

Failing run:
https://github.com/Runfusion/Fusion/actions/runs/30062695937
4 failures in `agents-view-mobile.test.tsx` (dashboard app quality
backfill shard).

## Test plan

- [x] `app/components/__tests__/agents-view-mobile.test.tsx` (15 tests)
- [x] `pnpm test:gate` ×2
- [ ] CI PR checks / Full Suite

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Tests**
* Improved mobile agents view test coverage by adding heartbeat toggle
behavior to the test setup.
* Documented heartbeat-related dependencies used by bulk and individual
agent controls.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-23 21:19:33 -07:00
gsxdsm
26628b356b chore(release): v0.73.0-beta.5
Version bump via changesets.
2026-07-23 20:23:55 -07:00
gsxdsm
0412113de7 fix(dashboard,cli): un-dead-end deleted plan tasks; harden fn task plan per review
Reported bug (screenshot): deleting the task created from a plan left the
session permanently stuck on PLANNING_CREATED_TASK_MISSING — Retry create
replayed the same 409 forever. A linked task absent from the
include-archived scan (task-row authority; a successful scan proves
deletion, not a flaky read) now clears the stale linkage and creates a
fresh task, in both the create-task route and createTaskFromPlanSession;
a still-listed-but-unreadable task keeps failing closed.

Multi-agent review of fdd120232 (correctness/adversarial/reliability):
- P1: CLI planning sessions were memory-only — setAiSessionStore only ran
  in the dashboard server, so --resume could never find a session across
  invocations. New ensureDurablePlanningSessionStore wires the durable
  AiSessionStore over the board store's public asyncLayer in runTaskPlan.
- P1: resume failures now THROW instead of process.exit (fn_task_plan
  runs inside the pi host — an exit killed the whole agent session), and
  a no-question resume requires an explicit refine focus (the provided
  description) so merely resuming never rotates the epoch.
- P2: claim and finalize CAS gained the same expected-epoch WHERE guard
  as reconcile, so a stale-epoch creator can no longer finalize an
  old-epoch task onto a rotated session.
- Side-effect failures (documents, logEntry, validate, reconcile) are now
  logged instead of swallowed; post-insert failures no longer mislabel
  the just-created task alreadyCreated:true; the keep-refining readline
  closes on thrown prompts and a failed refine after creation returns the
  created task id with a resume hint; cross-process generating guard
  added to createTaskFromPlanSession.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 20:19:18 -07:00
gsxdsm
fdd1202328 feat(cli): claim-aware multi-task planning parity for fn task plan
Closes the P1 agent-native gap from the multi-task review: the CLI and
fn_task_plan pi tool created tasks via a raw store.createTask with no
proposalClaimId — no idempotency, no session linkage, and tasks outside
the epoch sequence, so a later dashboard Proceed would duplicate them.

- New shared createTaskFromPlanSession in @fusion/dashboard/planning:
  the agent-surface twin of POST /planning/create-task (epoch-derived
  claim key, claim/finalize/reconcile/release CAS lifecycle with the 30s
  stale-lease takeover, formatPlanningPlanMd task shape, plan/original-
  description documents, validate-on-create, generating guard).
- runTaskPlan creates through it (making the FN-7734 retry wrapper
  genuinely safe), prints the session id, and offers an interactive
  keep-refining loop that creates further tasks from the evolved plan.
- fn task plan --resume <sessionId> / fn_task_plan resumeSessionId reopen
  an existing session — even a validated one whose task exists — and the
  no-question resume regenerates the interview via a refine turn, which
  rotates the creation epoch server-side.

Tests: CLI suite pins claim-aware creation, the continue prompt, and the
resume flow; dashboard suite pins createTaskFromPlanSession idempotent
replay and epoch-aware second creation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 20:01:50 -07:00
gsxdsm
fbaf3c56d2 fix(dashboard): close terminal bootstrap residuals from the terminal review
- Windows clients no longer force isReady(true) on mount: the validation
  effect owns isReady on every path, so persisted tabs are server-validated
  before xterm connects (previously Windows could attach to a dead session
  first and recover via 4004).
- isWindowsBrowserClient() matches 'Windows NT' minus 'Windows Phone' so
  phone UAs are not needlessly denied first-tab auto-create.
- normalizeActiveTab() now also collapses MULTIPLE active tabs to the first
  active one (zero-active was already handled), and readTabsFromStorage
  drops malformed persisted entries individually instead of discarding the
  whole payload's valid siblings via the outer catch.
- Regression tests for all four paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:49:43 -07:00
gsxdsm
faeb491ea4 fix(dashboard): harden terminal paste contract and manual-start button per review
Review follow-up to 907e8d03e (ce-code-review, 8 personas):
- Ctrl/Cmd+V with no clipboard API (or after a denied read) now returns
  false WITHOUT preventDefault: xterm skips key handling and the browser's
  default paste fires xterm's helper-textarea listener once. Returning true
  made non-mac xterm inject \x16 and cancel the native paste (verified
  against xterm 5.5.0 _keyDown).
- A denied clipboard read sets a sticky ref so later pastes use the native
  path instead of being preventDefaulted into zero delivery.
- Custom-path delivery goes through terminal.paste() to restore bracketed
  paste and newline normalization.
- 'Start terminal' surfaces createTab failures in the error banner and
  disables while a create is in flight (no duplicate PTY sessions).
- normalizeActiveTab() extracted so storage-read and server-validation
  share one all-inactive tie-break; failure-path regression test added.
- Rewrote docs/solutions/ui-bugs/xterm-async-font-remeasure-paste-dedupe.md
  to the current paste contract (was prescribing the pre-#1902 behavior).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:46:02 -07:00
gsxdsm
ca4639bb67 feat(dashboard): allow multiple tasks from one plan via epoch-scoped claims
One planning session can now create multiple tasks. Task-creation claims
are epoch-scoped: proposalClaimId stays planning-session:{id} for epoch 0
and becomes planning-session:{id}#N after the plan is edited past a
created task (rotateTaskCreationEpochOnReopen archives createdTaskId into
createdTaskIds and resets claim state). Unedited Proceed replays stay
idempotent within an epoch; crash-after-insert dedup still reconciles via
the epoch-keyed task row. Complete sessions resume to an editable plan
review with a linked-task banner; the task-created handoff gains a
Continue planning action.

Hardening from the multi-agent code review (9 reviewers):
- Reopen + rotation run only AFTER turn admission, so a rejected request
  never burns a phantom rotation (P1, 3 reviewers).
- Claim-lifecycle CAS writes are surgical jsonb merges and reconcile takes
  an expected-epoch guard, so a concurrent rotation can never be reverted
  or an archived task re-linked to a new epoch.
- create-task 409s while the session is still generating (turn-completion
  persist could tear the fresh linkage).
- Durable-read fallback in create-task now logs before trusting the
  in-memory epoch.
- linkedTaskId no longer leaks across session switches; the banner
  resolves the just-created Task before the tasks prop refreshes and
  falls back to the newest archived task after rotation; Continue
  planning re-registers the active session.
- Shared applyCompletePlanningResume helper replaces triplicated resume
  view-transitions; stale one-task-per-session comment corrected.

Tests: post-rotation replay idempotency and epoch-keyed crash reconcile
(e2e), rewind rotation + rejected-rewind non-rotation + payload
normalization round-trip (unit), Continue planning + banner-leak (UI),
create-task 409 (routes), and a new PG integration suite pinning the
surgical CAS merge and reconcile epoch guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:37:49 -07:00
gsxdsm
907e8d03e6 fix(dashboard): terminal manual-start on Windows clients and single-delivery Ctrl/Cmd+V paste
GitHub #2121/#2307: Windows browser clients intentionally skip first-tab
auto-create, but TerminalModal showed an endless 'Starting terminal...'
spinner whose only escape was the tab-strip '+'. useTerminalSessions now
exposes autoCreateDisabled and the modal renders an explicit 'Start
terminal' action instead. All-inactive persisted tab payloads are also
normalized on restore so the spinner can't wedge on activeTab=null.

Paste: attachCustomKeyEventHandler returning false does not cancel the
browser's default paste, so Ctrl/Cmd+V delivered the payload twice (custom
clipboard read + xterm helper-textarea paste event). preventDefault() makes
the custom read the single path; when the async clipboard API is missing
(non-HTTPS remote access, older Firefox) the handler returns true so the
native paste path works instead of paste being dead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:30:45 -07:00
gsxdsm
0e6108a1a5 fix(dashboard): Stop cancels pending initial planning turns per-session
stopGeneration only aborted generations with an activeGenerations record.
A just-started session whose initial turn was still pending (registered
by start-streaming, not yet consumed by a stream connect) returned false
from Stop and the "stopped" generation sprang back to life on the next
stream connect. Stop now discards the pending turn too, and remains
strictly keyed to its session id so stopping one plan never affects other
concurrently generating sessions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:52:19 -07:00
gsxdsm
370a7a645d fix(dashboard): a validated plan stays readable, editable, and creatable
A finished plan must never land on a do-nothing screen:

- submitResponse/rewindSession REOPEN a validated session (clear the
  terminal marker; the turn's persistSession durably writes it) instead
  of rejecting with "already been validated". validateSession remains the
  only terminalizer.
- A complete session with no created task resumes into the full plan
  review workspace (read plan, Refine/comments, Proceed) instead of the
  create-only retry card; task-linked sessions still resume to the task
  handoff, preserving the never-rotated one-task-per-session claim.
- The live create-failure screen gains a Back to plan action.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:52:19 -07:00
gsxdsm
ddea2876c4 fix(dashboard): let the planning workspace loader scroll on short viewports
Code-review follow-up to e2ee8ba27: the loader overlay now hosts the
streamed-thinking pane, and on short viewports (landscape phones are in
the mobile breakpoint) the centered column could exceed the overlay and
clip the Stop button and thinking output. The overlay scrolls instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:52:19 -07:00
gsxdsm
e2ee8ba276 fix(dashboard): stream AI thinking on every Planning Mode generation step
The workspace loader that covers all follow-up turns (next question,
refine, contextual comments, question regeneration) showed only a spinner
and elapsed time — streamed thinking/output was visible only on the first
pre-summary turn. Reuse the initial loading view's thinking container and
toggle there, and mirror the generation-activity label instead of a
hardcoded "Generating plan…".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:39:10 -07:00
gsxdsm
7cb87e7687 fix(dashboard): regenerate interview questions in mission/milestone/onboarding too
Extends the Planning Mode no-active-question fix to the other three
interview lanes: a LIVE session (no summary yet) that receives a
submission with no active question now reprompts the agent to continue
the interview and ask a fresh question — carrying the submitted input as
context — instead of throwing "No active question in session". Completed
interviews (summary present) still reject late submissions, preserving
the existing contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:39:10 -07:00
gsxdsm
64b20c8be3 fix(dashboard): regenerate a planning question instead of "No active question in session"
Refining a plan (or submitting any input) while the session had no active
question — e.g. after a failed retry cleared summary/currentQuestion —
threw InvalidSessionStateError("No active question in session") at the
operator. Now the interview continues instead:

- The refine and contextual-comment branches no longer require
  session.summary; they fall back to a running summary rebuilt from
  persisted history.
- A submission with no active question reprompts the agent via
  formatQuestionRegenerationForAgent to produce a fresh option-driven
  question, carrying the submitted operator input along as context.
- The Planning modal forwards no-question submissions to the server
  (loading view + SSE) instead of dead-ending with a local error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:29:59 -07:00
gsxdsm
b462978e92 fix(dashboard): emit planning terminal error exactly once on stream reconnect
Code-review follow-up to 716e69862: the terminal-error reconcile ran after
the Last-Event-ID replay, so a reconnecting client received a buffered
error event from the replay AND again from the reconcile block (double
onError, duplicate auto-retry triggers). The reconcile now runs before the
replay and skips it for terminal sessions, writing the newest buffered
error event (or a fresh broadcast when the bounded buffer evicted it)
exactly once, gated on lastEventId.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:18:04 -07:00
gsxdsm
2bebed18b2 fix(dashboard): pin mobile comment composer to visualViewport above keyboard
Phone fixed bottom:overlap left the panel under the soft keyboard (layout vs
visual viewport). While open on mobile, remeasure visualViewport and pin with
top/max-height so the entry box stays visible when the keyboard opens.
2026-07-23 18:16:28 -07:00
gsxdsm
b67dca4178 fix(dashboard): stop Chat Latest button jumping under the cursor
Center the jump-to-latest chip with margin-inline auto instead of
transform:translateX(-50%) so global .btn transform transitions and
:active scale cannot shift it sideways in Quick Chat and full Chat.
2026-07-23 18:15:03 -07:00
gsxdsm
716e698628 fix(dashboard): stop Planning Mode hanging on provider errors mid-generation
Provider errors thrown between persistSession("generating") and the turn's
own error handling (agent rebuild in ensureSessionAgent, history replay,
legacy sync createSession first turn) escaped to the route and left the
session row "generating" forever with no error, no SSE event, and no
watchdog — the modal hung on "Thinking/Generating plan" because its SSE
reconnect loop and 8s poll both treat a persisted "generating" row as
healthy.

- submitResponse/retrySession/createSession now convert any non-abort
  escape after entering "generating" into the standard persisted retryable
  error + SSE error broadcast before rethrowing.
- The SSE stream route reconciles settled/stranded sessions on connect
  (reconcileStalePlanningGeneration): a terminal error is replayed and the
  stream closed; a "generating" session with no live/pending turn past the
  watchdog window is converted to a retryable interrupted error.
- Provider failures on the JSON reformat retry now surface as themselves
  instead of a misleading "no valid JSON" parse error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 18:14:29 -07:00
gsxdsm
dcbf923e07 fix(dashboard): keep planning comment editor open after selection collapse
Snapshot the selected quote on Add-comment pointerdown and freeze it for the
composer so mobile selectionchange can no longer clear the quote and unmount
the entry box as soon as it opens.
2026-07-23 18:12:52 -07:00
gsxdsm
34a9216509 fix(dashboard): prevent comment-composer keyboard blur without early commit
Add/Submit no longer run on pointerdown (that closed the box immediately).
Match Start Planning: preventDefault keeps focus for the click, then click
commits the action once.
2026-07-23 18:09:13 -07:00
gsxdsm
b6a930eff0 fix(dashboard): commit planning comments on pointerdown before keyboard blur
On phone/tablet the first tap of Add/Submit blurred the composer, closed the
keyboard, and shifted the fixed panel so the click was lost. Commit the action
on pointerdown (same pattern as Refine Apply) so one tap is enough.
2026-07-23 18:03:21 -07:00
gsxdsm
45da5f71d3 fix(dashboard): keep planning comment composer above the keyboard
Pin the selection comment editor as a fixed panel on tablet and phone, and
lift it with visualViewport keyboard metrics so the first focus no longer
hides the form under the OS keyboard (or off-screen on tablet).
2026-07-23 17:56:05 -07:00
gsxdsm
f8e6fd5e2b fix(dashboard): stack tablet Add comment above actions with mobile icon
Tablet plan-actions no longer use flex nowrap (which put Add comment beside
Refine/Proceed). Keep the two-column grid so the selection control is a
full-width first row, and pin MessageSquarePlus to the same 16px/token size
as mobile.
2026-07-23 17:49:53 -07:00
gsxdsm
b15fd2b498 fix(dashboard): stack mobile Add comment above Refine/Proceed
Phone no longer pins Add comment under the action rail as a fixed bar. It
uses the same full-width in-flow footer row as tablet, above Refine and
Proceed. The composer stays fixed when open.
2026-07-23 17:43:27 -07:00
gsxdsm
73a57d9487 fix(dashboard): recover finished planning sessions instead of retry dead-ends
Reopening a complete plan no longer shows "still being prepared" when the
validated payload marker is missing. Generation Retry that hits
"already been validated" refreshes into create-retry or plan review.
2026-07-23 17:39:33 -07:00
gsxdsm
28e2cd587c fix(dashboard): put plan-review Add comment above actions on tablet
Tablet (≤1024px) now uses the action-rail Add-comment control as a full-width
row above Refine/Proceed instead of the document-end trigger. Phone keeps the
fixed bar above the mobile nav; desktop keeps the in-document control.
2026-07-23 17:36:10 -07:00
gsxdsm
c1d37cb137 test(FN-8544): assert mission autopilot system actor on status updates
Align MissionAutopilot expectations with autonomy-audit attribution: updateMission
carries the system actor options, and autopilot_disabled is recorded on the
mutation instead of a separate logMissionEvent mirror.
2026-07-23 17:28:56 -07:00
gsxdsm
0307476f35 fix(tests): restore listTasks hot-path contract and PG harness fs isolation
- usage-limit-detector + provider-health-monitor: make three bare listTasks()
  callers explicit with { slim: true }, restoring the architecture-hot-paths
  contract (they only read scalar pause/column/model-provider fields).
- pg-test-harness beforeEach: wipe <rootDir>/.fusion/tasks after TRUNCATE ...
  RESTART IDENTITY so filesystem isolation matches the id reset; stale task
  dirs from prior tests no longer collide with reused IDs (fixes
  store-reservation-atomicity rollback assertions).
2026-07-23 17:27:59 -07:00
gsxdsm
62c52972fc fix(dashboard): keep mobile plan-review selection comments on-screen
Plan review Add-comment controls now track document-level selectionchange so
they appear as soon as text is selected and dismiss when the selection ends.
On mobile the trigger and composer are fixed above the nav (with width auto)
so operators no longer need to scroll to reach them.
2026-07-23 17:19:26 -07:00
gsxdsm
dfb9ca6630 FN-8543: enforce bounded generated-fix remediation
Keep generated fix chains within their root retry budget and preserve intervention stops.

- Track retry counts and stop reasons on the canonical root feature.
- Persist project-isolated lineage stops across generated-fix removal and archive paths.
- Serialize stop recording with generated-fix admission and expose conflict-safe mission resume behavior.

Files changed:
 .changeset/fn-8543-bounded-fix-lineage.md          |   7 +
 docs/missions.md                                   |   6 +-
 .../__tests__/postgres/mission-store.pg.test.ts    |  72 +++++++
 packages/core/src/async-mission-store-queries.ts   |  91 ++++++++-
 packages/core/src/async-mission-store.ts           | 206 ++++++++++++++++++---
 packages/core/src/index.ts                         |   2 +-
 packages/core/src/mission-store.ts                 |  10 +
 packages/core/src/mission-types.ts                 |   7 +
 .../0035_fn_8543_mission_lineage_stop.sql          |  31 ++++
 packages/core/src/postgres/schema-applier.ts       |  18 +-
 packages/core/src/postgres/schema/project.ts       |  21 +++
 .../core/src/task-store/archive-lifecycle-2.ts     |  15 +-
 .../core/src/task-store/async-archive-lineage.ts   |  10 +-
 packages/dashboard/src/mission-routes.ts           |  14 +-
 packages/engine/src/mission-execution-loop.ts      |  30 ++-
 15 files changed, 495 insertions(+), 45 deletions(-)

Fusion-Task-Id: FN-8543

Fusion-Task-Lineage: 24c03d63-5914-4072-aa17-16862432fc78

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 16:12:44 -07:00
Victor Canô
0c085bf444 fix(engine): pushAfterMerge no longer strands approved merges when the remote diverges (#2407)
## Problem

With `pushAfterMerge` enabled (and `mergeStrategy` other than
`pull-request`), if `origin/<integration-branch>` advances externally
between the local squash-merge and the push, the divergence path opens a
clean-room `git pull --rebase` and an AI agent resolves and stages the
conflicts — but the flow could end there: no `git rebase --continue`, no
push, and no surfaced error.

Because finalize runs *before* the push, the task is already `done`, so
a reviewed, approved merge is silently left container-only, and every
subsequent merge on the project stalls the same way. Separately, an
abort mid-push (`MergeAbortedError`) was swallowed with only a
process-log warning — no task-log entry, no run-audit event.

## Change

- **Deterministic regression coverage** for the conflicting-divergence
path (real-git fixture) proving the rebase runs to completion and the
push lands (refs converge), plus abort/termination scenarios.
- **Recovery-branch safety net:** before the clean-room rebase starts,
the pre-rebase local squash is force-pushed to a per-task remote branch
`fusion/<task-id>-stranded`, so approved content is never container-only
— even across process death or abort. Deleted after a successful target
push; retained on failure/abort as the recovery source.
- **Never-silent outcomes:** every non-pushed outcome (failure or abort)
writes a durable task-log entry and a `push:origin` run-audit event. The
audit contract now documents `push:origin` as polymorphic (dashboard
Smart Push vs. automated post-merge push) and enumerates the automated
path's outcomes, including the new `"aborted"` shutdown case.
- **Cleanup hardening:** `isRebaseInProgress` now probes Git's
worktree-specific `rebase-merge`/`rebase-apply` state directories
(async, timeout-guarded) so a completed rebase can't receive a spurious
second `--continue`; unfinished rebases are cleaned up.

Out of scope by design: withholding the "merge confirmed" state until
the push succeeds — the `FNXC:MergePush` invariant ("a push problem can
never park or roll back a landed merge") is deliberate; the recovery
branch + surfacing satisfy the data-preservation intent without breaking
it.

## Files
`packages/engine/src/merger-ai.ts`, `packages/engine/src/merger.ts`,
`packages/engine/src/run-audit.ts`, new/updated tests under
`packages/engine/src/__tests__/`, `docs/settings-reference.md`,
`docs/dashboard-guide.md`, `AGENTS.md`, and a labeled changeset.

## Validation
`tsc --noEmit` clean; engine divergence + merger suites pass (41 tests);
rebased onto current `main` with no conflicts.

---

_Developed with Claude Code, under human supervision and review._


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Prevented approved post-merge pushes from becoming stranded when the
remote diverges by using a recovery-branch workflow and safer cleanup.
* Improved behavior and reporting when pushes are aborted or fail after
merge, including clearer non-fatal status and audit outcomes.
* **Documentation**
* Expanded push-after-merge and dashboard Smart Push documentation with
recovery-branch and `push:origin`/`push:recovery-branch` outcome
semantics.
* **Tests**
* Added end-to-end regression tests for divergent/conflicting AI
push-after-merge flows, including abort and worktree cleanup
verification.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Victor Cano <victortroz@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 15:55:03 -07:00
Phil Larson
9f79b22d51 fix(i18n): restore secondary locale key parity (#2430)
## Summary
- synchronize all five secondary app locale catalogs with the authored
English key structure
- restore fallback entries for heartbeat controls, release-channel
settings, report targeting, and task provenance labels
- add a patch changeset for the catalog parity fix

## Test Plan
- `pnpm i18n:status`
- `pnpm --filter @fusion/i18n test` (29 tests)
- `pnpm --filter @fusion/dashboard exec vitest run
app/components/__tests__/AgentsView.test.tsx --silent=passed-only
--reporter=dot` (138 tests)
- `pnpm check:changesets`
- `pnpm build`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Improved localization consistency for heartbeat controls, capability
settings, release-channel configuration, reporting guidance, and task
provenance details.
- Added missing translation entries across Spanish, French, Korean,
Simplified Chinese, and Traditional Chinese locales.
- Untranslated values now fall back cleanly to the authored English text
structure, preventing missing or inconsistent labels in supported
interfaces.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-23 15:54:41 -07:00
Umut
2b9131ba7c Fix broken anchor in README Workflow Steps link (#2431)
The Workflow Steps bullet in README.md links to
`./docs/workflow-steps.md#workflow-declared-optional-steps`, but the
target heading is `#### Workflow-declared optional steps
(`optional-group` nodes)`, which GitHub slugifies (including the
parenthesized text) to
`#workflow-declared-optional-steps-optional-group-nodes`. As a result
the link lands at the top of the page instead of the intended section.

The correct anchor is already used by a self-link elsewhere in the same
file (docs/workflow-steps.md, the "Optional groups and default-on gates"
row), confirming the expected slug.

This is a one-line fix: append `-optional-group-nodes` to the anchor in
README.md.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated the Workflow Steps documentation link to direct readers to the
more specific “optional group nodes” section.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-23 15:54:16 -07:00
gsxdsm
11fab37379 feat(ci): incremental caching for the PR merge-gate jobs (Gate, Build, Typecheck) (#2421)
## Summary

Every PR's blocking checks were dominated by redundant full rebuilds,
not by tests. Measured on recent runs: the Gate job spent ~6 of its ~7.5
min on a cold `pnpm build` (the exact-key dist cache missed on virtually
every PR) for ~45s of actual boot smoke + gate tests; Build ran ~8 min
and Typecheck ~4 min, both fully cold every time. Expected end state
once the warm job has run on main: all four blocking checks in roughly
2–4 min wall-clock.

### Gate job
- New `gate-dist-*` cache namespace with `restore-keys`, additionally
caching `.fusion/cache/plugin-build-cache.json` (build-workspace's
per-package content-hash skip cache) and `packages/cli/dist`. The
always-run `pnpm build` reconciles a near-match restore by content hash
and rebuilds only the packages the PR touched. This is safe *because*
the gate builds after restoring — the shard jobs' "no restore-keys" rule
(FN-4232/FN-4605 stale-dist incidents) still stands there, since they
consume dist without building.
- `FUSION_CLI_FULL_PACKAGE=0` on the gate build: skips the multi-minute
CLI desktop/plugins/DTS packaging tail nothing in the gate consumes
(same shape `pnpm verify:fast` proves locally). Full CLI packaging
coverage stays blocking in the Build job.

### Build job
- Restore-only tap (`actions/cache/restore`) of the same warmed cache.
Restore-only because this job runs FULL CLI packaging (`CI=true`) and
saving that shape would swap the cache's canonical fast-CLI contents out
from under the Gate job. Its distinctive coverage is preserved:
`ensureFullPackageCliPlanned` force-plans the CLI in full mode
regardless of cache state.

### Typecheck job
- Caches per-package tsc incremental buildinfo — self-validating (tsc
hashes every input against it and re-checks whatever changed), so
`restore-keys` is correctness-neutral by construction.
- **Fixes a real incrementality bug:** `tsconfig.json` and
`tsconfig.app.json` in the dashboard both inherited
`${configDir}/dist/.tsbuildinfo` from `tsconfig.base.json`, so the two
typecheck programs clobbered each other's buildinfo and re-checked the
full program every run — incremental typechecking never worked for the
dashboard, in CI or locally. `tsconfig.app.json` now writes
`dist/.tsbuildinfo-app`. Measured: dashboard typecheck 44s cold → 5.6s
warm.

### Warm job (full-suite.yml, push to main)
- New `warm-gate-build-cache` job saves both caches from main on every
push. Caches saved on a PR merge ref are invisible to other PRs, so
without this every PR's *first* run would still build/check cold.

## Guardrails

`ci-workflow.test.ts` pins the coupled invariants so they can't drift
apart silently:
- restore-keys requires the reconciling `pnpm build` after restore,
before boot smoke
- the mtime-defeating seed step stays exact-hit-only
- byte-identical cache path lists between the Gate/Build/warm blocks
(actions/cache versions caches by path list — a drifted list makes
caches mutually invisible)
- Build stays restore-only and must NOT opt out of full CLI packaging
- Typecheck cache shape + the distinct dashboard app buildinfo path

## Notes

- First PR runs after this lands still build cold until the warm job has
run once on main.
- No changeset: CI config + test-only per AGENTS.md.

## Verification

- `ci-workflow.test.ts` + `package-config.test.ts`: 106 tests pass
- Dashboard typecheck run twice locally: 44s cold → 5.6s warm, both
`.tsbuildinfo` and `.tsbuildinfo-app` written, exit 0
- Cache block path/key parity verified programmatically across both
workflow files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Performance**
* Improved CI build and type-check performance through incremental
caching.
* Added cache warming from the main branch to speed up pull request
checks.
* Enabled faster CLI packaging during gate validation while retaining
full packaging coverage elsewhere.

* **Bug Fixes**
* Prevented dashboard TypeScript build information from being
overwritten, preserving incremental type-checking reliability.

* **Tests**
* Added coverage to verify CI cache behavior, build ordering, cache
paths, and packaging modes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:53:31 -07:00
gsxdsm
94644ef849 fix(planning): mark session complete after Proceed-with-plan task creation
Proceed with plan called /api/planning/create-task without the legacy
/validate step, so the persisted AI session stayed awaiting_input and the
session list/needs-input banner kept advertising a finished session. The
create-task route now terminalizes the session via validateSession on every
path that ends with a created task, including alreadyCreated reconciliation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:45:39 -07:00
gsxdsm
d3f15f92bf docs: rewrite 0.73.0 beta changelog sections to per-beta deltas
The root CHANGELOG's beta sections (and the matching GitHub prerelease bodies, now edited in place) carried full-cycle aggregates because every beta distilled all preserved pre-mode changesets. Rebuilt each section from packages/cli/CHANGELOG.md's incremental per-beta entries so each beta lists only its own changes; future releases are handled by the channel-scoped selection in release.mjs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:41:09 -07:00
gsxdsm
e5caea542a FN-8544: gate mission remediation behind autopilot
Keep mission validation report-only until an operator explicitly enables autopilot.

- Gate validator-created remediation features and task dispatch behind mission autopilot.
- Audit attributed status and autopilot transitions atomically across mission stores.
- Expose mission autonomy controls and document the opt-in lifecycle.

Files changed:
 .changeset/fn-8544-mission-autonomy-audit.md       |   7 ++
 docs/missions.md                                   |  10 +-
 packages/cli/src/extension.ts                      |  26 ++++-
 .../__tests__/postgres/mission-store.pg.test.ts    |  27 +++++
 packages/core/src/async-mission-store.ts           |  70 +++++++++++--
 packages/core/src/index.gate.ts                    |   3 +
 packages/core/src/index.ts                         |   3 +
 packages/core/src/mission-store.ts                 | 113 +++++++++++++--------
 packages/core/src/mission-types.ts                 |  22 ++++
 .../dashboard/app/components/MissionManager.tsx    |   1 +
 packages/dashboard/src/mission-routes.ts           |  25 +++--
 .../src/__tests__/agent-mission-tools.test.ts      |  17 +++-
 .../src/__tests__/mission-execution-loop.test.ts   |  21 ++++
 packages/engine/src/agent-heartbeat.ts             |   4 +-
 packages/engine/src/agent-tools.ts                 |  30 +++++-
 packages/engine/src/executor.ts                    |   5 +-
 packages/engine/src/mission-autopilot.ts           |  51 +++++-----
 packages/engine/src/mission-execution-loop.ts      |  49 ++++++---
 packages/engine/src/triage.ts                      |   5 +-
 19 files changed, 377 insertions(+), 112 deletions(-)

Fusion-Task-Id: FN-8544

Fusion-Task-Lineage: 23a69923-5a19-407e-9fe2-8973c166ee9a

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 15:25:09 -07:00
gsxdsm
e7c9b2ac80 FN-8542: separate milestone acceptance from feature validation
Keep feature validation scoped to linked feature assertions while evaluating milestone acceptance at rollup.

- Add assertion scope and origin provenance with database migration support
- Synchronize milestone acceptance prose to a canonical milestone assertion
- Prevent milestone assertions from affecting feature verdicts and document the completion contract
- Cover scoped validation and milestone rollup behavior with core and engine tests

Files changed:
 .changeset/fn-8542-feature-validation-scope.md     |   7 +
 docs/missions-completion-contract.md               |  25 +-
 docs/missions.md                                   |   6 +-
 .../mission-store.sync-loop-transition.test.ts     |  53 +++++
 packages/core/src/async-mission-store-queries.ts   |  17 +-
 packages/core/src/async-mission-store.ts           |  58 ++++-
 packages/core/src/mission-store.ts                 | 118 +++++++++-
 packages/core/src/mission-types.ts                 |  25 ++
 .../core/src/postgres/migrations/0000_initial.sql  |   2 +
 .../0034_milestone_assertion_provenance.sql        |  30 +++
 packages/core/src/postgres/schema-applier.ts       |  24 +-
 packages/core/src/postgres/schema/project.ts       |   1 +
 .../src/__tests__/mission-execution-loop.test.ts   | 161 ++++++++++++-
 packages/engine/src/mission-execution-loop.ts      | 262 ++++++++++++++++-----
 14 files changed, 700 insertions(+), 89 deletions(-)

Fusion-Task-Id: FN-8542

Fusion-Task-Lineage: cf112d31-376a-456e-be08-225eab5de393

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-23 14:39:44 -07:00