Bridge
MeshSat Bridge changelog: standalone gateway releases.
Generated from the commit history of meshsat: features and fixes, newest first, one section per tag. Untagged work on the main branch is listed under Unreleased. MeshSat is a prototype and has never been deployed to a real user.
Latest tagged release: v0.1.0
Tagged 4 March 2026. This release added direct serial access for standalone installations, satellite pass scheduling, forwarding rules and delivery tracking. See the v0.1.0 release record for its features and fixes.
The much longer Unreleased section records later work on main; it is not a separate tagged
release and does not establish that every feature has been tested on hardware.
Unreleased (main, last change 2026-10-29)
Features
- web: a Warnings page lists the public warnings the kit holds, in force first with their marks, times, source, label, via and bearers, read again on every warning event and once a minute, and a banner on the dashboard and the booth screen carries the headline and the label while one is in force (8faee40a)
- warnings: a relayed public warning also goes to every LXMF peer heard in the last day on a free link, once per digest and peer through the delivery ledger, is one warning event on the Bridge’s event stream, and stands at the top of every Community Post page while in force (62151db0)
- tak: a dispatcher’s chat the Hub could not hand this kit over MQTT comes as one frame, a satellite MT or an SMS from the Hub’s number, is delivered as the same GeoChat, and the crew’s answer and the kit’s word go back as frames on that bearer (216f2256)
- cell: the warning relay broadcasts a relayed warning on the kit’s own 2G cell, 4380 for a test, the EU-Alert identifier for a real one only where the owner cleared it and channel 50 otherwise, through an allow-list that refuses every real identifier as cbs.sh does and a TX-log row before each; an Update replaces, a Cancel deletes; POST /api/cell/cbs/test and GET /api/cell/cbs for the bench (c9d4e36b)
- web: an LXMF voice note plays in the kit’s web UI, Codec2 decoded by the vendored libcodec2 wasm on first play, Opus in the browser’s own player, a photo shown inline (afb91671)
- api: the web app asks for the kit’s API token on a 401, keeps it in the browser, sends it on every call and logs in for the event stream’s cookie (fc81458c)
- api: the Bridge’s API can require a token, off by default: a Bearer header or the login cookie gets in, so do the kit itself and a phone through the Hub relay, CORS narrows to the kit’s own origin, and the token is set, rotated and cleared through the API (8ddb389a)
- post: the operator screen closes, reopens and purges the post, and shows the receipt printer as it last reported itself (4e455994)
- post: the operator closes the post and everything it stored is purged 30 days later or now, the portal and its notice say so, and an approved post and a reply print a slip on the kit’s receipt printer, which reports itself to the Bridge (9779d556)
- tak: a kit tells the Hub what became of a dispatcher’s chat on its own tak/chat/status: queued in the ledger, undelivered with the reason, failed when the ledger gives up (4993da58)
- warnings: the kit takes a public warning digest the Hub signed with the directory key it pins, on its own warn/in or as a satellite MT, keeps it, honours an Update or a Cancel, and puts it on the mesh as an alert and a text and on APRS as a bulletin, each once (b252eaef)
- post: the Community Post, a kit’s no-app front door: a captive portal on its own listener, an approval queue, one plain “@” lane text per post, the Hub’s “[from]” replies parsed to a pickup code, and the host AP files installed disabled (b7bfa6aa)
- lxmf: a voice note and a photo ride in a message’s LXMF fields, are kept on the kit and served by the API, and the rules forward the text only (92dcf314)
- reticulum: the kit joins its workspace’s Private Reticulum network with the access code the Hub hands it, keeps that one link current, and takes at most 60 inbound LXMF messages a minute (bf5ea819)
- reticulum: a Reticulum TCP link can carry a private network’s access code, and then carries only this kit’s own traffic and never connects that network to the kit’s mesh or other links (5eea43dd)
- tak: a dispatcher’s TAK chat to one crew reaches that node as a direct message, and the crew’s answer goes back to the dispatcher (23161237)
- hopset: Settings > Media Hopping shows each link’s last probe and what each peer reports about its own links (d711136c)
- hopset: two Bridges tell each other their links’ hop state over STATUS-NET, shown and never acted on, and a time-sync request answered on its link is that link’s probe (8f0bd76a)
- hopset: media hopping gets one switch in Settings, off by default, so routing stays as it was until someone turns it on (daafa0c7)
- hopset: the hop set takes the owner’s numbers, counts repeated radio refusals and silence as signs, and brings a link back more slowly each time it fails again (d67419d3)
- hopset: the delivery worker, the mesh receipts and the receivers feed the hop set; MESHSAT_HOPSET makes it the route gate, GET /api/hopset shows it (e969c6c9)
- hopset: the hop set keeps per link a state built from contact-independent evidence, with a two-sign rule, hysteresis and a floor (f83b0f97)
- routing: failover groups and the delivery intents skip a link whose band is jammed or whose receiver is deaf (05151076)
- sms: chat SMS go out in app SMS wire v2, whose frame names its codec inside the ciphertext, and v1 is still read by the old rule (a2239b8e)
- directory: the Hub settings take the provisioning bundle’s directory key and pin it when none is, so the HTTPS fetch never runs, and never over another key (74c5ab48)
- lxmf: every LXMF message the bridge sends carries its message id, an intent’s own, and a repeat of one already taken in is dropped, also after a restart (44d9263c)
- keys: the key list gives each key’s check value, so a phone and a kit can show they hold the same key without showing it (2f664212)
- hub: the birth declares each satellite chain’s format explicitly, sealed or plain (7a7b88e8)
- hub: a kit’s birth says whether each satellite chain seals its payloads, and the satellite and SMS framing each send path uses is one function the gateways and the S3-2 measurement share (b4a56fb2)
- transforms: smaz2g sends a text as typed when SMAZ2 would not make it shorter, and a satellite payload that starts with the version byte is Reticulum only when it is a signed announce (051ac60c)
- delivery: GET /api/delivery/stats says what became of each delivery attempt, per bearer, interface and size, without calling any of it radio loss (5f937e50)
- directory: an operator can remove a local address that keeps a Hub contact from its own, and a team send names the contact that holds it (11e8adcc)
- directory: send to a team: one submission, one intent per member, frozen at submission (9c5ec210)
- directory: the bridge applies its Hub’s signed directory whole, keeps its own edits, and moves the Hub key only by a signed record (11afb420)
- sos: an SOS carries its own id, so the Hub pages once whichever bearers carry it, and a cancel goes on each of them until the Hub has it (df4419fe)
- intents: a text to a contact’s bridge goes through the Hub and closes delivered to the MeshSat app, behind MESHSAT_HUB_MSG_ROUTE (6a28669f)
- hub: a Bridge in an organisation’s tenant publishes and subscribes under that tenant’s topic root (3b305817)
- delivery: a text by TETRA that a MeshSat Bridge on the group acknowledges shows as acked by a station, and one nobody acknowledged as may have been sent (3d21a68e)
- tetra: MeshSat Bridges on a TETRA group confirm each text they receive, so a text lost in a collision both radios missed is sent again (6aba9c83)
- delivery: a message can go by TETRA to a talk group, by the MeshSat 2G cell to a phone on it with the handset’s receipt, and by ZigBee to one device (790df436)
- web: the dashboard follows the hardware: a widget hides when its device is unplugged, a device plugged in for the first time brings its widget, the person can remove and add widgets, and TETRA has a card (9f28239f)
- web: Settings has a TETRA tab with the radio, its settings and a test send, and the README lists TETRA Direct Mode as LIVE (d03d8314)
- delivery: a message can go by Iridium SBD on a 9603, one session each, read as taken, not sent or may have been sent from the modem’s own status (87374463)
- tetra: a Motorola TETRA radio on a kit’s USB carries texts as SDS, radio to radio in Direct Mode, through the delivery ledger and the access rules (db9fef62)
- delivery: the status card updates as soon as the bridge writes about its message, and a closed card still shows a late answer (61ee6ac8)
- delivery: the compose screen sends to directory contacts and shows each message’s delivery status as the bridge knows it (a4f0f9b6)
- delivery: the RockBLOCK 9704 is a delivery-intent route, one MO at a time, with each final status read for what it means (3e97f890)
- delivery: paid intent routes are priced, reserved against the cap and charged; SMS joins delivery intents (5d83a725)
- delivery: APRS joins delivery intents: our own message id on every frame, an ack from the addressed station confirms it (49b3ca9e)
- delivery: an LXMF proof that arrives after the send gave up, or after a restart, still confirms the intent (d556d73b)
- delivery: unsupported send strategies are refused, seeded defaults become ALL_BEARERS, Hub policy pushes apply or refuse each row (101f1d23)
- delivery: contact sends can become delivery intents with ordered fallback, receipts and restart recovery, off unless MESHSAT_DELIVERY_INTENTS=true (72e6eac2)
- hemb: HeMB bonding is experimental and off unless MESHSAT_HEMB_EXPERIMENTAL=true (c130e79d)
- cell: the cell runs inside the Bridge: plug the Pluto into a kit and the 2G cell comes up by itself, radio keyed with the TX log written first (2f9ac841)
- cell: a Pluto on a kit’s USB port is adopted as the cell’s SDR: the host starts the core, the Bridge binds, the operator keys the radio with a logged purpose (a3a3fd93)
- cell: a phone on the MeshSat 2G cell texts the kit and gets its reply, over SMPP into the delivery ledger (8683af23)
- lxmf: access rules carry messages between LXMF and the satellite, so a Sideband user and a MeshSat app can talk across Iridium (0cf187b3)
- printer: a slip when a Reticulum message crosses the satellite link (40792dce)
- rns: a satellite link can count as several hops, so Reticulum clients wait for its round trip (ba9c8973)
- rns: a satellite or SMS link can carry Reticulum announces for a short list of addresses (05ea3e65)
- sos: every route that is set up is a leg that waits for its link, as MeshSat Android sends an SOS (f472331c)
- transport: the RockBLOCK on a MeshSat node, through the node’s Bluetooth pipe (5f6dd3ad)
- sos: the alarm test reports its position by satellite as Android does, and an SOS by satellite passes the credit budget (86c21f86)
- api: the satellite mailbox check a person asks for, and what it found (33846aa3)
- api: a chat’s own SMS key, and SMS that go out exactly as written (812e33e3)
- APRS-IS, a position beacon, TAK without a TAK server, and Reticulum over TCP with TLS (33362076)
- api: the Hub link’s state and reason, a switch, a connection test, and Hub settings that keep the CA (658a6c30)
- api: the contact card the phones exchange, signed by the routing identity (fa9c8001)
- engine: zones alert: every mesh position is checked, and the crossings are kept and served (155a8238)
- api: the audit log can be counted and read in pages, so a full copy can be saved (9f3a806d)
- api: the SOS carries the caller’s words, an alarm test for the Hub, the Hub link’s state, the adapter’s power, a keepalive on the event stream, topology links and positions with their node (043dd04d)
- mesh: the node over Bluetooth LE, adopted from the app as on Android and iOS (c9038ac9)
- cellular: the ModemManager modem counts as present hardware for the SMS gateway (b3b6a5cb)
- cellular: SMS through ModemManager for Linux phones (9bbe13ba)
- transport: Meshtastic over TCP to a meshtasticd on the same host (2e14b78b)
- hf: hf_0 gateway receives 10 m shouts on the borrowed RTL-SDR and transmits them only with an operator callsign (dadbef83)
- hf: 2-CPFSK modem for the 10 m codec: IQ and audio modulator, decimator, offset and timing search, soft LDPC decode (8a0cfe6e)
- hf: the public 10 m HF codec: inner frame, LDPC(128,64) with the normative H, 16-way interleave and burst framing, byte-matched to the recipe and a NumPy reference (8d8244d8)
- iridium: CrossTalk-compatible RNSI framing for Reticulum packets over IMT, toggled live from Settings > Routing (55816c78)
- reticulum: UDP, AutoInterface and KISS TNC interfaces, managed at runtime with RNode from Settings > Routing, verified against rnsd (70fa45b0)
- rnode: RNode over Bluetooth LE via the Nordic UART service, and a race-free radio validation (f8fc24ae)
- rnode: RNode LoRa radios as a Reticulum interface over serial and WiFi, verified against rnsd (148af1a4)
- lxmf: LXMF endpoint with packets, links, resources and stamps, verified against Python LXMF 1.1.0 (14411626)
- rns: the bridge runs the upstream-compatible Reticulum node on every interface (f6e3472c)
- rns: Reticulum transport node, links, path requests and proofs verified against Python RNS 1.5.4 (a6a0b710)
- reticulum: RNS 1.5.4 wire primitives: token, single-packet encryption, link formats, proofs, IFAC, timestamped announces (3a9837d3)
- satellite: a quiet kit fetches the messages waiting for it at Iridium (29b1b6de)
- timesync: a slow link asks for the time less often, and Settings shows who answered (88f2ba28)
- oob: a management command carries an expiry, and a kit refuses one that arrives too late (f4d457aa)
- aprs: the status names the cause when a PicoAPRS transmits and hears nothing (99e9e584)
- passes: predict Iridium passes offline from elements shipped in the binary, refresh via the TLE API when Celestrak fails (a4216cd2)
- mesh: keep the radio’s plain-text console lines too (a634855d)
- mesh: keep the radio’s own log, reboot flag and notifications (0244e7bb)
- printer: scripts/slip-counter.sh, and zero the counters after every test (b5943a4c)
- printer: print the whole path, not just the bearer that carried it (6353d7d9)
- printer: the hat on the 666th slip, and a way to preview a slip (91e79df0)
- printer: number every slip, and a hat at 666 (d8c42988)
- printer: the owner’s sentence in bold under the callsign (eeefab32)
- ttc: second screensaver poster, the TTC26 hall with stand S27 lit (80d4fe92)
- booth: print a receipt for every message that arrives on a kit (9cf00fa9)
- hub: keep the correlation token on inbound SMS, and publish mesh text to the Hub (ec34802e)
- relay: serve the bridge API to the tenant’s phones through the Hub relay (b2a4452b)
- ttc: both kits pair a T-Deck Pro, captioned (A) on tesseract and (B) on parallax (ce640cb9)
- aprs: report a serial TNC that has sent nothing since its link opened as silent, with a PTT hint on the panel (945cd285)
- ups: battery events on the event stream when the pack changes state (d4a92e3c)
- health: show device health beside the link state for gateways, the modem and the booth screen (486cbd6a)
- oob: follow a peer kit’s radio to its new node number (b567c680)
- time: establish the clock before the bridge starts, and never export one we cannot trust (002d1b50)
- web: the kiosk poster is an interlude in the attract loop, not a lid: 20 s every 4 min after 3 min idle (757aaa45)
- web: kiosk poster screensaver after 30 s idle, any touch or a live message wakes the panel (c5e5d9d2)
- web: TTC handhelds are the T-Deck Pro on tesseract and a T-Deck Plus without the SMA stub (e022d602)
- ttc: the four routes become one row each, riding their own lane (ba18ac3c)
- oob: the Hub can pair as a management peer, by its own key or the kit’s (40b18e14)
- ttc: fourth booth path, kit to kit over Iridium IMT, with a satellite lane on the panel and satellite traffic in the packet feed (68aa1752)
- ttc: the island with the kit and the handheld is the hero of the booth screen, the message strip is one row (7371ba4b)
- hub: wire the satellite fallback uplink, position/health/SOS frames to the Hub over IMT/SBD or SMS when MQTT is down (6aecb106)
- cellular: plaintext peers for the Hub SMS leg, [origin] prefix parsed, the Hub’s echo of a kit’s own SMS dropped (e3fae80b)
- ttc: booth flow selector, three paths drawn on the panel, tap a lane to choose this kit’s way out (eafb96cd)
- aprs: beacons carry the same repeat copies as messages (08289820)
- api: POST /api/messages/simulate-mesh-rx feeds a text through the radio-receive path for relay pre-flight without a handheld (71c12754)
- aprs: tx_repeat sends each message twice on the air; the far kit dedups (ef9dfc25)
- aprs: status beacon, Direwolf timing keys, watchdog rungs gated on a hung Direwolf; relayed texts travel as text on text bearers (c2b32a95)
- failover: groups skip a member whose receiver is deaf, for the APRS-first booth relay (bfff288d)
- api,web: nodes carry other_mesh, the dashboard lists this mesh first and counts only it as peers (dde1101e)
- web: TTC composer, double-tap the kit to type a message on the panel and send it to the local or the remote mesh (34f97762)
- web: leaving TTC mode is an easter egg, three taps on the mark then one on the QR (3874c6c9)
- web: TTC device drawings are the real T-Deck Plus and T-Echo, photos with a live screen overlay (409bc513)
- web: TTC island line counts only decrypted LoRa, shows unreadable frames from other meshes (1708a4e6)
- web: TTC mode islands are mesh A msat-ttc-01 on tesseract, mesh B msat-ttc-02 on parallax (29cbb493)
- power: power widget on the left of the clock in both headers (cd4c3e8e)
- power: power widget sits next to the clock in both headers (ec764488)
- power: power widget in the top bar, host poweroff action, POST /api/system/power (bcba019b)
- web: TTC mode follows the table, tesseract left of parallax (13957286)
- web: TTC mode audit pass, kit name in the header, honest labels (4243f858)
- web: TTC mode for the visitor, diptych layout, tap cards, replay, QR (b5a7fc4e)
- web: TTC mode device art from the real hardware, kit CAD render and LilyGO drawings (d94b49fe)
- kiosk: panels never dim on mains power, AC-aware
--idlemode for meshsat-backlight (71774336) - engine: live packet feed for TTC mode, packet SSE events, /api/packets, delivery events carry their row (bebf7e0f)
- web: brand re-skin and TTC mode booth screen replacing Run Full Demo (2e2d9134)
- web: ?pointer=1 keeps the kiosk profile but shows the mouse cursor (0d058498)
- aprs: serial KISS TNC path for the PicoAPRS V4, gateway fan-out to ax25_0, TNC receive health (76749893)
- health: RTL-SDR, GPS, IMT and SBD probes, spectrum scan serialisation, health on the dashboard (b429001b)
- health: ZigBee and cellular heal ladders, live zigbee_0 binding, cellular quiet window (12606134)
- health: device health watchdog with a heal ladder for the mesh radio (e9558a2c)
- scripts: DMR858M UART configuration tool for the bench swap (39f706eb)
- aprs: receive-health signal and a receive watchdog that walks the recovery ladder (355f380b)
- scripts: kit installers ship the RTL-SDR blacklist and the Goodix touch rebind unit (7252efce)
- oob: RESET level 3 cuts USB port power on a per-port switchable hub (fa133979)
- web: Remote Mgmt settings tab for OOB management frames (d105fac2)
- api: OOB routes, Prometheus counters, Hub mgmt commands, key-import peer registration (2705b185)
- deploy: OOB host agent, socket-activated units, tmpfiles and installer (5a612ff0)
- oob: management frame service, executor, classifier hooks and bridge wiring (9d409808)
- dispatch: per-delivery destination and class, verbatim SMS, directed APRS, SMS sender address (56cab4b0)
- keystore: mgmt channel type 0x08 and CreateBundleFromEntries (986004ed)
- database: v54 OOB peers and log, per-delivery destination and class (008eca77)
- oob: frame codec, replay window, key derivation, command and target tables (7ec91709)
- kit: kit-to-kit P2P bearer over the MT7612U dongle (9fd51ca3)
- kit: codify field kit WiFi provisioning, disable firmware roaming (f82bc7e3)
- sdd-tier6: customer-facing CHANGELOG.md generated from git history (51fb73ca)
- sdd-tier5: per-tag release notes generated from outcomes (3c61d2cc)
- sdd-tier4: CI gate + retrospective outcomes (34fd1342)
- sdd-tier3: acceptance test mappings + worker dispatch packets (293aa7e1)
- sdd-tier2: observability blocks on every task (936c905c)
- dashboard: demo polish: run-all button, sparklines, channel matrix, map marker pulse (9c9f8a0a)
- ble: host-side systemd unit pins BT adapter flags pre-bluetoothd (f3f40e3b)
- ble: pin advertising identity to hostname-derived static random MAC (b6433cf0)
- ble: resilience for bridge↔bridge Reticulum peer link (acd2f141)
- compose: plumb DCF77 env vars through standalone compose (9db481d3)
- timesync: DCF77 longwave stratum-1 time source (e4bbbea6)
- hemb: persist bond-decrypted payloads to the message store (9f29f0a0)
- hemb: MESHSAT_MESH_MTU env var for bond mesh bearer MTU (434b29c5)
- dashboard: APRS widget shows E2E encryption state (8a0fbe64)
- web: 9603 GPIO status + power-cycle button in Iridium card (78354ca9)
- iridium: OnOff GPIO + HardPowerCycle API (3a2fde6e)
- iridium: RI GPIO input: hardware ring-alert path (c73980f2)
- iridium: NetAv GPIO input: SBDIX veto + status exposure (8a0121b4)
- hemb: bond-level end-to-end encryption (encrypt-then-code) (0a6a8fae)
- keys: POST /api/keys/import: bridge-side bundle ingestion (4bbea1ce)
- aprs: end-to-end encryption over AX.25 using existing transform pipeline (36aca3ae)
- spectrum: detail view opens as full-screen modal, not a route (a71b67e5)
- spectrum: persist scan history + per-band detail view (f926dcff)
- p2p: overlay-IP reconciler: bulletproof WiFi-Direct TCP anchoring (60971996)
- wifi-p2p: auto-wire peer into Reticulum TCP + HeMB bond (d4350a0c)
- wifi-p2p: WiFi-Direct kit-to-kit link over USB dongles (81169d68)
- ui: WiFi adapter picker + dashboard Links widget (57de8100)
- federation: capability manifest + trusted peers + BLE exchange (4202a1e5)
- ble,wifi: GATT client + WiFi peer-link (4f05342b)
- hub: BT/WiFi command dispatcher over Hub MQTT (048c8347)
- bluetooth: detect + label MeshSat kits by advertised GATT UUID (4642ae8f)
- system-wifi: merge iw-dev signal dBm into WiFi status (930b94d5)
- ui: Bluetooth peers + WiFi manager in Settings (895b2b27)
- kiosk: long-running-renderer defences in depth (6631cb7c)
- image: add BT + WiFi + namespace tooling to runtime (6d0ba92a)
- api: port BT + WiFi host-ops from HAL: standalone-mode pragma (ef87d1f1)
- api: port BT + WiFi management from cubeos/hal (99fc4cd8)
- dashboard: Active Comms tile speaks HeMB: bond label + per-bearer dots (3fc897e4)
- web: bundle-hash polling auto-reloads kiosk after deploy (5cb4bc50)
- kiosk: swayidle backlight dim + sudoers-scoped wrapper (5563e072)
- system: wire X1202 UPS battery into bridge + operator tile (c658a23c)
- kiosk: one-shot Pi 5 kiosk provisioner (e7710eec)
- web,api: Phase-9: /pair/scan browser wizard + directory health envelope (e3eedb72)
- web: Settings > Devices: Arm pair mode + paired-clients list (e5bc394f)
- pair,api,database: pair-mode protocol v1: arm/claim/refresh/list/revoke (52ad8b74)
- web: PWA + touch keyboard + SPA fitness polish (e8131bc3)
- web: team broadcast + clustered map + USMTF library + FieldHelp (88d680cc)
- web,api: SOS panic button + USMTF templates (394b9598)
- directory,web: QR contact cards + trust levels + FLASH hard-block (ad78042e)
- directory,web: SIDC on contacts + milsymbol Map pins (efe190e0)
- web: Engineer keyboard shortcuts composable (9649e745)
- web: IQ-70 i18n dictionaries + useLabel composable (36408ef1)
- web,api: NVIS night theme + backlight sysfs bridge (393ab87a)
- web: Settings: 5 Operator tabs + Engineer drawer (517f48b4)
- web: Radios view + persistent StatusStrip (f27aa07b)
- web: People view: directory browser + trust dots + verify flow (2341db8a)
- web: Inbox: unified view, bearer-coloured bubbles, delivery ticks (50d117cb)
- web: Compose view: contact-first, precedence-second (11f2a3f3)
- web: primary nav reshape: 5 items + More + mobile bottom bar (14b701b7)
- web: Operator/Engineer mode toggle with localStorage (d0e519cd)
- engine,api: SendToRecipient + POST /api/messages/send-to-contact (e4beee00)
- database,engine: precedence-aware queue + FLASH preemption (5a8e0ab8)
- directory,api: vCard 4.0 + CSV import/export (Bridge) (44e21fc1)
- hubreporter: directory_push + trust_anchor_rotate handlers (36741860)
- api: retire legacy SMS-contacts endpoints (1e3c427e)
- types,database: STANAG 4406 precedence on every delivery (c44e7f91)
- engine: per-contact AES traffic key resolution (3efa7ca0)
- directory: internal/directory package: Store + SQLStore (5143b172)
- database: unified directory schema v44-v48 (64832f89)
- aprs: bundle Direwolf as supervised subprocess (3332c621)
- spectrum: MIL-grade operator UX + technical-debt closure (D1-D12) (4fbf1e8d)
- spectrum: add always-visible ECCM quick-reference table (bd89f126)
- spectrum: MIL/ITU compliance: MIJI-9 metrics + ECCM guidance (64343c42)
- spectrum: replace waterfall widget with scannable 5-band status list (5e629ade)
- spectrum: true connected/disconnected detection: USB sysfs check (03a318b1)
- spectrum: multi-feature classifier: kills false-positive alerts (67ac507c)
- spectrum: auto-retry calibration for bands that failed Phase 1 (every 60s) (1e141dec)
- spectrum: calibration progress bar + countdown in widget and page (a984b854)
- spectrum: paint waterfall from t=0 (publish during calibration) + 512-col upsampled smooth heatmap (SDR#-style) (a233edc1)
- spectrum: pause/play button + proper mini waterfall strips in widget (884bedc1)
- spectrum: real spectrum-analyzer look: FFT trace + Turbo waterfall + axes + hover cursor (a04294c8)
- spectrum: compact dashboard widget + /spectrum page + popup toggle + ACK mute (99c063a0)
- spectrum: Phase 2: waterfall widget + sticky jamming ACK modal (648cecb1)
- spectrum: Phase 1: SSE stream + TAK CoT + hub alert relay (4d3ae932)
- spectrum: monitor GPS L1 + LTE Band 20/8 + install rtl_power (0a016747)
- zigbee: all four follow-ups: staggered reads, leave req, level/color, IAS Zone (9a771994)
- zigbee: ZCL Read Attributes: pull sensor values on demand (7797fcc3)
- zigbee: complete device manager: DB, API, UI, TAK CoT bridge (b08d6afd)
- zigbee: BDB commissioning fallback + notification decode (6ffb48d3)
- zigbee: permit-join, ZCL temp/humidity decode, dashboard widget (df24cfb7)
- zigbee: add permit-join API + dashboard widget (f101fb70)
- aprs: 4-layer Direwolf self-healing system (266c624e)
- aprs: add APRS dashboard widget with heard stations and activity (50739b1c)
- deploy: add tesseract01 field kit to CI deploy matrix (bd5ad515)
- deploy: support field kit layout and per-target SSH user (95a7ab81)
- hubreporter: add spectrum monitoring to Hub telemetry (9a33022e)
- spectrum: RTL-SDR jamming detection with auto transport failover (fff55f21)
- routing: add BLE Reticulum interface via BlueZ D-Bus (1c0430df)
- keystore: complete v2 key bundle support with signing pubkey endpoint (a72673d6)
- api: add per-IP HTTP rate limiting middleware (908fd623)
- api: add Prometheus metrics endpoint at /metrics (faca8ddb)
- map: show TAK-relayed positions alongside mesh nodes (3ec132ca)
- tak: close data loop: bridge receives TAK CoT from Hub MQTT relay (2cb101ad)
- tak: show ‘Via Hub’ when bridge relays CoT through Hub to OTS (38d23c3f)
- tak: 100% compliance: protobuf inbound, team filter, GeoChat, 9-line (e58a7129)
- map: bearing/distance measurement tool + team group filter (caf39a8b)
- tak: Mission Browser + Certificate Lifecycle + Monitor polish (9eccab96)
- tak: add Missions, Data Packages, and SA Snapshot tabs to TakView (1a08072d)
- dashboard: enhance TAK widget with connection status dot and rate (fb8f7c86)
- tak: CoT event stream SSE + TakView page + dashboard widget (a568f1ef)
- map: TAK/CoT-compliant markers with MIL-STD-2525 SVG icons (c5363885)
- tak: DataPackage + Mission API: Marti REST client (afac7761)
- tak: auto-enrollment via TAK Server port 8446 (4bb7aff5)
- tak: multicast SA: serverless peer-to-peer LAN discovery (4b6aa272)
- tak: certificate auto-enrollment via TAK Server port 8446 (1eb4abc5)
- tak: TAK Protobuf v1 wire format + stream framing (99758743)
- tak: expanded CoT types: waypoints, circles, route/map types (db52b646)
- tak: position enrichment: GPS accuracy, velocity, coalescing, takv (ed7b23a4)
- ui: add TAK Settings tab for CoT gateway configuration (61877edb)
- hemb: wire cellular_0 as HeMB bearer + SMS peer API (513347b3)
- cellular: add /api/cellular/at debug endpoint (08cb347e)
- keys: Hub-driven key rotation + key_ref in transforms (7b41b588)
- hemb: add fault injection API + decode latency percentiles to stats (f5be2ea9)
- hemb: adaptive reassembly timeout + decode latency tracking (baa667e7)
- hemb: receive-side reassembly bonder + POST /api/hemb/send endpoint (7f404873)
- hemb: add Reticulum packet sender as bearer for bond groups (2c454e9e)
- ui: Hubble v3: fix flow table, lighter cards, port rows, timestamps (ae297cfd)
- ui: Hubble v2: left-accent cards, MTU info, connection dots, rule badges (803369e4)
- ui: Hubble-inspired visual overhaul of ObservabilityGraph (24983674)
- ui: replace Topology + HeMB tabs with Hubble-inspired observability dashboard (c132f83e)
- hemb: add RLNC matrix inspector + hemb_events persistence (d45c761b)
- hemb: add TUN/TAP adapter for IP-over-HeMB bonding (91c8dcdf)
- hemb: add observability dashboard: event bus, SSE, bearer graph, flow table (a0bb7e46)
- api: add bond group CRUD + HeMB stats REST endpoints (4e39c092)
- hemb: implement HeMB core protocol + MeshSat integration (4b90fb5e)
- hemb: add frame format, CRC-8, header detection and promotion (9ca83f69)
- routing: add ZigBee Reticulum interface for CC2652P coordinator routing (9ef79665)
- routing: add SMS Reticulum interface for cellular packet routing (c77e70cc)
- routing: add mTLS support to MQTT Reticulum interface for Hub relay (768c02b5)
- hub: sign birth messages with ECDSA-P256-SHA256 for MQTT anti-spoofing (5f7af498)
- hub: use shared MQTT username ‘meshsat’ + NATS password for Hub auth (6d0f1f90)
- dtn: wire custody transfer into delivery pipeline: point-to-point, not broadcast (403cdf33)
- wire: wire DTN fragmentation + RLNC coding + FEC into live pipelines (06b1a02e)
- wire: wire TimeService + mesh consensus into main.go startup (f8da5cc2)
- protocol: implement 4 protocol enhancements: FEC, Time Sync, DTN, RLNC (fcfe7885)
- e2e: add live E2E validation tooling for full-stack testing (46e6a24b)
- hub: mTLS client certificate via UI: paste PEM in Settings (c181562c)
- hub: TLS CA config for hub reporter + routing handler updates (f71a6b80)
- api: add bridge restart button: POST /api/system/restart (2b12afdd)
- routing: wire AX.25 and MQTT Reticulum interfaces in main.go (4b6e3c61)
- hub: UI-managed Hub MQTT credentials: paste from Fleet page (e0f01b89)
- hub: populate all health fields: CPU, memory, disk, interfaces, Reticulum, burst (c10ebed0)
- dashboard: Reticulum network widget: peers, nodes, links, interfaces (a908baf3)
- routing: UI-managed TCP peers, listen port, and announce interval (7635a877)
- routing: wire TransportNode + PathFinder + InterfaceRegistry in main.go (9f27f201)
- proto: adopt official Meshtastic protobuf bindings (db6b1951)
- dashboard: credential management tab in Settings (8fa9c5d3)
- hubreporter: credential_push/revoke command handlers (6cdb4d14)
- credentials: centralized cert/credential management for bridge (ea546a97)
- keystore: cross-platform key exchange with QR bundles and envelope encryption (31d55d21)
- resources: add resource transfer API and DB persistence (62bca541)
- routing: wire resource transfer and all transport interfaces (5731d1b2)
- routing: add Astrocast, MQTT, and AX.25 Reticulum interfaces (0e660fa0)
- routing: wire Iridium SBD and IMT as Reticulum interfaces (1fb6da59)
- gateway: pass scheduler works for both SBD and IMT (586d8e98)
- routing: wire Reticulum routing subsystem into processor (4c201f74)
- hub: wire real command handlers for send_text, send_mt, flush_burst (555e7d08)
- routing: wire TCP/HDLC Reticulum interface in main.go (1d43ca6e)
- gateway: multi-instance gateway support for xN modems of same type (fa2a2721)
- api: async message send: queue instead of blocking on satellite (cf10e0b3)
- imt: integrate jspr-helper C binary into meshsat (fa6c0805)
- imt: add jspr-helper C binary for RockBLOCK 9704 serial I/O (e3275910)
- imt: add checkProvisioning JSPR call and /api/iridium/provisioning endpoint (ce647b66)
- hub: bridge-to-hub uplink protocol: HubReporter, device streaming, offline queue, satellite fallback (c31c8f57)
- gateway: add TLS client certificate and CA support to MQTT gateway (a0ddb9b8)
- ci: add bananapi01 as deploy target + Playwright project (3c385531)
- transport: parse ROUTING_APP, request_id, reply_id, via_mqtt (30d289e7)
- api: add /api/cellular/signal/fast cached endpoint (c990c7cc)
- transport: full zero-config auto-detection: remove all device port env vars (1b905858)
- gateway: wire device supervisor events into gateway manager for hot-swap (2840ca9d)
- transport: add firmware version, MSSTM time, sleep/wake, power profile (52142d14)
- deploy: replace bananapi01 with pifour01 in deploy pipeline (26c5d04a)
- transport: wire DeviceSupervisor to API server and dashboard (26db59ff)
- transport: add USB tty recovery to DeviceSupervisor, remove debug logging (59190aaf)
- transport: add SetPort methods and gateway IMT support for DeviceSupervisor (16eca001)
- transport: add DeviceSupervisor for stable device discovery and auto-reconnect (7e81a360)
- deploy: source per-device env overrides from /cubeos/config/meshsat.env (f5b52b33)
- ui: dynamic Iridium widget: auto-detect SBD vs IMT, show modem info (8375ff74)
- transport: add JSPR protocol and DirectIMTTransport for RockBLOCK 9704 (606aae92)
- transport: add RockBLOCK 9704 IMT auto-detect and wire into startup (1bf9e583)
- transport: auto-request NodeInfo from unnamed mesh nodes (efd9b373)
- api,ui: add RequestNodeInfo to refresh peer names from mesh (f1711a95)
- ui: rename Radio to Meshtastic, add channel summary to Dashboard and Peers (5a46e255)
- ui: add webhook log + dedup mesh msgs in dashboard widget (237b8cae)
- ui: add mesh text messages to dashboard unified message widget (8922a56b)
- radio: add Meshtastic radio configuration page (69b80e40)
- api: add radio setup detection endpoint (6e5dada2)
- cell: add SIMCom AT+CPSI? cell info parser for A7670E (33828721)
- cell: add T-Call A7670E detection and auto-PIN-unlock (4343efd1)
- routing: wire TCP/HDLC Reticulum interface into app lifecycle (1565d434)
- routing: chunked resource transfer with segment bitmap and SHA-256 verification (ea91b002)
- routing: HDLC framing and TCP Reticulum interface for RNS interop (5facb7c6)
- routing: path request/response flooding for dynamic route discovery (853cd22d)
- astrocast: implement missing Astronode S binary protocol commands (d1af24d3)
- routing: register Iridium and Astrocast as Reticulum interfaces (5d4c718c)
- routing: wire Transport Node into app.go, add InterfaceRegistry (0ec515f2)
- routing: Transport Node with forwarding table and cross-interface relay (663bb486)
- link: 2-packet handshake, HKDF-SHA256 keys, AES-CBC+HMAC encryption (b880a30d)
- routing: switch announces to Reticulum wire format (f2d2ca75)
- routing: switch Identity to Reticulum 3-stage dest hash computation (bc22776d)
- reticulum: port Hub wire format library, replace custom packet.go (82e72740)
- routing: add Reticulum wire format packet header library (2c93f629)
- compat: protocol version byte, cert pinning, canned codebook, docs (ca2d8a46)
- ui: Hub auth UI, API key management, RBAC visibility, E2E tests (a988d6f9)
- ratelimit: add per-device SBD credit budget limits (e5e7bf10)
- auth: API keys with RBAC role enforcement (54230dc7)
- auth: tenant isolation layer with per-table filtering (600097b5)
- auth: harden OAuth2/OIDC with PKCE, RP logout, refresh token rotation (7624ccd7)
- hub: add Cloudloop credit balance polling (3b536434)
- deploy: add production deployment guide with Caddy, MQTT, and backup tooling (d17fffe2)
- api: device registry enhancements: status, IMEI validation, MQTT hub publish (bc453911)
- channel: register TAK and APRS channels in registry and gateway factory (e3bd9c54)
- gateway: APRS adapter: Direwolf KISS TCP with AX.25 encode/decode (8312c13d)
- gateway: TAK/CoT adapter: bidirectional CoT XML over TCP/TLS (d5164dcd)
- database: device config versioning: delete method and full tests (071dafb4)
- api: add device registry CRUD with IMEI key (5e63b8c5)
- web: fix audit log viewer and add map enhancements (aca95872)
- ui: wire all field intelligence features into frontend (44a608f3)
- field intelligence features: 8 new capabilities (c86c6331)
- api: complete MESHSAT-41: enable/disable, reorder, stats, failover update (f18d1498)
- api: add /api/config/diff endpoint for preview-before-import (0c5f3f94)
- compress: add MSVQ-SC rate-adaptive lossy semantic compression (eab0ca88)
- engine: wire QoS levels, sequence numbers, and ACK tracking (aa49a741)
- routing: wire routing package into main app event loop (8bfb9c20)
- routing: add path discovery, link establishment, and bandwidth limiting (da5fd760)
- routing: implement Reticulum-inspired announce broadcasting and delivery confirmations (f4f1602c)
- transport: implement AES-256-CTR encrypted passthrough relay (fca52999)
- web: add loop prevention metrics to Bridge view (653d35db)
- delivery: store-and-forward workers with pre-wake prep and priority eviction (7530fbc1)
- contacts: unified contact book with multi-transport conversation view (d26c6f07)
- cellular: enable SMS encryption + improve SMS format (b9c24749)
- meshsat: add Cloudflare DynDNS provider, rewrite README for v0.3.0 (f969360c)
- meshsat: per-rule SMS contacts, Dynu DynDNS, Huawei ICCID fix (e4ba9834)
- meshsat: direct node/portnum pickers in access rule form (a22a5ca2)
- meshsat: auto-bind interfaces to unambiguous USB devices, auto-online (5bc86ed6)
- meshsat: SIM card management with ICCID auto-detect and phone lookup (d8b9d13f)
- meshsat: dashboard widget dropdowns, queue height fix, deploy HAL coexistence (433cce7d)
- meshsat: RSRP/RSRQ display, roaming status, data usage tracking (8d2cf47b)
- web: SMS inbox, cell broadcast archive, signal quality labels (acb10e50)
- meshsat: SMS contact groups in access rules + contact manager UI (dba6546b)
- meshsat: add mobile data auto-reconnect and multi-APN failover (65baf2d5)
- web: interface selector dropdowns on widget titles (55486ef9)
- meshsat: operator refresh, phone number, unified queue, map fix, gateway SSE events (212527b5)
- web: complete LOW priority audit items: geolocation, deliveries, channels, factory reset (c56d894b)
- web: frontend audit: audit log, config export, structured editors (8f80f001)
- web: add ZigBee settings tab with paired device list (22300ae3)
- gateway: add ZigBee 3.0 gateway with Z-Stack coordinator management (ce50d0ab)
- meshsat: ZigBee 3.0 transport channel with Z-Stack ZNP codec (24c97ee7)
- meshsat: transport-aware transform validation (f7142488)
- meshsat: AES-256-GCM payload encryption transform (c051e117)
- meshsat: SMAZ2 compression with Meshtastic dictionary (325315b4)
- meshsat: transform pipeline + Ed25519 signing + audit log (b41943b0)
- meshsat: failover group runtime resolution (a85bbb14)
- meshsat: YAML config export/import (show running-config) (6266826d)
- meshsat: loop prevention, TTL expiry, QoS propagation (9e32b364)
- meshsat: worker lifecycle, HELD deliveries, drop forwarding_rules (4234570b)
- web: add Interfaces view for v0.3.0 interface management (2ccd6cbd)
- meshsat: wire v0.3.0 access rules into processor dispatch path (b92fcde4)
- meshsat: add v0.3.0 access rule evaluation engine (1399bb9b)
- meshsat: add interface-aware gateway routing (77c826a2)
- meshsat: add v0.3.0 interface model schema + InterfaceManager (86cfde03)
- meshsat: complete cellular modem frontend integration (39d120ca)
- meshsat: full cellular modem support: PIN unlock, CBS alerts, SMS history, cell info (c597e7ce)
- meshsat: fix AT-MSGEO ECEF parsing + multi-pass Iridium geolocation (76532514)
- meshsat: add GPS reader and time sync to Meshtastic radio (5bd97398)
- meshsat: add serial health watchdog for stale CDC sessions (549ec241)
- meshsat: add per-priority message expiration policy (e118c509)
- astrocast: direct transport, config wiring, and settings UI (9522a337)
- Astrocast LEO pass prediction: TLE manager, API, and dashboard tab (affab19a)
- any-to-any RuleEditor + cross-bridge tab (217d8b87)
- v0.2.0 any-to-any routing: channel registry, delivery ledger, unified rules engine (155ff89f)
- SMS contacts CRUD, webhook activity log, full UI wiring (24a0a461)
- UX overhaul: top bar labels, chart sizing, tabs, pages (70484e67)
- top bar redesign, activity log telemetry values, queue/signal UX (979d542b)
- UX polish: activity log clarity, delete queue API, top bar fixes (cdcf0dc9)
- frontend renovation: widget sizing, node modal, unified chart, SBD history, map themes (68cad888)
- full Meshtastic device management: config reads, position, S&F, range test, canned messages, neighbors (e39b60d8)
- smart scheduling intelligence: use custom elevation, GSS history, and MO counters (e76e436d)
- configurable min elevation filter with environment presets (20537bb6)
- GSS registration history tracking + pass/signal/GSS mini-charts (b61f9ac1)
- configurable mailbox polling mode + manual check button (00dcf9d2)
- dashboard UX overhaul: drag-and-drop widgets, stats modals, activity persistence (ea434a4a)
- add stats-for-nerds debug panels to Bridge view (f3fd3d4d)
- cellular dashboard, unified location, activity log events, infinite DLQ retry (4704c8e4)
- add 4G/LTE cellular gateway with 3-way bridge and cost risk analyzer (2895ce69)
Fixes
- aprs: a callsign, audio card or PTT device with a line break, space or # is refused before it reaches direwolf.conf, and KISS mode applies the same 1-6 character callsign rule as APRS-IS (0faa9daa)
- interfaces: a link bound to a device that is gone follows the one device of its type on the bus, cell_0 reads available only while the cell gateway runs, and sms_0 reads as the cellular modem does (5d45800c)
- gateway: the TAK server, KISS and SMPP addresses are joined with net.JoinHostPort, so an IPv6 literal host can be dialled (06afe614)
- api: the demo status is encoded without copying the run’s lock, so go vet passes (835b07f1)
- mesh: a text waits out the radio’s own 2 s interval instead of being dropped by it, so every chunk of an OOB reply goes on air; a position, waypoint or traceroute too soon answers 429 (af0c5420)
- hopset: the paid alarm names a free link’s state as it is, recovering as well as excluded (115bc47f)
- lxmf: a message goes as one packet only up to LXMF 1.2’s 287 bytes of content, not 1.1’s 295, so the 288 to 295 byte case travels over a link as the pinned reference does (786a9310)
- rns: a newer announce on a leaf displaces a stale path to the same destination elsewhere, never a neighbour’s path used within the reverse table’s lifetime, and SetLeaf changes the mark and the table under one lock (bc7e0c41)
- tak: a position the radio replays from its node table after a config download is dated by when the kit heard it, and one heard longer ago than cot_stale_seconds is not exported on any output, so a Bridge restart no longer puts nodes last heard weeks ago on the Hub’s map as crews seen this minute (0f9db42e)
- cell: a cell broadcast the kit’s modem receives keeps its pages, its coding and its language, is stored once, and reads 919 and 3471 as NL-Alert, 4370 as presidential, 4379 as amber and 4355/4380/4381 as tests; the modem is asked for every broadcast in the form the A7670E takes (2b2a4a21)
- hubreporter: a send_mt from the Hub goes on the satellite link the kit carries today, not on the 9704’s name every kit once had (521f3a65)
- tak: a position export carries the fix’s own time, and a chat to a crew the kit has not heard for a day says so in the log instead of vanishing (e508c5b1)
- rns: a satellite link opened without an extra-hops value gets 20, so a stock Reticulum client’s direct message waits long enough for the round trip (21d5c545)
- hopset: a STATUS-NET request keeps the media hopping interval it was made in, and a reply carries our hop state only while it holds that interval, so turning media hopping off waits for it (755512fa)
- hopset: turning media hopping off ends its interval, so a hop report, reply or probe from before is never read after, and off waits for a share or a reply carrying our state that is under way (23cbdce1)
- hopset: the STATUS-NET hop exchange tells a peer once per 10 min under concurrency, leaves paid bearers’ replies as they were, reads only replies to our own requests, caps them per peer and keeps nothing while off (6e6ce119)
- hopset: a time-sync answer on ax25_N is the probe of the APRS link aprs_N, and nothing is recorded per link while media hopping is off (f1039e3a)
- hopset: the hop form is canonical, one link per interface and no leading zero, and a reader takes the last form in a STATUS-NET body (e8cca4f0)
- hopset: only the modem’s own failure or answer counts as a bearer refusing, never a send its caller cancelled or a queued SMS that never ran (738c29ac)
- hopset: native gateways’ own refusals reach the hop set again, turning media hopping off stops its audits and events at once, and the settings page keeps an unsaved choice (a022c2a6)
- hopset: the intent sends feed the hop set, the paid alarm fires at a real submission, and the hop set learns which devices are absent (1d57101c)
- hopset: answered signs stay cleared, a recovering link waits for re-admission, a known-absent device is down, and every net change is audited (dd9c265c)
- spectrum: only a scan pass that classified every calibrated band measures the reader, so failed scans can’t stretch a jam verdict’s age limit (31eb92ec)
- spectrum: a jam verdict’s age limit is the classifier’s own recovery dwell, or two rounds of a slow reader (d98555a4)
- iridium: an AT-MSSTM count of zero is no usable time, as an MSGEO stamp of zero already was (673492a7)
- health: the signal recorder writes a reading at the time the modem observed it, so polling an old cached reading never makes it fresh (2e7377e1)
- routing: the retry path’s failover reads the same route gate as the groups and the delivery intents, so it skips a jammed member too (5888a14a)
- spectrum: a jam verdict carries its age and reads unknown when stale or the monitor is off, the 2 m band also answers for the APRS link, and the mesh band gets the LoRa power floor (edab8709)
- health: the interface health score reads each modem’s own signal and prices IMT, the free radios and the 2G cell right, and says when its success rate rests on no data (7054af8e)
- iridium: MSSTM and MSGEO read Iridium time in ERA3, the era it counts in since 14 Jan 2026, and a missing stamp reads as unknown, not now (9a620790)
- sms: the SMS history, receiver and relay read a clear app SMS wire v2 frame, keep what they cannot read, and let a key’s reading outrank it (3d1c3708)
- rns: a single data packet may carry what fits the MTU once encrypted, as upstream RNS allows, so a full single-packet LXMF message goes (b515ace3)
- lxmf: an inbound message and its id are filed in one transaction and handed on only once filed, and a ledger row keeps one persisted UUIDv7 as its message id (8f4ba9ab)
- transforms: the smaz2g warning says MeshSat Android reads it on a node’s 9704 and the Hub only relays it, as the docs do (ae44caa7)
- sos: the legacy SOS frame to the Hub’s SMS number fits one SMS whatever the bridge id, as the C10 start frame does (52da137c)
- imt: the 9704’s firmware version comes from the modem’s firmware query, as the official library reads it, not from the hardware version (ff0b094c)
- compress: text with bytes 0x01-0x08 survives SMAZ2 with the default table, and every other text compresses exactly as before (9e6e9315)
- keys: the key list and Settings show each key’s check value instead of the key’s first four bytes (a13adcdd)
- messages: since and until take an RFC 3339 time and find that day’s messages, and the topology view’s message links come back (f99edd4f)
- iridium: the SBD gateway takes the modem’s IMEI at the post-subscribe check, so the birth names a modem that answered after the start read (0b46b973)
- hub: a birth goes out only with a stamp stored before it, and one that cannot read or store its stamp is held back and sent once it can (4566ccab)
- hub: every birth is stamped later than the bridge’s last one, also when its clock stepped back or it restarted, so the Hub can order its births (767ba66c)
- hub: a satellite chain that could not be read declares nothing in the birth, never plain, and is declared once it reads again (de433b68)
- hub: the birth goes out again once a satellite modem has told its IMEI, so the Hub can tie the modem and its sealing declaration to this bridge (682b7477)
- delivery: the delivery statistics keep a pruned attempt in its own second, read one snapshot, prune one fixed set of intents, and say which intents an upgraded ledger may have lost (82517821)
- delivery: the delivery statistics keep counting what the retention prune removes, keep fractional window bounds, and find receipts by index (7782548d)
- directory: a key rotation keeps its own counter, a full snapshot moves addresses in any order and leaves a dropped contact only local data, and the Hub key is never fetched through a redirect (45edce54)
- sos: an owed SOS cancel is never dropped to make room, however many SOS follow (ceb7bbf6)
- sos: an SOS cancel frame is never lost to a failed enqueue, and a new SOS no longer drops the last one’s unconfirmed cancel (958b2256)
- intents: an event kept before the bound is never reported as an unknown outcome, even when its cleanup failed (44343766)
- intents: a completion lost after an expiry is still asked for, and a start asks for every operation without one (fb7d4d29)
- intents: a Hub event the kit could not keep stays asked for until its outcome is kept, across a restart too (64a3990a)
- intents: a Hub event or hand-off whose write fails is applied again and kept once, and a lost event is asked for again (ace79651)
- links: the Hub messages link reads online while its route is on, and unbound when it is off (96532aa2)
- intents: a text the Hub refuses reads not sent, not accepted, and its refusal counts once (8c960933)
- hub: a blank topic root saved in the Hub settings returns the Bridge to the platform tenant, whatever MESHSAT_HUB_TOPIC_PREFIX says (8b06e7ca)
- hub: a Hub command that ran without its claim no longer stores its reply under another request’s claim (88826a95)
- hub: a Hub send_text run again after a restart answers the delivery it queued first, a command that changes something is not run without the command log, and a refusal never replaces a finished command’s reply (9d703ced)
- hub: a Hub command an earlier process claimed and never finished runs after a restart, and a request id reused with other arguments is refused (91096cfb)
- hub: a Hub command the broker delivers twice runs once, and the MQTT gateway no longer drops other nodes’ messages after a direct send (790ec987)
- tetra: a send that failed before its SDS reached the radio is not sent, and no acknowledgement in hand makes it delivered (856e123c)
- tetra: a MeshSat Bridge’s acknowledgement that came before the radio reported the send failed counts as delivered, the radio’s report kept (c491c811)
- tetra: the radio’s error code is kept beside its not-sent report every time, and the mailbox check’s test waits for its finished event (cab021e3)
- delivery: a Bridge acknowledges a TETRA text only once it took it in, and a TETRA or cell send that may have reached the recipient shows as may have been sent (19a55a08)
- tetra: a Bridge that knows no MeshSat peer on the group says hello again every 5 minutes, so two kits that start in the same second still find each other (e8065f53)
- delivery: only refusals the radio’s firmware gives before anything goes on air mark a mesh send not sent, and one that arrives after the message closed corrects its status (febcbad4)
- tetra: a command ends on the reader the moment its final line arrives, so a send’s late radio error right after its OK is read as late and not swallowed (b1767b42)
- tetra: an SDS the radio takes and then reports not sent, as in a collision when both kits send at once, is a failed delivery that is retried, not a delivered one (023280f7)
- delivery: a mesh message our own radio refuses to send is not sent, so the next route takes over and the status no longer says it was accepted (972104ec)
- web: a widget’s arrival ring is the brand’s Sand, and Customize’s Remove sits on the card’s edge instead of over its status (22990dd7)
- web: a USB radio’s widget follows the Bridge’s device scan, so it goes the moment the radio is unplugged and comes back within seconds, with detection polled every 5 s (a2549237)
- tetra: an SDS-TL report’s message reference is read from the byte that holds it, and its delivery status is kept (a03d3589)
- relay: a custody offer is taken and acknowledged only when the mesh sends its text whole, and an offer repeated after a lost acknowledgement is acknowledged again, not queued twice (efadcdf3)
- delivery: a closed status card checks again once a minute and retries a failed read, and reads again whenever its event stream opens, so a lost update shows within a minute (1162c5a4)
- tetra: one SDS carries 126 characters, not the 144 the radio advertises, because the radio adds its own identity inside the limit, and a text it calls too long is refused for good (8caac648)
- tetra: the radio’s port opens without touching modem lines its driver does not have, and a first open that fails is retried in the background (76823da8)
- relay: a relay too long for its bearer goes as one message, not as numbered fragments nothing joins, and a custody payload is taken only where it will be sent (fa4bd47a)
- devices: a Motorola TETRA radio on USB is claimed by its id and no longer taken for an Iridium 9603 because it answers AT (52ff6fa0)
- aprs: a message the full receive queue refused is not remembered or acked, so the sender’s next copy is taken; a copy of a taken message is still acked (20443a71)
- aprs: a message the sender transmits again because our ack was late is acked again and taken once, not stored twice (87ee8909)
- delivery: a send the bridge took under a key is answered for what it was after delivery intents are turned off, and a partial send reports the address it could not queue beside the one it did (c361c12e)
- delivery: a retried send keeps its key with delivery intents off, a refusal after an unanswered send keeps the retry key, a slow status read never overwrites a newer one, and a 9704 cancel names its send by a token that is never reused (33d2776c)
- delivery: compose keeps a send’s retry key until the bridge’s answer is definitive, shows only the picked contact’s history, names each message’s recipient, follows a closed message while it settles, and no longer offers team sends (60ace12c)
- delivery: every 9704 MO frame is bound to its own message, a cancel names the exact send, a cancelled caller sends nothing, and only documented statuses release an MO as not sent (39420ae3)
- delivery: a route retired by its queue allowance is shown as not sent in time, not as offline (a6031fde)
- delivery: the SMS bundle’s end is kept to the whole second, and the dashboard says when it is unknown (4d43d759)
- delivery: a returned SMS share is always committed, and the prepaid bundle has a recorded end after which intent SMS are refused (6b0e5c4d)
- delivery: an intent SMS goes only once its bundle share is stored, every count change is one transaction, a failed read refuses instead of allowing, and a top-up keeps a running send’s share (09e94d64)
- delivery: the SMS bundle is checked and settled on the modem’s serial loop, a send without +CMGS stays unconfirmed, and the counter is set before anything can send (51a6946f)
- delivery: an SMS that may still go is unknown, only +CMGS is acceptance, tariffs are EUR and bounded, the minimum is charged, the modem is held to IRA and GSM 7-bit (67460ce8)
- delivery: an APRS ack is a station ack, matched against the kept send after a restart and only from the addressed station; a write that started is unknown (45a28438)
- delivery: an LXMF proof’s hash is stored before the packet is written, and the listener is up before the node takes any packet (1e9b6906)
- delivery: a raw send with an unsupported strategy is refused, Hub directory pushes with contact metadata verify (7fc5f6c3)
- delivery: an intent’s mesh send needs a radio that takes the packet id before sending, so a reused id cannot confirm the wrong message (6ec0d640)
- delivery: queued intents from before the fix stay off paid links, receipts stored before it are applied, a reused packet id confirms nothing (9b13c582)
- delivery: intent sends stay off paid links end to end, mesh and late receipts are no longer lost, each LXMF intent is its own message (4812b1d2)
- sms: an encrypted SMS too long for one text is refused instead of arriving cut and unreadable (caaed2cf)
- mqtt: a message sent while MQTT is disconnected waits for a retry instead of showing delivered (dfdae14a)
- contacts: a message to a contact goes to that contact on every route, not to the gateway’s default number (011c8172)
- sos: a restart no longer gives up the legs of an SOS that is still on (c16511c0)
- reticulum: a TCP peer that opens a frame and never closes it can no longer grow the reader’s buffer without bound (fc44fb18)
- rns: a neighbour across a satellite link that counts extra hops is reached directly, not dropped as transport traffic (bc9cfb91)
- lxmf: the bridge sends direct across the satellite and waits for the round trip (327242e5)
- iridium: Reticulum packets go to the satellite in order and are retried, not dropped after 30 s (d587e3e9)
- tak: the TAK export reaches the Hub, and the bridge shows what the Hub delivers back (10c1e707)
- a satellite message is kept until it is handed over once, and a failed send leaves nothing to send twice (da19d9b4)
- engine: a link set to encrypt never sends the text in the clear, and the Messaging and SMS settings can be written without wiping anything (ab277466)
- api: a radio settings write reaches the node over its own settings, the node’s log over Bluetooth on demand, a CA certificate keeps its facts (ada41e9a)
- api: a link switched off stops what goes out by it, and the interface list shows the switch at once (457fb72f)
- mesh: a NodeInfo request carries the radio’s own name instead of blanking it on the node asked (fdf5186e)
- interop: skip the AutoInterface namespace test where no veth pair can be built (d8a7db37)
- power: a full pack resting on mains is no longer reported as draining (e4b3014d)
- ttc: the booth screen no longer zooms or scrolls under a visitor’s fingers (06848a48)
- ttc: the booth screen lights the APRS lane again now the PicoAPRS units are back in their own kits (5ec09b1e)
- satellite: the MT poll keeps watching until it can give way, and a send whose session closed fails at once (d51c5c1c)
- satellite: the 9704 is switched on at start as Ground Control’s library does, and a real power cycle holds I_EN low (59550bd5)
- satellite: the 9704 is power-cycled, read and preempted the way Ground Control’s guide says (3baec744)
- satellite: the booth screen shows a satellite message as its words, not its ciphertext (f9c2b13b)
- mesh: a handheld’s reply that repeats a text the kit just relayed goes out again (6393d031)
- sms: an SMS typed on the dashboard goes through the delivery ledger, so the Hub can read it (cd4e58fe)
- satellite: the kits know every Iridium satellite again, so no pass goes missing (03953fe6)
- oob: a BEARER revert survives a bridge restart, and deleting a peer no longer cancels it (885a7259)
- aprs: a silent TNC no longer gets its gateway restarted during the cold start (ad94615a)
- relay: a client’s next tunnel no longer lands in its previous one, so every request through the Hub works (3cdf27d2)
- oob: a delayed BEARER off keeps its short reply, so APRS still shows the revert (f8fce6c3)
- oob: a BEARER off for the bearer the command came in on answers before it cuts (d5443425)
- oob: a mesh reset that succeeds is no longer reported as agent_error on a slow radio (80f70e58)
- hub: a kit that loses the Hub says it is alive the moment the fallback arms (bd8377ae)
- hub: the fallback frame to the Hub names the whole bridge, not its first 16 characters (38c6a97c)
- satellite: a message for the 9704 waits out a sky gap instead of dying after nine minutes (8862699c)
- hub: the satellite fallback to the Hub uses the modem the kit carries, not only a 9603 (81001405)
- satellite: a send that runs out of time is cancelled in the modem, so a retry no longer delivers the message twice (165cf96e)
- satellite: the serial watchdog no longer power-cycles the 9704 in the middle of a send (6da475e8)
- ttc: the booth screen names its own kit again, whatever callsign it transmits under (d0173a8b)
- satellite: a relayed kit to kit message is an app message, not a Reticulum packet (62976f83)
- satellite: relay kit to kit over Iridium as the bare text, and stop dropping version-prefixed frames at the receive gate (fb0a3fdc)
- transport: keep every serial probe and scanner off ports that belong to another device (8197a065)
- timesync: stop the 30 s time-sync beacon on LoRa when no bridge can answer it (12174457)
- spectrum: build the official osmocom rtl-sdr driver for the V4, re-set gain after retune (db4b78d4)
- spectrum: give rtl_tcp 12 s to exit on SIGTERM before killing it (bcaffaff)
- spectrum: stop rtl_tcp cleanly and never run two readers at once (32134a32)
- spectrum: read the RTL-SDR through one async rtl_tcp and never USB-reset it (ffefb980)
- mesh: never ask the radio for an ack on a broadcast or on a message to itself (9ad596ed)
- mesh: strip the firmware’s colour codes from console lines (5acd0b8e)
- oob: the mesh role accepts the T-Echo (239a:4405) (cebb820f)
- spectrum: thin transition captions by pixels, not percent (2057e8a7)
- spectrum: the noise floor is a low quantile, not the median (6b14d7b5)
- spectrum: the baseline’s plus-minus is the robust spread (2c17a0bc)
- spectrum: the baseline level is the median, not the mean (7a8c2b9b)
- spectrum: keep the reference line on the plot, and stop markers colliding (b315842e)
- spectrum: the seven findings from the visual audit (7cca8980)
- spectrum: watch the frequency the mesh actually transmits on (8d201acb)
- spectrum: five defects from the waterfall audit (da94687f)
- printer: a slip is proof a message crossed, not proof one arrived (c3960935)
- printer: one slip sequence across both kits, not one each (783332db)
- ttc: rotate the screensaver posters about every minute (b156df9c)
- aprs: count the ack against the last beacon, not a fixed window (32d6d8f4)
- aprs: skip the beacon when the peer just acked us (100ba8c6)
- oob: cut the TNC’s own hub port on a PicoAPRS kit (d3f0cadd)
- ci: bound the deploy probe, and stop the HeMB frame test failing on a coin toss (87230ee0)
- ci: the address probe must not kill the job when the first address is silent (0a605943)
- gateway: start a gateway on the manager’s context, not the HTTP request’s (817beb2d)
- ttc: the SMS lane’s sentence comes from the radio state, not from this browser (01dd7224)
- ttc: the auto-move watcher watches the lane too, so a failed first poll cannot strand it (4518562d)
- ttc: radio off reads red, and the panel moves the lane to SMS while the radio is off (2e1570a9)
- oob: BEARER on for a running bearer and off for a stopped one answer ok, as the spec promises (68530966)
- ttc: satellite lane and chip name the modem that is present; visitor line measure (3cb23c19)
- relay: fetch the bridge CA from the Hub instead of the MQTT root store (2a2abc77)
- cellular: the SMS bundle PUT applies every field under one lock before the thresholds run (777a9cc6)
- engine: a gateway restarting under a delivery in flight is a retry, not a bridge crash (015b4b24)
- aprs: hold the status beacon while this kit waits for an ack (5865a3fc)
- mesh: serial watchdog off by default and never reopens a radio that still answers (6ba731db)
- engine: drop inbound frames that fail the decrypt chain on an encrypted interface (85686c19)
- aprs: keep third-party frames out of the message pipeline, only messages to us and MeshSat relays are forwarded (e2059184)
- oob: let the host agent power-cycle a Meshtastic 2.8 radio on its HWCDC identity (40eba6fc)
- failover: copy the stored plaintext, not the mutated ciphertext, when a no-ack message moves bearers (dfe0f888)
- aprs: send an ack-requested frame once per attempt, without a blind repeat copy (abe0e5ff)
- mesh: tell the radio before closing its port, and pace writes like the official client (427d5b1a)
- aprs: an unacknowledged relayed text is sent again and then moves to SMS (f79e3a8a)
- cellular: a modem command can only act on the session it was queued to (617e77f9)
- mesh: keep DTR up when the radio’s port closes, and report the radio’s reboot count (fb06f35d)
- mesh: retry the handshake until the radio sends its node info (1853bfa4)
- mesh: count a silent handshake as a silent radio so the hub-port cut comes first (94129c46)
- ui: keep the compact battery chip its width when the pack drains on mains (dcde2e0d)
- aprs: listen before talking on every APRS transmission (a1964345)
- ups: halt before the X1202 cuts out and flag a pack draining on mains (d4aca545)
- mesh: cut a silent radio’s hub port at once and stop zeroing the radio’s own node entry (b8b38ff7)
- kiosk: rebind the touch controller when its probe misreads the config (ba4d52be)
- time: drop docker.socket from the clock guard ordering, it was deleting Docker’s start job (83aa3e1a)
- deploy: pass MESHSAT_API_RATE_LIMIT through compose so it can actually be set (d0eee480)
- aprs: the beacon and the message no longer keep the same cadence (8b4232c8)
- health: a probe that never returns can no longer freeze the heal ladder (66a1c8f6)
- hub: keep retrying a first MQTT connect that failed, and stop paying for the fallback afterwards (27c57171)
- kiosk: the booth screen survives a recycle, and no recycle fires at power-on (40f734c7)
- ci: read the pushed digest from buildx’s metadata file, not from imagetools (fc3e4d0b)
- delivery: a bearer that is down for a moment no longer kills the message queued to it (e4c47b39)
- deploy: a deploy is green only when the kit runs the image the pipeline built, and it survives a dropped SSH session (cbd7a285)
- time: the modem’s unset clock reads as 2070, not 1970, and the unit’s Documentation line was not a URL (6ab8ffd7)
- spectrum: LTE bands scan in one hop and calibration is sample-driven, so cellular jamming detection calibrates instead of burning a core forever (50b8a098)
- web: booth route tap times out and says “failed” instead of hanging; kiosk idle dim after 3 min (ff834be6)
- web: T-Deck Plus photo under a new name so the kiosk browser drops the cached SMA version (4c16b961)
- aprs: keep a KISS frame the PicoAPRS closes with a stray FESC, count it as repaired (b957c8d0)
- aprs: a bad KISS frame is dropped and logged, the TNC port stays open, and the beacon wait is jittered (c752a8b9)
- x1202: the battery reads 100 % on mains, the monitor learns the pack’s own full point from the fuel-gauge plateau (c19becca)
- ttc: the booth screen draws a relayed text from the inbound event, not from the encrypted frame (b938f9f6)
- spectrum: an RTL-SDR that appears after startup is attached without a restart, and its hard reset tries the hub port cut first (ad54af08)
- mesh: the two kit radios no longer loop NodeInfo requests across the split channels (0a7b8c22)
- sos: the dead man’s switch was never wired into the shipped binary (0678c449)
- zigbee: the interface scan no longer re-probes ports a transport already owns (59eda90b)
- kiosk: the bridge comes back after a power-on, and the kiosk follows it (fd94d758)
- ttc: the route rows fit the panel, and every glyph sits on its wire (05f7e139)
- kiosk: one autostart for both kits, and stop the installer flipping the panels (1d0b8465)
- ttc: shorter satellite lane text so it fits the right-hand kit’s lane (30275ab0)
- ttc: the booth flow rules are ingress rules on mesh_0, the relay convention the dispatcher evaluates (6f8c1b53)
- gateway: shutdown skips a gateway still being created instead of crashing on the nil sentinel (16a6e4cb)
- failover: a member served by a connected gateway counts as online; the booth group picked SMS over a healthy APRS (ae11680f)
- aprs: status beacons are liveness only, never an inbound message or a booth-screen trip (b23b9017)
- gateway: inbound receivers run under the manager’s context, not the restarting caller’s (d9f55eed)
- web: TTC panel audit round two, composer journeys, housekeeping frames, replay caption, spectrum skip (3ffa3b3e)
- web: TTC message box never squeezes the drawing on the panel, three lines at most (b89d60b8)
- web: operator dashboard’s four glance rows fit above the bottom nav on the 7 inch panel (0b528988)
- web: TTC mode designed for the panel’s real viewport, 853x480 CSS px at scale 1.5, and immune to the NVIS theme (20404ea2)
- web: TTC outbound dot takes the lane of the delivery that actually carried it, SMS lane lights (0f9c0aac)
- imt: Subscribe stops the previous loops and each loop closes its own done channel (f1d7b18a)
- imt: JSPR reader stop is idempotent, Close drops the connection; bridge died with close of closed channel (114015c3)
- cellular: SMS history stores the decoded text of encrypted inbound SMS (5535c3dd)
- database: apply SQLite pragmas with modernc syntax, kits ran a rollback journal (2b05accc)
- cellular: open the T-Call with DTR and RTS low and equal; the old DTR-only clear held the ESP32 in reset (b3dc9ce3)
- health: manual rungs outlive the HTTP request, USB reset hits the device not its hub, ZigBee ladder covers a missing gateway and a dongle off the bus (2beffdb7)
- health: GPS liveness on any NMEA sentence, RTL-SDR warm-up tolerance and real recovery (b607f5c3)
- aprs: receive watchdog survives a bridge restart, gateway list carries the receive fields (0430bed2)
- aprs: preflight sets the AIOC capture gain at every Direwolf start (default 94 %, MESHSAT_AIOC_CAPTURE) (f1548776)
- gateway: StopGatewayInstance leaves a starting instance alone instead of dereferencing the nil sentinel (6cb56526)
- oob: a level-3 reset of an interface restarts that interface itself 10 s after the power cycle (5e451b93)
- oob: host agent addresses hubs by exact location so the USB 3 half of a dual hub is switched too (5fc6356a)
- transport: mark every serial, USB and GPIO descriptor close-on-exec (f50c3569)
- cellular: refresh the registration state on every signal poll (f5a96510)
- oob: e2e driver never resends a mutating request after a lost response (2f357420)
- oob: target levels as JSON ints; deploy never removes the bridge for a missing image (338ec9aa)
- sdd: reword CGO prohibitions so they stop tripping the CGO gate (1a94c35d)
- sdd: recount PROJECT.md metrics and pin the SDD validator (7495a1b5)
- claims: remove dead interfaces and correct capability statements (60f1dbd3)
- bond: startup self-heal for stale auto bond labels (eecd8893)
- bond: preserve human-authored bond labels across member changes (14102a86)
- dashboard: 5 Active Comms audit fixes (d24d0873)
- demo: hard 28s deadline on iridium dispatch so demo run always completes (61701de3)
- dashboard: clean up mesh widget state + drop misplaced Channel Health (da72d5df)
- routing,transform,keystore: three demo-follow-up defects (ce3aec7a)
- dashboard: gate touch drag-reorder to grip handle only (d7b170cf)
- dashboard: count bridge publishes that Hub converts to CoT as TAK msgs_out (feb93075)
- dashboard: TAK/CoT widget shows live Hub-relayed counters (e63e646b)
- ble: meshsat-ble-addr-pin systemd unit was hanging on btmgmt without TTY (b4286e14)
- ble: accept LE-only peripherals in bluetooth connect handler (ca872c10)
- web: persist kiosk flag in localStorage so reloads after route nav stay kiosk (514d1afb)
- mesh: make Meshtastic config handshake timeout configurable, default 60s (f750bdf0)
- transport: 3-way probe cascade with DTR guard on all probes (e36a5aea)
- cellular: read live connection state from transport in Status() (93d52252)
- hemb: ax25 bearer recognised as free so HeMB bond allocates symbols to it (d3faf0f8)
- routing: TCPInterface.Send errors when no peers (419ddcb4)
- hemb: document mesh MTU=100 as the field-verified working value (8f8bb2e1)
- hemb: length-prefix bond payload to survive RLNC zero-pad (a71e86f5)
- iridium: open OnOff as tri-state input, pulse via Reconfigure (a5255d08)
- hemb: TUN bonder mustn’t overwrite the bond-decrypt bonder (437ea8d1)
- hemb: mesh bearer MTU 237→230 so LoRa SF7 doesn’t silently drop (3120af0b)
- iridium: omit unset NetAv/RI timestamps from API response (acdf6fb1)
- aprs: show regulatory notice before enabling encryption (fb57a80c)
- spectrum: classic SDR palette + aligned legend, dark noise floor (6b94ed13)
- shell: kiosk session ignores localStorage shell override (6703ca93)
- spectrum: per-band crop pad + 20 dB gain stops sidebars and saturation (f12f554e)
- spectrum: waterfall palette uses fixed dB offsets, not MAD scaling (f0a833ce)
- spectrum: band-level waterfall palette, 1 dB gridlines (fb7bb124)
- spectrum: bump scan context timeout 30s → 90s (7c779bcb)
- spectrum: scanner never demotes to legacy rtl_power (8d8ccd25)
- spectrum: seed waterfall from latest N rows, not last 5 min (5ef996c4)
- spectrum: persistence retries forever, no permanent self-disable (da114b98)
- spectrum: widen scan to crop Hann edges + swap trace Y-axis to row min/max (7e7952a5)
- spectrum: stop rendering per-bin FFT noise as rainbow snow (3f13e763)
- hemb: trim RLNC zero-padding to IP tot_len before TUN write (4e610df9)
- hemb: default non-zero LossRate per iface so bonder includes every bearer (5a7f9d4b)
- hemb: route all bearers through Reticulum registry, size by real MTU (3887a419)
- dashboard: iridium_0 short label SBD not Sat (de00e043)
- dashboard: HeMB tile: dynamic subtitle + count-aware sizing (8c85c61c)
- dashboard: ifaceOK consults Reticulum registry for tcp_/ble_/mqtt_rns_ (332e1a11)
- hemb: unblock multi-bearer send + auto-rebind on bond change (2bdf6d86)
- tcp: link-local-aware dialer for WiFi-Direct IPv6 peers (92a92a23)
- tcp-iface: default listen :4242 in standalone mode (21277ba4)
- wifi-p2p: bind role → go_intent deterministically (62ac81fe)
- wifi-p2p: pass WPS display/keypad role to p2p_connect (2918bec0)
- wifi-p2p: PIN-only pairing, PBC disabled (adf3d7f5)
- ui: auto-probe WiFi capabilities so P2P Find button enables (20fd4f54)
- wifi-p2p: retry p2p_peers for fresh-supplicant race (296669e3)
- wifi-p2p: ensureWpaSupplicant before wpa_cli on USB dongles (e48e1d41)
- wifi-p2p: exclude p2p-dev-* mgmt iface from active-group detection (18adf85e)
- ifacemgr: device_type ↔ channel_type alias unblocks auto-bind (60f4e164)
- devices: merge supervisor+bindings lists, filter Pi 5 BT UART (1790df33)
- ui: bind dropdown + scan dedup + mode selector (e11fcb74)
- devices: ambiguous VID:PID + WiFi scan auto-up + Devices→WiFi surface (baf458aa)
- ui: Settings tabs wrap, main nav shows scrollbar (6445d214)
- wifi-enum: classify USB via device/subsystem, not path scan (302cf7be)
- federation: return [] not null for empty peers list (8abbd33d)
- ui: match WiFi + BLE handler response shapes (5b7fb0b3)
- image: add standalone-mode pragma to Dockerfile apt block (adf22467)
- dashboard: operator mesh tile keys off radio state, not peer activity (ab8eece5)
- kiosk: remove duplicate swayidle in session launcher (5a8b41ab)
- dashboard: touch-event drag-reorder for widgets (9fc9117f)
- spa: inputmode + enterkeyhint hints on every input (a67a5800)
- spa: 40/48 dp tap-target floor for buttons (659d4a16)
- spa: checkbox row-as-target in InterfacesView (25bbe326)
- spa: narrow-screen textarea defaults (06d9f70e)
- install-kiosk: escape & in sed replacement for BRIDGE_URL (74467e20)
- x1202: in-place write preserves inode for bind mount (444d1864)
- dashboard: compact mission tile + inline orange TEST SOS (d536515b)
- dashboard: tighten operator tile padding for 480px viewport (bb9294e5)
- dashboard: operator row 1 (state+SOS) + row 3 (GPS/Batt/Queued) (027d4e77)
- dashboard: include APRS in operator channel count (40d2e169)
- dashboard: operator-specific glanceable view (6179fa87)
- kiosk: 7" polish pass: bump chrome labels + nav tap targets (70d4ee08)
- kiosk: bottom tab bar overlap + quote autostart URL (fa580dbc)
- kiosk: decouple kiosk chrome from shell role (a76784c9)
- kiosk: generate blank xcursor binary with python, drop xcursorgen dep (920e6a21)
- kiosk: install blank xcursor theme: compositor draws 0 visible pixels (146d9297)
- kiosk: restore @media(pointer:coarse) cursor rule + force touch-events on (6b6a8c87)
- kiosk: hide Wayland compositor cursor via labwc cursorSize=1 (ffb6784c)
- kiosk: wait for bridge /health before chromium + tighter scrollbar hide (860841c1)
- web: hide cursor + scrollbars via html.shell-kiosk class (2ae1503f)
- web: hide scrollbars on touch-primary devices (alongside the cursor) (829ad121)
- web: hide mouse cursor on touch-primary devices (d4e8018b)
- kiosk: labwc + wlr-randr + udev touch matrix: working on Pi Touch Display 2 (5ddecc69)
- kiosk,web: Raspberry Pi Touch Display 2 (720×1280) support (68ebf925)
- web: engineer mode uses new views + Pi 7" touchscreen compat (3c7297c7)
- aprs: track every AX.25 source, not only APRS-formatted payloads (f3d070b3)
- spectrum: auto-demote rtl_power_fftw → rtl_power on sustained failure (921c0d33)
- web: service worker: network-first for SPA shell + SSE passthrough (99130726)
- web: Operator ‘…’ overflow menu: teleport out of nav clip rect (75af45cc)
- map: load leaflet.markercluster after leaflet resolves (424664ef)
- deps: pin go.mod to 1.24 + downgrade x/crypto x/sys x/sync x/text (de7cb75a)
- web: modal max-width full on mobile, constrained on sm+ (24305961)
- web: dedupe NVIS toggle: keep only the StatusStrip copy (fd269588)
- app: pass empty precedence to QueueDirectSend in Hub cmd handler (098f5fab)
- transport: add Precedence field to SendRequest (6b20c03a)
- api: plumb precedence through /api/messages/send (b5bdf5d4)
- signing: wrap Ed25519 private key at rest under master key (2501c28a)
- ax25: auto-reconnect to KISS TNC after read error (fac0d908)
- aprs: Option-B provider, OTA TX/RX counters, richer connected (7d402723)
- aprs: detach supervisor ctx from HTTP request + SIGINT on stop (c28a5e3b)
- aprs: use PTT CM108 + ARATE/TXDELAY/TXTAIL to match field kits (7d3543e7)
- aprs: KISS loopback-only + surface supervisor state (35015361)
- dispatcher: add WaitGroup so tests can drain workers before db.Close (d7f238ce)
- Dockerfile: install libtclap-dev:arm64 (not native) for cross-compile (0039b6e9)
- hemb: de-flake TestGF256Consistency: retry on rank deficiency (1740817f)
- spectrum: skip NaN/Inf in stats + floor std to 0.5 dB (8328378d)
- Dockerfile: install librtlsdr to /usr/local so pkg-config+RPATH match runtime (3b074439)
- Dockerfile: pass explicit -I/-L for rpfftw cross-compile (b3a4b304)
- Dockerfile: point rpfftw pkg-config at /out/usr/local/lib/pkgconfig (423c0b61)
- spectrum: switch to rtl_power_fftw: async multi-URB read works on V4 where rtl_power’s single-URB sync read hangs (34ab3002)
- Dockerfile: correct patch sanity check grep pattern (5b6c2bde)
- spectrum: correct rtl_power patch: unified-diff blank line needed leading space (ff533953)
- spectrum: patch rtl_power to call rtlsdr_reset_buffer: fixes V4 hang (1f5bf03d)
- spectrum: bump scan timeout 12s->30s for Blog V4 driver cold start (51251ea9)
- Dockerfile: point pkg-config at arm64 multiarch dir for cross libusb (2e357f2d)
- Dockerfile: build rtl-sdr-blog in Debian c-builder (native cross) + Debian runtime (e1385c0b)
- Dockerfile: serial rtl-sdr-blog build: QEMU GCC segfaults under parallel make (6cb1ca28)
- spectrum: build rtl-sdr-blog fork: stock librtlsdr hangs on RTL-SDR Blog V4 (f5ddd77c)
- spectrum: bump rtl_power scan timeout 5s->12s (GPS+LTE were SIGKILLed) (c865122d)
- zigbee: gwmgr restart retry ladder + silence sysfs-RO unbind noise (c681cccd)
- spectrum: seed store from /api/spectrum/status so UI shows bands during calibration (c7bf6989)
- zigbee: unbind/rebind cp210x driver: deeper recovery than USB reset (d86949e5)
- zigbee: use unicast self-permit-join: broadcast rejected with 0xC2 (bf860b82)
- zigbee: supervisor → manager rebind race + re-enable watchdog (c845b2bf)
- zigbee: disable stuck-read watchdog: recovery race breaks gateway (f0100c0e)
- zigbee: watchdog false-positive: track readLoop iterations not bytes (a8de0e89)
- zigbee: humidity scale: Tuya /10 quirk fallback (c184faee)
- zigbee: stuck-read watchdog: auto-USBDEVFS_RESET when cp210x wedges (3d5a3c55)
- zigbee: e2e spec polish + history endpoint normalises empty slice (97f86c6b)
- zigbee: USBDEVFS_RESET to escape stuck cp210x state on re-init (c89be521)
- zigbee: close+reopen serial port on re-init to escape stuck read (f31043ba)
- hemb: de-flake TestEncodeDecodeRoundtrip: retry on rank deficiency (ed2ab6f0)
- zigbee: poll UTIL_GET_DEVICE_INFO during init (AREQ-less firmware) (9b5b5d87)
- zigbee: release z.mu around initCoordinator to unbreak startup (fe1dc236)
- zigbee: wait for DEV_ZB_COORD + cache port probes to stop dongle resets (ec973ca6)
- zigbee: show permit-join errors in UI instead of silent swallow (d81888bb)
- zigbee: skip unsolicited AREQs when waiting for permit-join SRSP (52abcba3)
- zigbee: serialMu prevents readLoop from stealing ZNP responses (ac778fb0)
- aprs: filter Reticulum frames from APRS parser + add APRS badge (c662a18d)
- aprs: count RX/TX at KISS connection level, not per-consumer (142cc79a)
- cellular: IMEI URC leak + SMS counters in dashboard (fce5ffd7)
- aprs: wire RecordTX() into sendMessage for TX counter (12cc1a00)
- web: remove leftover constellation refs breaking Passes page (bd169ede)
- cellular: retry PIN verify for 30s instead of fixed 5s wait (fefe3c23)
- cellular: permanently disable SIM PIN after first unlock (2426619b)
- imt: use GPIO chardev ioctl for I_EN reset (no gpioset binary) (84b74000)
- imt: cycle I_EN GPIO to reset JSPR state on connect (13feb941)
- imt: flush JSPR state via direct serial before starting helper (d0b96968)
- imt: flush modem JSPR state before handshake on reconnect (5e811c0b)
- cellular,zigbee: increase AT timeout to 60s, add ZNP probe retries (42c67ec9)
- zigbee: increase ZNP probe settle delay to 1.5s for DTR-triggered boot (4d3f11b8)
- supervisor: fix gateway startup ordering and ZNP probe DTR reset (e31751ca)
- supervisor: fix startup race and skip JSPR on ACM devices (d2df9917)
- supervisor: fix device detection for all field kit transports (808b5c53)
- supervisor: add Seeed XIAO ESP32-S3 VID:PID to Meshtastic auto-detect (d699f9c0)
- cellular: wait 30s for T-Call ESP32 cold boot before AT check (1edc15d3)
- web: repair duplicate class attrs in PassesView after Astrocast removal (b80bdf63)
- api: increase API rate limit default from 300 to 600 rpm (c7219422)
- mqtt: add ResumeSubs and OrderMatters for QoS 1+ in-flight persistence (7cb8b45f)
- hemb: skip TUN tests in CI environment (c243ae1a)
- hemb: skip TUN tests when device unavailable in CI (d5529d31)
- mqtt: persist sessions and retry subscriptions on broker reconnect (a91fd722)
- tak: import api client in DashboardView for Via Hub detection (b41d492a)
- tak: restore missing Vue imports in TakView (useMeshsatStore, ref, computed) (41c0993e)
- tak: add GeoChat + 9-Line tabs, fix Playwright test labels (a2c8c99a)
- tak: remove extra </div> breaking Vue SFC template (944ce1dd)
- tak: clean up duplicate GeoChat/9-Line template injections (f4d379d0)
- test: E2E mock TAK server skips version negotiation messages (17e8b27e)
- resolve 3 pre-existing test failures (8e7b55d7)
- cellular: A7670E SMS ME storage + polling fallback (5943478e)
- cellular: reduce AT+CSQ timeout to 3s: unblock I/O loop for URCs (156eb520)
- cellular: extract +CMTI URCs from AT response buffer (5bc3d0aa)
- hemb: re-inject decoded HeMB payload into DispatchAccess (4f8870c5)
- db: KeyBundleRow.ExpiresAt nullable: prevents key lookup failure (81654f8d)
- processor: apply ingress transforms before messages DB persist (a7c8b57e)
- imt: improve L4 Reticulum classifier: reject ASCII plaintext (bf4f1944)
- imt: L4 payload classification: split Reticulum vs app MT queues (03b53d74)
- imt: persist MT messages to DB and forward to inbound channel (d91e5a99)
- imt: MT receive pipeline verified working: keep INFO logging (57d9d2dc)
- sms: apply egress transforms on SMS send API (b6b9c73b)
- keystore: use MaxKeyVersion to avoid UNIQUE constraint on StoreKey (512014b8)
- transport: wake mesh processor immediately on port assignment (3b6a4076)
- transport: probe serialization + auto-PIN unlock for Huawei E220 (326b5d92)
- hemb: widen stream ID to 8-bit + clean up decoded generations (f197afbb)
- hemb: use global stream sequence to prevent generation ID collisions (313b950d)
- hemb: fix SendViaBondGroup bearer priority to match DispatchAccess (e975fa5a)
- hemb: detect HeMB frames inside Reticulum data packets (9838a1db)
- hemb: route mesh bearer via Reticulum transport node, not raw PRIVATE_APP (c6a9b193)
- hemb: commit linter additions: GaussStep, arrival tracking, matrix inspector (bfad0b8d)
- hemb: global stats aggregator, bearer contributions, N=1 regression (226f906b)
- ui: adjust viewport offset to 90px for nav + status bar height (65026977)
- ui: constrain topology view to viewport with calc(100vh - 48px) (0df6b5bb)
- ui: use flex ratio for graph/table split to prevent viewport overflow (a05891a5)
- ui: fix layout overflow + inline flow table with bridge events (0ea46203)
- ui: fix undefined template refs in ObservabilityGraph bridge node (2e310889)
- ui: add null guards to all computed array accesses in ObservabilityGraph (2a48fe6c)
- ui: null safety in ObservabilityGraph computed properties (c3056f29)
- hemb: fix ref unwrapping in bearer graph and flow table (83afd62a)
- hemb: fix ref unwrapping in bearer graph computed property (0e317460)
- hemb: dynamic bearer resolution for any interface type (9a12db1b)
- hemb: add mesh_0 fallback in bond group bearer resolution (2000e167)
- docker: add libc6-dev-arm64-cross for aarch64 cross-compilation headers (7b8a107a)
- docker: cross-compile C helper to avoid QEMU GCC segfault on ARM64 (4c82713b)
- channel: update test for IPoUGRS channel descriptor (10 channels) (888fcc64)
- build: commit local fixes: MQTTReticulumPrefix renamed, announce relay signature (eeff49b3)
- rlnc: trim padded segments to actual size during RLNC reassembly (25edf2d9)
- critical: stop time sync flooding satellite SBD: exclude paid interfaces (b7d6b628)
- routing: dispatch time sync packets before Reticulum header parser (f2fb0256)
- hub: remove CA PEM from bridge UI, fix clearing logic (ea437e1b)
- hub: include Meshtastic in health + birth interface list (455329d6)
- mesh: synthesize user_id from node number when NodeInfo is unavailable (12bc55ea)
- mesh: merge config-download nodes instead of full-replace to preserve OTA-learned identity (db000fcb)
- routing: DB-persisted listen port overrides env var on startup (bbfefd3e)
- ui: bridge UI polish: error parsing, responsive badges, settings forms (c21cbbd5)
- ui: suppress raw JSON error on Interfaces health scores (f441833f)
- transport: probe ACM ports before claiming as Meshtastic (3305170f)
- dashboard: show pending DLQ items and label SBD/IMT separately (3d8e1d58)
- iridium: track last mo_status in DLQ to prevent false-positive sent marking (1a550fd0)
- hub: wire command handler and burst queue in main.go (587a89de)
- gateway: align supervisor instance IDs with gateway type naming (753a5722)
- gateway: prevent duplicate instances when fewer transports than DB configs (ac15107f)
- ci: make HAL recreation non-fatal in deploy script (30b47d33)
- ci: scope migration lint to migrations.go diff section (83054796)
- imt: fix consecutive MO: remove aggressive buffer reset, add early timeout (0b52c66d)
- imt: rewrite jspr_helper.py to single-thread event loop with bulk reads (8e14cdbf)
- imt: use USBDEVFS_RESET ioctl for USB reset inside Docker (a781097d)
- imt: add USB device reset when JSPR handshake fails (7f800b80)
- imt: fix MT receive: persistent rx buffer + mt_received event handler (6ad680bf)
- gateway: give iridium_imt its own interface ID for delivery routing (f0bfd963)
- imt: fix bridge serial connection to RockBLOCK 9704 (2007135a)
- imt: only block stdin_thread writes during active MO, not all sends (8a3b9ee6)
- imt: block serial writes during MO flow in jspr_helper.py (598cd2ab)
- gateway: map iridium_imt gateway to iridium interfaces in syncIfaceMap (bab8dc83)
- api: resolve gateway type to correct interface ID from DB (a90d5a2d)
- api: route /api/messages/send through delivery ledger, not outCh (8fe2c722)
- imt: increase helper MO timeout from 120s to 240s (c73cb504)
- imt: touch lastRead before MO send to prevent watchdog kill (f6594bf9)
- ui: show IMT messages in queue widget, fix satellite label (233b3ccb)
- ui: use live modem type for Iridium widget title, not stale DB label (3aa47a66)
- imt: production cleanup: API/UI wiring, MT flow fix, debug removal (3293c8b2)
- imt: proper threading.Lock for serial read coordination (dfc26821)
- imt: fix MO helper serial thread race + code 0 rejection (d2980b11)
- imt: move MO segment exchange into Python helper for inline response (405c0f85)
- imt: chmod 755 jspr_helper.py in Dockerfile (fe917ea3)
- imt: add execute permission to jspr_helper.py (c0d49e3a)
- imt: add jspr_helper.py to repo for Docker build (22a96b52)
- imt: restore helper subprocess, fix watchdog + write timeout + Python helper (70d4eed4)
- imt: replace jspr-helper subprocess with direct Go serial I/O (85a22ea2)
- imt: O_NONBLOCK + select() + read() with TCSETS2: C library pattern (7526d89e)
- imt: probeJSPR uses raw fd + TCSETS2 for correct 230400 baud (4ba6b263)
- imt: use VMIN=1 VTIME=0 like minicom: block in read() permanently (34b4a401)
- imt: stop calling TCSETS2 on every read: set termios once like minicom (09ac5d4c)
- imt: use blocking read() with VTIME: FIONREAD polling breaks URB chain (5c2e33ea)
- imt: use TCGETS2/TCSETS2 for 230400 baud: TCSETS silently fails on ARM64 (67296a7b)
- imt: FTDI workarounds: latency 1ms, autosuspend off, serial watchdog (7d6dbfa7)
- imt: use FIONREAD polling for reads: select/poll/epoll all fail on ftdi_sio (00d1e254)
- imt: match C library read timeout (500ms) and fix readOneLine early exit (c30ea762)
- imt: match official RockBLOCK 9704 C library serial exactly (842ebe28)
- imt: switch from poll() to ioctl(FIONREAD) for serial reads (f630c9b0)
- imt: switch rawSerialPort from epoll to poll() syscall for serial reads (98f66a87)
- imt: replace go.bug.st/serial with rawSerialPort for JSPR to fix reader hang (18ed1db1)
- imt: restore active GET constellationState signal polling (77b22909)
- imt: re-set serial read timeout after each write in reader goroutine (807cf9c7)
- imt: single-goroutine serial I/O: write via channel to reader (bf15f790)
- imt: serialize serial port R/W via writeMu to prevent reader hang (4a512d1b)
- imt: persist partial line buffer across readOneLine calls (036f00ac)
- imt: use correct JSPR target ‘messageProvisioning’ (not ‘checkProvisioning’) (a0d52020)
- api: route /api/messages/send to satellite gateway when gateway field specified (8556b63d)
- hub: wire HubReporter into main.go startup path (f062e1f7)
- imt: event-driven signal polling per official RockBLOCK 9704 C library (34bf465f)
- cell: increase AT+CPIN timeout to 30s for ATdebug firmware (8138c022)
- transport: JSPR probe retries, signal recorder transport selection, IMT signal preservation (c51c5bb2)
- main: signal recorder wired to IMT transport in main.go, not just app.go (61691233)
- transport: 2s timeout for constellationState, record 0 bars on timeout (d8dc8110)
- engine: signal recorder polls GetSignalFast instead of Subscribe (599cc158)
- engine: signal recorder uses active satellite transport, not hardcoded SBD (94aa50bf)
- dashboard: Iridium widget finds either SBD or IMT gateway (6a4ef593)
- api: /api/iridium/* endpoints auto-select active satellite transport (8ab6b1da)
- transport: match official C library JSPR JSON format with spaces (82bebc86)
- transport: JSPR handshake retry + accept error responses with generic targets (956a23d7)
- gateway: auto-create config on device_connected, not just at startup (ecbe663f)
- ci: deploy job fails when device is unreachable instead of faking success (d5bd45c9)
- transport: accept any JSPR response as proof of 9704 device (a873923a)
- api: prefer cached signal in /api/cellular/signal too (2ebb7260)
- transport: use ‘supervisor’ sentinel to fully disable transport auto-detect (d7009d03)
- transport: disable transport auto-detect when supervisor is active (519ee533)
- gateway: reconcile DB configs with actual hardware at startup (3167562e)
- transport: always register both satellite transports for dynamic hot-swap (72403a52)
- gateway: wire device event watcher in main.go and fix swap event gap (729804e8)
- transport: fix critical device hot-swap detection in supervisor (48d6ad13)
- gateway: prevent false-positive MO buffer check on first DLQ attempt (d6bc9180)
- transport: include ttyAMA* in device supervisor scan patterns (c94b0400)
- transport: check cellular VID:PID before ambiguous handler in supervisor (7700c5f8)
- transport: don’t hold mu during JSPR connect to prevent Subscribe deadlock (68c4349a)
- engine: skip initial scanDevices() to prevent startup hang (7d35422d)
- deploy: stop meshsat before HAL recreation to prevent stale serial fds (5b4eeb26)
- transport: prefer unambiguous VID:PID in Meshtastic auto-detect (8071d749)
- deploy: use sudo for compose file sed injection (17bece31)
- deploy: force-stop HAL container before recreate to prevent removal error (fd6c855d)
- transport: make GetStatus and GetSignalFast non-blocking on IMT (2096f0db)
- deploy: add mule per-device env for RockBLOCK 9704 IMT port (26a853ec)
- deploy: inject env vars directly into compose environment section (a9b07366)
- deploy: always regenerate meshsat.env per device, not just on first run (cb43a81b)
- deploy: pass DEPLOY_TARGET to ci-deploy.sh for device identification (f9fa1a98)
- deploy: auto-create per-device meshsat.env and inject into compose (2c766626)
- transport: retry IMT probe at startup with 2s delay (82f5f8ee)
- transport: probe for 9704 at startup, fall back to 9603 SBD (e17ecc38)
- proto: add from field and remove empty payload in RequestNodeInfo (d89d5a95)
- ui: show node/contact names instead of raw IDs in Comms view (bb8fbbe9)
- proto: correct ChannelSettings field numbers to match proto spec (6ed20d14)
- proto: use correct AdminMessage field 33 for SetChannel (d64ae923)
- cell: strip ATdebug ANSI output from AT responses (23505c09)
- cell: correct T-Call VID:PID and add multi-device deploy (010005d0)
- astrocast: rewrite Astronode S codec to match official ASCII hex protocol (5efd47d7)
- routing: correct HDLC escape byte to 0x7D per RNS spec (4f60a6ab)
- mqtt: fix subscribe error handling and add retry on reconnect (16b865aa)
- db: restore append-only migrations (v30-v35) removed by revert (306302ba)
- geofence, health score, and MSVQ-SC codebook fixes (704cb03e)
- api: add missing rockblock webhook handler and device tests (e2c6b4ea)
- add PDU mode fallback decoder for SMS reception (ca10d9e5)
- apply ingress transforms before dispatching forwarded messages (cfe92898)
- wire HealthScorer, DeadManSwitch, BurstQueue, GeofenceMonitor into app startup (17122472)
- ci: install nodejs in build stage for web frontend compilation (435e77f7)
- ci: eliminate QEMU arm64 Go build from Docker: use pre-built binaries (7b738bd5)
- delivery: remove legacy workers, fix TTL reaper for held deliveries (eca8e8b6)
- web: double-height queue widget, 6h cell signal history, contact name priority (7911195d)
- iridium: sane retry limits and startup cleanup for runaway deliveries (0dba053a)
- iridium: custom SBDIX response reader to skip binary preamble (7d1478b0)
- iridium: prevent duplicate SBD sends from serial bus contention (417a3a31)
- web: SMS conversation view, dashboard queue fix, dedup (6377c86a)
- cellular: encrypt only message text for SMS, not full JSON payload (a1c4c586)
- cellular: select correct USB interface for Huawei AT commands (218a2b41)
- transport: reset t.running on ioLoop exit to allow serial reconnect (01d4cc26)
- cellular: add SMS raw function debug logging (750a3191)
- cellular: add GSM 7-bit SMS text sanitizer (cb64a431)
- transport: set AT+CMGF=1 before each SMS, improve SBDWB drain (eacca4b4)
- dispatch: fix 4 bugs in delivery pipeline (51207336)
- cellular: prevent goroutine leak when transport not ready (ecc6b0fb)
- cellular: improve SMS CMGS response handling for Huawei E220 on 2G (748212fb)
- cellular: force serial reconnect on command timeout (7e2aa759)
- cellular: robust SMS send with AT probe and post-send settle (8e6a7e62)
- iridium: drain serial buffer between SBDWB and SBDIX (9f16b731)
- cellular: fix SMS sending: plaintext, sync delivery, 2G timeout (4dbe0959)
- dashboard: show all channel deliveries in message queue widget (a189fd64)
- meshsat: expose transform fields in interface status API (5ec21673)
- meshsat: properly drain Swarm stack before compose deploy (769f4c7f)
- meshsat: detect ISU autonomous transmit via SBDSX MO buffer pre-check (ad9113f5)
- meshsat: add timeout to cellular AT command/SMS execution, prevent ioLoop hang (3cc223e5)
- meshsat: add 5s timeout to cellular/iridium signal API endpoints (e3d79099)
- meshsat: cellular widget bugs, remove SMS section, fix map rendering (60d201ef)
- web: remove undefined rules export, delete orphaned components, fix node.id in messages (2d980f9a)
- web: remove dead /api/rules, fix map node IDs, migrate Bridge to access-rules (07a1dfe3)
- transport: iridium auto-detect prefers VID:PID over AT probe, skips cellular (cf819fdf)
- ci: deploy always uses standalone docker-compose, never Swarm (488c0381)
- meshsat: enrich cellular status DB fallback with cell_info and signal data (9c66f41c)
- meshsat: cellular API fallback to DB when transport unavailable (535892ef)
- meshsat: add immediate first signal poll and remove debug logging (f59eea3c)
- meshsat: use AT+COPS? for Huawei E220 cell info (MCC/MNC/AcT) (2b09166e)
- meshsat: enrich CREG cell info with cached network type (c6887b5c)
- meshsat: add AT+CREG? fallback when AT+QENG unsupported (5f040586)
- meshsat: persist SMS, CBS, cell_info events without CellularGateway (eecb7b48)
- meshsat: separate stateMu from serial mu for non-blocking GetStatus (bdf91300)
- meshsat: skip AT+COPS? when SIM locked + harden readATResponse (32811210)
- meshsat: prevent cellular API deadlock with TryLock + diagnostic logging (e952e6aa)
- meshsat: use wall clock for iridium geolocation observation timestamp (17165e00)
- meshsat: expose GPS satellite count in location widget (4cf0f35e)
- meshsat: time sync all mesh nodes + remove Iridium geolocation (88fff0fa)
- ci: false positive in migration append-only check (b584bddd)
- meshsat: signal history clock skew, DLQ max_retries, SBDIX parser (14ce1669)
- use NAME=ASTROCAST Celestrak query (GROUP=astrocast not found) (2ae7ee92)
- ui: About page: subtitle and all 6 transport channels (8607bf0e)
- ui: update Help and About pages with accurate content (4f0dcccf)
- 17 bugs from codebase review: backend and frontend (432c3ef0)
- complete HardwareModel enum (126 models) + last message timestamp per node (99965443)
- remove_by_nodenum was field 96 (exit_simulator), correct is field 38 (bba5e7d7)
- protobuf field number mismatches: NodeInfo, Telemetry, User, Position (d5d9f712)
- map color differentiation and Iridium accuracy circle (b4c20b66)
- change AUTO location priority to GPS > Custom > Iridium (d9febf30)
- clamp AT-MSGEO altitude to prevent broken pass predictions (c7b8291d)
- navbar logo visibility: optimized icon for small display (d135859c)
- resolve high & medium audit issues across dashboard (2d5e36c6)
- smart DLQ backoff based on ISU mo_status codes (287906f2)
- DLQ retry mechanism stops retrying after signal-triggered drain fails (9d86cf36)
- update GSS sync timestamp on attempt, not just success (f8fd361c)
- restore SBDSX gate to stop empty-MO SBDIX credit burn (6141577c)
- always clear MO buffer after SBDIX attempt, not just on success (e5c7089d)
- always run SBDIX in MailboxCheck to discover queued MT messages (3d8c2177)
- clear MO/MT buffers on connect to prevent stale resend loops (c9f0e160)
- clear MO buffer after successful SBDIX to prevent stale resend loop (6e1b2c03)
- trigger SBDIX on outbound MO buffer during mailbox poll (5aada947)
- add mesh reconnect loop, dynamic port exclusion, proper Close() wait (d4851a44)
- SSE subscribers return on disconnect event to trigger reconnect (e35bcd37)
- revert stty context timeout (causes signal:killed during port contention) (9860e781)
- restore SBDSX disconnect on timeout (safe now without channel close) (f88d063a)
- standalone direct transport 24-bug parity fix with HAL (d5ff693e)
- prevent gateway→mesh→gateway feedback loop on inbound SBD messages (c305353d)
- force serial reconnect on SBDIX/SBDSX timeout to prevent stuck connection (eb458c65)
- close SBDSX parse failure fallback that bypassed empty-MO guard (8c6e7c02)
- remove stale SBDIX check that sent empty SBD messages every 15min (1f7b0950)
v0.1.0 (2026-03-04)
Features
- mode-aware CI deploy (direct vs Swarm) (8c85eb69)
- direct serial transport for standalone mode (no HAL required) (a52691e8)
- pass-aware smart scheduler + multi-source location management (bfbfb7f7)
- encoding fix, logo, map messages, node mailboxes, signal overlay (29b84034)
- Iridium operational dashboard + bridge pipeline builder (cfd2fa1b)
- tactical operations dashboard with 7-panel grid (dc98c1df)
- node management, message stats breakdown, logo (7adecc29)
- forwarding rules engine, presets, SOS, delivery tracking, standalone mode (1a4fc5c8)
- Iridium priority queue + offline compose (Priority 3d) (08f96fa6)
- opportunistic DLQ drain on Iridium signal SSE events (81bbb916)
- Iridium signal display with 10s fast poll + refresh in MeshSat SPA (03114387)
- MeshSat SPA UX overhaul: dashboard, channels, config forms (9910a8bd)
- add default_destination to Iridium gateway config (118337ec)
- Iridium dead-letter queue for failed SBD sends (98b00047)
- Phase 4: MQTT gateway, Iridium satellite bridge, gateway management API + UI (fdfaf6f8)
- Phase 3: standalone web UI with embedded SPA (b15d7395)
- Phase 2: admin commands, radio config, waypoints, signal quality (52dbdcaa)
- MeshSat coreapp Phase 1: scaffold, persistence, event ingestion (e55b33cd)
Fixes
- parseSBDIX tolerates 5-field responses (mtQueued optional) (675688a4)
- ringAlertListener retry + prevent stale SBDIX on fresh connect (e67288ab)
- match HAL’s serial mutex pattern exactly: eliminate SBDIX binary garbage (69fe7785)
- Iridium gateway shows disconnected despite working transport (6a61979e)
- SBDIX serial race + SBDSX gating in direct transport (b6f13f90)
- pollWorker initial timer race: start with 5s instead of idle interval (a9448a31)
- reduce serial contention + deduplicate ring alert handlers (73316864)
- handle plain-text MT messages from external senders (1db2540b)
- detect piggybacked MT from outbound sends + add mailbox result logging (495d0e0c)
- inbound SBD messages silently dropped when forwarding rules exist (6e0f2dd2)
- opportunistic DLQ drain bypasses backoff, ring alert retries on failure (ea87aec4)
- chart pass colors indigo, Last TX/RX from queue, bulk stale removal (0bc6b76d)
- portnum filter on all rule types, historical pass prediction (5ceb37e7)
- check MOSuccess after SBD send, redesign signal-vs-passes chart (252cefe1)
- plaintext SBD for text messages, reduce poll waste (06ffd978)
- 6 UX/bug fixes: signal, queue direction, inbound SBD, config, message stats, comms (4207ebd2)
- queue UI clarity: sent items show as ‘delivered’ with dimmed style (3ceec670)
- queue not displaying: API returns {queue:[]} not raw array (2a16467c)
- inbound node selector, queue shows sent messages (7f68f55c)
- bridge rules single authority, inbound evaluation, clear UI (790bd0ce)
- overhaul Messages view into tactical comms panel (60e7f582)
- message flow Y-fork layout for MQTT and Iridium gateways (bf6b00f1)
- Iridium SSE backoff: reset on successful connection, lower cap to 5s (8c16da41)
- SSE backoff: reset on successful connection, lower cap to 5s (803f28a7)
- processor forwards to live gateway instances via GatewayProvider (98e066a8)
- read HAL_CORE_KEY directly instead of HAL_API_KEY (41a4cd41)
- ci-deploy.sh sources secrets.env for compose variable substitution (c9ab2b1c)
- CI dual-IP failover for deploy target resolution (035f0f8e)
- CI deploy: use service update
--forcefor existing services (9b96160c) - add placeholder index.html for go:embed in CI builds (4d55db8b)