feat(FN-2734): merge fusion/fn-2734
- docs(FN-2734): complete Step 7 — cross-link routing docs Fusion-Task-Id: FN-2734
This commit is contained in:
@@ -744,6 +744,50 @@ In `packages/engine/src/ipc/ipc-protocol.ts`:
|
||||
+ InProcessRuntime
|
||||
```
|
||||
|
||||
## Task Routing Architecture
|
||||
|
||||
Task dispatch routing is resolved in two layers:
|
||||
|
||||
1. **Task routing resolution** (`packages/engine/src/effective-node.ts`)
|
||||
- `resolveEffectiveNode(task, settings)` applies precedence:
|
||||
1. `Task.nodeId` → `task-override`
|
||||
2. `ProjectSettings.defaultNodeId` → `project-default`
|
||||
3. no node set → `local`
|
||||
2. **Runtime selection** (`packages/engine/src/project-manager.ts`)
|
||||
- `child-process` isolation always uses `ChildProcessRuntime`
|
||||
- `in-process` isolation uses `RemoteNodeRuntime` when the registered project host node is remote
|
||||
- otherwise uses `InProcessRuntime`
|
||||
|
||||
### Dispatch flow in scheduler
|
||||
|
||||
On dispatch (`packages/engine/src/scheduler.ts`), scheduler:
|
||||
- resolves effective node/source,
|
||||
- persists `effectiveNodeId` + `effectiveNodeSource` on the task,
|
||||
- logs activity: `Node routing resolved: <node|local> (source: <source>)`.
|
||||
|
||||
### Active-task node-override guard
|
||||
|
||||
`packages/core/src/node-override-guard.ts` enforces immutable routing overrides for active tasks:
|
||||
- `validateNodeOverrideChange()` blocks node override updates while task column is `in-progress`
|
||||
- returns reason `task-in-progress`
|
||||
|
||||
`TaskStore.updateTask()` applies this guard before persisting `nodeId` changes.
|
||||
|
||||
### Unavailable-node policy status
|
||||
|
||||
`unavailableNodePolicy` is a validated/stored project setting (`block` default, `fallback-local` allowed) and is exposed in dashboard/CLI controls.
|
||||
|
||||
Current implementation note: scheduler dispatch does **not yet** enforce health-based `block`/`fallback-local` behavior; node-health enforcement is reserved for a follow-up path (see scheduler `nodeHealthMonitor` reserved comment).
|
||||
|
||||
### Routing activity visibility
|
||||
|
||||
Routing decisions are visible in task activity/log entries and in task metadata (`effectiveNodeId`, `effectiveNodeSource`), and surfaced in dashboard routing UI + `fn task show` output.
|
||||
|
||||
See also:
|
||||
- [Settings Reference → Node Routing settings](./settings-reference.md#node-routing-settings-project-scope)
|
||||
- [Task Management → Node Routing](./task-management.md#node-routing)
|
||||
- [Multi-Project → Node Routing](./multi-project.md#node-routing)
|
||||
|
||||
---
|
||||
|
||||
## 12) Settings Hierarchy
|
||||
@@ -840,3 +884,5 @@ Git behavior is implemented primarily in engine executor/merger + dashboard/CLI
|
||||
- **Pi extension:** `packages/cli/src/extension.ts`
|
||||
- **Runtime abstraction:** `packages/engine/src/project-runtime.ts`
|
||||
- **Multi-project orchestrator:** `packages/engine/src/hybrid-executor.ts`
|
||||
- **Task routing resolver:** `packages/engine/src/effective-node.ts`
|
||||
- **Node override guard:** `packages/core/src/node-override-guard.ts`
|
||||
|
||||
@@ -301,6 +301,7 @@ Task lifecycle and task operations.
|
||||
```bash
|
||||
fn task create "Fix login race condition"
|
||||
fn task create "Fix bug" --attach screenshot.png --depends FN-010
|
||||
fn task create "Investigate flaky runner" --node edge-runner
|
||||
fn task plan "Design a new authentication flow"
|
||||
```
|
||||
|
||||
@@ -312,6 +313,11 @@ fn task show FN-001
|
||||
fn task logs FN-001 --follow --limit 50 --type tool
|
||||
```
|
||||
|
||||
`fn task show <id>` includes routing context when available:
|
||||
- task node override
|
||||
- project default node fallback
|
||||
- unavailable-node policy value
|
||||
|
||||
### Execution and status
|
||||
|
||||
```bash
|
||||
@@ -323,6 +329,18 @@ fn task pause FN-001
|
||||
fn task unpause FN-001
|
||||
```
|
||||
|
||||
### Node routing controls
|
||||
|
||||
```bash
|
||||
fn task set-node FN-001 edge-runner
|
||||
fn task clear-node FN-001
|
||||
```
|
||||
|
||||
Notes:
|
||||
- `set-node` resolves either node name or node ID.
|
||||
- `set-node` and `clear-node` are blocked while the task is in progress.
|
||||
- Use `fn node list` / `fn node show <name>` to discover node IDs and status.
|
||||
|
||||
### Collaboration and guidance
|
||||
|
||||
```bash
|
||||
@@ -497,6 +515,8 @@ Show and manage settings.
|
||||
```bash
|
||||
fn settings
|
||||
fn settings set maxConcurrent 4
|
||||
fn settings set defaultNodeId node_abc123
|
||||
fn settings set unavailableNodePolicy fallback-local
|
||||
fn settings export [--scope global|project|both] [--output <file>]
|
||||
fn settings import <file> [--scope global|project|both] [--merge] [--yes]
|
||||
```
|
||||
@@ -583,6 +603,7 @@ Subcommands: `search`, `install`.
|
||||
| `--dev` | `fn dashboard`, `fn desktop` |
|
||||
| `--attach` | `fn task create` |
|
||||
| `--depends` | `fn task create` |
|
||||
| `--node` | `fn task create` |
|
||||
| `--feedback` | `fn task refine` |
|
||||
| `--yes` | confirmation-skipping flows (`task plan`, `settings import`, git pull/push, etc.) |
|
||||
| `--limit`, `-l` | `fn task import` (default: 30, max: 100), `fn skills search` (default: 10, max: 50) |
|
||||
|
||||
@@ -112,7 +112,15 @@ Memory view provides a multi-file editor for project and daily memory files.
|
||||
|
||||
## Task Detail Modal
|
||||
|
||||
Inspect task definition, logs, comments, documents, workflow outcomes, and model overrides from a single modal.
|
||||
Inspect task definition, logs, comments, documents, workflow outcomes, model overrides, and task routing from a single modal.
|
||||
|
||||
The **Routing** tab shows:
|
||||
- effective node
|
||||
- routing source (task override vs project default vs local)
|
||||
- unavailable-node policy value
|
||||
- per-task node override controls (locked while task is active)
|
||||
|
||||
Project-wide routing defaults are configured in **Settings → Node Routing**.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -80,6 +80,53 @@ Projects can run with:
|
||||
- **`in-process`** (default): low overhead, shared process
|
||||
- **`child-process`**: stronger isolation with independent process boundary
|
||||
|
||||
## Node Routing
|
||||
|
||||
Multi-project deployments use two related node fields at different layers:
|
||||
|
||||
1. **Project runtime placement** (`projects.nodeId` in `~/.fusion/fusion-central.db`)
|
||||
- Decides where a project runtime is hosted in multi-project orchestration.
|
||||
2. **Task dispatch default** (`defaultNodeId` in project settings)
|
||||
- Decides where tasks route when they do not have a per-task override.
|
||||
|
||||
These fields are intentionally distinct.
|
||||
|
||||
### Runtime placement (`projects.nodeId`)
|
||||
|
||||
`ProjectManager` uses project registration data plus isolation mode to pick runtime type:
|
||||
|
||||
- `isolationMode: "child-process"` → always `ChildProcessRuntime`
|
||||
- `isolationMode: "in-process"` + remote `projects.nodeId` → `RemoteNodeRuntime`
|
||||
- `isolationMode: "in-process"` + local/unset/missing node assignment → `InProcessRuntime`
|
||||
|
||||
So `projects.nodeId` is a **project host-node assignment**, not a per-task override.
|
||||
|
||||
### Task routing defaults (`defaultNodeId` + `Task.nodeId`)
|
||||
|
||||
Within a project runtime, effective task routing resolves as:
|
||||
|
||||
1. task override (`Task.nodeId`)
|
||||
2. project default (`defaultNodeId`)
|
||||
3. local execution
|
||||
|
||||
This allows each project to maintain independent routing behavior even when managed from one central registry.
|
||||
|
||||
### Unavailable node policy in multi-project context
|
||||
|
||||
`unavailableNodePolicy` is project-scoped and can be set differently per project (`block` or `fallback-local`).
|
||||
|
||||
Current behavior: scheduler dispatch records effective node/source for each task, but health-based block/fallback enforcement is not yet applied in the scheduler dispatch path.
|
||||
|
||||
### Example: different node defaults per project
|
||||
|
||||
- **Project A** (`projects.nodeId` assigned to remote host): runtime executes via `RemoteNodeRuntime`; `defaultNodeId=edge-a` routes unpinned tasks to edge-a.
|
||||
- **Project B** (`projects.nodeId` unset): runtime stays local `InProcessRuntime`; `defaultNodeId=edge-b` still marks its task dispatch default independently.
|
||||
|
||||
See also:
|
||||
- [Settings Reference → Node Routing settings](./settings-reference.md#node-routing-settings-project-scope)
|
||||
- [Task Management → Node Routing](./task-management.md#node-routing)
|
||||
- [Architecture → Task Routing Architecture](./architecture.md#task-routing-architecture)
|
||||
|
||||
## Auto-Migration from Single-Project
|
||||
|
||||
On first run after upgrade:
|
||||
|
||||
@@ -125,12 +125,8 @@ Defaults from `DEFAULT_PROJECT_SETTINGS`; key scope from `PROJECT_SETTINGS_KEYS`
|
||||
| `maxWorktrees` | `number` | `4` | Max git worktrees. |
|
||||
| `pollIntervalMs` | `number` | `15000` | Scheduler poll interval (ms). |
|
||||
| `heartbeatMultiplier` | `number` | `1` | Global multiplier applied to all agent heartbeat intervals. Configured from the Agents screen (not Settings). |
|
||||
| `defaultNodeId` | `string` | `undefined` | Optional project default node ID. When set, tasks without a per-task `nodeId` override are routed to this node. |
|
||||
| `unavailableNodePolicy` | `"block" \| "fallback-local"` | `"block"` | Routing policy when a selected node is unavailable/unhealthy. `"block"` stops execution until the node is healthy; `"fallback-local"` runs the task on the local node instead. Applies to both project-default node routing and per-task node overrides. |
|
||||
|
||||
CLI usage:
|
||||
- `fn settings set defaultNodeId <node-id>`
|
||||
- `fn settings set unavailableNodePolicy <block|fallback-local>`
|
||||
| `defaultNodeId` | `string` | `undefined` | Optional project default execution node for task dispatch. When set, tasks without a per-task `nodeId` override resolve to this node (`routing source: project-default`). See [Task Management → Node Routing](./task-management.md#node-routing). |
|
||||
| `unavailableNodePolicy` | `"block" \| "fallback-local"` | `"block"` | Project routing policy value used by dashboard/CLI routing controls. Current scheduler dispatch records effective routing but does not yet apply health-based block/fallback enforcement in the dispatch path. See [Architecture → Task Routing Architecture](./architecture.md#task-routing-architecture). |
|
||||
|
||||
| `groupOverlappingFiles` | `boolean` | `true` | Serialize execution when file scopes overlap. |
|
||||
| `overlapIgnorePaths` | `string[]` | `[]` | Optional project-relative file or directory paths to exclude from overlap blocking (for example `docs` or `generated/openapi.json`). Entries are trimmed, deduplicated, and must not be absolute or contain `..` traversal. |
|
||||
@@ -226,6 +222,30 @@ CLI usage:
|
||||
| `showQuickChatFAB` | `boolean` | `false` | Show floating quick-chat button (chat remains available via More menu). |
|
||||
| `experimentalFeatures` | `Record<string, boolean>` | `{}` | Project-scoped experimental feature flags. |
|
||||
|
||||
### Node Routing settings (project scope)
|
||||
|
||||
Node routing controls in the project settings table are configured from **Settings → Node Routing** in the dashboard or via CLI:
|
||||
|
||||
- `fn settings set defaultNodeId <node-id>`
|
||||
- `fn settings set unavailableNodePolicy <block|fallback-local>`
|
||||
|
||||
Routing precedence for task dispatch is:
|
||||
1. per-task override (`Task.nodeId`)
|
||||
2. project default (`defaultNodeId`)
|
||||
3. local execution
|
||||
|
||||
### Project Default Node vs central project node assignment
|
||||
|
||||
Fusion also stores `projects.nodeId` in the **central registry database** (`~/.fusion/fusion-central.db`). That value is a multi-project runtime placement field used by `ProjectManager` (for selecting remote vs local project runtime), not the same setting as `defaultNodeId` task dispatch routing.
|
||||
|
||||
- `defaultNodeId` (project settings): task-level dispatch default
|
||||
- `projects.nodeId` (central registry): which node hosts the project runtime in multi-project mode
|
||||
|
||||
See also:
|
||||
- [Task Management → Node Routing](./task-management.md#node-routing)
|
||||
- [Multi-Project → Node Routing](./multi-project.md#node-routing)
|
||||
- [Architecture → Task Routing Architecture](./architecture.md#task-routing-architecture)
|
||||
|
||||
### Remote Access settings (project-scoped)
|
||||
|
||||
Remote access settings are project-only (stored in `.fusion/config.json`), not global.
|
||||
|
||||
@@ -245,6 +245,70 @@ Each task may override:
|
||||
|
||||
Overrides are configured from the task model tab or task creation actions.
|
||||
|
||||
## Node Routing
|
||||
|
||||
Tasks execute on an effective node selected by routing precedence:
|
||||
|
||||
1. **Per-task node override** (`Task.nodeId`)
|
||||
2. **Project default node** (`defaultNodeId` in project settings)
|
||||
3. **Local execution** (no node configured)
|
||||
|
||||
At dispatch time, scheduler routing is persisted on the task as:
|
||||
- `effectiveNodeId`
|
||||
- `effectiveNodeSource` (`task-override`, `project-default`, or `local`)
|
||||
|
||||
### Per-task node override
|
||||
|
||||
You can set or clear a task override from:
|
||||
|
||||
- Task detail modal → **Routing** tab
|
||||
- Quick/create flows that support node selection
|
||||
- Bulk task actions
|
||||
- CLI:
|
||||
- `fn task set-node <task-id> <node-name-or-id>`
|
||||
- `fn task clear-node <task-id>`
|
||||
- `fn task create "..." --node <node-name-or-id>`
|
||||
- Pi extension tool `fn_task_update` with `nodeId`
|
||||
|
||||
### Active-task blocking
|
||||
|
||||
Node override changes are blocked while a task is active/in progress. Core validation (`validateNodeOverrideChange`) returns `reason: "task-in-progress"` and users must pause/stop or wait for completion before changing routing.
|
||||
|
||||
### Task detail routing summary
|
||||
|
||||
The Routing tab shows:
|
||||
|
||||
- Effective node (with health indicator when known)
|
||||
- Routing source (override vs project default vs local)
|
||||
- Unavailable-node policy value (`block` or `fallback-local`)
|
||||
- Lock banner when routing is currently immutable for an active task
|
||||
|
||||
### Activity log entries
|
||||
|
||||
When a task is dispatched, task activity/log records include routing decisions such as:
|
||||
|
||||
- `Node routing resolved: <node-or-local> (source: <source>)`
|
||||
|
||||
Use `fn task show <id>` or task logs to inspect current node routing context.
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Route one task to a specific remote node
|
||||
fn task set-node FN-204 edge-runner
|
||||
|
||||
# Remove override and return to project default routing
|
||||
fn task clear-node FN-204
|
||||
|
||||
# Create a task with node override immediately
|
||||
fn task create "Reproduce flaky node error" --node edge-runner
|
||||
|
||||
# Inspect routing summary from CLI
|
||||
fn task show FN-204
|
||||
```
|
||||
|
||||
See also: [Settings Reference → Node Routing settings](./settings-reference.md#node-routing-settings-project-scope) and [Architecture → Task Routing Architecture](./architecture.md#task-routing-architecture).
|
||||
|
||||
## Review Level
|
||||
|
||||
Review levels control the rigor of the review process for a task:
|
||||
|
||||
Reference in New Issue
Block a user