CodePulse v2.3.145 — Anchor-file resolver eliminates env-var fragility
Hooks now resolve their CodePulse install via an installer-written anchor file (`codepulse-home.txt`) instead of the fragile `CODEPULSE_HOME` env var. A new `/health` field surfaces hook resolver state so silent failures are visible. Triggered by an outage where the env var disappeared from a user's HKCU registry mid-session, taking every Telegram tool surface dark with no diagnostic.
What broke
A user's installed CodePulse v2.3.142 stopped surfacing tool calls in Telegram even though the bridge was running, hooks were registered, and /health happily reported hooksTriggered=42. Investigation traced it to the CODEPULSE_HOME user-scope env variable disappearing from HKCU:\Environment during a session. The hook script's resolver chain — env var → registry → script-location inference — failed at all three tiers, so the script silently exited at line 47 with no log entry, no diagnostic, no /health change. From the operator's seat, hooks were "running" while in reality nothing reached the bridge.
Likely causes for the env-var disappearance: setx's 1024-character Path-truncation race clipping other vars, AV / profile-cleaner sweeps, registry pruning, elevation context drift. The whole class is a known Windows fragility surface.
What changed (TAB-649)
- Anchor-file resolver as priority #1. The installer now writes
codepulse-home.txtnext to the hook script (D:\ClaudeCode\hooks\codepulse-home.txt). The hook reads this file FIRST. Plain UTF-8, no BOM, single line: the absolute path. Self-contained at the install site — no registry, no env var, no inference required. - 4-tier resolver chain with structured trace: anchor → env → registry → inference. Each failure step is recorded so
/healthcan report exactly which tier(s) failed. - Self-heal diag flag. When all four resolvers fail, the hook atomically stamps
%APPDATA%\CodePulse\diagnostics\hook-unresolved.flag(UTF-8 JSON, atomic tmp+rename write) and exits 0 (never blocking Claude). The bot's/healthendpoint reads the flag and surfaces:This is what would have caught the original outage 4 hours earlier. Successful hook runs clear the flag (Remove + truncate-to-empty fallback if the file is locked) so"hooksHealthy": false, "hooksReason": "resolver-failed:anchor-missing,env-empty-or-invalid,inference-no-env"/healthself-recovers within one Claude tool-call. - Stale-window logic. Flags older than 5 minutes are treated as recovered (the next successful hook clears them anyway). Future-stamped flags from clock skew also treated as stale (symmetric
Math.abswindow). - Test-only registry-bypass env var so the resolver-chain integration test isolates from the host's real HKCU (registry can't be mocked).
- Anchor-write is non-fatal. A transient AV / disk hiccup at anchor-write time logs a WARN but the install still succeeds — the hook will fall back to env / registry / inference if the anchor isn't there.
Two-round adversarial review
Round 1 (diff-scope) found 4 HIGH + 8 MEDIUM + 1 actionable LOW. All applied: install-fail-hard relaxed to WARN, registry-bypass for tests, atomic flag write via tmp+rename, truncate fallback for locked clears, symmetric stale-window for clock skew, treat-unparseable-ts as stale, env-vs-anchor mismatch warn surfacing in hook-events.jsonl, strict-match assertions in tests, orphan-tmp sweep after concurrent writes.
Round 2 (fresh-eyes) found 3 MEDIUMs (all comment/cleanup) + assorted LOWs. All MEDIUMs applied: tightened the readHookHealthFlag JSDoc, corrected the MoveFileEx atomicity claim (it's near-atomic on NTFS, not strictly atomic), added orphaned .tmp.<PID> cleanup sweep.
Tests
21 new tests in tab-649-anchor-resolver.test.ts across 4 sections: place-hooks anchor write semantics, uninstall cleanup, resolver-chain via isolated hook copy (anchor / env / inference / all-fail), and readHookHealthFlag staleness + parse semantics. 250+ adjacent tests pass with zero regressions.
Looking forward
This release was the first of four tracking the same epic — TAB-665 — that hardens the install-time path resolution end-to-end. v2.3.146 follows with installer Step 5 demoted to non-fatal so transient registry hiccups can't roll back working installs. v2.3.147 ports the same architecture to the bash hook for Linux/macOS parity.