docs(voyage): S20-fix2 — correct false custom-profile lookup claims in operations.md

Operator directive (same as S20-fix): a real error must be fixed, not
carried as "flagged, out of scope". docs/operations.md §Custom profiles
made three claims that contradict findProfilePath (resolver.mjs:57-78):
  - custom profiles created in lib/profiles/<custom>.yaml — that is the
    BUILT-IN dir; custom profiles live in voyage-profiles/
  - "custom profiles override built-ins of the same name" — the built-in
    is resolved FIRST and wins; a custom file cannot shadow it
  - "lookup is alphabetical with <custom> taking precedence" — resolution
    is by directory order (built-in -> repo-root voyage-profiles/ ->
    ~/.claude/voyage-profiles/), never alphabetical

Corrected to match the code and the behavior already pinned by
profile-application.test.mjs SC #8 (custom = new name, voyage-profiles/,
repo-root > home).

TDD: anti-false-claim doc-consistency pin written failing-first, then
prose fixed. Suite 714->715 (713 pass / 2 skip / 0 fail); census
doc-pins 70->71, total 671->672.

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 15:10:56 +02:00
commit 6ed0c27fe2
2 changed files with 22 additions and 1 deletions

View file

@ -43,7 +43,7 @@ Three built-in model profiles plus operator-defined `<custom>.yaml`. Each profil
### Custom profiles
Create `lib/profiles/<custom>.yaml` to define a new tier. The validator (`lib/validators/profile-validator.mjs`) enforces: every `phase_models[].phase` must be a known phase enum; every `phase_models[].model` must match `^(opus|sonnet)(\b|-).*` or one of the canonical short names. Custom profiles override built-ins of the same name (lookup is alphabetical with `<custom>` taking precedence).
Create `voyage-profiles/<custom>.yaml` in the repo root (or `~/.claude/voyage-profiles/<custom>.yaml`) to define a **new** tier — the name must not be a built-in. The validator (`lib/validators/profile-validator.mjs`) enforces: every `phase_models[].phase` must be a known phase enum; every `phase_models[].model` must match `^(opus|sonnet)(\b|-).*` or one of the canonical short names. `findProfilePath` (`lib/profiles/resolver.mjs`) resolves **built-in first** (`lib/profiles/<name>.yaml` for `economy`/`balanced`/`premium`), then repo-root `voyage-profiles/`, then `~/.claude/voyage-profiles/`. A custom file named after a built-in therefore **cannot** shadow it (custom profiles must use new names); for the same custom name, repo-root takes precedence over home.
Drift between plan-frontmatter `profile:` and step-manifest `profile_used:` emits a `MANIFEST_PROFILE_DRIFT` warning from `plan-validator --strict` (Step 20). Plan remains valid; the warning surfaces accidental tier-mismatch.

View file

@ -323,6 +323,27 @@ test('orchestrator docs do not claim ALL sub-agents run on Sonnet (agents are mo
}
});
// --- S20 — anti-false-claim: operations.md custom-profile prose must match findProfilePath ---
//
// findProfilePath (lib/profiles/resolver.mjs:57) resolves built-in FIRST, then
// repo-root voyage-profiles/, then ~/.claude/voyage-profiles/. Custom profiles
// live in voyage-profiles/ (NOT lib/profiles/), must use NEW names, and CANNOT
// shadow a built-in. The old prose claimed the opposite (lib/profiles/<custom>;
// "override built-ins of the same name"; "alphabetical … precedence") — guard it.
test('operations.md custom-profile prose matches findProfilePath resolution order [S20]', () => {
const ops = read('docs/operations.md');
for (const bad of ['lib/profiles/<custom>', 'alphabetical', 'override built-ins of the same name']) {
assert.ok(
!ops.includes(bad),
`docs/operations.md: false custom-profile claim "${bad}" contradicts findProfilePath — fix the prose, not this test`,
);
}
assert.ok(
ops.includes('voyage-profiles/'),
'docs/operations.md must point custom profiles at voyage-profiles/ (not lib/profiles/)',
);
});
// --- 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