The PostToolUse cost warnings emit imperative text via additionalContext
("Stop and inform the user...", "Review whether...", "Consider whether...").
Subagents read additionalContext as an instruction and obey the "Stop",
abandoning their task and returning a prompt-for-direction instead of their
result — derailing multi-agent workflows. The main loop is also nudged to
halt mid-task.
Reword all three severities to pure-informational data: keep the
CRITICAL/WARNING/NOTICE label + the dollar figure (and the threshold), drop
the imperative sentence, and state plainly it is informational. No logic,
severity, or threshold change. Existing tests pass (they assert the labels +
severities, which are preserved).
Before: `COST CRITICAL: Session cost is $X. Stop and inform the user about high cost before continuing.`
After: `COST CRITICAL: session total ~$X (over $50). Informational only — not an instruction to stop.`
Co-authored-by: OrenG Tools <tools@orengacademy.com>
* fix(hooks): stop false loop warnings and repeated identical context warnings
Two PostToolUse monitor defects surfaced during a long single-turn session:
1. ecc-metrics-bridge hashToolCall fingerprinted Edit/Write/MultiEdit on
file_path ONLY, so several distinct edits to the same file produced the
same hash and tripped the loop detector ("stuck loop") even though every
edit was different. Now the hash includes the edit content
(old_string/new_string/content/edits) so distinct edits to one file hash
differently; identical edits still collide as intended.
2. ecc-context-monitor re-emitted the SAME warning every DEBOUNCE_CALLS (5)
tool calls even when nothing changed. Because the cost figure only refreshes
at Stop (turn) boundaries, a single stale value printed the identical
warning ~20 times within one turn. Dedupe on message content instead: a
warning surfaces only when its text changes (cost moved, new file count, new
loop) or on first escalation to critical, and is otherwise suppressed.
Adds regression tests for the same-file/different-content hash case.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(hooks): address CodeRabbit review (#2121)
- ecc-context-monitor: clear dedupe state when warnings resolve, so the same
warning text recurring in a later turn (context dips/recovers/dips, a loop
that stops then restarts) is surfaced again instead of suppressed as a
duplicate. Guarded so the no-warning hot path stays write-free.
- ecc-metrics-bridge: hash the FULL serialized edit payload and truncate the
digest, not the input. Slicing the serialized string to HASH_INPUT_LIMIT
first could collapse large edits sharing their first 2048 chars, reviving the
false-loop collision for big Write/edit payloads.
- Add regression test for >2048-char edit divergence.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mirror the previous commit's Windows-EPERM retry on the companion
`writeWarnState` in `scripts/hooks/ecc-context-monitor.js`. Same
race: two PostToolUse subprocesses writing concurrent debounce
state racing on `MoveFileExW`, target-in-use throwing EPERM on
Windows even though each writer's tmp path is now unique.
Implementation: import `renameWithRetry` from `scripts/lib/session-bridge.js`
(exported in the previous commit) instead of duplicating the helper.
The retry policy, backoff schedule, and main-thread `Atomics.wait`
strategy stay identical to `writeBridgeAtomic`.
Three writers in the repo now share the same atomic-write contract:
- `writeBridgeAtomic` (scripts/lib/session-bridge.js) — round 1 +
this round's retry
- `writeWarnState` (this file) — round 1 + this round's retry via shared helper
- `writeCostWarningIfChanged` (scripts/hooks/ecc-metrics-bridge.js) —
out of scope for this PR (already uses unique tmp suffix; a future
consolidation could move it to the shared helper too).
Local: `yarn test` green, `yarn lint` clean. The companion test
suite for `ecc-context-monitor.js` does not currently exercise
concurrent `writeWarnState` writes, but the helper it now uses is
covered by the `tests/lib/session-bridge.test.js` concurrent-write
regression added in round 1's last commit.
Mirror the previous commit's `writeBridgeAtomic` fix on the
companion `writeWarnState` in `ecc-context-monitor.js`. Same shape:
fixed `${target}.tmp` → `${target}.${process.pid}.${randomNonce}.tmp`,
plus best-effort cleanup of the tmp file on `renameSync` failure
(throws original error after cleanup).
`writeWarnState` debounces the context-monitor's threshold alarms
(`COST_NOTICE_USD`, `COST_WARNING_USD`, `COST_CRITICAL_USD`, plus the
context-remaining and loop-detection ones). Without unique suffixes,
two PostToolUse subprocesses racing on the warn-state file produce
either a corrupted JSON debounce-state on disk or an ENOENT throw
that the hook catches and swallows — either way the next warn-state
read returns the default `{callsSinceWarn: 0, lastSeverity: null}`
and the threshold alarms re-fire or stop firing erratically. Users
see warning messages flicker or vanish; debounce no longer works.
Three call sites in this repo now share the same atomic-write
contract:
- `writeBridgeAtomic` (scripts/lib/session-bridge.js) — primary
- `writeCostWarningIfChanged` (scripts/hooks/ecc-metrics-bridge.js) — cost cache
- `writeWarnState` (this file) — debounce state
`yarn lint` clean. Regression test covering both `writeBridgeAtomic`
and `writeWarnState` under concurrent load lands in the next commit.
Salvages the useful statusline/context monitor work from stale PR #1504 while preserving the current continuous-learning hook runner wiring.
Adds the metrics bridge, context monitor, statusline script, shared cost/session bridge utilities, and tests. Fixes the reviewed false loop-detection hash collision for non-file tools, avoids default-session cost inflation, sanitizes statusline task lookup, and records hook payload session IDs in cost-tracker.