Commit Graph

12330 Commits

Author SHA1 Message Date
gsxdsm
d873ee8160 docs: correct KTD-6 — the "flag-off" move path is live, the hooks path is dead (#2466)
Docs only. Corrects a factual error in the program plan merged in #2463,
found during Phase A execution.

## What was wrong

KTD-6 listed three deletions as "provably dead." Two are. The third —
the flag-off inline move path in `task-store/moves.ts` — is the **live**
path:

- It is gated on `isWorkflowColumnsCompatibilityFlagEnabled`
(`store.ts:38`), which reads the **raw**
`experimentalFeatures.workflowColumns` key.
- That is a *different* function from the always-true public
`isWorkflowColumnsEnabled`, which is what the plan reasoned from.
- No production code writes that key, so the flag reads false — the
inline branch runs for essentially every project, and
`default-workflow-hooks.ts` is the dead one.
- `moves.ts:637` already said so: *"this 'flag-OFF' branch is the
DEFAULT move path for nearly every project — the strict compat flag
reads false because nothing sets it."*

Deleting it would have swapped every project onto an untravelled code
path and called it a cleanup.

## Changes

- **KTD-6** carries the correction inline, with the two consequences
that bind the rest of the program.
- **U2** rescoped to the two proven-dead deletions; `moves.ts` is out of
scope for it.
- **New U2b** converges the two implementations with a per-behavior
equivalence proof, and **blocks Phase B** — nothing downstream may
assume the trait-hook path runs until it lands.
- **U3's emit point must attach to the live inline path.** Wired into
the dead hooks path, the event seam would never fire — and because
subscribers are non-authoritative by design, *nothing would fail a
test*.
- Risk table gains: *a "dead" branch turns out to be live*.

## How it was caught

The Phase A worker escalated instead of following the instruction,
because U2 carried a delete-only Execution note: *any behavior change
found while removing a branch means the branch was not dead — stop and
treat it as a finding*. I verified the claim independently (flag
function, absent writers, live `settings.json`, source comment) before
accepting it.

That note stays on every deletion unit.

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

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

* **Documentation**
* Clarified terminology in the workflow lifecycle migration plan,
distinguishing the live inline move path from the compat-flag behavior.
* Expanded the convergence phase with explicit behavior-equivalence
requirements, pinned observable expectations, and removal of compat-flag
branching.
* Updated the migration diagram and phase ordering to reflect the new
gating structure, revised scope boundaries, and refreshed risk
mitigations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 13:28:26 -07:00
gsxdsm
8b039a543e fix(desktop): advance Pi runtime pin to 0.82.1 for packaging PR lane (#2465)
## Summary
- Advance the matched Pi runtime pin (`pi-ai`, `pi-coding-agent`,
`pi-agent-core`, `pi-tui`) from **0.82.0 → 0.82.1** so
electron-builder's production-dependency walk accepts `pi-agent-core`'s
`pi-ai@^0.82.1` requirement.
- Fixes the Desktop packaging PR-lane failure:
`Production dependency @earendil-works/pi-ai not found for package
@earendil-works/pi-agent-core` (required `^0.82.1`).
- Keep the workspace override guard; update pin-policy fixtures and CLI
package-config expectations.
- Tighten the advisory packaging step-order test so it asserts against
the real `electron-builder --dir` step (not a missing release-only step
name that previously passed via `indexOf === -1`).
- Run `pnpm dedupe` so the packaging lane's lockfile dedupe
early-warning is clean.

## Context
#2439 pinned the full Pi closure at 0.82.0 and made recent main-based
packaging runs green. This advances to the current upstream patch so
deploy + electron-builder stay aligned with `pi-agent-core@0.82.1`'s
declared dependency range.

## Test plan
- [x] `node scripts/check-pi-versions-pinned.mjs`
- [x] `node --test scripts/__tests__/check-pi-versions-pinned.test.mjs`
- [x] `pnpm --filter @runfusion/fusion exec vitest run
src/__tests__/package-config.test.ts`
- [x] `pnpm --filter @fusion/desktop exec vitest run
src/__tests__/release-workflow.test.ts`
- [x] `pnpm dedupe --check`
- [ ] GitHub: Desktop packaging (should run full packaging walk —
lockfile/package.json touched)
- [ ] GitHub: PR Checks (Lint, Typecheck, Build, Gate)
2026-07-26 23:47:49 -07:00
gsxdsm
3c5d07ab01 docs: workflow-owned lifecycle program plan + column-placement contract (#2463)
Docs only — no code. Companion to #2462.

##
`docs/solutions/architecture-patterns/workflow-node-column-placement-and-graph-entry-contract.md`

Why a workflow node's `column` is a lifecycle contract rather than a
display choice: it decides **who can drive the node**, **whether the
card holds a WIP slot**, and **whether anything can move it onward**.

Contents:
- The graph **entry contract** (`resolveColumnResumeNode`, shipped in
#2462) with the resume table.
- The **plan-in-place chain** — triage → finalize → continuation seed →
drain → resume → capacity suspend → release — annotated with the check
each link performs. Notably `todo`, not `triage`: an intake column has
no releaser, so a card parked there waits for a human.
- Why the pre-release gate must be narrow (column match **and**
enablement).
- The measured failure table from three reverted placement attempts.
- Why removing a column is a lifecycle-vocabulary refactor, not a
workflow edit: **82 guards** that silently stop matching, **43 writes**
to a column that no longer exists, **59 dashboard literals**. A guard
that never fires doesn't fail a test — it disables a recovery path.

## `docs/plans/2026-07-26-001-refactor-workflow-owned-lifecycle-plan.md`

The program that finishes the job, in four movements:

1. Resolve lifecycle columns from the workflow instead of ~207 string
literals.
2. Move every lane — planning, execution, review, merge — behind graph
nodes; lane services keep substrate only (storage, leases, timers,
supervision, capacity, recovery, audit).
3. A **post-commit event seam**: transitions commit transactionally,
*then* emit; subscribers react and may enqueue durable work items, but
no subscriber performs a transition. Enforced by test — dropping every
subscriber must change no lifecycle outcome.
4. Only then merge Todo into a single Planning column.

Phased so each phase lands green independently, with the IR change
deliberately **last** (KTD-7). Changing the workflow first makes the
suite green over dead guards — that's how the earlier attempts hid their
own breakage.

The merge lane **adopts** the existing design in
`docs/plans/2026-06-09-003-refactor-workflow-owned-merge-full-migration-slices-plan.md`
(slices S02–S08, still `draft-stack-handoff`) rather than authoring a
competing one, with a note to re-validate against current `main` since
it was drafted seven weeks ago.

Scale is stated honestly: ~48k lines across the four lane services, with
the executor unit explicitly landing across several commits rather than
one sweep.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 23:43:45 -07:00
gsxdsm
99c9f14ee0 feat: run Plan Review in the planning lane with a Plan Review badge (#2462)
## What

Plan Review, planning, and the replan loop move from the implementation
column into the **planning lane** (`todo`), so a task under
specification never holds a WIP slot. The card crosses into
`in-progress` exactly once, at `parse`, released by the scheduler.

Operators also finally see a **Plan Review** badge while the gate runs —
it was previously invisible on the default workflow.

## The part that made it possible

Moving the node is ten lines. It was attempted three times and reverted
each time, because a graph run with no durable continuation replayed
from `start` and dragged an in-progress card *backward* out of the WIP
column, firing `abort-on-exit` and stranding it in a pre-WIP column with
no releaser.

So this PR adds the graph **entry contract** —
`resolveColumnResumeNode`:

| Card is in | Resumes at |
|---|---|
| `triage` | `start` |
| `todo` | `plan` |
| `in-progress` | `parse` — never re-plans, never moves backward |
| `in-review` | first review node — gates are not skipped |

`ir.columns` is ordered and that order is the lifecycle order; rework
and failure edges are excluded so the entry point is always the main
path. The proof it's the right fix: **`executor-task-done-invariant`
passes unmodified** after failing every previous attempt.

## Also in here

- **Release gate narrowed twice.** `isUnplannedForExecution` applies its
pre-release plan-review gate only when the node's column equals the
card's column *and* the group is enabled for the task. The enablement
check fixes a real deadlock — a task with Plan Review toggled off was
held forever waiting for evidence nothing would ever write.
- **Badge cleanup.** Gate badge reads "Plan Review" instead of the
ambiguous "Reviewing" and no longer hides behind a lane restriction; the
status badge stops duplicating it; `planning` renders as "Planning"
instead of the raw engine token.
- **Coding (Ideas)** renames its planner column to "Planning" (id `todo`
unchanged) and loses its private planning-node re-home — the graph it
clones is already plan-in-place.
- **New sweep** `reconcileUndeclaredTaskColumns` re-homes a row whose
column its workflow no longer declares. Written for a follow-up, kept
because it makes any column edit survivable.

## Test changes

Scheduler and release fixtures now model a card whose Plan Review passed
— the state every real card is in when the capacity sweep sees it. A
held unreviewed card is the gate working, and that path stays owned by
`pre-release-plan-review.test.ts`.

New `workflow-graph-entry-contract.test.ts` covers the invariant at
every lifecycle position, plus the gap-column and remediation-node
cases.

## Verification

Gate 299 + 70 + 10, dashboard badge suites 672, engine
workflow/entry/executor suites 147, core 122. Lint and typecheck clean.
Full engine suite sits at the pre-existing baseline (notifier /
plugin-runner / notification-service, untouched by this).

## Follow-up

Removing the Todo column entirely is a separate ~207-site
lifecycle-vocabulary refactor — planned in
`docs/plans/2026-07-26-001-refactor-workflow-owned-lifecycle-plan.md`
(companion docs PR).

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

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

## Summary by CodeRabbit

* **New Features**
* Plan Review now runs in the Planning lane before implementation
begins.
* Cards resume from their current workflow column without replaying
earlier steps.
* Added automatic recovery for cards stranded in outdated workflow
columns.
* **Improvements**
  * Renamed the Coding (Ideas) planner column to “Planning.”
* Refined Plan Review gating to respect enabled settings and the card’s
current column.
* Updated planning and Plan Review badges for clearer, consistent labels
across cards and lists.
* **Bug Fixes**
* Improved workflow transitions and release behavior around planning,
review, and execution.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 23:42:46 -07:00
gsxdsm
5ae6332563 refactor: collapse dead SQLite dual-path code; keep migration-only readers (#2454)
# Remove dead SQLite dual-path code; keep migration-only readers

## Summary
PostgreSQL cutover left hundreds of production dual-path branches
(`backendMode ? PG : SQLite/store.db`) whose SQLite arms only hit
throwing `Database`/`ArchiveDatabase`/`CentralDatabase` stubs. This
change mechanically collapses those unreachable arms so production
authority is AsyncDataLayer/PostgreSQL only, while preserving the six
authorized read-only migration/recovery `DatabaseSync` seams.

## Dual-path mass removed
| Metric | Before | After |
|---|---|---|
| `if (…backendMode)` (non-test) | ~328 | ~70 |
| `store.db` / `this.db` refs in core (non-test) | ~570+ | ~375 (mostly
pure legacy MissionStore/eval/insight SQLite classes + thin getters) |
| Net diff | — | **~6.7k lines removed** across 41 files |

Remaining `backendMode` checks are intentional (incomplete-PG sync
safe-defaults, settings-sync disabled-on-PG, symbol-lock PG-only gates,
“requires PostgreSQL” config versioning throws), not live SQLite
authority.

## Subsystems cleaned
- **Core TaskStore / task-store/***: collapsed if/else and early-return
dual-path across reads, moves, lifecycle, mutations, workflow, archive,
branch/PR, artifacts, comments, audit, project ops, etc. `initImpl` is
PostgreSQL-only (SQLite startup tail deleted).
- **Satellite stores**: automation, agent, routine, plugin, secrets,
approval-request, central-core dual-path arms collapsed.
- **Plugins**: reports async methods, compound-engineering pipeline +
session stores, CLI Printing Press store — SQLite fallbacks removed; PG
required.
- **Engine**: no functional dual-path change beyond whitespace
(settings-sync / peer-exchange PG-disabled behavior kept).

## Six migration-only readers retained (allowlist unchanged)
1. `packages/core/src/postgres/sqlite-migrator.ts`
2. `packages/core/src/project-identity.ts`
3. `packages/core/src/sqlite-validation.ts`
4. `packages/core/src/postgres/startup-factory.ts`
5. `packages/cli/src/commands/db.ts`
6. `scripts/lib/start-local-project.mjs`

Plus low-level `sqlite-adapter` and migrator/startup-import tests.
Inventory ratchet still requires exactly these six `new DatabaseSync(`
production sites, all `readOnly: true`.

## Not treated as SQLite
- `.fusion/project.json`, `task.json`, `agent-log.jsonl` file storage
- AsyncDataLayer / Drizzle PG paths
- Incomplete-PG sync safe-default stubs (still return empty/false/null
under backend without consulting SQLite)

## Verification
- `sqlite-production-reader-inventory.test.ts` — 15/15 pass
- `incomplete-pg-ports.pg.test.ts` — 6/6 pass
- Targeted PG tests (create-task, move, handoff, runtime-persistence,
agent, mission, insight, central-core) — green
- `tsc --noEmit` for `@fusion/core`, `@fusion/engine`,
`@fusion/dashboard` — green
- `scripts/check-no-getdatabase.mjs` — clean

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

* **Improvements**
* Improved end-to-end consistency by making PostgreSQL/async persistence
the standard across core task/workflow, automation, agents, plugins,
routines, secrets, approvals, central operations, and session storage.
* Unified scheduling, settings, configuration revision writes,
run/workflow selection, queues/leases/transitions, and audit/lifecycle
updates around consistent async transaction behavior.
* **Bug Fixes**
* Fixed edge cases for archived/deleted reads, unarchive/recovery flows,
not-found handling, and task/artifact/document/log/comment operations,
including more reliable emissions and hydration across search/list and
lifecycle operations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-26 23:28:42 -07:00
Phil Larson
52d64fa66e fix(engine): project CE steps after review handoff (#2464)
## Summary

- reconcile successful graph-native workflow results with pending task
checklist steps even when review handoff already moved the card into the
merge column
- preserve terminal, paused, and no-redundant-move behavior
- cover the real Compound Engineering post-review-handoff state with a
regression test

## Root cause

Compound Engineering runs `review-handoff` before `merge`. Review
handoff moves the task to `in-review`, which is also the merge column.
`ensureWorkflowMergeBoundaryTask()` returned immediately for cards
already in that column, before projecting successful
`workflowStepResults` onto legacy `Task.steps[]`. The merger then saw
`0/N` and rejected approved work with `task has incomplete steps`.

## Verification

- RED: regression test failed before the fix because `store.updateTask`
was never called
- GREEN: `executor-graph-boundary.test.ts` — 6 passed
- relevant non-PostgreSQL set — 31 passed, 5 PostgreSQL tests explicitly
skipped
- `@fusion/engine` typecheck passed
- changeset format passed
- `git diff --check` passed

## Baseline note

`ce-workflow-step-executor.test.ts` currently has three failures on
clean `origin/main` after FN-8601 foreach-proof hardening. The same
failures reproduce without this patch and are not regressions from this
change.


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

* **Bug Fixes**
* Improved reconciliation after review handoff by projecting completed
step results onto the legacy checklist when reaching the merge column.
* Prevented tasks from being marked approved with incomplete step counts
(including “0/N” style states).
* Reduced unnecessary merge failures and deadlock/pause scenarios when
merge-column progress was already recorded.
* **Tests**
* Added coverage for execute-and-merge workflows, ensuring
merge-boundary resolution updates pending steps without moving the task.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-26 23:13:21 -07:00
dependabot[bot]
d6c7e7dc74 chore(deps): bump actions/cache from 4 to 6 (#2441)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update packages, migrate to ESM by <a
href="https://github.com/Samirat"><code>@​Samirat</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1760">actions/cache#1760</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v6.0.0">https://github.com/actions/cache/compare/v5...v6.0.0</a></p>
<h2>v5.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/cache</code> to v5.1.0 - handle read-only cache
access by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1775">actions/cache#1775</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.1.0">https://github.com/actions/cache/compare/v5...v5.1.0</a></p>
<h2>v5.0.5</h2>
<h2>What's Changed</h2>
<ul>
<li>Update ts-http-runtime dependency by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1747">actions/cache#1747</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.5">https://github.com/actions/cache/compare/v5...v5.0.5</a></p>
<h2>v5.0.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Add release instructions and update maintainer docs by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1696">actions/cache#1696</a></li>
<li>Potential fix for code scanning alert no. 52: Workflow does not
contain permissions by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1697">actions/cache#1697</a></li>
<li>Fix workflow permissions and cleanup workflow names / formatting by
<a href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1699">actions/cache#1699</a></li>
<li>docs: Update examples to use the latest version by <a
href="https://github.com/XZTDean"><code>@​XZTDean</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li>Fix proxy integration tests by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1701">actions/cache#1701</a></li>
<li>Fix cache key in examples.md for bun.lock by <a
href="https://github.com/RyPeck"><code>@​RyPeck</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
<li>Update dependencies &amp; patch security vulnerabilities by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1738">actions/cache#1738</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/XZTDean"><code>@​XZTDean</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li><a href="https://github.com/RyPeck"><code>@​RyPeck</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.4">https://github.com/actions/cache/compare/v5...v5.0.4</a></p>
<h2>v5.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.3">https://github.com/actions/cache/compare/v5...v5.0.3</a></p>
<h2>v.5.0.2</h2>
<h1>v5.0.2</h1>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h1>Releases</h1>
<h2>How to prepare a release</h2>
<blockquote>
<p>[!NOTE]
Relevant for maintainers with write access only.</p>
</blockquote>
<ol>
<li>Switch to a new branch from <code>main</code>.</li>
<li>Run <code>npm test</code> to ensure all tests are passing.</li>
<li>Update the version in <a
href="https://github.com/actions/cache/blob/main/package.json"><code>https://github.com/actions/cache/blob/main/package.json</code></a>.</li>
<li>Run <code>npm run build</code> to update the compiled files.</li>
<li>Update this <a
href="https://github.com/actions/cache/blob/main/RELEASES.md"><code>https://github.com/actions/cache/blob/main/RELEASES.md</code></a>
with the new version and changes in the <code>## Changelog</code>
section.</li>
<li>Run <code>licensed cache</code> to update the license report.</li>
<li>Run <code>licensed status</code> and resolve any warnings by
updating the <a
href="https://github.com/actions/cache/blob/main/.licensed.yml"><code>https://github.com/actions/cache/blob/main/.licensed.yml</code></a>
file with the exceptions.</li>
<li>Commit your changes and push your branch upstream.</li>
<li>Open a pull request against <code>main</code> and get it reviewed
and merged.</li>
<li>Draft a new release <a
href="https://github.com/actions/cache/releases">https://github.com/actions/cache/releases</a>
use the same version number used in <code>package.json</code>
<ol>
<li>Create a new tag with the version number.</li>
<li>Auto generate release notes and update them to match the changes you
made in <code>RELEASES.md</code>.</li>
<li>Toggle the set as the latest release option.</li>
<li>Publish the release.</li>
</ol>
</li>
<li>Navigate to <a
href="https://github.com/actions/cache/actions/workflows/release-new-action-version.yml">https://github.com/actions/cache/actions/workflows/release-new-action-version.yml</a>
<ol>
<li>There should be a workflow run queued with the same version
number.</li>
<li>Approve the run to publish the new version and update the major tags
for this action.</li>
</ol>
</li>
</ol>
<h2>Changelog</h2>
<h3>6.1.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v6.1.0 to pick up <a
href="https://redirect.github.com/actions/toolkit/pull/2435">actions/toolkit#2435
Handle cache write error due to read-only token</a></li>
<li>Switch redundant &quot;Cache save failed&quot; warning to debug log
in save-only</li>
</ul>
<h3>6.0.0</h3>
<ul>
<li>Updated <code>@actions/cache</code> to ^6.0.1,
<code>@actions/core</code> to ^3.0.1, <code>@actions/exec</code> to
^3.0.0, <code>@actions/io</code> to ^3.0.2</li>
<li>Migrated to ESM module system</li>
<li>Upgraded Jest to v30 and test infrastructure to be ESM
compatible</li>
</ul>
<h3>5.0.4</h3>
<ul>
<li>Bump <code>minimatch</code> to v3.1.5 (fixes ReDoS via globstar
patterns)</li>
<li>Bump <code>undici</code> to v6.24.1 (WebSocket decompression bomb
protection, header validation fixes)</li>
<li>Bump <code>fast-xml-parser</code> to v5.5.6</li>
</ul>
<h3>5.0.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<h3>5.0.2</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="55cc834586"><code>55cc834</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1768">#1768</a>
from jasongin/readonly-cache</li>
<li><a
href="d8cd72f230"><code>d8cd72f</code></a>
Bump <code>@​actions/cache</code> to v6.1.0 - handle cache write error
due to RO token</li>
<li><a
href="2c8a9bd745"><code>2c8a9bd</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1760">#1760</a>
from actions/samirat/esm_migration_and_package_update</li>
<li><a
href="e9b91fdc3f"><code>e9b91fd</code></a>
Prettier fixes</li>
<li><a
href="e4884b8ff7"><code>e4884b8</code></a>
Rebuild dist</li>
<li><a
href="10baf0191a"><code>10baf01</code></a>
Fixed licenses</li>
<li><a
href="e39b386c90"><code>e39b386</code></a>
Fix test mock return order</li>
<li><a
href="b692820337"><code>b692820</code></a>
PR feedback</li>
<li><a
href="60749128a4"><code>6074912</code></a>
Rebuild dist bundles as ESM to match type:module</li>
<li><a
href="5a912e8b4a"><code>5a912e8</code></a>
Fix lint and jest issues</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v4...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache&package-manager=github_actions&previous-version=4&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 22:49:14 -07:00
dependabot[bot]
88cc152d12 chore(deps): bump actions/setup-node from 4 to 7 (#2440)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4
to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Add cache-primary-key and cache-matched-key as outputs by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1577">actions/setup-node#1577</a></li>
<li>Migrate to ESM and upgrade dependencies by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1574">actions/setup-node#1574</a></li>
</ul>
<h3>Bug fixes:</h3>
<ul>
<li>Remove dummy NODE_AUTH_TOKEN export by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1558">actions/setup-node#1558</a></li>
<li>Only use <code>mirrorToken</code> in <code>getManifest</code> if
it's provided by <a
href="https://github.com/deiga"><code>@​deiga</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
</ul>
<h3>Documentation updates:</h3>
<ul>
<li>Add documentation for publishing to npm with Trusted Publisher
(OIDC) by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li>docs: Update restore-only cache documentation by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1550">actions/setup-node#1550</a></li>
<li>docs: Update caching recommendations to mitigate cache poisoning
risks by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1567">actions/setup-node#1567</a></li>
</ul>
<h3>Dependency update:</h3>
<ul>
<li>Upgrade <code>@​actions/cache</code> to 5.1.0, log cache write
denied by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li><a href="https://github.com/deiga"><code>@​deiga</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
<li><a href="https://github.com/jasongin"><code>@​jasongin</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v7.0.0">https://github.com/actions/setup-node/compare/v6...v7.0.0</a></p>
<h2>v6.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update <code>@​actions/cache</code> to 5.1.0 and add security
overrides for undici and fast-xml-parser by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1579">actions/setup-node#1579</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0">https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0</a></p>
<h2>v6.4.0</h2>
<h2>What's Changed</h2>
<h3>Dependency updates:</h3>
<ul>
<li>Upgrade <a
href="https://github.com/actions"><code>@​actions</code></a>
dependencies by <a
href="https://github.com/Copilot"><code>@​Copilot</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1525">actions/setup-node#1525</a></li>
<li>Update Node.js versions in versions.yml and bump package to v6.4.0
by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1533">actions/setup-node#1533</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Copilot"><code>@​Copilot</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1525">actions/setup-node#1525</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v6.4.0">https://github.com/actions/setup-node/compare/v6...v6.4.0</a></p>
<h2>v6.3.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Support parsing <code>devEngines</code> field by <a
href="https://github.com/susnux"><code>@​susnux</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1283">actions/setup-node#1283</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8207627860"><code>8207627</code></a>
Migrate to ESM and upgrade dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1574">#1574</a>)</li>
<li><a
href="04be95cf35"><code>04be95c</code></a>
Add cache-primary-key and cache-matched-key as outputs (<a
href="https://redirect.github.com/actions/setup-node/issues/1577">#1577</a>)</li>
<li><a
href="7c2c68d20d"><code>7c2c68d</code></a>
docs: Update caching recommendations to mitigate cache poisoning risks
(<a
href="https://redirect.github.com/actions/setup-node/issues/1567">#1567</a>)</li>
<li><a
href="6a61c0375d"><code>6a61c03</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/setup-node/issues/1569">#1569</a>
from jasongin/update-actions-cache-5.1.0</li>
<li><a
href="30eb73b41d"><code>30eb73b</code></a>
Resolve high-severity audit issues</li>
<li><a
href="4e1a87a501"><code>4e1a87a</code></a>
Update dist</li>
<li><a
href="360237f0c0"><code>360237f</code></a>
Strict equality</li>
<li><a
href="4f8aac5beb"><code>4f8aac5</code></a>
Bump <code>@​actions/cache</code> to 5.1.0, log cache write denied</li>
<li><a
href="f4a67bbeca"><code>f4a67bb</code></a>
Only use <code>mirrorToken</code> in <code>getManifest</code> if it's
provided (<a
href="https://redirect.github.com/actions/setup-node/issues/1548">#1548</a>)</li>
<li><a
href="0355742c94"><code>0355742</code></a>
Remove dummy NODE_AUTH_TOKEN export (<a
href="https://redirect.github.com/actions/setup-node/issues/1558">#1558</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-node/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-node&package-manager=github_actions&previous-version=4&new-version=7)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-26 22:48:53 -07:00
gsxdsm
0e3d2a2265 refactor: delete meta-task auto-archive and automated recovery follow-ups (#2461)
Deletes two pieces of automated "meta" machinery that filed and
garbage-collected cards restating state already on the task that failed.
Net **-1015 lines**.

## Why

**Automated recovery follow-ups.** `createAutomatedFollowup` and its
dedup engine (289 lines of signature matching, 1h recurrence
rate-limiting, 24h supersedes windows) existed to file recovery cards
for verification-cap and merge-conflict give-ups. In both cases the
parent is *already* parked `failed` with a descriptive `error` and a log
entry carrying the failing command, branch, and output — the card was a
second copy of that.

**Meta-task auto-archive.** The sweeps that garbage-collected those
cards were worse than redundant: the regex classifier matched ordinary
feature work, and its positional fallback bound cards to unrelated
tasks, so **live work could be archived**.

They are removed together, because the auto-archive sweeps only existed
to clean up after the follow-up engine.

## What changed

### Deleted
- `packages/engine/src/verification-followup-dedup.ts` in full —
`createAutomatedFollowup`, `decideAutomatedFollowup`,
`AutomatedFollowupKind`, `computeVerificationFailureSignature`,
`extractFailingTestFiles`.
- `findActiveRecoveryFollowUp` — dead code, defined and never called
(`tsc` independently flagged it `6133 declared but its value is never
read`).
- The meta-task auto-archive sweeps `autoArchiveResolvedMetaTasks` /
`autoArchiveStalledMetaTasks` and helpers `classifyMetaTask` /
`resolveMetaTargetTaskId` / `computeMetaChainDepth` / `archiveMetaTask`
/ `evaluateMetaAutoArchiveGuards`, plus settings
`metaTaskStallAutoCloseMs` and `metaTaskActiveExecutionGraceMs`.
- Run-audit types `task:auto-archived-meta-resolved`,
`task:auto-archived-meta-stalled`,
`task:auto-archive-meta-resolved-skipped`,
`task:auto-archive-meta-stalled-skipped`,
`verification:followup-created`, `verification:followup-deduped`.

The two signature helpers were **deleted rather than relocated** — once
the three call sites went they were provably unreachable:
`buildVerificationFailureSignature` had exactly one caller, and it was
the only caller of `extractFailingTestFiles`.

### Call sites 1 and 2 — park kept, card dropped
Verification-cap and merge-conflict give-ups keep their park, audit
event, operator comment, and log entry. Site 1's `error` string was
reworded off `"See follow-up task for investigation."` (no follow-up
will exist) to carry the guidance itself. `autoResolveDisabled` was
**kept** — it still drives the outer park guard and the `reason` string;
only the inner branch that guarded card creation is gone.

### Call site 3 — autostash orphan, replaced not deleted
This one is a genuine data-loss guard, so it keeps a durable trail. A
`live`-classified orphan is a merger stash holding **real uncommitted
work**, and unlike sites 1–2 there is no parked parent — the parent may
already be `done` and merged, so nothing else on the board would ever
mention the stash.

The card is replaced by a `logEntry` **and** an `addTaskComment` on the
parent, preserving every fact the old description carried: the sha,
`record.label` (the handle `git stash` recovery needs),
`record.detectedByTaskId`, and `sourcePhase`. New truthful run-audit
event `task:autostash-orphan-live-detected` replaces the borrowed
`verification:followup-*` name, with ids/outcomes-only metadata per
AGENTS.md.

### Kept unchanged: the two real product features
Eval follow-ups (`eval-followups.ts`) and PR-comment follow-ups
(`pr-comment-handler.ts`) only borrowed the shared engine for its dedup
pass. Both keep their exact behavior, column, priority, `sourceType`,
and log lines, with dedup inlined as a `listTasks` scan on
`suggestionId` / `prNumber` respectively. Both fail open (create) if the
listing throws, matching the old engine.

## Test changes — read this one

Two tests asserted the *deleted* engine's rate-limited `"[verification
recurrence]"` logEntry. Those assertions were removed, **not loosened**:
both tests still assert no duplicate card is created, and the eval test
still asserts the existing id is reported back. No coverage of surviving
behavior was weakened. The three `meta-*` test files were deleted along
with the sweeps they covered.

## Verification

```
$ pnpm test:gate
 Test Files  2 passed (2)     Tests   10 passed (10)    # core
 Test Files  16 passed (16)   Tests  299 passed (299)   # engine-core
 Test Files  1 passed (1)     Tests   70 passed (70)    # ci-shape
GATE_EXIT=0

$ pnpm --filter @fusion/engine --filter @fusion/core exec tsc --noEmit -p tsconfig.json
TSC_EXIT=0   (no output)
```

Plus a file-scoped run over the touched surfaces (`eval-followups`,
`pr-comment-handler`, `merger-autostash-orphan-surface`,
`merger-autostash-cleanup`, `run-audit`, `run-audit-secret-taxonomy`,
`project-engine`, `project-engine-manager`): **213/213 passed**.

A repo-wide grep confirms no surviving references to any deleted symbol,
module, or audit event.

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


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

## Summary by CodeRabbit

* **Bug Fixes**
* Failed tasks now retain recovery and verification details directly on
the original task instead of generating separate follow-up cards.
* Live autostash issues now preserve stash information in task comments
and activity logs.
* Existing evaluation and pull-request follow-ups continue to be reused
when appropriate.

* **Changes**
  * Removed automatic archival of meta-tasks.
  * Removed obsolete meta-task timing settings.

* **Documentation**
* Updated architecture and settings documentation to reflect these
workflow changes.

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

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 22:38:58 -07:00
Phil Larson
d19c82b33b test(dashboard): align modal and locale fixtures (#2460)
## Summary
- query Task Detail modal assertions from the document after its
FloatingWindow portal migration
- sync secondary locale catalogs with the current English key structure

## Test plan
- `pnpm --filter @fusion/dashboard exec vitest run
app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx
--silent=passed-only --reporter=dot`
- `pnpm i18n:status`
- `pnpm --filter @fusion/dashboard build`

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

* **Documentation**
* Added missing localization entries for workflow selection/help text,
action-based report targeting, agent tool output limit hints,
auto-update/restart messaging, and task refinement status labels across
Spanish, French, Korean, Simplified Chinese, and Traditional Chinese.

* **Tests**
* Updated task detail modal tests to query the correct rendered document
root so portal/modal content is asserted reliably.
* Minor test formatting adjustments to keep assertions consistent
without changing coverage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-26 22:36:09 -07:00
Phil Larson
11887625f1 test(dashboard): align touch fixture with FloatingWindow (#2459)
## Summary
- update the touch-resize browser fixture assertions for New Task's
FloatingWindow migration
- verify the shared nine touch targets, resize handle ID, and unified
geometry persistence key

## Test plan
- `corepack pnpm --filter @fusion/dashboard build`
- `corepack pnpm --filter @fusion/dashboard exec vitest run --project
dashboard-browser-touch --silent=passed-only --reporter=dot
src/__tests__/task-modal-touch-resize-browser.test.ts`
- `corepack pnpm check:changesets`


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

* **Tests**
* Updated tablet touch-resize coverage for task-detail to use the shared
southeast resize handle and corrected expected hit-target counts.
* Refreshed hit-target detection and drag target assertions after
switching the test surface to the task-detail/floating window layout.
* Updated persistence/geometry validations to compare the stored unified
width/height against the resized panel dimensions.
* Reworked desktop vs tablet assertions, including tighter overlay
padding checks and standardized shared resize-handle sizing
expectations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-26 22:35:53 -07:00
Phil Larson
232e17d1cb test(engine): complete runtime logger mock (#2458)
## Summary
- add the missing `debug` method to the runtime-resolution logger mock
- prevent logger calls from short-circuiting runtime selection
assertions

## Test plan
- `pnpm --filter @fusion/engine exec vitest run
src/__tests__/runtime-resolution.test.ts`
- `pnpm --filter @fusion/engine typecheck`
- `pnpm check:changesets`

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

* **Tests**
* Updated the runtime-resolution test suite’s mocked logger to also
support debug-level messages, alongside existing log, warn, and error
handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-26 22:35:28 -07:00
Phil Larson
159fbbe9f8 fix(i18n): restore auto-update locale parity (#2456)
## Summary
- restore the two auto-update settings keys in all five secondary locale
catalogs
- keep generated locale structure aligned with the authored English
catalog

## Test plan
- `pnpm i18n:status`


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

* **Localization**
* Added new settings text keys for “automatic updates and restart” (and
its help text) in Spanish, French, Korean, Simplified Chinese, and
Traditional Chinese.
* The new values are placeholders (currently empty), so the UI may show
missing/blank text until translations are completed.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-26 22:34:39 -07:00
Victor Canô
d6c917d726 feat(dashboard): add view and settings-section enumeration API (#2453)
## Summary

Gives external integrations (command palettes, plugin launchers,
alternate dashboard shells) a supported way to **discover the host UI**
— instead of hardcoding the dashboard's view ids, labels and settings
search terms and hand-syncing them on every release. This is the
read-only metadata slice of the "constrained by a stable host context
and API client" idea in
`docs/proposals/2026-07-01-dashboard-theme-plugin-system.md`, and the
follow-on to #2415 (theme tokens + overlay layering).

Two additions, both inert unless called:

| Endpoint | Returns |
|---|---|
| `GET /api/views` | Every registered built-in view id, in dashboard
order — `id`, English `label`, plus optional i18n `labelKey`, legacy
`aliases` and `internal` flag. |
| `GET /api/settings/sections` | Selectable Settings sections — `id`,
`label`, `labelKey`, `scope`, `group`, `keywords`, `searchableKeys`,
`advanced`. |

Both are read-only, return static project-independent metadata, take no
project id, and are mounted inside `createApiRoutes` so they sit behind
exactly the same `/api` authentication as every other dashboard route —
no more, no less.

## What actually changed — one source of truth

The endpoints are the small part. The core of the diff is **collapsing
duplicated UI metadata into two shared registries that now drive both
the dashboard UI and the API**:

- `packages/dashboard/src/shared/dashboard-views.ts` — canonical view
ids + English labels + i18n keys + legacy aliases.
- `packages/dashboard/src/shared/settings-sections.ts` — canonical
settings sections + scope/group/search metadata, with `group` and
`advanced` derived from the list's own structure.

`LeftSidebarNav`, `SettingsModal` and `useViewState` were rewritten to
consume those registries instead of carrying their own copies (net
**−230 lines** in `SettingsModal` alone). Edit the registry and the
rendered UI and the API move together.

## Drift protection

Being precise about what each test can and cannot catch, because
"no-drift" claims are easy to overstate:

- `left-sidebar-nav-registry-parity.test.tsx` — the one test that
catches drift the registry does not already determine. It **renders**
the sidebar with a recording `t()` spy and pins each entry's translation
key and English fallback to the registry (the sidebar still hardcodes
its keys). It also asserts the rendered destination count equals the
enrolled id list, so a newly added sidebar view fails until it is
enrolled.
- `ui-metadata-sync.test.ts` — pins the Settings navigation list,
advanced-visibility set, persisted view list, reset-key registry and
both endpoint payloads to the registries. Since those consumers are now
*derived* from the registries, these assertions mainly guard against a
future consumer **re-hardcoding** its own copy. Two of them do stand on
their own: each section's served `group` is pinned to the group header
it actually renders under, and no published `labelKey` may resolve to a
non-leaf i18n node.
- `register-ui-metadata-routes.test.ts` — drives the real Express router
and asserts each endpoint serves the registry payload verbatim, with no
filtering or reshaping.
- Exactly two **existing** tests are updated, both for the same reason:
they asserted that `SettingsModal.tsx`'s *source text* contains a
section literal that now lives in the registry.
`VoiceInputSection.modal-visibility.test.tsx` now asserts Voice Input's
Basic-mode contract against `SETTINGS_SECTION_METADATA`, and
`mcp-documentation.test.ts` reads the registry for the two MCP section
ids. No other existing test in the package changes.

## Design notes / decisions for review

- **`GET /api/views` returns the full registry, not the live menu.** It
includes flag-gated / experimental ids and `internal` (non-navigable)
destinations; reachability depends on flags and plugins this endpoint
does not evaluate. Documented as "known view ids", not "visible nav
entries".
- **`labelKey` is optional and best-effort; `label` is the guarantee.**
A `labelKey` is published only where the dashboard itself renders that
view's title through it. `graph` (labelled from a plugin manifest) and
the internal `task-detail` carry none rather than advertise a key that
resolves to nothing — and `task-detail` in particular must not point at
`taskDetail.title`, which is an occupied i18n *namespace* whose lookup
returns an object rather than falling through to a default. A guard test
now enforces that. Separately, a few published keys (`nav.ideation`,
`nav.importTasks`, `nav.automations`, `pr.view.title`) are the
dashboard's real keys but aren't in the shipped catalogs yet because the
host supplies their English inline; the docs say plainly that consumers
must fall back to `label`.
- **`keywords` / `searchableKeys` are explicitly non-contractual.**
`searchableKeys` exposes the raw i18n translation-key strings backing a
section's searchable copy; values, ordering and presence may change
between releases. Documented as best-effort search hints, never stable
identifiers.
- **Migration is deliberately partial.** The desktop sidebar, Settings
navigation and persisted view list now come from the registries;
`Header.tsx` and the mobile More sheet still hardcode a few of the same
labels. They can still drift from what `GET /api/views` reports;
converting them is left to a follow-up so this diff stays reviewable.
- **No project scoping, deliberately.** The proposal doc rightly pushes
plugin traffic through a project-scoped client — these two endpoints are
the exception that proves the rule: they return static registry metadata
that is identical for every project, so threading a `projectId` would
imply a scoping guarantee that does not exist here. They never touch
`getScopedStore` / `TaskStore`.
- **Two endpoints rather than one `/api/ui-metadata` envelope.** Views
and Settings sections are independent registries with different
consumers, and `/settings/sections` sits naturally beside the existing
`/settings/*` routes. A consumer that only needs navigation doesn't pay
for settings metadata.
- **The registry extraction ships with the endpoints rather than as a
separate PR.** The registries *are* the mechanism that keeps the API
honest — split apart, the first half is a refactor with no observable
effect and the second can't land without it.
- **Placement:** `packages/dashboard/src/shared/` is a new directory,
and these are the first *production* `app/ → src/` imports in the
package (today the only one is in `ProviderIcon.test.tsx`). They sit
under `src/` because `src/`'s tsconfig cannot import `app/`, so a module
both sides consume has nowhere else to go; both registries are
dependency-free data leaves, and `vite build` plus
`check-no-node-only-core-imports-in-dashboard` confirm the client bundle
is unaffected. The considered alternative was `packages/core/src` behind
the `dashboard-browser-safe-core-modules.json` allowlist, where
`mobile-nav-primary-items.ts` keeps a destination→labelKey table — these
stayed out of `core` because they are dashboard-owned UI ids, and
because the two tables describe different surfaces (core mirrors the
mobile nav's `nav.skills`/`nav.settings`; this registry mirrors the
desktop sidebar's `header.skillsView`/`header.settings`).
- Ships a `@runfusion/fusion` **minor** changeset (`category: feature`).

Happy to adjust any of the above — shape, placement, or dropping
`searchableKeys` — if you'd rather it landed differently.

## Verification

- Rebased onto `main@26dcccb7c`. Two conflicts, both resolved by
absorbing upstream's work rather than reverting it:
- `SettingsModal.tsx` — upstream's `voice-input` section (and the
`FNXC:VoiceInput` decision comment explaining it stays out of the
advanced-only set) moved into the registry. The registry's section list
is byte-identical to `main`'s `SETTINGS_SECTIONS` (45/45 entries, all
fields), and the registry-derived `ADVANCED_SETTINGS_SECTION_IDS` is
identical to `main`'s hardcoded set (19/19, same order) — both verified
mechanically, not by eye. Upstream's `RUNTIME_*`
hide-uninstalled-runtimes sets are untouched.
- `routes/README.md` — the `mount-sequence` list regenerated from
`CREATE_API_ROUTES_REGISTRAR_MOUNT_SEQUENCE`, so `registerVoiceRoutes`
and `registerUiMetadataRoutes` are both in place and the contract test
passes.
- `DASHBOARD_VIEWS` covers exactly `main`'s `BuiltInTaskView` union,
aliases included, and `BUILT_IN_TASK_VIEWS` reproduces `main`'s 27-entry
array in order (`devserver` still preceding `dev-server` for the
migration path).
- Every one of the 20 sidebar labels the refactor rewrote was checked to
be byte-identical to `main`'s hardcoded fallback, and every `FNXC:`
decision comment displaced by the move was accounted for — all 75 in
`SettingsModal.tsx` and all 11 in `useViewState.ts` survive, relocated
onto the registry entries they document.
- The full `dashboard-app` + `dashboard-api` suites were run at this
commit (**20,706 passing**) and again on unmodified `main@26dcccb7c`,
and the failing-file sets compared: **every file that fails here also
fails on `main`** — nothing regresses. The overlap is environment-driven
(Postgres-backed `*.pg.test.ts`, tests needing built `dist` artifacts,
and `SettingsModalNodeRouting.test.tsx`'s `No "fetchSystemInfo" export
is defined on the "../../api" mock`), none of it touched by this change.
- `tsc --noEmit` clean for both dashboard projects, `eslint` clean on
every changed file, and `vite build` of the client bundle succeeds (the
two pre-existing `@fusion-plugin-examples/claude-runtime` /
`playwright-core` module-resolution errors reproduce on unmodified
`main`).
- Repo gate scripts pass: `check-changeset-format`,
`check-routes-modular`, `check-no-node-only-core-imports-in-dashboard`,
`check-no-cwd-relative-dashboard-test-reads`, `check-mock-completeness`.
- The three new assertions were mutation-tested rather than assumed
load-bearing: breaking the registry's `group` derivation, dropping an
enrolled sidebar id, and re-pointing `task-detail` at the
`taskDetail.title` namespace each make their test fail.
- Local CodeRabbit review over two passes: 3 minor findings, all
addressed (parity projection missing `group`; route tests asserting
partial instead of exact payloads; the `labelKey` guard not covering the
settings registry).


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

## Summary by CodeRabbit

* **New Features**
* Added authenticated, read-only APIs for discovering dashboard views
and selectable Settings sections.
* Added dashboard view metadata, including labels, aliases, internal
status, and translation keys.
* Added Settings metadata with grouping, scope, advanced status, and
search-related information.
  * Updated navigation and Settings UI labels to use shared metadata.

* **Documentation**
  * Documented the new metadata endpoints and integration guidance.

* **Bug Fixes**
* Added safeguards and automated checks to keep UI navigation and API
metadata synchronized.

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

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-26 22:34:18 -07:00
Phil Larson
00778cb10f test(engine): refresh shellout allowlist (#2451)
## Summary
- refresh the engine synchronous-shellout allowlist after recent
self-healing and executor source additions shifted audited call sites
- keep the guard's path, primitive, and signature checks unchanged

## Test plan
- `corepack pnpm --filter @fusion/engine exec vitest run
src/__tests__/engine-no-blocking-shellout.test.ts --silent=passed-only
--reporter=dot`


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

* **Tests**
* Updated static validation allowlists for audited synchronous shell
command operations so matching stays accurate with the latest call-site
locations.
* Kept safeguards that prevent unapproved blocking shell commands from
passing validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com>
2026-07-26 22:33:21 -07:00
gsxdsm
f1a2d9ae1f FN-8626: validate committed test timing snapshot
Add an automated guard that keeps CI test-sharding timings usable.

- Validate snapshot structure, freshness, and recorded test-file paths.
- Confirm planning loads the snapshot and shard dry-runs use it without stale warnings.

Files changed:
 scripts/__tests__/ci-test-shard-timings.test.mjs | 50 +++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-8626

Fusion-Task-Lineage: ada6525f-8dcc-4494-8586-3aa2e41618f3

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 20:42:30 -07:00
gsxdsm
3f33cb000f feat: per-origin workflow selection + feedback-derived refinement titles
Two task origins had no workflow picker in front of the operator and always
inherited the project default: `fn task create` (CLI + the `fn_task_create`
agent tool) and refinement tasks. Add a Project General setting for each, where
blank/unset means "Selected workflow" (the operator's current Board lane,
falling back to the project default) and a concrete id pins that origin.

Because the Board lane lives in browser localStorage, non-browser callers could
not resolve "Selected workflow" at all. `boardSelectedWorkflowId` mirrors the
lane into project settings so they can. Note this makes the mirrored lane
project-scoped: two operators on one project share it, last switch wins. The
Board never reads it back, so the only effect is which workflow a newly created
task inherits.

Resolution is `TaskStore.resolveOriginWorkflowOverrideId(origin)`: pinned
setting -> mirrored lane -> `undefined` to inherit each caller's existing
default-workflow path unchanged. A deleted or fragment id degrades to inherit
rather than throwing, so a stale settings value can never break task creation.
An explicit `workflow_id` argument to `fn_task_create` still wins.

Separately, a refinement is now titled by the operator's own feedback via the
shared `deriveFallbackTaskTitle`, not `Refinement: <parent title>`. Ten
refinements of one task previously rendered ten identical titles, so the board
could not tell them apart while the text saying what each one asked for sat in
the description. Provenance moves to a `Refines <id>` card chip alongside the
existing detail-view parent link and dependency edge.

Verified: merge gate (299 tests), lint, full build, and typecheck for core, CLI,
and dashboard all pass. New coverage: origin resolution across both origins and
the full precedence ladder, the two settings pickers, the board-lane mirror,
refinement titling (including sibling distinctness), and the card chip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 20:33:25 -07:00
gsxdsm
e4cb957b57 FN-8619: migrate modal geometry to FloatingWindow
Unify migrated modal geometry and responsive behavior under FloatingWindow.

- Cover Agent Detail and GitHub Import floating-window interaction and persistence contracts.
- Preserve unique Agent Detail labels, mouse-only backdrop dismissal, and tablet touch layouts.
- Update the dashboard modal migration inventory.

Files changed:
 docs/dashboard-modal-inventory.md                  |   6 +-
 .../dashboard/app/components/AgentDetailView.css   |  49 +++++-----
 .../dashboard/app/components/AgentDetailView.tsx   |   6 +-
 .../dashboard/app/components/FloatingWindow.css    |  10 +-
 .../dashboard/app/components/TaskDetailModal.css   |  15 +++
 .../AgentDetailView.floating-window.test.tsx       | 102 +++++++++++++++++++++
 .../__tests__/GitHubImportModal.test.tsx           |  58 ++++++++++++
 ...etailModal.responsive-and-dependencies.test.tsx |  24 +++++
 8 files changed, 241 insertions(+), 29 deletions(-)

Fusion-Task-Id: FN-8619

Fusion-Task-Lineage: efa95e41-b12e-4e5d-aeb2-65b43c2dd8e0

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 20:04:33 -07:00
gsxdsm
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>
2026-07-26 19:52:32 -07:00
gsxdsm
7715a83e6f FN-8624: fix task detail activity right padding
Keep Task Detail activity insets symmetric while reserving overlay clearance only for first-row content.

- Move Live/Feed overlay clearance from the activity container to first-row elements.
- Preserve responsive overlay spacing and the full-width Interventions timeline.
- Cover modal, pop-out, embedded, and responsive activity layouts with updated tests.
- Add a patch changeset for the Task Detail padding fix.

Files changed:
 .changeset/fn-8624-task-detail-inset.md            |  7 ++++
 .../dashboard/app/components/TaskDetailModal.css   | 41 ++++++++++------------
 .../TaskDetailModal.attachments-and-tabs.test.tsx  |  6 ++--
 .../__tests__/TaskDetailModal.css.test.ts          | 21 ++++++-----
 ...etailModal.responsive-and-dependencies.test.tsx | 25 +++++++------
 5 files changed, 54 insertions(+), 46 deletions(-)

Fusion-Task-Id: FN-8624

Fusion-Task-Lineage: 578cfe86-3021-421d-841b-2670efc10a5d

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 19:45:47 -07:00
gsxdsm
d3c1955866 FN-8625: remove heartbeat controls from agent org charts
Keep org charts read-only for heartbeat configuration while preserving controls on board and list surfaces.

- Remove heartbeat toggle props, markup, and styling from org chart nodes
- Cover both org chart layouts and board heartbeat availability with regression tests
- Add a patch changeset for the dashboard behavior fix

Files changed:
 .../fn-8625-remove-org-chart-heartbeat-toggle.md     |  7 +++++++
 packages/dashboard/app/components/AgentsView.css     |  7 -------
 packages/dashboard/app/components/AgentsView.tsx     | 14 +++++---------
 .../__tests__/AgentsView.orgchart.test.tsx           | 20 ++++++++++++++++++++
 .../app/components/__tests__/AgentsView.test.tsx     | 20 +++++++++++---------
 5 files changed, 43 insertions(+), 25 deletions(-)

Fusion-Task-Id: FN-8625

Fusion-Task-Lineage: 454c05e6-fe31-486b-975a-80ba5e8c518c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 19:18:53 -07:00
gsxdsm
89b4621a93 FN-8607: migrate shared modals to FloatingWindow
Standardize agent, onboarding, and utility modal behavior on the shared FloatingWindow contract.

- Migrate modal hosts to shared geometry, sheet, dismissal, and focus behavior.
- Make FloatingWindow the sole owner of modal ARIA semantics and protect portal-safe dismissal surfaces.
- Cover migrated modal contracts and document the responsive sheet requirements.

Files changed:
 docs/dashboard-guide.md                            |   6 +-
 packages/dashboard/app/components/AgentGenerationModal.tsx        |   8 +-
 packages/dashboard/app/components/AgentImportModal.tsx  |   4 +-
 packages/dashboard/app/components/AgentListModal.tsx    |   4 +-
 packages/dashboard/app/components/AgentOnboardingModal.tsx        |   4 +-
 packages/dashboard/app/components/DockerNodeOnboardingModal.tsx   |   4 +-
 packages/dashboard/app/components/ExperimentalAgentOnboardingModal.tsx |   4 +-
 packages/dashboard/app/components/FloatingWindow.css    |  36 ++++--
 packages/dashboard/app/components/FloatingWindow.tsx    |  12 ++
 packages/dashboard/app/components/MilestoneSliceInterviewModal.tsx |   2 +-
 packages/dashboard/app/components/NativeShellOnboardingModal.tsx  |   2 +-
 packages/dashboard/app/components/SetupWizardModal.tsx  |   3 +-
 packages/dashboard/app/components/SubtaskBreakdownModal.tsx       |   2 +-
 packages/dashboard/app/components/__tests__/AgentModals.floatingWindow.test.tsx | 134 ++++++++++++++++++---
 packages/dashboard/app/components/__tests__/OnboardingModals.floatingWindow.test.tsx | 128 +++++++++++++++++---
 packages/dashboard/app/components/__tests__/UtilityModals.floatingWindow.test.tsx | 124 +++++++++++++++++--
 packages/dashboard/app/components/__tests__/migratedModalFixtures.tsx |  59 ++++++---
 packages/dashboard/app/components/__tests__/modalFloatingWindowContract.test.tsx |  20 ++-
 18 files changed, 458 insertions(+), 98 deletions(-)

Fusion-Task-Id: FN-8607

Fusion-Task-Lineage: 11ba6a9c-ce89-4358-83c4-a15ef15b6128

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 18:57:02 -07:00
gsxdsm
bdfa5186c4 FN-8622: capture Chromium CDP modal screenshots
Add assertion-guarded CDP evidence for migrated Agent List and Setup Wizard modal touch geometry.

- Mount production modal surfaces in the resize browser fixture
- Verify tablet resize and drag behavior plus true-phone sheet behavior
- Store the captured phone and tablet screenshots as regression evidence
- Extend mobile sheet styling to the migrated modal hosts

Files changed:
 .../dashboard/app/components/FloatingWindow.css    |   8 ++
 .../app/task-modal-touch-resize-e2e-fixture.tsx    |  17 +++-
 .../fn-8607/phone-fullscreen-sheet.png             | Bin 0 -> 17823 bytes
 .../fn-8607/tablet-agent-list-after.png            | Bin 0 -> 21489 bytes
 .../fn-8607/tablet-setup-wizard-after.png          | Bin 0 -> 81964 bytes
 .../task-modal-touch-resize-browser.test.ts        |  99 +++++++++++++++++++++
 6 files changed, 120 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8622

Fusion-Task-Lineage: 3fabd950-bac0-47f4-9649-08709db31e02

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 18:43:18 -07:00
gsxdsm
ba24a530ef FN-8620: migrate dashboard modals to FloatingWindow
Standardize dashboard modal geometry and interaction behavior through the shared FloatingWindow contract.

- Migrate New Task, right-dock expansion, terminal, onboarding, and utility modals to FloatingWindow.
- Expand shared window resizing, positioning, accessibility, and contract coverage.
- Document the modal migration inventory and publish changesets.

Files changed:
 .changeset/fn-8607-floating-modal-contract.md      |   7 +
 .changeset/fn-8620-bespoke-geometry-modals.md      |   7 +
 docs/dashboard-guide.md                            |  47 ++
 docs/dashboard-modal-inventory.md                  |   6 +-
 .../app/components/AgentGenerationModal.tsx        |  14 +-
 .../dashboard/app/components/AgentImportModal.tsx  |   7 +-
 .../dashboard/app/components/AgentListModal.tsx    |   8 +-
 .../app/components/AgentOnboardingModal.tsx        |   6 +-
 .../app/components/DockerNodeOnboardingModal.tsx   |  14 +-
 .../ExperimentalAgentOnboardingModal.tsx           |   6 +-
 .../dashboard/app/components/FloatingWindow.css    |  21 +
 .../dashboard/app/components/FloatingWindow.tsx    |  62 ++-
 packages/dashboard/app/components/MailboxModal.tsx |  14 +-
 .../components/MilestoneSliceInterviewModal.tsx    |  12 +-
 .../app/components/NativeShellOnboardingModal.tsx  |   6 +-
 packages/dashboard/app/components/NewTaskModal.css | 196 +------
 packages/dashboard/app/components/NewTaskModal.tsx | 593 +++++++--------------
 packages/dashboard/app/components/RightDock.css    |  84 +--
 .../app/components/RightDockExpandModal.tsx        | 333 ++----------
 .../dashboard/app/components/SetupWizardModal.tsx  |  20 +-
 .../app/components/SubtaskBreakdownModal.tsx       |   6 +-
 .../dashboard/app/components/TerminalModal.css     | 120 +----
 .../dashboard/app/components/TerminalModal.tsx     | 321 ++---------
 .../__tests__/AgentModals.floatingWindow.test.tsx  |  26 +
 .../components/__tests__/FloatingWindow.test.tsx   |  27 +-
 .../app/components/__tests__/NewTaskModal.test.tsx |  66 +--
 .../OnboardingModals.floatingWindow.test.tsx       |  20 +
 .../app/components/__tests__/RightDock.test.tsx    |  18 +-
 .../components/__tests__/TerminalModal.test.tsx    |  61 +--
 .../UtilityModals.floatingWindow.test.tsx          |  18 +
 .../components/__tests__/migratedModalFixtures.tsx |  25 +
 .../__tests__/modalFloatingWindowContract.test.tsx |  30 ++
 32 files changed, 726 insertions(+), 1475 deletions(-)

Fusion-Task-Id: FN-8620
Fusion-Task-Lineage: 2a912260-3292-4b13-bcf0-9de5a3df8ccd
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 18:35:10 -07:00
gsxdsm
256c64a7bd chore(release): v0.74.0-beta.5
Version bump via changesets.
2026-07-26 18:11:47 -07:00
gsxdsm
034827f251 FN-8623: restore CDP touch geometry test lane
Restore a dedicated Chromium CDP lane for dashboard touch-geometry coverage.

- Add an opt-in touch-geometry test command and isolated Vitest project.
- Keep the browser-dependent spec out of deep and quality backfill collection.
- Document browser discovery, port, and single-collection requirements.

Files changed:
 docs/testing.md                                    | 10 ++-
 packages/dashboard/package.json                    |  1 +
 .../__tests__/dashboard-test-config-guard.test.ts  | 71 +++++++++++++++++++++-
 .../task-modal-touch-resize-browser.test.ts        |  5 ++
 packages/dashboard/vitest.config.ts                | 28 ++++++++-
 scripts/lib/test-inventory-spec.json               |  3 +-
 6 files changed, 114 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-8623

Fusion-Task-Lineage: eafd7497-9302-49a4-8e9e-aa93c9f56a6f

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 18:04:28 -07:00
gsxdsm
73b2a32e2b test: backfill dashboard test mocks for new api and viewport exports
Concurrent dashboard work added runtime exports that hardcoded module
mocks did not expose, so any suite rendering the affected component threw
"No <export> is defined on the mock". Adds the missing `../api` exports
(system-info probe, update install/restart, cloudflared, provider key and
login helpers, git remotes/branches) and the `isTabletTouchViewport`
viewport helper across the 26 suites that mock those modules.

Verified: all 26 files pass (1012 tests).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 18:00:07 -07:00
gsxdsm
beebd270bd fix: make Queued to plan / Ready badges agree with the planning lane
TaskCard inferred "unplanned" from steps.length === 0 while triage's
todo-discovery and the scheduler's dispatch filter both decide from
PROMPT.md seed-ness, so the badges disagreed with the engine in both
directions: a real spec that parsed to zero steps read as "Queued to
plan" while the scheduler already treated it as a WIP-slot candidate, and
a re-seeded card still carrying old steps read as "Ready" while triage
was about to plan it. Either way the badge sent operators to the wrong
cap.

Adds the shared isTaskAwaitingPlanning predicate (replan park, missing
spec, seed-vs-real content) used by both triage's discovery and a new
best-effort `awaitingPlanning` enrichment on GET /api/tasks. TaskCard
derives both badges from that one value — strict complements — and keeps
the step count only as a fallback for SSE payloads and older servers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:48:46 -07:00
gsxdsm
01b27b13f1 test(dashboard): add per-character typing coverage to uncovered field surfaces
Sweeping the other views for the FN-8606 typing bug found no further breakage,
but it did expose why the bug shipped: almost all field coverage uses
fireEvent.change, which sets a value in one shot on a node it already holds and
never needs the input to stay mounted. A remount is invisible to it.

Adds expectStableTyping (types character by character via userEvent, then asserts
DOM node identity, accumulated value, and retained focus) and applies it to the
uncovered surfaces: the FN-8606-migrated AddNode, ConnectNode, NodeDetail,
Scripts, and WorkflowAddStep modals, plus the board's QuickEntryBox composer and
SubtaskBreakdownModal title editing. All pass — this is a detection floor, not a
fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:42:39 -07:00
gsxdsm
d193dcdbb0 chore(lint): ban React components declared inside another component
Adds fusion-react/no-nested-component-definitions, a custom rule in the house
style of the existing detached-spawn guard. A component declared in render is a
new element type every render, so React remounts its subtree on each parent
update and destroys focus, scroll, and local state.

This pattern shipped three times without review or tests catching it: FN-8606's
ModalShell left Planning Mode and Settings untypable, and MailboxModal's
ReplyContextExpandable collapsed expanded reply rows. Tests missed it because
fireEvent.change sets a value without needing the node to stay mounted.

The rule reports PascalCase functions (including memo()/forwardRef()-wrapped)
that return JSX and are declared inside another JSX-returning function.
Lowercase render helpers are deliberately allowed — they are the sanctioned fix.
Escape hatch: // nested-component-allowlist: <reason>.

Scoped to production .tsx, with a vitest guard for the rule itself. Hoists the
two pre-existing violations (ProviderStatusBadge, GitHubStatusBadge in
ModelOnboardingModal) to module scope so the rule lands clean at "error".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:34:45 -07:00
gsxdsm
5ea98f7d4b fix: release admission claims when triage evicts a hung planner
evictStaleProcessing cleared `processing` but left the task in
`coordinatorAdmittedTaskIds`, which is only cleared by specifyTask's
finally — the path a hung promise never reaches. The card stayed
eligible (so the throttle branch never logged or emitted
`task:plan-admission-throttled`) while admitOldest's refresh filtered it
out, leaving it on the "Queued to plan" badge with free slots and no
diagnostic until engine restart. Also drop an untransferred pre-held host
slot, which otherwise waits out the 600s stale-excess valve.

Regression tests assert the invariant on the real production candidate
source: an evicted card is re-offered and its host slot returned, while a
still-live stale task keeps both claims.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:33:35 -07:00
gsxdsm
c21fb0d1d0 fix(dashboard): stop Mailbox reply-context rows collapsing on unrelated re-renders
ReplyContextExpandable was declared inside MailboxModal's render, making it a new
element type on every render. Any parent update remounted the whole recursive
reply thread, so expanding one reply row collapsed the others and discarded their
DOM identity, focus, and scroll position.

Hoist it to module scope and pass the parent's reply state and handlers through an
explicit env prop so the element type stays stable. Adds a regression test that
expands one row, expands a second, and asserts the first keeps both its node
identity and aria-expanded state — same defect class as the FN-8606 ModalShell fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:23:48 -07:00
gsxdsm
62e13f484b docs: index dashboard-modal-inventory.md in Audit Reports
FN-8617 committed docs/dashboard-modal-inventory.md as the canonical
classification of all 45 dashboard modal surfaces (classes A-D) with
file:line evidence and FloatingWindow migration targets, but the docs
index was not updated. Add the Audit Reports entry so the doc is
discoverable from the docs hub.

Verified: orphan scan clean (only known intentional orphans remain);
pnpm --filter @runfusion/fusion test:docs-index passes (2/2).
2026-07-26 17:20:56 -07:00
gsxdsm
7065d03895 fix(dashboard): keep Planning Mode and Settings typable after floating-window migration
FN-8606 declared the window shell as a component inside PlanningModeModal and
SettingsModal render. A component declared in render is a new element type on
every render, so React remounted the whole subtree on each keystroke, destroying
the focused input: Planning Mode dropped everything after the first character and
Settings text fields did the same.

Replace ModalShell with a plain renderModalShell(children) call so the returned
element types stay stable, and add a Planning regression test that types
per-character across both the modal and embedded surfaces (fireEvent.change
cannot observe this class of bug, which is why it shipped).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 17:18:43 -07:00
gsxdsm
0022621d22 chore(release): v0.74.0-beta.4
Version bump via changesets.
2026-07-26 17:00:59 -07:00
gsxdsm
892e50b810 Update roadmap for GPT and Opus support 2026-07-26 16:24:59 -07:00
gsxdsm
2bb8537352 FN-8616: make agent tool-output limits configurable
Expose the shared agent tool-output budget as a scoped operator setting with an explicit no-limit option.

- Resolve global and project output caps with a safe finite default and zero sentinel.
- Propagate configured budgets through PI and plugin runtime tool wrappers.
- Add settings controls, localized labels, documentation, and regression coverage.

Files changed:
 .changeset/fn-8616-tool-output-budget-setting.md   |  7 ++++
 docs/agents.md                                     |  4 +-
 docs/settings-reference.md                         |  1 +
 .../core/src/__tests__/tool-output-budget.test.ts  | 23 ++++++++---
 packages/core/src/index.gate.ts                    |  2 +
 packages/core/src/index.ts                         |  2 +
 packages/core/src/settings-schema.ts               | 12 ++++++
 packages/core/src/tool-output-budget.ts            | 31 +++++++++++++--
 packages/core/src/types/settings-scope.ts          |  8 ++++
 .../app/components/settings/save-split.ts          |  1 +
 .../sections/GlobalGeneralSection.search.ts        | 20 ++++++++++
 .../settings/sections/GlobalGeneralSection.tsx     | 26 ++++++++++++
 ...lobalGeneralSection.tool-output-budget.test.tsx | 46 ++++++++++++++++++++++
 .../settings-default-descriptions.test.tsx         |  1 +
 .../src/__tests__/agent-session-helpers.test.ts    | 20 ++++++++++
 .../src/__tests__/runtime-resolution.test.ts       | 15 +++++++
 .../__tests__/tool-output-budget-wrapper.test.ts   | 45 ++++++++++++++++-----
 packages/engine/src/agent-runtime.ts               |  2 +
 packages/engine/src/agent-session-helpers.ts       | 18 +++++++--
 packages/engine/src/pi.ts                          | 29 ++++++++++----
 packages/engine/src/runtime-resolution.ts          | 10 ++++-
 packages/i18n/locales/en/app.json                  |  4 ++
 packages/i18n/locales/es/app.json                  |  6 ++-
 packages/i18n/locales/fr/app.json                  |  6 ++-
 packages/i18n/locales/ko/app.json                  |  6 ++-
 packages/i18n/locales/zh-CN/app.json               |  6 ++-
 packages/i18n/locales/zh-TW/app.json               |  6 ++-
 packages/i18n/src/resources.d.ts                   |  4 ++
 28 files changed, 323 insertions(+), 38 deletions(-)

Fusion-Task-Id: FN-8616

Fusion-Task-Lineage: 3ca99a61-d6ae-48ff-98d2-f14a153aa2b7

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 16:16:27 -07:00
gsxdsm
d3002d1453 FN-8617: restore authoritative dashboard modal inventory
Restore the committed source of truth for dashboard modal migration coverage.

- Add the evidence-backed inventory of dashboard modal classifications and migration ownership.
- Link the dashboard guide to the canonical modal inventory.

Files changed:
 docs/dashboard-guide.md           |   4 ++
 docs/dashboard-modal-inventory.md | 103 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

Fusion-Task-Id: FN-8617
Fusion-Task-Lineage: 87159726-d574-4f71-bd6f-66cf9f2f9a9e
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 16:05:08 -07:00
gsxdsm
743dc5f46e FN-8612: remove tablet task modal padding
Keep task modals dense on tablets without reducing their touch resize targets.

- Move the Task Detail drag target out of layout flow while preserving its 44px hit area.
- Restore desktop-density New Task header and body padding on tablet resize surfaces.
- Add CSS, unit, and browser coverage for tablet geometry and generic floating windows.

Files changed:
 .changeset/fn-8612-tablet-modal-padding.md         |   7 +
 docs/dashboard-guide.md                            |   8 +-
 .../task-detail-modal-tablet-width.test.ts         |   8 +
 .../dashboard/app/components/FloatingWindow.css    |  40 ++++-
 packages/dashboard/app/components/NewTaskModal.css |  14 ++
 .../FloatingWindow.touch-geometry.test.tsx         |  14 ++
 .../app/components/__tests__/NewTaskModal.test.tsx |   8 +
 .../app/task-modal-touch-resize-e2e-fixture.tsx    |  54 ++++++-
 .../task-modal-touch-resize-browser.test.ts        | 177 ++++++++++++++++++++-
 packages/dashboard/vitest.config.ts                |   6 +
 10 files changed, 322 insertions(+), 14 deletions(-)

Fusion-Task-Id: FN-8612

Fusion-Task-Lineage: fecd7c48-7b6c-434e-9002-f8f21241120c

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 15:42:53 -07:00
gsxdsm
a9b30013bb fix(core): approval dedupe lookup matches on PostgreSQL instead of minting duplicates
`findLatestByDedupeKey` read `targetContext` through the string-only `fromJson`.
In backend (PostgreSQL) mode that column is jsonb and Drizzle returns it ALREADY
PARSED, so the dedupe scan never matched: every gate retry minted a duplicate
approval request, and an approved grant could never be redeemed. The live
database shows the signature plainly — 17 approved requests, 0 completed.

Normalize both shapes in one place (`normalizeTargetContext`), applied at
`rowToRequest` and both dedupe scan sites, so a row resolves whether it arrives
as a JSON string (SQLite) or a parsed object (Postgres).

The regression test asserts shape-independence rather than the single reported
case: the same stored key must resolve in BOTH shapes, and must not match a
different key or an absent context in either. Mutation-checked — reverting the
scan sites fails exactly the parsed-object case.

Cherry-picked ahead of #2457, which carries the wider approval/permission
hardening pass, because this one is an active production defect on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:38:05 -07:00
gsxdsm
30f81ac0cd fix(engine): compact verification failure output
Keep successful verification responses quiet and return bounded, high-signal diagnostics for failures without hiding zero-work or green-while-red warnings.
2026-07-26 15:36:33 -07:00
gsxdsm
65f6748e5b FN-8613: theme mailbox markdown links
Theme mailbox message anchors with dashboard tokens and verify link coverage.

- Style markdown anchor default, visited, hover, and focus-visible states with design tokens
- Cover inline, autolink, list, and table links while preserving file-path controls
- Add a patch changeset for themed mailbox links

Files changed:
 .changeset/theme-mailbox-markdown-links.md         |  7 ++++
 packages/dashboard/app/components/MailboxModal.css | 29 +++++++++++++
 .../__tests__/MailboxMessageContent.test.tsx       | 49 ++++++++++++++++++----
 3 files changed, 77 insertions(+), 8 deletions(-)

Fusion-Task-Id: FN-8613

Fusion-Task-Lineage: a8c7e8bb-8238-4018-bf95-38193f908eb4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 14:49:17 -07:00
gsxdsm
07c8c95b10 FN-8614: cap agent tool output
Bound every engine-injected tool result to preserve agent context capacity.

- Add shared 16,000-character total text budgets with deterministic truncation markers and validated overrides.
- Apply outermost output clamps to Pi and non-Pi plugin tool paths, with semantic caps for high-volume reads.
- Cover budget behavior and document the operator-facing configuration contract.

Files changed:
 .changeset/fn-8614-tool-output-budget.md           |  7 ++
 docs/agents.md                                     |  8 ++
 .../core/src/__tests__/tool-output-budget.test.ts  | 58 +++++++++++++
 packages/core/src/index.gate.ts                    |  7 ++
 packages/core/src/index.ts                         |  7 ++
 packages/core/src/tool-output-budget.ts            | 97 ++++++++++++++++++++++
 .../src/__tests__/agent-artifact-tools.test.ts     | 10 +++
 .../src/__tests__/agent-document-tools.test.ts     | 10 +++
 .../__tests__/agent-task-logs-read-tools.test.ts   |  8 ++
 .../__tests__/tool-output-budget-wrapper.test.ts   | 67 +++++++++++++++
 packages/engine/src/agent-session-helpers.ts       |  7 +-
 packages/engine/src/agent-tools.ts                 | 43 ++++++++--
 packages/engine/src/pi.ts                          | 54 +++++++++++-
 13 files changed, 374 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-8614

Fusion-Task-Lineage: b6a76ccd-d7b4-4b43-af7e-cfd16ffb7fc8

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 14:42:06 -07:00
gsxdsm
a6885b73f2 FN-8606: migrate core workflow modals to shared floating windows
Migrate dashboard dialogs to the shared movable and resizable FloatingWindow contract.

- Move core, workflow, Git, planning, and automation modal surfaces to stable floating-window identities with persisted geometry.
- Suspend geometry and floating controls for phone and short-viewport sheets, including Quick Chat.
- Add accessibility wiring, tablet touch targets, migration tests, and operator documentation.

Files changed:
 .changeset/fn-8606-floating-window-core-modals.md  |   7 +
 docs/dashboard-guide.md                            |   4 +
 packages/dashboard/app/App.tsx                     |   8 +-
 .../dashboard/app/components/ActivityLogModal.tsx  |  30 ++--
 packages/dashboard/app/components/AddNodeModal.tsx |   8 +-
 .../dashboard/app/components/ChangesDiffModal.tsx  |  35 +++--
 .../dashboard/app/components/ConnectNodeModal.tsx  |   9 +-
 .../dashboard/app/components/FloatingWindow.css    |  71 ++++++++-
 .../dashboard/app/components/FloatingWindow.tsx    |  27 +++-
 .../dashboard/app/components/GitManagerModal.tsx   |  30 +++-
 .../dashboard/app/components/GroupTaskModal.tsx    |   8 +-
 .../app/components/ModelOnboardingModal.tsx        |  28 ++--
 .../dashboard/app/components/NodeDetailModal.tsx   |   9 +-
 .../dashboard/app/components/PlanningModeModal.css |   1 -
 .../dashboard/app/components/PlanningModeModal.tsx |  57 +++----
 .../app/components/ScheduledTasksModal.tsx         |   9 +-
 packages/dashboard/app/components/ScriptsModal.css |   1 -
 packages/dashboard/app/components/ScriptsModal.tsx |  32 ++--
 .../dashboard/app/components/SettingsModal.css     |   1 -
 .../dashboard/app/components/SettingsModal.tsx     |  58 ++++---
 .../app/components/WorkflowAddStepModal.css        |  15 --
 .../app/components/WorkflowAddStepModal.tsx        |  46 +++---
 .../components/__tests__/ActivityLogModal.test.tsx |  33 ++--
 .../app/components/__tests__/AddNodeModal.test.tsx |  12 +-
 .../components/__tests__/ChangesDiffModal.test.tsx |  78 +++++-----
 .../components/__tests__/ConnectNodeModal.test.tsx |   7 +
 .../components/__tests__/FloatingWindow.test.tsx   | 173 ++++++++++++++++++++-
 .../components/__tests__/GitManagerModal.test.tsx  |  30 ++--
 .../components/__tests__/GroupTaskModal.test.tsx   |   9 ++
 .../__tests__/ModelOnboardingModal.test.tsx        |  18 ++-
 .../components/__tests__/NodeDetailModal.test.tsx  |   9 ++
 .../__tests__/PlanningModeModal.autosize.test.tsx  |  30 ++--
 .../__tests__/ScheduledTasksModal.test.tsx         |  21 ++-
 .../app/components/__tests__/ScriptsModal.test.tsx |  15 +-
 .../__tests__/SettingsModal.mobileClose.test.tsx   |  25 ++-
 .../__tests__/WorkflowAddStepModal.test.tsx        |   7 +
 .../floatingWindowMigration.test-helpers.ts        | 126 +++++++++++++++
 37 files changed, 828 insertions(+), 259 deletions(-)

Fusion-Task-Id: FN-8606
Fusion-Task-Lineage: dab0df2d-73f4-4b0f-bec3-a45016310c91
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
2026-07-26 14:37:35 -07:00
gsxdsm
cf5575a319 Add new items to the project roadmap 2026-07-26 14:01:00 -07:00
gsxdsm
4c3b3c14b7 Update roadmap with new tasks and workflows
Added new items regarding tasks, workflows, and CEO role.
2026-07-26 13:56:45 -07:00
gsxdsm
82f85ce863 Update roadmap with new planned and completed items 2026-07-26 13:53:45 -07:00
gsxdsm
93a403af67 fix(dashboard): import delete-attribution constants via browser-safe subpath
The client bundle aliases `@fusion/core` to the leaf `core/src/types.ts` to
keep Node-only dependencies out of the browser, so a package-root import of
`FUSION_CLIENT_HEADER`/`FUSION_DASHBOARD_UI_CLIENT` typechecked but failed
`vite build`:

  "FUSION_CLIENT_HEADER" is not exported by "../core/src/types.ts"

Follow the documented pattern instead of widening the root alias: declare a
`./task-delete-attribution` subpath export, add the matching Vite alias ahead
of the broader `@fusion/core` key (Vite matches in order), register the module
in the browser-safe-core allowlist, and import the subpath from the client.
`task-delete-attribution.ts` has no imports at all, so it is a safe leaf.

`app/utils/detectContentLanguage.ts` already warned about exactly this trap;
the miss was mine for verifying with typecheck, lint and test:gate but not
`pnpm build`, which is one of the four checks CI blocks on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 13:22:18 -07:00
gsxdsm
15a2fb18cc Merge branch 'fix/incomplete-pg-ports'
Wire incomplete PostgreSQL ports for archive, reconcile, health, settings
cache, agent cache, and async prompt overrides.
2026-07-26 13:16:13 -07:00
gsxdsm
ab87d0d803 fix(api): return 404 for missing tasks, and make task deletions attributable
Three related fixes, all originating from a `[api:error] Request failed`
log line showing a 500 on `GET /api/tasks/FN-8610/runtime-fallback`.

1. Missing/deleted tasks now return 404 instead of 500.
   `getTaskImpl` signalled a miss with a bare `Error`, and route catches
   only mapped errno `ENOENT` to 404 — a leftover from the file-backed
   storage era. In Postgres mode nothing sets an errno code, so every
   unknown/missing/soft-deleted/wrong-project read returned 500. Adds a
   typed `TaskNotFoundError` (message byte-identical) plus a shared
   `task-lookup-error` mapper applied across the task, session-diff,
   git/GitHub, workflow and file-workspace route registrars. The same
   bare throw existed on both archive-lifecycle delete paths, so
   `DELETE /tasks/:id` was affected too.

2. 5xx logs now carry the origin stack.
   `rethrowAsApiError` constructed a fresh `ApiError` from the message
   and discarded the original, so the `FNXC:ApiErrorDiagnostics`
   contract logged the rethrow site rather than the throw site — the
   reported log entry had no stack at all. Threads `cause` through the
   error factories and walks the chain (bounded, cycle-guarded).

3. Task deletions are attributable, and non-operator deletes notify.
   `task:deleted` audit rows recorded `agentId: "system"` for every HTTP
   delete, making an operator click indistinguishable from a script or
   an agent; the calling agent's task id was accepted by the store and
   then never persisted. Adds a `callerKind` union recorded in audit
   metadata, tags every delete call site, and stamps a self-reported
   `x-fusion-client` header from the dashboard client. When the caller
   is `agent-tool` or `api-unattributed`, a best-effort notice is sent
   to the operator mailbox; operator and engine deletes stay silent.

`x-fusion-client` is attribution, not authentication — anything can send
it. No delete-blocking, gating or permission logic is added here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 13:15:36 -07:00