Repository navigation
Emit the anchor-bias heartbeat from the round loop with an explicit anchored:false reason #1078
Description
Emit the anchor-bias heartbeat from the round loop with an explicit anchored: false reason, so a skipped round is distinguishable from a detector that never saw it
Source
Reader comment 3dn6k by vinhnguyenthanhdn on "A guard that has never fired and a guard that stopped running look identical on disk" (https://dev.to/pm25coder/a-guard-that-has-never-fired-and-a-guard-that-stopped-running-look-identical-on-disk-177f), 2026-08-30T05:53Z.
Reader's insight
The anchor-bias-heartbeat (added in #1073, consumed by #1076's calibration) is emitted per anchored round FROM INSIDE _detect_silent_anchor_drift — so anything that stops anchored rounds entirely yields zero heartbeat lines, byte-identical to the detector having stopped:
"that is the same ambiguity you removed one level down with anchor_loss, reappearing one level up at the call site."
Current state (master 981f037)
- Heartbeat logged at
emrg/server/daemon.py:3128-3135, inside_detect_silent_anchor_drift(L3094) — AFTER the early returns at L3114 (if not old or old[1] <= 0 or estimate <= 0: return) and L3119 (if old_bias <= 0: return). - Call site at L2594-2606:
if final_usage:→pt = final_usage.get("prompt_tokens")→if pt:→_detect_silent_anchor_drift(session, pt, estimate). The detector is only reached when the LLM response carries prompt_tokens AND a previous anchor exists. - Failure modes that go fully silent:
final_usagemissing/empty (config flag, upstream change, stream edge case) → detector never called → no heartbeat;prompt_tokensmissing/zero → same;- no anchor yet / anchor invalid (first round, post-compact, post-switch, provider stopped returning usage) → early return before the heartbeat.
_warn_missing_usage_anchor(L2998-3050) covers only the auto-compact projection gate, fires once per session, and does not emit the drift heartbeat.
Proposed change
Move the heartbeat to the round loop so every round emits exactly one anchor-bias-heartbeat line with an explicit state:
- Keep the existing inside-detector heartbeat as the
anchored: truecase (it already logsbias_shift/threshold/old_bias/new_bias). - In the round loop at the usage-processing point (L2594-2606), log
anchored: falsewith a reason when the detector is skipped:reason=no_usage—final_usagemissing/empty;reason=no_prompt_tokens—final_usagepresent butprompt_tokensmissing/zero;reason=no_anchor— no previous anchor (not old or old[1] <= 0);reason=invalid_estimate—estimate <= 0;reason=invalid_bias—old_bias <= 0(kept as-is, reachable only via the detector's early return).
- Keep the greppable marker
anchor-bias-heartbeatand debug level unchanged so existinggrep "anchor-bias-heartbeat"workflows keep working; only thereasonfield is new.
This preserves "log unconditionally, alert conditionally" one level higher: a skipped round is now a first-class, labeled observation instead of an absence.
Acceptance (self-verifiable)
- A round with no
final_usageemitsanchor-bias-heartbeat ... anchored=false reason=no_usage. - A round with
final_usagebut noprompt_tokensemitsanchored=false reason=no_prompt_tokens. - A round with no previous anchor emits
anchored=false reason=no_anchor. - A normal anchored round still emits
anchored=truewithbias_shift(existing behavior unchanged). - Tests assert each state (positive + negative per the repo's verification rules); CI test + test-windows green.
Activity
argszero commentedon Aug 30, 2026
Thanks pm25coder — this is a correct and valuable observation. The reader's point (vinhnguyenthanhdn) is exactly right: the heartbeat living inside
_detect_silent_anchor_driftmeans any round that skips the detector (no usage, no prompt_tokens, no anchor, invalid estimate) produces zero heartbeat lines — byte-identical to the detector having stopped.Confirmed on master 981f037:
_detect_silent_anchor_drift(L3094), after the early returns at L3114 (not old or old[1] <= 0 or estimate <= 0) and L3119 (old_bias <= 0).if final_usage: → if pt: → detector. Missing/emptyfinal_usageorprompt_tokensnever reaches the detector.I agree with the proposed design: keep the inside-detector heartbeat as the
anchored: truecase, and emitanchored: falsewith an explicitreason(no_usage / no_prompt_tokens / no_anchor / invalid_estimate / invalid_bias) on every skip path, preserving theanchor-bias-heartbeatgreppable marker and debug level. Implementation: extract the call-site usage-refresh block into a_refresh_usage_anchorhelper so the round loop emits exactly one heartbeat per round, and split the combined early return so each reason is distinguishable. Tests will assert each state per the repo's positive+negative verification rules. I'll implement this now.emrg: emit anchor-bias-heartbeat with explicit anchored state every r…