FN-7508: add planner oversight workflow setting
Declare a workflow-native planner oversight level with release notes and docs. - Add the plannerOversightLevel enum setting with Off, Observe, Steer, and Autonomous recovery values. - Export the oversight settings catalog and include it in built-in workflow defaults. - Cover consistency, resolver defaults, and catalog membership with core tests. - Document the workflow setting and add the published package changeset. Files changed: .../fn-7508-planner-oversight-level-setting.md | 7 +++++ docs/settings-reference.md | 8 ++++-- docs/workflow-steps.md | 17 +++++++----- .../builtin-workflow-settings-triage.test.ts | 32 ++++++++++++++++++++++ .../src/__tests__/settings-consistency.test.ts | 4 ++- .../__tests__/workflow-settings-resolver.test.ts | 1 + packages/core/src/builtin-workflow-settings.ts | 26 ++++++++++++++++++ packages/core/src/index.ts | 1 + 8 files changed, 86 insertions(+), 10 deletions(-) Fusion-Task-Id: FN-7508 Fusion-Task-Lineage: 1adc7ce6-9e0e-475e-956a-ee36edae0cdc Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/fn-7508-planner-oversight-level-setting.md
Normal file
7
.changeset/fn-7508-planner-oversight-level-setting.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
summary: Add a per-workflow planner oversight level setting (Off, Observe, Steer, Autonomous recovery).
|
||||||
|
category: feature
|
||||||
|
dev: New workflow setting `plannerOversightLevel` declared in BUILTIN_OVERSIGHT_SETTINGS; default `autonomous`. Per-task override and engine behavior land in follow-up tasks.
|
||||||
@@ -280,8 +280,10 @@ Actions. It has two tabs:
|
|||||||
controls. Built-in Plan Review/spec and Code Review revision caps also live here:
|
controls. Built-in Plan Review/spec and Code Review revision caps also live here:
|
||||||
leave `planReviewMaxRevisions` or `codeReviewMaxRevisions` empty for unbounded
|
leave `planReviewMaxRevisions` or `codeReviewMaxRevisions` empty for unbounded
|
||||||
automatic revisions, enter a non-negative integer to cap attempts, or enter `0`
|
automatic revisions, enter a non-negative integer to cap attempts, or enter `0`
|
||||||
to disable automatic revision for that path. Edits batch and commit through a
|
to disable automatic revision for that path. `plannerOversightLevel` is the
|
||||||
single **Save** in the Values tab.
|
workflow-native planner oversight mode and accepts `off`, `observe`, `steer`,
|
||||||
|
or `autonomous` (default). Edits batch and commit through a single **Save** in
|
||||||
|
the Values tab.
|
||||||
|
|
||||||
**How values resolve.** The engine resolves *effective settings* per task as
|
**How values resolve.** The engine resolves *effective settings* per task as
|
||||||
`stored value ?? declaration default`. The task-detail Workflow, Chat, and Agent
|
`stored value ?? declaration default`. The task-detail Workflow, Chat, and Agent
|
||||||
@@ -320,6 +322,7 @@ These groups moved out of project settings and into workflow settings (built-in
|
|||||||
|---|---|
|
|---|---|
|
||||||
| **Step execution** | `workflowStepTimeoutMs`, `runStepsInNewSessions`, `maxParallelSteps`, `workflowStepScopeEnforcement`, `strictScopeEnforcement`, `verificationFixRetries`, `maxPostReviewFixes`, `buildRetryCount` |
|
| **Step execution** | `workflowStepTimeoutMs`, `runStepsInNewSessions`, `maxParallelSteps`, `workflowStepScopeEnforcement`, `strictScopeEnforcement`, `verificationFixRetries`, `maxPostReviewFixes`, `buildRetryCount` |
|
||||||
| **Review / approval** | Workflow values: `requirePrApproval`, `requirePlanApproval`, `reviewHandoffPolicy`, `maxReviewerContextRetries`, `maxReviewerFallbackRetries`, `planReviewMaxRevisions`, `codeReviewMaxRevisions`; project override: `planApprovalMode` |
|
| **Review / approval** | Workflow values: `requirePrApproval`, `requirePlanApproval`, `reviewHandoffPolicy`, `maxReviewerContextRetries`, `maxReviewerFallbackRetries`, `planReviewMaxRevisions`, `codeReviewMaxRevisions`; project override: `planApprovalMode` |
|
||||||
|
| **Planner oversight** | `plannerOversightLevel` (workflow-native; values: `off`, `observe`, `steer`, `autonomous`) |
|
||||||
| **Per-phase model lanes** | `executionProvider`/`executionModelId`, `planningProvider`/`planningModelId` (+ fallbacks), `validatorProvider`/`validatorModelId` (+ fallbacks) |
|
| **Per-phase model lanes** | `executionProvider`/`executionModelId`, `planningProvider`/`planningModelId` (+ fallbacks), `validatorProvider`/`validatorModelId` (+ fallbacks) |
|
||||||
|
|
||||||
### Workflow-native triage policy settings
|
### Workflow-native triage policy settings
|
||||||
@@ -353,6 +356,7 @@ The built-in workflows also declare triage/spec policy settings that were **not*
|
|||||||
| `autoApproveSpec` | `false` | Legacy compatibility setting. Workflow Plan Review now owns optional pre-execution AI plan approval. |
|
| `autoApproveSpec` | `false` | Legacy compatibility setting. Workflow Plan Review now owns optional pre-execution AI plan approval. |
|
||||||
| `planReviewMaxRevisions` | unset | Workflow-native Plan Review/spec revision cap. Unset/empty means unbounded automatic replans; a non-negative integer caps attempts; `0` disables automatic Plan Review revision. |
|
| `planReviewMaxRevisions` | unset | Workflow-native Plan Review/spec revision cap. Unset/empty means unbounded automatic replans; a non-negative integer caps attempts; `0` disables automatic Plan Review revision. |
|
||||||
| `codeReviewMaxRevisions` | unset | Workflow-native Code Review remediation cap. Unset/empty means unbounded automatic code-fix passes; a non-negative integer caps attempts; `0` disables automatic Code Review remediation. |
|
| `codeReviewMaxRevisions` | unset | Workflow-native Code Review remediation cap. Unset/empty means unbounded automatic code-fix passes; a non-negative integer caps attempts; `0` disables automatic Code Review remediation. |
|
||||||
|
| `plannerOversightLevel` | `autonomous` | Workflow-native planner oversight mode. `off` disables oversight; `observe` watches only; `steer` injects guidance or suggests revisions; `autonomous` enables bounded retry and targeted-fix recovery. Per-task overrides and engine behavior are follow-up work. |
|
||||||
|
|
||||||
When `triageProactiveSubtaskSplittingEnabled` is `true` (the default), triage may proactively replace a large task with 2-5 child tasks when the size, step-count, package breadth, file-scope, or remediation-batch signals justify the coordination overhead. When it is `false`, those automatic oversized-task signals are advisory only for writing a realistic single-task spec; triage must not split solely because the task is large. The per-task `breakIntoSubtasks: true` flag is separate and remains mandatory: if a user explicitly asks for subtask breakdown, triage still evaluates and creates child tasks when the work is meaningfully decomposable.
|
When `triageProactiveSubtaskSplittingEnabled` is `true` (the default), triage may proactively replace a large task with 2-5 child tasks when the size, step-count, package breadth, file-scope, or remediation-batch signals justify the coordination overhead. When it is `false`, those automatic oversized-task signals are advisory only for writing a realistic single-task spec; triage must not split solely because the task is large. The per-task `breakIntoSubtasks: true` flag is separate and remains mandatory: if a user explicitly asks for subtask breakdown, triage still evaluates and creates child tasks when the work is meaningfully decomposable.
|
||||||
|
|
||||||
|
|||||||
@@ -829,13 +829,16 @@ engine resolves *effective settings* per task as `stored value ?? declaration
|
|||||||
default`, dropping any stored value that no longer validates against the current
|
default`, dropping any stored value that no longer validates against the current
|
||||||
declaration (drop-on-orphan) and falling back to the default.
|
declaration (drop-on-orphan) and falling back to the default.
|
||||||
|
|
||||||
The **step-execution**, **review/approval**, **per-phase model-lane**, and
|
The **step-execution**, **review/approval**, **per-phase model-lane**,
|
||||||
**triage/spec policy** knobs are workflow settings declared by `builtin:coding`.
|
**triage/spec policy**, and **planner oversight** knobs are workflow settings
|
||||||
Triage policy includes `triageProactiveSubtaskSplittingEnabled` (default `true`),
|
declared by `builtin:coding`. Triage policy includes
|
||||||
which controls automatic large-task splitting guidance for oversized M/L work.
|
`triageProactiveSubtaskSplittingEnabled` (default `true`), which controls
|
||||||
Set it to `false` in a workflow's Values tab when triage should keep large tasks
|
automatic large-task splitting guidance for oversized M/L work. Set it to `false`
|
||||||
whole unless the task explicitly has `breakIntoSubtasks: true`; explicit subtask
|
in a workflow's Values tab when triage should keep large tasks whole unless the
|
||||||
requests still follow the mandatory split flow. See
|
task explicitly has `breakIntoSubtasks: true`; explicit subtask requests still
|
||||||
|
follow the mandatory split flow. Planner oversight uses `plannerOversightLevel`
|
||||||
|
(default `autonomous`) with `off`, `observe`, `steer`, and `autonomous` values;
|
||||||
|
per-task override and engine runtime behavior are follow-up work. See
|
||||||
[Settings Reference → Workflow Settings](./settings-reference.md#workflow-settings)
|
[Settings Reference → Workflow Settings](./settings-reference.md#workflow-settings)
|
||||||
for the full moved-key catalog, the editor walkthrough, and the export/sync posture.
|
for the full moved-key catalog, the editor walkthrough, and the export/sync posture.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
BUILTIN_MOVED_WORKFLOW_SETTINGS,
|
BUILTIN_MOVED_WORKFLOW_SETTINGS,
|
||||||
|
BUILTIN_OVERSIGHT_SETTINGS,
|
||||||
BUILTIN_REVIEW_REVISION_SETTINGS,
|
BUILTIN_REVIEW_REVISION_SETTINGS,
|
||||||
BUILTIN_TRIAGE_POLICY_SETTINGS,
|
BUILTIN_TRIAGE_POLICY_SETTINGS,
|
||||||
BUILTIN_WORKFLOW_SETTINGS,
|
BUILTIN_WORKFLOW_SETTINGS,
|
||||||
@@ -80,6 +81,37 @@ describe("workflow-native built-in workflow settings", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("declares planner oversight level as a workflow-native enum outside moved/project settings", () => {
|
||||||
|
const fullIds = new Set(BUILTIN_WORKFLOW_SETTINGS.map((setting) => setting.id));
|
||||||
|
const movedIds = new Set(BUILTIN_MOVED_WORKFLOW_SETTINGS.map((setting) => setting.id));
|
||||||
|
const movedKeyIds = new Set(MOVED_SETTINGS_KEYS);
|
||||||
|
|
||||||
|
expect(BUILTIN_OVERSIGHT_SETTINGS.map((setting) => setting.id)).toEqual(["plannerOversightLevel"]);
|
||||||
|
const oversight = BUILTIN_OVERSIGHT_SETTINGS[0];
|
||||||
|
expect(oversight).toMatchObject({
|
||||||
|
type: "enum",
|
||||||
|
default: "autonomous",
|
||||||
|
});
|
||||||
|
expect(oversight.options?.map((option) => option.value)).toEqual(["off", "observe", "steer", "autonomous"]);
|
||||||
|
expect(oversight.options?.map((option) => option.label)).toEqual([
|
||||||
|
"Off",
|
||||||
|
"Observe",
|
||||||
|
"Steer",
|
||||||
|
"Autonomous recovery",
|
||||||
|
]);
|
||||||
|
expect(fullIds.has("plannerOversightLevel"), "plannerOversightLevel should be in the full built-in catalog").toBe(
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
movedIds.has("plannerOversightLevel"),
|
||||||
|
"plannerOversightLevel should not be in the moved-key catalog",
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
movedKeyIds.has("plannerOversightLevel"),
|
||||||
|
"plannerOversightLevel should not be in MOVED_SETTINGS_KEYS",
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it("renders placeholders from resolved settings and rejects dangling tokens", () => {
|
it("renders placeholders from resolved settings and rejects dangling tokens", () => {
|
||||||
const prompt = [
|
const prompt = [
|
||||||
"Size S (<{{triageSizeSmallMaxHours}}h)",
|
"Size S (<{{triageSizeSmallMaxHours}}h)",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
import { describe, it, expect } from "vitest";
|
import { describe, it, expect } from "vitest";
|
||||||
import { MOVED_SETTINGS_KEYS } from "../moved-settings.js";
|
import { MOVED_SETTINGS_KEYS } from "../moved-settings.js";
|
||||||
import {
|
import {
|
||||||
|
BUILTIN_OVERSIGHT_SETTINGS,
|
||||||
BUILTIN_REVIEW_REVISION_SETTINGS,
|
BUILTIN_REVIEW_REVISION_SETTINGS,
|
||||||
BUILTIN_TRIAGE_POLICY_SETTINGS,
|
BUILTIN_TRIAGE_POLICY_SETTINGS,
|
||||||
BUILTIN_WORKFLOW_SETTINGS,
|
BUILTIN_WORKFLOW_SETTINGS,
|
||||||
@@ -50,11 +51,12 @@ describe("settings consistency (U5)", () => {
|
|||||||
const nativeCatalogs = [
|
const nativeCatalogs = [
|
||||||
{ name: "BUILTIN_TRIAGE_POLICY_SETTINGS", ids: BUILTIN_TRIAGE_POLICY_SETTINGS.map((s) => s.id) },
|
{ name: "BUILTIN_TRIAGE_POLICY_SETTINGS", ids: BUILTIN_TRIAGE_POLICY_SETTINGS.map((s) => s.id) },
|
||||||
{ name: "BUILTIN_REVIEW_REVISION_SETTINGS", ids: BUILTIN_REVIEW_REVISION_SETTINGS.map((s) => s.id) },
|
{ name: "BUILTIN_REVIEW_REVISION_SETTINGS", ids: BUILTIN_REVIEW_REVISION_SETTINGS.map((s) => s.id) },
|
||||||
|
{ name: "BUILTIN_OVERSIGHT_SETTINGS", ids: BUILTIN_OVERSIGHT_SETTINGS.map((s) => s.id) },
|
||||||
];
|
];
|
||||||
const native = new Set(nativeCatalogs.flatMap((catalog) => catalog.ids));
|
const native = new Set(nativeCatalogs.flatMap((catalog) => catalog.ids));
|
||||||
/*
|
/*
|
||||||
* FNXC:SettingsRegimes 2026-07-02-08:20:
|
* FNXC:SettingsRegimes 2026-07-02-08:20:
|
||||||
* Workflow-native settings include triage policy and review/revision policy. They must be recognized by the consistency guard without being tombstoned in MOVED_SETTINGS_KEYS or reintroduced into project/global schemas.
|
* Workflow-native settings include triage policy, review/revision policy, and planner oversight policy. They must be recognized by the consistency guard without being tombstoned in MOVED_SETTINGS_KEYS or reintroduced into project/global schemas.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Every moved key has a declaration.
|
// Every moved key has a declaration.
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ describe("resolveEffectiveSettings (per-task)", () => {
|
|||||||
expect(eff[s.id]).toStrictEqual(s.default);
|
expect(eff[s.id]).toStrictEqual(s.default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
expect(eff.plannerOversightLevel).toBe("autonomous");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("a stored value for (workflow, project) is returned over the default", async () => {
|
it("a stored value for (workflow, project) is returned over the default", async () => {
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ import type { WorkflowSettingDefinition } from "./workflow-ir-types.js";
|
|||||||
* `BUILTIN_REVIEW_REVISION_SETTINGS` is workflow-native review-loop policy.
|
* `BUILTIN_REVIEW_REVISION_SETTINGS` is workflow-native review-loop policy.
|
||||||
* These keys also never lived in project/global settings and intentionally omit
|
* These keys also never lived in project/global settings and intentionally omit
|
||||||
* declaration defaults: an unset workflow value means unbounded remediation.
|
* declaration defaults: an unset workflow value means unbounded remediation.
|
||||||
|
*
|
||||||
|
* `BUILTIN_OVERSIGHT_SETTINGS` is workflow-native planner oversight policy.
|
||||||
|
* These keys never lived in project/global settings and must never be added to
|
||||||
|
* `MOVED_SETTINGS_KEYS`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -428,10 +432,32 @@ export const BUILTIN_REVIEW_REVISION_SETTINGS: WorkflowSettingDefinition[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FNXC:PlannerOversight 2026-07-04-00:00:
|
||||||
|
* Workflows declare a default planner oversight level before per-task override and engine reader support land in FN-7509/FN-7510. The workflow-native enum stays out of project settings and `MOVED_SETTINGS_KEYS`; its schema default is `autonomous` so built-in workflows preserve full steering/control until operators choose Off, Observe, or Steer.
|
||||||
|
*/
|
||||||
|
export const BUILTIN_OVERSIGHT_SETTINGS: WorkflowSettingDefinition[] = [
|
||||||
|
{
|
||||||
|
id: "plannerOversightLevel",
|
||||||
|
name: "Planner oversight level",
|
||||||
|
type: "enum",
|
||||||
|
default: "autonomous",
|
||||||
|
options: [
|
||||||
|
{ value: "off", label: "Off" },
|
||||||
|
{ value: "observe", label: "Observe" },
|
||||||
|
{ value: "steer", label: "Steer" },
|
||||||
|
{ value: "autonomous", label: "Autonomous recovery" },
|
||||||
|
],
|
||||||
|
description:
|
||||||
|
"Workflow planner oversight mode: Off disables oversight; Observe watches only; Steer injects guidance or suggests revisions; Autonomous recovery enables bounded retry and targeted-fix recovery.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const BUILTIN_WORKFLOW_SETTINGS: WorkflowSettingDefinition[] = [
|
export const BUILTIN_WORKFLOW_SETTINGS: WorkflowSettingDefinition[] = [
|
||||||
...BUILTIN_MOVED_WORKFLOW_SETTINGS,
|
...BUILTIN_MOVED_WORKFLOW_SETTINGS,
|
||||||
...BUILTIN_TRIAGE_POLICY_SETTINGS,
|
...BUILTIN_TRIAGE_POLICY_SETTINGS,
|
||||||
...BUILTIN_REVIEW_REVISION_SETTINGS,
|
...BUILTIN_REVIEW_REVISION_SETTINGS,
|
||||||
|
...BUILTIN_OVERSIGHT_SETTINGS,
|
||||||
];
|
];
|
||||||
|
|
||||||
const TRIAGE_POLICY_DEFAULTS = new Map(
|
const TRIAGE_POLICY_DEFAULTS = new Map(
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ export {
|
|||||||
BUILTIN_WORKFLOW_SETTINGS,
|
BUILTIN_WORKFLOW_SETTINGS,
|
||||||
BUILTIN_MOVED_WORKFLOW_SETTINGS,
|
BUILTIN_MOVED_WORKFLOW_SETTINGS,
|
||||||
BUILTIN_TRIAGE_POLICY_SETTINGS,
|
BUILTIN_TRIAGE_POLICY_SETTINGS,
|
||||||
|
BUILTIN_OVERSIGHT_SETTINGS,
|
||||||
renderTriagePolicyPlaceholders,
|
renderTriagePolicyPlaceholders,
|
||||||
} from "./builtin-workflow-settings.js";
|
} from "./builtin-workflow-settings.js";
|
||||||
export {
|
export {
|
||||||
|
|||||||
Reference in New Issue
Block a user