Release v0.102.0 — cordless health needs a second opinion; the trunk is not a phone - #98
Merged
Merged
Conversation
…t for the cordless Accuracy fixes from the 2026-09-14 log review (links-01, calls-03, consistency-cordless-mos-vs-rtcp, links-02, the heartbeat half of links-05) plus three verified misses. devhealth - A handset MOS below mos_min degrades cordless_health only when the matched ledger leg corroborates it on the transmit side: loss_tx_pct >= 1.0 or a credible mes_tx < 78. Those lines come from callqos's own classify thresholds, checked against 190 non-playback ledger legs (lowest credible mes_tx 83.4; one leg ever at >= 1 % tx loss). An uncorroborated low score is still published, with last_mos_uncorroborated: true. - Every handset record scoring below mos_min is captured once to /data/state/cordless-mos.jsonl. The file is 0600, capped at 512 KiB, never written to /share, and uses a fourth _rotate_tail copy that the drift test now covers. Each row holds the whole rtpStatus record, the matched leg and a verdict. The mechanism behind the 2.2 is still unknown and is not patched. - Handset records are matched to their NEAREST ledger leg, with playback legs kept and tagged. A record whose nearest leg is playback is skipped. This closes the bypass where a playback leg next to a real call was confirmed by that call. - last_mos_age_s is published. rtpmon - The between-samples mass-drop set counts phone extensions only. Trunk transitions stay in the heartbeat record. - Warm-up also waits for extensions that have ever registered and are not gateway ports (the cordless), still capped at WARMUP_MAX_POLLS. The softphone that has never registered cannot hold it open. - worst_rtt_is_partial now counts the durable ever-registered set, so a fresh process sees the missing cordless on every warm-up cycle. - Heartbeat rows carry next_sleep_s, the sleep that actually follows the row. The published poll_interval_s stays the steady interval (that half of links-05 was refuted). Tests drive the real run() loops of both pollers. Mutation battery: 43 of 43 mutants killed, with green baselines before and after. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ered guards Review of 3146283 (verdict ship, three minors, three nits). All addressed. Whose leg judges the handset score (devhealth). Matching and corroboration ignored the leg's extension, so another phone's leg that hung up nearer could judge the cordless's score with that phone's transmit figures. A leg's ext is the channel that ran the context: the cordless for its own calls and for the playbacks aimed at it, the caller for a call made to it, the dialling phone for a page dialled from a handset. With cordless_ext set (the option defaults to 19 and devhealth already reads it): - the cordless's own leg is preferred unless another leg hung up more than CALLQOS_CLOCK_SLOP_S (5 s) nearer. The three 2026-09-14 degraded notices put the two clocks at most 0.7, 0.8 and 1.8 s apart; - a nearest playback leg of any extension still skips the record, so a dialled page logged under the dialler cannot slip in, and an own playback leg preferred over a nearer call skips too; - another extension's leg reads 'unmeasured' and cannot degrade, because its figures are about a different phone; - the capture row records match_rule (own-ext / nearest). Replayed over the live 300-leg ledger: 1242 records at cordless legs judge identically; at other phones' legs the chosen leg never changes, and the only difference is clean -> unmeasured (491). Tests that were missing: - an unmeasured leg (mes_tx 0.0) publishes a low score as last_mos_uncorroborated true, stays ok, captures 'unmeasured' (through run()); - the cordless counts toward the between-samples mass drop: four wired ports plus ext 19 is one notice naming 19 (through run()); - own-leg preference, the slop edge, the page and playback gates, and CORDLESS_EXT reaching the matcher through run(). An existing run()-driven stub had a fixed three-argument probe signature. When the call site grew an argument, the swallowed TypeError hung the suite, so the stub now has the real signature and a sleep cap that turns that into a failure. Nits: stale load_callqos_ts / last_call_mos references in switchboard-config, switchboard-backup-pre, test_switchboard_config and the test_devhealth docstring; the corroboration comment now says 1.0 % is classify()'s documented inaudibility bound, not one of its cut-offs; the DOCS warm-up sentence names every gateway port plus the other ever-registered phones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…is not a phone - devhealth: a low handset MOS degrades cordless_health only when the matched ledger leg corroborates it (loss_tx >= 1 % or mes_tx below callqos's 'good' line); otherwise it is published as last_mos_uncorroborated. Every low score is captured to /data/state/cordless-mos.jsonl (root-only, 512 KB cap). last_mos_age_s is published. Handset records match their nearest ledger leg, preferring the cordless's own leg, and a playback-tagged nearest leg is skipped (closes the neighbouring-call bypass). - rtpmon: the between-samples mass-drop set counts phones only; warm-up also holds for ever-registered non-gateway phones (the cordless), capped as before; worst_rtt_is_partial falls back to ever_registered in a fresh process; heartbeat rows carry next_sleep_s. poll_interval_s stays 300. Found in the 2026-09-14 live log review. 682+ tests; mutation batteries clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
These fixes come from the 2026-09-14 review of the live logs.
cordless_healthonly if the matched ledger leg corroborates it. Otherwise it is published aslast_mos_uncorroborated./data/state/cordless-mos.jsonl, so the mechanism can be studied. It is still unknown, so this adds no hypothesis patch.last_mos_age_sis now published.Endpoint trunktransitions were counted as phones. The mass-drop set now counts phones only, and the heartbeat still records trunk transitions.worst_rtt_is_partialno longer reads false with the cordless missing.next_sleep_s.poll_interval_sstays 300, because the devhealth rollup staleness check and the HA stale automation depend on it.Testing
run()and the poll loops.🤖 Generated with Claude Code