v0.88.0
Pre-release
Pre-release
0.88.0 (2026-07-11)
⚠ BREAKING CHANGES
- peers: the frontend Peer/PeersFile DTOs and the peers_read/peers:changed contract are gone; reachability reads flow through contacts_read and the Contact v2 shape.
- contacts: the peers_read/peer_* Tauri commands and the peers:changed event are removed (unreleased surface); the frontend re-source lands in Task T-E.
- mcp: the telnet_p2p_connect MCP tool is no longer exposed to the agent surface; agents can no longer dial a saved P2P peer's telnet endpoint. The operator's manual telnet P2P dial and the agent's radio P2P dial are unaffected.
Features
- contacts: Contact grows tier + reachability; contacts.json schema v2 (8f30768)
- contacts: delete the peers store — commands cutover, record-site re-point, keyring retarget (3cdcf91)
- contacts: observation recorder + inbound limiter with exact-callsign attach (3e56353)
- contacts: Recent section + contact-detail reachability (T-F Parts 1-2) (6e9fef6)
- contacts: success-only last_ok + last_ok_direction on reachability rows (T-F Part 0) (9bbf572)
- contacts: success-only last_ok timestamps (T-F Part 0) (2d3588a)
- finder: "Dial a station" manual-dial affordance — dial an unheard callsign through the peer-connect seam (T-G) (37d3df1)
- ft8: 51-tap Kaiser 4:1 decimator with response-verified committed table (tuxlink-b026z.3 T3) (65a3b55)
- ft8: canonical slot-WAV writer, tuxlink-jt9 preflight round-trip proven (tuxlink-b026z.3 T2) (a044dae)
- ft8: capture-capable device enumeration + hw:<index> resolver handle (tuxlink-b026z.3 T8) (8becb30)
- ft8: commands + events + lib wiring; sweep race re-check; clippy round 6 (tuxlink-b026z.3 T17) (999f7ef)
- ft8: decode types + jt9 discovery with sibling version probe (tuxlink-b026z.2 T4) (f6363d2)
- ft8: FT8 message field extractor with pinned grammar (tuxlink-b026z.2 T2) (58adc71)
- ft8: Ft8Config + sweep config, validation rules, alsa + tuxlink-capture deps (tuxlink-b026z.3 T9) (4ec95ad)
- ft8: host-side slot-WAV preflight — jt9 cannot be trusted to reject bad input (tuxlink-b026z.2 T3) (ce33e2a)
- ft8: jt9 runner — spawn/timeout/kill discipline, partial salvage, full failure taxonomy (tuxlink-b026z.2 T5) (0152d98)
- ft8: listener service core — supervisor, start sequence, snapshot, ring (tuxlink-b026z.3 T11) (67f57a6)
- ft8: listener state machine — axes, health flags, sweep element, N/k counters (tuxlink-b026z.3 T6) (0aabbb8)
- ft8: modem arbiter — pause/hold/resume + rig-session serialization (tuxlink-b026z.3 T14) (20ee1fe)
- ft8: modem yield seams — ardopcf choke wrapper, Dire Wolf pre-probe hook, VARA spawn_blocking (tuxlink-b026z.3 T15) (b365386)
- ft8: salvage-on-signal parity in the jt9 runner + contract doc edits (tuxlink-b026z.3 T7, resolves tuxlink-gujnz) (374870c)
- ft8: slot anomaly rules — surplus drop, clock-anomaly abandonment, lost-frames drop (tuxlink-b026z.3 T5) (bcb0ea4)
- ft8: slot pipeline — capture/decode threads, tap, backpressure, ring records (tuxlink-b026z.3 T12) (3fd0848)
- ft8: src/ft8 skeleton — traits, wire records, fakes, ALSA source, clock probe (tuxlink-b026z.3 T10) (25b9826)
- ft8: stop protocol + resume/device-absent recovery (tuxlink-b026z.3 T13) (8dfeaa8)
- ft8: sweep scheduler + provenance downgrade + composition pin (tuxlink-b026z.3 T16) (056f817)
- ft8: tuxlink-capture leaf crate + FT8 band→dial table (tuxlink-b026z.3 T1) (abcc392)
- ft8: tuxlink-jt9 leaf crate + jt9 stdout line parser (tuxlink-b026z.2 T1) (7ed80e3)
- ft8: wall-clock-true slot assembler — boundaries, gap fill, provenance (tuxlink-b026z.3 T4) (c0ec114)
- mcp: agent telnet P2P dial — (peer_id, endpoint_id) addressing, rebinding-safe denylist (ff5d084)
- mcp: curated find_peers behind the egress arm gate (bc3d4cd)
- mcp: engine-aware VARA agent egress — honor HF/SAT vs FM, drop the VaraHf hard-pin (93726ff)
- mcp: find_peers reads contacts; telnet host:port never crosses the agent surface (1c5ef02)
- packet: thread SessionIntent through the packet connect path (cfa8816)
- peers: ARDOP record sites — outer connect-fail, exchange, and answer (806428e)
- peers: circle peer layer on both maps (escaped divIcon, map_peers-gated) (3f347ed)
- peers: contact-link reconciliation + peer_id favorite cleanup; finder/map capabilities on (053a148)
- peers: endpoint-keyed keyring secrets with conservative migration and cascade clear (4688104)
- peers: favorites link — peer_id on FavoriteDial, recorder->recents bridge, double-count suppression (f1e8b64)
- peers: finder station-type filter + peer rows + capability hide (6f4928b)
- peers: frontend P2P connect seam — peer Connect dials p2p with via/path/intent (69fb08f)
- peers: frontend peer types, usePeers hook, distinct aggregation (cf037d0)
- peers: global observation sink + VARA record sites (dial + answer) (0102d87)
- peers: inbound auto-create rate limiter + quarantine counter with p2p_limits config (bf1203f)
- peers: packet record sites — dial + answer (ab5db94)
- peers: peer data model — types + serde wire shapes (c4e9458)
- peers: peer store — open/quarantine/flush, upsert/dedup, split routing, bounded caps (d3a66a6)
- peers: recorder drop-guard, central observation entry, Tauri commands + state wiring (8d500c7)
- peers: telnet record sites + global reject->limiter plumbing complete the 8-site matrix (0b193b1)
- vara: command-layer extensions — REGISTERED/WRONG parsing, Connected bandwidth+via, SessionType/RETRIES, corrected COMPRESSION vocabulary (005b660)
- vara: dial path — per-dial SessionType, WRONG fail-fast, SSID echo base-match, via threading (57a9ca2)
- vara: engine-split open sequence — HF/SAT full setter chain, FM MYCALL-only (6bc6087)
- vara: REGISTERED readiness gate — T_min settle, T_max fail-open, gate outside the session lock (53f1282)
- winlink: shared callsign module — canonical base, wire grammar, presented + display validators (e1875d5)
Bug Fixes
- build: cover EgressDenied in the operator telnet-dial guard-phase match (5d57493)
- config: add ft8 field to every exhaustive Config literal (CI E0063) (85f93c8)
- config: ft8 field in the two integration-test Config literals (CI E0063 round 2) (90e607b)
- contacts: key the heard/reached verb on last_ok_direction, never the failure-mutated direction (88eeb0f)
- favorites: peer_id is preserved through edits, never merged from the payload (09ef9bf)
- ft8: bound clean-exit pipe drains so decode_slot always returns; pin 12s slot budget + dropped-slot counter semantics for L2 (tuxlink-b026z.2 final review) (8fae18a)
- ft8: capture jt9 stderr lossily per the design contract — non-UTF-8 diagnostics must still surface (tuxlink-b026z.2 gate B) (c3464f9)
- ft8: enforce single-CQ-modifier pinned grammar in extract_fields (tuxlink-b026z.2 T2 review fix) (ebb2812)
- ft8: gate B hardening — pin all taxonomy arms, sentinel-aware partial flag, bounded version probe, prewarm cleanup, warm shared e2e harness (tuxlink-b026z.2 gate B) (ad8bce6)
- ft8: Gate B P2s — saturating boundary math at u64 edges + phase/N persistence pins (b1076f4)
- ft8: Gate E blockers — stop() preserves capture-wedged; spawn_workers/stop handle race closed (aca15ed)
- ft8: reject non-finite DT in the jt9 line parser; pin hashed-call test to the verified live capture (tuxlink-b026z.2 gate A) (92e7e18)
- ft8: T11 review Criticals — lock-across-I/O + non-test-target dead code (778dec1)
- lint: derive Debug on ExchangeOutcome — Task 14 test expect() requires it (2d2a737)
- lint: use contains() over iter().any() equality in peers store (67e2401)
- mcp: deny CGNAT 100.64.0.0/10 in the agent dial + repair stranded doc comment (c7b3a77)
- mcp: remove the agent telnet P2P dial (reverses Task 20) (d071092)
- merge: drop redundant Config field insertions — the auto-merge was already complete (a2a6390)
- p2p: gate the telnet dial password on operator provenance + cap observed endpoints (FIX-1/P1, FIX-2/P2a) (981db61)
- p2p: remove legacy-secret migration from the telnet dial path — close the auto-minted-endpoint two-step (FIX-1b/P1) (efe0f61)
- p2p: surface a selectable "P2P · ARDOP HF" row — close the wire-walk inbound gap (b8d8f97)
- packet: validate AX.25 grammar on packet target + via hops before the wire (FIX-3/P3) (be07f29)
- peers: arm the dial observation guard only at the CONNECT send (9d09ed6)
- peers: key reachability labels/tiers on success-only last_ok (T-F Part 0) (9171dad)
- peers: merge re-keys absorbed-endpoint keyring secrets; recorder conflict gate proven end-to-end (16833cd)
- peers: migration reports Migrated when only the legacy delete fails (f1fab78)
- peers: per-map peer tier scheme — finder reachability ramp, APRS outcome tiers (8622371)
- test: last_ok channel test asserts the true accumulated fail count (2, not 1) (5399dd1)
- test: packet dial-fail tests use a closing KISS wire — deterministic failure, no timing tune (81284ac)
- vara: LISTEN ON refuses while an ARQ exchange is in flight (e0b039a)
- vara: readiness gate breaks out promptly on mid-gate socket EOF (9619085)
Refactors
- ax25: fmt_addr is the single CALL-SSID formatter for roster via strings (dfaf329)
- contacts: reconcile P2pCapabilities bit set with the pivoted surface (5246429)
- favorites: rename Favorite.peer_id → contact_id (Rust + TS) (99ee3d0)
- ft8: drop stale build-phase comments + dead sweep binding (final review Minors) (fb70096)
- ft8: move dir into SlotJob — the clone was dead (T12 review Minor) (d88aedc)
- peers: re-source the frontend reachability layer from the dead peers store onto contacts (T-E) (812981c)