* 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.