8d84cee11ec00ca796d2b98dcd45a65f308f3cc9
389 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2771408bba |
ci: enforce the lifecycle-column ratchet — it has never actually run (#2654)
**The ratchet was advisory.** `scripts/lifecycle-column-census.mjs` existed only as `pnpm census:lifecycle-columns` — without `--strict` — and **no workflow invoked it**. Nothing has ever compared the tree to the baseline. Every "the baseline ratchet holds them" assumption in this program rested on a check that does not run. That explains both classes of hole: **1. Three PRs lowered counts without re-recording,** leaving allowances the deleted guards could return through while every check stayed green. I've tightened them across #2593 and earlier PRs, but nothing stops the next one. **2. #2621 GREW the count while its own title claimed "count 0 → 0".** It added `column === "triage"` and `column === "todo"` at `register-task-workflow-routes.ts:2681`, taking that file to **23 against an allowance of 22**. It landed unchallenged. This is the failure mode the ratchet exists to prevent, and it happened *inside this program*, in a PR that asserted the opposite. ## The change Adds `check:lifecycle-columns` (the census with `--strict`) to the `pr-checks.yml` lint job, next to `check:changesets` and `check:routes-modular` — the established pattern. **~1.8s over ~1950 files**, so this is not a slow-test addition. ## Proven to fail, in both directions A guard that reports success without checking anything is worse than no guard, so: | injected defect | result | |---|---| | `const __probe = (c: string) => c === "triage"` added to `moves.ts` | `count ROSE — moves.ts: 39 -> 40`, exit 1 | | run against main's current baseline | exit 1 on `mission-feature-sync.ts: allows 5, tree has 0` | Both reverted; exit 0 restored. Note the second row: **this check is RED on main right now**, which is the point. ## Merge order **Stacked on #2593**, which carries the `DELIBERATE-LITERAL` marker for the #2621 site (a v1 IR declares no roles, so no trait can answer that question) plus the baseline re-record. Standalone on main this PR is red — correctly. **Merge #2593 first**, then this. I stacked rather than duplicating those two edits because I already caused one conflict today by appending related content from two branches, and #2651 merged a correction ahead of the section it corrected. Same-content edits in two PRs is the same mistake. ## Census Unchanged by this PR: **776 total, triage 5, reviewed 16** — it adds no guards and converts none. It only makes the numbers enforceable. ## For the fleet This should land before the 776-guard fleet launches. The brief says "the baseline ratchet must shrink by exactly the converted count" — until now nothing verified that claim, so a batch worker could report a shrink that did not happen, or grow the count while converting, and CI would agree. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
642a4fa264 |
consolidate/u12 — U12 consolidation: 4 live defects, the AST ratchet fail-closed, and the moves.ts flag scoped (#2647)
One branch, one PR, per the consolidation directive. Contents file-by-file below. **Supersedes #2625** (its overlapping conversions landed via U11's #2624/#2626/#2636; only the parts nobody else did are folded here). **#2630 and #2639 stay open** — both green with zero threads, per rule 3. ## Four live defects, each measured **1. Every planning card renders an actions menu.** `TaskContextMenu.tsx` still had `shouldShowActionsMenu: task.column !== "triage"` on main *after* the rest of that file was converted. Since #2515 removed the id, the condition is TRUE for every card, so the suppression stopped applying anywhere — including on cards whose menu is empty, the orphaned click target the Surface Enumeration rule exists to catch. Found **twice independently**: by reading the guard, and again by the invariance test below, which failed on main with `shouldShowActionsMenu` true on one lineage and false on another. That is the argument for an invariance property over per-site conversion — the file had already been converted "2 → 1" and the survivor was the live one. **2. Worktree upcoming-work list empty on renamed boards.** `groupByWorktree` filtered `t.column === "todo"`. On the default board the id and the role coincide so every existing test passed; renamed, it matched nothing and a whole panel read as idle. **3. Hold-lane FIFO ordering lost on renamed boards.** `sortTasksForDisplayColumn` gated priority-then-FIFO on `column === "todo"`, degrading to the generic id-ordered sort elsewhere. Cards simply appear in the wrong order, silently. **4. The AST ratchet still failed open** — fourth time in that file, third found by review. `receiverName` understood only one-level property access and bare identifiers, so `task["column"]`, `metadataColumn(entry, "to")`, ternaries, `(task!.column)` and backtick literals were dropped. **Measured on main: `in-progress` 196 → 197, `in-review` 211 → 213** — three real guards nobody counted, including `metadataColumn(entry, "to") === "in-review"` in `reliability-metrics.ts`. Now walks wrappers, resolves calls to the callee name, and emits a `<SyntaxKind>` **sentinel** for anything unnameable: counted *and* trips the classification guard, so a human judges it instead of it vanishing. ## Per-file guard counts | file | before | after | |---|---:|---:| | `app/components/TaskContextMenu.tsx` | 1 | **0** | | `app/utils/worktreeGrouping.ts` | 1 | **0** | | `app/components/taskSorting.ts` | 1 | **0** | The other dashboard files I had converted reached 0 via U11's PRs; where our work overlapped I took theirs during the rebase, including two places where theirs was **stronger** than mine — they deleted Column's unreachable quick-create arm outright (with fixtures migrated) where I had converted it, and they verified the same `isPreExecutionHoldColumn` degraded-set asymmetry I did, independently. ## Flip precondition: the moves.ts flag is scoped, not flipped `move-target-declared-census.test.ts` answers precondition 2 with measurement. 41 engine `moveTask` calls have literal targets — `todo` 27, `in-progress` 7, `done` 6, `archived` 1 — and **all four are declared by the default lineage**, so the default board is not the exposure. `triage` appears only in a comment noting `replan-target.ts` used to hardcode it. My own grep had said `todo=29`; the AST says 27, because grep counts comments. The exposure is **custom** lineages: 20 of the 41 carry no `recoveryRehome` and would reject with unknown-column post-flip; 21 are exempt via the #1411 carve-out, which makes that carve-out load-bearing. I did not flip the flag. It is six seams, not the `789`/`837` pair every summary including mine described, and seam 2 turns on *new refusals* rather than swapping equivalent implementations — a green suite says nothing about that. #2639 pins the blast radius. ## Tests - `column-role-id-invariance.test.tsx` — hold traits fixed, vary only the column id across MERGED / LEGACY / RENAMED; every decision must agree. Drives the real consumers, so a component keeping an inline comparison fails it. Includes a unanimous-and-**false** case so it can't be satisfied by a predicate hardwired to true. **This is the test that caught defect 1 on main.** - `worktreeGrouping.test.ts` — includes two cards both in a column named `staging`, one hold and one not, asserting opposite answers. That assertion is impossible under a board-wide column-id set, which is why hold resolution is keyed per task via `getEffectiveTaskWorkflowId` (#2625 review). - `taskSorting.test.ts` — discriminates on the **tiebreak**, not priority: both branches sort by priority, so my first version passed for the wrong reason. Equal-priority cards whose `createdAt` order disagrees with their id order. - `no-hardcoded-lifecycle-columns.test.ts` — 16 detector cases: 11 shapes counted, 4 legitimate ignored, one asserting the sentinel path. Revert checks, all run: menu suppression → diff names the field; worktree → `expected [] to include 'FN-50'`; sort → `FN-2, FN-9` instead of `FN-9, FN-2`; ratchet → the 3 recovered guards disappear. ## One site that should never be converted `MissionControlPanel.tsx:46` — `{ id: "triage", match: (c) => c === "triage" || c === "signal" || c === "backlog" }` is a deliberate name-similarity heuristic for the SDLC funnel; it matches synonyms and folds unknown columns into an "other" bucket so custom columns still contribute. Converting it changes what the funnel displays. Like the `live-agent-count` fallbacks, it belongs in a documented floor — **the ratchet's target is that floor, not zero.** `DocumentsView.tsx:73` is convertible but the file has no column flags at all, so a real fix means plumbing board-workflow metadata into a view that doesn't fetch it — its own unit of work. ## Verification `pnpm lint` clean. `pnpm test:gate` green (10 / 482 / 71). `tsc -p packages/dashboard/tsconfig.app.json` and `packages/core/tsconfig.json` clean. Core ratchet + seam suites 24/24. Dashboard target suites 37/38 — the one failure is the pre-existing `"Back to In Progress"` label casing, confirmed identical on the base. --- ## Added after the initial push **5. `TaskCard` lost inline editing on renamed boards; `TaskDetailModal` kept it.** Still live on main: the modal resolved field editability from traits in U10/R8, the card used a hardcoded `{triage, todo}` set with **no trait path at all** — even though `taskColumnFlags` was already in scope. On a renamed board the title was editable in the modal and the pencil was missing from the card. Body moved unchanged into `isFieldEditableColumnRole` so the two surfaces cannot drift again. The veto traits are the substance: a column can legally carry `hold` **and** a WIP or review trait, and a plain `intake || hold` check would let an operator rewrite a description while a session executes against it. Coverage gap **measured, not assumed**: mutating `canEdit` back to the hardcoded set left `TaskCard*` at the same failure count as the unmutated run — nothing caught it. The four render cases assert the real `aria-label`; that mutation now fails with `Unable to find an accessible element ... name 'Edit task'`. **6. The ratchet's target is a documented FLOOR, not zero** — and this changes the completion bar. Zero is not reachable, and chasing it means breaking working code. Two categories are permanent, now protected as positive assertions so a future sweep cannot "finish the job" by deleting them: - `MissionControlPanel.tsx`'s `FUNNEL_STAGES` is a deliberate **name-similarity** heuristic — it matches `signal`, `backlog`, `to-do`, `ready`, `shipped` and folds unrecognised columns into an "other" bucket so a custom board still contributes counts. It is not asking whether a column has the intake trait; it buckets arbitrary column *names* for display. Asserted on the **synonym list**, because the synonyms are what prove it is name matching — if they disappear the site has changed character and the exemption stops applying. - `live-agent-count.ts`'s no-flags arm is reachable (a remote store is deliberately given an empty flag map; a card in an undeclared column has no flags at all) and deleting the literal makes such a card match **no** arm, so the queued total silently under-reports a stranded card. A count with an undocumented floor invites someone to drive it to zero. **Not done, and why:** `DocumentsView.tsx:73` is convertible but that file has no column flags anywhere, so a real fix means plumbing board-workflow metadata into a view that does not fetch it — its own unit of work, not something to smuggle into a conversion. **Re-verified after these commits:** `pnpm lint` clean, `pnpm test:gate` green (10 / 482 / 71), `tsc` clean on core and `tsconfig.app.json`, core ratchet suite 26/26, `columnRoles` 10/10, `TaskCard.test.tsx` 384/386 (the 2 are pre-existing CSS assertions). `TaskDetail*` is 130 failed / 551 passed **both with and without** this change — verified by stashing, so pre-existing and unrelated. --- ## Flag resolution: preconditions 1 and 2 are now DISCHARGED. Precondition 3 is blocked, and by evidence. **Precondition 1 — the side-effect equivalence proof — done.** `moves-flag-equivalence.test.ts` runs the same journey under both flag states against live PG and diffs the persisted row. **Result: identical** — whole-row equality across 128 fields plus an equal timing shape, over `todo → in-progress → in-review → todo → in-progress`. That test was **wrong twice** before it meant anything, and both times it was passing: 1. **It proved nothing.** `experimentalFeatures` is **global-only**, and `moves.ts` reads `getSettingsFast()`, which filters global-only keys out of the project layer. My `updateSettings` write was silently discarded, `useWorkflow` was false in *both* runs, and the "proof" compared the legacy path against itself. Found by stamping the flag-ON branch and observing the test still passed. Now written via `updateGlobalSettings`, and the helper **asserts the flag took effect** before the journey runs. 2. **The journey was forward-only**, so it never reached the reopen hook's field resets (`status`, `error`, `blockedBy`, pause clearing) — a mutation there passed. Extended with a backward move and a re-entry. Mutation-verified after both fixes: stamping seam 3, and diverging the reopen hook, each fail the comparison. **Precondition 2 — done, and its answer is a blocker.** The census says the default board is safe: all 41 literal engine move targets are declared by the default lineage. But **20 of those 41 carry no `recoveryRehome`**, so on a custom lineage that does not declare `todo` / `in-progress` / `done`, seam 2 would start rejecting them with unknown-column. That is a user-facing break on custom boards, not a theoretical one, and it is not fixed by the equivalence proof — seam 2 adds *new refusals* rather than swapping implementations. **So the flip is one step away, and the step is not mine to take alone:** those 20 call sites need to resolve their target from the task's workflow (or justify `recoveryRehome`), and they live across engine lanes in `moves.ts` caller territory — U2b/MAIN. Flipping before that trades a dormant flag for broken custom boards. What remains for precondition 3 once those land: flip both readers **atomically** (`moves.ts` + `workflow-task-create-ops.ts`, since the latter computes the preflight the former consumes), delete the flag-OFF branch with its guards, and drop the settings key. --- ## CORRECTION: seam 2 is not a blocker. My earlier claim was wrong. I stated in #2639 and above that "with the flag off there is **no** target-column validation on the move path", so flipping would introduce new refusals. **That is not what happens.** Reproduced against live PG: the identical custom-lineage move rejects with the flag **OFF** as well — ``` Error: Invalid transition: 'backlog' -> 'todo'. Valid targets: building ``` Transition validation is already in force on the flag-OFF path. So for the shape in question — an engine move to a column the task's own workflow does not declare — **the move already fails today**, and seam 2 introduces no new break for it. The 20 census sites lacking `recoveryRehome` are broken on a custom lineage *now*, not broken by the flip. I found this because the discriminator I added to prove "the flag is the cause" failed. Had I written the test to my assumption it would have passed and the false claim would have shipped — the same way the equivalence test passed while proving nothing until I tried to make it fail. **Revised precondition status:** | precondition | status | |---|---| | 1 — side-effect equivalence | **discharged** — identical rows, mutation-verified both directions | | 2 — seam-2 exposure census | **discharged, and it is not a blocker** — the rejection predates the flag | | 3 — flip both readers atomically, delete the flag-OFF branch, drop the settings key | **the remaining work** | So the flip is no longer gated on fixing 20 engine call sites. What it is still gated on is precondition 3 being done atomically across `moves.ts` and `workflow-task-create-ops.ts` (the latter computes the preflight the former consumes), which is `moves.ts` caller territory. Three cases now cover seam 2: the flag-ON rejection, the flag-OFF rejection (asserting the error *message*, so a change in which guard rejects stays visible rather than reading as agreement), and the #1411 `recoveryRehome` carve-out succeeding — pinning why that carve-out is load-bearing and must not be tidied away. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
da0351857e |
U12 part 5: put real workflow adjacency on the wire — custom-workflow move menus were guessing (measured), and the VALID_TRANSITIONS shortcut is gone (#2525)
## U12 part 5 — the move menu was guessing; now it asks the graph **Stacks on #2521** (same file). Merge that first. The context menu had **no adjacency data at all**, so it did two wrong things at once: it approximated move targets from a column's **neighbours in declared order**, and — because that approximation is strictly weaker than the real graph — it kept a `VALID_TRANSITIONS` shortcut for any workflow whose column-id set matched the six built-ins. Measured, the approximation loses real operator moves: | current | workflow graph | neighbour approximation | |---|---|---| | `in-progress` | in-review, todo, triage, done | todo, in-review | | `todo` | in-progress, triage, archived | triage, in-progress | | `done` | todo, triage, archived | in-review, archived | So **every custom workflow has been offering a guess**: menu entries the store would reject, and legal moves it never offered. The built-ins were fine only because the shortcut bypassed the guess entirely. ### The fix `BoardWorkflowColumn` gains `moveTargets`, resolved by `resolveAllowedColumns` — *the same resolver `moveTaskInternal` validates against*. The menu now offers exactly what the store will accept, for any workflow. Threaded through all four metadata builders (Board, Lane, ListView, TaskDetailModal). Optional on the wire, deliberately: a client older than this field keeps the neighbour fallback rather than losing its move menu mid-upgrade. ### Why deleting the legacy shortcut is safe Not an assertion — a measurement, then a pin. `resolveAllowedColumns(BUILTIN_CODING_WORKFLOW_IR, c)` is **identical to `VALID_TRANSITIONS[c]` for all six columns, order included**: ``` triage ["todo","archived"] == VALID SAME todo ["in-progress","triage","archived"] == VALID SAME in-progress ["in-review","todo","triage","done"] == VALID SAME in-review ["done","in-progress","todo","triage"] == VALID SAME done ["todo","triage","archived"] == VALID SAME archived ["done"] == VALID SAME ``` `builtin-adjacency-matches-legacy-transitions.test.ts` pins it so the equivalence cannot drift silently — if the built-in workflow's edges change without `VALID_TRANSITIONS` following, default menus change shape and that test fails first. It compares **order** too, since the menu renders targets in the order it receives them, so a reorder is operator-visible. Default-workflow menus are therefore byte-identical. Custom ones stop guessing. ### What's left of the legacy vocabulary here `COLUMNS` is gone from `TaskContextMenu` — deleting the shortcut removed its last use. `VALID_TRANSITIONS` survives for exactly one thing: the **no-metadata load window**, documented at the site. I measured removing that in #2521 and it left Task Detail with no move options during load, which is a regression rather than a cleanup. It retires when the load window does. ### Revert-proof, two ways - Drop the `declaredTargets` branch → the custom-workflow case fails: the neighbour fallback returns `["backlog","building"]`, missing the legal `shipped` jump **and** offering `backlog`, which that graph forbids. That is exactly the defect class shipped to every custom workflow today. - A second case pins that an adjacency edge into a column the board cannot show is **dropped**, not rendered as a dead menu entry. ### Verification `pnpm test:gate` (309 + 10 + 71), `pnpm lint`, `pnpm verify:fast`, core + dashboard typechecks green. **No new test failures**: five suites report 31 failures with and without the change — an identical, pre-existing set, verified by diffing failing test *names* against a stashed clean tree, not by comparing counts. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Move menus for custom workflows now show only the destinations permitted by that workflow. * Task-specific workflow rules are applied consistently across boards, lists, lanes, and task details. * Invalid or unavailable destinations are excluded from move options. * Existing clients remain supported when workflow destination data is unavailable. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
fd6d005333 |
U12 part 1: delete the legacy board path (262 ListView + 39 Board tests were measuring it; 9-site flag inventory, moves.ts group blocked on U2b) (#2500)
## U12, part 1 of 2 — and one blocker you need to route The unit's headline deletion (`isWorkflowColumnsCompatibilityFlagEnabled`) is **blocked by U2b** and is not in this PR. What is here is everything that could be deleted without making a convergence decision that belongs to another unit. ### The blocker PR #2468 landed as `b941d3cba` — but that was **Phase A2 steps 1–2 only: the differential characterization**. The convergence (pick a path, delete the other, delete the flag) has not landed; `feature/workflow-move-path-convergence` is still live. Deleting the raw flag **is** that convergence. `move-path-equivalence.pg.test.ts` says so in its own header, and its second `describe` is literally *"the flag gates MORE than side effects"*. The plan makes this a blocking unit with an equivalence *proof obligation* and an explicit "stop and escalate rather than reconcile silently" note. So I stopped. ### Inventory: every read of the raw flag, with a verdict Nine sites. All false in production because nothing writes `experimentalFeatures.workflowColumns`. **Blocked on U2b — one branch, not separable:** | Site | Silently disabled today | Visible if flipped | |---|---|---| | `moves.ts:312` `useWorkflow` | typed `TransitionRejectionError`, workflow adjacency, the shared transition invariants (merge-blocker *trait* generalization), plugin column gates, the `transitionPending` marker, `workflowId` in `task:move` run-audit, and the trait-hook side-effect path | Yes — rejections change **type and message** | | `moves.ts:931` | the in-transaction capacity gate. `resolveColumnCapacity` never runs | Yes — WIP limits begin binding | | `workflow-task-create-ops.ts:351` | `prepareWorkflowMovePolicyPreflight` returns `undefined` unconditionally → **workflow/plugin move policies have never been evaluated** | Yes — new rejections | On #2488: the pool-id sentinel fix is correct *and* still inert. Two dead layers stacked — the gate it fixed is inside `if (useWorkflow && …)`. **Not blocked, but each moves operators' cards — deferred to PR 2 per your call:** | Site | Silently disabled today | |---|---| | `workflow-ops.ts:183` | `OccupiedColumnsError` + `rehomeTo` when a workflow edit removes an **occupied** column. Today the save succeeds and strands the cards | | `workflow-ops.ts:344` | occupant re-home on workflow **delete** | | `workflow-definitions.ts:700` | workflow-**switch** reconciliation, and the `reconciliation` field in the API response | I verified these three are **not** coupled to `moves.ts`: `rehomeOccupant` reaches a custom target via the `isWorkflowDeclaredRecoveryRehome` carve-out (`moves.ts:641`), which exists because the repair "silently no-oped on every store open" before it. **Not blocked, no behaviour change for current binaries** (also PR 2): `project-store-ops.ts:687` + `lifecycle-ops.ts:1119` — `downgradeIrToV1IfPure` on persist, for *binary-downgrade* rollback. Needs a round-trip test, not an assumption. ### What this PR deletes **Dashboard.** `workflowColumnsEnabled` was a literal `true` at all three `MainContent` call sites; the server hardcodes `flagEnabled: true`. Gone: Board's legacy single-lane board (55 lines mapping the hardcoded `COLUMNS` enum — the last board surface deriving columns from the legacy vocabulary, an R8 violation that survived U10); `tasksByColumn` and its cache ref, orphaned with it; ListView's `LEGACY_LIST_COLUMNS` (the ListView copy of the synthesized-trait-flags defect U10 fixed in Board); both props; the `shouldHydrateCache` gate; TaskDetailModal's `flagEnabled` early return. **Neither Board nor ListView imports the legacy column enum any more.** **Core.** `evacuateCustomColumnsToLegacy` (#1409) — both triggers require the previous settings to have the flag ON, which no writer produces. `runWorkflowColumnsIntegrityPass` — no caller anywhere, superseded by `reconcileUndeclaredTaskColumns` (registered in startup recovery), and it read through the sync SQLite handle, so invoking it under PostgreSQL would have thrown rather than reconciled. **Migration answer:** a project with `workflowColumns: false` persisted needs no migration and no read-time drop. Nothing in this PR reads the key, and it stays in `HIDDEN_EXPERIMENTAL_FEATURE_KEYS` so Settings still suppresses it rather than resurrecting it as an unknown setting. Proven by tests, no instance booted. **`flagEnabled` stays on the wire** as a constant. Removing it changes the response shape, and a browser tab outliving a server upgrade would read the missing field as "off" and degrade. One boolean, no client branches on it, droppable a release later. ### Measured - Production sources: **-332 / +131** (net **-201**). Additions are almost entirely FNXC comments recording why each branch was unreachable. - Dashboard production only: -168 / +93. - Core: -164 / +38. ### The finding I'd actually flag `Board.test.tsx` and `ListView.test.tsx` both left `workflowColumnsEnabled` unset and stubbed `fetchBoardWorkflows` with a **never-resolving promise**. Under the old gate that rendered the **legacy** board — so **262 ListView tests and 39 Board tests were asserting against a configuration production never reached**, and a real regression in the workflow board or list would not have failed either file. Same shape as the other four: looked enforced, wasn't. Both now seed the first-paint lane cache with the default workflow's **real** columns (ids and names copied from `BUILTIN_CODING_WORKFLOW_IR`) — the same seam production uses. Repointing them surfaced assertions that encoded legacy-only values: `"In Progress"`/`"In Review"` (real IR names are `"In progress"`/`"In review"`), and Planning Mode asserted to receive `null` as the workflow id, which is only what `getTaskPlanningWorkflowId` returns when `workflowMode` is false. `"Back to In Progress"` is **not** one of those — it is a hardcoded i18n string in `TaskContextMenu:210`, not derived from the column name. Left alone, and flagged: it will not follow a renamed column. That's U11 vocabulary territory. **One test is SKIPPED, not weakened** — "keeps unaffected columns stable when archived collapse toggles". Pointed at the real board the invariant is **false**: toggling the archived column re-renders unaffected columns (measured: todo renders 3×, not 2×). Pre-existing production behaviour this deletion exposed, never covered because the test measured the dead path. I ruled out the obvious causes (every callback prop is `useCallback`; the per-column task memo's deps exclude `archivedCollapsed`; memoizing the inline `canDropTask` binding did **not** close it — I wrote that fix, could not prove it with a failing test, and **reverted it**). The reason is recorded at the test: un-skip with a fix, never with a new expected number. ### Verification `pnpm test:gate` (299 + 10 + 71), `pnpm lint`, `pnpm verify:fast` (17 steps), and both package typechecks green. `settings-defaults.test.ts > warns once per process for legacy cwd-main mode` fails — **pre-existing**, confirmed by stashing my changes and re-running. No Fusion instance was booted. ### Routing request Per your call: the `moves.ts` group and the final removal of `isWorkflowColumnsCompatibilityFlagEnabled` go to **U2b**, inside the convergence PR where the equivalence proof already lives. The divergences their characterization suite does **not** yet cover: plugin column gates, the `transitionPending` marker, `workflowId` in `task:move` run-audit, and move-policy preflight. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a271f1868f |
U10: dashboard renders workflow-resolved columns (6 legacy-vocabulary defects, incl. a silently-disabled open-PR guard) (#2492)
Phase D / **U10** of the workflow-owned-lifecycle program (**R8**). This
unit **blocks U11** (merge Todo into Planning) — the board must render
IR-resolved columns before the column shape can change.
## What was wrong
Six dashboard surfaces answered a column question from the legacy
`COLUMNS` / `VALID_TRANSITIONS` vocabulary rather than the card's own
workflow IR. Each is a defect today, and each is a way U11 would ship
visibly broken.
| # | Surface | Defect |
|---|---|---|
| 1 | Board — All workflows | Appended **every** legacy column id to the
lane union with synthesised flags → a phantom lane for a column no
workflow declares, labelled with the raw id, ordered by the enum index
with an alphabetical tie-break that scrambled a custom workflow's
declared order |
| 2 | ListView | `if (groups[column])` **silently dropped** a row whose
stored column the workflow no longer declares — no lane, no row, no
error |
| 3 | Move menu | A card stranded in an undeclared column got an **empty
move list** — the one surface that could rescue it offered nothing |
| 4 | Task Detail | Header badge rendered the raw stored id;
title/description editing gated on the literal `{triage, todo}` — a
renamed planning lane lost Edit with nothing on screen to explain it |
| 5 | `board-workflows` | The built-in lifecycle label map was an
**override**, not a fallback, so it replaced a name a built-in
deliberately chose |
| 6 | `POST /tasks/:id/move` | The open-PR backward guard used
`COLUMNS.indexOf(...)` → **-1 on any renamed board**, and the guard
treats a negative index as "allow" |
**#6 is the one worth reading twice.** The guard did not start rejecting
the wrong things — it stopped existing. On a renamed board an operator
could drag a card backward out of review with an open GitHub PR,
orphaning it, and nothing failed. This is precisely the "a converted
guard silently stops firing" row in the plan's risk table, reached
through a rename rather than a conversion.
The re-engage copy of that same guard is **deliberately left on the
legacy enum**, with a comment saying why: it is gated on literal
`in-review` / `in-progress` end to end, so converting only its indices
would make it *weaker* (a workflow declaring `in-review` but not
`in-progress` would score -1 and disable it). U5 owns that lane.
## Evidence
**Every fix has a test that fails when the fix is reverted.** With the
six production files stashed and the tests kept, **10 of the 28 tests
fail**:
- Board aggregate: phantom lane present (2)
- ListView: stranded card dropped, desktop **and** mobile (2)
- Move menu: empty move list for a stranded card (1)
- Task Detail: badge shows `staging`, Edit missing in a renamed intake
**and** hold lane (3)
- `board-workflows`: `builtin:lead-generation`'s `triage` renders as
"Planning" (1)
- Move route: backward move between renamed columns **allowed** with an
open PR (1)
The other 18 are regression pins on behaviour that must not change
(default-workflow lane order and labels, legacy `in-review →
in-progress` block, legacy editable columns, forward moves, terminal
PRs).
**Measured, not estimated.** The label-map clobber was quantified
against the built-in IRs actually in tree: **4 column names replaced — 3
case-only variants ("In progress" → "In Progress"), 1 genuine semantic
rename.** Only the rename is a user-visible defect; the fix preserves
the case normalisation rather than churning the default board.
## Surface enumeration (AGENTS.md)
Desktop **and** mobile — the breakpoint is `(max-width: 768px),
(max-height: 480px)`, so landscape phones exceed 768 wide and match on
height. Column states: empty, populated, duplicate id across two
workflows, and a column no workflow declares. Views: single-workflow
lane, All-workflows aggregate, list, move menu, task detail, move route.
## Regression check
Full dashboard suite, both sides of the change:
| | Test Files | Tests |
|---|---|---|
| Before | 41 failed / 1068 | **296 failed** / 21195 |
| After | 42 failed / 1071 | **297 failed** / 21223 |
`+28` total is exactly the tests this change adds. The single failure
delta is `register-model-routes-kimi-k3-supplemental`, which **fails
identically on this branch's base when run in isolation** — shard-order
dependent, unrelated to columns. **Zero regressions attributable to
U10.** The ~296 pre-existing dashboard failures are inherited from main
and are flagged to the coordinator, not touched here.
`pnpm test:gate`, `pnpm lint`, both dashboard typechecks
(`tsconfig.json` and `tsconfig.app.json`), `pnpm smoke:boot`, and `pnpm
check:changesets` are green.
## Not in this unit
- `Board`'s legacy single-lane `COLUMNS.map` fallback still exists.
`MainContent` passes `workflowColumnsEnabled` unconditionally, so it is
unreachable in-app, but proving that is a deletion argument and this is
not a deletion unit — flagging rather than removing.
- `ListView`'s `LEGACY_LIST_COLUMNS` fallback, same reasoning.
- `flagEnabled` on the wire (U2 noted U10 retires it once no client
reads it) — four clients still branch on it; retiring it is a
client-shape change that belongs with U11's shape work.
- `GET /api/tasks?column=` still validates against `COLUMNS`, rejecting
a workflow-declared custom column as a list filter. Server-side filter
surface, not a rendering decision.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
43160a7aae |
FN-8621: migrate complex modals to FloatingWindow
Unify complex dashboard modal presentation under persisted FloatingWindow geometry. - Migrate Create Room, Task Detail, Agent Detail, and GitHub Import modal presentations. - Preserve documented embedded and docked exceptions, dismissal behavior, and nested scrolling. - Add presentation-contract coverage and publish dashboard guidance and changesets. Files changed: ...n-8619-resize-persist-modals-floating-window.md | 7 ++ .changeset/fn-8621-create-room-floating-window.md | 7 ++ docs/dashboard-guide.md | 16 +++- docs/dashboard-modal-inventory.md | 12 +-- .../dashboard/app/components/AgentDetailView.css | 16 +--- .../dashboard/app/components/AgentDetailView.tsx | 102 ++++++++++++++++----- .../dashboard/app/components/CreateRoomModal.css | 19 +++- .../dashboard/app/components/CreateRoomModal.tsx | 57 ++++++++---- .../dashboard/app/components/FloatingWindow.css | 13 ++- .../dashboard/app/components/FloatingWindow.tsx | 15 +++ .../dashboard/app/components/GitHubImportModal.css | 11 +-- .../dashboard/app/components/GitHubImportModal.tsx | 40 ++++++-- .../dashboard/app/components/TaskDetailModal.css | 52 +---------- .../dashboard/app/components/TaskDetailModal.tsx | 58 ++++++------ .../__tests__/AgentDetailView.core.test.tsx | 2 +- .../AgentDetailView.mobile-scroll.test.tsx | 6 +- .../components/__tests__/CreateRoomModal.test.tsx | 62 +++++++++++-- .../components/__tests__/FloatingWindow.test.tsx | 1 + .../__tests__/GitHubImportModal.test.tsx | 8 +- ...etailModal.responsive-and-dependencies.test.tsx | 77 +++++++--------- .../__tests__/modal-presentation-contract.test.tsx | 74 +++++++++++++++ .../dashboard/app/hooks/useEmbeddedPresentation.ts | 2 +- .../dashboard/app/hooks/useModalResizePersist.ts | 5 + 23 files changed, 441 insertions(+), 221 deletions(-) Fusion-Task-Id: FN-8621 Fusion-Task-Lineage: 04b6f3fe-d527-4a21-a0cb-489eb20f5e91 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
fde3b76a8c |
FN-8602: enable tablet touch resizing for task modals
Enable touch-driven resizing for task modals on tablet viewports. - Add tablet touch resize handles and pointer interactions for task and new-task modals. - Preserve responsive modal sizing while keeping phone layouts fullscreen. - Add unit, browser, and visual regression coverage with updated documentation. Files changed: .changeset/fn-8602-tablet-touch-resize.md | 7 + docs/dashboard-guide.md | 6 +- docs/testing.md | 4 + packages/dashboard/app/components/NewTaskModal.css | 70 ++++++++++ packages/dashboard/app/components/NewTaskModal.tsx | 19 ++- .../dashboard/app/components/TaskDetailModal.css | 12 ++ .../dashboard/app/components/TaskDetailModal.tsx | 7 +- .../app/components/__tests__/NewTaskModal.test.tsx | 4 + ...etailModal.responsive-and-dependencies.test.tsx | 1 + .../hooks/__tests__/useModalResizePersist.test.tsx | 10 +- .../app/hooks/__tests__/useViewportMode.test.ts | 26 +++- .../dashboard/app/hooks/useModalResizePersist.ts | 26 +++- packages/dashboard/app/hooks/useViewportMode.ts | 13 ++ packages/dashboard/app/styles.css | 16 +++ .../app/task-modal-touch-resize-e2e-fixture.html | 5 + .../app/task-modal-touch-resize-e2e-fixture.tsx | 60 ++++++++ .../__screenshots__/fn-8602/phone-fullscreen.png | Bin 0 -> 43987 bytes .../e2e/__screenshots__/fn-8602/tablet-after.png | Bin 0 -> 52549 bytes .../e2e/__screenshots__/fn-8602/tablet-before.png | Bin 0 -> 11500 bytes .../task-modal-touch-resize-browser.test.ts | 154 +++++++++++++++++++++ 20 files changed, 424 insertions(+), 16 deletions(-) Fusion-Task-Id: FN-8602 Fusion-Task-Lineage: f07ce22f-f529-4be3-ba1b-04063154a1b0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
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> |
||
|
|
4b4df1ff30 |
FN-8565: restore tablet task modal resizing
Restore resizable Task Detail and New Task windows on 768px touch tablets. - Classify known touch tablets separately from phone sheets - Restore bounded modal geometry and resize grips with keyboard support - Add regression coverage, documentation, and a patch changeset Files changed: .changeset/fn-8565-tablet-task-modal-resize.md | 7 +++ docs/dashboard-guide.md | 5 ++ .../task-detail-modal-tablet-width.test.ts | 15 +++++ packages/dashboard/app/components/NewTaskModal.css | 18 +++++- packages/dashboard/app/components/NewTaskModal.tsx | 44 +++++++++++++- .../dashboard/app/components/TaskDetailModal.css | 30 ++++++++++ .../dashboard/app/components/TaskDetailModal.tsx | 40 +++++-------- .../app/components/__tests__/NewTaskModal.test.tsx | 68 +++++++++++++++++++++- ...etailModal.responsive-and-dependencies.test.tsx | 51 ++++++++++++++++ .../hooks/__tests__/useModalResizePersist.test.tsx | 53 ++++++++++++++++- .../dashboard/app/hooks/useModalResizePersist.ts | 58 +++++++++++++++--- 11 files changed, 352 insertions(+), 37 deletions(-) Fusion-Task-Id: FN-8565 Fusion-Task-Lineage: 7d9bbeb9-0e6a-4ad9-8b4d-e9f3d8aef650 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
5f3f7709da |
FN-8530: link GitHub Import to source issues
Make GitHub import provenance a direct, single source-issue link. - Link the GitHub Import label whenever source metadata contains a URL. - Preserve a plain provenance label when no source URL is available. - Cover desktop, compact, nonstandard URL, and absent URL rendering. Files changed: .../dashboard/app/components/TaskDetailModal.tsx | 38 +++++++------ .../__tests__/TaskDetailModal.rendering.test.tsx | 66 ++++++++++++++-------- 2 files changed, 64 insertions(+), 40 deletions(-) Fusion-Task-Id: FN-8530 Fusion-Task-Lineage: 03f899c2-2a3b-4b27-9bb6-b4db12667bb0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e24fb37c8b |
FN-8492: keep mobile task footer actions on one row
Keep task-detail footer actions compact and readable across mobile widths. - Prevent mobile footer controls from wrapping while preserving shrink behavior. - Add ellipsis-safe labels for actions and review controls. - Cover standard and in-review footer layouts with responsive tests. - Add a patch changeset for the mobile footer fix. Files changed: .../fn-8492-mobile-task-footer-single-row.md | 7 ++ .../dashboard/app/components/TaskDetailModal.css | 74 ++++++++++++++++- .../dashboard/app/components/TaskDetailModal.tsx | 8 +- ...etailModal.responsive-and-dependencies.test.tsx | 94 +++++++++++++++++++++- 4 files changed, 175 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-8492 Fusion-Task-Lineage: dae7a449-5022-4bfe-a879-880349341594 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ddb5c5eca4 |
FN-8481: enable GitHub tracking for Ideas tasks
Allow operators to manage GitHub tracking from Ideas intake and Coding (Ideas) task details. - Permit GitHub tracking toggles in the Ideas column and the built-in Coding (Ideas) workflow. - Cover fallback and resolved workflow metadata paths with dashboard tests. - Add a patch changeset for the operator-facing capability. Files changed: .changeset/fn-8481-ideas-github-tracking.md | 7 ++++ .../dashboard/app/components/TaskDetailModal.tsx | 13 +++++-- ...lModal.inline-editing-and-integrations.test.tsx | 40 ++++++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-8481 Fusion-Task-Lineage: d267e203-bceb-492b-b218-8829406ef537 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
8ab4241afd |
FN-8476: restore Ideas detail move action
Restore Coding (Ideas) task-detail moves to Todo while preserving supplied workflow field definitions. - Resolve selected workflow columns independently for detail move actions - Use workflow-specific primary action labels and add desktop/mobile regression coverage - Add a patch changeset for the restored detail action Files changed: .changeset/fn-8476-coding-ideas-move.md | 7 ++ .../dashboard/app/components/TaskDetailModal.tsx | 85 +++++++++++++------- .../TaskDetailModal.custom-fields.test.tsx | 9 ++- .../__tests__/TaskDetailModal.rendering.test.tsx | 91 ++++++++++++++++++++++ 4 files changed, 160 insertions(+), 32 deletions(-) Fusion-Task-Id: FN-8476 Fusion-Task-Lineage: 37975987-91e4-47f2-9fa4-57b2074391f9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
57636226b1 |
FN-8421: align tablet task modal control heights
Align Task Detail action controls and Planner Chat composer heights across tablet and desktop. - Apply shared compact-height classes to inline Task Detail actions - Use Quick Add control-height tokens and remove conflicting button padding - Size Planner Chat Send and Stop controls to match the composer - Add dashboard regression coverage and a patch changeset Files changed: .../fn-8421-task-detail-tablet-control-heights.md | 7 ++++++ .../dashboard/app/components/TaskDetailModal.css | 18 ++++++++++++--- .../dashboard/app/components/TaskDetailModal.tsx | 11 ++++++--- .../app/components/TaskPlannerChatTab.css | 10 ++++++++ .../__tests__/TaskDetailModal.rendering.test.tsx | 8 +++++++ ...etailModal.responsive-and-dependencies.test.tsx | 13 +++++++++++ .../__tests__/TaskPlannerChatTab.test.tsx | 27 ++++++++++++++++++++++ 7 files changed, 88 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-8421 Fusion-Task-Lineage: 151795c8-4c00-4976-8901-9446557fc1a3 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
237d9be05f | fix(dashboard): de-emphasize empty verification status | ||
|
|
38891bfd81 |
FN-8296: add chat-requested task verification
Enable chat agents to queue and monitor executor-owned verification runs. - Persist task verification requests through a new PostgreSQL migration. - Expose action-gated chat request and status tools with executor processing. - Show verification status in task and Command Center views. - Advance the schema baseline to migration 0024 and keep chat mocks complete. Files changed: .changeset/fn-8296-feature.md | 7 ++ docs/agent-tool-surface-full-loop.md | 10 +-- docs/dashboard-guide.md | 4 + packages/core/src/index.ts | 2 + .../core/src/postgres/migrations/0000_initial.sql | 20 +++++ .../migrations/0024_task_verification_request.sql | 20 +++++ packages/core/src/postgres/schema-applier.ts | 13 ++- packages/core/src/postgres/schema/project.ts | 25 ++++++ packages/core/src/store.ts | 16 +++- packages/core/src/task-store/reads.ts | 14 +++- packages/core/src/task-store/remaining-ops-6.ts | 49 ++++++++++- packages/core/src/types.ts | 30 +++++++ packages/dashboard/app/api/legacy.ts | 1 + packages/dashboard/app/api/task-content.ts | 10 +++ .../dashboard/app/components/TaskDetailModal.tsx | 17 +++- .../app/components/TaskVerificationStatus.css | 94 ++++++++++++++++++++++ .../app/components/TaskVerificationStatus.tsx | 39 +++++++++ .../__tests__/TaskVerificationStatus.test.tsx | 28 +++++++ .../components/command-center/CommandCenter.css | 33 ++++++++ .../components/command-center/CommandCenter.tsx | 37 ++++++++- packages/dashboard/src/__tests__/chat.test.ts | 1 + packages/dashboard/src/chat.ts | 55 +++++++++++++ .../src/routes/register-command-center-routes.ts | 20 +++++ .../src/routes/register-task-workflow-routes.ts | 17 ++++ packages/engine/src/executor.ts | 51 +++++++++++- packages/engine/src/gating-classifications.ts | 5 ++ packages/engine/src/index.ts | 2 +- 27 files changed, 605 insertions(+), 15 deletions(-) Fusion-Task-Id: FN-8296 Fusion-Task-Lineage: f94647cf-c89f-4f0e-b25f-cbf5b56683bc Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
4a4f231ef4 |
fix(FN-8277): preserve planning task lineage (#2324)
## Summary Planning breakdowns now preserve their creating task as durable lineage and reuse only siblings from that same parent. Identical wording under a different parent creates a distinct child instead of silently linking the wrong lineage. The dashboard planning path now uses the same duplicate-safe creation contract as agent tools, leaves reused canonical tasks untouched, and exposes API-created parent links in task details. Related: FN-8277 ## Validation - Core duplicate guard: 12 tests passed - Engine task creation: 32 tests passed - Dashboard planning routes: 4 focused tests passed - Dashboard task detail provenance: 2 focused tests passed - Core, engine, dashboard, and CLI typechecks passed - Lint and strict changeset validation passed <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Preserved parent-task lineage for subtasks created through planning breakdowns and API workflows. - Improved duplicate detection so identical tasks from different parent tasks can coexist safely. - Added parent-task links to API-created task provenance details. - Reused existing duplicates only within the same parent-task context. - **Bug Fixes** - Prevented duplicate handling from incorrectly archiving or skipping tasks belonging to other parents. - Improved dependency handling when creating planned subtasks. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ce3f55fec9 |
FN-8263: reflect session advisor state in task-detail eye
Keep the task-detail oversight indicator aligned with the effective session advisor state. - Show and light the oversight eye for enabled advisor inheritance while lifecycle oversight is off or unresolved. - Limit unresolved advisor-only menus to the session advisor toggle and repaint the icon after toggles. - Cover desktop and mobile behavior and document the interaction. Files changed: .changeset/fn-8263-session-advisor-detail-eye.md | 7 ++ docs/dashboard-guide.md | 6 +- .../dashboard/app/components/TaskDetailModal.tsx | 47 ++++++---- .../TaskDetailModal.oversight-controls.test.tsx | 101 +++++++++++++++++++++ .../TaskDetailModal.oversight-mobile.test.tsx | 40 ++++++++ 5 files changed, 183 insertions(+), 18 deletions(-) Fusion-Task-Id: FN-8263 Fusion-Task-Lineage: 61cd134c-7721-4e19-89a9-a406358f54a9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
dbf52886ca |
FN-8256: preserve task detail tabs during column changes
Preserve a task detail view's selected tab and related state through live task column updates. - Reinitialize tabs only when the caller changes initialTab - Retain dedicated guards for unavailable PR, Summary, and Session tabs - Cover modal and embedded task-detail tab persistence Files changed: .../dashboard/app/components/TaskDetailModal.tsx | 20 +- .../TaskDetailModal.tab-persistence.test.tsx | 244 +++++++++++++++++++++ 2 files changed, 261 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-8256 Fusion-Task-Lineage: 86620e72-65b2-4c2f-b0e9-04ecce4d951c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
62f121e0c9 |
FN-8247: stop session advisor with oversight
Stop now persists session-advisor disablement and reflects inherited advisor state in task details. - Persist an explicit advisor-off override and clear its live runtime when stopping oversight. - Resolve workflow-level advisor defaults for task-detail icons and toggle behavior. - Cover stop cleanup and desktop/mobile oversight state transitions with regression tests. - Document the combined stop contract and add a patch changeset. Files changed: .changeset/fn-8247-session-advisor-stop-and-icon.md | 7 ++ docs/dashboard-guide.md | 6 +- packages/dashboard/app/components/TaskDetailModal.tsx | 86 +++++++++++------ packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-controls.test.tsx | 104 +++++++++++++++++++++ packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-mobile.test.tsx | 62 ++++++++++++ packages/engine/src/__tests__/project-engine-stop-overseer-session-advisor.test.ts | 62 ++++++++++++ packages/engine/src/project-engine.ts | 13 ++- 7 files changed, 310 insertions(+), 30 deletions(-) Fusion-Task-Id: FN-8247 Fusion-Task-Lineage: dcb67af7-9a36-4b25-bafa-84722fe158a0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
c43fdbb520 |
FN-8245: stabilize dashboard focus and planning tests
Make dashboard test execution deterministic and restore quarantined coverage. - Defer oversight-menu autofocus until the opening frame and cover both breakpoints. - Replace timing-dependent planning stream mocks with deterministic microtasks. - Isolate QuickEntryBox focus state and re-admit restored dashboard tests. Files changed: .../dashboard/app/components/TaskDetailModal.tsx | 15 ++- .../PlanningModeModal.planning-flow.test.tsx | 132 ++++++++++++++------- .../components/__tests__/QuickEntryBox.test.tsx | 13 ++ .../TaskDetailModal.oversight-mobile.test.tsx | 19 +-- packages/dashboard/vitest.config.ts | 24 ++-- scripts/lib/dashboard-curated-skiplist.json | 4 + scripts/lib/test-quarantine.json | 20 ---- 7 files changed, 140 insertions(+), 87 deletions(-) Fusion-Task-Id: FN-8245 Fusion-Task-Lineage: cd9b0638-0a6b-4dcf-980a-e90ba72b5db9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f0b6e4be0c |
FN-8233: reflect oversight state in menu trigger
Make the Oversight menu trigger icon reflect the effective overseer configuration. - Switch the trigger between Eye and EyeOff based on oversight level and Session advisor state. - Cover icon updates after changing either control. - Document the combined trigger-state behavior. Files changed: docs/dashboard-guide.md | 6 ++- .../dashboard/app/components/TaskDetailModal.tsx | 10 +++- .../TaskDetailModal.oversight-controls.test.tsx | 61 ++++++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-8233 Fusion-Task-Lineage: 16012bf1-94f8-4461-90b6-95d309aa9a6d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
cdcdc32679 |
FN-8232: keep task attachment picker available across tabs
Keep the task-detail attachment picker functional outside the Definition tab. - Mount the shared hidden file input outside tab-specific content. - Cover attachment picker access from the Activity tab. - Add a patch changeset for the task-detail fix. Files changed: .../fn-8232-task-detail-attachment-picker.md | 7 +++++++ .../dashboard/app/components/TaskDetailModal.tsx | 20 ++++++++++++------- ...lModal.inline-editing-and-integrations.test.tsx | 23 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) Fusion-Task-Id: FN-8232 Fusion-Task-Lineage: a425a373-f15c-4e7f-a50e-e2eba592d2c9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
611e51d2a8 |
FN-8209: align task detail toolbar icons on mobile
Make Task Detail inline controls use the compact, accessible Quick Add icon pattern. - Replace labeled priority and execution controls with icon-only buttons and a priority picker. - Apply shared icon sizing to oversight, attachment, priority, and fast-mode controls. - Update responsive and interaction coverage and add a patch changeset. Files changed: .changeset/fn-8209-task-detail-toolbar-icons.md | 7 + .../dashboard/app/components/TaskDetailModal.css | 160 ++++++--------------- .../dashboard/app/components/TaskDetailModal.tsx | 109 ++++++++++---- ...lModal.inline-editing-and-integrations.test.tsx | 31 ++-- .../TaskDetailModal.oversight-controls.test.tsx | 5 +- .../TaskDetailModal.oversight-mobile.test.tsx | 4 + .../__tests__/TaskDetailModal.rendering.test.tsx | 95 +++--------- ...etailModal.responsive-and-dependencies.test.tsx | 20 ++- 8 files changed, 182 insertions(+), 249 deletions(-) Fusion-Task-Id: FN-8209 Fusion-Task-Lineage: 3c079a7b-245a-4c4d-b058-6e1cf4b5a69d Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
a51cba0d69 |
FN-8197: move merge details to summary tab
Keep completed task merge metadata with its completion summary. - Relocate the Merge Details card from Definition to the done-only Summary tab. - Cover merge-detail states and Definition/mobile containment with dashboard tests. - Document the Summary tab behavior and add a patch changeset. Files changed: .changeset/fn-8197-merge-details-summary-tab.md | 7 +++ docs/dashboard-guide.md | 2 +- packages/dashboard/app/components/TaskDetailModal.tsx | 4 +- packages/dashboard/app/components/TaskSummaryTab.tsx | 9 +++ packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx | 49 ++++++++++------ packages/dashboard/app/components/__tests__/TaskDetailModal.summary-tab.test.tsx | 65 ++++++++++++++++++++++ 6 files changed, 115 insertions(+), 21 deletions(-) Fusion-Task-Id: FN-8197 Fusion-Task-Lineage: f4aac014-1e8d-4b8f-91f1-ba40ae879508 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
87ffb24fca |
FN-8194: align task detail inline controls
Align task-detail actions with Quick Add while preserving existing integrations. - Add inline attachment and eligible GitHub tracking controls - Replace the Oversight menu dots with an Eye icon and reorder metadata actions - Cover action order, integration behavior, icon rendering, and mobile wrapping Files changed: .changeset/fn-8194-task-detail-inline-controls.md | 7 ++ docs/dashboard-guide.md | 6 +- .../dashboard/app/components/TaskDetailModal.tsx | 99 +++++++++++++++------- ...lModal.inline-editing-and-integrations.test.tsx | 80 ++++++++++++++++- .../TaskDetailModal.mock-coverage.test.ts | 1 + .../TaskDetailModal.oversight-controls.test.tsx | 19 +++++ ...etailModal.responsive-and-dependencies.test.tsx | 5 +- .../__tests__/TaskDetailModal.test-helpers.ts | 10 +-- 8 files changed, 187 insertions(+), 40 deletions(-) Fusion-Task-Id: FN-8194 Fusion-Task-Lineage: 8de0e36f-b428-401c-98aa-35964c556a39 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
5f70447a62 |
FN-8108: require resolution for triage duplicate tasks
Require explicit resolution for triage-detected duplicate tasks. - Add configurable prompt, keep, and delete handling for explicit duplicate markers. - Surface linked duplicate decisions in task details and scheduling settings. - Preserve task failure provenance and strengthen lifecycle recovery coverage. Files changed: .changeset/blocked-park-survives-graph-teardown.md | 7 + .changeset/failure-provenance-promoter-marker.md | 7 + .changeset/fn-8108-triage-duplicate-resolution.md | 7 + .changeset/veto-progressing-does-not-clear.md | 7 + docs/settings-reference.md | 2 + .../completed-promotion-failure-provenance.test.ts | 31 +++ .../core/src/__tests__/duplicate-intake.test.ts | 11 ++ .../src/completed-promotion-failure-provenance.ts | 38 +++- packages/core/src/duplicate-intake.ts | 29 +++ packages/core/src/index.gate.ts | 1 + packages/core/src/index.ts | 3 +- packages/core/src/settings-schema.ts | 1 + packages/core/src/types.ts | 6 + .../dashboard/app/components/TaskDetailModal.tsx | 38 +++- .../__tests__/TaskDetailModal.rendering.test.tsx | 26 +++ .../settings/sections/SchedulingSection.search.ts | 9 + .../settings/sections/SchedulingSection.tsx | 15 ++ .../__tests__/routes-tasks-near-duplicate.test.ts | 31 +++ .../src/routes/register-task-workflow-routes.ts | 19 ++ .../__tests__/executor-task-done-blocked.test.ts | 212 ++++++++++++++++++++- packages/engine/src/__tests__/merger-ai.test.ts | 56 +++++- .../__tests__/overseer-noop-finalize-veto.test.ts | 64 ++++++- .../explicit-duplicate-marker-sweep.test.ts | 19 +- packages/engine/src/__tests__/self-healing.test.ts | 53 ++++++ .../triage-explicit-duplicate-marker.test.ts | 22 ++- packages/engine/src/executor.ts | 30 +++ packages/engine/src/merger-ai.ts | 5 +- packages/engine/src/overseer-noop-finalize-veto.ts | 148 ++++++++++---- packages/engine/src/self-healing.ts | 29 ++- packages/engine/src/triage.ts | 58 +++--- packages/i18n/locales/en/app.json | 15 +- packages/i18n/src/resources.d.ts | 13 +- 32 files changed, 897 insertions(+), 115 deletions(-) Fusion-Task-Id: FN-8108 Fusion-Task-Lineage: 8e732bad-d418-426e-85e1-903a7f990fba Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
50179ed5eb |
FN-8167: suppress failed UI during automatic recovery
Prevent transient automatic-retry tasks from appearing as terminal failures. - Centralize pending-recovery and manual-retry presentation rules. - Suppress failed styling, failure alerts, and Retry actions across list, card, and detail views. - Cover recovery timing and desktop/mobile task surfaces with regression tests. Files changed: .changeset/fn-8167-transient-retry-affordance.md | 7 ++ packages/dashboard/app/components/ListView.tsx | 16 ++--- packages/dashboard/app/components/TaskCard.tsx | 13 ++-- .../dashboard/app/components/TaskDetailModal.tsx | 13 ++-- .../app/components/__tests__/ListView.test.tsx | 38 +++++++++++ .../app/components/__tests__/TaskCard.test.tsx | 22 +++++++ .../__tests__/TaskDetailModal.rendering.test.tsx | 26 ++++++++ .../app/utils/__tests__/taskRecovery.test.ts | 77 ++++++++++++++++++++++ packages/dashboard/app/utils/taskRecovery.ts | 32 +++++++++ 9 files changed, 215 insertions(+), 29 deletions(-) Fusion-Task-Id: FN-8167 Fusion-Task-Lineage: 60d599e2-2e0e-46e7-ad16-cc6a836b5ac7 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f63818a6e9 |
FN-8072: add critical-action confirmation skip setting
Add a global operator preference that bypasses centralized critical-action confirmation dialogs. - Add a global-only skipConfirmationDialogs setting and Settings toggle - Return primary/default confirmation results without rendering dialogs when enabled - Route task reset actions through the centralized confirmation seam and add coverage - Document the setting and add a minor changeset Files changed: .changeset/fn-8072-skip-confirmation-dialogs.md | 7 +++++ docs/settings-reference.md | 1 + .../core/src/__tests__/settings-defaults.test.ts | 12 ++++++++- packages/core/src/settings-schema.ts | 5 ++++ packages/core/src/types.ts | 5 ++++ packages/dashboard/app/App.tsx | 11 ++++---- packages/dashboard/app/components/ListView.tsx | 20 +++++++++++---- packages/dashboard/app/components/TaskCard.tsx | 22 +++++++++++----- .../dashboard/app/components/TaskDetailModal.tsx | 26 +++++++++++-------- .../app/components/__tests__/ListView.test.tsx | 13 ++++++++++ .../__tests__/SettingsModal.general.test.tsx | 19 ++++++++++++++ .../app/components/__tests__/TaskCard.test.tsx | 17 ++++++++++++ .../components/__tests__/TaskDetailModal.test.tsx | 25 ++++++++++++++++++ .../app/components/settings/save-split.ts | 1 + .../sections/GlobalGeneralSection.search.ts | 10 ++++++++ .../settings/sections/GlobalGeneralSection.tsx | 10 ++++++++ .../settings-default-descriptions.test.tsx | 1 + .../app/hooks/__tests__/useConfirm.test.ts | 30 ++++++++++++++++++++++ packages/dashboard/app/hooks/useAppSettings.ts | 4 +++ packages/dashboard/app/hooks/useConfirm.ts | 21 ++++++++++++++- packages/i18n/locales/en/app.json | 4 ++- 21 files changed, 235 insertions(+), 29 deletions(-) Fusion-Task-Id: FN-8072 Fusion-Task-Lineage: bab4b8f2-5996-4161-8733-8e03bb6a7024 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e46ffebde1 |
FN-7985: surface review budget exhaustion and configure replan cap
Expose exhausted Plan Review replan budgets for operator approval and allow workflows to configure the cap. - Add validated numeric workflow setting support and a Plan Review replan-cap setting. - Route configured cap exhaustion with a distinct approval reason and preserve fallback behavior. - Display the budget-exhaustion state across task cards, lists, and details. - Add tests, localized copy, documentation, and a minor changeset. Files changed: .changeset/fn-7985-review-budget-approval.md | 7 ++++ docs/settings-reference.md | 9 +++-- docs/workflow-steps.md | 2 +- .../builtin-workflow-settings-triage.test.ts | 27 +++++++++++++-- packages/core/src/builtin-workflow-settings.ts | 17 ++++++++++ packages/core/src/index.gate.ts | 1 + packages/core/src/index.ts | 1 + packages/core/src/workflow-ir-types.ts | 4 +++ packages/core/src/workflow-ir.ts | 27 +++++++++++++++ packages/core/src/workflow-settings-resolver.ts | 1 + packages/core/src/workflow-settings.ts | 6 ++++ packages/dashboard/app/components/ListView.css | 19 +++++++++++ packages/dashboard/app/components/ListView.tsx | 22 +++++++++--- packages/dashboard/app/components/TaskCard.css | 18 ++++++++++ packages/dashboard/app/components/TaskCard.tsx | 6 ++-- .../dashboard/app/components/TaskDetailModal.tsx | 4 +-- .../app/components/__tests__/ListView.test.tsx | 30 +++++++++++++++++ .../app/components/__tests__/TaskCard.test.tsx | 17 ++++++++-- .../app/components/workflow-setting-display.ts | 11 ++++++ .../dashboard/app/utils/reviewBudgetApproval.ts | 11 ++++++ .../triage-plan-review-replan-cap.test.ts | 39 +++++++++++++++++++--- packages/engine/src/triage.ts | 21 ++++++++---- packages/i18n/locales/en/app.json | 2 +- packages/i18n/src/resources.d.ts | 19 ++++++++--- 24 files changed, 288 insertions(+), 33 deletions(-) Fusion-Task-Id: FN-7985 Fusion-Task-Lineage: 125f101c-caca-45c2-8b40-996b2a31c019 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e3f98253cc |
feat: Quality plugin — Task QA tab, preview servers, tests, and suggested cases (#2127)
## Summary Adds a bundled **Quality** plugin (`fusion-plugin-quality`) that makes task QA easier and more visual: - **Task QA tab** (action-first): preview/test server for the task worktree, allowlisted test runs, report viewer, screenshots CTA, suggested test cases, CI handoff - **Quality hub** (left sidebar): project-wide run history and preset launches - Host **task-detail slot context** (`taskId`, worktree, `projectId`) so plugin tabs can scope correctly - `superviseSpawn` re-exported on the plugin packaging shim for published plugins - Plan: `docs/plans/2026-07-14-001-feat-quality-plugin-plan.md` ## Design constraints - Does **not** replace the merge gate — advisory orchestration only - Composes Dev Server process patterns and artifact registry (no second browser stack) - Never free-form shell; never port 4040 - Full-suite requires explicit confirm ## Test plan - [x] `pnpm --filter @fusion-plugin-examples/quality test` (15 tests) - [x] PluginSlot unit tests still pass - [ ] Enable Quality plugin in dashboard Settings → Built-in Plugins - [ ] Open Task Detail → **QA** tab with a worktree; start preview, run verify:fast, generate suggestions - [ ] Open left sidebar **Quality** hub and list runs - [ ] Confirm merge gate / PR checks unchanged ## Residual / follow-up (same plan, later units) - Deeper hub CI (host route) - Full browser-verification toggle UX + agent QA sessions (U7/U9/U10) - Richer screenshots gallery wiring to live artifacts API - Test plans CRUD polish <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added the Quality plugin with a project Quality hub and task-focused QA tab. * Added test runs, reports, preview server controls, suggested test cases, and run history. * Added configurable test presets, cancellation, status tracking, and safe command execution. * Added experimental-feature controls for enabling Quality functionality. * Bundled Quality with the CLI and made it available through the plugin manager. * **Documentation** * Added Quality plugin guidance, terminology, configuration details, and implementation planning documentation. * **Bug Fixes** * Improved process supervision so command failures and shutdown timers are handled safely. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
96b1f21707 |
FN-7999: show failed-banner diagnostics and model/node retry
Expose a richer Task Failed banner with tool-error diagnostics and one-click retry using a different model or node. - Always show the failed banner for failed tasks (including errorless failures) with a generic reason fallback - Surface the latest agent-log tool_error detail and a retry hint for workflow/step-execute failures - Add Retry and Retry with a different model/node actions with deferred model/node override save on confirm - Style the banner recovery controls and cover them in TaskDetailModal tests - Add minor changeset for @runfusion/fusion Files changed: .changeset/fn-7999-failed-banner-retry.md | 7 + .../dashboard/app/components/TaskDetailModal.css | 47 +++++++ .../dashboard/app/components/TaskDetailModal.tsx | 143 ++++++++++++++++++++- .../__tests__/TaskDetailModal.test-helpers.ts | 3 +- .../components/__tests__/TaskDetailModal.test.tsx | 59 ++++++++- 5 files changed, 248 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-7999 Fusion-Task-Lineage: d4268c43-442f-4f39-afbe-c6f583ec0fc0 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
335b6a4dc2 |
fix: raise Plan Review replan cap to 8 and explain approval holds
Give planner/reviewer pairs more room to converge before escalating, and surface why a task is parked for plan approval—especially plan-review-replan-cap non-convergence—on cards, detail, and notifications. |
||
|
|
4f037679ad |
feat: planner overseer session advisor (OMP advisor parity) (#2082)
## Summary Adds a **session advisor** to the planner overseer so Fusion can review live executor transcripts the way [oh-my-pi’s advisor](https://github.com/can1357/oh-my-pi/tree/main/packages/coding-agent/src/advisor) does — without replacing the existing lifecycle supervisor (stage watch, retry, merge confirmation, human-control withhold). ### What ships - **Emission guard** (`OverseerEmissionGuard`) — content-free phrase filter, session dedupe with severity-rank escalation, one accept per advisor update - **Session delta runtime** — queues agent-log deltas, drains through an advisor agent, drops backlog after 3 failures - **Session advisor service** — model gate, level matrix (`observe` / `steer` / `autonomous`), human-control re-check at inject, `[session-advisor]` steering comments - **OVERSEER.md / WATCHDOG.md** discovery for project review priorities - **AgentLogger `onEntriesFlushed`** + poll-backed agent-log cursor for durable deltas - Workflow settings: `plannerOverseerAdvisorProvider` + `plannerOverseerAdvisorModelId` (both required; empty = soft-disabled for cost safety) - Docs + changeset ### What does not ship (deferred) - Multi-advisor YAML roster, mutating advisor tools, reviewer/merger shadowing, true tool-abort interrupt ### Plan `docs/plans/2026-07-13-001-feat-overseer-advisor-parity-plan.md` ## Enablement 1. Set workflow **Session advisor model provider** + **Session advisor model id** 2. Oversight level `observe` (log only), `steer`, or `autonomous` (inject) 3. Optional: add `OVERSEER.md` or `WATCHDOG.md` in the project ## Test plan - [x] `pnpm --filter @fusion/core exec vitest run src/__tests__/overseer-emission-guard.test.ts` - [x] `pnpm --filter @fusion/engine exec vitest run` overseer-* unit tests (21 tests) - [x] Related planner-overseer / intervention regression tests - [x] `@fusion/engine` + `@fusion/core` typecheck - [ ] Manual: configure advisor model, run an executor task, confirm `[session-advisor]` inject + timeline metadata when concern is raised ## Residual Review Findings None from autofix pass (log-cursor ordering fix already committed). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an off-by-default “session advisor” that can review live execution activity and provide severity-based guidance. * Added project and per-task controls to enable it, including a default enable switch and Quick Add / Task Detail toggles. * Enhanced advisor prompting by discovering and incorporating `OVERSEER.md`/`WATCHDOG.md` review files. * **Documentation** * Added architecture and settings documentation for the new session-advisor parity behavior. * **Bug Fixes** * Improved fail-soft handling so advisor behavior won’t disrupt execution. * Fixed concurrent PostgreSQL migration startup failures. * **Tests** * Added coverage for advice parsing, emission guarding, runtime behavior, and watchdog discovery. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
30d2e3660d |
FN-7927: fix Refine feedback modal self-dismissing immediately after opening
The task-detail Refine overlay used a raw onClick backdrop handler with a stopPropagation-wrapped inner modal, so the same click/touch sequence that opened Refine could bubble into the backdrop handler and close it right away; route it through the shared useOverlayDismiss contract instead so it behaves like every other dashboard modal. - Compute refineOverlayDismissProps via useOverlayDismiss(handleCloseRefineModal) and spread it onto the refine overlay instead of a plain onClick handler - Drop the redundant stopPropagation-only onClick from the inner .detail-refine-modal div now that the overlay itself no longer misfires on the opening interaction - Update docs/dashboard-guide.md to document that the Refine modal (Board and List entry points) stays open until an explicit close or an enabled backdrop dismissal - Add TaskDetailModal.refine.test.tsx regression coverage for the modal staying open across the opening interaction and honoring the dismiss-preference gate - Add a patch changeset summarizing the fix for @runfusion/fusion release notes Files changed: .changeset/fn-7927-refine-modal.md | 7 + docs/dashboard-guide.md | 8 +- .../dashboard/app/components/TaskDetailModal.tsx | 12 +- .../__tests__/TaskDetailModal.refine.test.tsx | 182 +++++++++++++++++++++ 4 files changed, 201 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-7927 Fusion-Task-Lineage: c7e7cd4a-d103-47e6-93ce-6577147b4795 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
49faf0afe2 |
FN-7832: reorder Task Detail tabs and default terminal picker to task worktree
Reworks the Task Detail terminal experience: the embedded Terminal tab now sits between Comments and Cost, its workspace picker defaults to the task's worktree, and the mobile terminal panel is shorter. - Move the Terminal tab in Task Detail's tab strip to sit right after Comments and before Cost (previously Cost was earlier and Terminal was near the Session tab) - TerminalModal now defaults its workspace picker to the useWorkspaces entry whose worktree matches the passed defaultCwd, but only until the operator manually changes the selection; the footer/global terminal still defaults to Project Root since it doesn't pass defaultCwd - Reduce `.detail-section--worktree-terminal`'s mobile min-height from min(65dvh, 14 * --space-2xl) to min(50dvh, 11 * --space-2xl) so tab context and controls stay reachable above the fold - Update docs/dashboard-guide.md to describe the new Comments → Terminal → Cost tab order and the worktree-matching picker default - Add regression tests covering the new tab order and the default terminal workspace selection behavior - Add a patch changeset describing the user-facing change Files changed: .changeset/FN-7832-task-terminal-picker-and-tab-order.md | 7 +++ docs/dashboard-guide.md | 9 +-- packages/dashboard/app/components/TaskDetailModal.css | 5 +- packages/dashboard/app/components/TaskDetailModal.tsx | 30 +++++----- packages/dashboard/app/components/TerminalModal.tsx | 19 +++++++ packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx | 15 ++--- packages/dashboard/app/components/__tests__/TaskDetailModal.worktree-terminal.test.tsx | 12 ++++ packages/dashboard/app/components/__tests__/TerminalModal.test.tsx | 64 ++++++++++++++++++++++ 8 files changed, 134 insertions(+), 27 deletions(-) Fusion-Task-Id: FN-7832 Fusion-Task-Lineage: 4ee67a65-8564-49c9-b93c-8c3eab05c073 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
17d7bd19ef |
FN-7826: make Task Detail interactive Terminal tab always available
Removes the single-worktree gate on the Task Detail Terminal tab so it renders for every task, defaulting its first shell to the task worktree when present and otherwise falling back to the project root. - TaskDetailModal.tsx: showWorktreeTerminalTab is now always true (drops the isWorkspaceTask/single-worktree gate and its stale fallback effect); taskWorktreeCwd still feeds defaultCwd when a worktree is recorded, and the tab renders without requiring taskWorktreeCwd - Adds a changeset documenting the behavior change (minor, feature) for @runfusion/fusion - docs/dashboard-guide.md: updates the Terminal tab description to state it is always available, with worktree-or-project-root cwd fallback, including for multi-repo workspace tasks - Expands TaskDetailModal.worktree-terminal.test.tsx coverage for the no-worktree and workspace-task cases now that the tab is always shown Files changed: .changeset/FN-7826-worktree-terminal-always-available.md | 7 +++ docs/dashboard-guide.md | 4 +- packages/dashboard/app/components/TaskDetailModal.tsx | 12 ++--- .../TaskDetailModal.worktree-terminal.test.tsx | 57 +++++++++++++++++++--- 4 files changed, 63 insertions(+), 17 deletions(-) Fusion-Task-Id: FN-7826 Fusion-Task-Lineage: f87504fe-9330-4392-bdbe-33bba006d96c Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
937650472a |
FN-7820: add Cost tab to task detail and optional card cost badge
Adds a shared cost-derivation utility and surfaces token/cost info in a new Cost tab on the task detail modal, plus an opt-in per-card cost badge on the board. - Extract token-cost calculation into a shared taskTokenCost helper (read-time costFor derivation) reused by the Summary tab, new Cost tab, and card badge - Add TaskDetailModal Cost tab (TaskCostTab.tsx/.css) showing cost breakdown for a task - Simplify TaskSummaryTab by delegating cost math to the shared helper - Add default-off project setting showCostBadgeOnCards (settings-schema.ts, types.ts) with a SettingsModal/AppearanceSection toggle - Add CostBadgeContext to thread the setting into TaskCard without prop drilling - Show an optional cost badge on TaskCard when the setting is enabled - Update i18n strings across en/es/fr/ko/zh-CN/zh-TW locales - Update docs (dashboard-guide.md, settings-reference.md) and add changeset fn-7820-cost-tab-and-card-badge.md Files changed: .changeset/fn-7820-cost-tab-and-card-badge.md | 7 ++ docs/dashboard-guide.md | 4 + docs/settings-reference.md | 1 + .../core/src/__tests__/settings-defaults.test.ts | 13 ++ packages/core/src/settings-schema.ts | 5 + packages/core/src/types.ts | 5 + packages/dashboard/app/App.tsx | 5 + .../dashboard/app/components/SettingsModal.tsx | 6 + packages/dashboard/app/components/TaskCard.css | 7 +- packages/dashboard/app/components/TaskCard.tsx | 27 +++- packages/dashboard/app/components/TaskCostTab.css | 51 ++++++++ packages/dashboard/app/components/TaskCostTab.tsx | 91 ++++++++++++++ .../dashboard/app/components/TaskDetailModal.tsx | 14 ++- .../dashboard/app/components/TaskSummaryTab.tsx | 123 +----------------- .../app/components/__tests__/TaskCard.test.tsx | 81 +++++++++++- .../app/components/__tests__/TaskCostTab.test.tsx | 55 ++++++++ .../TaskDetailModal.attachments-and-tabs.test.tsx | 11 +- .../settings/sections/AppearanceSection.tsx | 8 ++ .../sections/__tests__/AppearanceSection.test.tsx | 20 +++ .../settings-default-descriptions.test.tsx | 1 + .../dashboard/app/context/CostBadgeContext.tsx | 19 +++ packages/dashboard/app/hooks/useAppSettings.ts | 15 +++ .../app/utils/__tests__/taskTokenCost.test.ts | 62 +++++++++ packages/dashboard/app/utils/taskTokenCost.ts | 139 +++++++++++++++++++++ packages/i18n/locales/en/app.json | 29 ++++- packages/i18n/locales/es/app.json | 30 ++++- packages/i18n/locales/fr/app.json | 27 +++- packages/i18n/locales/ko/app.json | 30 ++++- packages/i18n/locales/zh-CN/app.json | 30 ++++- packages/i18n/locales/zh-TW/app.json | 30 ++++- 30 files changed, 789 insertions(+), 157 deletions(-) Fusion-Task-Id: FN-7820 Fusion-Task-Lineage: d33c5678-a68c-4b29-9db1-8ff0369dfd72 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6317fcddb5 |
FN-7813: add embedded worktree-rooted multi-tab Terminal to Task Detail
Add an interactive, worktree-rooted, multi-tab Terminal tab to the Task Detail view, distinct from the pre-existing CLI-agent Session tab. - TaskDetailModal gains a new embedded Terminal tab (single non-workspace task with one recorded worktree) that mounts TerminalModal in a new `embedded` render mode, rooted at the task's worktree - Rename the existing agent-session tab label to "Session" to disambiguate it from the new Terminal tab - useTerminalSessions gains task-scoped session storage and a `defaultCwd` option so embedded terminal tabs persist separately from footer/global project terminal tabs and start in the task worktree - TerminalModal/CSS updated to support the embedded layout mode - Update lazy-loaded-views docs test and AGENTS.md exclusion list to cover the new `LazyTerminalModal` task-detail-internal surface - Document the new Session/Terminal tab split in docs/dashboard-guide.md - Add i18n strings for the new Terminal tab across all locales - Add a changeset (minor) for @runfusion/fusion Files changed: .changeset/FN-7813-worktree-terminal-tab.md | 7 + AGENTS.md | 2 +- docs/dashboard-guide.md | 3 + .../app/__tests__/lazy-loaded-views-docs.test.ts | 4 +- .../dashboard/app/components/TaskDetailModal.css | 17 +++ .../dashboard/app/components/TaskDetailModal.tsx | 41 +++++- .../dashboard/app/components/TerminalModal.css | 51 +++++++ .../dashboard/app/components/TerminalModal.tsx | 71 +++++++--- .../__tests__/TaskDetailModal.test-helpers.ts | 3 + .../TaskDetailModal.worktree-terminal.test.tsx | 139 ++++++++++++++++++ .../components/__tests__/TerminalModal.test.tsx | 29 ++++ .../hooks/__tests__/useTerminalSessions.test.ts | 157 +++++++++++++++++++++ .../dashboard/app/hooks/useTerminalSessions.ts | 63 ++++++--- packages/i18n/locales/en/app.json | 3 +- packages/i18n/locales/es/app.json | 3 +- packages/i18n/locales/fr/app.json | 3 +- packages/i18n/locales/ko/app.json | 3 +- packages/i18n/locales/zh-CN/app.json | 3 +- packages/i18n/locales/zh-TW/app.json | 3 +- 19 files changed, 550 insertions(+), 55 deletions(-) Fusion-Task-Id: FN-7813 Fusion-Task-Lineage: 4ef86a15-347a-4862-b01c-5063d8004cb8 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
5729fe292c |
FN-7781: add optional workflow step toggles to task edit form
Enables editing a task's optional workflow steps directly from TaskForm edit mode, sourcing the step catalog from the resolved task workflow instead of re-seeding from defaultOn. - TaskForm loads optional-step catalog from the task's resolved workflow when editing and exposes toggles for enabling/disabling optional steps - TaskDetailModal passes through the additional workflow context needed for edit-mode step toggling - Added changeset for @runfusion/fusion (minor) - Updated docs/dashboard-guide.md to describe the new edit-mode workflow step behavior - Added test coverage in TaskForm.test.tsx and TaskDetailModal.models-progress-workflow.test.tsx Files changed: .changeset/fn-7781-edit-workflow-steps.md | 7 ++ docs/dashboard-guide.md | 5 +- .../dashboard/app/components/TaskDetailModal.tsx | 6 ++ packages/dashboard/app/components/TaskForm.tsx | 76 +++++++++++++----- ...skDetailModal.models-progress-workflow.test.tsx | 90 ++++++++++++++++++++++ .../app/components/__tests__/TaskForm.test.tsx | 51 ++++++++++++ 6 files changed, 214 insertions(+), 21 deletions(-) Fusion-Task-Id: FN-7781 Fusion-Task-Lineage: e44d9383-cfe7-4da1-9f20-8191211651cf Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
6a13ad175e |
FN-7732: remove dangling release-authorization UI/i18n/docs scaffolding
Narrative: The triage release-authorization gate itself was already removed in b5b0458; this cleans up the leftover scaffolding it left behind — an unemitted activity type, a dead TaskCard badge/label/CSS, orphaned i18n keys across all 6 locales, and a stale solutions doc — so the codebase no longer references a gate that no longer exists. - Drop the unused `task:release-authorization-required` ActivityEventType and its label/rendering in ActivityFeed.tsx and ActivityLogModal.tsx - Remove the dead `isReleaseAuthorizationHold` badge logic and `.awaiting-release-authorization` CSS class from TaskCard.tsx/TaskCard.css - Simplify TaskDetailModal.tsx comments/logic now that legacy release-authorization holds render as ordinary manual plan-approval holds - Delete orphaned i18n keys `tasks.awaitingReleaseAuthorization` and `taskDetail.plan.releaseAuthorizationHold` across en/es/fr/ko/zh-CN/zh-TW locales and resources.d.ts - Delete the stale docs/solutions/architecture-patterns/release-triage-requires-user-authorization.md doc - Update docs/workflow-steps.md and docs/settings-reference.md to describe the gate as removed (superseded by FN-7732) instead of documenting still-active behavior - Add changeset for @runfusion/fusion (patch/internal) Files changed: .changeset/fn-7732-remove-release-authorization-block.md | 7 +++++ docs/settings-reference.md | 2 +- docs/solutions/architecture-patterns/release-triage-requires-user-authorization.md | 33 ---------------------- docs/workflow-steps.md | 6 ++-- packages/core/src/types.ts | 8 ++++-- packages/dashboard/app/components/ActivityFeed.tsx | 5 ---- packages/dashboard/app/components/ActivityLogModal.tsx | 6 ---- packages/dashboard/app/components/TaskCard.css | 11 -------- packages/dashboard/app/components/TaskCard.tsx | 13 +++------ packages/dashboard/app/components/TaskDetailModal.tsx | 14 +++------ packages/i18n/locales/en/app.json | 3 -- packages/i18n/locales/es/app.json | 5 +--- packages/i18n/locales/fr/app.json | 5 +--- packages/i18n/locales/ko/app.json | 5 +--- packages/i18n/locales/zh-CN/app.json | 5 +--- packages/i18n/locales/zh-TW/app.json | 5 +--- packages/i18n/src/resources.d.ts | 3 -- 17 files changed, 30 insertions(+), 106 deletions(-) Fusion-Task-Id: FN-7732 Fusion-Task-Lineage: d4137bd8-9056-4062-9f2a-c6f5d47295f4 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
e4a59f7269 |
fix: remove over-firing triage release-authorization gate
The triage release-authorization gate (FN-6481/FN-6469) false-flagged any spec that merely mentioned release tooling (scripts/release.mjs, pnpm release) and, because non-user sources made the in-band authorization marker inert, stranded ordinary tasks in awaiting-approval with no exit. - Delete triage-release-authorization.ts + its test and the finalizeApprovedTask parking block; release-class specs now flow through triage normally. - Remove the dashboard approve/reject-plan API guards and UI gating so tasks still carrying the legacy awaitingApprovalReason="release-authorization" hold render as ordinary manual plan-approval holds and can be resolved. - Keep the awaitingApprovalReason field + activity label for backward-compat. - Replace the engine gate with agent instruction (AGENTS.md -> Releasing): agents must never run a release from inside a Fusion task. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
626e00288c |
FN-7720: add operator review-lane bypass for stranded pre-merge review failures
Add a policy-gated review-lane bypass primitive so operators can unstick cards stranded by a failed pre-merge review step (e.g. the no-feedback review-engine defect), without exposing it to agent-driven lanes.
- Add `store.bypassFailedPreMergeReviewStep(id, { reason, actor })` in @fusion/core plus `getLatestFailedPreMergeReviewStep` in task-merge.ts, and new `bypassedBy`/`bypassedAt`/`bypassReason`/`bypassedFromStatus`/`bypassedFromVerdict` fields on `WorkflowStepResult`
- Add operator-only `fn_task_bypass_review` CLI/pi-extension tool; explicitly withheld from executor/reviewer/triage agent tool lists
- Add `POST /tasks/:id/bypass-review` dashboard API route and wire it through `register-task-workflow-routes.ts` and legacy API compatibility layer
- Add dashboard UI affordance (context menu action + task detail modal + right-dock controller wiring) to trigger the bypass with a reason
- Add i18n strings for the bypass action/labels across en/es/fr/ko/zh-CN/zh-TW locales
- Update `gating-classifications.ts` to recognize the bypassed state
- Add unit tests: `store-bypass-review.test.ts`, `task-merge-bypass.test.ts`, extension test coverage, and `useTasks` hook test coverage
- Update docs (`docs/workflow-steps.md`, `docs/dashboard-guide.md`, AGENTS.md, fusion skill references) to describe the new bypass tool/route
- Add changeset `.changeset/fn-7720-review-lane-bypass-primitive.md` (minor)
Files changed:
$(git diff --cached --stat)
Fusion-Task-Id: FN-7720
Fusion-Task-Lineage: 590b020a-ae02-4b51-8189-df8f54bf3044
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
|
||
|
|
f4f165640a |
FN-7607: fix manual PR flow gating to key off global auto-merge setting
Fixes TaskDetailModal so manual PR affordances stay visible based on the live global auto-merge setting rather than the per-task effective override, and repairs a pre-existing test regression from the FN-7510 oversight default change. - isManualPrFlow now checks mergeStrategy === "pull-request" && !autoMergeEnabled (live global setting) instead of the per-task effective auto-merge override, fixing a regression from FN-7255 that stranded users without manual PR controls when a task's auto-merge override was true but global auto-merge was off. - Pinned plannerOversightLevel: "off" on the Chat-first default-routing test fixture so the FN-7510 autonomous-oversight default doesn't add an extra Activity-view option and break the test's actual intent (asserting Chat-first tab routing). - Added changeset documenting the fix. Files changed: .changeset/fn-7607-manual-pr-flow.md | 7 +++++++ packages/dashboard/app/components/TaskDetailModal.tsx | 14 +++++++++++++- .../TaskDetailModal.attachments-and-tabs.test.tsx | 12 +++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7607 Fusion-Task-Lineage: f0b077d4-792f-4e43-8e40-43d325920be5 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
f7dfcb3b09 |
FN-7604: collapse overseer/oversight controls into a single dropdown across surfaces
Unifies the previously mobile-only Oversight overflow menu into a single, always-present dropdown that replaces the scattered desktop oversight buttons and the separate mobile affordance. - Replace discrete desktop oversight action buttons in TaskDetailModal's footer with one universal "Oversight actions" dropdown trigger, reusing the menu across desktop and mobile breakpoints. - Simplify TaskDetailModal.tsx footer rendering logic, removing now-redundant responsive branching for oversight controls. - Update TaskDetailModal.css to drop the old mobile-only oversight-overflow styles and support the unified dropdown across breakpoints. - Update definition-actions, oversight-controls, oversight-mobile, rendering, and responsive-and-dependencies tests to assert the single dropdown behavior and disambiguate the exact "Actions" button query from the new "Oversight actions" aria-label. - Refresh docs/dashboard-guide.md to describe the unified oversight dropdown UX. Files changed: docs/dashboard-guide.md | 14 +- packages/dashboard/app/components/TaskDetailModal.css | 89 +++++------ packages/dashboard/app/components/TaskDetailModal.tsx | 177 +++------------------ packages/dashboard/app/components/__tests__/TaskDetailModal.definition-actions.test.tsx | 70 ++++---- packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-controls.test.tsx | 130 ++++++++++----- packages/dashboard/app/components/__tests__/TaskDetailModal.oversight-mobile.test.tsx | 42 +++-- packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx | 27 ++-- packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx | 57 ++++--- 8 files changed, 278 insertions(+), 328 deletions(-) Fusion-Task-Id: FN-7604 Fusion-Task-Lineage: afbb7573-d654-48db-a9ac-aecbd8e22e46 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
5b193d2d08 |
FN-7600: fix Nudge control stuck on periodic-observation copy when overseer is active
Attach the transient plannerOverseerState snapshot to the single-task detail route so the Nudge control reflects live overseer observation instead of always showing the periodic-observation message. - GET /api/tasks/:id now best-effort attaches plannerOverseerState (mirrors the list route), never throwing on enrichment failure. - TaskDetailModal reads overseerSnapshot from workingTask (merged full-detail object) instead of the raw task prop, so detail refetches via fetchTaskDetail (dependency chips, Documents view, logs, post-open refetch) no longer drop the snapshot. - Added regression tests for the detail-route enrichment and the modal's Nudge-availability behavior. - Added a patch changeset documenting the fix. Files changed: .changeset/fn-7600-oversight-nudge-detail-snapshot.md | 7 ++ packages/dashboard/app/components/TaskDetailModal.tsx | 14 ++- .../TaskDetailModal.oversight-controls.test.tsx | 131 +++++++++++++++++++++ .../__tests__/tasks-planner-overseer-state.test.ts | 95 +++++++++++++++ packages/dashboard/src/routes/register-task-workflow-routes.ts | 25 +++- 5 files changed, 269 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-7600 Fusion-Task-Lineage: 500614d0-091a-461c-8e7b-329a7b791502 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
8a7507ad36 |
FN-7587: add predictive-back slide/fade animation for mobile task-detail dismissal
Adds a presentation-only enter animation for mobile task-detail surfaces (modal and board main-panel), layered on top of the existing FN-7583/FN-7586 dismissal routing, without altering close/back timing. - Gate a new `.task-detail-modal--mobile-transition` class in TaskDetailModal.tsx via a local resize listener at the 768px breakpoint, mirroring the existing OVERSIGHT_MENU_MOBILE_BREAKPOINT pattern - Add matching `.task-detail-main-panel--mobile-transition` modifier in MainContent.tsx gated by the existing isMobile prop - Add slide/fade keyframe animations in TaskDetailModal.css and styles.css, both honoring prefers-reduced-motion - Add regression tests covering the modal and board-panel mobile transition behavior - Document the Capacitor WebView limitation preventing a true interactive predictive-back in packages/mobile/README.md Files changed: .../dashboard/app/components/TaskDetailModal.css | 33 ++ .../dashboard/app/components/TaskDetailModal.tsx | 31 +- ...skDetail.mobile-transition.board-panel.test.tsx | 333 +++++++++++++++++++++ .../TaskDetail.mobile-transition.test.tsx | 156 ++++++++++ .../app/components/dashboard/MainContent.tsx | 10 +- packages/dashboard/app/styles.css | 35 +++ packages/mobile/README.md | 30 ++ 7 files changed, 626 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7587 Fusion-Task-Lineage: cc5f08df-4aaf-447d-9c30-237b32191d3f Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
a1a6b09a4f |
FN-7582: clarify oversight nudge-disabled guideline copy
Reword the disabled-Nudge tooltip/helper text so it no longer reads as an overseer fault, and split it into two distinct reasons. - Add taskDetail.oversight.nudgeSuppressedTitle for the human-control-suppressed case (user-paused, done/archived, autoMerge:false human-review terminal), naming manual control as the cause - Reword taskDetail.oversight.nudgeDisabledTitle to a reassuring periodic-poll framing for the no-observation-yet case instead of implying the overseer is idle - Compute the shared nudgeDisabledReason once and reuse it at all four render sites (mobile menu + desktop inline title/helper) so the two copies can't drift - Add a changeset (patch) documenting the operator-facing copy fix - Extend TaskDetailModal.oversight-controls tests and test-helpers to cover the new suppressed-vs-disabled copy branching Files changed: .changeset/fn-7582-oversight-guideline-copy.md | 7 ++ .../dashboard/app/components/TaskDetailModal.tsx | 37 +++++++++-- .../TaskDetailModal.oversight-controls.test.tsx | 76 +++++++++++++++++++++- .../__tests__/TaskDetailModal.test-helpers.ts | 7 ++ 4 files changed, 121 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-7582 Fusion-Task-Lineage: bf2ceab4-2fb0-4686-a9e1-9e015502a521 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |
||
|
|
ab28e7811c |
FN-7581: make Intervention Timeline activity panel full width on mobile
Stop the Interventions Activity segment from reserving padding for an overlay toggle button it never renders, which was insetting the FN-7519 timeline from the right edge (worse on mobile). - Add `.detail-activity--interventions` CSS modifier that zeroes `padding-inline-end` for the Interventions segment, both base and mobile breakpoints, while leaving Live/Feed/Raw's reserved padding untouched - Apply the new modifier class to the Interventions `.detail-activity` container in TaskDetailModal.tsx - Add a regression test asserting the Interventions container carries `detail-activity--interventions` while the Feed container (which still renders the overlay toggle) does not Files changed: .../dashboard/app/components/TaskDetailModal.css | 18 ++++++++++ .../dashboard/app/components/TaskDetailModal.tsx | 2 +- .../TaskDetailModal.oversight-controls.test.tsx | 38 ++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-7581 Fusion-Task-Lineage: d5c55773-7df3-4eb4-aa70-01f6e0a622c6 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai> |