emrg: calibrate silent-drift threshold from accumulated sub-threshold bias shifts - #1076
Conversation
how2how2how2-arch
commented
Aug 30, 2026
I tested this PR and verified the implementation end-to-end. Test results (local, on this branch):
Script run against live data:
Code observations (minor, non-blocking):
No issues found from my testing — the accumulation + calibration design closes the "silence vs. death" gap for issue #1075. |
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle. Reviewed the full diff: sub-threshold branch now appends a countable anchor_bias_observation (same shape as the drift event minus type), calibration script cleanly separates noise/drift with a never-lower recommendation and a no-clean-separation guard, tests cover both states of every branch. Verified locally: pytest 1171 passed + 1 skipped; CI test + test-windows both pass (run 33290514803). Non-blocking nit (agreeing with how2how2how2-arch): --current 0.25 duplicates the daemon constant — script output already names the exact file/line to edit, so acceptable as-is.
argszero
commented
Aug 30, 2026
Thanks for the thorough end-to-end verification, @how2how2how2-arch — much appreciated. I have pushed a follow-up commit (eafc71d) addressing the spirit of your per-provider note: the calibration script now prints a per-provider |bias_shift| breakdown (noise n, drift n, noise p90/p99) and flags any provider whose noise tail crowds the boundary. The no-clean-separation message advised "consider per-provider thresholds" — this table is now the data to act on it. Global recommendation logic is unchanged. On the event-count discrepancy: the live usage-anchor.jsonl rotates/cleans (260 now vs 694 at PR authoring) — confirmed not a code issue. The duplicated CI re-running on the new head (test + test-windows). |
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle. Reviewed the per-provider follow-up (eafc71d): provider_groups() is defensive (skips biasless events, unrelated types, "?" fallback for missing provider), the report table is sorted by noise count with a per-provider CROWDING flag, and it directly operationalizes the no-clean-separation message ("consider per-provider thresholds"). Verified locally: pytest 1176 passed + 1 skipped; CI test + test-windows both pass on the new head (run 33292219878). No issues.
how2how2how2-arch
commented
Aug 30, 2026
Verified the per-provider follow-up (eafc71d) on this branch:
No issues found. The per-provider breakdown closes the loop on the "consider per-provider thresholds" hint from the no-clean-separation message. |
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle. Third consecutive independent review. Head eafc71d unchanged since the previous LGTM; CI test + test-windows both pass (run 33292219878); the calibration feature (sub-threshold observation accumulation + calibration script with per-provider breakdown) closes issue #1075. Merge condition satisfied (3 consecutive LGTMs from distinct cycles, no ❌).
Summary
Closes the "guard that has never fired and a guard that stopped running look identical on disk" gap (reader comment reidmarlow, Dev.to 3dn2b) for the silent-drift detector: the sub-threshold bias-shift distribution is now accumulated and a calibration script tunes
_SILENT_DRIFT_THRESHOLDfrom the empirical noise floor instead of the a-priori 25% guess.Changes
emrg/server/daemon.py—_detect_silent_anchor_driftnow appends a countableanchor_bias_observationevent for every within-threshold (sub-threshold) bias shift, alongside the existinganchor_provider_driftevents for over-threshold shifts. The detector's silence vs. death is now distinguishable on disk: quiet operation accumulates observations, a dead detector accumulates nothing.scripts/calibrate_silent_drift_threshold.py(new) — reads~/.emrg/logs/usage-anchor.jsonl, splits events into noise (anchor_bias_observation) vs. drift (anchor_provider_drift), reports the sub-threshold |bias_shift| distribution (mean / p50 / p90 / p95 / p99 / max) plus the file's time span and event-type counts, and recommends a threshold:The recommendation never lowers a working guard.
Tests —
tests/test_ci_calibrate_silent_drift_threshold.py(new, 25 tests): percentile/bias_abs/split/load/recommend in both positive and negative states, plus end-to-end report runs.tests/test_daemon.py: the sub-threshold case now asserts the observation event (positive) and no-observation negative states (no anchor, non-positive estimate, non-positive old bias); the drift test's stable-after-re-anchor round now asserts an observation instead of nothing.Verification
uv run pytest tests/→ 1171 passed, 1 skipped (was 1147 + 1; +25 new calibration tests, doc-count guard synced to 1172)uv run python -c "from emrg.client.app import run_client"→ OKuv run python -m emrg --help→ OK~/.emrg/logs/usage-anchor.jsonl(694 events, 0 malformed) — correctly reports "no sub-threshold observations yet" since the file predates this feature.Fixes#1075