diff --git a/docs/command-modes.md b/docs/command-modes.md index 6e64ec7..01c28e9 100644 --- a/docs/command-modes.md +++ b/docs/command-modes.md @@ -8,7 +8,7 @@ Per-command flag tables, imported from `CLAUDE.md` via pointer. |------|----------| | _(default)_ | Dynamic interview until quality gates pass → brief.md with research plan | | `--quick` | Compact start; still escalates if required sections are weak or the brief-review gate fails → brief.md with research plan | -| `--gates {open\|closed\|adaptive}` | (v3.4.0) Autonomy-checkpoint policy. Default `adaptive` | +| `--gates {true\|false}` | (v3.4.0) Boolean autonomy-gate flag; present → gating on. Policy (`gates_mode`) detailed under `## Autonomy mode` in `docs/operations.md`. | | `--profile ` | (v4.1.0) Model profile: `economy` / `balanced` / `premium` / ``. Sets `phase_models` for the brief phase. See `## Profile system` in `docs/operations.md`. | Always interactive. Phase 3 is a section-driven completeness loop (no hard cap on question count); Phase 4 runs a `brief-reviewer` stop-gate with max 3 review iterations. After writing the brief, asks the user to choose manual (print commands) or auto (Claude runs research + plan in foreground). @@ -23,7 +23,7 @@ Always interactive. Phase 3 is a section-driven completeness loop (no hard cap o | `--local` | Only codebase analysis agents (skip external + Gemini) | | `--external` | Only external research agents (skip codebase analysis) | | `--fg` | No-op alias (foreground is default since v2.4.0) | -| `--gates {open\|closed\|adaptive}` | (v3.4.0) Autonomy-checkpoint policy. Default `adaptive` | +| `--gates {true\|false}` | (v3.4.0) Boolean autonomy-gate flag; present → gating on. Policy (`gates_mode`) detailed under `## Autonomy mode` in `docs/operations.md`. | | `--min-brief-version ` | (S18) Warn — never block — if an attached `--project` brief declares a version below `` (e.g. `2.2`), i.e. sidesteps framing enforcement | | `--profile ` | (v4.1.0) Model profile for the research phase. | @@ -41,7 +41,7 @@ Flags combine: `--project --local`, `--external --quick`. | `--min-brief-version ` | (S18) Warn — never block — if the brief declares a version below `` (e.g. `2.2`), i.e. sidesteps framing enforcement | | `--export ` | Generate shareable output from existing plan | | `--decompose ` | Split plan into self-contained headless sessions | -| `--gates {open\|closed\|adaptive}` | (v3.4.0) Autonomy-checkpoint policy. Default `adaptive` | +| `--gates {true\|false}` | (v3.4.0) Boolean autonomy-gate flag; present → gating on. Policy (`gates_mode`) detailed under `## Autonomy mode` in `docs/operations.md`. | | `--profile ` | (v4.1.0) Model profile for the plan phase (and others, since plan emits `profile:` to plan.md frontmatter). | **Breaking change (v2.0):** one of `--brief` or `--project` is required. There is no interview inside `/trekplan`. The `--spec` flag has been removed — use `/trekbrief` to produce a brief instead. @@ -60,7 +60,7 @@ If `{project_dir}/architecture/overview.md` exists (typically produced by an opt | `--step N` | Execute only step N | | `--fg` | Force foreground — run all steps sequentially, ignore Execution Strategy | | `--session N` | Execute only session N from plan's Execution Strategy | -| `--gates {open\|closed\|adaptive}` | (v3.4.0) Autonomy-checkpoint policy. Default `adaptive` | +| `--gates {true\|false}` | (v3.4.0) Boolean autonomy-gate flag; present → gating on. Policy (`gates_mode`) detailed under `## Autonomy mode` in `docs/operations.md`. | | `--profile ` | (v4.1.0) Model profile for the execute phase. Inherited from plan.md frontmatter `profile:` if present. | ## /trekreview modes diff --git a/docs/operations.md b/docs/operations.md index d61c07a..e42da4b 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -4,15 +4,17 @@ Imported from `CLAUDE.md` via pointer. ## Autonomy mode (`--gates`, v3.4.0) -All four pipeline commands accept `--gates {open|closed|adaptive}`: +All four pipeline commands accept a boolean `--gates {true|false}` flag. Presence (`--gates true`, or bare `--gates`) turns gating **on** — the run pauses at autonomy boundaries for operator confirmation. Absence (or `--gates false`, the default) runs phases continuously without pausing. -| Value | Behavior | -|-------|----------| -| `open` | Skip optional checkpoints; trust manifests + verify gates only | -| `closed` | Stop at every autonomy boundary; operator confirms each transition | -| `adaptive` (default) | Stop only at meaningful boundaries (manifest-audit FAIL, plan-critic BLOCKER, main-merge gate) | +`/trekexecute` additionally refines *how strict* the gating is via a `gates_mode` policy derived from the brief's effort signal (an explicit operator `--gates` flag takes precedence over the brief signal — see `commands/trekexecute.md` § High-effort behavior (v5.1.1)): -Under the hood: `lib/util/autonomy-gate.mjs` runs the state machine `idle → approved → executing → merge-pending → main-merged`. `lib/stats/event-emit.mjs` records each transition to `${CLAUDE_PLUGIN_DATA}/trek*-stats.jsonl`. The main-merge gate is the final autonomy boundary before HEAD lands on `main`. +| `gates_mode` | Derived from (effort) | Behavior | +|--------------|-----------------------|----------| +| `adaptive` | standard / absent (default) | Stop only at meaningful boundaries (manifest-audit FAIL, plan-critic BLOCKER, main-merge gate) | +| `closed` | high | Stop at every autonomy boundary; operator confirms each transition | +| `open` | low | Skip optional checkpoints; trust manifests + verify gates only | + +Under the hood: `lib/util/autonomy-gate.mjs` runs the state machine `idle → gates_on | auto_running → paused_for_gate → completed`. `start` routes to `gates_on` when `--gates true`, else `auto_running`; a `phase_boundary` from `gates_on` pauses at `paused_for_gate` (awaiting `resume`); `finish` reaches the terminal `completed`. The module is pure data with no I/O. Separately, `lib/stats/event-emit.mjs` records named lifecycle events (`brief-approved`, `main-merge-gate`, `user_input`) to `${CLAUDE_PLUGIN_DATA}/trek*-stats.jsonl`. The main-merge gate is the final autonomy boundary before HEAD lands on `main`. ### Path A/B/C decision (v3.4.0; Path C closed 2026-05-05) diff --git a/tests/lib/doc-consistency.test.mjs b/tests/lib/doc-consistency.test.mjs index cc84616..bbfd555 100644 --- a/tests/lib/doc-consistency.test.mjs +++ b/tests/lib/doc-consistency.test.mjs @@ -25,6 +25,7 @@ import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { parseDocument } from '../../lib/util/frontmatter.mjs'; import { resolveProfile, loadProfile } from '../../lib/profiles/resolver.mjs'; +import { STATES } from '../../lib/util/autonomy-gate.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); @@ -375,6 +376,55 @@ test('operations.md custom-profile prose matches findProfilePath resolution orde ); }); +// --- S24 — anti-false-claim: operations.md + command-modes.md autonomy-gate truth-pass --- +// +// autonomy-gate.mjs is a BOOLEAN gate: --gates {true|false} → gates_on|auto_running. +// State machine: idle → gates_on|auto_running → paused_for_gate → completed. +// The old prose (operations.md:15 / command-modes.md gates rows) (1) fabricated a +// state machine `idle → approved → executing → merge-pending → main-merged` — only +// `idle` exists in autonomy-gate.mjs STATES; (2) claimed event-emit.mjs "records +// each transition" — it emits 3 named lifecycle events and is decoupled from the +// (pure, no-I/O) autonomy-gate; (3) advertised `--gates {open|closed|adaptive}` — +// open/closed/adaptive is a DERIVED gates_mode policy in the command layer, not a +// flag value (the CLI shim + all 4 command docs take boolean `--gates {true|false}`). +test('operations.md + command-modes.md describe the real autonomy-gate, not a fabricated one [S24]', () => { + const ops = read('docs/operations.md'); + const modes = read('docs/command-modes.md'); + + // F1 — fabricated state names (merge-pending/main-merged are unique to the false claim) + for (const bad of ['merge-pending', 'main-merged']) { + assert.ok( + !ops.includes(bad), + `docs/operations.md: fabricated autonomy state "${bad}" — autonomy-gate.mjs has no such state; fix the prose, not this test`, + ); + } + + // F1 — the real transient states (derived from autonomy-gate.mjs STATES) must be documented + for (const real of [STATES.GATES_ON, STATES.AUTO_RUNNING, STATES.PAUSED_FOR_GATE]) { + assert.ok( + ops.includes(real), + `docs/operations.md must name the real autonomy-gate state "${real}" (from autonomy-gate.mjs STATES)`, + ); + } + + // F2 — event-emit does NOT record each autonomy-gate transition + assert.ok( + !ops.includes('records each transition'), + 'docs/operations.md: event-emit records 3 named lifecycle events, not "each transition" of the (decoupled) autonomy-gate; fix the prose', + ); + + // F3 — --gates is boolean; open/closed/adaptive is a derived gates_mode policy, not a flag enum + const GATES_ENUM_FORMS = ['{open|closed|adaptive}', '{open\\|closed\\|adaptive}']; + for (const [label, txt] of [['operations.md', ops], ['command-modes.md', modes]]) { + for (const bad of GATES_ENUM_FORMS) { + assert.ok( + !txt.includes(bad), + `docs/${label}: --gates flag enum "${bad}" is false — flag is boolean {true|false}; open/closed/adaptive is a derived gates_mode; fix the prose, not this test`, + ); + } + } +}); + // --- v4.1 Step 21 — pin --profile + phase_models on the 6 commands --- // // CLAUDE.md / README.md pinning is deferred to Step 22 (post-write of