From 0b7549a5342996824759dfe648cb60b7abaf01bd Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Tue, 9 Jun 2026 14:10:01 -0700 Subject: [PATCH] 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 --- .changeset/fn-6126-workflow-flags-default-on.md | 5 +++++ CONCEPTS.md | 4 ++-- demo/seed.ts | 1 - docs/workflow-steps.md | 10 +++++----- .../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(-) create mode 100644 .changeset/fn-6126-workflow-flags-default-on.md diff --git a/.changeset/fn-6126-workflow-flags-default-on.md b/.changeset/fn-6126-workflow-flags-default-on.md new file mode 100644 index 0000000000..20e85969f1 --- /dev/null +++ b/.changeset/fn-6126-workflow-flags-default-on.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": minor +--- + +Enable workflow columns, graph executor, dual-observe, and authoritative interpreter experimental flags by default. diff --git a/CONCEPTS.md b/CONCEPTS.md index 57e397486b..ff41d90561 100644 --- a/CONCEPTS.md +++ b/CONCEPTS.md @@ -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 — `#:` — 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. diff --git a/demo/seed.ts b/demo/seed.ts index 0513a37d91..b33ffd35e6 100644 --- a/demo/seed.ts +++ b/demo/seed.ts @@ -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.", diff --git a/docs/workflow-steps.md b/docs/workflow-steps.md index 4174de1772..b266d6ab9e 100644 --- a/docs/workflow-steps.md +++ b/docs/workflow-steps.md @@ -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: diff --git a/packages/core/src/__tests__/move-task-characterization.test.ts b/packages/core/src/__tests__/move-task-characterization.test.ts index 66c4f4901a..2507c4a755 100644 --- a/packages/core/src/__tests__/move-task-characterization.test.ts +++ b/packages/core/src/__tests__/move-task-characterization.test.ts @@ -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 () => { diff --git a/packages/core/src/settings-schema.ts b/packages/core/src/settings-schema.ts index 200126d39b..d2df190a36 100644 --- a/packages/core/src/settings-schema.ts +++ b/packages/core/src/settings-schema.ts @@ -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; diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 9ee6a8c411..f4e2afd6b1 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -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; /** Per-adapter CLI-agent launch configuration (CLI Agent Executor, U15). * Keyed by adapter id (e.g. `"claude-code"`, `"codex"`, `"generic"`). Each diff --git a/packages/core/src/workflow-columns-settings.ts b/packages/core/src/workflow-columns-settings.ts index e5a946546f..fa675f55d7 100644 --- a/packages/core/src/workflow-columns-settings.ts +++ b/packages/core/src/workflow-columns-settings.ts @@ -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