From 686fc2ce7d3ec09aa0e6448b5b136358fe3265b6 Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Mon, 17 Aug 2026 07:34:48 +0200 Subject: [PATCH] docs: fix three review findings in calibration documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Finding 1 (Critical): replace "16 chars" with "16 UTF-8 bytes" in the setCalibration unit field description (StreamHub-API.md) and the Cal·Unit toolbar row (WebUI.md); note that multi-byte characters consume more than one byte and that truncation never splits a character. - Finding 2 (Important): correct the claim that a sources broadcast after reloadConfig is conditional on new sources being added — that is true only of the Go hub. The C++ hub calls BroadcastSources() unconditionally on success. Both the reloadConfig command description and the configReloaded event description in StreamHub-API.md are updated; the Reload bullet in WebUI.md is updated with a brief note. Clients must tolerate an unsolicited sources frame after any reload. - Finding 3 (Minor): the configSaved failure example used "no SourcesFile configured", which matches neither hub. Corrected to the C++ form "no sources file configured" and added a note that the exact error text is not part of the protocol contract (Go uses "no sources-file configured"). Source evidence: calibration.go (maxUnitLen, len(), rune-repair loop), StreamHub.cpp (kMaxUnitLen, byte strncpy, HandleReloadConfig unconditional BroadcastSources, HandleSaveSources error string). Co-Authored-By: Claude Sonnet 4.6 --- Docs/StreamHub-API.md | 22 +++++++++++++++------- Docs/WebUI.md | 6 ++++-- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Docs/StreamHub-API.md b/Docs/StreamHub-API.md index 228c334..330f5ef 100644 --- a/Docs/StreamHub-API.md +++ b/Docs/StreamHub-API.md @@ -66,7 +66,7 @@ name — one entry covers every element of an array signal. | `signal` | string | — | non-empty after trimming; any trailing `[i]` is stripped | | `scale` | number | `1` | finite and non-zero | | `offset` | number | `0` | finite | -| `unit` | string | `""` | trimmed, truncated to 16 chars; empty = use the streamer's own unit | +| `unit` | string | `""` | trimmed, truncated to 16 UTF-8 bytes (a multi-byte character such as `°C` consumes more than one byte; truncation never splits a character); empty = use the streamer's own unit | Calibration is **metadata only**: the hub stores and redistributes it but never applies it. Ring buffers, recorded history, the `zoom` reply, both binary frames @@ -96,7 +96,11 @@ a live UDP session that must not be interrupted. An unsaved source the user adde keeps streaming. The hub replies with [`configReloaded`](#configreloaded), followed on success by a -`calibration` broadcast and a `sources` broadcast. +`calibration` broadcast. Whether a `sources` broadcast follows depends on the +hub implementation: the Go hub emits `sources` only when the file adds at least +one new source (each `sm.Add()` call triggers it individually), while the C++ +hub always emits `sources` unconditionally after a successful reload. Clients +must therefore tolerate an unsolicited `sources` frame after any reload. ### `getSources` / `getConfig` / `getStats` @@ -284,10 +288,12 @@ after a successful `reloadConfig`. It is a separate frame rather than a field on ```json {"type":"configSaved","ok":true,"path":"/etc/streamhub/sources.json"} -{"type":"configSaved","ok":false,"path":"","error":"no SourcesFile configured"} +{"type":"configSaved","ok":false,"path":"","error":"no sources file configured"} ``` Broadcast in reply to `saveSources`. `path` is always present (empty when the hub -has no config file configured); `error` only when `ok` is false. +has no config file configured); `error` only when `ok` is false. The exact error +text is not part of the protocol contract and differs between hubs (the Go hub +uses `"no sources-file configured"`, the C++ hub `"no sources file configured"`). ### `configReloaded` @@ -295,9 +301,11 @@ has no config file configured); `error` only when `ok` is false. {"type":"configReloaded","ok":true,"path":"/etc/streamhub/sources.json"} {"type":"configReloaded","ok":false,"path":"/etc/streamhub/sources.json","error":"cannot read sources file"} ``` -Broadcast in reply to `reloadConfig`; same shape as `configSaved`. On success it -is followed by a `calibration` broadcast and, if the file added any source, a -`sources` broadcast. +Broadcast in reply to `reloadConfig`; same shape as `configSaved`. On success +it is followed by a `calibration` broadcast. Whether a `sources` broadcast also +follows is hub-specific: the Go hub sends it only if the reload added at least +one new source; the C++ hub sends it unconditionally. Clients must tolerate an +unsolicited `sources` frame after any reload. --- diff --git a/Docs/WebUI.md b/Docs/WebUI.md index b896049..aa3439b 100644 --- a/Docs/WebUI.md +++ b/Docs/WebUI.md @@ -91,7 +91,9 @@ At the bottom of the sidebar, the collapsible **Sources & Config** section holds config file; - **Reload** — re-reads that file. Calibration is replaced wholesale (so unsaved edits are discarded), sources present in the file but not running are added, - and no running source is stopped or reconnected; + and no running source is stopped or reconnected. The hub may send an updated + `sources` list even when nothing changed (see the API doc for the per-hub + difference); - a status line showing the written path on success or the hub's error text on failure. @@ -160,7 +162,7 @@ plot header showing per-signal vertical scale controls: | **Type** (Mixed mode only) | Toggle between **Analog** and **Digital** for this signal | | **Cal · Scale** | Data calibration gain. `value = raw × Scale + Offset` | | **Cal · Offset** | Data calibration bias, in calibrated units | -| **Cal · Unit** | Overrides the unit reported by the streamer (max 16 chars) | +| **Cal · Unit** | Overrides the unit reported by the streamer (max 16 UTF-8 bytes; a multi-byte character such as `°C` counts as more than one byte) | | **Reset** | Clears this signal's calibration (`Scale = 1`, `Offset = 0`, no unit override) | | **✕** | Close the toolbar and deselect the signal |