The progress file /trekexecute's prose described did not pass the command's own validator: run status in-progress and no partial, no plan_version (required), step status running and passed. Measured on the 4 real progress files: 3 used passed, 2 failed on plan_version. The prose now speaks the validator's vocabulary, site by site: schema (plan_version = the value Phase 2 parsed; run status in_progress|completed|failed|stopped|partial), fresh-mode warning, both resume rules, step start in_progress, step finish completed, the escalation staging rule, the Phase 7.5 commit count (status=completed - left alone, every successful run would read as drift and be overridden to partial) and the final write (adds partial; a sandbox-blocked run writes stopped, report result blocked). Untouched on purpose: plan_verification.status, session-state / NEXT-SESSION-PROMPT status, stats and report result, the tolerant session-orders reader list, Phase 2.6's running state.
Valgt: tolerate a legacy passed on resume (one sentence after each resume rule) because Voyage is a public plugin and an in-flight run written under the old prose would otherwise re-execute finished steps. The validator gets no alias. Valgt: fresh mode also warns for stopped and partial - both are resumable, so they now get the --resume hint instead of a silent overwrite (intended behaviour change).
Red: 3 of 5 new tests fail on the pre-fix text - SC4 (documented progress file validates 0/0 per run status), SC5 (offenders at trekexecute.md 1011, 1055, 1062, 1164, 1169, 1326, 1352, 1489), the legacy-sentence count. Regression guard and known-positive control green on arrival.
Verify 125/125 (trekexecute-progress-schema, trekexecute, session-orders, criteria-runner, progress-validator). Suite 1388 (1386/0/2).
Voyage order 20261005T104513Z-1250514346, plan step 4/5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 9 said 'append to ${CLAUDE_PLUGIN_DATA}/trekexecute-stats.jsonl; if it is not set, skip silently' - the Bash tool env never carries it. It now runs stats-append.mjs trekexecute with the record on stdin, the /trekbrief Phase 7 shape, and reports a written:false. The gates_mode_flag_override record was prose with no writer; it now has an event-emit block (fixed literal payload: --gates is a boolean flag) and a documented shape {ts, event, known_event, payload:{flag, signal_effort}}. Phase 8's three event blocks spliced ${PLAN_PATH} (set in an earlier Bash call that does not survive) and ${WAVE_COUNT} (never assigned) into a double-quoted payload, so a literal run printed payload-not-json, and the decline reason was operator free text in a shell argument. Payloads are now single-quoted with {plan-path} / {wave-count} placeholders and the literal label hold-for-review; each call runs on its own and a written:false is printed and passed. docs/architecture.md and the jsonl-schemas rows (writer, measured line_refs) follow.
Red: 7 of 7 new tests fail on the pre-fix text (Phase 9 writer + no 'skip silently', Phase 9 record lands, no bare ${CLAUDE_PLUGIN_DATA}/...jsonl target, no shell expansion in --payload, the three Phase 8 blocks land known events when run as written in a fresh shell, the written:false sentence, the override writer and shape).
Verify 198/198 (stats-landing, main-merge-gate, gates-flag-coverage, profile-stats-fields, plugin-root-resolution, doc-consistency, no-claude-code-launch). Suite 1383 (1381/0/2).
Voyage order 20261005T104513Z-1250514346, plan step 3/5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
event-emit returned {written:false, reason:'CLAUDE_PLUGIN_DATA unset'} whenever the harness did not export the variable - the normal case for the Bash tool - so /trekexecute's Phase 8 events never landed. It now resolves the directory through stats-append's resolveStatsDir (one resolver; opts.path still wins, so intent-approval is unchanged). The CLI uses the realpath isMain() guard (the file:// guard was a silent no-op under a symlink or a path with a space) and exits 1 on every written:false - usage error, payload-not-json, failed write - instead of always 0. KNOWN_EVENTS gains main-merge-approved, main-merge-declined and gates_mode_flag_override, which /trekexecute emits by design. Header, intent-approval docstring (comment only), docs/operations.md and the README autonomy sentence (wrong state names, 'records each transition') updated.
Red: 10 of 20 tests fail on the pre-fix code - 7 new (CLI lands with CLAUDE_PLUGIN_DATA empty / absent, unwritable target exit 1, usage error exit 1, symlink, space path, known events) and 3 inverted contracts. Regression guards (green on arrival): never throws when unwritable; no second copy of the fallback directory name.
Inverted (the contract this changes, not deleted): emit with no CLAUDE_PLUGIN_DATA (silent skip) -> lands under a pinned HOME; never throws when unwritable -> a genuinely unwritable target (env {} now resolves to the real home); resolveStatsPath({}) === null -> the fallback path; malformed --payload exit 0 -> exit 1.
Readers checked: otel-export keys on 'event', yardstick counts only user_input, cache-analyzer and research-loop-cap name event-emit only in comments. Verify 268/268 (stats-event-emit, intent-approval, doc-consistency, otel-export-validators, yardstick). Suite 1376 (1374/0/2); non-hook lines in the real trekexecute-stats.jsonl 60 before and after.
Voyage order 20261005T104513Z-1250514346, plan step 2/5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/trekexecute writes run status stopped (dirty-tree stop, entry-condition stop, escalation) and step status blocked (Step 0 sandbox sentinel); the validator rejected the first and warned on the second. Both are real states lib/util/session-orders.mjs already reads (ENDED_BAD), so the validator learns them. The step-status list is exported as PROGRESS_STEP_STATUSES (was an inline literal) so tests check prose against it instead of keeping a copy. docs/HANDOVER-CONTRACTS.md Handover 5 rows updated.
Red: 3 of 4 new tests fail on the pre-fix code (stopped run status, PROGRESS_STEP_STATUSES export, blocked step status). Regression guard (green on arrival): every run status but completed stays resumable.
progress-validator 16/16. Suite 1368 (1366/0/2).
Voyage order 20261005T104513Z-1250514346, plan step 1/5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Kildefiks C (e7ac34b..3f073b7) plus the /trekreview remediation test
(5329355). /trekreview verdict WARN (0 BLOCKER, 1 MAJOR: a missing test,
now added); operator approved the release 05.10 (decision 14).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/trekreview of e7ac34b..3f073b7 (WARN, 1 MAJOR, finding
986c939f93808a274b5e4ecd2c5318fd422a3be4): baseDir's accepting branch
was never exercised, though every production /trekbrief record carries
project_dir. One unit test (attributeOrder from a non-git parent with
projectDir inside it) and one end-to-end landing test (the Phase 7 line
with a record carrying project_dir).
Both pass on HEAD and both fail on the always-cwd mutant (measured,
then reverted). Suite 1364 (1362/0/2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/trekbrief Phase 7 says the writer adds order_id / order_claimed_at /
order_reason (never typed by the model) and that the yardstick joins use on
order_id; the fixture row lists them in `fields`, EXPORT_DENYLIST names them,
and its stale line_ref (657-672) now reads 961-976; the allowlist header
names them as dropped; docs/architecture.md Stats explains them.
/trekbrief --approve now runs Phase 7 after a successful stamp, with fixed
values (mode "approve", 0 turns, brief_quality/research_topics/auto_research
from the brief's frontmatter, auto_result "manual", intent_approved true).
Valgt fordi PM 04.10 (point 3): fix the code, not the criterion - the
approval must leave the trekbrief record. Measured hole: okf-wiki v1-k has
brief-approved 04.10 17:12Z and trekplan 17:29Z, but only a 03.10 trekbrief
record with intent_approved false. CLAUDE.md, README.md and
docs/command-modes.md say so. The manual path is unchanged.
npm test 1309 -> 1362 (1360 pass / 0 fail / 2 skip).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
order_id / order_claimed_at / order_reason on the five surfaces: (1) record
format = the writer (pinned in stats-landing), (2) Phase 7 prose with "the
writer adds", (3) the field-allowlist header names them as dropped and
TREKBRIEF_ALLOWED leaves them out, (4) the trekbrief-stats fixture row's
`fields` column + EXPORT_DENYLIST, (5) docs/architecture.md Stats. Plus: the
row's line_ref must contain the Phase 7 stats-append line (it said 657-672,
the line is at 958); /trekbrief --approve reaches Phase 7 with mode "approve"
(PM 04.10, point 3) and CLAUDE.md, README.md, docs/command-modes.md say so.
Red: 7 doc pins fail. Green on arrival: the yardstick-header pin (Step 6
already rewrote the header) and the otel DROP guard (the fields were never
allowlisted).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The slug join (voyageSlugs: every slug in every stats file against the order's
`slug:`, which 0 of 690 orders carried) is replaced by an order-id join:
orderRuns() indexes trekbrief-stats.jsonl's order_id <-> slug, readOrders()
keeps each order's file stem and its own-line arbeidsform marker. Per new-work
order: arbeidsform: ordre = declared NO; one record under one slug that names
no other order = YES; no record or disputed = not measured, never a no
(PM 04.10, point 1). value = YES, denominator = YES + declared NO.
USE_COUNTING_SINCE = null (operator 04.10: the tool now, the counting after
the work is declared done): until it is set the row is NOT COUNTABLE and every
order not measured; once set, the window starts at the latest of cutoff,
MARKER_SINCE and that date. facts.ordersNamedByARecord is the known-positive
diagnostic. The header names the measured-share bias and the false-positive
class (Goal iii) next to the number. The CLI guard compares real paths.
Real queue 2026-10-04: use NOT COUNTABLE, 695 of 695 orders not measured,
0 named by a record. yardstick.test.mjs 43/43.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
measureUse({ queue, runs, cutoff, countingSince }): runs come from
orderRuns(stats) - trekbrief-stats.jsonl only. YES = a trekbrief record names
the order's id under one slug that names no other order; declared NO = a
new-work order carrying <!-- arbeidsform: ordre --> on its own line; no
record or a disputed record = NOT MEASURED, never a no (PM 04.10, point 1).
countingSince null -> NOT COUNTABLE, every order not measured; the window
starts at the latest of cutoff, MARKER_SINCE and the counting start.
facts.ordersNamedByARecord is the known-positive diagnostic (SC8).
Existing use tests get countingSince = MARKER_SINCE (their window unchanged)
and records instead of slugs; their denominators now read YES + declared NO.
Replaced: "a new-work order without a slug leaves the numerator NOT
MEASURED" - the slug join it guarded is gone. New exports are read through a
namespace import, so the trust/interrupts/mutants tests still run.
Red: 24 of 43 fail (every use test, the two measureAll tests, the symlink
CLI test); 19 pass, none of them new.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
appendStatsRecord(kind, record, env, { cwd }): for kind trekbrief it drops
every order_* key the record came with and adds attributeOrder()'s three
keys (lib/stats/claimed-order.mjs), resolving the mailbox from the record's
project_dir when that lies inside cwd. Other kinds are written untouched.
The CLI guard compares real paths (realpathSync on argv[1] and on
import.meta.url). The old `import.meta.url === file://${argv[1]}` was a
silent no-op - exit 0, nothing written - under a symlink and under a path
with a space (measured 04.10). Valgt realpath fordi `resolve()` alone fixes
only the space.
stats-landing 15/15; intent-approval, claimed-order, proevesett green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stats-landing gains a baseEnv() (process.env minus CLAUDE_COORD_DIR) at every
spawn - the real voyage mailbox holds a claimed order while the suite runs -
and runLine takes a cwd and extra env. New: Phase 7's own line, run in a temp
git repo against a temp coord dir, must land order_id / order_claimed_at /
order_reason (one claimed -> the id; zero -> keys present, null, none-claimed;
two -> several-claimed:2; model-supplied order_* keys replaced; no coord ->
coord-missing). The CLI must also write when run through a symlink or from a
path with a space.
Red on behaviour: 7 of 8 new tests fail against today's writer (no order keys;
the file:// guard is a silent no-op under a symlink and under a space -
measured in a scratch repro 04.10). Guard green on arrival: a trekplan record
gains no order keys.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lib/stats/claimed-order.mjs reads <coord>/<mailbox>/orders/claimed/ the way
repo-mailbox's claim verb writes it (read, never called): the stem is the id,
the .claim sidecar gives claimed-at, every .md counts toward "several".
Mailboxes come from two independent git calls (toplevel basename, the claim
script's rule; and the main repo behind a linked worktree), with GIT_DIR /
GIT_WORK_TREE dropped and a 5 s timeout. A project_dir outside cwd cannot
steer the lookup. Never throws, never guesses, starts nothing.
Valgt: identity = file stem, not frontmatter, fordi the claim script moves
<id>.md and never reads the frontmatter; a quoted order-id would otherwise
never join.
claimed-order.test.mjs 20/20.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
20 tests for lib/stats/claimed-order.mjs (new): exactly one claimed order is
an attribution (stem id + the .claim sidecar's claimed-at); zero, several
(an unparseable file still counts), a to: naming another repo, a missing
coord dir or no git repo is null plus a reason - never a guess. Mailboxes
mirror coord-order-claim.sh (basename of the toplevel) plus the worktree's
main repo; _* is reserved; an inherited GIT_DIR and a project_dir outside
cwd cannot steer it.
Red: the module does not exist (20 of 20 fail, each on its own - the module
is loaded per test). Against a null stub in a scratch copy, 18 fail on
behaviour; 2 are guards green on arrival (13 _-prefixed mailbox never read,
14 the recorder only reads).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The numerator joins an order to a Voyage run by `slug:`. When a new-work order
carries none, the row is NOT COUNTABLE: the denominator is still read and shown,
the matches that were possible are reported, and the missing key is named.
Real queue 2026-10-03: use = not countable, denominator 2 (2 prove), 2 of 2
carry no slug; 4 ikke-nytt; 684 not measured. Suite 1304 -> 1309 (1307/0/2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured 2026-10-03: the two new-work orders on the real queue carry no `slug:`
(0 of 690 orders do), so "0 of 2" was forced by the missing join key, not by
work going around Voyage. An absence without a possible match is "not
measured", never 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`<!-- loesningsvalg: plan|prove -->` on its own line = new work, `ikke-nytt` =
not new; a mention in prose or an unknown value is no marker. The window starts
at the later of --cutoff and MARKER_SINCE (2026-09-28). Orders before it and
unmarked orders are reported as "not measured", never in the denominator.
`work-class` decides nothing any more. The detail shows numerator, denominator
and the not-measured count.
Real queue 2026-10-03: 6 of 690 orders carry the marker (2 prove, 4 ikke-nytt,
0 plan), 684 not measured (all before 2026-09-28), identical to a grep census.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The use number read `work-class` from the order frontmatter; 0 of 690 orders
carry it, so the denominator was always empty. PM rule 02.10: the order
marker `<!-- loesningsvalg: plan|prove -->` is new work, `ikke-nytt` is not,
counted from 2026-09-28 (enforced by pre-order-loesningsvalg.sh since then).
Unmarked orders and orders before the start are "not measured", never a no.
Red against today's code: MARKER_SINCE is not exported, and with it stubbed in
a scratch copy all five new use tests fail on behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verified 2026-10-02 against code.claude.com/docs/en/model-config and
/sub-agents. On the Anthropic API opus -> Opus 5.5 and sonnet ->
Sonnet 5.5 (default effort medium), fable -> Fable 5.1 (default high).
Three more claims in the same section were false and are corrected:
an agent without effort: inherits the session level, not the model
default; MAX_THINKING_TOKENS=0 has no effect on Opus 5.5, Sonnet 5.5
or Fable; effort is capped by maxEffortLevel or an organization cap.
"Mythos-class" is replaced by the docs' own wording. History is
untouched (CHANGELOG, the measurement docs, the Path C line).
STATE said seven files but listed six; the red pin found exactly
these six. The end-state registry line names a CC changelog fact and
stays as history.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verified 2026-10-02 against code.claude.com/docs/en/model-config and
/sub-agents: opus -> Opus 5.5 and sonnet -> Sonnet 5.5 (both default
effort medium), fable -> Fable 5.1 (default high), and a subagent
without effort: inherits the session level. Seven tracked files still
say Opus 4.8 / Sonnet 4.6 / Fable 5. History keeps its names; a
known-positive control proves the query can find them there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lifted target (operator, 2026-09-27; PM order 44111111): Voyage + the
operator's way of working level with or ahead of related frameworks in all
14 areas, and every Voyage part a documented Claude Code primitive covers
removed or with a measured reason to stay.
scripts/comparison-gate.mjs reads both denominators from their source, never
from the table: the areas from the first column of the PM report's table,
the parts from git ls-files (one part per eval case). It fells the table on
missing evidence, never on a verdict: a cited file must exist inside its
root and hold the cited lines, a pinned clone must sit at its pin, a web
citation needs a verbatim quote, an absence needs zero hits and a
known-positive control. Green also requires an independent reader. The
table itself is local-only (docs/comparison.local.json).
Measured today on 7439dac: RED, 0 evidence problems; 2 of 14 areas against
all five references (Superpowers 11, Pocock 14, agent-skills 11, Cherny 10,
playbook 2); tidy 5 of 64 covered parts resolved.
23 tests in tests/scripts/comparison-gate.test.mjs; six mutants felled (no
evidence check, no line check, no reader check, denominator from the table,
no tidy completeness, no pin check). Suite 1278 -> 1301 (1299/0/2).
[skip-docs]: an operator measurement instrument like scripts/yardstick.mjs,
whose table is local-only - no user-facing behaviour changes, so README and
CLAUDE.md have nothing true to say about it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Check 4, Step 2a' and Step 5 start with
`[ -n "${ZSH_VERSION:-}" ] && setopt nonomatch`, so an unmatched
session-* glob stays literal under zsh as it does under bash and the
existing `[ -d "$wt" ] || continue` guard skips it. null_glob was not
used: it turns `ls -d .../session-*` into `ls -d`, which lists `.`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Bash tool runs the user's shell; on macOS that is zsh, whose NOMATCH
option fails an unmatched session-* glob with exit 1. A first run has no
worktrees yet, so Check 4 stops every first multi-session run and every
re-run after a declined main-merge gate. Red under /bin/zsh, green under
/bin/bash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Valgt 6.0.0 (major) because the change is incompatible for a 5.11.1 user:
/trekexecute multi-session no longer finishes in one call, /trekplan
--decompose no longer writes launch.sh, and the per-session turn/budget
environment variables no longer apply. Version synced in plugin.json,
package.json, package-lock.json (both fields), the README badge and the
CHANGELOG heading.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1. Step 6 cleared the orders dir before Phase 8's main-merge gate asked,
so a declined gate lost the merged-waves record and the next run
prepared wave 1 again on merged code. The clear now sits only under
the gate's "On confirm" (wave path, next-wave none, Step 4 passed);
Step 6 and a declined gate keep the record, so a re-run goes
next-wave none -> Step 4 -> back to the gate.
2. The gate's Decline row and Recovery surface now say what holds on the
wave path: the waves are already merged on the current branch,
nothing is finalized, the record is kept, and re-running the same
command (not --resume, which Phase 2.5 runs as a single session)
re-runs master verification and returns to the gate. The branch name
is trek/{slug}/session-N; the push-before-cleanup note now holds only
where the push succeeded. The single-session --resume line stays.
3. The report footer adds the multi-session way to continue.
4. wave.json stores the branch the wave was prepared on (write
--branch); Step 3's status call passes the current branch and stops,
touching nothing, when the main checkout is on another branch.
npm test: 1277 tests, 1275 pass, 0 fail, 2 skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 3 of the review of the session-order flow:
- the orders dir is cleared only under the main-merge gate's confirm
(wave path, next-wave none, Step 4 passed); Step 6 keeps it, and a
declined gate keeps the merged-waves record
- the gate text is true on the wave path: the waves are already merged
on the current branch, nothing is finalized, and re-running the same
command (not --resume) returns to the gate; the single-session
--resume statement stays
- the report footer names the multi-session way to continue
- wave.json stores the branch the wave was prepared on, and Step 3's
status call (executed from the doc in a temp repo) refuses another
branch, keeping wave.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One invariant closes the data-loss class: Phase 2.55, 2.6 and 7.6 remove
worktrees only with `git worktree remove` without force and branches only
with `git branch -d`. Whatever git refuses (a worktree with changes, an
unmerged or checked-out branch) is kept, reported with what the user can
do, and never retried with force; every unmerged trek/{slug}/* branch
survives every failure path. Step 1 stops on a branch or worktree left
by an earlier attempt instead of deleting it. After a merged wave, a
progress file is dropped from its worktree only when untracked and
byte-identical to its archived copy, so the happy path still cleans up.
B1: Step 3 refuses to merge into a dirty main checkout, and tells a
refused merge (no MERGE_HEAD: stop, keep wave.json) from a real conflict
(abort, Step 5 keeps the branches).
B2: Phase 2.5, Check 4 and Step 0 take the main checkout from the first
`git worktree list` entry and refuse to run from a linked worktree.
B3: wave.json and merged-waves.json carry the plan's sha256 and refuse
another plan or version, naming the run that holds the orders dir and
the clear command; Step 0 stops on that. Step 6 clears the orders dir
when every wave is merged AND Step 4 passed, no longer keyed on the
Phase 8 label the wave path cannot reach.
Also: every session-orders.mjs call runs from the main checkout with a
main-relative plan path; Check 1 no longer counts .claude/trekplan-sessions/
as a dirty tree (it blocked every re-run after a failed wave); a stuck
wave has a documented non-force way out; Hard rule 12 states the
invariant. The test file only narrows one call-site filter that also
matched Step 0's plugin-root existence check.
npm test: 1273 tests, 1271 pass, 0 fail, 2 skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 2 of the review of the session-order flow. One invariant closes the
class: Phase 2.55, 2.6 and 7.6 remove worktrees only without force and
branches only with -d; a refusal keeps the work and is reported.
These tests execute the bash blocks of commands/trekexecute.md in
throwaway repos with linked worktrees:
- Check 4 and Step 5 remove a clean worktree and a merged branch, keep an
unmerged branch and a worktree with untracked files, and list them
- Step 1 stops on a branch or worktree left by an earlier attempt
- Step 3 stops on a dirty main checkout (B1) and tells a refused merge
(no MERGE_HEAD) from a real conflict; after a merged wave it records
the wave and drops only identical, untracked, archived progress copies
- Phase 2.5, Check 4 and Step 0 resolve the main checkout and refuse a
linked worktree (B2); Step 0 derives a main-relative plan path
- Check 1 does not count .claude/trekplan-sessions/ as a dirty tree
- wave.json and merged-waves.json carry the plan sha256 and refuse
another plan or version, naming the run and the clear command (B3);
Step 6, not Phase 8, clears on every wave merged + Step 4 passed
One test is a structural guard over the text (no force flag in those
phases); the executed blocks pin the behavior.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude Code's positional-argument shorthand replaces $N in a command's
text; awk's $(0) is the same field without that collision.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operator decision 2026-10-02: keep the test set that a person runs
through Anthropic's plugin eval tool. Voyage starts nothing; the gate
counts that entry exactly, and the binding rule and the gate header now
say so instead of claiming historical mentions only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Seven defects from an independent review of the 6.0 session-order flow,
all verified against the text before fixing:
1. Step 3 branched only on pending/failed/stopped/unreadable, so a session
still writing in-progress (or in_progress) next to a failed one had its
live worktree force-removed. status now classifies each session as
completed, running (no file, pending, in-progress, in_progress, or any
unknown status) or ended-bad (failed, stopped, partial, blocked,
unreadable), keeping the raw status; Step 3 stops on any running FIRST
and touches no worktree, branch or wave.json.
2. The Phase 2.5 wave-in-flight guard was cwd-relative; from a subdirectory
it missed wave.json and Check 4 force-removed the wave. The guard is now
anchored at the git toplevel, and Check 4 opens with a block that refuses
to clean while wave.json exists.
3. Step 6 read progress files from worktrees that Step 3/5 had removed. A
new archive subcommand copies each to orders/wave-W-session-N.progress.json
before any worktree goes; Step 6 and Phase 8 read the copies.
4. NO_WAVE always prepared the lowest wave, so a re-run after a wave-2
failure re-ran wave 1. record-merged writes orders/merged-waves.json
after each merged wave (Step 5 keeps it); next-wave returns the lowest
unmerged wave or none (then Step 4). Phase 8 clears the orders dir only
after a completed report; the record refuses another plan's path.
5. Phase 7.6 named a deleted worktree and promised an unwired re-run. The
order now names the main checkout and says the recovery session's own
audit is the check.
6. (test side, previous commit) progress paths are asserted literally.
7. Hard rule 12 now carries the awaiting-sessions exception.
npm test: 1262 tests, 1260 pass, 0 fail, 2 skipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An independent review of the 6.0 session-order flow found seven defects.
These tests pin the fixed behavior:
- status classifies each session as completed, running (no file, pending,
in-progress, in_progress, or any unknown status) or ended-bad (failed,
stopped, partial, blocked, unreadable), keeping the raw status; a failed
session next to a running one reports running, and Step 3 must branch on
running before any failure cleanup
- archive copies each progress file into orders/ before worktrees go
- a merged-waves record drives next-wave, survives Step 5, and clear
resets it (refused while wave.json exists, and for another plan)
- the Phase 2.5 guard is anchored at the git toplevel; Check 4's guard is
executed from a subdirectory and must refuse while wave.json exists
- Phase 7.6 names no deleted worktree and promises no unwired re-run
- Hard rule 12 carries the awaiting-sessions exception
- progress paths are asserted literally; the old self-referential check
stayed green under a basename(planPath) mutation, the new one goes red
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README claimed four security layers including scoped per-child tool
access (gone with the launched children), an auto-dispatched Phase 7.6
recovery session and a launch template; architecture.md still pointed at
launch.sh. They now describe what 6.0.0 does: session specs plus
orders.md, a recovery order for a session the user opens, three layers.
operations.md gets a status note instead of a rewrite (decision record).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Valgt the literal ${CLAUDE_PLUGIN_ROOT} because that is the form Claude
Code substitutes in a command's text (recorded sessions ran
node <cache>/voyage/5.11.1/lib/...); a :- default is never replaced and
the Bash env is empty. The fallback now picks the highest installed
version under cache/<marketplace>/voyage/<version>/ by version number
(mtime ranked 5.11.0 above 5.11.1 on the measuring machine). Without
this, /trekexecute's multi-session Step 0, plan verification (Phase 7),
/trekreview's criteria checks and /trekresearch's loop gate all exit 2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The four blocks in trekexecute (x2), trekresearch and trekreview read
${CLAUDE_PLUGIN_ROOT:-}, which Claude Code never substitutes (it replaces
the literal ${CLAUDE_PLUGIN_ROOT}), and the fallback returns the
version-less cache/<marketplace>/voyage directory, so the guard after it
exits 2 every time. Red on both conditions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The operator decision of 2026-09-27 stands where every session reads it:
a short binding rule in CLAUDE.md that names the replacement (order plus
starter, subagents inside one session) and the gate that enforces it.
CHANGELOG gets an Unreleased entry; the version is left for the release
round to set.
npm test 1250 (1245 pass, 0 fail, 5 skipped). The gate is unchanged:
the new changelog text adds no hit line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operator decision 27.09.2026: Voyage works the PM way, so nothing in it
starts Claude Code. Work that needs another session becomes an order plus
a starter line the user gives a session they open themselves; Voyage
never starts the session.
/trekexecute's multi-session path (Phase 2.6) now prepares one wave at a
time: worktree per session, then lib/util/session-orders.mjs writes one
order per session (worktree, steps, done-condition, starter) plus
orders/wave.json, and the run stops. Running the same command again reads
each session's progress file (status mode), merges sequentially with
push-before-cleanup as before, and prepares the next wave. Phase 2.5 skips
the destructive pre-flight while a wave is in flight. Phase 7.6 recovery is
handed over the same way. Hard rule 21: never start Claude Code.
Removed with it, because they existed only for launched children: the
ANTHROPIC_API_KEY billing check (and its dry-run line and Hard rule 1
exception), the hooks-fire version precheck, the safety preamble, the
scoped-tool/turn/budget flags, templates/headless-launch-template.md, the
decomposer's launch.sh (now orders.md), /trekplan's "launch", the README
billing and MCP tuning sections, and scripts/q3-cache-prefix-experiment.mjs
(an experiment that spawned the binary; its results stay in docs/).
/trekresearch's deep-research pre-gate no longer runs the binary for its
version; the post-hoc check was already the authoritative guard.
Chose orders + starters over in-session subagents because the order's done
criterion asks for exactly that, and because /trekexecute disallows the
Agent tool on purpose (Hard rule 10); reopening that is a separate change.
Gate: 54 -> 0 hit lines outside EXEMPT. npm test 1250 (1245 pass, 0 fail,
5 skipped: 3 are the retired-reference scan without its local list).
verify.sh 7/0. The fixture run (tests/lib/session-orders.test.mjs) writes
two orders and wave.json for wave 1 and leaves a trap binary untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A node:test gate that scans every tracked file (the tree a release tag
publishes) for any way to start a Claude Code session or model run: the
CLI with a flag or prompt, `claude plugin eval`, spawn/exec of the binary,
the Agent SDK / claude-code package / GitHub Action, and the permission
bypass flags. Plugin management (install, validate, marketplace add)
starts no session and is not a hit.
The scanner is proven on a known-positive fixture that exercises every
pattern, and on look-alikes that must not hit. Historical mentions (class
c) stand only in EXEMPT, each with a reason and its exact hit count, so a
new hit in an exempt file fails as well. Two entries are the operator's
own eval run through Anthropic's tool; they are listed as their own class
so the decision stays visible.
Red on 57e620b: 54 hit lines in 14 files outside EXEMPT (a: 34 in 6 files,
b: 18 in 7 files, a descriptive comment: 2 in 1 file). EXEMPT holds 16
files and 46 hit lines, and matches exactly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.11.0 ships from the base commit before this branch lands, so the
reference cleanup and its hygiene check go out as 5.11.1: plugin.json,
package.json, package-lock.json (both fields), the README badge and a new
CHANGELOG entry. No tag.
Suite after staging: 1240 tests, 1238 pass, 0 fail, 2 skipped;
verify.sh 7 pass, 0 fail.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The annotation surface's provenance is now described as the pattern it
follows (pencil toggle, intent buttons, popover form, structured export)
rather than by naming a repository that no longer exists. Touches the
plugin/package descriptions, README, docs/architecture.md, the v5.0.3
CHANGELOG entry, and two comments in scripts/annotate.mjs and its test.
Retired-reference check: 12 hits in 7 files -> 0 (content and path names).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A node:test pin that scans every tracked text file and path for the terms
in a gitignored local list (tests/.excluded-terms.local.txt), so the terms
never live in tracked text. The scanner is validated against a planted
known-positive (content and path name), an empty scan fails closed, the
named EXEMPT list is empty and rot-checked, and without the local list the
scan is skipped with an explicit message.
Red on 0be152a with the list present: 12 hits in 7 files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New § Stability section: the PM's 8/8 and 7/8 on ea66a98, the cause (correct
lower-case verdicts, 3 of 34 case-8 and 2 of 22 case-6 recorded replies), the
grader changes and why, and the measured result on 7f7161b: case 8 12 of 12
(10 alone + 2 full), case 6 8 of 8 (6 + 2), two full runs 8 of 8 each. The
status block and "every full run gave 8 of 8" now name whose sample that was.
Correction to 687710a's message: it said a grader file carries only
`pattern`. The docs list `flags` for the regex grader. The letter classes
stay, for the reason now written in the doc: a flag applies to the whole
pattern, and the opposite-verdict refusal must stay case-sensitive.
Suite after git add: 1236 tests, 1234/0/2. No version bump: plugin code
is untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both patterns now start at the beginning of the reply ((?<![\s\S]), which
holds with or without a multiline flag) and refuse the whole reply when it
carries the opposite verdict in capitals (FAIL/FAILED for says-pass,
PASS/PASSED for says-fail), unless negated. The opposite word in lower case
does not refuse: correct case-6 replies say "did not pass" and, once on
687710a, "The other checks passed".
Chosen: refuse only the capitalised opposite, because refusing it in any
case would fail correct replies again, the instability this change removes.
Measured on 22 case-8 and 14 case-6 recorded replies (PM re-measurement +
this session): old says-pass 19/22, new 22/22; old says-fail 13/14, new
14/14; each grader on the other case's replies 0.
Suite after git add: 1236 tests, 1234/0/2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on 687710a: a correct case-6 reply said "**FAIL**: ... did not pass
... The other checks passed." With lower case accepted, says-pass matches that
reply, so a wrong case-8 reply of the same shape would pass the case. The test
pins that a reply whose capitalised verdict is the opposite one is refused,
while the opposite word in lower case (a side clause) or negated is not.
Red on 687710a: 11 of 12 in tests/lib/proevesett.test.mjs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Case 8 failed 2 of 12 in the PM re-measurement of ea66a98 on correct replies
that said "passed" without PASS. The patterns now spell each letter as a
class ([Pp][Aa][Ss][Ss]...) instead of relying on a regex flag, since a grader
file carries only `pattern`. The verb forms pass/passes/passed and
fail/fails/failed are verdicts; a preceding "not " or "n't " still refuses.
Measured on the PM's recorded replies (distinct runs): old says-pass 10/12 on
case 8 (reproduces the finding), new 12/12; says-pass on case 6 replies 0/8
both, says-fail 8/8 on case 6 and 0/12 on case 8 both.
Suite after git add: 1235 tests, 1233/0/2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PM re-measurement of ea66a98 had case 8 pass 10 of 12. Both failures were
correct replies that gave the verdict only in lower case ("passed"), and
\bPASS(?:ED)?\b is case-sensitive. The test pins lower-case pass/passes/passed
and fail/fails/failed as verdicts, keeps "not passed", "doesn't pass", "failed"
refused by says-pass, and checks that each case's recorded reply does not
satisfy the other case's grader.
Red on ea66a98: 10 of 11 in tests/lib/proevesett.test.mjs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Version 5.11.0 in every file that carries it: .claude-plugin/plugin.json,
package.json, package-lock.json (both entries; they said 5.10.0, drift
from before 5.10.1), the README badge, and a CHANGELOG entry for
everything since v5.10.1. Chose a minor bump because /trekplan gains a
halt (a new capability, additive schema). Handover 1 changes for
downstream producers: their briefs stop at /trekplan until approved.
No tag and no catalog bump here: release-plugin.mjs runs in the operator's
push round.
Suite after git add: 1234 tests, 1232 pass / 0 fail / 2 skip in 2 of 3
runs. The third failed only the known timing test otel SC #14 tail-latency
(877 ms against an 800 ms ceiling), which this order leaves alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New § Stability: why case 4 was unstable (it could halt on the intent gate,
5 of 6 here before the fix, 6 of 12 and 7 of 10 in the PM re-measurement),
the three changes, the case-4 known-positive (3 of 3 passed with the gate's
code off until names-code; then 0 of 3), and the says-fail cause left
unmeasured (the failing trace was deleted; 0 of 13 kept replies used
another spelling).
After the fix (a384ce6): three full runs (one --runs 3, two --runs 1),
every case 5 of 5, each full run 8 of 8; case 4 alone 10 of 10, 15 of 15
in total. The status line no longer lets 8 of 8 read as a stable state.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New grader names-code (regex, trace, code\W{1,12}BRIEF_V51_MISSING_SIGNALS),
the same form as the intent case's names-code. It checks what the case's
expected_outcome promised before any run: the validator reports the code.
Checked on this session's recorded traces before the commit: it matches
10 of 10 green runs and 0 of 3 runs with the check disabled.
Known-positive re-run in the scratch copy (validator check 'if (false)'):
0 of 3 cases pass, names-code fails in each, the other 5 graders pass.
Green: tests/lib/proevesett.test.mjs 10 of 10.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>