Commit Graph

63 Commits

Author SHA1 Message Date
gsxdsm
3cc1d9373f FN-8780: expand Activity thinking blocks by default
Make Task Detail Activity reasoning immediately readable in every workflow column.

- Default newly mounted thinking segments to expanded state
- Preserve user collapse choices while streamed reasoning updates
- Add coverage for default, toggle, and streaming behavior

Files changed:
 .changeset/fn-8780-activity-thinking-open.md       |  7 ++
 packages/dashboard/app/components/TaskChatTab.tsx  | 25 ++-----
 .../app/components/__tests__/TaskChatTab.test.tsx  | 79 +++++++++-------------
 3 files changed, 45 insertions(+), 66 deletions(-)

Fusion-Task-Id: FN-8780

Fusion-Task-Lineage: 51a0be0d-0bc8-4e1f-ac1d-b30583d7b202

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-08-04 01:54:22 -07:00
gsxdsm
b8f7f9e75c FN-8701: standardize tool-call detail displays
Standardize expandable tool-call payloads across dashboard chat and log surfaces.

- Add a shared formatter and detail renderer that preserves complete browser-available arguments and results.
- Use compact previews with wrapped, scrollable expanded payloads in chat, activity, and agent logs.
- Cover formatting and rendering behavior with dashboard tests and document the display contract.

Files changed:
 .changeset/fn-8701-tool-call-display.md            |  7 ++
 docs/dashboard-guide.md                            |  4 +-
 .../dashboard/app/components/AgentLogViewer.tsx    | 12 +++-
 packages/dashboard/app/components/ChatView.css     | 37 ++---------
 .../app/components/StandardChatSurface.tsx         | 56 +++++++---------
 packages/dashboard/app/components/TaskChatTab.css  | 17 -----
 packages/dashboard/app/components/TaskChatTab.tsx  | 31 +++++----
 .../dashboard/app/components/ToolCallDetails.css   | 52 +++++++++++++++
 .../dashboard/app/components/ToolCallDetails.tsx   | 77 ++++++++++++++++++++++
 .../__tests__/AgentLogViewer.rendering.test.tsx    |  8 +++
 .../components/__tests__/ChatView.core.test.tsx    | 24 +++++++
 .../app/components/__tests__/TaskChatTab.test.tsx  | 33 +++++++---
 .../__tests__/TaskPlannerChatTab.test.tsx          | 19 ++++++
 13 files changed, 275 insertions(+), 102 deletions(-)

Fusion-Task-Id: FN-8701

Fusion-Task-Lineage: 86513f9a-31d4-45fb-97fe-1f0c73d0e5b3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-08-01 09:32:37 -07:00
gsxdsm
4f929acc10 fix(dashboard): stop over-aggressive component unmounts (keep-alive for planning, terminals, popups) (#2420)
Implements
docs/plans/2026-07-22-001-fix-dashboard-remount-churn-plan.md: every
confirmed source of unnecessary unmount/remount churn in the dashboard,
plus a keep-alive layer for conversation- and terminal-bearing surfaces.

## What changed

**Keying / component identity (U1–U3)**
- Streaming chat segment key no longer embeds `entries.length` — an
expanded thinking block stays expanded while entries stream into it
(R1).
- Dock task list keys `TaskCard` rows by `task.id` (occurrence suffix
only for the duplicate-id anomaly) instead of `id-index` — no remount on
reorder/filter/status change (R2).
- `ProviderStatusBadge` / `GitHubStatusBadge` hoisted out of
ModelOnboardingModal's render body (R3); MCP server rows key by
`server.name` alone (R4).

**Keep-alive layer (U4–U6)**
- New shared `KeepAliveView` wrapper: visible = in-flow flex child;
hidden = out-of-flow `position:absolute; inset:0` with
`visibility:hidden; pointer-events:none` + `aria-hidden` (never
`display:none`, so xterm geometry never collapses).
- Planning Mode renders as a kept-alive sibling of the MainContent
switch after first open (per-project latch mirroring Quick Chat). While
hidden, the session-list SSE, recovery poll, and elapsed ticker suspend
via a new `active` prop; reveal re-subscribes and refreshes the sessions
list once. Payload-carrying entry points (initial-plan handoff, resume)
and project switches remount via a new
`modalManager.planningEntryGeneration` key, preserving pre-keep-alive
fresh-open semantics. `recordResumeEvent` instrumentation records
`remount` on first activation and `route-active` on reveal.
- Task-detail Terminal / Worktree-terminal / Planner-chat tabs stay
mounted-but-hidden after first open (per-task latches; task switch/close
still disposes fully). `SessionTerminal` gains `active`: reveal refits +
forces a font remeasure, and if the WS died while hidden it re-runs the
full attach lifecycle (dead-socket recovery).
- Popped-out task windows hide via FloatingWindow `hidden` instead of
leaving the render array; `TaskDetailContent` gains `active` so hidden
popups close their SSE/EventSource channels while the terminal WS stays
open. `visiblePoppedOutTaskEntries` remains the Escape-shortcut
consumer.

**Planning Mode internal-transition audit (U7)**
- Audit findings: session-list mode and mobile list/detail flips are
CSS-class transitions over one always-mounted detail pane (no
state-discarding unmounts); re-selecting the active session is an
early-return visibility restore; session switching intentionally reloads
from the session row (stream re-attach for generating sessions);
remaining index keys are on stateless lists. No product-code defects
found; regression tests now lock the always-mounted invariant on desktop
+ mobile.

**Cheap-view state (U8)**
- CommandCenter (active sub-tab + date range) and DevServerView
(selected script/task + typed-but-unsent command) persist per project
via `modalPersistence` and restore after their (intentional) unmount
round-trips. Also fixed the candidate auto-fill effect clobbering a
customized non-empty command.

## Symptom Verification
- **Original symptom:** streaming thinking blocks collapsed mid-stream;
terminals reconnected and lost scroll/input on tab flips; Planning Mode
lost in-flight interviews on navigation; popped-out windows vanished
off-view; dock cards remounted on reorder.
- **Exact reproduction:** (1) expand a thinking block during a stream;
(2) run a command in the Terminal tab, flip to Plan and back; (3) start
a planning interview, navigate Board and back; (4) pop out a task with
board/list-only scoping and switch views; (5) change a dock task's
status.
- **Assertion it is gone:** component-identity/instrumentation tests in
TaskChatTab, SessionTerminal, TaskDetailModal
(worktree/planner-chat/tabs), PlanningModeModal keep-alive +
internal-transitions, App keep-alive round-trip, and
App.taskPopupViewGating assert no remount and preserved state for each
repro, across desktop and mobile breakpoints.

## Verification
- File-scoped vitest: 23 files / 1091 tests green (all touched suites
plus FloatingWindow, TerminalModal, TaskPlannerChatTab,
lazy-loaded-views guard, App suites).
- `pnpm verify:fast`: PASS (13 steps — scoped typecheck/build, CLI
build, boot smoke).
- `pnpm check:changesets`: passes; changeset
`fix-dashboard-remount-churn` (`@runfusion/fusion` patch, labeled
format).
- Known pre-existing failures NOT caused by this branch (verified
failing at base a224c1111 in a clean worktree): 7 tests in
`TaskDetailModal.oversight-controls/oversight-mobile/models-progress-workflow`.
- jsdom cannot prove rendered-grid correctness for xterm reveal; per the
plan's risk note, manual browser verification of terminal reveal remains
recommended.

🤖 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**
* Switching views or tabs no longer resets Planning Mode, task details,
terminals, planner chats, or popped-out task windows.
  * Streaming content remains expanded and stable as new entries arrive.
* Hidden views suspend background activity and resume correctly when
shown.
  * Terminal sessions reconnect automatically when needed.

* **Improvements**
  * Command Center and Dev Server selections persist per project.
  * Custom Dev Server commands are preserved while browsing suggestions.
* Improved stability when reordering task lists and updating server
states.

* **Documentation**
* Updated dashboard guidance for hidden, retained task pop-ups and view
transitions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 21:50:47 -07:00
gsxdsm
ba40942a10 batch-dashboard-app: 75 → 2 across packages/dashboard/app — the last two are deliberate, not missed (#2772)
**Batch branch is live: `batch-dashboard-app`.** Push conversions here
as commits rather than opening per-file PRs — that is the CI-run
bottleneck this model removes.

**One-line ownership note for you to arbitrate:** you have addressed me
as U11, U12 and U7 at different points, so the `u12 worker ->
batch-dashboard-app` mapping is ambiguous from my side. I claimed it
because `dashboard/app` is where I have done the most work this session
(TaskContextMenu, Column, TaskCard, TaskDetailModal, columnRoles,
taskActivity) and I know which of its guards are load-bearing fallbacks.
**If another worker is the intended owner, say so and I will hand the
branch over rather than both of us pushing to it** — two workers on one
shared branch is exactly what silently discarded a reviewed fix in #2645
today.

## The work order (measured at branch point, tests excluded)

**75 guards across 32 files.** Largest: `TaskContextMenu.tsx` 9 ·
`Column.tsx` 7 · `ListView.tsx` 6 · `TaskDetailModal.tsx` 4 · then a
long tail of 3s, 2s and 1s. Full per-file list is in the committed work
order so feeders can claim without re-measuring.

## Two rules this surface keeps tripping on

**1. A literal after `??`, or in the `else` of a `flags ?` ternary, is a
DEGRADED-MODE answer — not an unconverted guard.** Two real states reach
it: the **pre-load window** (board renders before the workflows fetch
resolves) and a card stranded on an id its workflow no longer declares.
In both, `columnFlagsById` has no entry at all. Deleting the fallback
does not remove a decision — it substitutes "no role" silently, and
affordances vanish during first paint.

Those sites reach 0 by **marking**, not deleting. Expect
`TaskContextMenu.tsx` and the `utils` files to be **mostly marks**. A "9
→ 0" that deleted 9 fallbacks is a regression wearing a green census.

**2. A marker excuses ONLY the construct it is attached to** — the
statement or function holding the literal, not a sibling declaration.
This has cost three passes, two of them mine; my first attempt on
`reliability-metrics.ts` scored **1 of 6**. **Verify by the count
moving, not by the comment existing.** With the ratchet gate-blocking, a
mis-marked batch either wedges the gate or locks the miss into a
re-recorded baseline.

## Status

Opening commit is the work order only — **0 of 75 converted so far.** I
am near the end of my context, so I am establishing the branch and the
shared list rather than starting conversions I cannot finish cleanly.
Feeders can begin immediately; I will keep the branch rebased.

My other PR **#2762** (`live-agent-count.ts` 6 → 0) is green and
unconflicted — per your rule it should land rather than fold into a
batch, and it is `packages/core` so it belongs to batch-core anyway.

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

* **New Features**
* Task UI now resolves workflow “column roles” per task to drive
diffs/merge details, routing/steering, progress/runtime visibility, and
review badges.
* Right-dock/overflow views and dev-server now use per-task column
traits for “executing” behavior and dependency-based “Up Next”
eligibility.
* **Bug Fixes**
* Fixed bulk action selection/delete/archive eligibility and prevented
cross-workflow role leakage.
* Made in-review/stale-paused-review, stuck, and effective
executor/validator model logic role-aware.
* **Tests**
* Added regression coverage for degraded-flag behavior and ensured
resolved-flag props aren’t ignored.
  * Added a static check to fail builds on inert optional flag seams.
* **Documentation**
  * Updated batch work-order and mega-batch branch guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---

## Late addition: the seam gate was masking a real offender

`scripts/check-inert-flag-seams.mjs` matched call sites by NAME, so two
same-named functions in
different modules were conflated. I had documented that as a known
false-positive source and moved
on — reports mentioning `sortTasksForDisplayColumn` are noise, read past
them.

That annotation was the damage. Core's `sortTasksForDisplayColumn`
genuinely never receives its
`columnFlags` argument outside its own tests. The dashboard's separate
function of the same name
(`app/components/taskSorting.ts`), called with up to five arguments from
`Lane`/`Board`/`ListView`,
was raising the arg-count max and clearing core's seam. The offender was
behind a row everyone had
been told to skip.

The gate now records the module each callee is imported from and matches
it against the seam's
declaring module.

**Measured, by reverting the change:** the scan prints `17 seams, all
supplied` and emits **no row**
for the function. With the change, it is reported. Both directions
watched.

Reported on #2783 rather than fixed from outside — core owns it, and
"wire the flags" vs "drop the
parameter and let the literal stay counted" is their judgment call.
TEMPORARY allow-list entry
carries it meanwhile; the existing staleness check fails the moment the
site becomes supplied, so
the entry cannot outlive the fix.

Two known limits remain, both inherent to name matching and both
documented in the script: the
one-supplier floor, and the `__tests__` exclusion (hence the two
permanent `ALLOWED` entries).


## And the one-supplier floor, closed the same way

I wrote in the section above that the floor "hasn't cost anything yet."
That is verbatim the
reasoning that kept the imported-shadow bug alive, so I closed it
instead of leaving the note.

`best < arity` asked only whether SOME caller supplied the argument. One
correct call site cleared
the seam while every sibling took the legacy fallback — the
`isTaskStuck` defect class, where two of
three sites omitted the flags and the gate stayed green because the
third was right. Review caught
that one. A partially-supplied seam is the harder of the two:
wholly-unsupplied is uniformly wrong,
this works on the board you tested and degrades on the column you did
not.

**Measured:** dropping the flags argument at `Column.tsx`'s supplied
call site produces
`supplied by 5/6 call sites; omitted at
packages/dashboard/app/components/Column.tsx:1 (of 2)`;
restoring returns `all supplied at every call site`. Red and green both
watched.

Two real omissions found, both on `isNearDuplicateCanonicalInactive`:

- **`TaskDetailModal.tsx`** — deliberate, and it **corrects a note I
left at that site**. The old
note said hoisting the flags state was "the actual fix." It is not, for
this call: the flags in
scope describe the *modal's* task, and the canonical is a **different
task** on a column this
component never resolves. Passing them would type-check, read as a
conversion, and answer about
the wrong task — exactly what `column-role-degraded-flags.test.ts`
exists to catch. Supplying it
  correctly needs a fetch, which is a data change and out of scope.
- **`core/task-store/branch-group-ops.ts`** — genuinely wireable (the
impl is async and already
holds `store` and `canonicalId`). Reported on #2783, not edited from
outside.

Exemptions for this class are keyed by **call site**
(`<file>::<function>`), not by function name.
A name-level entry would waive every site of a partially-supplied seam,
which is backwards — its
other sites are correct and are the reason the omission is worth
reporting. Both entries carry the
same staleness check as the name-level list and cannot outlive their
fix.

Remaining known limit, now the only one: the `__tests__` exclusion,
which makes a test-only export
read as having no callers. That is what the two permanent `ALLOWED`
entries are.


## The `__tests__` exclusion, and two allow-list entries built on false
reasons

Named as the "last remaining limit" above, so it got closed too. The
scan now reads test files for
call sites — but counts them **separately**, and a test never clears a
seam. That direction is the
dangerous one: counting test callers as suppliers would have re-hidden
core's
`sortTasksForDisplayColumn`, whose only suppliers are its own tests.
Measured by lifting its
exemption: still reported.

Both permanent allow-list entries claimed the scanner couldn't see their
callers. **Both reasons
were false**, and reading tests is what proved it:

- **`evaluateMergeBlockerGuard`** — zero callers in tests either. Its
only reference in the repo is
its own declaration; never registered as a trait hook; the
`evaluateDefaultWorkflowGuards` reader
its file header credits does not exist. The `lifecycleColumns`
conversion went onto dead code, and
its note describes a crossing the guard cannot make. Reported on #2783,
including the two things I
am explicitly *not* concluding (no `"guard"` hook is registered in
production; whether that is
  residue or a dropped registration needs core's intent).
- **`isRecoverableMissingWorktreeReviewFailure`** — 5 test call sites.
It wraps
`...WithProgress`/`...NoProgress`, the live pair called from
`self-healing.ts`, both supplying
  `reviewColumns`. Entry kept, true reason recorded.

### A wrong turn, recorded because it is the failure mode this PR is
about

I first classified no-production-caller seams as *informational* when
they weren't re-exported from
a package index, reasoning that a public export might be called
externally. That silently downgraded
`sortTasksForDisplayColumn` — a confirmed real offender — from failing
to a footnote. Publication
status has nothing to do with whether there is production behaviour to
be wrong. Reverted to the
simple rule: no production caller means inert, and it fails.

It is worth stating plainly because it is the exact shape of everything
else in this PR: a change
that made the gate read *cleaner* while making it catch *less*, and it
type-checked, passed every
test, and would have reviewed fine.

### Where that leaves the check

Every blind spot named in this PR has now been closed, and **each one
produced a real defect within
minutes of closing it** — imported shadows, the one-supplier floor, the
`__tests__` exclusion. Four
verified findings went to core, one to engine. I would not read the
remaining ~240 guards' green
gates as evidence that they are clean; I would read them as untested.


## Two guards for one question, one of them worse

Having hardened the script, I checked its older twin rather than
assuming it was fine.
`resolved-flags-seams-have-suppliers.test.ts` carried its own copy of
the trailing-flags-parameter
check — written before the script existed — with **all three** holes the
script has since closed.

**Measured on one reintroduced defect** (dropping the flags argument at
`Column.tsx`'s supplied
`isNearDuplicateCanonicalInactive` call):

| | result |
|---|---|
| `scripts/check-inert-flag-seams.mjs` | `supplied by 5/6 call sites;
omitted at .../Column.tsx:1 (of 2)` |
| this test's arity half | **3 passed** |

Deleted the arity half. Redundancy between a strong and a weak check
isn't redundancy — it's a green
result available to whoever runs the weak one, and there was no signal
at the call site telling you
which you were looking at.

The **props-shape half stays**: it has no twin in the script, and I
confirmed it still fires by
reintroducing the original `PrPanel` defect (outer component stops
destructuring `taskColumnFlags`)
— it reports `PrPanel declares taskColumnFlags but never takes it`.

Dashboard app suite: **113 files / 3921 tests** (was 3922 — the deleted
case is the difference).


## The gate started catching defects as they landed

Syncing with main brought in three fresh conversions from other workers.
The hardened check flagged
all three immediately — the first time these guards have fired on
someone else's landed code rather
than on my own.

- **`TaskCard`** — `getRunningOptionalGateBadge(task)` omitted flags
while *both* `ListView` sites
supplied. Fixed, and `taskColumnFlags` added to the `useMemo` deps: no
`exhaustive-deps` rule here,
so a memo that reads flags without listing them keeps the first-paint
`undefined` answer and
  reproduces the bug through staleness instead of omission.
- **`TaskTokenStatsPanel`** — `getTotalAgentActiveMs` omitted while
`TaskCard` supplied, so the same
runtime number came from the real column on a card and from legacy ids
in the detail modal. Now
takes `columnFlags`, supplied from `detailColumnFlags` — correct here
because the panel renders the
  modal's **own** task, unlike the near-duplicate canonical above.
- **`ListView` ×2** — passed `columnFlagsById.get(task.column)`, the
cross-workflow **union**. A task
whose own workflow doesn't declare that column gets a *neighbour
workflow's* traits. The landed
comment justified it as "this list already owns `columnFlagsById`" —
exactly the reasoning
`column-role-degraded-flags.test.ts` exists to reject. It failed on
merge and is how I found this.

Also: the `getTotalAgentActiveMs` exemption I was carrying
**self-retired**. Main wired the seam, the
staleness check failed the entry, and I removed it. That mechanism has
now paid for itself once.

### Pre-existing, NOT from this PR: `App.test.tsx` is red on main

`app/components/__tests__/App.test.tsx` fails **10 of 141** identically
with my changes, with my
changes stashed, and with main's own `App.tsx` restored. Not mine, and
not in the merge gate.

**Bisected on clean `main` checkouts, so this is measured rather than
inferred:**

| commit | date | result |
|---|---|---|
| `main~400` (`41d60f0355`) | 2026-07-25 | **140 passed** (140 tests) |
| `main~275` (`74d6513fae`) | 2026-07-27 | 3 failed / 141 |
| `main~210` (`d2ce1ba8b5`) | 2026-07-29 | 10 failed / 141 |
| `main` (`6fc98fd6c7`) | 2026-07-30 | 10 failed / 141 |

So it is **not one regression** — it degraded in two stages across
2026-07-25 → 07-29, and the test
file itself changed in that window (140 → 141 tests). Three commits
touched it there:
`73b2a32e2b`, `f26cbedf4f`, `f157bf7460`. That window overlaps the
workflow-owned lifecycle
migration, which is suggestive but not something I confirmed.

The failures are render-level, not assertion-level — `Unable to find an
element with the text: + New
Task`, `Unable to find role="dialog"`, `Unable to find ... Back nav
task`. The board appears to
render nothing. That reads like a real regression or a harness mismatch
after the lifecycle
migration, not a flake, so I have deliberately **not** quarantined it —
quarantine is for flakes, and
using it here would hide the signal. Flagging for whoever owns
`App.tsx`.

My suites: `app/__tests__` **113 files / 3921 tests** green, `tsc` 0,
lint 0, census `--strict` 0,
seam gate 0.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 12:46:12 -07:00
gsxdsm
31e49b684a TAKING default-workflow-hooks.ts + executor.ts + live-agent-count.ts + 6 dashboard files: reopen semantics by role, and the census's blind spot in both directions (13 sites) (#2628)
Batched conversion of every lifecycle-column guard I hold, plus the
three the census could not see. **Six files to zero, repo-wide 60 → 49
by a comment-stripped unanchored sweep.** Each conversion has an
isolated revert proof and a paired negative case, and the one code move
is a separate commit from the behavior changes.

## Per-file before → after

Counts from a comment-stripped, unanchored `(===|!==) ["']triage["']`
sweep over `packages/*/src` + `plugins/*/src`, excluding tests.

| file | before | after | note |
|---|---:|---:|---|
| `core/default-workflow-hooks.ts` | 4 | **0** | |
| `core/task-store/moves.ts` | 5 | **4** | only the flag-ON mirror
converted; the flag-OFF inline block is the parity reference and stays |
| `engine/executor.ts` | 3 | **0** | **absent from the 45-guard list** —
see below |
| `core/live-agent-count.ts` | 2 | **0** | duplication removed; answer
deliberately unchanged |
| `engine/replan-target.ts` | 2 | **0** | both were comment prose, not
guards |
| `core/agent-prompts.ts` | 3 | **0** | ROLE comparisons, never column
guards |
| `engine/usage-limit-detector.ts` | 2 | **0** | ROLE comparisons |
| `dashboard/app/components/DocumentsView.tsx` | 1 | **0** | real column
guard |
| `dashboard/app/components/TaskChatTab.tsx` | 2 | **0** | ROLE |
| `dashboard/app/components/AgentLogViewer.tsx` | 1 | **0** | ROLE |
| `dashboard/app/components/effective-model-resolution.ts` | 1 | **0** |
ROLE |
| `dashboard/app/hooks/useTasks.ts` | 1 | **0** | ROLE |
| `dashboard/…/command-center/MissionControlPanel.tsx` | 1 | 1 | alias
table, marked `DELIBERATE-LITERAL` with its reason |

## The census errs in BOTH directions

This is the finding I would most like carried into the remaining work.

- It **flagged 10 sites that were never column guards.** `role ===
"triage"` / `agentType === "triage"` compare an **AGENT ROLE**. The
planner *lane* is named `triage` and keeps that name — U11 removed the
*column*. Worse than noise: the obvious "finish the migration" edit is
to rename the role, and that silently empties the planner's prompt
template and mis-binds its model markers. `PLANNER_AGENT_ROLE` now names
it, so the two vocabularies are distinguishable by grep and a rename
fails loudly (revert proof: 4 tests, two of them pre-existing).
- It **missed 3 real guards in `executor.ts`**, because the pattern
matches `column`/`toColumn`/`fromColumn` and those locals are named
`from` and `originColumn`. A census keyed on variable names will keep
missing guards wherever a local was named for its role in the function.

## Two real defects, not tidying

**1. A renamed board could merge with its re-review never run.**
`default-workflow-hooks.ts` is named for the default workflow, but the
store runs it on the flag-ON path for *every* workflow — the trait
registry resolves hooks by trait id, not by workflow. Its reopen
predicates listed the default lineage's column names, so on a renamed
board **no reopen effect fired at all**. One of them clears
`workflowStepResults`, which `getTaskMergeBlocker` reads: a card bounced
out of review carried its old `passed` result back in, and that
satisfies the merge gate. Same regression the graph-owned-crossing
carve-out exists to prevent, arriving through the other door. (Two
smaller ones rode along: failure state never cleared on a renamed
reopen, and an operator dragging a card back to the queue never parked
it, so the scheduler re-dispatched what they had just pulled back.)

**I forgot the carve-out on my first pass, and that was worse than not
converting.** A role-resolved clear plus a *name*-matched exemption
means a renamed board takes the clear and never the exemption,
destroying the remediation input the graph had just written. My own
paired negative test caught it.

**2. The last-resort recovery for completed-but-stranded work did not
exist off the default lineage.** In `recoverCompletedTask`,
`promotedFromPlannerColumn` was false on a renamed board, so finished
work resting in the planning lane was never promoted — the code fell
through to `handoffTaskToReview` straight from the planning column, and
role adjacency has no planning → review edge, so the handoff was
rejected and the card stayed stuck with its work complete. I converted
the promotion **target** too: resolving the lane and then moving to a
literal `in-progress` is the half-conversion I have already been burned
by twice this program, where the guard starts admitting cards and the
move then sends them to a column the board does not declare.

## E2E evidence

`renamed-board-reopen.pg.test.ts` drives a **real PostgreSQL store** and
a real `moveTask` on a workflow whose columns carry the standard traits
under non-default names. The unit tests cannot show this: if `moves.ts`
passed `undefined`, every unit case still passes via the no-basis
fallback while the real board keeps the old behavior. **Proof it is
load-bearing: forcing `moveLifecycleColumns` to `undefined` fails 2 of
3.** The executor suite covers both the split-role and the MERGED
post-U11 shape.

## Revert proofs, isolated per site

| change reverted | result |
|---|---|
| reopen predicate → literal names | 4 of 10 fail |
| reopen field clears → literal names | 2 of 10 fail |
| `userPaused` hold lane → literal `todo` | 1 of 10 fail |
| graph carve-out → literal names | 1 of 10 fail |
| store passes `undefined` lifecycle columns | 2 of 3 fail (real PG) |
| `promotedFromPlannerColumn` → literals | 3 of 7 fail |
| two-hop condition → `=== "triage"` | 1 of 7 fails |
| promotion target → `"in-progress"` | 3 of 7 fail |
| `isPlannerColumnFor` → literals | 1 of 7 fails |
| live-agent-count: one arm dropped | 2 of 11 fail |
| DocumentsView: trait branch removed | 3 of 7 fail |
| planner role renamed to `"planner"` | 4 fail (2 pre-existing) |

Every conversion is paired with a negative case (a forward move, a
not-a-planner-lane card, a default-lineage card, a renamed column with
no traits), so neither "always fire" nor "never fire" can pass for
"resolve the role".

## Deliberately NOT converted, with reasons

- **`moves.ts` flag-OFF inline block (4).** That branch *is* the legacy
path, kept verbatim so the two can be parity-checked. Converting it
erases the reference implementation.
- **`live-agent-count.ts`'s no-flags fallback.** Reachable, and there is
nothing to resolve from — `enrich…FromFlags` exists for callers with
board flags rather than an IR, so a column missing from that map is the
renamed case. "Not intake" is as much a guess as "todo is intake", and
Running/Waiting are complements, so a card matching neither arm is
reported as neither and the footer's queued total under-reports it. The
real fix is at the caller; four new cases pin that flags override the
legacy answer **in both directions**. What did change is the
duplication: two hand-written copies of one rule now call one named
function.
- **`MissionControlPanel`'s `FUNNEL_STAGES`.** An alias table of column
*names* where `triage` sits beside `signal` and `backlog`. Command
Center aggregates across projects, so there is no single workflow to
resolve traits from — the honest conversion is a data change, not a
predicate change.
- **`DocumentsView` with no traits.** Same no-basis rule; the documents
list is full of historical columns absent from the current board. A case
asserts a renamed column with no traits still reads as "working",
documenting the gap rather than hiding it.

## Fixture findings

Each cost a red run that looked like the code under test:

- a `merge-blocker` column needs a reachable merge-class node, or
`parseWorkflowIr` rejects the workflow;
- a back-edge must be `kind: "rework"`, and a rework edge is legal only
**into** a node with `config.reworkRegion: true`;
- a workflow gets role-level transitions only when it declares wip +
review + complete + **archived** plus a planning lane — without the
archived column, adjacency falls back to order-derived neighbours and
`checking -> queued` is not a legal move at all;
- `recoverCompletedTask` only *reaches* the promotion seam when nothing
is left to gate; without passed `plan-review`/`code-review` rows it
re-enters the workflow graph and returns first, so a naive fixture
silently tests the wrong branch and every assertion reads "no moves
happened" for an unrelated reason.

## Verification

- `pnpm test:gate` **71/71**
- new suites: 10/10 reopen-semantics, 3/3 renamed-board-reopen (real
PG), 7/7 executor-planner-lanes, 7/7 documents-status-dot, 4/4
planner-role-is-not-a-column
- neighbours: 132 + 10 + 482 (gate shards), 350/351 engine
planning/replan suites, 64/64 agent-prompts, 51/51 usage-limit-detector,
11/11 live-agent-count, 11/11 dashboard hook/log suites
- the single engine failure (`executor-fast-mode-workflows.test.ts` ›
"raw fast mode still invokes non-executable review seam nodes")
**reproduces with my changes stashed** — pre-existing on `origin/main`
- typechecks clean for core, engine, and dashboard-app
(`tsconfig.app.json`; `tsconfig.json` checks nothing under `app/`);
`pnpm lint` clean

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 22:39:14 -07:00
gsxdsm
f26cbedf4f fix(dashboard): close the code-review findings on the mobile tab-discard work
An 11-reviewer pass over f157bf7460..f5163d8351 found defects in the mobile
tab-discard change set itself. This fixes them.

Silent data loss (the recurring defect class):
- AgentDetailView reconnect refetched limit:100 and replaced wholesale, so 380
  displayed lines vanished with no "Load older" and no indicator; it now
  reconciles through the shared logStreamReconcile helper.
- useActivityLog.loadMore past the cap discarded the page it had just fetched
  while advancing the cursor and leaving hasMore true, so the feed silently
  stopped paginating behind a live-looking button.
- useAgentLogs: loadMore and resyncFromServer had no mutual exclusion, a
  no-overlap resync discarded explicitly paged-back history, a resync outliving
  the reconnect delay left an unmarked gap, and the live-tail trim could evict
  the gap marker itself.
- useLiveTranscript's resync overwrote live entries that raced the refetch.

The premise itself was not fully delivered:
- useProjects, useNodes, and useMeshState never called clearInterval, so they
  polled the whole time the tab was hidden. useProjects is mounted for the
  entire session, so the page never went idle -- the primary mechanism this
  work depends on. All three now use the shared visibility gate.
- sse-bus fired onReconnect twice per reconnect cycle and fanned out ~28
  subscribers in one tick, against a ~6-connection-per-origin cap on a waking
  radio. The successful open is now the single authority, and the fan-out uses
  the same exported stagger primitive as the polling path rather than a second
  copy of the slot formula.
- A channel first subscribed during the hidden window opened a live EventSource
  and keepalive; suspension is now a module-level condition openChannel
  consults, and a channel opened inside the grace window re-arms it.

Credentials and correctness:
- The service worker persisted every GET /api/* to durable Cache Storage,
  including /api/settings with daemonToken, githubAuthToken, gitlabAuthToken
  and ntfyAccessToken in plaintext, with no exclusion and no purge path --
  "Clear all cached data" only walked localStorage. Now gated, bounded, and
  genuinely purgeable.
- useTasks cleared its own snapshot when the mount revalidation failed on a
  waking radio, so the board blanked and the next restore was empty too.
  Suspension-class failures no longer destroy the cache.
- A single-row SSE update reset lastFetchTimeMs to now while an hours-old
  hydrated snapshot was on screen, re-marking every in-progress card stuck.
- ListView's "Select all visible tasks" acted on the full filtered set while
  only 50 rows rendered, so a bulk delete reached rows the operator could not
  see. Column's search window reset keyed on a boolean, so refining a query
  kept the expanded window.

Tests that could not fail:
- App.test.tsx mocked TerminalModal as isOpen ? <div/> : null, making the
  unmount-on-close invariant unobservable; MockEventSource kept its listeners
  after close(), so cases passed with their onReconnect handlers deleted.
- The SSE resync ratchet scanned only hooks/, exempting ~13 component call
  sites -- the exact regression it exists to prevent.
- MissionControlPanel's bespoke poll and the xterm scrollback constants and
  WebGL disposal had no coverage at all.

Verified: tsc -p tsconfig.app.json clean, pnpm lint clean, pnpm
check:changesets clean, 877 tests passing across 36 scoped files.
Known unrelated red: MailboxView.test.tsx's FN-8407 CSS guard fails at HEAD
too -- this diff adds no @media rule and no .mailbox-view--mobile selector,
the only two things that assertion inspects. Left alone deliberately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 11:17:52 -07:00
gsxdsm
32adc0a153 FN-8573: add voice dictation controls to composers
Add shared voice dictation support across chat, planning, and task-creation composers.

- Add browser speech-recognition and composer insertion hooks.
- Provide a reusable mic button with accessible recording states.
- Integrate and test dictation across all supported composer surfaces.
- Document the feature and add a package changeset.

Files changed:
 .changeset/fn-8573-voice-dictation-mic.md          |   7 +
 docs/dashboard-guide.md                            |   6 +
 packages/dashboard/app/components/ChatView.tsx     |  44 +++-
 .../dashboard/app/components/ComposeChatPanel.tsx  |   8 +-
 packages/dashboard/app/components/MicButton.css    |   5 +
 packages/dashboard/app/components/MicButton.tsx    |  20 ++
 .../dashboard/app/components/PlanningModeModal.tsx |  82 ++++--
 .../dashboard/app/components/QuickEntryBox.tsx     |   4 +
 .../app/components/StandardChatSurface.tsx         | 108 +++++---
 packages/dashboard/app/components/TaskChatTab.tsx  |   4 +
 packages/dashboard/app/components/TaskComments.tsx |  66 ++---
 packages/dashboard/app/components/TaskForm.tsx     |  18 +-
 .../app/components/TaskPlannerChatTab.tsx          |   7 +
 .../app/components/__tests__/MicButton.test.tsx    |  28 +++
 .../components/__tests__/QuickEntryBox.test.tsx    |   5 +
 .../app/components/__tests__/TaskForm.test.tsx     |   5 +
 .../app/components/__tests__/insertAtCaret.test.ts |  25 ++
 .../__tests__/voice-dictation-composers.test.tsx   | 230 +++++++++++++++++
 packages/dashboard/app/components/insertAtCaret.ts |  20 ++
 .../hooks/__tests__/useComposerDictation.test.tsx  |  58 +++++
 .../app/hooks/__tests__/useVoiceDictation.test.tsx | 158 ++++++++++++
 .../dashboard/app/hooks/useComposerDictation.ts    | 112 +++++++++
 .../dashboard/app/hooks/useVoiceDictation.ts       | 277 +++++++++++++++++++++
 23 files changed, 1204 insertions(+), 93 deletions(-)

Fusion-Task-Id: FN-8573

Fusion-Task-Lineage: 905ae982-3e63-494f-aba8-e3665f00cdda

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-25 05:15:02 -07:00
gsxdsm
0ade15481d FN-8477: label planning model activity logs
Planning activity consistently identifies its model provenance while preserving legacy log compatibility.

- Emit Planning using model markers from the planning lane.
- Accept Planning and legacy Triage markers in dashboard model resolution.
- Update documentation, regression coverage, and release metadata.

Files changed:
 .changeset/fn-8477-planning-model-marker.md        |  7 +++++++
 docs/agents.md                                     |  2 +-
 packages/dashboard/app/components/TaskChatTab.tsx  |  2 +-
 .../app/components/__tests__/TaskChatTab.test.tsx  |  2 +-
 ...skDetailModal.models-progress-workflow.test.tsx |  4 ++--
 .../__tests__/WorkflowResultsTab.test.tsx          |  2 +-
 .../__tests__/effective-model-resolution.test.ts   | 24 ++++++++++++++--------
 .../app/components/effective-model-resolution.ts   | 20 ++++++++++++------
 packages/engine/src/__tests__/triage.test.ts       |  8 ++++----
 packages/engine/src/triage.ts                      |  8 ++++++--
 10 files changed, 52 insertions(+), 27 deletions(-)

Fusion-Task-Id: FN-8477

Fusion-Task-Lineage: 7ddce64a-d378-4d08-ad63-ade1b20d4b87

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-22 00:30:34 -07:00
gsxdsm
0a581f50db FN-8339: preserve manual scroll position during streaming
Keep live chat and log viewers from snapping readers back to the bottom while streamed content grows.

- Track pinned-bottom state synchronously across task chat, general chat, and agent logs.
- Follow streamed DOM and layout growth only when the reader remains at the tail.
- Add regression coverage and a patch changeset.

Files changed:
 .changeset/fn-8339-chat-scroll-follow.md           |  7 +++
 .../dashboard/app/components/AgentLogViewer.tsx    | 52 +++++++++++--------
 packages/dashboard/app/components/ChatView.tsx     |  4 ++
 packages/dashboard/app/components/TaskChatTab.tsx  | 59 ++++++++++++++++------
 .../__tests__/AgentLogViewer.layout.test.tsx       | 58 ++++++++++++++++++++-
 .../__tests__/ChatView.streaming-thread.test.tsx   | 18 ++++++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 34 +++++++++++++
 7 files changed, 195 insertions(+), 37 deletions(-)

Fusion-Task-Id: FN-8339

Fusion-Task-Lineage: 8f1290ea-de87-4edc-b343-f50c0ba55bad

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 16:23:02 -07:00
gsxdsm
a251d4105e FN-8303: delay task chat loading indicator
Prevent the Activity Live transcript spinner from flashing during default task opens or task selection.

- Delay the empty transcript loading indicator until a request remains pending.
- Scope delayed spinner state to each task to protect reused split-detail chat instances.
- Cover fast initial loads, overlay and embedded defaults, and task switching.

Files changed:
 packages/dashboard/app/components/TaskChatTab.tsx  | 35 ++++++++++++++---
 .../app/components/__tests__/TaskChatTab.test.tsx  | 44 +++++++++++++++++++++-
 .../TaskDetailModal.task-activity-chat.test.tsx    | 41 ++++++++++++++++++++
 3 files changed, 113 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-8303

Fusion-Task-Lineage: 34af8f5e-9e47-4ff6-bf08-b3bda0744dae

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 12:26:03 -07:00
gsxdsm
3b0b9a5661 FN-8214: show runtime model providers in chat
Ensure task chat role icons reflect each agent's actual runtime model.

- Parse runtime model markers from status and text log entries.
- Prefer runtime and effective models over stale task provider overrides.
- Cover provider icon precedence and fallback behavior for all chat roles.

Files changed:
 packages/dashboard/app/components/TaskChatTab.tsx        |  8 +-
 packages/dashboard/app/components/__tests__/TaskChatTab.test.tsx | 88 ++++++++++++++++++----
 2 files changed, 76 insertions(+), 20 deletions(-)

Fusion-Task-Id: FN-8214

Fusion-Task-Lineage: 1eb02ca5-469f-4a9d-932c-5cf02383b7fe

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-17 10:30:46 -07:00
gsxdsm
25df9bf4fd FN-8171: expand active task thinking by default
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>
2026-07-16 18:41:24 -07:00
gsxdsm
c2475b012d FN-8064: add proactive task chat status updates
Task-detail chat now narrates engine progress and review outcomes in real time.

- Emit bounded, redacted status rows for step lifecycle and review paths.
- Present status entries with a distinct task-chat treatment.
- Cover status narration and diagnostic sanitization with engine tests.

Files changed:
 .changeset/fn-8064-proactive-chat.md               |   7 +
 docs/architecture.md                               |   1 +
 packages/dashboard/app/components/TaskChatTab.css  |  16 ++
 packages/dashboard/app/components/TaskChatTab.tsx  |   9 +-
 .../engine/src/__tests__/executor-prompt.test.ts   |  28 +++-
 .../engine/src/__tests__/proactive-status.test.ts  |  54 +++++++
 packages/engine/src/executor.ts                    | 176 ++++++++++++++++-----
 packages/engine/src/proactive-status.ts            | 117 ++++++++++++++
 8 files changed, 365 insertions(+), 43 deletions(-)

Fusion-Task-Id: FN-8064

Fusion-Task-Lineage: c6d0a9b5-0946-4bf4-8338-e982e1cbfd53

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:47:59 -07:00
gsxdsm
d74018ff81 FN-7974: collapse chat thinking blocks by default
Collapse Thinking reasoning blocks by default so chat transcripts stay scannable without manually closing each block.

- Remove the open attribute from TaskChatTab thinking details so blocks start collapsed
- Strengthen ChatView and TaskChatTab tests for collapsed-by-default and expand-on-click across persisted, streaming, and Task Detail surfaces
- Add a patch changeset for the operator-facing transcript UX fix

Files changed:
 .changeset/fn-7974-collapse-thinking.md            |  7 ++++++
 packages/dashboard/app/components/TaskChatTab.tsx  |  6 ++++-
 .../__tests__/ChatView.core-interactions.test.tsx  | 26 +++++++++++++++++-----
 .../app/components/__tests__/TaskChatTab.test.tsx  | 13 +++++++----
 4 files changed, 41 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-7974

Fusion-Task-Lineage: 7cd9009f-3483-444c-8024-ed6b1cec3b89

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 14:15:50 -07:00
gsxdsm
2b8df56cb8 fix: escalate reviewer provider errors instead of looping on them
A rate-limited reviewer filled a task's Chat tab with 14 identical
"Reviewer using model: ..." markers and no review text, hammering an
already-limited provider.

Root cause: the reviewer was the only AI lane that never classified
provider errors, so a 429 became an UNAVAILABLE verdict. With no
validator fallback configured the fallback ladder re-ran the SAME model
instantly, and fn_review_step answered with "code review remains
blocking; retry once" — bounding the loop with prompt text rather than
code. The tool's catch-all also swallowed the error into tool output, so
withRateLimitRetry, UsageLimitPauser and RetryStormError never fired.

- reviewer: throw ReviewerProviderError for usage-limit/transient errors
  instead of laundering them into UNAVAILABLE, and never spend the
  fallback budget (which bounds bad reviews) on an outage.
- reviewer: absorb flaky-network blips in-lane via withRetry with
  jittered backoff; rate limits still escalate immediately.
- executor: re-raise the fatal after the prompt via
  throwDeferredReviewerFatal — pi-agent-core converts tool throws into
  tool_error results, so a tool cannot throw out of session.prompt().
- executor: give code review a real MAX_CODE_REVIEW_UNAVAILABLE_RETRIES
  counter, mirroring the plan/spec limiter.
- reviewer: dedupe the model marker on text, so same-model retries stay
  silent while a genuine model switch still emits.

Also fixes the run-on rendering: AgentLogType gains `status` for complete
engine messages. `text` means "streamed delta" and is re-glued with
join(""), which is why N standalone markers rendered as one string. The
split is at the type, not a separator — a separator would reintroduce the
FN-5787/5789/5803 streamed-spacing regression.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 12:54:16 -07:00
gsxdsm
2797803c0b FN-7503: add agent log timing metrics
Record and surface request first-token latency and tool processing duration in task logs.

- Add optional agent log timing fields and persist them in file-backed task logs.
- Track Time To First Token from the first visible model output per agent logger request.
- Track FIFO tool durations for tool result and error rows without storing sensitive payloads.
- Render TTFT and duration badges in task chat and agent log viewers with regression coverage.
- Document the new persisted timing fields and add a patch changeset for the CLI package.

Files changed:
 .changeset/fn-7503-agent-log-timing.md             |   7 ++
 docs/storage.md                                    |   1 +
 .../src/__tests__/agent-log-file-store.test.ts     |  35 ++++++
 .../src/__tests__/store-agent-log-file.test.ts     |  28 +++++
 packages/core/src/agent-log-file-store.ts          |  19 ++++
 packages/core/src/store.ts                         |  13 +++
 packages/core/src/types.ts                         |   4 +
 .../dashboard/app/components/AgentLogViewer.css    |  33 ++++++
 .../dashboard/app/components/AgentLogViewer.tsx    |  39 ++++++-
 packages/dashboard/app/components/TaskChatTab.css  |  23 +++-
 packages/dashboard/app/components/TaskChatTab.tsx  |  17 ++-
 .../__tests__/AgentLogViewer.rendering.test.tsx    |  24 +++++
 .../app/components/__tests__/TaskChatTab.test.tsx  |  18 ++++
 packages/engine/src/__tests__/agent-logger.test.ts | 120 ++++++++++++++++++---
 packages/engine/src/agent-logger.ts                |  97 ++++++++++++++---
 15 files changed, 446 insertions(+), 32 deletions(-)

Fusion-Task-Id: FN-7503

Fusion-Task-Lineage: 7e62034f-4c35-420d-a670-3f7f4a7948df

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-04 10:42:21 -07:00
gsxdsm
4378053433 FN-7386: overlay Activity expand controls and remove Raw duplicate
Overlay Activity expansion controls while keeping Raw logs to a single fullscreen affordance.

- Move Live and Feed Activity expand controls into overlaid buttons instead of a reserved toolbar row.
- Let Raw logs rely on AgentLogViewer fullscreen controls, including loading and empty states, to avoid duplicate expand buttons.
- Update responsive CSS and regression coverage for Activity overlay behavior and Raw fullscreen uniqueness.
- Add a patch changeset for the dashboard Activity control fix.

Files changed:
 .changeset/fn-7386-activity-expand.md              |  7 ++++
 .../dashboard/app/components/AgentLogViewer.css    |  6 ++++
 .../dashboard/app/components/AgentLogViewer.tsx    | 34 ++++++++++++-------
 packages/dashboard/app/components/TaskChatTab.tsx  |  2 +-
 .../dashboard/app/components/TaskDetailModal.css   | 36 ++++++++++++++------
 .../dashboard/app/components/TaskDetailModal.tsx   | 29 +++++++++--------
 .../TaskDetailModal.attachments-and-tabs.test.tsx  | 38 ++++++++++++++++++----
 ...etailModal.responsive-and-dependencies.test.tsx | 17 ++++++++++
 8 files changed, 128 insertions(+), 41 deletions(-)

Fusion-Task-Id: FN-7386

Fusion-Task-Lineage: 93728fc2-785d-44de-9903-b61df4911053

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 11:07:32 -07:00
gsxdsm
67f93cedd9 FN-7370: show thinking effort in model log markers
Display configured thinking effort alongside runtime task-log model markers.

- Add a shared formatter for model marker annotations and use it for triage, executor, reviewer, and workflow-step logs.
- Teach dashboard model parsing to ignore parenthesized marker diagnostics while preserving provider/model resolution.
- Cover thinking-effort markers with engine and dashboard tests, docs, and a patch changeset.

Files changed:
 .changeset/fn-7370-thinking-effort-model-logs.md   |  7 +++
 docs/agents.md                                     |  2 +
 packages/dashboard/app/components/TaskChatTab.tsx  |  7 +--
 .../app/components/__tests__/TaskChatTab.test.tsx  |  6 +--
 ...skDetailModal.models-progress-workflow.test.tsx |  6 +--
 .../__tests__/WorkflowResultsTab.test.tsx          |  6 +--
 .../__tests__/effective-model-resolution.test.ts   | 17 ++++--
 .../app/components/effective-model-resolution.ts   | 23 +++++---
 .../src/__tests__/executor-model-marker.test.ts    | 62 ++++++++++++++++++++++
 .../engine/src/__tests__/executor-test-helpers.ts  |  4 ++
 .../__tests__/executor-workflow-step-model.test.ts | 23 +++++++-
 packages/engine/src/__tests__/pi.test.ts           | 12 ++++-
 packages/engine/src/__tests__/reviewer.test.ts     | 37 +++++++++++++
 packages/engine/src/__tests__/triage.test.ts       | 20 ++++++-
 packages/engine/src/executor.ts                    | 17 ++++--
 packages/engine/src/pi.ts                          | 19 +++++++
 packages/engine/src/reviewer.ts                    |  7 +--
 packages/engine/src/triage.ts                      |  4 +-
 18 files changed, 244 insertions(+), 35 deletions(-)

Fusion-Task-Id: FN-7370

Fusion-Task-Lineage: 2c94a20c-77e1-41db-8af0-76239b30e3c4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 09:30:00 -07:00
gsxdsm
d8f3cc64ae FN-7356: fix mobile chat send taps
Make task chat and planner chat submit reliably from mobile send buttons.

- Submit touch and pen send-button interactions on pointer down before soft-keyboard blur can consume the tap.
- Add synchronous duplicate-send guards for task chat and planner chat send flows.
- Cover one-tap mobile send behavior and duplicate prevention in chat component tests.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-7356-mobile-chat-send.md             |  7 +++
 packages/dashboard/app/components/TaskChatTab.tsx  | 25 +++++++-
 .../app/components/TaskPlannerChatTab.tsx          | 36 +++++++++++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 65 +++++++++++++++++++++
 .../__tests__/TaskPlannerChatTab.test.tsx          | 67 +++++++++++++++++++++-
 5 files changed, 194 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-7356

Fusion-Task-Lineage: 90b243e0-ae36-459d-bf01-112219e7865b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 07:33:56 -07:00
gsxdsm
35d37d603d fix(FN-7344): compact planner and activity chat inputs 2026-07-01 00:07:42 -07:00
gsxdsm
5ff81cb460 FN-7343: Remove task chat steering guidance copy
Remove the visible steering/refinement guidance shell from task Activity chat while preserving composer behavior.

- Drop the TaskChatTab composer label/hint affordance and stale aria-describedby wiring.
- Keep accessible form names and existing steering/refinement send flows intact.
- Update dashboard docs, regression tests, and the published package changeset for the copy removal.

Files changed:
 .changeset/fn-7343-task-chat-copy.md               |  7 ++++
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/TaskChatTab.css  | 29 ---------------
 packages/dashboard/app/components/TaskChatTab.tsx  | 24 +++++--------
 .../app/components/__tests__/TaskChatTab.test.tsx  | 41 +++++++++++++---------
 .../TaskDetailModal.task-activity-chat.test.tsx    | 13 ++++---
 .../components/__tests__/TaskDetailModal.test.tsx  | 15 ++++----
 7 files changed, 59 insertions(+), 72 deletions(-)

Fusion-Task-Id: FN-7343

Fusion-Task-Lineage: ebcffb2c-a42e-46af-8291-1ff77bcec2c6

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 23:45:02 -07:00
gsxdsm
863c5ce83f FN-7325: rename Activity Current to Live
Renames the task-detail Activity Current segment to Live and makes expansion available across Activity views.

- relabel Activity Current as Live while preserving the legacy internal current segment routing
- move the Activity expand/collapse control to the shared Activity toolbar for Live, Feed, and Raw Logs
- update expanded Activity layout, docs, tests, and release notes for the shared behavior

Files changed:
 .changeset/fn-7325-activity-live-expand.md         |   7 ++
 docs/dashboard-guide.md                            |   8 +-
 packages/dashboard/app/components/TaskChatTab.tsx  |   6 +-
 .../dashboard/app/components/TaskDetailModal.css   |  53 ++++++++++-
 .../dashboard/app/components/TaskDetailModal.tsx   | 103 ++++++++++++---------
 .../app/components/__tests__/TaskChatTab.test.tsx  |  12 +--
 .../TaskDetailModal.attachments-and-tabs.test.tsx  |  90 ++++++++++++++++--
 .../__tests__/TaskDetailModal.rendering.test.tsx   |   2 +-
 .../components/__tests__/TaskDetailModal.test.tsx  |   8 +-
 9 files changed, 213 insertions(+), 76 deletions(-)

Fusion-Task-Id: FN-7325
Fusion-Task-Lineage: 1aee503b-ace8-4238-a9f9-3e536a43c1f8
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 23:44:59 -07:00
gsxdsm
f677ab4f19 FN-7309: add Activity steering composer labels
Make Activity Current clearly expose steering and refinement entry points.

- Add explicit Steering comment and Refinement request labels with accessible hints to the Activity Current composer.
- Keep Feed and Raw Logs read-only while preserving done-task Summary defaults and legacy Activity Current links.
- Cover desktop, mobile, embedded detail, completed-task, and segment-switching behavior in dashboard tests.
- Document the Activity steering affordance and add a patch changeset for the published CLI package.

Files changed:
 .changeset/fn-7309-activity-steering.md            |  7 ++
 docs/dashboard-guide.md                            |  9 +--
 packages/dashboard/app/components/TaskChatTab.css  | 29 ++++++++
 packages/dashboard/app/components/TaskChatTab.tsx  | 22 +++++--
 .../dashboard/app/components/TaskDetailModal.tsx   | 12 +++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 19 +++++-
 .../__tests__/TaskDetailModal.summary-tab.test.tsx | 22 +++----
 .../components/__tests__/TaskDetailModal.test.tsx  | 77 ++++++++++++++++++++++
 8 files changed, 173 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-7309
Fusion-Task-Lineage: 0674bf35-b0a3-4fa7-81c3-4312024c9c53
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 16:23:12 -07:00
gsxdsm
2a5a108123 FN-7265: preserve workflow on refinements
Preserve workflow context when creating refinement tasks from completed or reviewed work.

- Inherit explicit source workflow selections when creating refinement tasks and seed the new card into the workflow entry column.
- Write task rows and workflow-selection rows atomically so refinements cannot be stranded outside their intended board.
- Clear successful done-task chat refinement composer bubbles and document the dashboard behavior.
- Add core and dashboard regression coverage for refinement workflow preservation.

Files changed:
 .changeset/fuzzy-refinements-dance.md              |   7 +
 .changeset/preserve-refinement-workflow.md         |   7 +
 docs/dashboard-guide.md                            |   3 +-
 .../src/__tests__/workflow-selection-store.test.ts | 159 +++++++++++++++++++--
 packages/core/src/store.ts                         |  55 ++++++-
 .../workflow-selection-cross-surface.test.tsx      |  41 +++++-
 packages/dashboard/app/components/TaskChatTab.tsx  |   5 +
 .../app/components/__tests__/TaskChatTab.test.tsx  |  27 +++-
 .../TaskDetailModal.definition-actions.test.tsx    |  52 +++++++
 9 files changed, 335 insertions(+), 21 deletions(-)

Fusion-Task-Id: FN-7265

Fusion-Task-Lineage: 48700e3e-9f3a-474e-806c-47db0b75fca1

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-29 22:54:50 -07:00
gsxdsm
c6c4a003f9 FN-7241: add per-block task chat timestamps
Show relative timestamps throughout task-detail chat transcript blocks.

- Add reusable timestamp rendering for text, tool, thinking, and user message blocks.
- Align timestamp styling with quiet, responsive task chat metadata treatments.
- Cover empty, loading, invalid timestamp, block timestamp, and tool fallback cases.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-7241-task-chat-block-timestamps.md   |  7 ++
 packages/dashboard/app/components/TaskChatTab.css  | 44 +++++++++++-
 packages/dashboard/app/components/TaskChatTab.tsx  | 65 +++++++++++++++---
 .../app/components/__tests__/TaskChatTab.test.tsx  | 80 ++++++++++++++++++++--
 4 files changed, 179 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-7241

Fusion-Task-Lineage: 87470de1-4113-4c6a-832d-ced4b1675a76

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-29 15:28:46 -07:00
gsxdsm
d87db1490e FN-7215: compact task chat tool summaries
Compact task-detail chat tool-call history so collapsed summaries stay scannable.

- Tighten collapsed tool-call summary styling to one-line, ellipsis-friendly rows on desktop and mobile.
- Preserve count, deduped tool names, overflow, and error indicators while keeping expanded details dense.
- Document the compact task chat behavior and add regression coverage against regular Chat styling.

Files changed:
 .changeset/fn-7215-compact-task-chat-tools.md      |  7 +++
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/TaskChatTab.css  | 63 +++++++++++++++-------
 packages/dashboard/app/components/TaskChatTab.tsx  |  4 ++
 .../app/components/__tests__/TaskChatTab.test.tsx  | 50 ++++++++++++++++-
 5 files changed, 105 insertions(+), 21 deletions(-)

Fusion-Task-Id: FN-7215

Fusion-Task-Lineage: 0cec8c11-1539-4c11-96d9-ec5a7936862b

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-28 20:02:14 -07:00
gsxdsm
d08e8db2c3 FN-6932: repair dashboard copy assertions
Repair dashboard copy and keep changed-only assertions aligned with current navigation behavior.

- Restore TaskChat tool-call pluralization and inline result/error casing.
- Replace JSX entity defaults in Settings helper copy with literal apostrophes.
- Refresh dashboard tests for embedded navigation destinations and theme option parity.
- Add a patch changeset for the dashboard copy repairs.

Files changed:
 .changeset/fn-6932-dashboard-copy-repairs.md       |  7 ++
 packages/dashboard/app/components/TaskChatTab.tsx  | 27 ++++++-
 .../app/components/__tests__/App.test.tsx          | 94 +++++++++++++++++-----
 .../components/__tests__/ThemeSelector.test.tsx    |  7 +-
 .../settings/sections/GlobalGeneralSection.tsx     |  2 +-
 .../components/settings/sections/MergeSection.tsx  | 12 +--
 .../settings/sections/SchedulingSection.tsx        |  2 +-
 .../settings/sections/WorktreesSection.tsx         |  4 +-
 8 files changed, 119 insertions(+), 36 deletions(-)

Fusion-Task-Id: FN-6932

Fusion-Task-Lineage: 262f40e3-5a04-49c7-b2d4-8122d88ac488
2026-06-25 08:34:43 -07:00
gsxdsm
bd5a779423 FN-6982: remove task chat guidance copy
Remove the task Chat composer guidance line and rely on placeholders for task state cues.

- Drop the idle/guidance text block above the task Chat entry box.
- Remove obsolete localized guidance strings and generated resource types.
- Update dashboard docs, regression coverage, and release notes for the simplified composer.

Files changed:
 .changeset/fn-6982-task-chat-guidance.md           |   7 ++
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/TaskChatTab.css  |  10 --
 packages/dashboard/app/components/TaskChatTab.tsx  |  83 +----------------
 .../app/components/__tests__/App.test.tsx          |  42 ++++-----
 .../PlanningModeModal.ui-interactions.test.tsx     |   2 +-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 102 +++++++++++----------
 packages/i18n/locales/en/app.json                  |   2 -
 packages/i18n/locales/es/app.json                  |   2 -
 packages/i18n/locales/fr/app.json                  |   2 -
 packages/i18n/locales/ko/app.json                  |   2 -
 packages/i18n/locales/zh-CN/app.json               |   2 -
 packages/i18n/locales/zh-TW/app.json               |   2 -
 packages/i18n/src/resources.d.ts                   |   2 -
 14 files changed, 81 insertions(+), 181 deletions(-)

Fusion-Task-Id: FN-6982

Fusion-Task-Lineage: b880df6c-d84b-4d34-886b-f54c1d568ece
2026-06-24 23:32:52 -07:00
gsxdsm
192a2f2e94 fix(FN-6951): preserve settings saves and inline file changes 2026-06-23 01:05:13 -07:00
gsxdsm
5e55d9c46c fix(FN-6950): show effective model icons in task chat 2026-06-23 00:38:14 -07:00
gsxdsm
a147a983d5 fix(FN-6950): protect global settings and task chat icons 2026-06-23 00:31:58 -07:00
gsxdsm
4ed84be7d1 fix(FN-6950): polish dashboard modal and chat chrome 2026-06-23 00:20:55 -07:00
gsxdsm
590e064e37 feat(dashboard): remove the idle 'No agent is working' hint in task chat
The idle session hint banner is suppressed (empty) per user request — idle chats stay sendable but no longer show the banner. Done/active hints remain. Test updated to assert the banner is absent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 05:20:18 -07:00
gsxdsm
217fd74f56 FN-6866: fix active planning chat guidance
Prevent task chat from showing idle guidance while planner sessions are actively working.

- Treat triage/planning task states as active steering sessions when they are not queued, paused, or blocked.\n- Keep queued, awaiting, failed, and paused states on idle guidance even in active columns.\n- Cover inline and expanded planning chat surfaces across empty, populated, and loading transcripts.\n- Update the dashboard guide to document planning and live session bridge steering behavior.\n\nFiles changed:\n docs/dashboard-guide.md                            |  2 +-\n packages/dashboard/app/components/TaskChatTab.tsx  | 24 +++++++---\n .../app/components/__tests__/TaskChatTab.test.tsx  | 51 +++++++++++++++++++---\n 3 files changed, 66 insertions(+), 11 deletions(-)

Fusion-Task-Id: FN-6866

Fusion-Task-Lineage: 48c57515-40fa-40c1-ae3b-fec0690bba75
2026-06-21 13:25:41 -07:00
gsxdsm
2e6cfa22ff Address PR review feedback (#1694)
- TaskChatTab: add FNXC:TaskDetailChat prefix/date to the ephemeral
  active-session comment, matching the file's comment convention.
- useModalManager: clear stale planning/subtask resume-session id (and
  initial plan) when opening a fresh planning/subtask flow, so the modal
  no longer reopens into a prior session.
- boardWorkflowsCache: validate cached workflow item shape (id/name/
  columns) and taskWorkflowIds value types so a malformed cache entry
  can't pass and later crash Board on render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:25:44 -07:00
gsxdsm
7b85fead54 Address code-review findings on pause-abort + task-chat fixes
- Reliability (P3): emit an `Auto-recovered:`-prefixed log on the
  benign-todo stale-failure clear path so NotificationService
  proactively cancels the pending failure timer (recoveredStatus path)
  instead of relying only on the fire-time re-check, which is
  race-contingent when failureNotificationDelayMs is near 0. Scoped to
  the actual-clear path so the common no-failure re-queue isn't
  mislabeled as a recovery.
- Project-standards (P3): add the required yyyy-MM-dd-hh:mm stamp to the
  new FNXC comments (AGENTS.md FNXC_LOG convention).
- Maintainability (P3): extract the scheduler "queued" waiting marker to
  a named SCHEDULER_WAITING_STATUS constant.
- Testing: pin the guard's skip on a clean todo row, assert the
  Auto-recovered log fires on the stale-failure path, and add a
  paused+unassigned in-progress idle case (paused early-return wins over
  the ephemeral active-session path).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 20:07:07 -07:00
gsxdsm
b990872827 Extend ephemeral active-session detection to in-review tasks
Mirror the in-progress fix for in-review: a reviewer/merger runs
ephemerally with no assignedAgentId/checkedOutBy, so an in-review task
in an active review/merge status (reviewing, merging, merging-fix,
fixing) now reads as a live session without an assignment. A null-status
in-review row is awaiting human review, not actively worked, so it stays
assignment-gated and idle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 19:57:14 -07:00
gsxdsm
a2342cadae Fix task chat always showing "no agent is working" in ephemeral mode
isActiveAgentSession required a persistent assignedAgentId/checkedOutBy,
but the scheduler only sets those when ephemeralAgentsEnabled === false
(scheduler.ts:1857). The default is ephemeralAgentsEnabled: true
(settings-schema.ts:351), so an actively-executing in-progress task
never has either field and always read as idle, showing the
"No agent is working on this task right now" hint while an agent was
running. sessionLive only covers live CLI sessions, not ephemeral runs.

Treat assignment as sufficient-but-not-necessary: a non-blocked,
non-"queued" in-progress task is a live agent session on its own.
"queued" (the waiting marker) stays assignment-gated and in-review is
unchanged, so existing FN-6314 idle/active behavior is preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 19:48:09 -07:00
gsxdsm
bdf95f8d65 FN-6770: localize dashboard workflow and task UI strings
Localize dashboard workflow, task, setup, and pull request UI copy through the shared i18n resources.

- Replace hardcoded dashboard strings in workflow, task detail/chat/comment, setup wizard, PR, and related modal components with translation lookups.
- Add app/common namespace keys across English and secondary locale catalogs, plus regenerated i18n resource types.
- Add the published package changeset and clear the now-localized component files from the i18n lint deferral list.

Files changed:
 .changeset/fn-6770-localize-workflow-task-pr.md    |   5 +
 i18next.config.ts                                  |  17 +-
 packages/dashboard/app/components/Board.tsx        |  10 +-
 .../dashboard/app/components/PrCreateModal.tsx     |  38 +--
 packages/dashboard/app/components/PrPanel.tsx      |   2 +-
 .../dashboard/app/components/PullRequestView.tsx   |  51 ++--
 .../dashboard/app/components/SettingsModal.tsx     |  92 +++----
 .../dashboard/app/components/SetupWizardModal.tsx  |   8 +-
 packages/dashboard/app/components/TaskChatTab.tsx  | 107 ++++----
 packages/dashboard/app/components/TaskComments.tsx |   2 +-
 .../dashboard/app/components/TaskDetailModal.tsx   |  54 ++--
 .../app/components/WorkflowNodeEditor.tsx          | 109 +++++----
 .../app/components/WorkflowResultsTab.tsx          | 190 +++++++-------
 .../dashboard/app/components/WorkflowSelector.tsx  |  20 +-
 packages/i18n/locales/en/app.json                  | 268 ++++++++++++++++++--
 packages/i18n/locales/en/common.json               |  28 +--
 packages/i18n/locales/es/app.json                  | 268 ++++++++++++++++++--
 packages/i18n/locales/es/common.json               |  28 +--
 packages/i18n/locales/fr/app.json                  | 268 ++++++++++++++++++--
 packages/i18n/locales/fr/common.json               |  28 +--
 packages/i18n/locales/ko/app.json                  | 268 ++++++++++++++++++--
 packages/i18n/locales/ko/common.json               |  28 +--
 packages/i18n/locales/zh-CN/app.json               | 268 ++++++++++++++++++--
 packages/i18n/locales/zh-CN/common.json            |  28 +--
 packages/i18n/locales/zh-TW/app.json               | 268 ++++++++++++++++++--
 packages/i18n/locales/zh-TW/common.json            |  28 +--
 packages/i18n/src/resources.d.ts                   | 272 ++++++++++++++++++---
 27 files changed, 2144 insertions(+), 609 deletions(-)

Fusion-Task-Id: FN-6770

Fusion-Task-Lineage: 393b6b8a-1902-4e46-a53e-b4a0793022ca
2026-06-20 10:35:40 -07:00
gsxdsm
d2c7ff5f95 FN-6751: show idle task chat warning
Make task-detail chat disclose when sent guidance will not receive an immediate agent reply.

- Add an idle session hint for non-done tasks without an active steerable agent while keeping the composer sendable.
- Style the idle hint with warning color and expose a stable test id for regression coverage.
- Expand TaskChatTab tests across inline, expanded, empty, populated, paused, and non-live session states.
- Document the idle saved-guidance behavior in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/TaskChatTab.css  |  5 ++
 packages/dashboard/app/components/TaskChatTab.tsx  | 13 ++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 95 +++++++++++++++++++---
 4 files changed, 99 insertions(+), 16 deletions(-)

Fusion-Task-Id: FN-6751

Fusion-Task-Lineage: 21f0764d-23db-49ca-b737-3b6a8be7a918
2026-06-20 02:56:51 -07:00
gsxdsm
c261217ac1 FN-6597: add task chat timestamps
Show compact relative timestamps in task chat without adding live polling.

- Add a shared relative-time formatter for chat timestamps.
- Render muted timestamps on user message headers and agent group metadata.
- Cover timestamp formatting and chat header rendering with dashboard tests.
- Document task chat timestamp behavior in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/TaskChatTab.css  | 19 +++++
 packages/dashboard/app/components/TaskChatTab.tsx  | 23 ++++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 97 +++++++++++++++++++++-
 .../app/utils/__tests__/relativeTimeAgo.test.ts    | 32 +++++++
 packages/dashboard/app/utils/relativeTimeAgo.ts    | 23 +++++
 6 files changed, 192 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6597

Fusion-Task-Lineage: 52c54a9e-6d00-4df1-a454-2218a935ebda
2026-06-17 16:21:54 -07:00
gsxdsm
9cfa6d8176 FN-6578: keep sent chat messages at transcript tail
Ensure task-detail chat places newly sent user steering immediately after current transcript output and before later agent replies.

- Clamp optimistic user message timestamps after the latest transcript entry to handle client/server clock skew.
- Preserve the clamped display timestamp when reconciling persisted steering comments to avoid jumps or duplicates.
- Cover in-progress, in-review, done/refinement, desktop, mobile, and persisted reconciliation chat ordering cases.

Files changed:
 packages/dashboard/app/components/TaskChatTab.tsx  |  28 +++--
 .../app/components/__tests__/TaskChatTab.test.tsx  | 117 +++++++++++++++++++++
 2 files changed, 138 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-6578

Fusion-Task-Lineage: d9ba03c7-e151-41b6-9b00-87d5732f2fab
2026-06-17 14:52:55 -07:00
gsxdsm
c073fdc85c FN-6522: load earlier task chat messages
Preserve task-detail chat reading position while paging older agent log entries.

- Add top-of-transcript pagination with an explicit Load previous messages control and loading state.
- Preserve scroll anchoring when earlier log entries are prepended while keeping live bottom-follow behavior for new output.
- Cover scroll-to-top loading and manual loading with regression tests and document the behavior.

Files changed:
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/TaskChatTab.css  |  28 ++++
 packages/dashboard/app/components/TaskChatTab.tsx  |  82 ++++++++++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 163 ++++++++++++++++++++-
 4 files changed, 269 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-6522

Fusion-Task-Lineage: b93464cf-0b9a-4a73-b4f5-4f3a5e34cc89
2026-06-16 23:04:45 -07:00
gsxdsm
3d5c22c075 FN-6425: pin task chat expand control
Keep the task chat expand action visible as an icon-only overlay inside the chat view.

- Move the expand/collapse button out of the scrolling transcript and onto the task chat container.
- Style the control as a centered icon-only button with stable overlay positioning.
- Extend TaskChatTab coverage for empty, loading, populated, expanded, and scrolled transcript states.

Files changed:
 packages/dashboard/app/components/TaskChatTab.css  | 10 +++-
 packages/dashboard/app/components/TaskChatTab.tsx  | 26 +++++-----
 .../app/components/__tests__/TaskChatTab.test.tsx  | 58 +++++++++++++++++-----
 3 files changed, 68 insertions(+), 26 deletions(-)

Fusion-Task-Id: FN-6425

Fusion-Task-Lineage: 6526eb4a-4be9-472b-9595-c7fcea6971b1
2026-06-13 20:54:32 -07:00
gsxdsm
417183da9f FN-6415: send task chat on Enter
Enable the task-detail Chat composer to submit messages with standard Enter behavior.

- Submit non-empty task chat drafts on plain Enter while preserving Shift+Enter newline entry and IME composition safety.
- Keep Cmd/Ctrl+Enter as a supported send path through the same handler.
- Document the composer keyboard shortcuts and add dashboard tests for steering, refinement, newline, shortcut, and composition behavior.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/tiny-tasks-chat-enter.md                |   5 +
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/TaskChatTab.tsx  |  13 ++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 120 +++++++++++++++++++++
 4 files changed, 136 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6415

Fusion-Task-Lineage: 7d200bf6-5130-4fb8-b59c-66bccffe4265
2026-06-13 19:32:27 -07:00
gsxdsm
6a5d7ab48f FN-6405: overlay task chat expand control
Moves the task chat expand control into the transcript as an overlay while preserving accessible labels and state coverage.

- Render the expand/collapse button inside the transcript container instead of a separate toolbar.
- Add tokenized overlay positioning and mobile sizing styles for the transcript expand control.
- Extend TaskChatTab tests across loading, empty, populated, and CSS states to prevent toolbar regressions.

Files changed:
 packages/dashboard/app/components/TaskChatTab.css  | 34 +++++++++---------
 packages/dashboard/app/components/TaskChatTab.tsx  | 22 ++++++------
 .../app/components/__tests__/TaskChatTab.test.tsx  | 42 ++++++++++++++++++++--
 3 files changed, 67 insertions(+), 31 deletions(-)

Fusion-Task-Id: FN-6405

Fusion-Task-Lineage: 344d3ad0-bd57-4df2-86dc-deb8cddb76bc
2026-06-13 18:38:57 -07:00
gsxdsm
6fff41817a FN-6372: start refinements from done task chat
Done-task chat messages now create refinement tasks while preserving steering behavior elsewhere.

- Route completed-task Chat composer submissions through refineTask and show the created task ID.
- Keep non-done task sends on the existing steering-comment path with queued/live session copy.
- Cover refinement success, failure rollback, send lifecycle, and routing surfaces in TaskChatTab tests.
- Document the completed-task refinement behavior in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/TaskChatTab.tsx  |  45 +++---
 .../app/components/__tests__/TaskChatTab.test.tsx  | 152 ++++++++++++++++++++-
 3 files changed, 177 insertions(+), 22 deletions(-)

Fusion-Task-Id: FN-6372

Fusion-Task-Lineage: 201f3a5e-e951-4f70-8b92-8d270e3181de
2026-06-13 11:30:45 -07:00
gsxdsm
4838c86b8c FN-6370: add expandable task chat modal
Add a full-modal expansion affordance for task-detail chat conversations.

- Add an expand/collapse toolbar button to the task chat tab with accessible labels and icon states.
- Let the task detail modal switch into a chat-expanded layout and reset that state when leaving chat or entering edit mode.
- Cover the chat toggle and layout behavior with dashboard component tests and document the control.

Files changed:
 docs/dashboard-guide.md                            |   1 +
 packages/dashboard/app/components/TaskChatTab.css  |  22 +++++
 packages/dashboard/app/components/TaskChatTab.tsx  |  21 ++++-
 .../dashboard/app/components/TaskDetailModal.css   |  42 +++++++++
 .../dashboard/app/components/TaskDetailModal.tsx   |  13 ++-
 .../app/components/__tests__/TaskChatTab.test.tsx  |  37 ++++++++
 .../TaskDetailModal.attachments-and-tabs.test.tsx  | 100 +++++++++++++++++++++
 7 files changed, 233 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-6370
Fusion-Task-Lineage: 787300bb-b928-45cf-a5c1-7fed5f375111
2026-06-13 11:14:06 -07:00
gsxdsm
6e9f2a384d FN-6369: make task chat send control icon-only
Refine the task-detail chat composer so the send action stays narrow and inline with the input.

- Replace the composer placeholder with the steering-focused copy.
- Convert the send button to an accessible icon-only control with loading state labels.
- Keep the send control inline at mobile breakpoints and cover the behavior in tests and docs.

Files changed:
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/TaskChatTab.css  | 14 +++++++----
 packages/dashboard/app/components/TaskChatTab.tsx  | 11 ++++++---
 .../app/components/__tests__/TaskChatTab.test.tsx  | 27 ++++++++++++++++++++--
 4 files changed, 44 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-6369
Fusion-Task-Lineage: b7e0717f-4cba-4380-a08a-e01fc12985e3
2026-06-13 10:51:31 -07:00
gsxdsm
422833045c FN-6359: add latest jump control to task chat
Adds an in-transcript control for returning to the newest task chat output after reviewing older messages.

- Track whether the task chat transcript is near the bottom and preserve live-follow behavior.
- Render an accessible sticky Latest button when populated transcripts are scrolled up, including mobile styling.
- Cover empty/loading, desktop, mobile, and click-to-jump behavior in TaskChatTab tests.
- Document the Latest jump affordance in the dashboard guide.

Files changed:
 docs/dashboard-guide.md                            |  2 +-
 packages/dashboard/app/components/TaskChatTab.css  | 40 +++++++++++
 packages/dashboard/app/components/TaskChatTab.tsx  | 40 ++++++++++-
 .../app/components/__tests__/TaskChatTab.test.tsx  | 82 ++++++++++++++++++++++
 4 files changed, 162 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-6359

Fusion-Task-Lineage: 9b4a3533-2969-4f0d-a4de-6ba895662726
2026-06-13 10:20:11 -07:00