Commit Graph

496 Commits

Author SHA1 Message Date
gsxdsm
18ba5c0c59 Address PR review feedback (#1363)
- db.ts: restrict migration-105 orphan-step cleanup to JSON arrays
  (json_type guard so json_each can't expand objects/strings)
- project-engine.ts: requestInterpreterMerge throws on null task lookup
  instead of casting null into MergeResult (seam converts to clean failure)
- executor.ts: truncate dual-observe shadow stage walk at the live terminal
  stage so healthy in-review tasks don't record a phantom merge transition

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 21:02:01 -07:00
gsxdsm
759e2e67af Merge remote-tracking branch 'origin/main' into gsxdsm/workflowbuilder 2026-06-03 19:52:37 -07:00
gsxdsm
8e9a3ac4ce feat(engine): wire dual-observe parity at the post-execute handoff (CU-U5 #2)
maybeObserveWorkflowParity compares the selected workflow graph's routing
against the legacy authoritative run for the same task and records
workflow:parity-observed / -drift audit events (aggregated by
getWorkflowParitySummary). The shadow walks the graph via WorkflowGraphTaskRunner
with no-side-effect seams whose outcomes mirror the legacy task's reality
(execute reached review?, review verdict, merged?), then maps visited seam nodes
to execute/review/merge stages. Hooked in handoffTaskToReview, gated by
workflowInterpreterDualObserve (off by default), wrapped so it never affects the
authoritative handoff. Scope: execute->review->merge routing parity; full
execution-fidelity shadow is future graduation work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 19:02:37 -07:00
gsxdsm
eb67d08213 Address PR review feedback (#1363)
Greptile + CodeRabbit findings across core/engine/dashboard. Stale findings
(written against earlier commits) verified and skipped; valid ones fixed.

Engine:
- await-input: do not clear pausedReason in the /input route (the node's
  marker must survive unpause); the node clears it after consuming input.
  Embed a colon-free epoch watermark in the marker so only post-pause steering
  comments count as the reply (ISO timestamps collided with the colon
  separator and the dashboard question parser).
- gate nodes without a registered runner now fail closed (throw) instead of
  silently passing.
- a thrown interpreter error in maybeExecuteWorkflowGraph now falls back to the
  legacy pipeline instead of stranding the task in-progress.
- approved-CLI path clears the stale awaiting-cli-approval status/marker.

Core:
- persist+cascade workflow selection: purge task_workflow_selection rows and
  compiled workflow_steps on physical task deletes; migration 105 cleans
  already-orphaned rows; catch-cleanup for materialized steps when the owner
  write fails; WF-id allocation now in a BEGIN IMMEDIATE transaction.
- compiler validates the canonical execute->review->merge seam order (rejects
  duplicate/misordered seams).
- disk-backed reopen round-trip + tightened updatedAt/list assertions.

Dashboard:
- WorkflowSelector clears stale default/options across project changes and on
  fetch failure; InlineCreateCard/NewTaskModal reset the workflow on all
  clear/discard paths and include it in dirty-state.
- WorkflowNodeEditor: config-key deletion now persists; removed an invalid
  eslint-disable that was itself a hard lint error.
- TaskCard: single status badge for awaiting-input (no duplicate).
- WorkflowResultsTab: reset paused-action UI between pauses; surface
  resume/approve failures inline.
- TaskDetailModal: treat awaiting-user-input/awaiting-cli-approval/paused as
  not-in-progress for the live-log subscription.
- workflow-flow-mapping: don't write synthetic node names back into IR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:32:12 -07:00
gsxdsm
5c02271551 feat(engine): add fn_workflow_list and fn_workflow_select agent tools
Agent-native parity: users can list workflows and select one for a task in
the dashboard, so agents should be able to as well. Adds two task-session
tools — fn_workflow_list (read: built-ins + user definitions) and
fn_workflow_select (assign a workflow to a task, defaulting to the current
one) — wired into the executor's customTools and exported from the engine
index. Covered by unit tests against mock stores.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:31:11 -07:00
gsxdsm
291072446d feat(workflows): enforce node autoApprove by bypassing the CLI approval pause
The node "Auto-approve requests" toggle was captured but unused. The only
human-approval pause reachable from a custom node is the CLI first-run
trust-on-first-use gate (review-style nodes run as ephemeral readonly agents
with no permission gate), so autoApprove now bypasses that pause — a superset
of the CLI-specific cliSkipApproval flag. The inspector explains the effect
when the toggle is on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:26:29 -07:00
gsxdsm
68e52e3c35 fix(engine): capture baseCommitSha against local main, not origin/main
In-review tasks showed other tasks' files in their "files changed"
list. Task branches fork from local main, but the base capture
measured merge-base(HEAD, origin/main) — when local main carried
merged-but-unpushed task commits, the recorded base rewound past
them, and after the post-merge rebase-and-push rewrote those SHAs,
baseCommitSha..HEAD permanently swept the predecessors' files into
the new task's diff.

Extract the capture into base-commit-capture.ts, measure local main
first (origin/main fallback) to match the contamination-base sites,
and add a real-git regression suite covering local-ahead-of-origin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:24:03 -07:00
gsxdsm
0435fefd86 fix(workflows): persist pausedReason + harden CLI approval, await-input, and node isolation
Address PR #1363 review findings:

- core: pausedReason was written in-memory and read by SELECT but never
  persisted by the task upsert (missing column/value) nor mapped back in
  rowToTask — so it was lost on every reload. Add it to both. This is the
  root cause behind the workflow CLI-approval / await-input pause cycle and
  also fixes token-budget / worktrunk pause reasons silently vanishing.
- dashboard: approve-cli now derives the approved command exclusively from
  the task's pausedReason; a caller-supplied body.command is ignored, closing
  a trust-on-first-use bypass.
- engine: await-input nodes resume only when THIS node paused the task (its
  marker on pausedReason), not on any pre-existing steering comment.
- engine: write-capable custom nodes (coding/script/CLI) are refused until a
  task worktree exists, so they never mutate the shared repo root before the
  execute seam.
- engine: document cliSkipApproval as an intentional workflow-author-only
  escape hatch; scriptName is now const (ESLint).
- tests: pausedReason round-trip coverage in store-persistence; approve-cli
  body-command-ignored + no-pending-command coverage; built-in-aware list
  assertion in workflow-routes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 15:16:16 -07:00
gsxdsm
a98d14c252 feat: per-node option to skip CLI first-run approval
A CLI node can set cliSkipApproval to bypass the trust-on-first-use pause and
run its command immediately. Exposed as a checkbox in the node inspector.
2026-06-03 13:52:42 -07:00
gsxdsm
ddde3c5b57 feat(engine,core,api): CLI nodes run arbitrary commands with trust-on-first-use approval
CLI prompt nodes now accept a raw cliCommand (any command + args), not just
named scripts. A raw command must be explicitly approved by the user before it
runs: an unapproved command pauses the task (status awaiting-cli-approval) with
the command shown; the user approves via POST /tasks/:id/workflow/approve-cli,
which records the exact command string in settings.approvedWorkflowCliCommands
and resumes. Named scripts (settings.scripts) still never require approval.
Adds POST /tasks/:id/workflow/input to answer await-input nodes (records a
steering comment + resumes).
2026-06-03 13:44:13 -07:00
gsxdsm
fd94d0f5f2 feat(engine): prompt-node execution profiles + await-input nodes
Prompt nodes now support an executor kind: model (provider/model override),
agent (adopts a named agent's model + custom instructions), skill (prompt
becomes a skill invocation), and cli (named project script with the prompt in
FUSION_NODE_PROMPT — raw commands still never accepted). Per-node maxRetries
overrides the executor-wide default (capped at 10). Await-input nodes pause the
task with status 'awaiting-user-input' and the question as pausedReason; on
unpause the newest steering comment is consumed as the answer and exposed in
graph context.
2026-06-03 13:26:01 -07:00
gsxdsm
6bb5eebf38 fix(engine,core): code-review safety fixes for the graph interpreter
- liveness: graph-routed tasks count as executing in getExecutingTaskIds/
  isTaskActive and are skipped by recoverCompletedTask + the completed-task
  resume fast-path — recovery can no longer drive a parallel lifecycle (P0)
- handleGraphFailure: sets status 'failed' (self-healing revival exemption,
  prevents FN-5704-style re-run loop) and leaves paused tasks untouched
- execute seam distinguishes pause/abort from implementation failure
- merge seam: 30-minute timeout so a wedged queue cannot strand the run
- awaitAbortInFlightTaskWork: defensive interceptor/routing cleanup
- deleteWorkflowDefinition: cascades to selections, materialized steps,
  affected tasks' enabledWorkflowSteps, and the project default
2026-06-03 13:21:54 -07:00
gsxdsm
5502025001 fix: apply safe_auto code-review fixes
- runner: report visited nodes on mid-run interpreter errors
- handleGraphFailure: clear completed-task watchdog + untrack stuck detector
- getDefaultWorkflowId: use getSettingsFast (drop per-create listWorkflowSteps read)
- db: index workflows(createdAt) in base schema + migration 103
- store: hoist workflow-definition type imports; mapping: single editorKind call
- executor: drop backwards TaskDetail->Task cast in execute seam
2026-06-03 12:26:49 -07:00
gsxdsm
44e77fda5c feat(engine): graph interpreter owns the full task lifecycle behind the flag (CU-U3, CU-U4)
Real engine seams: execute delegates to the legacy implementation phase via a
completion interceptor that stops execute() at the implementation-complete
boundary (no double review/merge); review performs the in-review handoff; merge
resolves through ProjectEngine.onMerge over the same serialized merge queue
(wired via a late-bound setMergeRequester, mirroring setMergeEnqueuer). Custom
graph nodes run on the proven WorkflowStep machinery (readonly tool policy,
verdict parsing). Adds a 'planning' seam to the vocabulary (no-op for
pre-specified tasks; custom planning is a prompt node today).

Entry point: execute() routes graph-selected tasks through the runner when
experimentalFeatures.workflowGraphExecutor is on, with process-wide routing
claims (FN-4811 posture), duplicate-dispatch dropping, pre-run errors falling
back to legacy, and mid-run errors parking the task in review (never re-running
the implementation, never stranding the task).

Flag off by default: all 587 executor tests pass unchanged.
2026-06-03 11:07:30 -07:00
gsxdsm
8156382d76 FN-5889: suppress post-done continuation wedges
Keep completed post-done continuation errors from wedging review tasks in a failed state.

- route step-session non-continuable continuation errors through the executor recovery path before marking tasks failed
- add self-healing recovery and run-audit events for in-review tasks already wedged by post-done non-continuable errors
- extend reliability coverage and architecture/backstop docs for the new post-done wedge handling

Files changed:
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   3 +-
 packages/engine/src/__tests__/reliability-interactions/post-done-continuation-no-wedge.test.ts        | 131 ++++++++++++++++++++-
 packages/engine/src/executor.ts                    |  11 +-
 packages/engine/src/run-audit.ts                   |   2 +
 packages/engine/src/self-healing.ts                |  97 ++++++++++++++-
 6 files changed, 236 insertions(+), 9 deletions(-)

Fusion-Task-Id: FN-5889

Fusion-Task-Lineage: c22716f2-cddb-4c98-ac87-0282017e7c82
2026-06-02 11:03:18 -07:00
gsxdsm
742a564491 FN-5888: retry non-continuable sessions with a fresh session
Retry incomplete executor work with a fresh session after non-continuable session errors.

- add executor recovery handling that clears session state and requeues incomplete tasks to todo while retry budget remains
- preserve terminal failure behavior once the fresh-session retry budget is exhausted
- extend reliability coverage and AGENTS.md backstop notes for the new retry path

Files changed:
 AGENTS.md                                          |  1 +
 .../post-done-continuation-no-wedge.test.ts        | 48 +++++++++++++++++++++-
 packages/engine/src/executor.ts                    | 40 ++++++++++++++++++
 3 files changed, 87 insertions(+), 2 deletions(-)

Fusion-Task-Id: FN-5888

Fusion-Task-Lineage: 4ebce260-8923-4599-aced-541533b94543
2026-06-02 10:14:20 -07:00
gsxdsm
f4cbaed494 FN-5866: suppress post-done non-continuable session errors
Keep completed executor work in review when session continuation is no longer possible.

- detect non-continuable session errors separately from unsupported message role failures
- suppress post-done continuation errors once task work is already complete and clear any failed state before review handoff
- add regression coverage for completed vs incomplete continuation failures and document the FN-5866 backstop

Files changed:
 AGENTS.md                                          |   1 +
 .../post-done-continuation-no-wedge.test.ts        | 169 +++++++++++++++++++++
 .../src/__tests__/transient-error-detector.test.ts |  27 ++++
 packages/engine/src/executor.ts                    |  41 ++++-
 packages/engine/src/transient-error-detector.ts    |   8 +
 5 files changed, 245 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-5866

Fusion-Task-Lineage: b5cffce4-7c14-40f6-b12e-84b9acdf7f50
2026-06-02 01:48:26 -07:00
gsxdsm
327f0a9a4f FN-5818: fix shared-branch-group execution to use per-task working branches
Ensure shared branch-group flows consistently derive and acquire per-task working branches.

- update engine merge/executor/scheduler/self-healing paths to resolve task-scoped working branch names instead of shared branch-group names
- adjust worktree acquisition and already-merged detection logic to use the corrected branch resolution
- add regression coverage for shared-branch-group working-branch behavior, worktree acquisition, and worktree name derivation
- add a patch changeset for @runfusion/fusion

Files changed:
 .changeset/fn-5818-shared-branch-working-branch.md |  5 ++
 .../shared-branch-group-working-branch.test.ts     | 53 ++++++++++++++++++++++
 .../src/__tests__/worktree-acquisition.test.ts     | 52 +++++++++++++++++++++
 .../engine/src/__tests__/worktree-names.test.ts    | 20 +++++++-
 packages/engine/src/already-merged-detector.ts     |  6 +--
 packages/engine/src/executor.ts                    | 10 ++--
 packages/engine/src/merger-ai.ts                   |  4 +-
 packages/engine/src/merger.ts                      | 16 +++----
 packages/engine/src/scheduler.ts                   |  6 +--
 packages/engine/src/self-healing.ts                | 12 ++---
 packages/engine/src/worktree-acquisition.ts        |  4 +-
 packages/engine/src/worktree-names.ts              |  9 +++-
 12 files changed, 166 insertions(+), 31 deletions(-)

Fusion-Task-Id: FN-5818

Fusion-Task-Lineage: c7eb1ec4-971a-49ad-9156-5c0349c629aa
2026-06-01 01:37:25 -07:00
gsxdsm
feceedbf7e FN-5803: normalize streamed sentence spacing across message boundaries
Ensure streamed agent text preserves sentence-boundary spacing even when providers split output across message boundaries.

- add stateful streaming delta normalizer that tracks prior text/thinking tail when partial blocks reset
- update executor and PI session subscriptions to use per-session normalizer instances for text_delta and thinking_delta events
- expand streaming-delta tests to cover cross-message/tool-call boundary spacing regressions
- add task notes documenting cross-message spacing refinement

Files changed:
 .../fn-5803-streaming-cross-message-space.md       |  5 ++
 .../engine/src/__tests__/streaming-delta.test.ts   | 86 +++++++++++++++++++++-
 packages/engine/src/executor.ts                    | 13 ++--
 packages/engine/src/pi.ts                          | 24 +++---
 packages/engine/src/streaming-delta.ts             | 44 ++++++++++-
 5 files changed, 155 insertions(+), 17 deletions(-)

Fusion-Task-Id: FN-5803

Fusion-Task-Lineage: 8f88d54c-bbc0-44dd-99fc-c69738ce0ca8
2026-05-31 23:24:53 -07:00
gsxdsm
2140ab2dcf FN-5789: normalize missing sentence spaces in streamed deltas
Repair provider-agnostic streaming deltas so sentence boundaries keep expected spacing in chat and agent logs.

- add shared streaming-delta normalization helpers for text/thinking events
- apply normalization at executor and PI message_update chokepoints before emitting deltas
- add focused engine tests covering punctuation-boundary repairs and no-op cases
- add a patch changeset for @runfusion/fusion describing the fix

Files changed:
 .changeset/fn-5789-streaming-space-repair.md       |  5 ++
 .../engine/src/__tests__/streaming-delta.test.ts   | 84 ++++++++++++++++++++
 packages/engine/src/executor.ts                    | 11 ++-
 packages/engine/src/pi.ts                          | 13 +++-
 packages/engine/src/streaming-delta.ts             | 91 ++++++++++++++++++++++
 5 files changed, 197 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-5789

Fusion-Task-Lineage: e60ed2ae-c006-42f9-9ab0-f4e79560fb66
2026-05-31 16:48:28 -07:00
gsxdsm
b154844286 FN-5772: re-anchor nested task worktree paths
Fix executor worktree invariant handling by re-anchoring nested task worktree paths to the actual git top-level.

- add nested worktree root detection that only re-anchors when the top-level is a registered worktree inside the configured worktrees directory
- update executor liveness gating and verifyWorktreeInvariants to persist re-anchored task.worktree values and retry checks safely
- emit a new run-audit git mutation (worktree:reanchored) and add reliability tests/docs coverage plus a patch changeset

Files changed:
 .changeset/fn-5772-worktree-reanchor.md            |  7 +++
 docs/architecture.md                               |  4 +-
 packages/engine/src/__tests__/reliability-interactions/executor-liveness-gate.test.ts                 | 33 ++++++++++
 packages/engine/src/__tests__/verify-worktree-invariants-missing.test.ts     | 62 +++++++++++++++++-
 packages/engine/src/__tests__/worktree-reanchor-nested-root.test.ts          | 73 ++++++++++++++++++++++
 packages/engine/src/executor.ts                    | 54 ++++++++++++++--
 packages/engine/src/run-audit.ts                   |  1 +
 packages/engine/src/worktree-pool.ts               | 63 +++++++++++++++++++
 8 files changed, 290 insertions(+), 7 deletions(-)

Fusion-Task-Id: FN-5772

Fusion-Task-Lineage: 475de161-7bc1-4359-bb76-20c4c07196d9
2026-05-31 08:32:01 -07:00
gsxdsm
4b8650cac2 Merge pull request #1205 from plarson/fix/incomplete-stuck-loop-parking
fix: park incomplete stuck-loop exhaustions
2026-05-30 23:01:37 -07:00
gsxdsm
d98ff8780c FN-5759: inject active-goal context across engine lanes
Enable always-on active-goal prompt injection and diagnostic wiring across triage/executor flows.

- Refactor goal-context injection so agent heartbeat, executor, and triage all apply the active-goal seam consistently.
- Extend goal injection diagnostics implementation and exports, plus anchoring audit touchpoints.
- Add and update tests for goal context injection behavior and diagnostics wiring.
- Update architecture and diagnostics docs to describe the new always-on seam.

Files changed:
 docs/architecture.md                               |  2 +-
 docs/diagnostics.md                                |  2 +-
 .../src/__tests__/goal-context-injection.test.ts   | 19 ++++-
 .../goal-injection-diagnostics-wiring.test.ts      | 98 +++++++++++++++++++++-
 packages/engine/src/agent-heartbeat.ts             | 31 ++-----
 packages/engine/src/executor.ts                    | 32 ++-----
 packages/engine/src/goal-anchoring-audit.ts        |  2 +-
 packages/engine/src/goal-injection-diagnostics.ts  | 42 +++++++++-
 packages/engine/src/index.ts                       |  2 +
 packages/engine/src/triage.ts                      | 28 +++++--
 10 files changed, 191 insertions(+), 67 deletions(-)

Fusion-Task-Id: FN-5759

Fusion-Task-Lineage: 1419de34-2e86-4459-bcd4-426f15c067fe
2026-05-30 21:54:06 -07:00
Phil Larson
ce6ebb7b8e fix(engine): preserve parked progress through stale-spec checks 2026-05-30 21:53:00 -07:00
gsxdsm
20c1c3261e FN-5741: persist merge-request handoff shadow contract
Introduce Phase 1 write-only persistence for merge-request handoff acceptance across core and engine paths.

- add persisted merge-request record types, schema/settings plumbing, and store write-path support
- update merger/executor/self-healing/run-audit flows to emit and consume the handoff-accepted shadow marker
- expand core/engine/roadmap tests and docs to cover the new merge-request shadow contract
- add a patch changeset for @runfusion/fusion for this bundled package update

Files changed:
 .changeset/fn-5741-merge-request-shadow.md         |   5 +
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   2 +
 docs/settings-reference.md                         |   1 +
 packages/core/src/__tests__/db-migrate.test.ts     |  12 +-
 packages/core/src/__tests__/db.test.ts             |  34 ++--
 packages/core/src/__tests__/goals-schema.test.ts   |   2 +-
 packages/core/src/__tests__/insight-store.test.ts  |  10 +-
 .../src/__tests__/merge-request-record.test.ts     |  97 +++++++++++
 packages/core/src/__tests__/mission-store.test.ts  |   2 +-
 packages/core/src/__tests__/run-audit.test.ts      |   2 +-
 packages/core/src/__tests__/secrets-schema.test.ts |   6 +-
 .../core/src/__tests__/settings-parity.test.ts     |   3 +
 .../core/src/__tests__/store-merge-queue.test.ts   |   2 +-
 packages/core/src/__tests__/task-documents.test.ts |   2 +-
 packages/core/src/db.ts                            |  49 +++++-
 packages/core/src/index.ts                         |   4 +-
 packages/core/src/settings-schema.ts               |  30 ++++
 packages/core/src/store.ts                         | 189 ++++++++++++++++++++-
 packages/core/src/types.ts                         |  37 ++++
 .../src/__tests__/merger-merge-lifecycle.test.ts   |  54 ++++++
 .../merge-request-shadow-handoff.test.ts           |  74 ++++++++
 packages/engine/src/executor.ts                    |  15 +-
 packages/engine/src/merger.ts                      |  37 ++++
 packages/engine/src/run-audit.ts                   |   1 +
 packages/engine/src/self-healing.ts                |  16 +-
 .../src/store/__tests__/roadmap-store.test.ts      |   4 +-
 27 files changed, 646 insertions(+), 45 deletions(-)

Fusion-Task-Id: FN-5741

Fusion-Task-Lineage: 3fec14c3-47ff-4f14-bc02-24021518c992
2026-05-30 14:42:50 -07:00
gsxdsm
ee0b1cd9c8 FN-5658: add goal injection visibility diagnostics
Improve anchoring visibility by classifying and emitting goal-injection diagnostics across engine lanes.

- add goal-injection diagnostics module with result/failure classification and audit emission helpers
- wire heartbeat and executor prompt construction to resolve classified goal context and emit diagnostic events
- expose diagnostic APIs from engine index and add new run-audit event type for prompt goal injection
- add unit and wiring tests plus diagnostics docs updates for the new observability path

Files changed:
 docs/diagnostics.md                                |   8 +
 .../goal-injection-diagnostics-wiring.test.ts      |  87 +++++++++
 .../__tests__/goal-injection-diagnostics.test.ts   | 150 +++++++++++++++
 packages/engine/src/agent-heartbeat.ts             |  34 +++-
 packages/engine/src/executor.ts                    |  35 +++-
 packages/engine/src/goal-injection-diagnostics.ts  | 209 +++++++++++++++++++++
 packages/engine/src/index.ts                       |  10 +
 packages/engine/src/run-audit.ts                   |   7 +-
 8 files changed, 521 insertions(+), 19 deletions(-)

Fusion-Task-Id: FN-5658

Fusion-Task-Lineage: f4feaa37-d9b1-4bb6-b8c9-35a9b7a02f57
2026-05-29 20:50:08 -07:00
gsxdsm
afc3b4749f FN-5655: add goal anchoring audit events across lanes
Add audit guardrails that track goal anchoring injection across executor, heartbeat, and CLI/dashboard surfaces.

- add a dedicated engine goal-anchoring audit emitter and export it
- emit goal anchoring audit events from executor and heartbeat goal-context injection paths
- extend run-audit wiring and CLI extension output to surface goal anchoring events
- add engine, CLI, and dashboard regression tests for goal-tool and audit event behavior
- document the new audit coverage and include a published changeset entry

Files changed:
 .changeset/fn-5655-goal-anchoring-audit.md         |  7 ++
 docs/architecture.md                               |  1 +
 docs/dashboard-guide.md                            |  1 +
 .../__tests__/extension-goal-tools-audit.test.ts   | 65 +++++++++++++++
 packages/cli/src/extension.ts                      | 28 +++++++
 .../__tests__/routes-run-audit-goal-events.test.ts | 72 ++++++++++++++++
 .../src/__tests__/goal-anchoring-audit.test.ts     | 95 ++++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             | 20 +++--
 packages/engine/src/executor.ts                    | 20 +++--
 packages/engine/src/goal-anchoring-audit.ts        | 89 ++++++++++++++++++++
 packages/engine/src/index.ts                       | 10 +++
 packages/engine/src/run-audit.ts                   |  6 +-
 12 files changed, 399 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-5655

Fusion-Task-Lineage: f3c10568-4050-42c4-9fe2-b84bf749b89d
2026-05-29 20:05:14 -07:00
gsxdsm
0dbb1cd6f9 FN-5704: escalate self-owned execution limbo instead of endless resume
Escalate reclaimable in-progress resume limbo into an explicit failure path to stop infinite self-healing loops.

- add resume-limbo escalation handling in self-healing/executor flow so self-owned stuck execution is failed and surfaced
- extend core task/run-audit types and retry-reset/store behavior to persist and expose the new escalation state
- add reliability interaction coverage for reclaim self-owned resume limbo escalation and update related schema/store/CLI/plugin tests and docs

Files changed:
 AGENTS.md                                          |   1 +
 docs/architecture.md                               |   2 +
 packages/cli/src/commands/__tests__/task.test.ts   |   2 +
 packages/core/src/__tests__/db-migrate.test.ts     |  12 +-
 packages/core/src/__tests__/db.test.ts             |  34 ++---
 packages/core/src/__tests__/goals-schema.test.ts   |   2 +-
 packages/core/src/__tests__/insight-store.test.ts  |  10 +-
 packages/core/src/__tests__/mission-store.test.ts  |   2 +-
 packages/core/src/__tests__/run-audit.test.ts      |   2 +-
 packages/core/src/__tests__/secrets-schema.test.ts |   6 +-
 .../core/src/__tests__/store-merge-queue.test.ts   |   2 +-
 packages/core/src/__tests__/task-documents.test.ts |   2 +-
 packages/core/src/db.ts                            |  13 +-
 packages/core/src/manual-retry-reset.ts            |   1 +
 packages/core/src/store.ts                         |  37 ++++-
 packages/core/src/types.ts                         |  11 ++
 ...laim-self-owned-resume-limbo-escalation.test.ts | 168 +++++++++++++++++++++
 packages/engine/src/executor.ts                    |   5 +
 packages/engine/src/run-audit.ts                   |   1 +
 packages/engine/src/self-healing.ts                |  72 +++++++++
 .../src/store/__tests__/roadmap-store.test.ts      |   4 +-
 21 files changed, 345 insertions(+), 44 deletions(-)

Fusion-Task-Id: FN-5704

Fusion-Task-Lineage: c8f73d16-d95b-450f-a514-e7d3c2f7aebe
2026-05-29 20:05:14 -07:00
gsxdsm
ff575f8b06 FN-5653: inject active goal context into heartbeat and executor prompts
Align heartbeat and executor prompt assembly so both lanes receive the same active-goal context block.

- inject goalContext into heartbeat and executor buildPromptLayers inputs using buildGoalContextSection
- extend goal-context regression coverage with parity tests for heartbeat/executor injection and empty-goal behavior
- update executor test helpers for goal-store access and document the shared prompt-lane behavior in architecture/agents docs

Files changed:
 docs/agents.md                                     |  1 +
 docs/architecture.md                               |  1 +
 packages/engine/src/__tests__/executor-test-helpers.ts  |  3 +
 packages/engine/src/__tests__/goal-context-injection.test.ts   | 72 ++++++++++++++++++++++
 packages/engine/src/agent-heartbeat.ts             | 12 +++-
 packages/engine/src/executor.ts                    | 12 +++-
 packages/engine/src/prompt-layers.ts               |  9 ++-
 7 files changed, 107 insertions(+), 3 deletions(-)

Fusion-Task-Id: FN-5653
Fusion-Task-Lineage: d2670585-57f7-409d-bb11-cef3448267a6
2026-05-29 20:05:14 -07:00
Phil Larson
6b57e7cbf6 fix(engine): resume execution after review revise 2026-05-29 12:57:53 -07:00
Phil Larson
b5f2f91e87 fix(FN-057): park pending review without failed status 2026-05-29 06:54:45 -07:00
gsxdsm
cec191eac3 FN-5638: migrate pi-ai and pi-coding-agent packages to @earendil-works scope
Fusion-Task-Id: FN-5638

Fusion-Task-Lineage: 6e99c156-5f6c-42e6-bd26-618e08ffd05f
2026-05-28 21:23:48 -07:00
gsxdsm
200dda95dc feat(FN-5624): suppress transient task.json ENOENT with guard, logging, and
Implements graceful suppression of transient `task.json` ENOENT errors in the executor, logging a suppression signal and surfacing a banner in the UI, with test coverage for both the executor behavior and notification service. Documentation in `docs/architecture.md` and a changeset for `@runfusion/f

Fusion-Task-Id: FN-5624

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fusion-Task-Id: FN-5624
2026-05-28 12:10:03 -07:00
gsxdsm
390bd7f923 perf(dashboard): cache gh CLI checks and defer SQLite integrity scan
Cold-start dashboard responsiveness went from ~99s to ~6-11s. CPU profiling
identified two synchronous-spawn hotspots blocking the event loop:

- `GitHubTrackingReconciler` scanned up to 200 done tasks per startup,
  each call into `getIssue` invoking `isGhAvailable()` + `isGhAuthenticated()`
  via `execFileSync`. `gh auth status` makes a network roundtrip, so 400
  sync spawns ≈ 71s of pure event-loop blocking (69% of cold-start CPU).
  Memoized both checks with a 60s TTL; `resetGhAvailabilityCache()` is
  exported for login/logout flows that need immediate invalidation.

- `PRAGMA integrity_check(100)` walks every page of the SQLite file (~7s
  per database, multiple DBs × projects). The deferred check was scheduled
  3s after init — right in the responsiveness-critical window. Pushed to
  60s so the user is already interacting before it runs; check itself is
  unchanged.

Also yields the event loop between major InProcessRuntime init phases and
between self-healing recovery steps (34 per project), defers orphan-task
AI agent resumption by 30s (env-overridable, auto-zero under Vitest), and
ships an opt-in `FUSION_TRACE_EL_LAG=/path/to/file` event-loop lag tracer
that diagnosed all of the above.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 23:41:28 -07:00
gsxdsm
3a81e65e1d Merge branch 'main' into feat/fn-024-add-dependencies-to-task-update 2026-05-25 13:28:32 -07:00
gsxdsm
a6a57dc40a test: guard tests from killing the live dashboard port
Adds a static pretest check and a runtime vitest-setup wrapper that block
shell/process calls matching `kill|pkill|killall|fuser|lsof ... <port>` or
`.listen(<port>)` against reserved Fusion ports. Reserved set is dynamic:
default 4040 plus $PORT, $FUSION_SERVER_PORT, $FUSION_RESERVED_PORTS, and any
port responding to /api/health on 4040..4045 at worker startup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:51:36 -07:00
gsxdsm
6e7f1e570e fix(dashboard): useMergeAdvanceNotice tests should waitFor toBeDefined
`notice` is `events.find(...)` which returns `undefined` (not `null`)
when no match. `waitFor(() => expect(...).not.toBeNull())` exited
immediately because `undefined !== null` — the test never actually
waited for the api mock to resolve. Sometimes the followup assertions
happened to land after the events fetched (test passed by luck);
sometimes they ran while notice was still undefined and the assertions
failed.

Switched all five waitFor sites to `.toBeDefined()` so they actually
block on the events-fetch resolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 18:39:36 -07:00
gsxdsm
7a20b95502 feat(FN-5544): emit runtime-resolved audit event across engine lanes
Adds a "session runtime resolved" audit event that flows through the engine's main execution lanes — triage, executor, reviewer, merger, heartbeat, step-session-executor, and mission-execution-loop — with runtime mutation support and test coverage, plus a compile-fix for the merger auditor wiring.

Fusion-Task-Id: FN-5544

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fusion-Task-Id: FN-5544
2026-05-23 12:14:07 -07:00
gsxdsm
ec1269fd84 feat(merger): auto-rehome FF-recoverable orphan commits in contamination recovery
Follow-up to bf4428c00 (FF-only ref advance). After the prevention fix
new orphans can't form, but pre-fix orphans like f6358ce4 on
fusion/fn-5419 still need a path back onto the integration branch.

Adds an `orphan-our-advance` classification to contamination recovery:
a "unique" foreign commit whose Fusion-Task-Id trailer points at a
`done` task AND that is unreachable from refs/heads/<integrationBranch>
is treated as a stranded merger output.

For these, the executor attempts a fast-forward rehome onto the
integration branch via advanceIntegrationBranchRef (which still enforces
the FF-only invariant). When successful, the orphan sha is added to the
existing `shasToDrop` set so the same recovery pass that drops
already-upstream/misrouted commits also drops the now-upstream orphan.

Non-FF orphans (diverged from current integration tip) are refused.
Doing a cherry-pick onto the integration branch from inside automated
recovery would introduce conflict-resolution surface that's too high
blast radius for a never-event recovery path. The refusal log line
includes the exact `git cherry-pick <sha>` command an operator can run
manually.

Two new GitMutationType audit events:
  - merger:orphan-rehome-ff (successful FF rehome)
  - merger:orphan-rehome-refused (non-FF, manual cherry-pick required)

Tests in merger-orphan-rehome.test.ts cover classification (orphan,
not-done, already-reachable, no-trailer) and the rehome operation
(FF success advances the ref + emits the audit event; non-FF refusal
emits the hint and leaves the ref untouched).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 09:59:50 -07:00
gsxdsm
2209c57dd6 chore(engine): remove workflow-step mock routing + stale FN-5482 docs
Drops the "workflow-step" MockSessionPurpose enum value and the
workflowStepId / workflowStepTemplateId plumbing through
agent-runtime, agent-session-helpers, mock-provider, executor, and
merger. The seeded-workflow-prompts script loses its FN-5205
rationale comment + test (no longer applicable now that workflow
steps run through the regular session purposes).

Also strips the stale FN-5482 architecture-invariant bullet from
AGENTS.md and the corresponding audit-event line from
docs/architecture.md (the self-healing reclaim invariant they
described no longer holds).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 03:09:00 -07:00
gsxdsm
76bd3a7d90 feat(FN-5205): add workflow-step test mode dispatch and routing for mock pr
Implements workflow step test mode (FN-5205) by wiring mock dispatch, context forwarding, and routing through executor, merger, and mock provider, plus adding corresponding tests and docs. Also adds broad-scope triage heuristics to improve task-scope detection, touching triage.ts, triage-broad-scope

Fusion-Task-Id: FN-5205

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
Fusion-Task-Id: FN-5205
2026-05-23 02:25:00 -07:00
gsxdsm
2a3a07a612 feat(FN-5403): merge fusion/fn-5403 2026-05-22 23:12:49 -07:00
gsxdsm
3ccb132dcc feat(FN-5519): merge fusion/fn-5519 2026-05-22 22:43:26 -07:00
gsxdsm
838002491d fix(executor): bypass summary-incomplete refusal for PREMISE STALE: summaries
Address the code-review finding on the prior commit: a natural premise-stale
summary like "PREMISE STALE: the task has no remaining work — implementation
is already done on HEAD" matches /\b(incomplete|not implemented|not done|
not finished)\b/i with 'the task' inside the 40-char first-person window,
refusing fn_task_done with summary-claims-incomplete and deadlocking the
escape hatch.

When summary starts (case-insensitive) with PREMISE STALE:, skip the
dissent-pattern and scoped-incomplete summary checks. Pending-code-review
and bulk-step-completion guards still apply unchanged.

Add executor-task-done-premise-stale.test.ts covering: the deadlock case
now passes; dissent phrasing in a sentinel summary is allowed; case-
insensitive sentinel; sentinel must be at the start (mid-summary doesn't
bypass); REVISE verdict still blocks even with the sentinel.
2026-05-22 22:34:32 -07:00
gsxdsm
8a3afcf9d4 fix(executor+engine-tests): preflight premise-stale exit and serialize reliability suite
Root-cause prevention for the FN-5521 failure class where PROMPT.md describes
work that is already done on HEAD and the executor still marches through
plan/review/test/doc, then merger burns hours retrying against unrelated
flakes in @fusion/engine reliability-interactions.

- Executor system prompt: add a Preflight escape hatch. When Step 0
  reproduces and finds HEAD already matches the desired state, the agent
  marks Step 0 done, marks remaining steps skipped, and calls fn_task_done
  with a `PREMISE STALE:` summary. Reuses the existing
  evaluateTaskDoneRefusal/skipped semantics and the merger's
  empty-own-diff fast-path — no new tools or refusal classes needed.

- packages/engine/vitest.config.ts: split into two projects. engine-default
  retains full parallelism; engine-reliability scopes
  src/__tests__/reliability-interactions/** to
  poolOptions.threads.singleThread so event-ordering assertions stop
  flaking under workspace-concurrent merge-gate load (the
  `expected 24 to be less than 19` rowid interleaving in
  merge-reuse-task-worktree).
2026-05-22 22:26:18 -07:00
gsxdsm
e291d86444 feat: attribute Fusion as Co-authored-by trailer instead of primary author
Switch commits Fusion produces (both executor step commits and merger squash
commits) from setting `--author="Fusion <noreply@runfusion.ai>"` to appending
`-m "Co-authored-by: Fusion <noreply@runfusion.ai>"`. The user's configured
git identity now stays as the primary author/committer, and Fusion is recorded
as a co-author (recognized by GitHub for shared attribution). The
`commitAuthorEnabled` toggle and `commitAuthorName`/`commitAuthorEmail`
settings keep their existing keys; the dashboard settings UI relabels them
from "Author" to "Co-author" to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 20:38:11 -07:00
gsxdsm
5848606a9a feat(engine): post-session branch attribution audit
Contamination on fusion/<id> branches (FN-5233 was the recent example:
two untrailered feat(FN-5353): commits sitting on fusion/fn-5233) used
to be invisible until merge time, days after it happened. The executor
already runs assertCleanBranchAtBase at worktree acquisition and reclaim
— the gap was the active session window itself.

Add reportBranchAttribution(repoDir, branch, baseSha, taskId) which
walks base..branch and bins every commit into ownTrailed (healthy),
ownUntrailed (subject tag but commit-msg hook didn't fire), foreign
(different FN-id), or unattributed (no subject pattern, no trailer —
typically a hand-merge or plumbing commit). Wire it into the executor
right after captureModifiedFiles in the post-session path: when any
anomaly bucket is non-empty, emit a structured branch:attribution-
anomaly audit event and a task log entry. The audit itself is wrapped
in a try/catch so a probe failure never destabilizes a completing
session. New branch:attribution-anomaly and branch:auto-reattach-
authoritative GitMutationType variants accept the structured metadata
(the latter for the handoff re-attach added earlier this session).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:20:33 -07:00
Fusion (runfusion.ai)
79850b233f feat(FN-5349): add integration branch resolver with auto-recovery fallback
FN-5349 adds a dedicated integration branch resolution module (`packages/engine/src/integration-branch.ts`) replacing ad-hoc dynamic fallbacks, routes merger branch conflict resolution through it, wires auto-recovery handlers (branch-worktree, contamination) to use integration branch fallback, and w

Fusion-Task-Id: FN-5349
2026-05-21 12:04:58 -07:00
Fusion (runfusion.ai)
a2a643844d feat(FN-5436): skip step retries when review is pending
Added executor logic to skip retries when a review is pending for a task, introducing a `pendingReviewBlockHelper` in the task-done path and updating the retry-gate to consult it; two new reliability-interaction test suites cover the feature behavior and composition with existing retry/backstop laye

Fusion-Task-Id: FN-5436
2026-05-21 10:58:28 -07:00
gsxdsm
7d25d98b2f fix(FN-5256): await disposal across task:moved-away and task:deleted
Close the last fire-and-forget gap from the previous fixes: the task:moved
(away from in-progress) and task:deleted listeners no longer call the
synchronous fire-and-forget `abortInFlightTaskWork`. Instead they track an
awaited disposal promise per task in `pendingTaskDisposals`. The task:moved
(to in-progress) dispatch path awaits any in-flight disposal for the same
task before calling `execute()`, so a fast bounce (in-progress → todo →
in-progress) no longer races the conflict-cleanup path against a still-live
shell.

`awaitAbortInFlightTaskWork` now claims each session surface (activeSessions,
activeStepExecutors, activeWorkflowStepSessions, activeSubagentSessions)
synchronously before awaiting any async abort. This lets concurrent disposal
calls for the same task dedupe naturally — the second call finds the maps
empty and no-ops, preserving the existing single-abort/single-dispose
contract that the soft-delete and user-cancel tests assert.

Adds a regression test in executor-user-cancel covering the re-dispatch
ordering: an immediate task:moved-to-in-progress that follows a still-running
task:moved-away must wait for abort to complete before execute() runs.

The legacy `abortInFlightTaskWork` is removed (no callers).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:14:38 -07:00