Skip to content

WCB firmware 6.2.1 sweep (4.3.0) - #9

Merged
travisccook merged 17 commits into
mainfrom
wcb-firmware-6.2.1-sweep
Sep 15, 2026
Merged

travisccook merged 17 commits into
mainfrom
wcb-firmware-6.2.1-sweep

Conversation

@travisccook

Copy link
Copy Markdown
Owner

Minor release 4.3.0: WCB firmware 6.2.1 sweep (WCB 66845b9a, 6.2.1_021242RSEP2026; WcbCmd 0.8.0 @ 168f1e5). Catalog 21 → 22 boards, 397 → 500 commands. Spec: docs/superpowers/specs/2026-09-15-wcb-firmware-6.2.1-sweep-design.md.

Id policy (D1/D2): no 4.2.0 id is removed, renamed or re-templated, with one documented exception below. A new guard test (test/wcb-621.test.js + test/fixtures/catalog-4.2.0-commands.json) freezes every 4.2.0 id's template, ordered param names, board, encoder and duration support, and checks WCB-board examples decode to their own command and fit the 187-char ETM limit.

What's in it

  • maestro: WCB 6.2+ comma verbs under new maestro.wcb.* ids (sub/subParam/sub verb forms, stopScript, goHome, setTarget/Speed/Accel, getPosition/MovingState/Errors). Ids 0-9 (9 = this WCB's Maestros), subroutines 0-127. maestro-native (NaviCore grammar) is unchanged apart from routing notes.
  • New wcb-dfp board: DFPlayer Mini ;D, verbs (WCB 6.2+).
  • wcb-hcr: TRIGGER, all-channel VOL/VOLUP/VOLDN steps, FN limited to firmware function codes; 6.2.1 host routing.
  • wcb-mp3: 6.2.1 host routing notes. wcb-wled: preset starts at 1, "(WCB 6.2+)".
  • wcb-native: 66 new commands (mesh channel, alias, controller, LED pin/identify, WLED/DFPlayer/MP3/HCR remote config, ;W alias routing, ;P PWM pulse, ;V/;VP variables and IF, sequence names/get and ,L local runs, timer stop, WDP, debug/track/version) and range/grammar corrections (board numbers 1-20, 30-minute timer, S0 routing, HCR baud/poll/get fields, ETM miss 100, multi-destination maps).
  • FlthyHPs fix (the one template exception): flthy.led.solid → 005, rainbow → 006, shortcircuit → 007, X/Y/Z designators restored. The v1.8 manual table is the pre-v1.6 numbering; stock v1.81 source (apsteven/FlthyHP@bdbcbe3 FlthyHPs_v1.8.ino L118-120, dispatch L932-934) and the author's current v2.1 (ryan-sondgeroth/FlthyHPs@aea19d8 L440-442, README L188-190) use 005 solid / 006 rainbow / 007 short circuit — as astropixels-holo already does. Evidence and the decode note are in the spec.

Heads-up for other consumers: new maestro.wcb.* ids and new sequence ids (wcb.runSeqLocal, wcb.runSeqLongLocal, wcb.seqNames, wcb.seqGet, wcb.timerStop) — NaviCore's local wcb-sequences split won't move these automatically.

npm run validate exit 0 (non-standard category warnings only); npm test 12 suites / 387 tests.

🤖 Generated with Claude Code

travisccook and others added 17 commits September 15, 2026 11:18
Design and implementation plan for the WCB firmware 6.2.1 sweep
(droidnet-command-library 4.3.0), generated against WCB 66845b9a
(SoftwareVersion 6.2.1_021242RSEP2026) and WcbCmd 0.8.0 @ 168f1e5.

Spec records the id policy (D1 minor release, maestro.wcb.* as new ids;
D2 4.2.0 templates and param names frozen), maestro-native left as is
(D3), one version number (D4), firmware requirements in names (D5), the
out-of-scope list (D6), per-board tables, ordering hazards, and how
DroidNet's unpublished 2.2.0 ids map to 4.3.0.

FlthyHPs: every sketch from v1.6 through the author's v2.1 dispatches
005 solid / 006 rainbow / 007 short circuit and accepts X/Y/Z; the
v1.8 manual table is the pre-v1.6 order. 4.3.0 follows the firmware.

BOARD_AUTHORING_GUIDE: the composer shows neither firmware nor
routing.notes, so firmware requirements go in command/component names.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
…mand

Guards for the WCB 6.2.1 sweep, landed before any board edit and green
on 4.2.0:

- test/fixtures/catalog-4.2.0-commands.json: every 4.2.0 command id
  (397) with its board, template and ordered param names, generated once
  from a pristine export of 82b6a04 via src/load-node.js readCatalog().
  Committed because CI checks out with depth 1.
- test/wcb-621.test.js
  (a) every frozen id still resolves with the same template and param
      names (D2); an explicit, empty TEMPLATE_FIXES allowlist pins
      from/to for sanctioned template corrections;
  (b) every example on maestro, wcb-hcr, wcb-mp3, wcb-wled, wcb-native
      (and wcb-dfp once added) matches its own command id, catching
      first-match-wins ordering regressions web.test.js cannot see;
  (c) wcb-verb examples stay within the 187-char ETM limit
      (WCB 6.2.1 WCB.ino:216-223 ETM_MAX_CMD_WITH_CRC).

Mutation-checked in a scratch copy: a changed template, a removed id, a
catch-all moved ahead of its literals, an over-long example and a wrong
allowlist entry each fail the matching assertion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
…nes 0-127

Firmware re-read: WCB 6.2.1 @ 66845b9a WCB.ino:6729-6786 (processMaestroCommand),
WCB_Maestro.cpp:245-527 (sendMaestroServoVerb, handleMaestroGet :396-397,
maestroVerbForwardText), WCB_Help.cpp:430-459; WcbCmd 0.8.0 WcbMaestro.h:10-51,
WcbMaestro.cpp:6-182; 6.1.5 WCB.ino:4871-4876 and WCB_Maestro.cpp:143-168;
Pololu Maestro guide 5.c (data bytes 0-127) and 5.e (target/speed/accel,
Get Moving State on Mini Maestros only).

- maestro.id codes 0-9: 0 All, 1-8, 9 "All local (this WCB)". Id 9 is not
  6.2-only; 6.1.5 already fans ;M9<seq> out to the local Maestros.
- New maestro.queryId (1-8): handleMaestroGet rejects 0 and 9.
- maestro.trigger seq max 9 -> 127 (firmware accepts 0-255, but the
  subroutine goes on the wire as one Pololu data byte). Template and param
  names unchanged (D2).
- 12 new maestro.wcb.* ids, all named "(WCB 6.2+)": sub, subParam, subVerb,
  subVerbParam, stopScript (Sequences); goHome, setTarget, setSpeed,
  setAccel (Movement); getPosition, getMovingState, getErrors (System,
  cosmetic, queryId). Channels 0-23; new params carry range labels and
  defaults, and id defaults to #1 rather than the All broadcast.
- Component: name "Maestro (WCB ;M verbs)" (manifest too), firmware
  "WCB 6.2.1_021242RSEP2026", categories Sequences/Movement/System,
  routing.notes covering the 6.1.x subroutine-0 hazard, id meanings,
  the 0-127 subroutine range, async get queries into m<id>pos<ch> /
  m<id>moving / m<id>err read by a later IF, no ;W around a get, and
  getMovingState being Mini Maestro only.

Refinement of the spec's "comma forms need 6.2.1 on the sender and the
Maestro host": per maestroVerbForwardText / sendMaestroCommand, a 6.2.1
board forwards a plain ;M<id>,<n> as the legacy ;M<id><n>, so only verbs
and subroutines with a parameter reach the host in comma form. The notes
say exactly that.

Tests (test/wcb-621.test.js): ;M11/;M91 -> maestro.trigger; ;M1,5 ->
maestro.wcb.sub; ;M3,5,1000 -> maestro.wcb.subParam; ;M2,goHome ->
maestro.wcb.goHome while bare goHome stays maestro.goHome (no shared id);
get queries on id 0/9 stay raw; all 12 ;M{id}, templates are named
"(WCB 6.2+)"; component/manifest metadata.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
New wcb-verb board libraries/boards/wcb-dfp.json, "WCB · DFPlayer Mini
(WCB 6.2+)", firmware WCB 6.2.1_021242RSEP2026, categories Sound, Volume,
System. Listed in the manifest right after wcb-mp3 (the ;D, prefix is
unique, so position does not affect matching).

21 commands, re-checked against WcbCmd 0.8.0 DfPlayerCodec::handle
(WcbDfPlayer.cpp:51-168), WCB_DFP.cpp:69-91 and WCB_Help.cpp:566-593:
- PLAY track 1-2999, FOLDER folder 1-99 / track 1-255, MP3FOLDER 1-9999,
  each with an ONFIN,<key> callback variant
- STOP, PAUSE, RESUME, NEXT, PREV, RANDOM
- LOOP 1-2999, LOOPALL 0/1, LOOPFOLDER 1-99, EQ 0-5 (Normal..Bass)
- VOL 0-30 (default 20), VOLUP, VOLDN
- RESET (safety config), STATUS
dfp.play, dfp.stop and dfp.volume keep DroidNet 2.2.0's templates and
param names.

;D,DEVICE,<n> is documented but not modeled: WCB 6.2.1 rejects it.
processDFPCommand strips the leading "D," (WCB_DFP.cpp:72-74) and
DfPlayerCodec::handle strips an optional leading 'D' again
(WcbDfPlayer.cpp:54), so the codec sees "EVICE,<n>". Confirmed by
compiling WcbDfPlayer.cpp with a copy of that dispatch. routing.notes and
a test record this; adding dfp.device later is a minor.

test/load-node.test.js: catalog board count 21 -> 22.
test/wcb-621.test.js: wcb-dfp assertions (manifest position and names,
verb list, DroidNet-compatible ids, firmware ranges, ONFIN decoding,
LOOP*/VOL* disambiguation, safety, DEVICE left raw).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…er 6.2.1

- hcr.trigger ;H,TRIGGER,{emotion},{strength} (WCB_HCR.cpp:290-299; also on 6.1.5).
- hcr.volAll ;H,VOL,{level} "(WCB 6.2+)": 6.2.1 treats a missing channel as all
  of V/A/B (WCB_HCR.cpp:365-388); 6.1.5 requires a channel.
- hcr.volUpAllStep / hcr.volDownAllStep ;H,VOLUP|VOLDN,{step} (1-100, default 5):
  a bare step bumps every channel on 6.1.5 and 6.2.1 (WCB_HCR.cpp:389-413).
- hcr.fn: fn becomes enum hcr.fnCode with the codes HcrCodec::normalize accepts
  (WcbCmd WcbHcr.cpp:7-36): 2-11, 13, 14, 16-19; 7, 10, 13, 18 and 19 are
  labelled 6.2+ (absent from the 6.1.5 switch). chan max 9 -> 99 (fn 7 muse
  gap). Template and param names unchanged.
- firmware "WCB 6.2.1_021242RSEP2026" (was the stale 6.1.0 HCR_Integration);
  routing.notes document 6.2.1 host routing (local, ?HCR,REMOTE,W<n>, WDP
  owner; WCB.ino:6391-6409, 6429-6431) vs 6.1.x local-only.
- hcr.emotion / hcr.channel untouched (byte-identical with hcr-native).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- firmware "WCB 6.2.1_021242RSEP2026".
- routing.notes: on 6.2.1 ;A runs on the MP3 host (this board, else the stored
  ?MP3,REMOTE,W<n> board, else an online WDP owner; WCB.ino:6391-6409,
  6423-6425) and a mesh-delivered ;A is never re-forwarded; 6.1.x plays only on
  the receiving board (6.1.5 WCB.ino:4709-4710). Volume scale 0 loudest to 64
  inaudible, 5-step VOLUP/VOLDN.
- Verbs and ranges unchanged: 6.2.1 delegates to WcbCmd Mp3Codec::handle
  (WcbMp3.cpp:32-93), which matches the board.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- wled.preset: preset min 0 -> 1. WLED preset slots are 1-250 (WLED JSON API
  psave/pdel); WcbWled::build passes the number through unchecked.
- Component and manifest name "WCB · WLED Lighting (WCB 6.2+)": 6.1.5 has no ;L
  dispatch (6.1.5 WCB.ino:4697-4718; 6.2.1 WCB.ino:6432-6433).
- firmware "WCB 6.2.1_021242RSEP2026" (was "WCB WCB_WLED").
- routing.notes: the receiving WCB must know the id (?WLED,<id>:W<wcb>S<port>:<baud>
  or WDP auto-add), no fallback for an unknown id (WCB_WLED.cpp:110-157); one
  mesh hop, no re-forward, no read-back; mesh-routed commands stay within 187
  characters while ?ETM,CHKSM is on (WCB.ino:216-223).
- The other nine wled.* ids are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Re-read against WCB 6.2.1 @ 66845b9a (SoftwareVersion
6.2.1_021242RSEP2026). Templates and ordered param names are unchanged
(the 4.2.0 freeze test still passes); only ranges, enums and patterns
tighten or widen. Hand-edited in place to keep the file's formatting.

- firmware -> "WCB 6.2.1_021242RSEP2026"; add routing.notes recording
  the 6.1.x vs 6.2.1 behavior differences a reviewer needs (;S comma,
  ;C/;SEQ mesh fan-out and ,L, ;V volatile vs ;VP, ?FUNCCHAR,? / ?CMDCHAR,?
  6.2.1-only, ?CONTROLLER = ?SPECIAL on 6.1.x, IF limits, the
  ?MAP,PWM,CLEAR,OUT reboot)
- new enums wcb.portUsb (S0 USB + S1-S5), wcb.devBaud
  (9600-115200), wcb.hcrField (the 14 GET fields)
- wcb.num / wcb.qty max 20 (WCB.ino:5298-5305, WCB_Storage.cpp:447-451)
- wcb.routeWcb wcb max 20 (WCB.ino:6553-6566)
- wcb.routeSerial port -> wcb.portUsb (WCB.ino:6450-6463)
- wcb.timer ms max 1800000 (command_timer.cpp:166)
- wcb.maestroClear id max 8 (WCB_Maestro.cpp:817)
- wcb.maestro spec .+ -> M<id>:W<wcb>S<port>:<baud> list, so
  ?MAESTRO,REMOTE no longer parses as a Maestro spec (WCB.ino:5437)
- wcb.hcrPort baud -> wcb.devBaud (WCB_HCR.cpp:630-633)
- wcb.hcrPoll min 3 (WCB_HCR.cpp:568-575)
- wcb.hcrGet field -> wcb.hcrField (WCB_HCR.cpp:586-604)
- wcb.etmMiss max 100 (WCB.ino:5211-5217)
- wcb.mapSerial / wcb.mapSerialRaw dest -> comma list of S0-S5 /
  W1-20S0-5 with an optional R per destination
  (WCB_Storage.cpp addSerialMonitorMapping); a destination cannot start
  with R, so the ,R, literal of mapSerialRaw stays unambiguous
- wcb.mapPwm dest -> comma list of S1-S5 / W1-20S1-5
  (WCB_PWM.cpp addPWMMapping)

Tests appended to test/wcb-621.test.js pin each range, the S0 route,
the HCR baud/field sets, the Maestro spec tightening and the map
destination grammar (including the R suffix vs the ,R, literal).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
Adds 66 new command ids to wcb-native (77 -> 143), each re-read against
WCB 6.2.1 @ 66845b9a, with 6.1.5 (v6.1.5_290119RJUN2026 = 5cd4b6ba)
checked to decide the name suffix: the 40 commands 6.1.5 lacks end in
"(WCB 6.2+)"; the 26 it already had do not. No 4.2.0 id, template or
param name changes. Inserted by hand at the ordering anchors, keeping
the file's formatting (the diff is additions plus the enum and
categories lines).

- Setup (before wcb.mac2): ?WCBCH mesh channel 1-11; ?ALIAS CLEAR /
  LIST / <name>; ?CONTROLLER ON / ON,<id> / OFF; ?LED,PIN[,gpio 0-48];
  ?IDENTIFY (cosmetic)
- Config: ?BCAST,OUT,S0; ?MAP,PWM,CLEAR,OUT,S<port> (safety power, it
  reboots); ?KYBER,LOCAL,S<port>,<maestro specs>; ?MAESTRO,REMOTE
  (before ?MAESTRO,{spec}); ?MP3,REMOTE W<n> / OFF; the ?DFP family
  (S<port>:9600:V<vol>, S<port>, LIST, CLEAR, REMOTE, ONERR); ?HCR,POLL,OFF
  and ?HCR,REMOTE W<n> / OFF; the ?WLED family (<id>:W<wcb>S<port>:<baud>,
  LIST, STATUS, CLEAR, CLEAR,<id>)
- Routing / Movement (before wcb.timer): ;W<alias>,<message>;
  ;P<port><width> 500-2500 (movement; port is a one-digit enum so it
  cannot swallow the width)
- Sequences: ?SEQ,NAMES, ?SEQ,GET,<key>; ;C<key>,L and ;SEQ<key>,L
  (local-only runs); ?STOP
- Variables (before wcb.etmOn): ;V / ;VP set, TOGGLE/INC/DEC/true/false,
  INC/DEC by n; IF,<cond>[,AND|OR,<cond>...]; ?VAR LIST / SET / GET /
  CLEAR,ALL / CLEAR,<name>
- System (before wcb.stats): ?DEBUG,MGMT / RAW; ?TRACK ON|OFF / STATUS;
  ?VERSION; ?PEERSLIVE; the ?WDP family (LIST, <n>, STATUS, DUMP, DA,
  POLL, ON|OFF, AUTOJOIN[,ON|OFF], ADD, FORGET, CLEAR)
- enums wcb.varScope, wcb.varOp, wcb.varDir; categories gain Movement
  and Variables (Variables is a non-standard name; the validator warns)

Where the firmware is stricter than the scratch proposal:
- wcb.wledCfg port uses wcb.port (S1-S5), not wcb.portUsb: a WLED is
  never on S0/USB (WCB_WLED.cpp:311).
- wcb.alias, wcb.dfpOnErr and wcb.varClear exclude any-case CLEAR /
  LIST / ALL, because the firmware compares those words
  case-insensitively (WCB.ino:5375-5378, WCB_DFP.cpp:189,
  WCB_Variables.cpp:328); ?ALIAS,clear, ?DFP,ONERR,clear and
  ?VAR,CLEAR,all stay raw steps instead of being mislabelled. The
  ONERR key is capped at 23 characters (onErrCmd[24]).

Tests appended to test/wcb-621.test.js: the exact 66-id set, the name
suffix split, safety classes, literal-before-catch-all pairs (ALIAS,
VAR,CLEAR,ALL, DFP,ONERR,CLEAR, MAESTRO,REMOTE), any-case raw steps,
;W alias vs number, ;C<key>,L vs ;C<key>, ;P11500 -> port 1 width 1500,
variable and IF grammar, device/config/system verbs with optional
arguments, and byte-identical round-trips of every new example.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
routing.notes only (D3); no command, range or category change.

The board is the bare Pololu action grammar NaviCore and local controllers
use. Re-read WCB 6.2.1 WCB.ino:4868-4880: handleSingleCommand sends any line
without the ? or ; prefix to processBroadcastCommand as-is, so a WCB never
translates setTarget,… / goHome into Pololu frames. The notes point WCB
users at the maestro board (;M{id},…) and record that WcbCmd's WcbMaestro
omits restartScript, setSpeedAccel and setEasing (WcbMaestro.h:48-51).

Test: maestro-native notes say a WCB does not translate it and name the
;M{id}, forms.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
2.3.0 (b38b5d2) took the LED sequence numbers from the FlthyHPs Manual v1.8
command table, which is the order of the v1.3-v1.5 sketches. Every sketch from
v1.6 on, including v1.81 (FlthyHPs_v1.8.ino:932-934) and the author's v2.1
(FlthyHPs_v2.1.ino:440-442), dispatches 5 = solid, 6 = rainbow and
7 = short circuit, and accepts the X/Y/Z designators (v1.81 :791-797, :813-818).

- flthy.led.solid        {designator}006{color} -> {designator}005{color}
- flthy.led.rainbow      {designator}007        -> {designator}006
- flthy.led.shortcircuit {designator}005{color} -> {designator}007{color}
- flthy.designator regains X (Front & Rear), Y (Front & Top), Z (Rear & Top)
- examples follow the author's manual (R0053 solid green, T006, A006|45);
  firmware field now names the v1.6+ numbering

Ids and param names are unchanged. The 4.2.0 freeze test allowlists exactly
these three template changes, pinning both templates and the reason, and new
assertions cover the codes and designators. Tests, the sample fixture, the
README quick start, the integration guide, the Node example and the schema
durationSuffix example move to the firmware codes. The 2026-07-06 FlthyHPs spec
gets a note that decisions 1 and 2 are superseded (servo codes stand).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
The board commits re-read the firmware and, as the spec allows, followed it
where it disagreed with the tables. Add an "As built" section so the spec
matches what 4.3.0 ships:

- wcb-dfp has 21 commands: ;D,DEVICE,<n> is rejected by 6.2.1 (the leading
  D is stripped twice, WCB_DFP.cpp:72-74 and WcbDfPlayer.cpp:54), so
  dfp.device is not modeled.
- maestro: a numeric-only comma payload is forwarded in the legacy ;M<id><n>
  spelling (WCB_Maestro.cpp:262-271); 6.1.5 also allows a Maestro at id 9.
- wcb-native: wledCfg port is S1-S5; dfpOnErr / varClear lookaheads; ONERR
  key <= 23 chars; queries stay config; var enums land with the new commands.
- wcb-hcr: volume sends cap at 99; fn track range note.
- Totals: 22 boards, 500 commands; only the FlthyHPs template fixes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
- libraries/manifest.json: libraryVersion 4.3.0; generatedFrom appends
  "WCB 6.2.1_021242RSEP2026 + WcbCmd 0.8.0 (2026-09)". The wcb-dfp entry
  and the renamed maestro / wcb-wled names landed with their boards.
- releases.json: latest and libraries[0] -> 4.3.0, releasedAt 2026-09-15,
  notes for the sweep as built: maestro +12 (maestro.wcb.*), new wcb-dfp
  (21 verbs; ;D,DEVICE is not modeled because 6.2.1 rejects it), wcb-hcr +4,
  wcb-native +66 with range fixes, wled.preset from 1, the FlthyHPs v1.6+
  sequence codes, and the engine 3.1.0 compatibility sentence old DroidNet
  confirm dialogs show. Boards 21 -> 22, commands 397 -> 500.
- package.json and package-lock.json (top-level and packages[""]) -> 4.3.0
  (D4), hand-edited.
- Test pins: load-node and engine libraryVersion 4.3.0 (board count 22
  already pinned by the wcb-dfp commit).

npm run validate exits 0 (category-outlier warnings only); npm test 385/385.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
…ailing space

wcb.alias and wcb.routeAlias accepted [A-Za-z][^,;?]{0,23}, which let
names through that the firmware or the wire format cannot keep:

- WCB 6.2.1 saveWCBAlias() trims the alias and rewrites ^ , ; ? CR LF
  to '_' (WCB_Storage.cpp:212-229), so no saved alias holds them.
- ?ALIAS trims its argument before the LIST/CLEAR compare
  (WCB.ino:5372-5384), so "?ALIAS,List " runs LIST but decoded as Set
  Board Alias. ;W<alias>, trims the alias too (WCB.ino:6525-6531).
- ^ splits steps, and match() strips a trailing |<digits> as a
  duration, so "?ALIAS,Dome|25" can never decode to wcb.alias.

Both patterns are now [A-Za-z](?:[^,;?^|\r\n]{0,22}[^,;?^|\s])?
(still 1-24 characters, letter first); wcb.alias keeps its CLEAR/LIST
lookahead. Strings outside the shape survive as raw steps. The spec
tables and As built section record the change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
The D2 freeze guard compared only template and ordered param names, but
match() keeps a trailing |n only when the matched command sets
supportsDuration. Deleting supportsDuration from ap.hp.native.solid left
validate and every test green while the stored value @HPF0051|30 stopped
decoding (five 4.2.0 duration commands have no |n example).

- test/fixtures/catalog-4.2.0-commands.json: each entry adds encoder
  (default "template") and supportsDuration (boolean), regenerated from
  a pristine 82b6a04 export in the same one-line format. The generator
  reproduced the committed board/template/params byte-for-byte first.
- test (a) also asserts the entry's board, encoder and supportsDuration,
  and that a frozen duration command still encodes a |n suffix (the
  board's durationSuffix is on).

Mutation-checked in a scratch copy: deleting or adding supportsDuration,
changing an encoder, turning a board's durationSuffix off and a board
mismatch each fail test (a) with a named drift line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
The 4.3.0 notes said "Saved steps keep their exact text." True of the
bytes, but the FlthyHPs code fix is the one change to how stored values
decode, and the notes an old DroidNet update dialog shows did not say
so:

- 4.2.0 Solid Color / Rainbow steps (A0065, R0063, T007, A007|45) no
  longer match a command and load as raw text.
- 4.2.0 Short Circuit steps (A0057, F0055|10) load as Solid Color and
  keep their saved "*** Flthy short circuit" label.

Verified by decoding with the 82b6a04 and HEAD engines.

- releases.json: the notes name both effects.
- test/wcb-621.test.js pins the Short Circuit -> Solid Color decode
  (with label and duration) and the raw decode of the old codes.
- Spec: the FlthyHPs hardware check is recorded as not yet run, and
  gated as in release plan M1 (bench result or maintainer sign-off,
  otherwise the fix moves to a 4.3.1).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
The wcb-dfp section, the DroidNet id map and the plan still described
the planned board: a dfp.device command and enum, "22 commands", and
"plus 19 more dfp.*". Only the As built bullet said otherwise.

- Spec wcb-dfp section: drop the dfp.device enum and table row, say 21
  commands with only dfp.reset as config, and point to As built for why
  DEVICE is not modeled (WCB_DFP.cpp:72-74 strips "D," and WcbCmd
  WcbDfPlayer.cpp:54 strips a leading D again, so "DEVICE,2" arrives
  as "EVICE,2").
- Spec id map: "plus 18 more dfp.*" (21 - dfp.play/stop/volume).
- Plan A4 and A12: 21 commands/verbs, no dfp.device enum.

The board, tests and releases.json already said 21.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cv8VK6dup1R8xDzk3MJgRZ
@travisccook
travisccook merged commit 7bb6629 into main Sep 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant