mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
* fix(continuous-learning-v2): warn when the observer never survives a hook invocation (#2489) The observer is lazy-started from a hook process that exits immediately afterwards. start-observer.sh's liveness check runs inside that still-living process tree, so it always sees a healthy observer and prints "Observer started (PID: N)". On native Windows (Git Bash/MSYS2) the reap happens later, when the hook's Job Object closes, so no self-check placed in start-observer.sh can ever observe the failure. The next hook invocation is the only place the death is visible, and _CHECK_OBSERVER_RUNNING already found it there -- then discarded it, deleting the stale PID file and restarting silently, once per tool call, forever. Users were left with an observer-start.log full of success lines and an observer that never completed a single analysis cycle. Record the "well-formed PID that is no longer alive" case, count consecutive non-survivals in ${PROJECT_DIR}/.observer-nosurvive-count, and log one explanatory warning when the streak reaches ECC_OBSERVER_NOSURVIVE_WARN_AFTER (default 3). Warning fires on equality so a persistent failure logs once per streak rather than once per tool call; finding the observer alive resets the streak. The Windows-specific explanation is gated on uname so Linux/macOS users are pointed at observer.log instead of a wrong diagnosis. Counting happens in the caller, not inside _CHECK_OBSERVER_RUNNING, because that function is invoked once per PID file and again under the start lock. The PowerShell backgrounding rewrite is deliberately not included: it cannot be exercised on a non-Windows machine, and untested process-spawning code is a worse outcome than an accurate diagnostic. * docs(continuous-learning-v2): state observer platform support and the new warn threshold The observer's Windows limitation was only discoverable by hitting it. Record it next to observer.enabled, where it is read before the flag is set, and document ECC_OBSERVER_NOSURVIVE_WARN_AFTER so the knob added alongside the warning does not repeat the undocumented-env-var problem tracked in #2573. zh-TW is intentionally left alone: translation parity is not enforced here and the repo rejects blind translation imports without translator review. * fix(continuous-learning-v2): serialize the non-survival streak under the lazy-start lock observe.sh runs on every tool call, so the streak read-modify-write could race between concurrent invocations -- losing an increment or logging the warning twice. That is the same class of bug the signal counter hit in #2296, and this repo's rule is to never fall back to an unlocked read-modify-write. Rather than add a second lock, move the increment into _START_OBSERVER_LOGGED. All three of its call sites already run inside the lazy-start lock (flock / lockfile / mkdir), so the update is serialized with no new machinery. Counting at the restart instead of at detection also means N racing hooks record one death rather than N. The reset stays in the caller: it is an idempotent unlink, not a read-modify-write, so it needs no lock. Adds a regression case pinning the increment inside _START_OBSERVER_LOGGED and asserting all three call sites remain locked. * fix(continuous-learning-v2): harden the non-survival threshold and warning output Three review findings on the #2489 diagnostic: - An all-zero threshold silently disabled it. `00` passes a digits-only check but compares as zero, and the streak only grows, so the warning could never fire. Normalize with base-10 arithmetic and fall back to the default for anything below 1. Base 10 is forced explicitly because a leading zero would otherwise be read as octal, and `08` is an arithmetic error that would abort the hook under `set -e`. The same normalization now guards the streak read. - An unwritable log silently swallowed the diagnostic. Build the message once and fall back to stderr when the append fails. This cannot spam: the block runs once per streak, not once per tool call. The counter write keeps its `|| true` -- observe.sh runs on every tool call and the repo rule is that hooks exit 0 on non-critical errors, so a full disk must not break tool use. - The live-PID test fixture used process.pid, which is 1 in a container and is deliberately rejected by _CHECK_OBSERVER_RUNNING; the reset case would then fail for the wrong reason. Use a spawned child and clean it up. Adds a regression case for the all-zero threshold. Verified on bash 3.2 (the macOS CI runner shell) as well as bash 5. * fix(continuous-learning-v2): warn only on a persisted streak increment If the counter write fails, the file stays below the threshold, so every later hook invocation rereads it, re-increments in memory, hits the equality check and warns again -- turning the once-per-streak diagnostic into once-per-tool- call spam. That is worse in exactly the case the stderr fallback added in the previous commit was meant to cover, since a disk that cannot take the log usually cannot take the counter either. Gate the warning on the write succeeding. The write stays non-fatal: it runs as an `if` condition, so `set -e` is satisfied and an unwritable counter costs a delayed diagnostic rather than a broken tool call. Tests: an unwritable counter must stay silent across repeated invocations while the hook still exits 0, and a leading-zero threshold ("08") must be read as decimal -- "00" alone did not exercise the base-10 conversion, since it is zero either way. --------- Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>