feat(FN-4625): complete Step 7 — verification and docs updates

Fusion-Task-Id: FN-4625
Fusion-Task-Lineage: c1d9b414-b5dd-4786-ba51-0b8adec4acf5
This commit is contained in:
Fusion (runfusion.ai)
2026-05-15 20:53:07 -07:00
committed by gsxdsm
parent 7c364da077
commit 8b371bae04
4 changed files with 17 additions and 3 deletions

View File

@@ -0,0 +1,5 @@
---
"@runfusion/fusion": minor
---
Fail-hard by default when a delegated worktrunk operation fails: the task is paused with `pausedReason: "worktrunk_operation_failed"` and the underlying stderr is surfaced in the dashboard. Set `worktrunk.onFailure: "fallback-native"` to instead fall back transparently to Fusion's built-in worktree-pool and receive a one-shot dashboard alert per task.

View File

@@ -264,7 +264,7 @@ Sandbox backend precedence is:
| --- | --- | --- | --- |
| `worktrunk.enabled` | `boolean` | `false` | Enables `WorktreeBackend` selection in `packages/engine/src/worktree-backend.ts`. Tier: global + project, merged field-by-field with project overrides. |
| `worktrunk.binaryPath` | `string \| undefined` | `undefined` | Optional absolute `worktrunk` binary path passed to the worktrunk backend. Tier: global + project with field-level precedence (project overrides only this field when set). |
| `worktrunk.onFailure` | `"fail" \| "fallback-native"` | `"fail"` | Worktrunk failure mode in `packages/engine/src/worktree-backend.ts`: `fail` rethrows the backend error; `fallback-native` retries once with native `git worktree` and records fallback audit telemetry. Binary auto-install (FN-4624), dashboard settings UX (FN-4627), and CLI setter wiring (FN-4629) are downstream follow-ups. |
| `worktrunk.onFailure` | `"fail" \| "fallback-native"` | `"fail"` | Failure disposition for delegated worktrunk operations (`create`, `sync`, `prune`, `remove`, install/resolve): `fail` (default) pauses the task with `pausedReason: "worktrunk_operation_failed"`, persists `task.worktrunkFailure`, and emits `worktree:worktrunk-failure`; `fallback-native` emits `worktree:worktrunk-fallback-native`, sends a one-shot per-task fallback alert guarded by `task.worktrunkFallbackAlertedAt`, then retries against native `git worktree`. |
| `worktrunk.installedBinaryPath` | `string \| undefined` | `undefined` | Cached install path set by the auto-install flow. Managed by the engine; not intended for manual editing. Tier: global + project with field-level precedence. |
### Worktrunk auto-install flow
@@ -286,7 +286,13 @@ Fusion maintains a pinned release version (`WORKTRUNK_PINNED_RELEASE` in `packag
If the platform has no pinned release asset, or if the release download/verification fails, Fusion falls back to `cargo install worktrunk --version <pinned>` when `cargo` is on `$PATH`. After cargo install, Fusion probes `$PATH` and `~/.cargo/bin/worktrunk` for the installed binary.
If both release and cargo paths fail, the install throws `WorktrunkInstallFailedError` and the worktrunk backend's `onFailure` setting determines whether the task pauses or falls back to native worktree operations.
If both release and cargo paths fail, the install throws `WorktrunkInstallFailedError` and `worktrunk.onFailure` governs disposition (`fail` → pause task, `fallback-native` → native fallback with one-shot alert).
When fail-hard disposition is used, the task carries structured diagnostics:
- `pausedReason: "worktrunk_operation_failed"`
- `worktrunkFailure: { op, stderr, exitCode, attemptedAt }`
- `worktrunkFallbackAlertedAt` remains unset unless `fallback-native` is used
#### `network_api` action-gate

View File

@@ -23,6 +23,7 @@ describe("acquireTaskWorktree backend wiring", () => {
const task = { id: "FN-1", title: "Task", description: "Desc", branch: null, worktree: null } as any;
const store = {
updateTask: vi.fn().mockResolvedValue(undefined),
pauseTask: vi.fn().mockResolvedValue(undefined),
logEntry: vi.fn().mockResolvedValue(undefined),
} as any;
@@ -30,6 +31,7 @@ describe("acquireTaskWorktree backend wiring", () => {
execMock.mockReset();
store.updateTask.mockClear();
store.logEntry.mockClear();
store.pauseTask.mockClear();
});
it("uses native backend by default and emits no worktrunk audit", async () => {

View File

@@ -21,6 +21,7 @@ import {
} from "./worktrunk-installer.js";
import {
handleWorktrunkOperationFailure,
type WorktreeOperationResult,
type WorktrunkOpName,
} from "./worktrunk-failure-handler.js";
import type { RunAuditor } from "./run-audit.js";
@@ -125,7 +126,7 @@ export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Pro
runContext,
runAudit: audit,
notify: ({ op: failedOp, stderr: failedStderr }) => notifyFallback(failedOp, failedStderr),
nativeFallback: nativeFallback as (() => Promise<any>) | undefined,
nativeFallback: nativeFallback as (() => Promise<WorktreeOperationResult>) | undefined,
});
if (disposition.kind === "fallback-native") {
return disposition.result;