feat(voyage): W2 impl (S4) — gate resolver model, adopt native effort:, doc-truth

S4 of the 2.1.181 upgrade — implementation, not a gate. TDD: failing test
written first for the resolver gate, then the fix; suite green throughout.

- Resolver MAJOR (FIX): lib/profiles/phase-signal-resolver.mjs now imports
  BASE_ALLOWED_MODELS from profile-validator and gates `model`
  (if 'model' in entry && BASE_ALLOWED_MODELS.includes(entry.model)),
  mirroring the EFFORT_LEVELS gate one line up. Out-of-allowlist models
  (gpt-4, haiku) are dropped instead of handed to an agent spawn —
  defense-in-depth behind brief-validator's validation-time check. No
  circular import (brief-validator already imports the same symbol).
  +2 tests (drops-invalid / keeps-valid).
- Native effort: (SHIP, static additive): effort: frontmatter on 8 agents —
  retrieval (task-finder, git-historian, dependency-tracer,
  architecture-mapper) = medium; adversarial-reasoning (plan-critic,
  risk-assessor, contrarian-researcher, review-coordinator) = high. The
  other 15 stay unset -> inherit Opus-4.8 default (high). This per-spawn
  REASONING effort is a different axis from brief phase_signals.effort
  (ORCHESTRATION shape) per the S3 decision.
- Doc-truth + axis distinction: new canonical docs/profiles.md
  §Model & effort axes (opus->Opus 4.8 default-high; orchestration vs
  reasoning effort table; native-effort precedence; per-agent levels).
  Short notes in CLAUDE.md (after Agents table) and README.md (Cost
  profile), both pointing to profiles.md.
- Open (non-blocking, unchanged): only STATIC effort shipped — the
  verified-safe minimum. Profile-driven DYNAMIC effort still needs
  verification of the per-spawn effort param or env-var injection.

Matrix: new "S4 resolutions" section. Tests 582 total / 580 pass / 0 fail /
2 skip (was 578 pass; +2). claude plugin validate passes (only pre-existing
root-CLAUDE.md 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-18 12:27:07 +02:00
commit fdd3ad80d7
14 changed files with 102 additions and 1 deletions

View file

@ -26,6 +26,45 @@ runs (Step 17 calibration was deferred — see
`tests/synthetic/profile-jaccard-calibration.md`). If you observe
economy-plan quality regressions, fall back to `balanced`.
## Model & effort axes
`opus` and `sonnet` are model **aliases**, not pinned ids. As of Claude Code
2.1.154 the `opus` alias resolves to **Opus 4.8**, whose default reasoning
effort is **`high`**; `sonnet` resolves to Sonnet 4.6. The profile table above
selects *which alias* runs each phase — it does not touch reasoning effort.
Two different things share the word "effort" in Voyage. They are **orthogonal
axes** — same name, different mechanism:
| | **Orchestration effort** | **Reasoning effort (native)** |
|---|---|---|
| Where | brief `phase_signals.effort`, consumed by command prose | native Claude Code `effort:` in agent frontmatter |
| Values | `low` / `standard` / `high` | `low` / `medium` / `high` / `xhigh` / `max` |
| Controls | *which agents/passes/gates run* (swarm cardinality, gate strictness, sequential-vs-parallel) | *per-spawn reasoning-token budget* the harness gives one agent |
| `low` means | "run fewer agents" (the `--quick`-equivalent code-path) | "think with a smaller budget" |
| Applied by | Voyage command logic | the harness, at spawn time |
The `phase-signal-resolver.mjs` helper only reads the **orchestration** axis
(`phase_signals.effort`, gated against `low/standard/high`) plus the optional
per-phase `model` (gated against `['sonnet','opus']`). It never emits native
`effort:`.
**Native `effort:` on agents.** Voyage sets the reasoning axis statically on
selected agents, additively over the Opus-4.8 default:
- **Retrieval agents → `medium`:** `task-finder`, `git-historian`,
`dependency-tracer`, `architecture-mapper` (structured discovery, not deep
multi-step reasoning).
- **Adversarial-reasoning agents → `high`:** `plan-critic`, `risk-assessor`,
`contrarian-researcher`, `review-coordinator` (synthesis and stress-testing
where reasoning depth pays off).
- **All other agents:** unset → inherit the model default (Opus 4.8 = `high`).
Native-effort precedence (harness): env `CLAUDE_CODE_EFFORT_LEVEL` > frontmatter
`effort:` > session setting > model default. `MAX_THINKING_TOKENS=0` (or
`--thinking disabled`) overrides effort entirely. Enterprise `availableModels`
constrains the *model* alias only — it does **not** bound effort.
## Decision tree
```