Commit Graph

5 Commits

Author SHA1 Message Date
gsxdsm
890d588891 Phase B — Column.tsx 2→0 and taskActivity.ts 2→0 (U11's cluster to zero) (#2636)
**Claimed:** `Column.tsx`, `taskActivity.ts` — both to zero.

| file | before | after |
|---|---:|---:|
| `packages/dashboard/app/components/Column.tsx` | **2** | **0** |
| `packages/dashboard/app/utils/taskActivity.ts` | **2** | **0** |

## `Column.tsx` — two different fixes, because the two sites are
different problems

**The preserve-progress prompt** routed through
`isPreImplementationColumnRole`. This is the *same* question that helper
was written for — ListView asks it about a move target, Column asks it
about itself — and the degraded id sets are identical (`{todo,
triage}`), so the consolidation is exact.

I verified the sets matched **before** consolidating, because the
sibling case is not interchangeable: `isPreExecutionHoldColumn` in
`TaskContextMenu` drives the Plan affordance and its degraded set is
`{triage}` alone. Routing *that* through this helper added `plan` to
flagless `todo` cards, caught by an existing test. **Same shape,
identical trait path, non-interchangeable fallbacks.**

**The legacy-board arm** (`workflowMode || column === "triage"`) —
deleted, on the third attempt.

I deleted it twice before and reverted both times because four Column
tests render without `workflowMode`. That was the delete-only rule
working, but **my conclusion from it was wrong**: a behaviour change
means the branch was not dead *for those callers*, and the callers are
**fixtures, not production**. Board is Column's only consumer and passes
`workflowMode` at all three render sites. Defending an unreachable arm
so four tests keep passing preserves the tests, not the behaviour.

Two notes for anyone converting the remaining dashboard files:

- I did **not** default `workflowMode` to `true`, which was the tempting
one-liner. `isArchived`, `isHoldColumn` and `isWipProcessingColumn` all
switch on that same flag, so a global default would silently reinterpret
every other fixture in an 85-test file.
- **"Four tests break" was itself an underestimate.** Two more FN-770
fixtures surfaced only after the first two were fixed, because they
render their own explicit `column="triage"` block instead of using
`defaultProps`. The blast radius only became accurate by fixing it in
waves.

## `taskActivity.ts` — composed, not copied

The degraded arm now composes `utils/columnRoles`' predicates instead of
naming ids. **No local copy** — which is the failure mode #2625 hit from
the other direction.

Equivalent *by construction*:

| lane | composition | resolves to |
|---|---|---|
| intake | `isIntakeColumnRole(undefined, col)` | `triage` |
| hold | `isPreImplementationColumnRole(...)` **and not** intake |
`todo` |

reproducing `col === "triage" || (col === "todo" && isReplanning)`
exactly, since the shared pre-implementation set is `{todo, triage}` and
the shared intake id is `triage`.

Deliberately phrased as *"pre-implementation and not intake"* rather
than a second id list: if either shared set changes, this composition
follows it instead of silently disagreeing with the file next door. That
disagreement is precisely what bit the `TaskContextMenu` consolidation
above.

**I previously reported this site as blocked on `TaskCard.tsx` (U12's)**
— on the theory that the arm could only die once every caller supplied
resolved flags. Wrong framing: the arm doesn't need to become
*unreachable*, it needs to stop *naming ids*. Composing the shared
predicates does that without touching any caller.

## Verification

**1139 of 1141** green across `app/utils`, `Column` and `TaskCard`
suites. The two `TaskCard` failures are **pre-existing** — verified by
stashing this change and re-running, where they fail identically.
Dashboard app typecheck and lint clean.

Takes U11's cluster to zero except `TaskContextMenu.tsx`, whose
remaining site is covered in **#2626** and whose second site is a
documented non-consolidation.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 22:37:43 -07:00
gsxdsm
bad35775a1 Drift 3/4: Task Detail intake affordances from traits — the UI half of the #2571 approve/reject stall (4→3) (#2577)
## Drift conversion 3 of 4 — Task Detail, the UI half of the #2571 stall

**Stacks on #2566.** Merge order: #2558 → #2566 → this. (#2571 is the P0
and is independent — merge it first regardless.)

### Convergence number

Live-code `column === / !== "todo" | "triage"` in `TaskDetailModal.tsx`:
**4 → 3**

All three survivors are the documented no-metadata fallback, same shape
as TaskCard and ListView: `workflowMoveMetadata` is `null` until the
detail payload resolves, and a bare trait read would drop these controls
during that window.

### This is the UI half of the P0

`isAwaitingApproval` and the standalone Delete button were both gated on
`task.column === "triage"`. On the merged lineage (#2515) that is false
for every card, so a task parked `awaiting-approval` **loses its
Approve/Reject controls in the one surface that shows them**.

#2571 fixes the routes that *reject* those actions. This fixes the UI
that stops *offering* them. Either half alone leaves the operator stuck
— one with buttons that 400, the other with no buttons at all.

### Three conversions

| site | was | now |
|---|---|---|
| `isAwaitingApproval` + standalone Delete | `column === "triage"` |
resolved column's `intake` |
| `requiresExecutionModeReplan` | `todo \|\| in-progress` | `hold \|\|
countsTowardWip` |
| move-progress prompt | source column ids | **target** column's flags |

The replan rule is "this card may already hold a plan or a live
execution context" — which the traits state directly;
`todo`/`in-progress` was the Default workflow's spelling of it.

The move prompt is the mistake I made first in TaskCard, where its
regression test caught that the site tests the move **destination**, not
the card. Carried the lesson here rather than repeating it.

### Tested through a pure seam, and why

`requiresExecutionModeReplanForTest` is exported so the rule can be
asserted as a function of (column id, flags).

Asserting it through the modal means booting async detail loading to
observe one boolean — and an earlier DOM-level attempt at exactly this
class of assertion (in #2566, ListView) **passed with the conversion
reverted**, because the text it matched also appears in a column header.
I am not repeating that. A seam discriminates; that DOM test did not.

Revert-proof: restore `column === "todo" || column === "in-progress"`
and the merged-column case fails, because that column is `intake + hold`
and carries no `countsTowardWip`. The suite also pins that the rule
still **narrows** (a complete lane needs no replan) and that the legacy
fallback is unchanged when flags are absent.

### Verification

`pnpm test:gate` (414 + 10 + 71), `pnpm lint`, dashboard typecheck
green.

**No new failures**: `TaskDetailModal.rendering.test.tsx` reports the
same 28 pre-existing failures with and without this change, diffed by
test *name* against a stashed clean tree.

### Drift set status

| file | before | after | PR |
|---|---|---|---|
| `TaskCard.tsx` | 8 | 3 | #2558 |
| `ListView.tsx` | 5 | 3 | #2566 |
| `taskActivity.ts` (found underneath) | 1 | 1 | #2566 |
| `TaskDetailModal.tsx` | 4 | 3 | this |
| `register-task-workflow-routes.ts` | 10 | 11 | #2571 (P0, widened on
purpose) |

Survivors are no-metadata fallbacks except the routes, where the guards
deliberately accept resolved-intake **or** `triage` so a P0 fix cannot
reject anything previously allowed. Those retire together once the
legacy id is gone board-wide.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 10:26:21 -07:00
gsxdsm
b6135f4bd5 FN-8494: keep task cards active while replanning
Keep task-card activity chrome visible throughout durable and fresh replanning states.

- Treat needs-replan tasks as agent-active on triage and todo lanes without changing lock policy.
- Cover board, list, mobile, pause, and freshness behaviors with regression tests.
- Add a patch changeset for the replanning activity indicator.

Files changed:
 .changeset/fn-8494-replan-active-glow.md           |  7 +++++
 .../app/components/__tests__/ListView.test.tsx     |  4 +++
 .../app/components/__tests__/TaskCard.test.tsx     | 31 ++++++++++++++++++++++
 .../app/utils/__tests__/taskActivity.test.ts       | 23 ++++++++++++++++
 packages/dashboard/app/utils/taskActivity.ts       |  7 ++++-
 5 files changed, 71 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8494
Fusion-Task-Lineage: a910a22a-cff7-423f-82ee-359830beb104
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-22 13:57:02 -07:00
gsxdsm
9debeaa951 FN-8300: show planner activity on status-null cards
Keep planning cards visibly active while fresh planner logs precede authoritative task status updates.

- Track bounded client-only planner activity from fresh triage log events
- Render matching pulsing Planning badges in board and list card views
- Cover transient activity, authoritative clearing, and inactive edge cases

Files changed:
 docs/dashboard-guide.md                            |  2 +
 packages/core/src/types.ts                         |  6 +++
 packages/dashboard/app/components/ListView.tsx     | 26 ++++++++---
 packages/dashboard/app/components/TaskCard.tsx     | 20 +++++---
 .../app/components/__tests__/ListView.test.tsx     | 38 +++++++++++++++
 .../app/components/__tests__/TaskCard.test.tsx     | 19 +++++++-
 .../dashboard/app/hooks/__tests__/useTasks.test.ts | 54 ++++++++++++++++++++++
 packages/dashboard/app/hooks/useTasks.ts           | 44 +++++++++++++-----
 .../app/utils/__tests__/taskActivity.test.ts       | 22 ++++++++-
 packages/dashboard/app/utils/taskActivity.ts       | 15 +++++-
 10 files changed, 219 insertions(+), 27 deletions(-)

Fusion-Task-Id: FN-8300

Fusion-Task-Lineage: e12f1277-5628-45a1-b731-54310027540e

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-18 12:13:20 -07:00
gsxdsm
8f176e3b89 FN-8055: align active-agent indicators with task activity
Keep board and list activity styling synchronized with actual agent work.

- Centralize task activity detection across cards, lists, routing, and model-resolution surfaces.
- Show running workflow activity while suppressing stale, paused, stuck-killed, and terminal task states.
- Cover status-null workflow activity and terminal-state regressions.

Files changed:
 packages/dashboard/app/components/ListView.tsx     | 34 ++---------
 packages/dashboard/app/components/RoutingTab.tsx   | 17 +-----
 packages/dashboard/app/components/TaskCard.tsx     | 28 +++------
 .../app/components/__tests__/ListView.test.tsx     | 66 +++++++++++---------
 .../app/components/__tests__/TaskCard.test.tsx     | 44 ++++++++++++++
 .../app/components/effective-model-resolution.ts   | 18 +-----
 .../app/utils/__tests__/taskActivity.test.ts       | 71 ++++++++++++++++++++++
 packages/dashboard/app/utils/taskActivity.ts       | 59 ++++++++++++++++++
 8 files changed, 228 insertions(+), 109 deletions(-)

Fusion-Task-Id: FN-8055
Fusion-Task-Lineage: 9ce38d60-06c8-4050-83f4-263e2f765c86
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-16 02:01:56 -07:00