Use names for JSON configuration targets#373
Merged
Merged
Conversation
ConfigTarget options used raw integer flags on the workbench wire, coupling the frontend to Go bit assignments and leaving parts of the model unavailable to satpulsetool. Give message, survey, save, and reset options stable name-based JSON forms, update the workbench and embedded assets, and add a strict hidden --target-json path for applying complete targets without CLI policy. Fixes #372
Empty JSON targets bypassed the normal probe default and entered passive capture, while target flag exclusivity failed open and could ignore message-file options. Make target JSON always reach the configurator and validate changed flags against an explicit session-option allowlist. Reject unnamed model bits and unknown frontend names, centralize the remaining option spellings, and cover stdin, trailing data, readback merging, exclusivity, and workbench wire conversion.
The workbench still declared ConfigTarget vocabulary locally and built apply requests through Record<string, any>, so TypeScript could not detect drift from Go serialization. Add central ConfigTarget types and runtime names to gps/ts, validate the complete vocabulary with generated Go JSON fixtures, and use those types throughout workbench readback and apply handling.
The workbench kept NMEA, PVT, satellite, and raw message selections as numeric bitmasks even after the ConfigTarget wire format moved to named values. This left UI state coupled to local flag ordering and required untyped conversion helpers.\n\nRepresent each selection group as an immutable typed set, derive wire arrays from the centralized ConfigTarget vocabulary, and cover set toggling plus unchanged and empty wire semantics in the workbench tests. Regenerate the embedded workbench assets.
Workbench apply requests could retain the read-only port property and panic the configurator, while HTTP decoding accepted unknown fields and trailing values. JSON CLI mode also discarded the show-port capability requirement and fell through to flag-derived property setters. Sanitize read-only properties at the session boundary, make request decoding strict, isolate JSON target construction, and retain display capability diagnostics. Replace the duplicated flag maps and ordering slices with one generic ordered codec and add regression coverage.
The config/wb-apply scenario was written on master while the ConfigTarget wire format was moving to named values on this branch, so it posted Opts.SatsMsg as the numeric bitmask 3. Once the two met in the merge, the apply request failed to decode and the scenario got a 400. Send the flag names the config panel sends, matching the array-of-names encoding SatsMsgFlags now marshals to.
The wb-apply scenario applied only Opts.SatsMsg, so the four other message flag groups crossed the ConfigTarget wire format untested: a regression in the array-of-names encoding of PVTMsg, NMEAMsg, RTCMMsg or RawMsg would have passed the suite. The one check it did make was also vacuous, because NMEA GSV decodes to a SatellitesMsg just as NAV-SAT does and NMEA defaults on: a satellites kind arrived whether or not the VALSET landed. Apply every group, and check them against the workbench packet stream, which names the packet the receiver actually sent rather than the kind the session decoded from it. NAV-TIMELS (PVTMsg), NAV-SAT/NAV-SIG (SatsMsg) and MSM4 (RTCMMsg) are off in the personality defaults, so their packets can only be the apply landing; NMEA, which defaults on, is disabled with the empty array, shown gone, and re-enabled by name, pinning both encodings. RawMsg is wire-format-only: the nav bank holds no RXM packet for its keys to gate.
ConfigOptions.Socket says the connection is a proxy rather than a serial port,
and gpscfg.Configure leans on it hard: it sends the probe immediately instead
of waiting for the line to go silent, asserts validPacketReceived before any
packet has arrived, nils the silence and deadline timers, and returns early,
skipping the framing checks. Nothing downstream cross-checks it against the
port it was handed. The --target-json path only forced Socket on, when --socket
was given, so a target carrying "Opts":{"Socket":true} kept that value on a
serial device and took the proxy path against real hardware. Assign it from the
transport in both directions instead, the way Session already does for its own
requests, so the JSON cannot state a transport fact it is not in a position to
know. The flag path gets the same assignment: it was correct only because no
flag ever writes configOpts.Socket, an invariant nothing stated.
The flag types accepted a JSON null as an empty array, the one strictness hole
left in the target's entry points, where the opt.Val groups reject it. Reject
it there too.
NMEASelectableMsgFlag did not exclude NMEAMsgOther: filter with a plain
predicate widens the readonly tuple back to the full union, so the type
promised a subset it did not deliver. Give it a type-guard predicate. The
survey report flag could also send "survey" twice, since the array concat that
replaced the bitwise OR does not dedupe.
Also lift the JSON decoding into decodeTargetJSON, drop an unreachable
configSupport reset in resolve, and correct the note in webui/CLAUDE.md that
says gps/ts never reaches a bundle: the workbench now value-imports the name
vocabularies, so editing gps/ts requires regenerating cmd/satpulsewb/dist.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
satpulsetool gps --target-jsoninput for applying a complete ConfigTarget from an argument or stdinThe previous workbench wire format duplicated Go bit assignments in TypeScript, so renumbering a model flag could silently change requests. The CLI also could not express several ConfigTarget semantics. The name vocabulary removes the bit coupling, while the JSON target path exposes the raw model without applying per-flag CLI policy.
Validation
make testnpm --prefix webui run typechecknpm --prefix webui testgo generate ./cmd/satpulsewbFixes #372