Review finding 4638fea9 (MAJOR emitted, catalogue tier BLOCKER). Live in every
session regardless of the STORM flag, so it is not deferrable to the measurement
decision.
Anchoring the rule to command position (S75-S78) was right in intent - the
unanchored word match blocked quoted grep patterns, heredoc data and commit
messages - but it ran against the whitespace-collapsed string. Measured against
normalizeCommand() output, five forms that the previous rule blocked were
allowed:
- newline separator: \s+ -> ' ' collapsed the newline BEFORE the pattern ran,
making the \n branch of the separator class dead code
- `&` background separator: absent from the class entirely
- `bash -c` / `sh -c`: the wrapped command sits inside quotes, never at
command position
- `xargs <cmd>`: no separator in front of the command at all
And it missed its own motivating case: `grep "a|b" f` stayed blocked, because
the `|` inside the quotes still read as a separator.
Fix: the rule now runs against a command-position view (`commandView: true`,
per-rule input selection) instead of the collapsed string. The view keeps
newlines, adds `&` to the separator class, and classifies each span:
- quoted spans -> data (one space), so a grep alternation, echoed prose and a
commit message pass
- EXCEPT the argument of a shell wrapper (`sh -c`, `bash -c`, with optional
sudo and absolute path) -> spliced back in at command position
- heredoc bodies -> data, keeping the operator line. Restoring the newline
separator without this would newly block every heredoc line starting with a
matched word - the exact friction anchoring existed to remove
- `xargs [flags]` -> separator inserted after the flags
Two defects found while verifying, both the same regression class and both
fixed here rather than left:
- `\name` runs name (the backslash only suppresses alias expansion). The old
unanchored rule blocked it; the anchored one allowed it.
- heredoc bodies, as above - a false positive this change would otherwise have
introduced.
Known limit, stated rather than implied: `xargs -I {} <cmd>` is not parsed, so
the inserted separator lands before the argument, not the command.
Other BLOCK rules are untouched and still run against the collapsed string.
Verified by a 37-case adversarial probe through the real hook (all five bypass
forms, both wrapper forms, backslash, heredoc, quoted alternation, ordinary
commands, and the unrelated rules): 37/37 as expected. 9 new tests.
Suite 952 (950/0/2, baseline 937 + 15 across both Track A fixes).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013zNqxP8qTWgJhn3wMYUFEh
pre-agent-cap.mjs (S78) enforces the Phase 5 loop bound only while a scope
marker exists for the calling session. Nothing wrote that marker, so the hook
shipped correct but latent. Phase 5 now writes it at loop start and removes it
on all three exits.
- Write: ${CLAUDE_PLUGIN_DATA}/trekresearch-loop-scope/<session_id>.json with
{runId, startedAt}, keyed by CLAUDE_CODE_SESSION_ID. Verified 2026-08-12 that
this equals the session_id on the hook's PreToolUse payload.
- runId must be the same --run-id the ledger is counted under; a mismatched id
counts zero turns and enforces nothing.
- Fail-soft on write: the hook is defence in depth, research-loop-cap.mjs stays
the gate. Report and continue. The reverse (skipping the budget gate because
a marker exists) stays forbidden.
- Removal on every exit, load-bearing on the exhausted one: the hook keeps
denying WebSearch/WebFetch/Task while the marker is there, and Phase 6 spawns
agents. Crash is covered by the hook TTL, not by cleanup - stated as such
rather than claiming cleanup covers it.
- Marker written in Phase 5, not Phase 4.5: 4.5 mines already-retrieved Phase-4
results and spends no loop turns, so scoping there widens the window for
nothing. Pinned by a test.
Six pins in tests/lib/doc-consistency.test.mjs derive the directory name from
SCOPE_DIRNAME in the hook and the payload fields from marker.runId/startedAt,
so drift in either direction fails. hooks/scripts/pre-agent-cap.mjs untouched.
Verified end-to-end with the snippets as shipped: marker written -> hook allows
under budget, denies 8/8 at budget, allows again after removal; removal is
idempotent; unset CLAUDE_PLUGIN_DATA takes the fail-soft branch.
Suite 937 (935/0/2, baseline 931 + 6).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R77nGJjZ1hqjAQQHefFdnc
D12 (org-ops docs/decisions.md, 2026-08-01) requires the plugin-class
disclosure line to be self-contained with three parts: generator, process,
and the ownership basis. Voyage carried the first two; adds the Anthropic
Consumer Terms §4 clause so the line no longer depends on a cross-repo
anchor that does not exist.
repo-standard v0.3.0: 14/14 OK. Suite: 832 (830 pass / 0 fail / 2 skipped).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WfGRt8MkPVvnkGCzidTuis
The `[Full disclosure →](../../README.md#ai-generated-code-disclosure)`
link was inherited from the monorepo layout. In a standalone repo `../../`
resolves outside the repository (404), and the anchor never existed in any
README. Replaced with the inline sentence the polyrepo migration intended.
Reported by catalog (coord 20260803T191159Z-4541213484), confirmed by
repo-standard v0.2.0 gate (LINK-OUTSIDE-REPO, README.md:11).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRYUCVByhmzWBMCCFSYK2j
repo-standard gate (plugin class) flagged 6 ERROR. Fixed all six:
- README-DESC: H1 is now `# voyage` (was `# trekplan — …`, stale from the
rename) and the opening line is byte-identical to the forge description,
so description == catalog == README on all three surfaces.
- INSTALL-NO-CLI + HEADING-MISSING: new first-screen `## Install` with the
CLI install command (`claude plugin install voyage@ktg-plugin-marketplace`)
beside `marketplace add`; the `enabledPlugins` JSON is kept as the second
form. Retires the duplicate `## Installation` section further down (its
architect paragraph already exists verbatim under Quick start) and drops
the now-redundant install lines from the Quick start block.
- HEADING-MISSING: `## Non-goals` (promotes the existing "What it doesn't
solve" list) and `## Changelog` (release notes moved off the first screen,
per the standard, now a link + one line per recent version — keeps the
doc-consistency pin on framing / brief_version 2.2).
Remaining 3 gate ERROR are a classifier defect in the gate, not this repo:
directory link targets (`agents/`, `examples/observability/`) are checked
against `git ls-files`, which never contains directories. Links are correct
and left as-is by operator decision; reported to repo-standard via coord.
Suite: 832 tests, 829 pass, 1 fail, 2 skipped — the failure is the
load-dependent otel tail-latency NFR (passes 3/3 in isolation), unrelated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PRYUCVByhmzWBMCCFSYK2j
Phase 3 (atomic-write) and Phase 4 (validator) used !`...` eager-exec
with unresolved runtime placeholders; the harness executes those at
command LOAD time, so zsh parsed <project-dir> as input redirection and
/trekendsession aborted before the model saw a single instruction.
Both blocks are now plain runtime Bash fences with {curly} placeholders
(shell-inert, trekplan.md convention) and absolute ${CLAUDE_PLUGIN_ROOT}
paths (cwd-relative plugin paths were a latent ERR_MODULE_NOT_FOUND in
any user repo). Phase 1 discovery block keeps its legitimate eager-exec.
Regression guard: new tests/commands/trekendsession.test.mjs flags any
!`-block in commands/*.md containing <angle>/{curly} placeholders, and
pins Phase 3/4 as runtime Bash. Suite 828 -> 832 (830/0/2). E2E: fixed
blocks run with real values write both state files, validator valid:true;
trekcontinue.md:147 runtime-verified self-contained.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013NXzF3F2zAM8S7FCBXCqAb
Operator reviewed the brief (S57) and approved as-is, then chose research-first
at the /trekplan research gate (option A: investigate only the genuinely-external
topic 1; fold local topics 2/3 into /trekplan exploration).
Topic 1 finding (validator-green; claude-code-guide + CC 2.1.196 binary + a real
local /deep-research run, all cited): /deep-research is a built-in *dynamic
workflow* (not a skill), outside the Skill-tool allowlist. Trigging is
prose-instruction only; the report lands inline in context with no on-disk
artifact (only the .js script is written). => the engine must be instruction-based
+ in-context transform, surface-only. Brief's v2.1.154+ / Pro-via-/config
constraints verified correct; SC3 ("dynamic workflows off -> fallback to swarm")
is correct as written (an earlier review note that called it a conflation rested
on a wrong premise and is retracted).
- docs/deep-research-engine-research.md: new, research-validator green strict.
- docs/deep-research-engine-brief.md: status draft->ready (operator-approved),
research_status pending->complete (option-A decision recorded), Research Plan
traceability note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ddpUq3MNQFoV5h3qYrVYj
Operator-delivered draft (S55) carried only brief_version/status/brief_quality/
research_topics and an explicit "reconcile frontmatter against brief-validator
before /trekplan" note. Add the required fields (type, task, slug,
research_status, phase_signals_partial) plus the brief_version 2.2 gates:
framing: refine (operator-confirmed — additive opt-in engine, swarm stays
default, no contract change) and a 5-line ## TL;DR. brief-validator passes
strict + --min-version 2.2. status stays draft pending operator review before
the /trekplan run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1krHamUehZh6JqVqs85t
The documented `brief-validator.mjs <brief.md>` invocation (no flags) always
bailed to Usage/exit 2. Root cause: when --min-version is absent, minIdx is -1,
so the skip index minIdx+1 was 0 — excluding argv index 0, exactly where the
file positional sits in the no-flag case. Any leading flag (--soft, --json)
pushed the file to index >=1 and masked the bug, so the function-level tests
never caught it.
Guard the skip index to -1 when --min-version is absent. Add two CLI regression
tests (execFileSync, matching the next-session-prompt-validator pattern):
no-flag invocation reaches validation, and --min-version still skips its value
token to find the file. Suite 822 -> 824 (822/0/2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1krHamUehZh6JqVqs85t
Version sync 5.7.1 -> 5.8.0 across plugin.json, package.json,
package-lock.json, README badge, and CHANGELOG top entry (guarded by
doc-consistency.test.mjs). Suite 822 (820/0/2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJQYC5vpkJWxndS55vQQZ6
Records the operator-supplied brief for an --engine {swarm|deep-research}
choice on /trekresearch's external phase (swarm stays default; deep-research
delegates the external phase to the built-in workflow with auto-fallback).
Backlog item only — not implemented. Lives beside the work (docs/), tracked.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJQYC5vpkJWxndS55vQQZ6
Scores committed agent-run fixtures against the golden corpus at
(file, rule_key) granularity, building on the deterministic coordinator
contract (4a). Offline: committed reviewer payloads, no live agent spawn,
no LLM, no network (the LLM-in-the-loop grading is the separate 4c tier).
- lib/review/gold-scorer.mjs: scoreFindings (precision/recall/f1 at
(file,rule_key) granularity, line+severity ignored) + scoreVerdict; pure,
with documented vacuous-set conventions.
- tests/fixtures/bakeoff-rich/runs/run-perfect.json: committed run that
reproduces all 5 seeded gold findings through runContract.
- tests/lib/gold-eval.test.mjs: the scoring RUN (precision/recall/f1 = 1.0,
verdict == expected_verdict BLOCK, nothing suppressed/skipped).
- lib/util/test-census.mjs: third census category (goldEval) — a scoring run
is neither behavior coverage nor a doc-pin; honest-count invariant now 3-way.
- docs/eval-corpus/README.md: 4b moved from Future hardening to implemented.
Suite 809 -> 822 (820/0/2). gold-scorer covers TP+FP+FN+degenerate paths.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJQYC5vpkJWxndS55vQQZ6
SC1 (zero `ultra` refs) was a pre-existing false-positive on
docs/cc-upgrade-2.1.181-decision-matrix.md, which cites real CC features:
`ultracode` (a CC keyword, 2.1.160) and the `ultra-cc-architect` plugin
name. Rewording would make the doc factually wrong, so the file is
excluded via exclude_path() — same pattern as CHANGELOG/MIGRATION.
Tooling-only (verify.sh); no version bump. verify.sh 7/0, suite 809 (807/0/2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013J12WFAbngQNMTJMoybD7N
origin is open/voyage (an OFFENTLIG/public mirror per ~/.claude/CLAUDE.md, which
names open/ as the public example). STATE.md was wrongly tracked since 5bf574a
(23 commits) under a mistaken 'PRIVAT Forgejo' premise. Its content has now been
scrubbed from all history via git filter-repo; this gitignores it going forward
and corrects the false tracked/private comments. STATE continuity stays local.