Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions emrg/server/daemon.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -259,7 +259,7 @@ def __init__(self, llm_config: LlmConfig) -> None:
# (estimated_tokens, iso_ts) at anchor-loss warning time, so the
# estimator drift of the anchor-less window can be measured when
# the provider re-anchors (countable metric, not just a log line).
self._missing_anchor_est: dict[str, tuple[int, str]] = {}
self._missing_anchor_est: dict[str, tuple[int, str, str]] = {}
# Rant 2026-08-23T13:54:14: per-session dynamic-context snapshot
# (session_id → (text, injected_ms)) so unchanged context is not
# re-sent (context_refresh_interval_ms gating).
Expand DownExpand Up@@ -3023,12 +3023,18 @@ def _warn_missing_usage_anchor(
return # already warned once for this session
self._warned_missing_usage_anchor.add(session.session_id)
loss_ts = datetime.now().astimezone().isoformat()
self._missing_anchor_est[session.session_id] = (estimated, loss_ts)
# Issue #1011 (Dev.to post-3, heinrichneb): record WHICH provider went
# silent so cross-provider loss windows are attributable, not just
# countable — "a counter that can't say WHICH provider went silent is
# half a counter". The provider at loss time is stored so the drift
# measurement (possibly after a switch) can attribute both ends.
self._missing_anchor_est[session.session_id] = (estimated, loss_ts, self.llm.config.model)
try:
_append_usage_anchor_event({
"type": "anchor_loss",
"timestamp": loss_ts,
"session": session.session_id,
"provider": self.llm.config.model,
"est": estimated,
})
except OSError as exc:
Expand All@@ -3055,7 +3061,7 @@ def _record_anchor_drift(self, session, real_pt: int) -> None:
stored = self._missing_anchor_est.pop(session.session_id, None)
if not stored:
return
est_before, loss_ts = stored
est_before, loss_ts, provider_at_loss = stored
try:
_append_usage_anchor_event({
"type": "anchor_drift",
Expand All@@ -3064,6 +3070,11 @@ def _record_anchor_drift(self, session, real_pt: int) -> None:
"real_after": real_pt,
"delta": real_pt - est_before,
"loss_ts": loss_ts,
# Issue #1011: attribute both ends of a cross-provider loss
# window (a mid-session switch deliberately drops anchors per
# #1003, so provider_at_loss may differ from provider_after).
"provider_at_loss": provider_at_loss,
"provider_after": self.llm.config.model,
})
except OSError as exc:
logger.warning("usage-anchor stats append failed: %s", exc)
Expand Down
9 changes: 8 additions & 1 deletion tests/test_daemon.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -613,7 +613,7 @@ def test_invalidate_usage_anchors_on_switch():
server = _make_server()
server._usage_anchors["s1"] = (222_000, 148_000)
server._usage_anchors["s2"] = (100_000, 60_000)
server._missing_anchor_est["s1"] = (150_000, "2026-08-26T00:00:00+08:00")
server._missing_anchor_est["s1"] = (150_000, "2026-08-26T00:00:00+08:00", "gpt-4o-mini")

server._invalidate_usage_anchors_on_switch()

Expand DownExpand Up@@ -710,7 +710,10 @@ def test_usage_anchor_loss_event_is_countable(tmp_path, monkeypatch):
e1, e2 = json.loads(lines[0]), json.loads(lines[1])
assert e1["type"] == "anchor_loss" and e1["session"] == "s1"
assert e1["total"] == 1 and "timestamp" in e1
# Issue #1011: the loss event must name the provider that went silent
assert e1["provider"] == "gpt-4o-mini"
assert e2["session"] == "s2" and e2["est"] == 60_000 and e2["total"] == 2
assert e2["provider"] == "gpt-4o-mini"


def test_usage_anchor_stats_survive_restart(tmp_path, monkeypatch):
Expand DownExpand Up@@ -759,6 +762,10 @@ def test_usage_anchor_drift_measured_on_reanchor(tmp_path, monkeypatch):
assert drift["real_after"] == 180_000
assert drift["delta"] == 80_000
assert drift["loss_ts"] == loss["timestamp"]
# Issue #1011: both ends of the loss window carry provider identity
assert loss["provider"] == "gpt-4o-mini"
assert drift["provider_at_loss"] == "gpt-4o-mini"
assert drift["provider_after"] == "gpt-4o-mini"

# Re-anchor measured once — a second call (no pending loss) is a no-op
server._record_anchor_drift(_SidSession(sid), 200_000)
Expand Down
Loading