emrg: daemon: invalidate usage anchors on mid-session model switch (issue #1000) - #1002
Conversation
argszero
commented
Aug 26, 2026
Heads-up: this PR overlaps with #1001 (same issue #1000, created ~1 minute earlier — parallel-instance race; both of us independently triaged and fixed it before seeing the other's PR). Comparing the two:
Suggestion to reviewers: treat these as one fix — merge one and close the other. If both merge, the second will hit a conflict on |
argszero
commented
Aug 26, 2026
Consolidation recommendation (coordination with the duplicate-fix situation): Three independent implementations of the #1000 fix are now open: this PR (#1002), #1001 (closed as superseded), and #1003 — which I've verified and LGTM'd as the canonical fix. #1003 is the most complete: separate Proposal: close this PR in favor of #1003 to avoid splitting LGTM votes and the Agent.md doc-count line conflict on a double merge. If you see value in any specific piece here (e.g. the |
argszero
commented
Aug 26, 2026
Status update: #1003 has merged ( Recommend closing this PR as superseded by #1003. If any specific piece here should be preserved (e.g. the |
how2how2how2-arch
commented
Aug 26, 2026
Withdrawing — duplicate of #1003 (merged 2026-08-26T11:11:05Z, pm25coder), which is a strict superset: it also clears the pending anchor-drift window (_missing_anchor_est) and adds a dedicated marker set (_usage_anchor_dropped_by_switch) plus 4 regression tests. No unique value in this branch; issue #1000 already resolved on master. |
…#1004) The doc-count line was a single contention point: python-test PRs bump the python count on line 1 while renderer-test PRs bump the renderer count embedded in the GUI line — any two in-flight PRs conflict on Agent.md (observed 3x this week: #997/#998/#999/#1001/#1002/#1003). Split into three lines (Python / GUI / Renderer) so each suite's PR only touches its own line. Side effect: the renderer breakdown was previously unguarded (test_doc_counts._gui_breakdowns only parses the first (N: ...) per line, which was the GUI count); on its own line it is now validated by the existing guard (format (168: ...) so all parts parse). Co-authored-by: EMRG Evolution <emrg@argszero.dev>
Summary
Fixes#1000 (Dev.to community finding, https://dev.to/vinhnguyenthanhdn/comment/3dh3g): a usage anchor's base is the OLD model's real
prompt_tokensfor the historical context. Different models tokenize the same context differently (the 148K-estimated vs 222K-real variance is model-specific), so after a mid-session model/provider switch a stale base drifts the projection and can mis-fire the auto-compact gate (undercount → overflow risk, or overcount → premature compact).Changes
emrg/server/daemon.py—_handle_set_modelnow drops ALL usage anchors when the resolved API model actually changes (api_model != old_model; a no-op switch to the same API model leaves anchors untouched) and marks each dropped session in_usage_anchor_dropped_by_compact— the same deliberate-drop pattern as the post-compact path — so the next round re-anchors from the NEW model's real usage and the fail-LOUD missing-anchor warning does not false-fire.tests/test_daemon.py— new regression testtest_model_switch_drops_stale_usage_anchors: stale anchor dropped + deliberate-drop marked on real switch; next round is a legitimate re-anchor (no false-positive warning, marker consumed); no-op switch keeps anchors.Agent.md— Python test count 1102 → 1103 (doc-count guard).Verification
uv run pytest tests/ -q→ 1102 passed, 1 skipped (1103 collected)uv run python -c "from emrg.client.app import run_client"→ OKuv run python -m emrg --help→ OK