Commit Graph

30 Commits

Author SHA1 Message Date
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
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
e22c65ad11 FN-8397: separate pinned chats and retain failed edits
Separate direct-chat session groups and make message edits safely retryable.

- Render explicit Pinned and Recent sections across desktop and mobile chat lists.
- Keep inline message corrections open until edit-and-resend succeeds in Direct and Planner Chat.
- Add localized Recent labels, documentation, release metadata, and regression coverage.

Files changed:
 .changeset/fn-8397-chat-pin-separation-and-edit-save.md   |  7 +++
 docs/dashboard-guide.md                                    |  5 +-
 packages/dashboard/app/components/ChatView.css             | 10 ++++
 packages/dashboard/app/components/ChatView.tsx             | 31 ++++++++---
 packages/dashboard/app/components/StandardChatSurface.tsx  | 35 +++++++++----
 packages/dashboard/app/components/TaskPlannerChatTab.tsx   | 14 +++--
 packages/dashboard/app/components/__tests__/ChatView.core-contracts.test.tsx | 46 +++++++++++++++++
 packages/dashboard/app/components/__tests__/ChatView.message-edit.test.tsx | 60 ++++++++++++++++++++--
 packages/dashboard/app/components/__tests__/TaskPlannerChatTab.test.tsx | 10 ++--
 packages/dashboard/app/hooks/__tests__/useChat.test.ts     |  4 +-
 packages/dashboard/app/hooks/useChat.ts                    | 13 +++--
 packages/i18n/locales/{en,es,fr,ko,zh-CN,zh-TW}/app.json  |  6 +++
 17 files changed, 205 insertions(+), 36 deletions(-)

Fusion-Task-Id: FN-8397

Fusion-Task-Lineage: 4dbc664a-56a3-48c7-be9a-febd5f411c9e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-20 00:42:15 -07:00
gsxdsm
13540ee9c2 FN-8344: preserve manual planner chat scroll position
Keep Planner Chat pinned to live output only while readers remain near the transcript tail.

- Track user scroll position and distinguish programmatic anchoring.
- Preserve manually unsnapped transcript positions during streamed updates.
- Add scroll-follow regression coverage and a patch changeset.

Files changed:
 .changeset/fn-8344-planner-chat-scroll-follow.md   |   7 ++
 .../app/components/TaskPlannerChatTab.tsx          |  63 +++++++++-
 .../__tests__/TaskPlannerChatTab.test.tsx          | 134 ++++++++++++++++++++-
 3 files changed, 198 insertions(+), 6 deletions(-)

Fusion-Task-Id: FN-8344

Fusion-Task-Lineage: fde7965c-cffc-4908-90c1-3df1f3c2af75

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 19:24:52 -07:00
gsxdsm
b2977d1a7a FN-7982: clear stale planner chat streaming on fresh reply
Fix task chat showing a previous agent message while a new reply is generating by clearing streaming carriers on fresh generations.

- Clear streamingThinking and the streaming-assistant row when starting a generation without an in-flight snapshot
- Preserve text/thinking/tool restore only when attaching to a live in-flight generation
- Add regression coverage for consecutive replies that must not reuse prior stream content
- Add patch changeset for the planner chat stale-message fix

Files changed:
 .changeset/fn-7982-planner-chat-stale-message.md   |  7 ++++
 .../app/components/TaskPlannerChatTab.tsx          | 19 ++++++++--
 .../__tests__/TaskPlannerChatTab.test.tsx          | 44 ++++++++++++++++++++++
 3 files changed, 67 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7982

Fusion-Task-Lineage: 71daaa80-6d66-4940-a656-a2c42a6b03bb

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-15 12:22:33 -07:00
gsxdsm
93a93450c2 fix(FUX-015): address slash-command review feedback
Greptile/CodeRabbit review of the chat slash-command framework:

- Composer-wipe race: ChatView and TaskPlannerChatTab cleared the composer
  inside the command's success callback, silently wiping any text the user
  typed while the command was in flight. Clear on submit (before the network
  round-trip) instead — consistent with normal chat send, which also clears
  immediately and does not restore on failure.
- Attachments were silently dropped when dispatching a slash command in
  ChatView (clearing the composer revokes staged attachment URLs). Block
  dispatch with a warning toast when attachments are staged.
- CHAT_COMMANDS is now a readonly array; helper signatures accept
  readonly ChatCommand[].
- The planner command menu (commands-only) used skill-menu aria-label/empty
  copy; use command-specific copy instead.

Add regression tests: in-flight text survives command success, composer
clears on submit even on failure, attachment dispatch is blocked, and the
planner command menu uses command-specific accessible copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:14:09 -07:00
ddonaldson130
7c91824875 feat(dashboard): add slash-command framework with /steer (FUX-015)
Adds a chat command registry and the /steer command for task-bound
chats. Commands are triggered by '/' and dispatch through a common
match/dispatch path alongside existing skills autocomplete.
2026-07-10 18:14:09 -07:00
gsxdsm
2bea332ff2 FN-7685: make Planner Chat send button icon-only to match regular chat
Summary: The Planner Chat idle send button now renders icon-only, dropping its visible "Send" text span to match TaskChatTab's regular chat send button, while keeping the accessible name "Send" via aria-label.

- Removed `showSendText` prop from the planner chat send/stop button so the idle send button no longer shows a visible text span.
- Updated the CSS FNXC comment documenting that the send-text-hiding rule is now solely load-bearing for the streaming Stop button's icon-visibility contract, not the idle Send button.
- Updated the corresponding test to assert the send button has no visible text span (icon-only) while still asserting the accessible name resolves to "Send".

Files changed:
 packages/dashboard/app/components/TaskPlannerChatTab.css           | 7 +++++++
 packages/dashboard/app/components/TaskPlannerChatTab.tsx           | 5 ++++-
 .../dashboard/app/components/__tests__/TaskPlannerChatTab.test.tsx | 4 +++-
 3 files changed, 14 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-7685

Fusion-Task-Lineage: 5ec896c5-7ca3-415b-bd5f-99a49f6a21ec

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-08 09:40:59 -07:00
gsxdsm
dfb084c59e FN-7655: make planner chat stop button icon-only
Removes the visible "Stop generation" text label from the planner chat's stop button while keeping it accessible via aria-label.

- Add showStopText prop to StandardChatActionButton (defaults to showSendText) to independently control Send vs Stop visible text
- Set showStopText={false} in TaskPlannerChatTab so the streaming stop button renders icon-only
- Update TaskPlannerChatTab test to assert no visible text span on the stop button while aria-label is retained
- Add changeset for @runfusion/fusion (patch)

Files changed:
 .changeset/fn-7655-planner-stop-icon-only.md             |  7 +++++++
 .../dashboard/app/components/StandardChatSurface.tsx     | 16 ++++++++++++++--
 packages/dashboard/app/components/TaskPlannerChatTab.tsx |  3 +++
 .../app/components/__tests__/TaskPlannerChatTab.test.tsx |  4 +++-
 4 files changed, 27 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-7655
Fusion-Task-Lineage: f68a8bfa-30ba-439e-97d0-28654a614c54
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 23:26:55 -07:00
gsxdsm
1b7bb1fe18 FN-7639: wire message editing into Planner Chat
Adds the ability to edit and resend a prior user message in task-detail Planner Chat, discarding subsequent turns without reverting already-applied steering/refinement side effects.

- Wire FN-7628's editChatMessage + rewindSessionForEdit into TaskPlannerChatTab for synthetic task-planner:<id> sessions
- Add edit affordance/UI flow and message resend handling in TaskPlannerChatTab
- Ensure already-applied steering comments and refinement tasks are not reverted when a turn is discarded
- Expand TaskPlannerChatTab test coverage for edit/resend flows
- Update dashboard guide docs to describe the new Planner Chat edit behavior
- Add changeset for @runfusion/fusion (minor)

Files changed:
 .changeset/fn-7639-planner-chat-edit.md            |   7 +
 docs/dashboard-guide.md                            |   4 +-
 .../app/components/TaskPlannerChatTab.tsx          |  90 +++++++-
 .../__tests__/TaskPlannerChatTab.test.tsx          | 242 ++++++++++++++++++++-
 4 files changed, 328 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-7639

Fusion-Task-Lineage: ed568a81-12fa-42a8-9ecf-29e6c9a2a884

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:06:17 -07:00
gsxdsm
42009cfdb9 FN-7628: allow editing sent chat messages and rewinding agent responses
Adds the ability to edit a previously sent message in an agent chat, which rewinds the session/task room and regenerates the response from the edited message.

- Add chat-store support for locating/replacing a message and truncating subsequent history for a rewind
- Add a chat-manager rewind-session flow and a new register-chat-routes endpoint to rewind a room to an edited message
- Add legacy API route wiring and useChat hook support for issuing an edit request
- Add ChatView/StandardChatSurface/TaskPlannerChatTab UI affordances (edit control, styling) to trigger message edits
- Add a changeset documenting the new chat message-edit capability
- Add unit/integration tests covering chat-store rewind logic, chat-manager rewind-session behavior, chat routes, useChat, and ChatView edit UI

Files changed:
 .changeset/fn-7628-chat-message-edit.md            |   7 +
 docs/dashboard-guide.md                            |   4 +
 packages/core/src/__tests__/chat-store.test.ts     | 171 ++++++++++++++
 packages/core/src/chat-store.ts                    |  95 ++++++++
 packages/dashboard/app/api/legacy.ts               |  22 ++
 packages/dashboard/app/components/ChatView.css     |  78 ++++++
 packages/dashboard/app/components/ChatView.tsx     |  14 ++
 .../app/components/StandardChatSurface.tsx         |  87 ++++++-
 .../app/components/TaskPlannerChatTab.tsx          |   8 +
 .../__tests__/ChatView.autosize.test.tsx           |   1 +
 .../__tests__/ChatView.default-model-icon.test.tsx |   1 +
 .../components/__tests__/ChatView.draft.test.tsx   |   1 +
 .../__tests__/ChatView.hash-mention.test.tsx       |   1 +
 .../__tests__/ChatView.message-edit.test.tsx       | 262 +++++++++++++++++++++
 .../__tests__/ChatView.mobile-render.test.tsx      |   1 +
 .../components/__tests__/ChatView.rooms.test.tsx   |   1 +
 .../__tests__/ChatView.scroll-to-top.test.tsx      |   1 +
 .../components/__tests__/ChatView.test-harness.tsx |   1 +
 .../dashboard/app/hooks/__tests__/useChat.test.ts  |  98 ++++++++
 packages/dashboard/app/hooks/useChat.ts            |  60 +++++
 .../__tests__/chat-manager-rewind-session.test.ts  | 185 +++++++++++++++
 .../dashboard/src/__tests__/chat-manager.test.ts   |  12 +
 .../dashboard/src/__tests__/chat-routes.test.ts    | 124 ++++++++++
 packages/dashboard/src/chat.ts                     | 147 +++++++++++-
 .../dashboard/src/routes/register-chat-routes.ts   |  52 ++++
 25 files changed, 1429 insertions(+), 5 deletions(-)

Fusion-Task-Id: FN-7628

Fusion-Task-Lineage: 36d98989-1b75-428c-baf1-b2c7e8e78013

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-07 22:06:15 -07:00
gsxdsm
1a523e7d1b FN-7407: enable done-task planner refinements
Enable planner chat on completed tasks and let clear follow-up requests create refinements.

- Allow task-planner chat sessions for done tasks while keeping archived tasks blocked.
- Add a task-scoped refinement tool that creates follow-up tasks only from completed source tasks.
- Render refinement creation, pending, and failure states in the planner chat transcript.
- Extend planner-chat context, route, manager, and component tests for done-task chat and refinement behavior.
- Document the completed-task planner chat behavior and add a patch changeset.

Files changed:
 .changeset/fn-7407-done-planner-chat.md            |   7 ++
 docs/dashboard-guide.md                            |   5 +-
 .../app/components/TaskPlannerChatTab.tsx          |  50 +++++++-
 .../__tests__/TaskPlannerChatTab.test.tsx          |  66 ++++++++++-
 .../dashboard/src/__tests__/chat-manager.test.ts   | 126 ++++++++++++++++++++-
 .../dashboard/src/__tests__/chat-routes.test.ts    |  41 ++++++-
 .../__tests__/task-planner-chat-context.test.ts    |   5 +-
 packages/dashboard/src/chat.ts                     |  66 ++++++++++-
 .../dashboard/src/routes/register-chat-routes.ts   |   9 +-
 .../dashboard/src/task-planner-chat-context.ts     |   5 +-
 10 files changed, 360 insertions(+), 20 deletions(-)

Fusion-Task-Id: FN-7407

Fusion-Task-Lineage: b3214d89-a59c-4682-b5cd-98d7d6cc09e2

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 23:44:05 -07:00
gsxdsm
e341c0673f FN-7379: render planner questions outside tool groups
Make planner clarification prompts stay answerable when assistant messages include other tool calls.

- Extract fn_ask_question cards before grouping generic chat tool calls.
- Keep non-question tools in the existing grouped tool-call details.
- Cover persisted and streamed mixed-tool planner transcripts with actionable question assertions.
- Add a patch changeset for the planner-chat fix.

Files changed:
 .changeset/fn-7379-planner-question-cards.md       |  7 +++
 .../app/components/StandardChatSurface.tsx         | 73 +++++++++++++++-------
 .../app/components/TaskPlannerChatTab.tsx          |  3 +
 .../__tests__/TaskPlannerChatTab.test.tsx          | 48 ++++++++++++--
 4 files changed, 103 insertions(+), 28 deletions(-)

Fusion-Task-Id: FN-7379

Fusion-Task-Lineage: 5e88f991-cbcf-49d8-a815-fc44d49bad10

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 10:45:19 -07:00
gsxdsm
c194248d4b FN-7366: restore planner chat in-flight state
Planner chat now resumes active generations when task detail is reopened.\n\n- Rehydrate in-flight planner chat snapshots and reattach to the session stream after tab/modal remounts.\n- Preserve accepted optimistic user turns across provider failures while rolling back pre-acceptance failures.\n- Add regression coverage for remount reattachment, attached completion/error refresh, and accepted error reconciliation.\n- Add a patch changeset for the published Fusion package.\n\nFiles changed:\n .changeset/fn-7366-planner-chat-resume.md          |   7 +\n .../app/components/TaskPlannerChatTab.tsx          | 334 +++++++++++++--------\n .../__tests__/TaskPlannerChatTab.test.tsx          | 189 +++++++++++-\n 3 files changed, 382 insertions(+), 148 deletions(-)

Fusion-Task-Id: FN-7366

Fusion-Task-Lineage: b13b9c5e-9295-461f-b44b-f2b5a9008b4f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 09:12:30 -07:00
gsxdsm
a65633d878 FN-7368: keep accepted chat sends visible after provider errors
Preserve sent chat turns when provider failures arrive after the server accepts a stream.

- Track whether chat stream errors happen before or after server acceptance.
- Reconcile persisted user-message echoes with optimistic bubbles across global chat and planner chat.
- Preserve delivered room-chat messages when reply generation or recovery refresh fails.
- Cover accepted-error and pre-acceptance rollback behavior with focused dashboard tests.

Files changed:
 .changeset/fn-7368-chat-provider-error.md          |  7 ++
 packages/dashboard/app/api/legacy.ts               | 25 ++++--
 .../app/components/TaskPlannerChatTab.tsx          | 47 ++++++++++-
 .../__tests__/TaskPlannerChatTab.test.tsx          | 71 ++++++++++++++++
 .../dashboard/app/hooks/__tests__/useChat.test.ts  | 96 ++++++++++++++++++++++
 .../app/hooks/__tests__/useChatRooms.test.ts       | 25 ++++++
 .../app/hooks/createChatStreamHandlers.ts          | 10 +--
 packages/dashboard/app/hooks/useChat.ts            | 48 ++++++++---
 packages/dashboard/app/hooks/useChatRooms.ts       |  5 +-
 9 files changed, 305 insertions(+), 29 deletions(-)

Fusion-Task-Id: FN-7368

Fusion-Task-Lineage: b7935c3f-3604-4ed5-b32e-a6ead536a991

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 07:50:52 -07:00
gsxdsm
7457f04287 FN-7355: reuse standard chat surface for planner
Task planner chat now renders through the shared Chat surface while preserving task-scoped behavior.

- Extract shared standard chat message, streaming, tool-call, and action-button rendering for reuse outside ChatView.
- Update TaskPlannerChatTab to use the shared surface for messages, thinking output, mobile send dedupe, and stop generation.
- Cover planner chat standard-surface rendering and mobile first-tap behavior in tests, docs, and a patch changeset.

Files changed:
 .changeset/fn-7355-standard-planner-chat.md        |   7 +
 docs/dashboard-guide.md                            |   2 +-
 packages/dashboard/app/components/ChatView.css     |  18 +
 packages/dashboard/app/components/ChatView.tsx     | 795 ++-------------------
 .../app/components/StandardChatSurface.tsx         | 417 +++++++++++
 .../app/components/TaskPlannerChatTab.css          |  39 +-
 .../app/components/TaskPlannerChatTab.tsx          | 246 ++++---
 ...etailModal.responsive-and-dependencies.test.tsx |   4 +-
 .../__tests__/TaskPlannerChatTab.test.tsx          |  52 ++
 9 files changed, 693 insertions(+), 887 deletions(-)

Fusion-Task-Id: FN-7355

Fusion-Task-Lineage: 608ee0d7-3a1b-4f5f-a295-d3a4e62d759e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-01 07:33:56 -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
411f46a5ea fix(FN-7344): keep planner chat empty state at top 2026-07-01 00:13:47 -07:00
gsxdsm
35d37d603d fix(FN-7344): compact planner and activity chat inputs 2026-07-01 00:07:42 -07:00
gsxdsm
7c53c97137 fix(FN-7344): make planner chat expansion intentional 2026-06-30 23:51:16 -07:00
gsxdsm
e37260b30c fix(FN-7344): keep planner chat context expanded 2026-06-30 23:45:03 -07:00
gsxdsm
6005f89979 fix(FN-7344): compact planner chat on mobile 2026-06-30 23:45:03 -07:00
gsxdsm
7d2bd9794e FN-7337: make planner chats lazy and archive-scoped
Task planner chats now stay out of global chat history until a user interacts and are retained until task archive.

- Load task planner chat tabs with lookup-only resume before any user send.
- Show task-planner sessions in global Chat only after messages exist, including SSE refresh handling.
- Keep interacted planner chats for done tasks while deleting task-scoped planner sessions on archive.
- Cover chat store deletion, planner tab behavior, route filtering, and chat-list refresh with regression tests.

Files changed:
 .changeset/fn-7337-planner-chat-retention.md       |   7 ++
 docs/dashboard-guide.md                            |   4 +-
 packages/core/src/__tests__/chat-store.test.ts     |  44 +++++++++
 packages/core/src/chat-store.ts                    |  22 +++++
 packages/dashboard/app/api/legacy.ts               |  35 ++++++-
 .../app/components/TaskPlannerChatTab.tsx          |  13 ++-
 .../__tests__/TaskPlannerChatTab.test.tsx          |  91 +++++++++++++-----
 .../dashboard/app/hooks/__tests__/useChat.test.ts  |  41 ++++++++
 packages/dashboard/app/hooks/useChat.ts            |  15 ++-
 .../dashboard/src/__tests__/chat-routes.test.ts    | 105 +++++++++++++++++++++
 .../dashboard/src/routes/register-chat-routes.ts   |  17 +++-
 packages/dashboard/src/server.ts                   |  10 +-
 packages/engine/src/runtimes/in-process-runtime.ts |   8 ++
 13 files changed, 378 insertions(+), 34 deletions(-)

Fusion-Task-Id: FN-7337

Fusion-Task-Lineage: 7ef9ed8f-af2e-4fa9-a2b6-0e8c8a805d5e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 23:45:01 -07:00
gsxdsm
b52f92cb7c FN-7328: keep Planner Chat controls compact
Keep Planner Chat compact while preserving expanded mobile task context.

- Match the Planner Chat composer sizing to Activity chat on desktop and mobile.
- Keep the expanded mobile detail tab bar, priority, and execution-mode controls visible while hiding lower-priority metadata.
- Move and constrain the planner model badge so header actions stay compact.
- Cover the responsive layout and header ordering with dashboard tests.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-7328-planner-chat-compact.md         |  7 +++
 .../dashboard/app/components/TaskDetailModal.css   | 21 +++++++--
 .../app/components/TaskPlannerChatTab.css          | 51 +++++++++++++++++-----
 .../app/components/TaskPlannerChatTab.tsx          | 10 ++---
 ...etailModal.responsive-and-dependencies.test.tsx | 26 +++++++++--
 .../__tests__/TaskPlannerChatTab.test.tsx          |  2 +
 6 files changed, 93 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-7328

Fusion-Task-Lineage: b787d818-e65c-486b-b5f7-cd0881bf3ee0

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 23:45:00 -07:00
gsxdsm
2f5e15ac43 FN-7324: Focus task details on planner chat
Task details now prioritize the planner Chat experience while preserving Activity links and done-task summaries.

- Default active task details to Chat and render it before Activity without breaking legacy Activity tab ids.
- Add focused planner Chat expansion, pinned composer, mobile row hiding, and in-view expand/collapse controls.
- Update responsive coverage, planner-chat tests, dashboard docs, and the release changeset.

Files changed:
 .changeset/fn-7324-chat-focused-task-detail.md     |  7 ++
 docs/dashboard-guide.md                            | 11 +--
 .../dashboard/app/components/TaskDetailModal.css   | 47 ++++++++++-
 .../dashboard/app/components/TaskDetailModal.tsx   | 36 +++++----
 .../app/components/TaskPlannerChatTab.css          | 36 ++++++++-
 .../app/components/TaskPlannerChatTab.tsx          | 37 ++++++---
 ...etailModal.responsive-and-dependencies.test.tsx | 14 +++-
 .../components/__tests__/TaskDetailModal.test.tsx  | 93 +++++++++++++++++++---
 .../__tests__/TaskPlannerChatTab.test.tsx          | 18 +++++
 9 files changed, 255 insertions(+), 44 deletions(-)

Fusion-Task-Id: FN-7324
Fusion-Task-Lineage: 0699d224-7280-4959-8086-b0ea985937a2
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 23:45:00 -07:00
gsxdsm
0915377a1c FN-7314: reuse shared planner question UI
Reuse the existing question-response modal UI inside task-detail planner Chat clarification flows.

- Render planner fn_ask_question tool calls with ChatQuestionResponse, including answered read-only and duplicate-pending states.
- Preserve steering-tool confirmations while sending submitted clarification answers back through planner Chat.
- Extend parser and modal tests for multi-question payloads, submitted answers, duplicate prompts, and empty dependency labels.
- Add a patch changeset for the published Fusion package.

Files changed:
 .changeset/fn-7314-planner-question-ui.md          |  7 ++
 .../app/components/TaskPlannerChatTab.css          |  9 +++
 .../app/components/TaskPlannerChatTab.tsx          | 76 ++++++++++++++++--
 ...etailModal.responsive-and-dependencies.test.tsx |  3 +
 .../__tests__/TaskPlannerChatTab.test.tsx          | 89 ++++++++++++++++++----
 .../utils/__tests__/parseQuestionToolCall.test.ts  | 10 ++-
 .../dashboard/app/utils/parseQuestionToolCall.ts   |  6 +-
 7 files changed, 176 insertions(+), 24 deletions(-)

Fusion-Task-Id: FN-7314

Fusion-Task-Lineage: bd5da323-0ba1-4094-a965-cc2801a1c9b7

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 19:21:53 -07:00
gsxdsm
cb0d38a0c6 FN-7313: add guarded planner chat steering
Task-detail planner chat now turns only clear task change requests into persisted steering comments while keeping ambiguous requests in clarification flow.

- Add a scoped planner-chat steering tool with task-bound persistence and richer result details.
- Refresh task details and show steering confirmation, pending, and error states in the planner chat transcript.
- Expand planner chat prompt guidance and tests for clear steering, ambiguous clarification, and ordinary status questions.
- Add a published Fusion changeset for the new task chat steering behavior.

Files changed:
 .changeset/fn-7313-task-chat-steering.md           |   7 ++
 .../dashboard/app/components/TaskDetailModal.tsx   |   1 +
 .../app/components/TaskPlannerChatTab.css          |  28 +++++
 .../app/components/TaskPlannerChatTab.tsx          |  96 ++++++++++++++++-
 .../__tests__/TaskPlannerChatTab.test.tsx          |  72 ++++++++++++-
 .../dashboard/src/__tests__/chat-manager.test.ts   | 120 +++++++++++++++++++++
 packages/dashboard/src/chat.ts                     |  32 +++++-
 7 files changed, 347 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-7313
Fusion-Task-Lineage: 29da54cc-c379-4fe5-8419-be3acc712495
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 19:15:11 -07:00
gsxdsm
ddfd841b53 FN-7312: send task context to planner chat
Send bounded task state into task-detail planner chat so status and progress questions can be answered in context.

- Build reusable server-side planner chat context from task metadata, dependencies, steps, comments, activity, source, and review state.
- Pass and validate the task id on planner chat sends to keep sessions scoped to the current task.
- Update planner chat copy, docs, tests, and changeset coverage for task-aware status/progress questions.

Files changed:
 .changeset/fn-7312-task-planner-chat-context.md    |   7 +
 docs/dashboard-guide.md                            |   4 +-
 packages/dashboard/app/api/legacy.ts               |   5 +-
 .../app/components/TaskPlannerChatTab.tsx          |   5 +-
 .../__tests__/TaskPlannerChatTab.test.tsx          |  22 ++
 .../dashboard/src/__tests__/chat-manager.test.ts   |  17 +-
 .../dashboard/src/__tests__/chat-routes.test.ts    |  76 +++++
 .../__tests__/task-planner-chat-context.test.ts    | 165 +++++++++++
 packages/dashboard/src/chat.ts                     |  92 +-----
 .../dashboard/src/routes/register-chat-routes.ts   |  11 +-
 .../dashboard/src/task-planner-chat-context.ts     | 326 +++++++++++++++++++++
 11 files changed, 634 insertions(+), 96 deletions(-)

Fusion-Task-Id: FN-7312

Fusion-Task-Lineage: 90cf0fe3-3984-4a67-bb44-fce492c256eb

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 18:51:41 -07:00
gsxdsm
45509708e5 FN-7311: add planner chat starter prompts
Add guided prompts to the empty task-detail Chat tab so operators can start useful planner conversations quickly.

- Render a task-aware Chat empty state with four accessible starter prompt buttons.
- Send starter selections through the normal planner-chat stream while guarding stale session loads and stream callbacks.
- Style responsive prompt cards and document the Chat/Activity separation.
- Cover empty-state, loading, history, sending, and task-switch behavior with dashboard tests.

Files changed:
 .changeset/fn-7311-chat-starter-prompts.md         |   7 +
 docs/dashboard-guide.md                            |   2 +
 .../app/components/TaskPlannerChatTab.css          |  55 ++++-
 .../app/components/TaskPlannerChatTab.tsx          | 185 ++++++++++++---
 ...etailModal.responsive-and-dependencies.test.tsx |   3 +
 .../__tests__/TaskPlannerChatTab.test.tsx          | 252 ++++++++++++++++++++-
 6 files changed, 460 insertions(+), 44 deletions(-)

Fusion-Task-Id: FN-7311

Fusion-Task-Lineage: 5a58bc4f-1139-4c68-9ade-b79a52558bef

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 18:20:16 -07:00
gsxdsm
db7b46f60f FN-7310: add task planner chat tab
Add a dedicated task-detail Chat surface for planner-model conversations separate from Activity steering.

- Add task-scoped planner chat session creation and routing with planning-model overrides.
- Render a new top-level Chat tab next to Activity, including streaming responses, tool-call cards, and retry/error states.
- Cover planner chat tab ordering, session reuse, route validation, manager dispatch, and dashboard documentation.

Files changed:
 .changeset/fn-7310-planner-chat.md                 |   7 +
 docs/dashboard-guide.md                            |   3 +-
 packages/dashboard/app/api/legacy.ts               |  35 +++
 .../dashboard/app/components/TaskDetailModal.tsx   |  40 ++-
 .../app/components/TaskPlannerChatTab.css          | 149 ++++++++++
 .../app/components/TaskPlannerChatTab.tsx          | 322 +++++++++++++++++++++
 ...etailModal.responsive-and-dependencies.test.tsx |  13 +-
 .../__tests__/TaskDetailModal.test-helpers.ts      |   3 +
 .../components/__tests__/TaskDetailModal.test.tsx  |  58 ++++
 .../__tests__/TaskPlannerChatTab.test.tsx          | 193 ++++++++++++
 .../dashboard/src/__tests__/chat-manager.test.ts   |  65 +++++
 .../dashboard/src/__tests__/chat-routes.test.ts    | 106 +++++++
 packages/dashboard/src/chat.ts                     | 132 ++++++++-
 .../dashboard/src/routes/register-chat-routes.ts   |  68 +++++
 14 files changed, 1181 insertions(+), 13 deletions(-)

Fusion-Task-Id: FN-7310

Fusion-Task-Lineage: a276c356-599e-4495-9879-472d157d95e5

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-06-30 17:20:42 -07:00