Canonical design record for architecture, interfaces, operational model, and runtime evolution of the multi-radio (FT-710 / IC-7300 / IC-7300MK2) web control system.
IBM TeamSD aligned, 15 chapters, implementation-grounded content.
| Attribute | Value |
|---|---|
| Document ID | SDD-MRRC-MODERN-2026-001 |
| Version | V3.03 |
| Baseline Date | 2026-10-09 |
| Runtime | Python 3.12+, FastAPI, Uvicorn, PyAudio, NumPy |
| Frontend | HTML5, CSS3, vanilla JavaScript, Web Audio API |
| Core Interfaces | 4+1 WebSockets (optional ATR1000) + Serial CAT / CI-V + FT4222 SPI / CI-V 0x27 + USB Audio |
logs/server-stdout.log is systemd's
StandardOutput=append: target, and neither systemd nor
the server rotates an append: target — which made it
the one file in an image with no ceiling. Measured: a defect that
logged one warning per 20 ms audio frame wrote 17 MB in
five hours on a 6.5 GB root. The service layer now ships
/etc/logrotate.d/mrrc (5 MB trigger, three
generations, compressed, copytruncate because systemd
holds the descriptor) with its own
mrrc-logrotate.timer — it does not trust cron or the
distro's timer to be running — and caps journald at 128 MB
(the default is 10% of the filesystem).
Recordings got the non-destructive half of a retention policy:
below MRRC_RECORDINGS_MIN_FREE_MB (200 MB, about
seven hours at the default bitrate) a new recording is
refused, with the numbers, and never started. Nothing the
operator recorded is deleted to make room.
one bounded file · one bounded journal · refusals, never deletions
sign_for() now signs once per name: a usable pair
(CN/SAN match, more than 30 days to expiry, key and certificate
paired, parseable) is reused and not rewritten, so
"signed but the enrolment failed" can no longer leave the hub
pinning one certificate while the instance serves another — the
shape of an all-night 502 on a live entry. Rotating
is an explicit act (delete the file), and a broken instance heals
by clicking Connect once.
The FT8 deep path used to kill the server's DSP worker on
every slot: a Fortran stop in the native
decoder terminates its host process, and the launcher's startup
tee stops writing to a file once the server answers HTTP — so the
reason reached no log at all, only a bare
worker_exit. The worker now writes its own
logs/ft8-worker.log (the diagnostic bundle collects
it), the FFTW thread initialisation returns a status instead of
aborting, and worker_exit names the generation and
the restart count.
AD-021 · idempotent enrolment · a worker's death is now diagnosable
The flash-and-ship image (build-image.sh --preflash,
off by default) bakes in the three credentials,
Asia/Shanghai and zh_CN.UTF-8, so a box
goes from power-on to a logged-in browser with nothing in between.
Wi-Fi grew a typed SSID field (scan results only prefill
it) plus a show/hide password toggle — hidden networks and an
empty scan list used to be dead ends — and a new public-entry
panel takes a callsign, applies to the portal and reports the
entry address. The same pass fixed a real gap:
the first-boot probe had never run on any image
(the wrapper's MRRC_PRESEED=1 call short-circuited
before it), so a radio plugged in later was never found; the probe
now runs and repeats each boot until the config settles.
AD-027 · NFR-069 · first-boot probe now actually runs