chore(cleanup): R-b R3 — profiles, phase signals and the effort dialog removed, one fixed path per command
The four profiles, the resolver, the profile validator and docs/profiles.md go; /trekbrief Phase 3.5 and the brief's phase_signals checks go (an older brief's key is ignored); MANIFEST_PROFILE_DRIFT and profile_used go. Every Profile, Composition rule, Sequencing gate and High-effort section leaves the commands. Decision 209: /trekresearch runs the full swarm with contrarian-researcher as wave 2 every run; /trekreview and the coordinator run all four passes with no high-effort normalization. Voyage agents are spawned with no model (their own model: opus applies); the two built-in spawns pass model "opus". --profile stays in the parser as a retired flag that swallows its value. §Model & effort moves to docs/architecture.md; the sequencing-gate eval case goes. Files removed: 44 (43 from the R3 list + tests/commands/trekreview.test.mjs, whose every test pinned removed text). Files edited: 43. Tests: 2467 (2466 pass / 0 fail / 1 skipped) before, 2309 (2309 pass / 0 fail / 0 skipped) after. Durable check: all three groups green, none pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
32621dcb63
commit
2a35d067d9
87 changed files with 225 additions and 4967 deletions
|
|
@ -71,8 +71,6 @@ Every validator exposes a CLI: `node lib/validators/<name>.mjs --json <path>` re
|
|||
| `interview_turns` | number | optional | ≥ 0 | |
|
||||
| `source` | string | optional | `interview \| manual` | |
|
||||
| `brief_quality` | string | optional | `complete \| partial` | Set when iteration cap is hit |
|
||||
| `phase_signals` | list | optional (v5.1+) | list of `{phase, effort?, model?}` entries | Per-phase effort + model commitment from Phase 3.5. Mutually exclusive with `phase_signals_partial`. |
|
||||
| `phase_signals_partial` | bool | optional (v5.1+) | `true` | Force-stop record from Phase 3.5. Mutually exclusive with `phase_signals`. |
|
||||
| `framing` | string | **required at ≥ 2.2** (v5.5) | `preserve \| refine \| replace \| new-direction` | How this brief relates to prior operator intent. Enum-checked on any version when present; missing → `BRIEF_MISSING_FRAMING` at `brief_version ≥ 2.2`. Layer 1 of the framing-alignment defense. |
|
||||
| `intent_approved_hash` | string | optional in the schema; **required by `/trekplan`** (veikart steg 1) | `"sha256:<64 hex>"` | Hash over the normalized `## Intent` + `## Goal`. Written only by `lib/validators/intent-approval.mjs --stamp`, which `/trekbrief` runs on the operator's explicit "Approve" (Phase 4h, or `--approve <project-dir \| brief-file>`). |
|
||||
| `intent_approved_at` | string | optional | ISO-8601 | When the stamp was written. Informational; the gate reads the hash. |
|
||||
|
|
@ -80,6 +78,8 @@ Every validator exposes a CLI: `node lib/validators/<name>.mjs --json <path>` re
|
|||
| `ceremony` | string | optional (K1) | `small \| bounded \| architectural` | The brief's size class: sets `/trekbrief`'s question budget and review cap, and what downstream phases scale to. **Absent (or unreadable) = `architectural`**, the heaviest, so another producer's brief is never treated lighter by accident. Enum-checked when present (`BRIEF_INVALID_CEREMONY`). Read it through `briefCeremony(fm)` in `brief-validator.mjs`. |
|
||||
| `artifact_store` | string | optional | `git \| local` | Whether the brief and plan are committed to the target repo (`git`) or kept out of git through `.git/info/exclude` (`local`). The approval log is committed either way. **Absent = `local`**: nothing is published without the operator's yes. Enum-checked when present (`BRIEF_INVALID_ARTIFACT_STORE`). |
|
||||
|
||||
An older brief's `phase_signals` key is ignored.
|
||||
|
||||
**Body invariants:** required sections (validator runs in strict mode at write-time, soft mode at read-time):
|
||||
- `## TL;DR` — **required at `brief_version ≥ 2.2`** (v5.5); ≤ 5 content lines (soft cap → `BRIEF_TLDR_TOO_LONG` warning). Layer 3 of the framing-alignment defense.
|
||||
- `## Intent`
|
||||
|
|
@ -97,16 +97,15 @@ Optional but standard sections: `## Non-Goals`, `## Constraints`, `## Preference
|
|||
| Type discriminator | every read | `type === "trekbrief"` |
|
||||
| Status enum | every read | `research_status ∈ allowed values` |
|
||||
| **State machine** | every read | `research_topics > 0 && research_status === "skipped"` requires `brief_quality === "partial"` |
|
||||
| **v5.1 sequencing gate** | every read | `brief_version ≥ 2.1` requires `phase_signals` (list) OR `phase_signals_partial: true` — error `BRIEF_V51_MISSING_SIGNALS` on miss. Validator-only enforcement; commands surface, don't re-enforce. |
|
||||
| **v5.5 framing gate** | every read | `framing` enum-checked on any version when present (`BRIEF_INVALID_FRAMING`); at `brief_version ≥ 2.2` a missing `framing` → `BRIEF_MISSING_FRAMING` and a missing `## TL;DR` → `BRIEF_MISSING_SECTION` (strict) / warning (soft). `trekreview` briefs are exempt. |
|
||||
| Body sections | strict only | All `BRIEF_BODY_SECTIONS` present (`## TL;DR` added at ≥ 2.2) |
|
||||
| Runnable criteria | every read | A `## Success Criteria` bullet whose first backticked span is a command the review's criteria runner never runs (the product's own binary, `jq`, `grep`, a pipe), or whose first span is not a command while a later span is one (the runner reads only the first, voyage-lekerepo trial 5) → warning `BRIEF_SC_NOT_RUNNABLE`, never an error: a criterion a human judges stays allowed. Prose-only criteria, also those that only name a flag or a path, are not flagged. `trekreview` briefs are exempt. No schema change. Indented sub-bullets belong to the criterion above them (counted, never criteria of their own); a criterion with sub-points and no command → warning `BRIEF_SC_SUBPOINTS`. A brief whose Constraints or NFRs require bash 3.2 and a criterion that runs plain `bash` → warning `BRIEF_SC_BASH_NOT_PINNED` (use `/bin/bash`). |
|
||||
|
||||
**State machine** detail: a brief that says it has research topics but skipped them must explicitly admit it (via `brief_quality: partial`). This is the most common failure mode the validator catches.
|
||||
|
||||
**Versioning:** the `2.1` schema axis (v5.1 — adds optional `phase_signals` + `phase_signals_partial`; current is `2.2`, see the next paragraph). The forward-compat policy in `brief-validator.mjs` header still applies: unknown frontmatter keys flow through silently, so a `2.1` brief still validates against pre-v5.1 consumers. The version bump exists because v2.1 activates the **version-conditional sequencing gate** (above) — the only check in the validator that triggers on `brief_version` rather than field-presence. There are no live `1.x` briefs; remove legacy paths in next major. The v5.5.0 contract formalization **established `2.1` as the public-contract baseline** (see the PUBLIC CONTRACT callout under the Handover 1 heading): per the S3 effort-axis decision, `phase_signals` stays **optional**, and the v2.1 sequencing gate (`phase_signals` **or** `phase_signals_partial`) is the stability mechanism. Promoting `phase_signals` to required would be a future breaking change under the protocol above — explicitly *not* part of the v5.5.0 formalization.
|
||||
**Versioning:** current is `2.2`, see the next paragraph. The forward-compat policy in `brief-validator.mjs` header still applies: unknown frontmatter keys flow through silently. There are no live `1.x` briefs; remove legacy paths in next major. The v5.5.0 contract formalization **established `2.1` as the public-contract baseline** (see the PUBLIC CONTRACT callout under the Handover 1 heading).
|
||||
|
||||
**v5.5 → `2.2` (framing enforcement).** `2.2` adds two **required-at-2.2** elements — the `framing` enum field and the `## TL;DR` body section — gated identically to the v2.1 mechanism: the new requirements fire only on `brief_version ≥ 2.2`, so every existing `2.0` / `2.1` brief still validates (forward- and backward-compatible). Because adding required elements is a breaking change for any producer that declares `2.2`, this is a controlled version bump under the breaking-change protocol: downstream producers (e.g. a Tier-2 per-app producer) that emit `brief_version: "2.2"` MUST also emit `framing` + `## TL;DR`. The framing enum is additionally enforced on *any* version when the field is present (`BRIEF_INVALID_FRAMING`). The three framing-alignment layers (framing field, `brief-reviewer` memory-alignment dimension, obligatory TL;DR) implement the `CLAUDE.md` cross-cutting invariant. Note: the *plugin* version bump + CHANGELOG entry for this schema change land at the coordinated release (matrix §S10), separate from this schema axis.
|
||||
**v5.5 → `2.2` (framing enforcement).** `2.2` adds two **required-at-2.2** elements — the `framing` enum field and the `## TL;DR` body section — gated on `brief_version`: the new requirements fire only on `brief_version ≥ 2.2`, so every existing `2.0` / `2.1` brief still validates (forward- and backward-compatible). Because adding required elements is a breaking change for any producer that declares `2.2`, this is a controlled version bump under the breaking-change protocol: downstream producers (e.g. a Tier-2 per-app producer) that emit `brief_version: "2.2"` MUST also emit `framing` + `## TL;DR`. The framing enum is additionally enforced on *any* version when the field is present (`BRIEF_INVALID_FRAMING`). The three framing-alignment layers (framing field, `brief-reviewer` memory-alignment dimension, obligatory TL;DR) implement the `CLAUDE.md` cross-cutting invariant. Note: the *plugin* version bump + CHANGELOG entry for this schema change land at the coordinated release (matrix §S10), separate from this schema axis.
|
||||
|
||||
**Pre-2.2 briefs receive zero framing enforcement (producer-elective defense).** The framing-alignment defense is gated at `brief_version ≥ 2.2`, so a brief declaring `2.0` or `2.1` gets **none** of it: `framing` is optional and a missing value is not an error, the `## TL;DR` section is not required, and the `brief-reviewer` memory-alignment dimension scores N/A. The backward-compatibility this buys is deliberate, but it also means the framing defense is **producer-elective**: any producer can sidestep the entire defense — deliberately or by shipping a legacy template — simply by declaring `brief_version: "2.1"`, and the pipeline raises no signal by default. This is a documented property of the contract, not a bug. Two remedies close it for a given consumer: (1) require upstream producers to emit `brief_version: "2.2"` (which forces `framing` + `## TL;DR`); or (2) pass the opt-in **`--min-brief-version <ver>`** flag to `/trekplan` or `/trekresearch` (forwarded to the validator as `--min-version`), which raises a `BRIEF_VERSION_BELOW_MINIMUM` **warning** — never a block — when a brief declares a version below the floor. The flag defaults to off, so the N-1 compatibility window for `2.0`/`2.1` briefs is preserved unless a consumer explicitly opts into the stricter floor.
|
||||
|
||||
|
|
@ -124,24 +123,10 @@ Optional but standard sections: `## Non-Goals`, `## Constraints`, `## Preference
|
|||
- `BRIEF_MISSING_FIELD` → strict halt; soft-mode warning
|
||||
- `BRIEF_STATE_INCOHERENT` → strict halt; soft-mode warning (incoherence will haunt downstream agents)
|
||||
- `BRIEF_MISSING_SECTION` → strict halt; soft-mode warning
|
||||
- `BRIEF_V51_MISSING_SIGNALS` → strict halt (v5.1+ sequencing gate); soft-mode warning. Commands surface a friendly hint pointing back to `/trekbrief` (Phase 3.5).
|
||||
- `BRIEF_INVALID_PHASE_SIGNALS` → strict halt; phase_signals must be a list of `{phase, effort?, model?}` entries.
|
||||
- `BRIEF_INVALID_PHASE_SIGNAL_PHASE` → strict halt; phase ∉ `[research, plan, execute, review]`.
|
||||
- `BRIEF_INVALID_EFFORT` → strict halt; effort ∉ `[low, standard, high]`.
|
||||
- `BRIEF_INVALID_MODEL` → strict halt; model ∉ `BASE_ALLOWED_MODELS` (currently `[sonnet, opus, fable]`).
|
||||
- `BRIEF_SIGNALS_MUTUALLY_EXCLUSIVE` → strict halt; cannot set both `phase_signals` and `phase_signals_partial: true`.
|
||||
- `BRIEF_SC_NOT_RUNNABLE` → warning in both modes; `/trekbrief` names each one and offers a script under `tests/` the criterion runs (`bash tests/<script>.sh`).
|
||||
- `BRIEF_SC_SUBPOINTS` → warning in both modes; `/trekbrief` offers one script that checks all sub-points, or one criterion per sub-point.
|
||||
- `BRIEF_SC_BASH_NOT_PINNED` → warning in both modes; `/trekbrief` offers `/bin/bash tests/<script>.sh` so a bash 3.2 requirement is measured under the system bash.
|
||||
|
||||
**Compatibility direction of the v5.9 allowlist widening (`fable`):** enum
|
||||
widening is safe for new readers of old data, not old readers of new data.
|
||||
Existing sonnet/opus briefs stay valid under the v5.9+ validator (non-breaking,
|
||||
no `brief_version` bump — value-space extension, not a schema change). The
|
||||
reverse does NOT hold: a fable-bearing brief REQUIRES a v5.9+ validator — an
|
||||
older cached brief-validator (e.g. a stale v5.8 marketplace clone) rejects it
|
||||
with `BRIEF_INVALID_MODEL`.
|
||||
|
||||
---
|
||||
|
||||
## Handover 2 — research/*.md → plan
|
||||
|
|
|
|||
|
|
@ -34,9 +34,7 @@ Doc-consistency test at `tests/lib/doc-consistency.test.mjs` pins agent-table co
|
|||
|
||||
## Architecture
|
||||
|
||||
**Brief:** 7-phase workflow: Parse mode → Create project dir → Phase 3 completeness loop (section-driven, no question cap) → Phase 3.5 per-phase effort dialog (v5.1) → Phase 4 draft/review/revise with `brief-reviewer` as stop-gate (max 3 iterations; gate = all dimensions ≥ 4 and research plan = 5) → Finalize (`brief.md` on pass, or `brief_quality: partial` on cap/force-stop) → Manual/auto opt-in. Always interactive. Auto mode runs research + plan inline in the main context (v2.4.0).
|
||||
|
||||
**Phase 3.5 (v5.1) — adaptive-depth signals:** Between Phase 3 completeness exit and Phase 4 draft, the operator commits an effort level (`low | standard | high`) and an optional `model` (`sonnet | opus | fable`) per downstream phase (`research`, `plan`, `execute`, `review`) via 4 tier-coupled `AskUserQuestion` calls. The choices land in `brief.md` frontmatter as `phase_signals:` (a list of `{phase, effort?, model?}` entries) when committed, or `phase_signals_partial: true` when the operator force-stops. `brief_version: 2.1` activates the **sequencing gate**: validator emits `BRIEF_V51_MISSING_SIGNALS` if a 2.1-versioned brief lacks both fields. Downstream commands surface a friendly hint pointing back to `/trekbrief` — enforcement is validator-only. Composition is documented prose in each downstream command's `## Composition rule (v5.1)` section: `brief.phase_signals[phase] > profile.phase_models[phase]`. The brief signal wins per-phase when present; the profile fills gaps. `effort == low` activates each command's existing `--quick`-equivalent code-path (`/trekexecute` low effort = one session at a time). High-effort behavior is deferred to v5.1.1 per brief Non-Goal.
|
||||
**Brief:** 7-phase workflow: Parse mode → Create project dir → Phase 3 completeness loop (section-driven, no question cap) → Phase 4 draft/review/revise with `brief-reviewer` as stop-gate (max 3 iterations; gate = all dimensions ≥ 4 and research plan = 5) → Finalize (`brief.md` on pass, or `brief_quality: partial` on cap/force-stop) → Manual/auto opt-in. Always interactive. Auto mode runs research + plan inline in the main context (v2.4.0).
|
||||
|
||||
**Research:** Foreground workflow (v2.4.0): Parse mode → Interview → Parallel research swarm (5 local + 4 external + 1 bridge, spawned from main context) → Follow-ups → Triangulation → Synthesis + brief. With `--project`, writes to `{dir}/research/NN-slug.md`.
|
||||
|
||||
|
|
@ -97,6 +95,47 @@ Which native Claude Code primitive each pipeline step runs on today, and the alt
|
|||
|
||||
**Legend:** *production* = wired and active · *not wired* = considered, deferred (delegated orchestrator, the `AskUserQuestion` brief engine).
|
||||
|
||||
## Model & effort
|
||||
|
||||
`opus`, `sonnet`, and `fable` are model **aliases**, not pinned ids. On the
|
||||
Anthropic API (verified 2026-10-02 against the Claude Code model-config docs)
|
||||
the `opus` alias resolves to **Opus 5.5** and `sonnet` to **Sonnet 5.5**, both
|
||||
with default reasoning effort **`medium`**; `fable` resolves to **Fable 5.1**
|
||||
(the most capable model in Claude Code), whose default reasoning effort is
|
||||
**`high`**. Other providers resolve `opus` and `sonnet` to other versions.
|
||||
|
||||
**Reasoning effort inherits from the session.** Fable 5.1's default reasoning
|
||||
effort is `high`, NOT xhigh, and Claude Code saves effort per model, so a level
|
||||
saved for one model does not carry to another. To run Fable 5.1 at xhigh,
|
||||
choose it explicitly: `/effort xhigh`, `--effort xhigh`, or
|
||||
`CLAUDE_CODE_EFFORT_LEVEL`.
|
||||
|
||||
**Native `effort:` on agents.** Voyage sets the reasoning axis statically on
|
||||
selected agents, overriding the session level:
|
||||
|
||||
- **Nine agents pin `high`:** the retrieval agents `task-finder`,
|
||||
`git-historian`, `dependency-tracer`, `architecture-mapper`, the
|
||||
adversarial-reasoning agents `plan-critic`, `risk-assessor`,
|
||||
`contrarian-researcher`, `review-coordinator`, and `/trekexecute`'s step
|
||||
helper `step-implementer`. No agent pins below `high`
|
||||
(operator rule, 2026-10-05: standard is Opus 5.5 at effort High).
|
||||
- **All other agents:** unset → inherits the session's effort level (a session
|
||||
that nothing sets runs at its model's default — `medium` on Opus 5.5).
|
||||
|
||||
**Every agent is pinned `model: opus`.** The pin is set in each agent's
|
||||
frontmatter (operator decision, commit `40d8742`). The operator wants Opus on
|
||||
all Voyage work and accepted the roughly fivefold sub-agent cost against
|
||||
Sonnet. The glue, mechanical, retrieval and dormant roles were reconsidered
|
||||
for a Sonnet downgrade (operator, 2026-06-20) and kept on Opus: the pin stays
|
||||
firm.
|
||||
|
||||
Native-effort precedence (harness): env `CLAUDE_CODE_EFFORT_LEVEL` > frontmatter
|
||||
`effort:` > session setting > model default, and a `maxEffortLevel` setting or
|
||||
an organization effort cap still limits the result. `MAX_THINKING_TOKENS=0` has
|
||||
no effect on Opus 5.5, Sonnet 5.5 or the Fable models: thinking cannot be turned
|
||||
off there. `availableModels` restricts which models can be selected — it does
|
||||
**not** bound effort.
|
||||
|
||||
## State
|
||||
|
||||
All artifacts in one project directory (default):
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ Per-command flag tables, imported from `CLAUDE.md` via pointer.
|
|||
| _(default)_ | Question round sized by class (`small` / `bounded` / `architectural`), brief-review gate, approval → brief.md with research plan |
|
||||
| `--quick` | Proposes `small` as the class (still said aloud, overridable, raised when the task proves bigger) → brief.md with research plan |
|
||||
| `--gates [true\|false\|closed\|open]` | (v3.4.0) Autonomy flag: bare, `true` or `closed` = on; `false` or `open` = off; any other next token is not its value. See `## Autonomy mode` in `docs/operations.md`. |
|
||||
| `--profile <name>` | (v4.1.0) Model profile: `economy` / `balanced` / `premium` / `fable` / `<custom>`. Sets `phase_models` for the brief phase. See `## Profile system` in `docs/operations.md`. |
|
||||
| `--approve <project-dir \| brief-file>` | (veikart steg 1) No interview: show the existing brief's `## Intent` + `## Goal` verbatim, ask the operator to approve, and on "Approve" stamp `intent_approved_hash` + `intent_approved_at`. The remedy `/trekplan` names when it halts on `BRIEF_INTENT_NOT_APPROVED` / `BRIEF_INTENT_APPROVAL_STALE`. |
|
||||
|
||||
Always interactive. Phase 3 puts the task in a size class (`ceremony:`, K1; heaviest in doubt, said aloud, overridable, only moved up) and asks one round of questions within the class budget (`small` 4, `bounded` 8, `architectural` 12 per round), recommendation first, facts looked up instead of asked, a visible Deferred list; it also asks where the brief is stored (`artifact_store: git | local`). Phase 4 runs a `brief-reviewer` stop-gate with 1 / 2 / 3 review iterations by class. Phase 4h takes only an explicit "Approve" («høres bra ut» and an empty answer are refused by `lib/util/approval-log.mjs answer`), stamps the brief, appends the approval to the target repo's log (`approval-log.mjs append`, K2) and commits it (`lib/util/artifact-commit.mjs`: the log always, the brief when `git`). After that, asks the user to choose manual (print commands) or auto (Claude runs research + plan in foreground).
|
||||
|
|
@ -26,7 +25,6 @@ Always interactive. Phase 3 puts the task in a size class (`ceremony:`, K1; heav
|
|||
| `--fg` | No-op alias (foreground is default since v2.4.0) |
|
||||
| `--gates [true\|false\|closed\|open]` | (v3.4.0) Autonomy flag: bare, `true` or `closed` = on; `false` or `open` = off; any other next token is not its value. See `## Autonomy mode` in `docs/operations.md`. |
|
||||
| `--min-brief-version <ver>` | (S18) Warn — never block — if an attached `--project` brief declares a version below `<ver>` (e.g. `2.2`), i.e. sidesteps framing enforcement |
|
||||
| `--profile <name>` | (v4.1.0) Model profile for the research phase. |
|
||||
|
||||
Flags combine: `--project <dir> --local`, `--external --quick`.
|
||||
|
||||
|
|
@ -43,7 +41,6 @@ Flags combine: `--project <dir> --local`, `--external --quick`.
|
|||
| `--export headless <plan>` | Legacy alias for `--decompose` — the only remaining export format (the `pr` / `issue` / `markdown` variants were removed; Claude reformats a plan ad-hoc on request) |
|
||||
| `--decompose <plan>` | Split plan into self-contained session specs + `orders.md` (one starter line per session) |
|
||||
| `--gates [true\|false\|closed\|open]` | (v3.4.0) Autonomy flag: bare, `true` or `closed` = on; `false` or `open` = off; any other next token is not its value. See `## Autonomy mode` in `docs/operations.md`. |
|
||||
| `--profile <name>` | (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.
|
||||
|
||||
|
|
@ -64,7 +61,6 @@ If `{project_dir}/architecture/overview.md` exists (typically produced by an opt
|
|||
| `--fg` | Force foreground — run all steps sequentially, ignore Execution Strategy |
|
||||
| `--session N` | Execute only session N from plan's Execution Strategy |
|
||||
| `--gates [true\|false\|closed\|open]` | (v3.4.0) Autonomy flag: bare, `true` or `closed` = on; `false` or `open` = off; any other next token is not its value. See `## Autonomy mode` in `docs/operations.md`. `/trekexecute` accepts the flag and pauses on nothing; it adds no question of its own before a merge: the guard asks there (operator decision 2026-10-08). |
|
||||
| `--profile <name>` | (v4.1.0) Profile for this run's resolver; the step helper and the controller stay on opus. Inherited from plan.md frontmatter `profile:` if present. |
|
||||
|
||||
Every mode that executes refuses a plan whose approval in the approval log does not cover its current sha256 (K2). A run ends with the review it starts by itself (`/simplify` → `/trekreview` → verdict gate); a BLOCK or an undecided verdict keeps the merge into main closed. `MAX_REVIEW_ROUNDS` in `lib/review/review-rounds.mjs` (3) caps the reviews per run; `/trekreview` refuses a fourth round.
|
||||
|
||||
|
|
@ -80,7 +76,6 @@ Every mode that executes refuses a plan whose approval in the approval log does
|
|||
| `--validate` | Schema-only check on existing `{dir}/review.md` plus the verdict gate. No LLM calls. A 1.0 review without `verdict:` fails here (it still seeds a plan in soft mode) |
|
||||
| `--dry-run` | Print discovered scope + triage map; skip writes |
|
||||
| `--fg` | No-op alias (foreground is default) |
|
||||
| `--profile <name>` | (v4.1.0) Model profile for the review phase. |
|
||||
|
||||
## /trekcontinue modes
|
||||
|
||||
|
|
@ -88,6 +83,5 @@ Every mode that executes refuses a plan whose approval in the approval log does
|
|||
|------|----------|
|
||||
| _(default)_ | Auto-discover active project's `.session-state.local.json` and resume |
|
||||
| `<project-dir>` | Resume the next session of an explicit project directory |
|
||||
| `--profile <name>` | (v4.1.0) Model profile for the resumed session. Inherited from the previous session's plan.md frontmatter when absent. |
|
||||
|
||||
The triage gate is deterministic — path-pattern classifier produces `{file → deep-review|summary-only|skip}`. Hard refuse-with-suggestion above 100 files / 100K diff tokens.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Voyage — Autonomy gates, profile system, observability
|
||||
# Voyage — Autonomy gates, observability
|
||||
|
||||
Imported from `CLAUDE.md` via pointer.
|
||||
|
||||
|
|
@ -22,30 +22,6 @@ Three architectural options were considered for the speedup work:
|
|||
|
||||
A revived Path C (post-v2.2.xxx) would require: (1) re-architecting tool-list to be identical across all wave children, (2) cache-telemetry analysis confirming the new fork-cache behaviour holds, (3) prompt-level deny re-enablement to compensate for tool scoping rollback.
|
||||
|
||||
## Profile system (`--profile`, v4.1.0)
|
||||
|
||||
Four built-in model profiles plus operator-defined `<custom>.yaml`. Each profile pins `phase_models` for the six pipeline phases (`brief`, `research`, `plan`, `execute`, `review`, `continue`). Profile is recorded in plan.md frontmatter as `profile: <name>`.
|
||||
|
||||
| Profile | Brief | Research | Plan | Execute | Review | Continue | Use case |
|
||||
|---------|-------|----------|------|---------|--------|----------|----------|
|
||||
| `economy` | sonnet | sonnet | sonnet | sonnet | sonnet | sonnet | ⚠ **Experimental** (uncalibrated Jaccard floor) — lowest cost; high-confidence small-scope tasks (operator-opt-in via `--profile economy`) |
|
||||
| `balanced` | sonnet | sonnet | opus | sonnet | opus | sonnet | Mixed — opus where reasoning depth pays off (operator-opt-in via `--profile balanced`) |
|
||||
| `premium` (default) | opus | opus | opus | opus | opus | opus | Maximum quality — Opus on every phase. Default since 2026-05-13 operator request; also the hardcoded resolver default returned by `resolveProfile()` in `lib/profiles/resolver.mjs` |
|
||||
| `fable` | fable | fable | fable | fable | fable | fable | Max quality — Fable 5.1 (the most capable model in Claude Code) on every phase (operator-opt-in via `--profile fable`); reasoning effort inherits from the session — see `docs/profiles.md` §Model & effort axes |
|
||||
|
||||
### Lookup 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
|
||||
4. Default `premium`
|
||||
|
||||
### Custom profiles
|
||||
|
||||
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 exactly match an entry in `BASE_ALLOWED_MODELS` (`['sonnet', 'opus', 'fable']`; `haiku` only with `VOYAGE_ALLOW_HAIKU=1`). `findProfilePath` (`lib/profiles/resolver.mjs`) resolves **built-in first** (`lib/profiles/<name>.yaml` for `economy`/`balanced`/`premium`/`fable`), 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.
|
||||
|
||||
## Observability
|
||||
|
||||
Claude Code's own OpenTelemetry (`CLAUDE_CODE_ENABLE_TELEMETRY`) gives tool durations, tokens and cost per agent and skill: see [Monitoring usage](https://code.claude.com/docs/en/monitoring-usage) (read 2026-11-07, Claude Code 2.1.319).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Prøvesett — Voyage's fixed test set as a plugin eval suite
|
||||
|
||||
**Status:** v2, eight cases. v1 (seven cases) first run **6 of 7**; v2 first run
|
||||
**Status:** seven cases: v2's eight, less the sequencing-gate case (v1 case 4), which
|
||||
went with the phase signals in cleanup R-b. v1 (seven cases) first run **6 of 7**; v2 first run
|
||||
**8 of 8** (both 2026-09-23, Claude Code 2.1.280). Each version's cases and
|
||||
expectations were committed *before* its first run; the run did not change them.
|
||||
Red is data here, not a defect in the suite. What v2 changed and why: § v2 below.
|
||||
|
|
@ -53,12 +54,12 @@ promises and ends in seconds. Nothing starts the `/trekplan` exploration swarm o
|
|||
| `plan-requires-brief` | `/trekplan` without a brief prints usage and stops | "A brief is required"; no Agent, no Write | pass |
|
||||
| `plan-project-not-initialized` | `/trekplan --project` on a missing folder stops before exploring | "project directory not initialized"; no Agent, no `plan.md` | pass |
|
||||
| `plan-rejects-unknown-export` | a removed export format is named and refused | "format 'pr' is not supported"; no Agent, no Write | pass |
|
||||
| `plan-halts-without-phase-signals` | a `brief_version` 2.1 brief without `phase_signals` halts at the sequencing gate | brief-validator runs, reply names `phase_signals`; no Agent, no `plan.md` | pass |
|
||||
| `review-requires-project` | `/trekreview` without `--project` refuses | "--project <dir> is required"; no Agent, no Write | **fail** (2 of 3 graders) |
|
||||
| `review-validate-flags-bad-finding-id` | **known-positive:** `--validate` fails a review whose finding ID is not 40-char hex, and names the rule | review-validator runs; `REVIEW_BAD_FINDING_ID` in the trace; reply says FAIL; no Agent, no Write | pass |
|
||||
| `review-validate-passes-clean-review` | **known-negative:** `--validate` passes a valid review and raises nothing | review-validator runs; reply says PASS; no `REVIEW_*` error code in the trace; no Agent, no Write | pass |
|
||||
|
||||
The v1 table above is kept as it was run. v2 rows and grader changes: § v2.
|
||||
The v1 table above is kept as it was run, less case 4 (the sequencing gate, pass),
|
||||
removed in cleanup R-b with the phase signals it tested. v2 rows and grader changes: § v2.
|
||||
|
||||
### The one red case (v1; fixed in v2, see § v2)
|
||||
|
||||
|
|
@ -99,7 +100,7 @@ Expectations committed in `3892a83` before the v2 run. Offline structure tests i
|
|||
|
||||
| Change | Why |
|
||||
|--------|-----|
|
||||
| **New case `plan-halts-without-intent-approval`**: a `brief_version` 2.1 brief *with* `phase_signals` and no `intent_approved_hash`. Graders: `gate-ran` (`intent-approval.mjs --check` in a Bash call), `names-code` (the gate's own JSON `code` for `BRIEF_INTENT_NOT_APPROVED` in the trace), `no-agent`, `no-plan-file` | Veikart steg 1's gate had no case. No v1 trace reached it: case 4 halts at the sequencing gate first |
|
||||
| **New case `plan-halts-without-intent-approval`**: a `brief_version` 2.1 brief with no `intent_approved_hash` (it carried phase signals until cleanup R-b). Graders: `gate-ran` (`intent-approval.mjs --check` in a Bash call), `names-code` (the gate's own JSON `code` for `BRIEF_INTENT_NOT_APPROVED` in the trace), `no-agent`, `no-plan-file` | Veikart steg 1's gate had no case. No v1 trace reached it: case 4 halts at the sequencing gate first |
|
||||
| **`review-requires-project`**: the arg parser got a CLI that checks `--project` itself and prints `Error: --project <dir> is required.` + usage (exit 1, code `ARG_REQUIRED_MISSING`). `trekreview.md` runs it with `$ARGUMENTS` and relays its stderr. The reply-regex grader `project-required` is replaced by `parser-ran` + `names-missing-project` (the parser's code in the trace, the same form as `names-rule`) | The fix this doc recommended for the red case. Also: the prose passed `"$@"`, which the Bash tool never has. The parser never ran (0 Bash calls in the case-5 traces), so the model composed the line from prose. That failed 2 of 10 on backticks |
|
||||
| `no-error-code` → `code\W{1,12}REVIEW_[A-Z_]+`, bound to the validator's JSON output | The listed codes missed `REVIEW_WRONG_TYPE` and `REVIEW_VERSION_FORMAT` |
|
||||
| `says-pass` / `says-fail` reject a preceding `NOT` and a longer word | Raw substrings: "did not PASS" passed `says-pass` |
|
||||
|
|
@ -265,7 +266,7 @@ From the plugin root:
|
|||
claude plugin eval . --trust-plugin --ablation none --runs 1 --scaffold --no-publish --allow-tools Bash Write
|
||||
```
|
||||
|
||||
- `--scaffold` runs each case's `scaffold.sh` as you, outside the sandbox. The four
|
||||
- `--scaffold` runs each case's `scaffold.sh` as you, outside the sandbox. The three
|
||||
scaffolds in this suite only write fixture files into the run's workspace.
|
||||
- `--allow-tools Bash Write` grants the tools the commands need (Bash runs under the OS
|
||||
sandbox). Write is granted so that the `no-write` and `no-plan-file` graders measure a
|
||||
|
|
@ -291,4 +292,4 @@ will sometimes stop a change that is innocent. That is the intended price. Movin
|
|||
into code removes the instability; editing the grader does not. v2 did the move: the
|
||||
parser now writes the line, and the grader reads the parser's code. One green run does
|
||||
not show the instability is gone. That takes more runs. § Stability has them:
|
||||
`review-requires-project` 5 of 5, and case 4 15 of 15 after its own fix.
|
||||
`review-requires-project` 5 of 5, and case 4 (removed in cleanup R-b) 15 of 15 after its own fix.
|
||||
|
|
|
|||
236
docs/profiles.md
236
docs/profiles.md
|
|
@ -1,236 +0,0 @@
|
|||
# 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
|
||||
|
||||
Four pre-defined tiers ship with the plugin (fable added in v5.9), located at
|
||||
`lib/profiles/{economy,balanced,premium,fable}.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) |
|
||||
| `fable` | fable | fable | fable | fable | fable | fable | Max quality — Fable 5.1 (the most capable model in Claude Code) on every phase; opt-in via `--profile fable`; reasoning effort inherits from the session (see Model & effort axes) |
|
||||
|
||||
`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. Step up to `--profile fable` (Fable 5.1 on every phase) when
|
||||
maximum quality is wanted end-to-end and cost is not a constraint.
|
||||
|
||||
`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`, `sonnet`, and `fable` are model **aliases**, not pinned ids. On the
|
||||
Anthropic API (verified 2026-10-02 against the Claude Code model-config docs)
|
||||
the `opus` alias resolves to **Opus 5.5** and `sonnet` to **Sonnet 5.5**, both
|
||||
with default reasoning effort **`medium`**; `fable` resolves to **Fable 5.1**
|
||||
(the most capable model in Claude Code), whose default reasoning effort is
|
||||
**`high`**. Other providers resolve `opus` and `sonnet` to other versions. The
|
||||
profile table above selects *which alias* runs each phase — it does not touch
|
||||
reasoning effort.
|
||||
|
||||
**Reasoning effort inherits from the session.** Voyage effort (orchestration
|
||||
shape — which agents/passes run) and model reasoning effort are different
|
||||
axes. Fable 5.1's default reasoning effort is `high`, NOT xhigh, and Claude
|
||||
Code saves effort per model, so a level saved for one model does not carry to
|
||||
another. To run the fable tier at xhigh, choose it explicitly: `/effort xhigh`,
|
||||
`--effort xhigh`, or `CLAUDE_CODE_EFFORT_LEVEL`.
|
||||
|
||||
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','fable']`). It never emits
|
||||
native `effort:`.
|
||||
|
||||
**Native `effort:` on agents.** Voyage sets the reasoning axis statically on
|
||||
selected agents, overriding the session level:
|
||||
|
||||
- **Nine agents pin `high`:** the retrieval agents `task-finder`,
|
||||
`git-historian`, `dependency-tracer`, `architecture-mapper`, the
|
||||
adversarial-reasoning agents `plan-critic`, `risk-assessor`,
|
||||
`contrarian-researcher`, `review-coordinator`, and `/trekexecute`'s step
|
||||
helper `step-implementer`. No agent pins below `high`
|
||||
(operator rule, 2026-10-05: standard is Opus 5.5 at effort High).
|
||||
- **All other agents:** unset → inherits the session's effort level (a session
|
||||
that nothing sets runs at its model's default — `medium` on Opus 5.5).
|
||||
|
||||
**Every agent is pinned `model: opus`.** The pin is set in each agent's
|
||||
frontmatter (operator decision, commit `40d8742`), because the profile
|
||||
resolver does not reach sub-agents: the profile picks the model for the
|
||||
phases, the frontmatter for the agents. The operator wants Opus on all Voyage
|
||||
work and accepted the roughly fivefold sub-agent cost against Sonnet. The
|
||||
glue, mechanical, retrieval and dormant roles were reconsidered for a Sonnet
|
||||
downgrade (operator, 2026-06-20) and kept on Opus: the pin stays firm.
|
||||
|
||||
Native-effort precedence (harness): env `CLAUDE_CODE_EFFORT_LEVEL` > frontmatter
|
||||
`effort:` > session setting > model default, and a `maxEffortLevel` setting or
|
||||
an organization effort cap still limits the result. `MAX_THINKING_TOKENS=0` has
|
||||
no effect on Opus 5.5, Sonnet 5.5 or the Fable models: thinking cannot be turned
|
||||
off there. `availableModels` restricts which models can be selected — 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 plan-file fields for the resolved value:
|
||||
|
||||
- Plan-file frontmatter `profile: <name>` and `phase_models: [...]`
|
||||
|
||||
## Custom profiles
|
||||
|
||||
Drop a YAML file at `voyage-profiles/<name>.yaml` in the repo root, or at
|
||||
`~/.claude/voyage-profiles/<name>.yaml`, to define a new tier (the repo root
|
||||
is tried first). `lib/profiles/` holds only the four built-ins; a custom file
|
||||
placed there is never found.
|
||||
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 exactly match an entry in
|
||||
`BASE_ALLOWED_MODELS` (`['sonnet', 'opus', 'fable']` in
|
||||
`lib/validators/profile-validator.mjs`; `haiku` only with
|
||||
`VOYAGE_ALLOW_HAIKU=1`)
|
||||
- All six phases must be present (no partial profiles)
|
||||
|
||||
The four built-in names (`economy`, `balanced`, `premium`, `fable`) 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
|
||||
|
||||
```yaml
|
||||
# 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.10–0.50 | $0.50–2.00 | $0.50–2.00 | $1.00–5.00 | $0.20–1.00 | **$2–10** |
|
||||
| `balanced` | $0.10–0.50 | $0.50–2.00 | $1.00–4.00 | $1.00–5.00 | $0.50–2.00 | **$3–14** |
|
||||
| `premium` | $0.50–2.00 | $0.50–2.00 | $1.00–4.00 | $1.00–5.00 | $0.50–2.00 | **$4–15** |
|
||||
|
||||
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).
|
||||
|
||||
The stats records carry no profile field, so they cannot split cost by
|
||||
profile. 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
|
||||
|
||||
- [`README.md` § Profile system](../README.md) — top-level overview
|
||||
- [`CLAUDE.md` § Profile system](../CLAUDE.md) — internal reference
|
||||
- [`tests/synthetic/profile-jaccard-calibration.md`](../tests/synthetic/profile-jaccard-calibration.md)
|
||||
— calibration status and threshold rationale
|
||||
- [`lib/profiles/`](../lib/profiles/) — built-in profile YAMLs
|
||||
- [`lib/validators/profile-validator.mjs`](../lib/validators/profile-validator.mjs)
|
||||
— schema validator with CLI shim
|
||||
Loading…
Add table
Add a link
Reference in a new issue