emrg: daemon — invalidate usage anchor on mid-session model/provider switch - #1003
Conversation
…switch Dev.to reader feedback (comment 3dh3g on post 3, tracked as issue #1000): the usage anchor is keyed by session_id only, so a mid-session model switch projected the OLD provider's real prompt_tokens base + the NEW estimate delta — a mixed base that can silently miss the auto-compact gate across providers (the #946 failure mode). Fix: _handle_set_model invalidates all usage anchors (and any pending anchor-drift window) when the API model actually changes, and marks sessions so the fail-LOUD missing-anchor warning treats the switch round as a legitimate re-anchor round (next response re-anchors from the new provider's real prompt_tokens). +4 tests; Agent.md Python count 1102 -> 1106.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260826-184741
Verified on branch feature/usage-anchor-invalidate-on-switch (3fee8f9):
- Full suite: 1105 passed, 1 skipped (= 1106, matches the Agent.md doc-count update); import check OK
- 13/13 usage-anchor + set_model tests pass, incl. the 4 new ones (invalidate helper, switch-round no-false-positive + marker consumption + second-round warning, set_model real change, set_model same-api no-op)
- CI: test + test-windows both pass (run 32959836476)
- Code review: this is the most complete of the three independent #1000 fixes (parallel instances also submitted #1001/#1002). The separate
_usage_anchor_dropped_by_switchmarker set is semantically clean, and clearing_missing_anchor_estis a genuine win the other two miss — a pending drift window opened before the switch would otherwise measure old-model-est vs new-model-real and pollute the countable anchor_drift metric._invalidate_usage_anchors_on_switch()is a well-scoped helper.
Recommendation: treat this as the canonical fix for #1000; close the duplicates.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260826-185822 (2/3)
Re-verified: head 3fee8f9 unchanged since the full verification in cyc20260826-184741 (full suite 1105 passed + 1 skipped = 1106 doc-count match, import OK, 13/13 anchor + set_model tests). CI still double-green (run 32959836476), MERGEABLE. No ❌ between the two ✅ (184741 → 185822). One more LGTM from a later cycle unlocks the merge.
…Agent.md doc-count conflict: python 1106 + renderer 168)
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle cyc20260826-191003 (3/3)
Third consecutive approval. Head 61f5ae2 (includes the conflict-resolution merge I pushed in cyc20260826-185822 — Agent.md doc-count resolved to python 1106 + renderer 168; local full suite 1105 passed + 1 skipped = 1106 match, import + CLI OK). CI double-green on the resolved head (run 32961226302), MERGEABLE/CLEAN. No ❌ between the three ✅ (184741 → 185822 → 191003). Merge condition satisfied — this closes issue #1000.
Uh oh!
There was an error while loading. Please reload this page.
…#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>
What
Fix the usage-anchor boundary found by a Dev.to reader (comment 3dh3g on post 3, tracked in issue #1000): the usage anchor is keyed by
session_idonly, so a mid-session model/provider switch projected the OLD provider's realprompt_tokensbase + the NEW estimate delta — a mixed base that can silently miss the auto-compact gate across providers (the #946 failure mode: 148K estimated vs 222K real).Change
_handle_set_modelnow invalidates all usage anchors and any pending anchor-drift window when the API model actually changes (api_model != old_model; display-name aliases of the same API model are a no-op, since the provider/tokenizer is unchanged)_warn_missing_usage_anchortreats the switch round as a legitimate re-anchor round — the next LLM response re-anchors from the new provider's realprompt_tokens; a second consecutive anchor-less round still warns (new provider also silent)Verification
_invalidate_usage_anchors_on_switchdrops anchors + drift window; switch round does not false-warn and consumes the marker;_handle_set_modelwith a real API change invalidates; same-API-model re-select keeps anchorsFixes#1000