voyage/docs/profiles.md
Kjell Tore Guttormsen 213cf388de chore(voyage): S34 — V30 economy-profile self-declares experimental (uncalibrated Jaccard floor)
The economy profile's cross-tier Jaccard floor (0.55) rests on parked-synthetic
fixtures; empirical Step-17 calibration is v4.2-budget-gated ($60–120,
unauthorized). Fork resolved as label-not-calibrate: the experimental status,
previously prose-only in docs/profiles.md, now lives in the profile data and is
machine-checked. No new user-facing capability — honest labeling + a guard.

- lib/profiles/economy.yaml: add `experimental: true` (with rationale comment).
- lib/validators/profile-validator.mjs: recognize `experimental` as an OPTIONAL
  boolean; non-boolean → PROFILE_INVALID_ENUM. Absent ⇒ tier is stable
  (premium/balanced unaffected, profile_version stays 1.0 — additive).
- README.md + docs/operations.md + docs/profiles.md: flag the `economy` table
  row "⚠ Experimental (uncalibrated Jaccard floor)".
- tests/synthetic/profile-jaccard-calibration.md + analysis §6/§10 + backlog
  plan §S34: cross-reference the marker; mark V30/S34 done.

+5 tests (739 → 744, 742/2/0): economy declares experimental:true; premium and
balanced do not; validator rejects non-boolean experimental; every profile-doc
economy row is flagged; the flag tracks the calibration's parked-synthetic
status (must drop in the same change that lands real calibration).

Closes the balance backlog (4/4, S31–S34). claude plugin validate green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqBYc8Ltrk7LipyJmGxXiB
2026-06-20 10:18:38 +02:00

10 KiB
Raw Permalink Blame History

Profile system — voyage v4.1

This document describes the model profile system: built-in tiers, lookup precedence, custom-profile authoring, drift detection, and cost estimation (with disclaimer).

Built-in profiles

Three pre-defined tiers ship with v4.1, located at lib/profiles/{economy,balanced,premium}.yaml.

Profile Brief Research Plan Execute Review Continue Use case
economy sonnet sonnet sonnet sonnet sonnet sonnet Experimental (uncalibrated Jaccard floor) — lowest cost; small-scope tasks where you have high confidence the brief is right
balanced sonnet sonnet opus sonnet opus sonnet Mixed — opus where reasoning depth pays off (plan synthesis + adversarial review); opt-in via --profile balanced
premium (default) opus opus opus opus opus opus Maximum quality — Opus on every phase + external research on (default since the 2026-05-13 operator decision)

premium is the default tier — set by the 2026-05-13 operator decision and matched by the hardcoded resolver default in lib/profiles/resolver.mjs. It runs opus on every phase and turns external research on: maximum quality, at roughly 5× the sub-agent cost of an all-sonnet run, accepted as a deliberate trade-off. Drop to --profile balanced (opus only on the two phases where quality matters most — Plan synthesis + Review — and sonnet everywhere else) or --profile economy (sonnet everywhere) when cost or latency matters more than depth.

economy is strictly experimental in v4.1, and says so in the profile data itself: lib/profiles/economy.yaml carries experimental: true. The cross-tier Jaccard floor (0.55) is grounded in parked-synthetic fixtures, not empirical runs (Step 17 calibration was deferred — see tests/synthetic/profile-jaccard-calibration.md). The flag is pinned: it must stay true while the calibration status is parked-synthetic, and must be dropped in the same change that lands empirical calibration (status: empirical). 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

Are you uncertain whether the brief is correctly framed?
  └── Yes → premium (opus on brief + plan + review)
  └── No  → continue
            ↓
Is the change small (≤ 5 steps in the plan)?
  └── Yes → economy (sonnet everywhere)
  └── No  → balanced (opus on plan + review)

Special cases:
  - Critical-infrastructure plan          → premium
  - Migration with rollback risk          → premium
  - Research-heavy task (≥ 4 dimensions)  → balanced (research-stage benefits)
  - Bug fix with clear reproducer         → economy
  - Documentation-only PR                 → economy

Lookup order

Voyage resolves the profile in this priority order:

  1. Explicit --profile <name> flag — passed to the command
  2. Plan-file frontmatter profile: — when resuming via /trekexecute --resume or /trekcontinue
  3. VOYAGE_PROFILE environment variable — useful for headless CI
  4. Default premium — final fallback

The resolved value is recorded in two places:

  • Plan-file frontmatter profile: <name> and phase_models: [...]
  • Stats stream ${CLAUDE_PLUGIN_DATA}/trek*-stats.jsonlprofile, profile_source, phase_models, model_used, phase_models_resolved fields

profile_source distinguishes how the profile was resolved (flag / plan_frontmatter / env / default), so dashboards can surface unexpected env-var inheritance in CI.

Custom profiles

Drop a YAML file at lib/profiles/<name>.yaml to define a new tier. The validator (lib/validators/profile-validator.mjs) enforces:

  • Every phase_models[].phase must be a known phase enum: brief / research / plan / execute / review / continue
  • Every phase_models[].model must match ^(opus|sonnet)(\b|-).* or one of the canonical short names
  • All six phases must be present (no partial profiles)

The three built-in names (economy, balanced, premium) resolve to their bundled yaml first — findProfilePath() returns the built-in before consulting voyage-profiles/, so a same-named custom file is ignored and cannot shadow a built-in. To customize, give your profile a new name and reference it via --profile <new-name> or VOYAGE_PROFILE=<new-name>.

Example custom profile

# lib/profiles/critical.yaml — opus everywhere except continue
phase_models:
  - phase: brief
    model: opus
  - phase: research
    model: opus
  - phase: plan
    model: opus
  - phase: execute
    model: opus
  - phase: review
    model: opus
  - phase: continue
    model: sonnet

Validate with: node lib/validators/profile-validator.mjs --json lib/profiles/critical.yaml

Drift detection

In --strict mode, plan-validator.mjs emits a MANIFEST_PROFILE_DRIFT warning when the plan-level profile: differs from any step manifest's profile_used. The warning is a signal, not a failure — the plan remains valid: true. This catches:

  • Manual edits where an operator changed a single step's profile
  • Resume from a partial run where the previous session used a different tier
  • Copy-paste errors when stitching plan fragments

To suppress the warning intentionally (e.g. when a critical step genuinely needs a higher tier), document the override in the step's prose and re-run with --soft to validate without strict-mode warnings.

Cost estimation

Disclaimer: the table below is an anslag, not a contractual SLA. Real cost depends on context size, agent-swarm cardinality, tool-use density, and Claude Code billing schedule. Treat these as rough order-of-magnitude.

Profile Brief Research Plan Execute Review Total
economy $0.100.50 $0.502.00 $0.502.00 $1.005.00 $0.201.00 $210
balanced $0.100.50 $0.502.00 $1.004.00 $1.005.00 $0.502.00 $314
premium $0.502.00 $0.502.00 $1.004.00 $1.005.00 $0.502.00 $415

Numbers are per full pipeline run (brief + research + plan + execute + review) on a moderate-complexity task. Numbers scale roughly linearly with the size of the resulting plan (10 steps ≈ baseline; 30 steps ≈ 3× the execute column).

Per-profile actuals are emitted to JSONL stats — pipe them through the OTel export (docs/observability.md) to get real cost-attribution graphs in Grafana. Replace the table above with your own measured numbers after ≥ 3 runs of each profile.

Deferred to v4.2

  • balanced.external_research_enabled operator-override — v4.1 omits this per scope-guardian SG2. v4.2 may add an opt-in flag to enable external research agents in the balanced tier without forcing premium.
  • Empirical Jaccard re-calibration — parked-synthetic fixtures in v4.1 use a 0.55 conservative starting threshold. v4.2 plans an empirical re-run with $60-120 LLM budget to derive a calibrated threshold from real economy-vs-premium plan pairs.
  • ROUGE-L + char-4gram MinHash as primary/secondary cross-tier gates per research/02 Recommendation #7. Jaccard remains the gate in v4.1; v4.2 may layer ROUGE-L on top.

See also