feat(FN-3503): add project-node path mapping persistence APIs and schema

Adds project-node path mapping infrastructure in the core database layer (schema, migration backfill, and persistence APIs in `central-core.ts` and `central-db.ts`) with accompanying documentation. Also introduces a review-before-apply draft gate for agent onboarding and the agent detail view's mail

Fusion-Task-Id: FN-3503
This commit is contained in:
Fusion
2026-05-07 12:32:49 -07:00
committed by gsxdsm
parent ad5bed22f8
commit b434cc2d38
9 changed files with 568 additions and 31 deletions

View File

@@ -89,11 +89,14 @@ Projects can run with:
## Node Routing
Multi-project deployments use two related node fields at different layers:
Multi-project deployments use three related node/path records 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)
2. **Project working-directory mapping** (`projectNodePathMappings` in `~/.fusion/fusion-central.db`)
- Stores the absolute path for a project on each node (`projectId` + `nodeId` key).
- Local mappings are auto-created from `projects.path` at registration and kept in sync when local canonical path changes.
3. **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.
@@ -106,7 +109,7 @@ These fields are intentionally distinct.
- `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.
So `projects.nodeId` is a **project host-node assignment**, not a per-task override, and not the node-specific working-directory source of truth (that lives in `projectNodePathMappings`).
### Task routing defaults (`defaultNodeId` + `Task.nodeId`)