U7: full mode × surface × own-settings matrix ledger with 5 gap-filling
tests, default-workflow zero-binding parity assertions, changeset covering
the complete feature, and a workflow-steps.md authoring section for column
agents.
U5: action-gating contexts, the heartbeat deferral gate, a two-pass
resumeTaskForAgent, and the reverse-direction agent.taskId guards (via a
new isAgentEffectivelyExecuting callback wired at the in-process runtime)
all consult the column-effective agent; the restart watcher re-resolves
column bindings per tick for bound graph sessions, hot-swapping on
agent-changed and falling back without restart on agent-deleted.
U4: seams stamp the governing node id into run context; a per-seam
resolveSeamColumnAgent feeds the core resolver and threads the effective
agent through resolveExecutorSessionModel, runtime hints, persona, memory
tools, and StepSessionExecutor attribution. Characterization tests pin the
no-binding path byte-identical. Gating/deferral principal moves in U5.
U3: per-run IR resolution feeds the core column-agent resolver at the
runCustomNode seam; override supersedes node agent/model/persona wholesale,
defer fills bare nodes only; adoption and fallback are audited via logEntry;
raw-CLI nodes log a skip. Also fixes the customInstructions persona drift —
node-level executor:"agent" persona injection now uses the typed
soul/instructionsText fields (KTD-6).
U1+U2 of the column-agent plan: WorkflowColumnAgent on WorkflowIrColumn
(defer/override), template-subgraph column validation, v2-only-feature
registration, plugin-sdk type parity, and the shared core resolver with
instanceNodeId format ownership moved to core.
Main went red when the fast-tests quality-backfill projects (PR #1385)
landed alongside the workflow-columns stream (PR #1424) — the new test
projects were written against pre-stream code:
- TaskFieldsSection.css toggle knob used background: #fff, violating the
theme-token assertion in AgentListModal's styling-parity test; use
var(--card) per the SkillsView toggle convention
- ListView.test.tsx api mock lacked fetchBoardWorkflows (TaskDetailModal
now calls it on mount)
- chat.test.ts and routes-agent-import.test.ts @fusion/core mocks lacked
registerTraitHookImpl (engine merge-trait registers hooks at import)
- auto-merge-toggle-blank.mobile and board-mobile-initial-render used
vi.runAllTimers(), which never terminates now that sse-bus starts a
keepalive setInterval; use vi.runOnlyPendingTimers()
Both quality-backfill projects now pass fully: 7151/7151 across 414
files.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Expand the directory-path follow-up section: PR #1428, 400 no-entry
branch, heal-on-enable in both routers
- Document the vitest fs-mock vs externalized workspace-dep trap and
the real-fs drift-guard test pattern
- Add Plugin Entry to CONCEPTS.md Plugins cluster
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Bundled fallback assertions for dependency-graph/reports now require
the bundled.js entry-file suffix instead of just containing the id
- Add route-level fallback cases for dist/index.js and src/index.ts
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add heal block to createPluginRouter's enable handler so it matches
routes.ts (directory-path registrations re-pointed at entry files)
- Test the 400 "no loadable entry file" install branch
- Add a real-fs drift-guard test asserting the CLI and @fusion/core
copies of resolvePluginEntryPath resolve identically
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Plugins installed from Settings → Built-in Plugins registered the
manifest directory as the plugin path, but since FN-4128 the loader
requires a loadable entry FILE (Node ESM cannot import directories),
so enabling failed with "Plugin entry must be a file, got directory".
Only the CLI startup path had been migrated to entry-file resolution,
which is why CLI-auto-installed plugins worked and Settings installs
never did.
- Add resolvePluginEntryPath (bundled.js → dist/index.js →
src/index.ts) to @fusion/core; the CLI keeps its local copy (its
test fs mocks don't reach externalized core) with sync comments
both ways.
- Register the resolved entry file in both dashboard install routes;
400 with a clear message when a package has no loadable entry.
- Heal legacy directory-path registrations on enable, mirroring the
CLI's startup heal, so existing broken rows recover from the UI
without a restart.
- Route tests: assert installs register entry files, cover the
enable-route heal, and update existing install tests to the
entry-file contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>