From c330f70f65fa5cb8e7011ad382741946fe0facde Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Sat, 20 Jun 2026 15:32:07 -0400 Subject: [PATCH] feat(#1494): add workflow.mvp_mode to VALID_CONFIG_KEYS; document code_review_command and plan_chunked in planning-config.md (#1500) * feat(#1494): add workflow.mvp_mode to VALID_CONFIG_KEYS; document code_review_command, plan_chunked, mvp_mode in planning-config.md Co-Authored-By: Claude Sonnet 4.6 * chore: backfill PR number 1500 in changeset Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- .changeset/curious-eagles-purr.md | 5 + docs/CONFIGURATION.md | 1 + .../bin/shared/config-schema.manifest.json | 1 + gsd-core/references/planning-config.md | 3 + ...enh-1494-workflow-config-key-docs.test.cjs | 118 ++++++++++++++++++ 5 files changed, 128 insertions(+) create mode 100644 .changeset/curious-eagles-purr.md create mode 100644 tests/enh-1494-workflow-config-key-docs.test.cjs diff --git a/.changeset/curious-eagles-purr.md b/.changeset/curious-eagles-purr.md new file mode 100644 index 000000000..d0bb8852c --- /dev/null +++ b/.changeset/curious-eagles-purr.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 1500 +--- +**`workflow.mvp_mode` now accepted by `config-set`; three undocumented workflow keys added to references** — `workflow.mvp_mode`, `workflow.code_review_command`, and `workflow.plan_chunked` were consumed by planning-pipeline code but could not be set via `config-set` (they were missing from `VALID_CONFIG_KEYS`) or discovered via reference docs. All three are now in the schema and documented in `references/planning-config.md`. (#1500) diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 550dceff3..a21244574 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -260,6 +260,7 @@ All workflow toggles follow the **absent = enabled** pattern. If a key is missin | `workflow.plan_chunked` | boolean | `false` | Enable chunked planning mode. When `true` (or when `--chunked` flag is passed to `/gsd-plan-phase`), the orchestrator splits the single long-lived planner Task into a short outline Task followed by N short per-plan Tasks (~3-5 min each). Each plan is committed individually for crash resilience. If a Task hangs and the terminal is force-killed, rerunning with `--chunked` resumes from the last completed plan. Particularly useful on Windows where long-lived Tasks may hang on stdio. Added in v1.38 | | `workflow.code_review_command` | string | (none) | Shell command for external code review integration in `/gsd-ship`. Receives changed file paths via stdin. Non-zero exit blocks the ship workflow. Added in v1.36 | | `workflow.tdd_mode` | boolean | `false` | Enable TDD pipeline as a first-class execution mode. When `true`, the planner aggressively applies `type: tdd` to eligible tasks (business logic, APIs, validations, algorithms) and the executor enforces RED/GREEN/REFACTOR gate sequence. An end-of-phase collaborative review checkpoint verifies gate compliance. Added in v1.36 | +| `workflow.mvp_mode` | boolean | `false` | Persist the MVP-mode flag in config so every phase defaults to MVP framing without requiring `--mvp` on the CLI. Resolved via the precedence chain: `--mvp` CLI flag → ROADMAP.md `**Mode:** mvp` field → this config value → `false`. When `true`, the planner, executor, verifier, and discovery surfaces treat the phase as an MVP vertical slice (UI → API → DB) of one user-visible capability instead of a horizontal layer. | | `workflow.human_verify_mode` | string | `'end-of-phase'` | Controls human verification checkpoints. `'end-of-phase'` (default since #3309) suppresses `checkpoint:human-verify` tasks and embeds checks into `` blocks for end-of-phase review. `'mid-flight'` restores blocking checkpoint tasks. `checkpoint:decision` and `checkpoint:human-action` are unaffected. See [Checkpoints Reference](../gsd-core/references/checkpoints.md#checkpoint_types). | | `workflow.cross_ai_execution` | boolean | `false` | Delegate phase execution to an external AI CLI instead of spawning local executor agents. Useful for leveraging a different model's strengths for specific phases. Added in v1.36 | | `workflow.cross_ai_command` | string | (none) | Shell command template for cross-AI execution. Receives the phase prompt via stdin. Must produce SUMMARY.md-compatible output. Required when `cross_ai_execution` is `true`. Added in v1.36 | diff --git a/gsd-core/bin/shared/config-schema.manifest.json b/gsd-core/bin/shared/config-schema.manifest.json index a768fa069..fdd268892 100644 --- a/gsd-core/bin/shared/config-schema.manifest.json +++ b/gsd-core/bin/shared/config-schema.manifest.json @@ -55,6 +55,7 @@ "workflow.subagent_timeout", "workflow.test_command", "workflow.build_command", + "workflow.mvp_mode", "executor.stall_detect_interval_minutes", "executor.stall_threshold_minutes", "workflow.inline_plan_threshold", diff --git a/gsd-core/references/planning-config.md b/gsd-core/references/planning-config.md index 997855b3a..6b35fc763 100644 --- a/gsd-core/references/planning-config.md +++ b/gsd-core/references/planning-config.md @@ -266,6 +266,9 @@ Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research": | `workflow.subagent_timeout` | number | `300000` | Any positive integer (ms) | Timeout for parallel subagent tasks (default: 5 minutes) | | `workflow.test_command` | string\|null | `null` | Any shell command | Regression/test gate command run by verify-phase, execute-phase, audit-fix, and post-merge-gate. Unset → GSD auto-detects (Makefile / package.json / Cargo.toml / go.mod / pyproject.toml). | | `workflow.build_command` | string\|null | `null` | Any shell command | Build gate command run by the post-merge gate. Unset → build step auto-detected/skipped. | +| `workflow.mvp_mode` | boolean | `false` | `true`, `false` | Persist the MVP-mode flag in config so every phase defaults to MVP framing without requiring `--mvp` on the CLI. Resolved via the chain: `--mvp` CLI flag → ROADMAP.md `**Mode:** mvp` field → this config value → `false`. When `true`, the planner, executor, verifier, and discovery surfaces (progress, stats, graphify) all treat the phase as an MVP vertical slice (UI → API → DB) of one user-visible capability. | +| `workflow.plan_chunked` | boolean | `false` | `true`, `false` | Enable chunked planning mode. When `true`, the plan-phase orchestrator splits the single long-lived planner Task into a short outline Task followed by N short per-plan Tasks (~3–5 min each). Each plan is committed individually for crash resilience. Particularly useful on Windows where long-lived Tasks may hang on stdio. Also activated by the `--chunked` flag. | +| `workflow.code_review_command` | string\|null | `null` | Any shell command | External code-review command integrated into `/gsd:ship`. The diff is piped to the command via stdin; the command must output JSON with a `verdict` field (`"APPROVED"` or `"REVISE"`). Non-zero exit or `"REVISE"` verdict blocks the ship workflow. When unset, the built-in review flow runs. Example: `my-review-tool --review`. | | `workflow.inline_plan_threshold` | number | `2` | `0`–`10` | Plans with ≤N tasks execute inline instead of spawning a subagent | | `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow | | `workflow.code_review_depth` | string | `"standard"` | `"light"`, `"standard"`, `"deep"` | Depth level for code review analysis in the ship workflow | diff --git a/tests/enh-1494-workflow-config-key-docs.test.cjs b/tests/enh-1494-workflow-config-key-docs.test.cjs new file mode 100644 index 000000000..bd782533d --- /dev/null +++ b/tests/enh-1494-workflow-config-key-docs.test.cjs @@ -0,0 +1,118 @@ +'use strict'; + +/** + * Parity assertions for #1494: workflow config keys that are consumed by + * planning-pipeline code must be (a) accepted by VALID_CONFIG_KEYS and + * (b) documented in references/planning-config.md. + * + * Per DEFECT.GENERATIVE-FIX: a shared constant / key-list that spans two + * surfaces requires a parity assertion that fails when the surfaces diverge. + */ + +const { describe, test, before, afterEach } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('fs'); +const path = require('path'); + +const { createTempProject, cleanup, runGsdTools } = require('./helpers.cjs'); + +const CONFIG_SCHEMA_PATH = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'config-schema.cjs'); +const PLANNING_CONFIG_PATH = path.join(__dirname, '..', 'gsd-core', 'references', 'planning-config.md'); + +describe('VALID_CONFIG_KEYS parity — #1494 orphan-undocumented keys', () => { + const { VALID_CONFIG_KEYS } = require(CONFIG_SCHEMA_PATH); + + test('workflow.mvp_mode is in VALID_CONFIG_KEYS', () => { + assert.ok( + VALID_CONFIG_KEYS.has('workflow.mvp_mode'), + 'workflow.mvp_mode is read by config-loader.cts and plan-phase.md but was missing from VALID_CONFIG_KEYS (#1494)' + ); + }); + + test('workflow.code_review_command is in VALID_CONFIG_KEYS', () => { + assert.ok( + VALID_CONFIG_KEYS.has('workflow.code_review_command'), + 'workflow.code_review_command must be in VALID_CONFIG_KEYS' + ); + }); + + test('workflow.plan_chunked is in VALID_CONFIG_KEYS', () => { + assert.ok( + VALID_CONFIG_KEYS.has('workflow.plan_chunked'), + 'workflow.plan_chunked must be in VALID_CONFIG_KEYS' + ); + }); + + test('workflow.test_command is in VALID_CONFIG_KEYS', () => { + assert.ok( + VALID_CONFIG_KEYS.has('workflow.test_command'), + 'workflow.test_command must be in VALID_CONFIG_KEYS' + ); + }); + + test('workflow.build_command is in VALID_CONFIG_KEYS', () => { + assert.ok( + VALID_CONFIG_KEYS.has('workflow.build_command'), + 'workflow.build_command must be in VALID_CONFIG_KEYS' + ); + }); +}); + +describe('config-set accepts workflow.mvp_mode (#1494)', () => { + let tmpDir; + afterEach(() => { if (tmpDir) cleanup(tmpDir); }); + + test('config-set workflow.mvp_mode true succeeds and stores the value', () => { + tmpDir = createTempProject(); + const result = runGsdTools(['config-set', 'workflow.mvp_mode', 'true'], tmpDir); + assert.ok( + result.success, + `config-set workflow.mvp_mode must succeed; got:\nstdout: ${result.output}\nstderr: ${result.error}` + ); + const parsed = JSON.parse(result.output); + assert.strictEqual(parsed.updated, true, 'response must have updated:true'); + assert.strictEqual(parsed.key, 'workflow.mvp_mode', 'response must echo the key'); + }); + + test('config-set workflow.mvp_mode false succeeds', () => { + tmpDir = createTempProject(); + const result = runGsdTools(['config-set', 'workflow.mvp_mode', 'false'], tmpDir); + assert.ok( + result.success, + `config-set workflow.mvp_mode false must succeed; got:\nstdout: ${result.output}\nstderr: ${result.error}` + ); + const parsed = JSON.parse(result.output); + assert.strictEqual(parsed.updated, true); + }); +}); + +// allow-test-rule: source-text-is-the-product — planning-config.md is the deployed reference contract (#1494) +describe('planning-config.md documents #1494 keys', () => { + let content; + before(() => { content = fs.readFileSync(PLANNING_CONFIG_PATH, 'utf-8'); }); + + const KEYS = [ + 'workflow.mvp_mode', + 'workflow.code_review_command', + 'workflow.plan_chunked', + 'workflow.test_command', + 'workflow.build_command', + ]; + + for (const key of KEYS) { + test(`planning-config.md documents \`${key}\``, () => { + assert.ok( + content.includes(`\`${key}\``), + `planning-config.md must document \`${key}\` (#1494)` + ); + }); + + test(`\`${key}\` appears in the Complete Field Reference section`, () => { + const refSection = content.slice(content.indexOf('## Complete Field Reference')); + assert.ok( + refSection.includes(`\`${key}\``), + `planning-config.md Complete Field Reference must include \`${key}\` (#1494)` + ); + }); + } +});