From f01e5c9651a0ccdb9035e0c014480132cb6283cf Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Mon, 29 Jun 2026 19:46:23 -0700 Subject: [PATCH] FN-7247: document current workflow behavior Refresh workflow documentation to match the latest runtime, dashboard, and agent tool behavior. - Add a current workflow behavior inventory covering built-ins, fail-closed runtime semantics, optional gates, settings, tools, routing, and create forwarding. - Clarify dashboard All workflows aggregation, workflow badges, and workflow-aware task creation behavior. - Expand editor, agent, CLI, and settings docs for governed workflow authoring, values, trait inspection, and selection boundaries. - Add docs drift tests requiring workflow docs index coverage and current behavior markers. Files changed: docs/agents.md | 5 +- docs/cli-reference.md | 11 ++- docs/dashboard-guide.md | 10 ++- docs/settings-reference.md | 5 ++ docs/workflow-editor.md | 15 +++- docs/workflow-steps.md | 48 ++++++++--- .../cli/src/__tests__/docs-readme-index.test.ts | 4 + .../src/__tests__/workflow-docs-current.test.ts | 95 ++++++++++++++++++++++ 8 files changed, 172 insertions(+), 21 deletions(-) Fusion-Task-Id: FN-7247 Fusion-Task-Lineage: 72bf0c89-80a3-440c-b6aa-1aea315279f5 Co-authored-by: Fusion (runfusion.ai) --- docs/agents.md | 5 +- docs/cli-reference.md | 11 ++- docs/dashboard-guide.md | 10 +- docs/settings-reference.md | 5 + docs/workflow-editor.md | 15 ++- docs/workflow-steps.md | 48 +++++++--- .../src/__tests__/docs-readme-index.test.ts | 4 + .../__tests__/workflow-docs-current.test.ts | 95 +++++++++++++++++++ 8 files changed, 172 insertions(+), 21 deletions(-) create mode 100644 packages/cli/src/__tests__/workflow-docs-current.test.ts diff --git a/docs/agents.md b/docs/agents.md index fa1e89cbb8..ab70b2791f 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -7,6 +7,9 @@ Fusion uses multiple agent roles for planning, execution, review, and merge work ## CLI session actions @@ -34,7 +37,7 @@ fn chat [message…] [--once] [--non-interactive] [--poll-ms ] - Dashboard chat and planning sessions with a scoped task store expose `fn_task_document_write` and `fn_task_document_read`; because neither lane has an ambient task, both tools require an explicit `task_id`. - Agent workflow-routing tools follow an intent boundary: agents may select or change a task workflow only when the user explicitly requested that workflow or when the agent created the task. Executors must not call `fn_workflow_select` to reroute the task they are executing unless the task instructions or a user steering comment explicitly asks for the workflow change. Lanes without an ambient task, including dashboard chat/planning and published/pi extension calls outside a task, must pass an explicit `task_id`; task-bound executor paths may default to the current task. - Executor, heartbeat, and dashboard chat sessions expose artifact registry tools so agents can publish and inspect multi-type deliverables without relying on the dashboard gallery. Planning sessions intentionally exclude artifact tools until they can thread the existing `MessageStore` dependency. -- Permanent/custom heartbeat agents and the published/pi extension receive the broad coordination and work-discovery tool surface instead of a narrowly curated subset: read-only task discovery (`fn_task_list`, `fn_task_show`, `fn_task_search`) for work discovery and duplicate avoidance, workflow discovery and authoring (`fn_workflow_list`, `fn_workflow_get`, `fn_workflow_create`, `fn_workflow_update`, `fn_workflow_delete`, `fn_workflow_settings`, `fn_trait_list`), governed research (`fn_research_run`, `fn_research_list`, `fn_research_get`, `fn_research_cancel`), structured clarification (`fn_ask_question`), artifact, memory, messaging, goal, evaluation, identity, and delegation tools. Task-scoped heartbeat sessions also expose current-task workflow selection and promotion (`fn_workflow_select`, `fn_task_promote`); no-task heartbeats omit those because they have no ambient task, while no-task extension/chat/planning lanes expose `fn_workflow_select` but require explicit `task_id`. Prompt-injectable lanes strip workflow approval-bypass flags during `fn_workflow_create`/`fn_workflow_update`; executor-owner paths are the only authoring path that may preserve those flags. Executor-only worktree/workspace tools such as `fn_run_verification` and `fn_acquire_repo_worktree` remain out of the ambient heartbeat lane until that lane owns the required worktree/workspace context. The task read tools are store-backed, text-only, and action-gate-recognized as read-only; dangerous actions are controlled at invocation time by each agent's `AgentPermissionPolicy` through the action gate (allow / require approval / block), not by withholding governed tools from the session. +- Permanent/custom heartbeat agents and the published/pi extension receive the broad coordination and work-discovery tool surface instead of a narrowly curated subset: read-only task discovery (`fn_task_list`, `fn_task_show`, `fn_task_search`) for work discovery and duplicate avoidance, workflow discovery and authoring (`fn_workflow_list`, `fn_workflow_get`, `fn_workflow_create`, `fn_workflow_update`, `fn_workflow_delete`, `fn_workflow_settings`, `fn_trait_list`), governed research (`fn_research_run`, `fn_research_list`, `fn_research_get`, `fn_research_cancel`), structured clarification (`fn_ask_question`), artifact, memory, messaging, goal, evaluation, identity, and delegation tools. Task-scoped heartbeat sessions also expose current-task workflow selection and promotion (`fn_workflow_select`, `fn_task_promote`); no-task heartbeats omit those because they have no ambient task, while no-task extension/chat/planning lanes expose `fn_workflow_select` but require explicit `task_id`. Workflow creation, updates, settings writes, deletion, and selection remain permission-gated task/agent mutations even when the tools are exposed in the lane. Prompt-injectable lanes strip workflow approval-bypass flags during `fn_workflow_create`/`fn_workflow_update`; executor-owner paths are the only authoring path that may preserve those flags. Executor-only worktree/workspace tools such as `fn_run_verification` and `fn_acquire_repo_worktree` remain out of the ambient heartbeat lane until that lane owns the required worktree/workspace context. The task read tools are store-backed, text-only, and action-gate-recognized as read-only; dangerous actions are controlled at invocation time by each agent's `AgentPermissionPolicy` through the action gate (allow / require approval / block), not by withholding governed tools from the session. - `agent.taskId` is an active-execution linkage, not durable ownership. It may legitimately point at a `todo`/`triage` task only while the agent has live run or executor-active proof; task-move sync and self-healing clear stale parked, terminal, or unresolved links otherwise. `fn_list_agents` and `fn_agent_show` therefore include column context in the human-readable `Current Task` line, such as `(triage)`, `(in-progress)`, `(not active — done)`, or `(unresolved)`, so coordinators can distinguish transient planning ownership from drift. ### Artifact registry tools diff --git a/docs/cli-reference.md b/docs/cli-reference.md index fda8eb7e0e..3c48ce49fb 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -7,6 +7,9 @@ Fusion’s command-line interface is exposed through the `fn` command. ## Published agent extension workflow tools @@ -14,12 +17,14 @@ The published CLI/pi extension must document its agent-facing workflow authoring The published `@runfusion/fusion` CLI bundle also exposes the pi extension tool surface used by external agents. Alongside task and coordination helpers, agents can now author and manage workflow definitions: - `fn_workflow_list` / `fn_workflow_get` — discover built-in and custom workflows and inspect a workflow's IR before editing. -- `fn_workflow_create` / `fn_workflow_update` — create or revise custom workflow definitions through Fusion's central workflow validator. -- `fn_workflow_settings` — read and write typed per-project values for a workflow's declared settings. +- `fn_workflow_create` / `fn_workflow_update` — create or revise custom workflow definitions through Fusion's central workflow validator. Built-in definitions are read-only, and broader-than-default column permission bindings require explicit policy-escalation confirmation. +- `fn_workflow_settings` — read and write typed per-project values for a workflow's declared settings. `get` returns stored and engine-effective values; `set` validates atomically and treats `null` as deleting a stored override. - `fn_workflow_delete` — delete custom workflows; built-in workflows remain protected. - `fn_trait_list` — list the column trait vocabulary used when authoring workflow columns. +- `fn_workflow_select` — assign a workflow to the current task in task-bound lanes or to an explicit `task_id` when the lane has no ambient task. Published/pi extension calls, dashboard chat/planning, and no-task heartbeat lanes must pass `task_id`; executor paths may omit it only for the task currently under execution. +- `workflow_id` on task creation/delegation tools — create or delegate a task onto a real workflow id from the start. -Agents should still use `fn_workflow_select` only when assigning a workflow to an explicit task context or to a task they created. +Agents should still use `fn_workflow_select` only when the user explicitly requested that workflow or when assigning a workflow to a task they created; they must not reroute arbitrary existing tasks just because another workflow appears more suitable. Prompt-injectable lanes strip workflow approval-bypass flags during `fn_workflow_create` / `fn_workflow_update`; executor-owner paths are the only authoring path that may preserve those flags. ## Global Usage diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 59e76c6f5b..0f6fc2c1dd 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -132,7 +132,9 @@ Features: - The quick-entry GitHub icon is a per-task tracking override: leave it untouched to use the project default, turn it on to opt the next task into tracking when the default is off, or turn it off to opt the next task out when the default is on. - PR/issue badges with live updates - GitHub provenance marker on task cards imported from GitHub (`sourceType: github_import`), shown in the footer with other external-source metadata -- Task card header meta badges group priority, fast mode, agent-created provenance, and elapsed/created-time chips into one wrapping row; agent labels prefer `sourceMetadata.agentName` over raw agent IDs +- Task card header meta badges group priority, fast mode, agent-created provenance, workflow name, and elapsed/created-time chips into one wrapping row; agent labels prefer `sourceMetadata.agentName` over raw agent IDs +- Task detail surfaces show the selected/effective workflow name near the task's workflow controls so individual cards remain understandable when Board is in **All workflows** or another aggregate/mixed context. + - Column ordering semantics: `todo` mirrors scheduler pickup order (priority descending, then oldest `createdAt`, then task ID); `triage`, `in-progress`, `in-review`, and `archived` remain priority-first with task-ID tie-breaks; `done` defaults to most recent completion first (`columnMovedAt`, then `updatedAt`, then `createdAt` fallback) and can be switched from the Done column header to descending task ID. In workflow mode, non-archived columns marked with the `complete` flag use the same Done ordering even when their column ID or label is customized. @@ -142,7 +144,7 @@ Features: -- Board and List workflow switchers use a themed dropdown instead of a native select. The closed trigger shows the workflow name and chevron only; compact Todo / In Progress / Done counts derived from workflow column flags (excluding archived and board-hidden columns) refresh each time the dropdown opens and appear while the dropdown is expanded, including on each workflow option. Built-in lanes with synthesized trait-less lifecycle columns fall back to canonical column ids (`todo`, `in-progress`, `done`, and `archived`) for those counts. Board also shows **All workflows** before real workflows as a dashboard-only aggregate view with combined counts and a deterministic union of visible workflow columns; shared column ids use the default workflow label/flags when available, otherwise the first workflow definition that declares the column. That option is not editable and is not saved as the durable selected workflow, and its quick-create affordance appears only on the chosen real workflow intake/default column so task creation still sends a real workflow id and column. Each real workflow option row also exposes an inline edit action, and a persistent **New workflow** footer stays visible below the scrollable option list. The open listbox grows from the longest workflow name plus its count/edit decorations while remaining viewport-bounded; the closed trigger stays narrow and ellipsized. Those inline count badges intentionally use the same board column color tokens as cards: `--todo`, `--in-progress`, and `--done`. +- Board and List workflow switchers use a themed dropdown instead of a native select. The closed trigger shows the workflow name and chevron only; compact Todo / In Progress / Done counts derived from workflow column flags (excluding archived and board-hidden columns) refresh each time the dropdown opens and appear while the dropdown is expanded, including on each workflow option. Built-in lanes with synthesized trait-less lifecycle columns fall back to canonical column ids (`todo`, `in-progress`, `done`, and `archived`) for those counts. Board also shows **All workflows** before real workflows as a dashboard-only aggregate view with combined counts and a deterministic union of visible workflow columns; shared column ids use the default workflow label/flags when available, otherwise the first workflow definition that declares the column. Hidden columns stay workflow-scoped in the aggregate: a task whose effective workflow hides a shared column is omitted from that aggregate column even if another workflow exposes the same column id. That option is not editable and is not saved as the durable selected workflow, and its quick-create affordance appears only on the chosen real workflow intake/default column so task creation still sends a real workflow id and column. Each real workflow option row also exposes an inline edit action, and a persistent **New workflow** footer stays visible below the scrollable option list. The open listbox grows from the longest workflow name plus its count/edit decorations while remaining viewport-bounded; the closed trigger stays narrow and ellipsized. Those inline count badges intentionally use the same board column color tokens as cards: `--todo`, `--in-progress`, and `--done`. - When workflow columns are enabled, Board and List hydrate the last successful workflow-lane payload from a per-project session cache; cold loads show a neutral skeleton until settings and workflow metadata are known, avoiding a legacy single-lane flash. The selected workflow is remembered per project in durable browser storage and restored when returning to Board/List after task refreshes, route changes, or respecification flows; if that saved workflow is later deleted, Fusion falls back to a valid default/first workflow so tasks remain visible. ![Board view](./screenshots/dashboard-overview.png) @@ -323,7 +325,9 @@ Planning is a desktop/tablet left-sidebar main-content destination after **Comma These values are sent with the Planning Mode create-task request as `branchSelection`, so created tasks persist branch/base-branch settings consistently with other branch-aware task creation flows. -When inline quick-create, Planning Mode, or Subtask Breakdown is opened from a workflow-filtered board/list lane, the create request also carries that active workflow selection. Quick-created tasks appear on the selected workflow lane immediately while board-workflows metadata refreshes, and planning saves, planning breakdown saves, and subtask-breakdown saves create their tasks directly on the selected workflow lane instead of briefly landing on the default board. + + +When inline quick-create, Planning Mode, or Subtask Breakdown is opened from a workflow-filtered board/list lane, the create request also carries that active workflow selection. Quick-created tasks appear on the selected workflow lane immediately while board-workflows metadata refreshes, and planning saves, planning breakdown saves, and subtask-breakdown saves create their tasks directly on the selected workflow lane instead of briefly landing on the default board. When Board is showing **All workflows**, quick-create uses the real workflow intake/default column that owns the affordance; it never submits the synthetic aggregate as a workflow id. The **New Task** dialog's workflow selector also defaults to the current or last selected Board/List workflow lane for the current project. If no valid lane has been selected, or the remembered lane was deleted, the selector falls back to the project default workflow and task creation omits an explicit `workflowId`. diff --git a/docs/settings-reference.md b/docs/settings-reference.md index a47d9ec903..92627cf577 100644 --- a/docs/settings-reference.md +++ b/docs/settings-reference.md @@ -227,6 +227,11 @@ When the dashboard footer reports that a newer `@runfusion/fusion` version is av ## Workflow Settings + + Some knobs that used to live in this Settings reference as project settings are now **workflow settings**: they are declared by a workflow and their values are stored **per `(workflow, project)`**, not as ambient project settings. A workflow models diff --git a/docs/workflow-editor.md b/docs/workflow-editor.md index 2f2e0f0b53..1734acac4a 100644 --- a/docs/workflow-editor.md +++ b/docs/workflow-editor.md @@ -5,6 +5,9 @@ The workflow editor is Fusion's visual workflow authoring surface in the dashboard. It uses the `@xyflow/react` canvas to view built-in lifecycle workflows and create or edit custom workflow definitions backed by Fusion's [Workflow IR](./workflow-steps.md#workflow-ir-v1). The graph you see is the same policy model the runtime uses for task lifecycle routing: nodes describe work or control-flow boundaries, edges describe how execution moves between them, and side panels declare workflow-specific columns, task fields, and typed workflow settings. @@ -25,7 +28,7 @@ These entry points do not create different workflow formats. Desktop and mobile ## Canvas anatomy -The editor is a modal with a workflow picker, toolbar actions, a React Flow graph, and inspectors: +The editor is a modal with a workflow picker, toolbar actions, a React Flow graph, and inspectors. Built-in workflows use the same viewer and Values surfaces as custom workflows, but their topology stays read-only except for project-scoped prompt overrides on prompt/gate nodes: - **Workflow list / picker:** choose a built-in or custom workflow. Built-ins are labeled and remain read-only; custom workflows are editable. - **Graph canvas:** the central React Flow surface where nodes and edges are displayed. Drag nodes to rearrange them, connect handles to create edges, and select a node or edge to inspect it. @@ -35,6 +38,7 @@ The editor is a modal with a workflow picker, toolbar actions, a React Flow grap - **Templates section:** insert reusable graph fragments, built-in workflow-step templates, and plugin-contributed workflow-step templates when available. - **Inspectors and side panels:** selecting a node opens its configuration inspector; selecting an edge opens the edge inspector. Separate panels manage Columns, Fields, and Settings. - **Validation and status banners:** save-time validation errors, import warnings, branch/interpreter notices, and read-only built-in hints appear inline instead of relying only on toasts. +- **Prompt override controls:** when a built-in prompt or gate node is selected, the inspector allows only prompt text overrides and reset-to-default; node kind, edges, columns, traits, field declarations, and setting declarations remain locked. ## Node palette @@ -167,7 +171,7 @@ Fusion ships built-in workflows as read-only references: - `builtin:coding` — the default Stepwise-based coding lifecycle: plan steps, execute them one at a time, then run the optional final Code Review gate and merge. - `builtin:legacy-coding` — the original monolithic coding lifecycle for tasks that should not use graph-owned step execution. -- `builtin:quick-fix` — a short path for trivial or no-commit/decision work. +- `builtin:quick-fix` — a short explicitly selected path for trivial or decision work; no-commit markers do not select it automatically. - `builtin:review-heavy` — a standard execute/review/merge path with an additional gated security review. - `builtin:marketing` — a marketing content pipeline with brief, draft, editorial review, and publish stages. - `builtin:compound-engineering` — a plugin-gated Compound Engineering pipeline: `/ce-plan` writes the CE plan doc, optional `ce-doc-review` can pressure-test plans (markdown gets autofix/Open Questions write-back; HTML uses DOM-safe helper mutations, including canonical checklist repair, only when safety is proven and otherwise report-only with no write), `/ce-work` implements, `/ce-code-review` gates merge, and autoMerge-off projects route through the CE PR/feedback skills before Fusion's manual merge seam. @@ -177,7 +181,12 @@ Fusion ships built-in workflows as read-only references: Built-ins can be viewed, exported, and used as templates, but their graph, columns, field declarations, and setting declarations are not editable. Their per-project setting **values** are editable from the Settings panel's Values tab. Selectable built-ins all use a capacity-released queue column (`todo` or a workflow-specific backlog) that dispatches to the active WIP column through the standard hold/release sweep. -To customize behavior, create a workflow from **Blank** or copy a built-in/custom workflow with **Duplicate to customize**. Tasks select a workflow by workflow id. Agents and automation can discover workflows with `fn_workflow_list`, assign one to an existing task with `fn_workflow_select`, or pass `workflow_id` when creating tasks through `fn_task_create` / delegation tools. + + +To customize behavior, create a workflow from **Blank** or copy a built-in/custom workflow with **Duplicate to customize**. Tasks select a workflow by workflow id. Agents and automation have parity with the editor's governed save paths: they can inspect definitions with `fn_workflow_list` / `fn_workflow_get`, inspect column traits with `fn_trait_list`, author custom definitions with `fn_workflow_create` / `fn_workflow_update` / `fn_workflow_delete`, tune per-project values with `fn_workflow_settings`, assign one to an existing task with `fn_workflow_select`, or pass `workflow_id` when creating tasks through `fn_task_create` / delegation tools. Tool writes run the same validation as dashboard saves/imports, including malformed-IR rejection and policy-escalation confirmation for broader column-agent bindings. The routing boundary still applies: agents select workflows only for explicit user requests or tasks they created. ## Mobile editor diff --git a/docs/workflow-steps.md b/docs/workflow-steps.md index d8f92e0b24..f213656ea8 100644 --- a/docs/workflow-steps.md +++ b/docs/workflow-steps.md @@ -26,7 +26,7 @@ FNXC:WorkflowRuntime 2026-06-28-08:10: Selectable built-in workflows must share the canonical dispatch traits: their held work enters through a capacity-released `todo`/backlog column and moves to the first WIP execution column via the hold/release sweep, so non-default built-ins do not need a separate dispatcher. --> -Fusion workflows define the task lifecycle policy that moves work from an idea to delivery. The default coding path is **Plan/Triage → Execute → Workflow steps → Review → Merge**, but that path is now represented as a workflow selection rather than only as fixed engine behavior. A task with no explicit workflow resolves to `builtin:coding`; an explicit missing/corrupt custom workflow fails closed instead of silently falling back. +Fusion workflows define the task lifecycle policy that moves work from an idea to delivery. The default coding path is **Plan/Triage → Execute → graph-native optional gates → Review → Merge**, but that path is now represented as a workflow selection rather than only as fixed engine behavior. A task with no explicit workflow resolves to `builtin:coding`; an explicit missing/corrupt custom workflow fails closed instead of silently falling back. ### Selecting workflows @@ -49,7 +49,7 @@ Decision-only or investigation tasks can also declare `noCommitsExpected` / `**N |---|---|---| | Coding | `builtin:coding` | Default Stepwise-based coding lifecycle: plan steps, execute them one at a time, then run the optional final Code Review gate and merge. | | Legacy coding | `builtin:legacy-coding` | Original monolithic coding lifecycle for tasks that should not use graph-owned step execution. | -| Quick fix | `builtin:quick-fix` | Short path for trivial or no-commit/decision work; omits the standard review stage. | +| Quick fix | `builtin:quick-fix` | Short explicitly selected path for trivial or decision work; omits the standard review stage. No-commit markers do not route tasks here automatically. | | Review-heavy | `builtin:review-heavy` | Standard execute/review/merge path with an additional gated security review. | | Marketing | `builtin:marketing` | Content pipeline with custom Ideation, Backlog, Drafting, Editorial review, Published, and Archived columns plus structured marketing brief/draft/editorial prompts; drafts are persisted as task documents for review while the workflow reuses standard lifecycle traits and merge primitives. | | Compound engineering | `builtin:compound-engineering` | Plugin-gated CE workflow that invokes `/ce-plan`, optional advisory `ce-doc-review` (markdown autofix; HTML DOM-safe mutation with report-only fallback), `/ce-work`, merge-blocking `/ce-code-review`, CE PR/feedback skills, Fusion merge, and learnings capture. | @@ -60,6 +60,29 @@ Decision-only or investigation tasks can also declare `noCommitsExpected` / `**N Every selectable built-in workflow uses a capacity-released hold column (`todo` or a workflow-specific backlog) for queued work and a WIP execution column for active work, so the hold/release sweep performs the normal `todo`/backlog → in-progress dispatch across the catalog. +### Current workflow behavior inventory + + + +Use this inventory as the documentation map for current workflow behavior: + +| Topic | Current behavior | Canonical home | +|---|---|---| +| Built-in catalog and ids | The selectable built-ins are `builtin:coding`, `builtin:legacy-coding`, `builtin:quick-fix`, `builtin:review-heavy`, `builtin:marketing`, `builtin:compound-engineering`, `builtin:stepwise-coding`, `builtin:design`, and `builtin:lead-generation`; `builtin:pr-workflow` is a reusable fragment, not a task-selectable workflow. | This page, [Built-in workflow catalog](#built-in-workflow-catalog); authoring summary in [Workflow Editor](./workflow-editor.md#built-in-vs-custom-workflows). | +| Runtime and fail-closed behavior | The graph runtime owns lifecycle routing. Unselected/default tasks resolve to `builtin:coding`; missing explicit custom selections fail closed as workflow-resolution failures, and corrupt or invalid resolved IR fails closed as `invalid-ir` instead of returning a legacy fallback. | This page, [Workflow graph integrity validation](#workflow-graph-integrity-validation) and [Workflow Graph Executor](#workflow-graph-executor). | +| Workflow IR validation | Save/import/AI design/tool writes and runtime materialization all use the central IR validator for node/edge integrity, column/field/setting uniqueness, optional-group references, and plugin extension keys. | This page, [Workflow graph integrity validation](#workflow-graph-integrity-validation); visual authoring in [Workflow Editor](./workflow-editor.md). | +| Optional groups and default-on gates | Quality gates are graph `optional-group` nodes keyed by node id in `enabledWorkflowSteps`; the runtime/display effective set is persisted ids plus `defaultOn` groups, so default-on gates still run and appear for in-progress tasks when a persisted selection array is empty. Edit-mode controls continue to show the persisted selection so operators can see exactly what the task stored. There is no workflow-step table, Settings manager, or CRUD form. | This page, [Workflow-declared optional steps](#workflow-declared-optional-steps-optional-group-nodes), [Default-On Behavior for New Tasks](#default-on-behavior-for-new-tasks), and [Authoring a Custom Quality Gate](#authoring-a-custom-quality-gate). | +| Explicit empty step dependencies | A heading annotation `(depends:)` or JSON step `"depends": []` means the step has no prerequisites; an absent dependency annotation/key still inherits the legacy previous-step dependency. | This page, [Parallel mode & the `(depends:)` annotation](#parallel-mode--the-depends-annotation). | +| Workflow settings values | Setting declarations live in workflow IR; values persist per `(workflowId, projectId)` and resolve as `stored value ?? declaration default`, with invalid/orphaned values dropped from effective settings. | [Settings Reference → Workflow Settings](./settings-reference.md#workflow-settings); editor UX in [Workflow Editor](./workflow-editor.md#settings-panel-definitions-and-values). | +| Built-in prompt overrides | Built-in topology stays read-only, but prompt/gate node text can be overridden per `(workflowId, nodeId, projectId)` and reset to shipped defaults. | This page, [Overriding built-in workflow prompts](#overriding-built-in-workflow-prompts); dashboard UX in [Dashboard Guide](./dashboard-guide.md#workflow-selection-and-editor). | +| Agent workflow tools | Agents can list/get/create/update/delete workflows, inspect traits, read/write workflow settings, select workflows for explicit task contexts, and pass `workflow_id` when creating/delegating tasks. Prompt-injectable lanes strip approval-bypass flags on workflow writes. | [Agents](./agents.md#interactive-cli-chat) and [CLI Reference](./cli-reference.md#published-agent-extension-workflow-tools). | +| Routing boundary | Agents may select/change a workflow only for explicit user requests or tasks they created; no-commit markers do not imply Quick fix or any other workflow. | This page, [Selecting workflows](#selecting-workflows); [Agents](./agents.md#interactive-cli-chat). | +| Dashboard board/list/graph selection | Board/List/Header/Graph share durable per-project workflow selection; stale saved ids fall back to a valid workflow. Board adds a dashboard-only **All workflows** aggregate and task workflow-name badges; Graph uses **All workflows** for the full active graph. | [Dashboard Guide → Board View](./dashboard-guide.md#board-view), [Graph View](./dashboard-guide.md#graph-view), and [Workflow Selection and Editor](./dashboard-guide.md#workflow-selection-and-editor). | +| Create/planning forwarding | Inline quick-create, Planning Mode, Subtask Breakdown, and the New Task dialog forward the active real workflow id when creating tasks; **All workflows** quick-create chooses a real workflow intake/default column instead of saving a synthetic aggregate id. | [Dashboard Guide → Planning Mode](./dashboard-guide.md#planning-mode). | + ### Skill-backed workflow steps Optional quality gates are authored directly in the workflow graph as `optional-group` **nodes**. An `optional-group` node is a container (mirroring `foreach`/`loop`) whose `template` subgraph the executor runs **once** when the group is enabled for the task, and passes through (skips) when disabled. There is no iteration and no rework budget — a single pass — and rework edges inside the template are rejected by `validateOptionalGroup`. Node config (`WorkflowOptionalGroupConfig`): `{ name?, defaultOn?, maxRevisions?: number | "unbounded", phase?: "pre-merge" | "post-merge", template: { nodes, edges } }`. -- `defaultOn` seeds the per-task enable set at task creation; operators can still toggle it. +- `defaultOn` contributes to the runtime/display effective enable set for the task; operators can still toggle persisted selections when creating or editing tasks. - `maxRevisions` optionally overrides the workflow/project `maxPostReviewFixes` budget for this one optional group's pre-merge fix → re-review loop. Use a non-negative integer for a bounded number of automatic fix passes, `0` to disable automatic fixes for that step, or `"unbounded"` to keep cycling until the step returns `APPROVE` / `APPROVE_WITH_NOTES`. When omitted, the step keeps the global `maxPostReviewFixes` behavior. - `phase` defaults to `"pre-merge"` (the prior, only behavior). `"post-merge"` marks a group the executor runs after a successful merge (see [Execution Phases](#execution-phases)). -- Enable state lives on the per-task `enabledWorkflowSteps` array, keyed by the **group node id** (for example `browser-verification`, `code-review`). The graph executor runs an optional-group node only when its id is present in `enabledWorkflowSteps`. +- Persisted enable state lives on the per-task `enabledWorkflowSteps` array, keyed by the **group node id** (for example `browser-verification`, `code-review`). For execution and in-progress display, Fusion treats a group as enabled when its id is present in `enabledWorkflowSteps` **or** the workflow node has `defaultOn: true`; this preserves default-on gates even for tasks whose persisted array is empty. Edit-mode controls remain based on the persisted array so an operator can distinguish stored selections from workflow defaults. Built-in optional gates ship as inlined IR builders, not as a template catalog: - `builtin:coding` carries the `browser-verification` optional-group node (`builtin-browser-verification-group.ts`), default-off, so browser verification runs only for tasks whose `enabledWorkflowSteps` includes `browser-verification`. -- `builtin:coding` and `builtin:stepwise-coding` carry the `plan-review` optional-group node (`builtin-plan-review-group.ts`), default-on, before `parse-steps` so the plan can be reviewed before execution begins. -- The `code-review` optional-group node (`builtin-code-review-group.ts`) is the inlined code-review gate. On default `builtin:coding`, this is the only final review surface before merge; disabling it lets the graph continue from implementation/verification to the merge gate. On `builtin:stepwise-coding`, it remains a post-foreach optional final review gate before the workflow's final review seam. +- `builtin:coding` and `builtin:stepwise-coding` carry the `plan-review` optional-group node (`builtin-plan-review-group.ts`), default-on, before `parse-steps` so the plan can be reviewed before execution begins even when a task has not persisted explicit optional-step ids. +- The `code-review` optional-group node (`builtin-code-review-group.ts`) is the inlined default-on code-review gate. On default `builtin:coding`, this is the only final review surface before merge; it is effective by default even when no explicit optional-step ids are stored. On `builtin:stepwise-coding`, it remains a post-foreach optional final review gate before the workflow's final review seam. - A workflow (for example compound-engineering) can add a **post-merge** optional-group node via the generic `postMergeOptionalGroupNode(...)` builder (`builtin-post-merge-group.ts`) — e.g. a `document` step that runs after merge. Create-time optional-step controls appear in the quick-add action row and the **New Task** dialog inline quick buttons for the active workflow. They resolve the workflow's optional-group nodes (plus plugin-contributed palette templates, see [Plugin-Contributed Steps](#plugin-contributed-steps)) into toggleable rows. Workflows with no optional groups render no trigger, and the selected node ids are submitted through `enabledWorkflowSteps` when the task is created. Unknown or removed ids are skipped during resolution so stale selections never render blank controls or break workflow loading. @@ -462,7 +488,7 @@ There is no longer a Settings → Workflow Steps manager or step CRUD form. To a - Set the node's `name`, `defaultOn`, and `phase` (`pre-merge` / `post-merge`). - Author the gate inside the node's `template` subgraph as `prompt`/`script`/`gate` nodes (single pass, no rework edges). -- Tasks enable the gate by its node id via `enabledWorkflowSteps` (seeded from `defaultOn` and toggled at task creation). +- Tasks persist operator-selected gate ids via `enabledWorkflowSteps`; runtime/display also includes gates whose nodes declare `defaultOn: true`, while edit controls show only the persisted selection. Plugin palette templates (above) can be dropped in as a starting point instead of authoring a node from scratch. @@ -479,7 +505,7 @@ If both are set, node execution uses that model; otherwise it falls back to defa `optional-group` nodes support `defaultOn`. -When `defaultOn: true`, the gate is preselected automatically for newly created tasks (users can still deselect it). +When `defaultOn: true`, the gate is effectively enabled for execution and in-progress display even if the task's persisted `enabledWorkflowSteps` array is empty. Creation and edit controls still use the persisted selection as their source of truth, so operators can distinguish an explicit stored toggle from a workflow-authored default. ## Workflow Step Revision Loop @@ -727,7 +753,7 @@ Workflow graph execution is the task lifecycle runtime. `TaskExecutor` pins `wor Default node dispatch: - `prompt` / `script` nodes with `config.seam` dispatch through workflow runtime primitives (`planning`, `execute`, `review`, `merge`, `schedule`, `step-execute`). The legacy `workflow-step` seam/primitive was removed in FN-7039 — quality gates are graph nodes now, and an IR node still declaring `config.seam: "workflow-step"` fails loudly rather than silently skipping. -- `optional-group` nodes run their template subgraph once when enabled for the task (per `enabledWorkflowSteps`) and pass through when disabled; the executor records the outcome onto `task.workflowStepResults` +- `optional-group` nodes run their template subgraph once when enabled for the task (per `enabledWorkflowSteps` plus workflow-authored `defaultOn`) and pass through when disabled; the executor records the outcome onto `task.workflowStepResults` - `step-review`, `parse-steps`, `code`, `notify`, and PR nodes use their dedicated primitive/dependency adapters - `gate` nodes evaluate context-key expectations or run configured executable checks diff --git a/packages/cli/src/__tests__/docs-readme-index.test.ts b/packages/cli/src/__tests__/docs-readme-index.test.ts index df5291c212..9175076a19 100644 --- a/packages/cli/src/__tests__/docs-readme-index.test.ts +++ b/packages/cli/src/__tests__/docs-readme-index.test.ts @@ -7,6 +7,7 @@ const docsReadmePath = resolve(workspaceRoot, "docs", "README.md"); const requiredDocs = [ "docs/dev-server-modules.md", + "docs/workflow-steps.md", "docs/workflow-editor.md", "docs/plugins/external-proof-point-runbook.md", "docs/research/pi-autoresearch-analysis.md", @@ -18,6 +19,9 @@ const requiredDocs = [ FNXC:DocsIndex 2026-06-15-01:35: FN-6479 keeps CLI Printing Press design and research entries indexed only as Audit Reports, not duplicated in Plugins. This test guards the documentation-index dedup invariant while requiredDocs guards committed upstream artifacts that must remain discoverable. + +FNXC:WorkflowDocs 2026-06-30-09:45: +Workflow authors need both the runtime Workflow Steps guide and the visual Workflow Editor guide discoverable from the docs index, so the drift guard treats both as required index entries. */ describe("docs README index", () => { diff --git a/packages/cli/src/__tests__/workflow-docs-current.test.ts b/packages/cli/src/__tests__/workflow-docs-current.test.ts new file mode 100644 index 0000000000..8761d03df8 --- /dev/null +++ b/packages/cli/src/__tests__/workflow-docs-current.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, it } from "vitest"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; + +const workspaceRoot = resolve(import.meta.dirname, "../../../.."); +const doc = (relativePath: string) => readFileSync(resolve(workspaceRoot, relativePath), "utf8"); + +const workflowSteps = () => doc("docs/workflow-steps.md"); +const workflowEditor = () => doc("docs/workflow-editor.md"); +const dashboardGuide = () => doc("docs/dashboard-guide.md"); +const agents = () => doc("docs/agents.md"); +const cliReference = () => doc("docs/cli-reference.md"); + +/* +FNXC:WorkflowDocs 2026-06-30-09:30: +Workflow docs drift easily when implementation tasks add agent tools or board affordances. Keep this guard targeted to the public docs surfaces that define the current workflow behavior inventory. +*/ + +describe("workflow documentation current behavior", () => { + it("documents the current built-in workflow catalog and fail-closed runtime contract", () => { + const content = workflowSteps(); + for (const id of [ + "builtin:coding", + "builtin:legacy-coding", + "builtin:quick-fix", + "builtin:review-heavy", + "builtin:marketing", + "builtin:compound-engineering", + "builtin:stepwise-coding", + "builtin:design", + "builtin:pr-workflow", + "builtin:lead-generation", + ]) { + expect(content).toContain(id); + } + expect(content).toContain("fails closed"); + expect(content).toContain("invalid-ir"); + expect(content).toContain("instead of silently falling back"); + expect(content).toContain("An explicit empty list"); + expect(content).toContain('`json-steps` `"depends": []`'); + expect(content).toContain("An absent annotation/key is different"); + expect(content).toContain("default-on gates still run and appear for in-progress tasks when a persisted selection array is empty"); + expect(content).toContain("edit controls show only the persisted selection"); + }); + + it("keeps workflow tool docs broader than list/select only", () => { + const combined = [workflowSteps(), workflowEditor(), agents(), cliReference()].join("\n"); + for (const tool of [ + "fn_workflow_list", + "fn_workflow_get", + "fn_workflow_create", + "fn_workflow_update", + "fn_workflow_delete", + "fn_workflow_settings", + "fn_trait_list", + "fn_workflow_select", + "workflow_id", + ]) { + expect(combined).toContain(tool); + } + expect(combined).toContain("explicitly requested"); + expect(combined).toContain("tasks they created"); + }); + + it("documents aggregate board selection, workflow badges, and create forwarding", () => { + const content = dashboardGuide(); + expect(content).toContain("All workflows"); + expect(content).toContain("workflow name"); + expect(content).toContain("synthetic aggregate"); + expect(content).toContain("active workflow selection"); + expect(content).toContain("Hidden columns stay workflow-scoped in the aggregate"); + expect(content).toContain("it never submits the synthetic aggregate as a workflow id"); + }); + + it("documents current workflow settings ownership and extension task-id semantics", () => { + const settings = doc("docs/settings-reference.md"); + expect(settings).toContain("Settings → Project Models → Default workflow model lanes"); + expect(settings).toContain("workflow editor Values tab"); + expect(settings).toContain("Built-in prompt overrides"); + expect(settings).toContain("not writable through"); + + const cli = cliReference(); + expect(cli).toContain("must pass `task_id`"); + expect(cli).toContain("treats `null` as deleting a stored override"); + expect(cli).toContain("broader-than-default column permission bindings require explicit policy-escalation confirmation"); + }); + + it("keeps removed workflow-step CRUD surfaces documented only as removed", () => { + const content = workflowSteps(); + expect(content).toContain("There is no longer a Settings → Workflow Steps manager or step CRUD form"); + expect(content).toContain("The legacy workflow-step CRUD routes were removed"); + expect(content).not.toContain("create a workflow step in Settings"); + expect(content).not.toContain("Use `POST /api/workflow-steps`"); + }); +});