diff --git a/docs/superpowers/plans/2026-11-02-flat-udp-source.md b/docs/superpowers/plans/2026-11-02-flat-udp-source.md index 90cb534..99c89a2 100644 --- a/docs/superpowers/plans/2026-11-02-flat-udp-source.md +++ b/docs/superpowers/plans/2026-11-02-flat-udp-source.md @@ -1619,6 +1619,16 @@ git commit -m "flatudp: the source, kind, mock sender and stream probes" --- ### Task 3: The row-editor form, its probe lines, README and architecture +> **Amendment (read first).** After Task 2 the vector semantics changed: see the "Amendment 2026-11-02" section +> of `docs/superpowers/specs/2026-11-02-flat-udp-source-design.md`. `flatudp::Row` now has a `bool wave` +> (default false) and the codec/source already implement `channels` vs `waveform` rows and the channel cap. This +> task's form must therefore: add a "Vector as" `GtkDropDown` (`Channels` / `Waveform`, widget name `flatudp-vector`) +> to each row, shown only while that row's count is above 1 (reset to Channels when the count returns to 1); write +> it into `Row::wave`; show the channel total in the subtitle (the first `problem()` text still wins); and extend the +> form probe with a waveform case (a waveform row beside a scalar row is invalid; two waveform rows of the same count +> are valid). Where the code below predates this, follow the amendment. README and the docs must describe both +> modes, the `w` suffix, the mixed-list rule and the 256 channel cap. + **Files:** - Modify (full replacement): `src/source/flatudp/flatudp_kind.cpp` - Modify: `src/ui_probe.cpp` (a form check, called from `flatudp_probe`) diff --git a/docs/superpowers/specs/2026-11-02-flat-udp-source-design.md b/docs/superpowers/specs/2026-11-02-flat-udp-source-design.md index 31af66e..1f243d8 100644 --- a/docs/superpowers/specs/2026-11-02-flat-udp-source-design.md +++ b/docs/superpowers/specs/2026-11-02-flat-udp-source-design.md @@ -120,3 +120,28 @@ README (the kind and its limits: no loss detection, the signal list is the user' responsibility), `docs/claude/build-and-run.md` (options and mock usage), `docs/claude/architecture.md` (source plugins), `docs/claude/probe-readings.md` and `docs/claude/verification.md` (the new probe lines). + +## Amendment 2026-11-02: how a vector signal is shown (decided with the user during Task 2) + +Task 2 found that treating every vector row as one channel of `count` consecutive samples zero-pads +the scalar channels of a mixed list (the model spans a frame by its largest element block, and +`Frame::value` is 0 past a scalar's one value) and declares the wrong rate for the vector channel. +Both readings of a vector are useful depending on the sender, so each vector row picks one: + +- **`channels` (default).** `Wave:float32[16]` becomes 16 scalar channels named `Wave[0]` .. `Wave[15]`, + one sample per cycle each. All such lists are batched like an all-scalar list. +- **`waveform`.** `Wave:float32[16]w` is ONE channel receiving a block of `count` consecutive samples per + cycle: `SignalInfo{rows=count, cols=1, sampling_rate=rate*count}`, one datagram per `Frame` + (`num_samples = 1`). + +Rules: +- The `signals` string takes an optional trailing `w` after the count; `format` emits it only for a waveform row. +- A waveform row needs `count > 1`. +- A list with a waveform row must contain only waveform rows, all with the same `count`; otherwise it is + invalid, with a message the form shows. (No zero-padding, no holding scalars across a block.) +- The channel total is capped at 256: scalars count 1, a `channels` row counts `count`, a waveform row counts 1. + Over the cap is invalid. +- `block` batching applies whenever the list has no waveform row; with a waveform row it is 1. +- The form shows a "Vector as" dropdown (`Channels` / `Waveform`) on rows whose count is above 1, and + the channel total in the subtitle. +- The earlier "Data flow" text saying every vector row forces `num_samples = 1` applies to waveform rows only.