feat(trekresearch): wire Phase 5 scope marker so the cap hook enforces
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
This commit is contained in:
parent
fce11a1178
commit
cef3e7fa24
3 changed files with 170 additions and 10 deletions
|
|
@ -147,8 +147,14 @@ inside a sub-agent was never measured — so this hook is **defence in depth**,
|
|||
and `research-loop-cap.mjs` must remain correct on its own if the hook
|
||||
silently stops firing.
|
||||
|
||||
**Open follow-up (outside Step 10's scope fence):** the marker file is written
|
||||
by nothing yet. `commands/trekresearch.md` is on Session 4's never-touch list,
|
||||
so wiring Phase 5 to write and remove the marker belongs to a later session.
|
||||
Until then the hook is correct but latent: it enforces exactly when a marker
|
||||
exists, and no marker is ever created.
|
||||
**Follow-up, closed (S79).** Step 10 shipped the hook correct but **latent** —
|
||||
nothing wrote the marker, and it enforces exactly when a marker exists.
|
||||
`commands/trekresearch.md` Phase 5 now writes it (`### Loop scope marker`,
|
||||
keyed by `CLAUDE_CODE_SESSION_ID`, carrying the same `run_id` the ledger is
|
||||
counted under) and removes it on all three exits. Cleanup covers exits only; a
|
||||
crashed session is covered by the TTL above. Verified end-to-end: the snippet
|
||||
as shipped arms the hook, the hook denies at `8/8` turns, and the removal
|
||||
snippet returns it to allow so Phase 6 can still spawn agents. Pinned by
|
||||
`tests/lib/doc-consistency.test.mjs` (STORM marker), which derives the
|
||||
directory name from `SCOPE_DIRNAME` in the hook, so renaming either side
|
||||
fails.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue