voyage/docs
Kjell Tore Guttormsen 6dafdf2a2a fix(research-loop-cap): resolve the data root in code so the loop can run
CLAUDE_PLUGIN_DATA is empty in the Bash tool's process env, and the Phase 5
bash snippet is the cap's only caller. resolveLedgerPath() returned null there
and allowTurn() failed closed, so the budget gate denied turn 1 of every real
run: the loop this delivery exists to bound could never spend a turn, and the
pre-registered measurement could not be run at all.

resolveDataRoot() is now the single root for everything the loop writes --
CLAUDE_PLUGIN_DATA when the harness sets it, ~/.claude/voyage when it does
not. Three consumers resolve through it, which is the point: the cap ledger,
the PreToolUse hook's scope-marker lookup, and the command's bash snippets.
A writer and a reader that resolved the root separately are what made the
enforcement hook allow unconditionally in every real run while CLAUDE.md and
docs/architecture.md called it enforcing.

Same root cause, same commit:
- Marker write and remove now share ONE absolute-path guard and one root; the
  write requires a non-empty CLAUDE_CODE_SESSION_ID before composing the path
  (unset, the marker was named `.json`, which no lookup matches and no TTL
  sweep cleans up).
- The per-turn gates resolve VOYAGE_ROOT with a plugin-cache fallback and
  reserve exit 2 for "gate could not run". Interpolating an empty
  ${CLAUDE_PLUGIN_ROOT} ran `node /lib/...` -> exit 1, which the contract read
  as "privacy gate says no" -- an unsatisfiable rewrite loop no query could
  clear.

Two now-unreachable deny branches are removed rather than left as dead safety
claims (allowTurn's no_plugin_data_dir; the hook's uncountable-ledger deny).
The fail-closed stance stays where it is still real: a ledger that cannot be
WRITTEN denies the turn.

Verified end-to-end through the real bash snippets and the real hook with both
variables stripped and HOME sandboxed: marker written under the fallback root,
8 turns spent, 9th denied, hook exits 2, and exits 0 again after removal.
Note: the fallback exit-2 branch fires against the installed v5.9.1 cache,
which predates lib/util/research-loop-cap.mjs -- correct behaviour, and it
clears when the plugin is reinstalled.

Review findings 2670c10a, fbd6d534, 93550dfb.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011vPSXe88qp5aqWUqbDNWoF
2026-08-12 22:26:46 +02:00
..
eval-corpus feat(eval): SKAL-1·4b offline gold-scored output eval 2026-06-30 09:00:33 +02:00
agent-description-token-trim-brief.md docs(voyage): track agent-description token-trim brief (M4 input) 2026-06-26 20:15:34 +02:00
architecture.md fix(research-loop-cap): resolve the data root in code so the loop can run 2026-08-12 22:26:46 +02:00
balance-backlog-plan.md chore(voyage): S34 — V30 economy-profile self-declares experimental (uncalibrated Jaccard floor) 2026-06-20 10:18:38 +02:00
cc-upgrade-2.1.181-decision-matrix.md docs(voyage): S20 — CC-04/T3 verified clean (research-agent MCP degradation under --strict-mcp-config) 2026-06-19 14:08:51 +02:00
claudemd-token-trim-brief.md docs(claude-md): trim CLAUDE.md to invariants (always-loaded token trim, S53) 2026-06-29 14:49:32 +02:00
command-modes.md fix(trekresearch): gate Phase 4.5 on VOYAGE_STORM_ENABLED, not effort alone 2026-08-12 22:17:56 +02:00
deep-research-engine-brief.md docs(research): resolve deep-research-engine topic-1 (/deep-research trigging) 2026-06-30 10:39:03 +02:00
deep-research-engine-research.md docs(research): remove literal keyword tripping verify SC1 2026-08-12 20:29:35 +02:00
devils-advocate-plan.md docs(voyage): plan S14 devil's-advocate audit via Dynamic Workflow 2026-06-18 18:30:05 +02:00
devils-advocate-results.md docs(voyage): S22 — happy-path dogfood results (blind spot #1/#4 measured) 2026-06-19 20:53:21 +02:00
HANDOVER-CONTRACTS.md docs(voyage): fable-aware allowlist prose in contracts, architecture, templates, CLAUDE.md 2026-07-02 17:14:35 +02:00
observability.md docs(observability): document token-usage schema + main-context v1 scope 2026-06-26 14:47:24 +02:00
operations.md docs(voyage): add fable profile row and correct model-allowlist prose 2026-07-02 17:13:15 +02:00
profiles.md docs(voyage): add fable profile row and correct model-allowlist prose 2026-07-02 17:13:15 +02:00
S22-happy-path-dogfood.md docs(voyage): S27 — close version-skew (S22 defect #4) as no-op 2026-06-19 22:11:25 +02:00
spike-pretooluse-subagent-reach.md feat(trekresearch): wire Phase 5 scope marker so the cap hook enforces 2026-08-12 20:55:55 +02:00
storm-measurement.md fix(storm-measure): restore the pre-registered OR decision rule 2026-08-12 22:15:07 +02:00
subagent-delegation-audit.md feat(voyage)!: bulk content rewrite ultra -> voyage/trek prose [skip-docs] 2026-05-05 15:08:20 +02:00
T1-cc26-delegated-orchestration.md docs(voyage): S7 (W1/CC-26 gate) — T1 feasibility probe + measurement design 2026-06-18 13:21:09 +02:00
T1-synthesis-poc-results.md feat(voyage): S12 — NW3 synthesis-agent built + measured → declined per measurement [skip-docs] 2026-06-18 17:58:39 +02:00
T2-bakeoff-results.md fix(voyage): S21 — close IPv4-mapped IPv6 SSRF bypass + security/safety audit (blind spot #2) 2026-06-19 20:02:56 +02:00
T2-cc27-workflow-substrate.md docs(voyage): S8 (W1/CC-27 gate) — T2 Workflow-substrate probe + measurement design 2026-06-18 13:34:05 +02:00
voyage-vs-cc-balance-analysis.md chore(voyage): S34 — V30 economy-profile self-declares experimental (uncalibrated Jaccard floor) 2026-06-20 10:18:38 +02:00
voyage-vs-cc-balance-charter.md docs(voyage): add Voyage-vs-CC balance-analysis charter (next-session launch spec) 2026-06-20 06:34:40 +02:00
W1-narrow-wins-plan.md docs(voyage): plan W1 narrow-wins implementation (NW1/NW2/NW3, S9->) 2026-06-18 13:41:20 +02:00