docs(voyage): S24 — autonomy-gate truth-pass + guard pin (S21b doc/code drift)

operations.md:15 + command-modes.md described an autonomy surface that does
not exist in code. Truth-pass against lib/util/autonomy-gate.mjs (the source
of truth) closes three false claims found while auditing the autonomy surface
in S21 (devils-advocate-results.md S21b forward-pointer):

  F1 (MAJOR) — fabricated state machine. operations.md claimed
      `idle → approved → executing → merge-pending → main-merged`; only `idle`
      exists. Real states: idle → gates_on|auto_running → paused_for_gate →
      completed (events: start/phase_boundary/resume/finish).
  F2 (MINOR) — event-emit.mjs does NOT "record each transition"; it emits 3
      named lifecycle events (brief-approved, main-merge-gate, user_input) and
      is decoupled from the pure, no-I/O autonomy-gate.
  F3 — `--gates {open|closed|adaptive}` is false: the CLI shim + all 4 command
      docs take a BOOLEAN `--gates {true|false}`. open/closed/adaptive is a
      DERIVED gates_mode policy, /trekexecute-only, mapped from the brief effort
      signal (low→open, standard→adaptive, high→closed; trekexecute.md:1562/74/75).

Operator-chosen fix (S24): boolean-true representation + a gates_mode policy
note, applied to BOTH operations.md and command-modes.md (4 rows) — same
false-claim class, fixed in one pass (fix-errors-found-in-scope).

TDD: doc-pin in doc-consistency.test.mjs imports STATES from autonomy-gate.mjs,
forbids the fabricated names + the flag-enum, requires the real states. Red
first (failed on "merge-pending"), green after the truth-pass.

Tests: 725 (723 pass / 2 skip / 0 fail). plugin validate passes (1 accepted
CLAUDE.md-at-root warning).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
This commit is contained in:
Kjell Tore Guttormsen 2026-06-19 21:36:15 +02:00
commit fe97f6172c
3 changed files with 63 additions and 11 deletions

View file

@ -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