FN-6126: enable workflow experimental flags by default

Turn on the workflow rollout flags by default and update docs/tests for the new opt-out behavior.

- default workflowColumns, workflowGraphExecutor, workflowInterpreterDualObserve, and workflowInterpreterAuthoritative to enabled in global settings
- update workflow docs and concepts to describe explicit flag-off overrides instead of default-off rollout gating
- remove redundant demo/test setup that manually enabled workflow columns and keep characterization coverage for both enabled and disabled states
- add a changeset for the published CLI package documenting the default-on workflow rollout

Files changed:
 .changeset/fn-6126-workflow-flags-default-on.md                |  5 +++++
 CONCEPTS.md                                                    |  4 ++--
 demo/seed.ts                                                   |  1 -
 docs/workflow-steps.md                                         | 10 +++++-----
 packages/core/src/__tests__/move-task-characterization.test.ts |  4 +---
 packages/core/src/settings-schema.ts                           |  7 ++++++-
 packages/core/src/types.ts                                     |  4 +++-
 packages/core/src/workflow-columns-settings.ts                 |  4 ++--
 8 files changed, 24 insertions(+), 15 deletions(-)

Fusion-Task-Id: FN-6126

Fusion-Task-Lineage: 334283a6-e80a-42d0-bf66-68f88a12e287
This commit is contained in:
gsxdsm
2026-06-09 14:10:01 -07:00
parent 19f8d86152
commit 0b7549a534
8 changed files with 24 additions and 15 deletions

View File

@@ -0,0 +1,5 @@
---
"@runfusion/fusion": minor
---
Enable workflow columns, graph executor, dual-observe, and authoritative interpreter experimental flags by default.

View File

@@ -197,7 +197,7 @@ A plugin-contributed workflow capability registered through the engine rather th
## Workflow columns & traits
*Behind the `experimentalFeatures.workflowColumns` flag. With the flag off, the legacy fixed pipeline (the closed column enum + `VALID_TRANSITIONS`) is authoritative and unchanged.*
*Controlled by the default-on `experimentalFeatures.workflowColumns` flag. With an explicit flag-off override, the legacy fixed pipeline (the closed column enum + `VALID_TRANSITIONS`) is authoritative and unchanged.*
### Column (workflow-defined)
A first-class, workflow-defined unit of task state: an id, a display name, and a set of Trait configurations. A Task's board position is its current column, persisted in `tasks."column"`. Column validity is workflow-scoped — the legacy closed enum widens to a string validated against the Task's resolved workflow. The Default workflow's column ids are byte-identical to the legacy enum values, so no task row is ever rewritten.
@@ -230,7 +230,7 @@ A persisted crash-safe marker (`tasks.transitionPending`) written in the same tr
## Step inversion
*Behind the `experimentalFeatures.workflowGraphExecutor` flag (orthogonal to `workflowColumns`). With the flag off, and for the Default workflow always, step policy is the legacy engine-owned path (PROMPT.md parsing, in-session review verdicts, RETHINK reset) — unchanged.*
*Controlled by the default-on `experimentalFeatures.workflowGraphExecutor` flag (orthogonal to `workflowColumns`). With an explicit flag-off override, and for the Default workflow always, step policy is the legacy engine-owned path (PROMPT.md parsing, in-session review verdicts, RETHINK reset) — unchanged.*
### Step instance
One runtime expansion of a `foreach` template subgraph, bound to a single planned step (`Task.steps[i]`). Identity is deterministic — `<foreachNodeId>#<stepIndex>:<templateNodeId>` — so resume reconstructs the full instance set from the pinned step count without persisting the expansion itself. Each instance carries its own run-state (current node, rework count, baseline/checkpoint, and in worktree mode its branch and integration status) in its own persisted run-state table. The step count is pinned at expansion; a later disagreement with the live step list is a `pin-mismatch` failure, never a silent re-expansion. An instance's lifecycle writes flow through `store.updateStep` so `Task.steps[]` stays the physical projection sink for every existing consumer.

View File

@@ -47,7 +47,6 @@ async function main() {
const store = new TaskStore(root);
await store.init();
await store.updateSettings({ maxConcurrent: 10 } as any);
await store.updateGlobalSettings({ experimentalFeatures: { workflowColumns: true } });
const browserDemoWorkflow = await store.createWorkflowDefinition({
name: "Browser Demo Lifecycle",
description: "Simple board lifecycle for browser demos: Todo → In Progress → In Review → QA → Publish.",

View File

@@ -422,12 +422,12 @@ Tasks are not parked in `in-review` for this remediable path unless additional t
## Workflow Interpreter Dual-Observe (parity instrumentation)
Fusion now includes a **default-OFF** experimental parity seam for the workflow interpreter rollout.
Fusion now enables the workflow interpreter parity seam by default as part of the workflow rollout.
- **Flag:** `experimentalFeatures.workflowInterpreterDualObserve`
- **Mode:** observe-only shadow run; legacy executor/reviewer/merger/scheduler path remains authoritative
- **Behavior when OFF (default):** strict no-op (no shadow run, no parity audit records)
- **Behavior when ON:** compare legacy and interpreter observations plus comparable run-audit slices
- **Flag:** `experimentalFeatures.workflowInterpreterDualObserve` (default ON)
- **Mode:** observe-only shadow run; legacy executor/reviewer/merger/scheduler path remains authoritative unless the authoritative cutover guard passes
- **Behavior when OFF:** strict no-op (no shadow run, no parity audit records)
- **Behavior when ON (default):** compare legacy and interpreter observations plus comparable run-audit slices
Run-audit events emitted in `database` domain:

View File

@@ -39,9 +39,7 @@ for (const flag of flagStates) {
beforeEach(async () => {
await harness.beforeEach();
store = harness.store();
if (flag.workflowColumns) {
await store.updateGlobalSettings({ experimentalFeatures: { workflowColumns: true } });
}
await store.updateGlobalSettings({ experimentalFeatures: { workflowColumns: flag.workflowColumns } });
});
afterEach(async () => {

View File

@@ -225,7 +225,12 @@ export const DEFAULT_GLOBAL_SETTINGS = {
onFailure: "fail",
},
owningNodeHandoffPolicy: "reassign-to-local",
experimentalFeatures: {},
experimentalFeatures: {
workflowColumns: true,
workflowGraphExecutor: true,
workflowInterpreterDualObserve: true,
workflowInterpreterAuthoritative: true,
},
cliAgents: {},
} satisfies CompleteSettings<GlobalSettings>;

View File

@@ -3077,7 +3077,9 @@ export interface GlobalSettings {
* "another-experiment": false
* }
*
* Default: {} (empty object — no experimental features enabled). */
* Default: workflow columns, graph executor, dual-observe, and authoritative
* interpreter flags enabled; operators may explicitly set individual flags
* false while rollout controls remain available. */
experimentalFeatures?: Record<string, boolean>;
/** Per-adapter CLI-agent launch configuration (CLI Agent Executor, U15).
* Keyed by adapter id (e.g. `"claude-code"`, `"codex"`, `"generic"`). Each

View File

@@ -4,8 +4,8 @@ import type { Settings } from "./types.js";
/**
* The `experimentalFeatures.workflowColumns` flag (KTD-8). OFF: the legacy
* enum/`VALID_TRANSITIONS` path runs untouched. ON: `moveTaskInternal` resolves
* each task's workflow column graph + trait guards. Default OFF until the
* transition-parity suite and field observations prove zero drift (U12).
* each task's workflow column graph + trait guards. The workflow-resolved path
* is now default-on while the explicit OFF override remains available.
*
* Mirrors `isSandboxExperimentalEnabled` / `isEvalsViewEnabled` — a thin,
* named accessor over the shared experimental-features map so the literal flag