Builds with one app slot (C6, debug, and the C5 to come) have nowhere
for /updateFirmware to write. It answered "Error updating firmware: "
and rebooted.
- ConfigSettings::otaSlot, from esp_ota_get_next_update_partition().
- The header sends otaSlot, default 1, so only those builds send it.
- /updateFirmware refuses with 400 and a reason, and doesn't stop the
radio or reboot.
- The web UI's Update Firmware says to flash the onboard image over USB,
with a backup first. Firmware before the field leaves it undefined,
which keeps the uploader.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- One socket at a time: a socket being replaced is let go without a word,
and connect() or a new token while a reconnect waits opens no second one.
A new token reconnects at once, without a refused.
- Events that came before the schema go as soon as it is whole, ahead of
the sync frames formatted after them, not at syncEnd over newer state.
- A schema's hash counts only once it has come whole, so a sync cut short
gets it again.
- Feeds are subscribed again after a reconnect; an unknown feed is refused.
- A long op refused as busy without its id goes again.
- A sync without repeaters clears them; order changes name their list; a
refused resync is called off.
- refused: a listener can close() to stop the retries, which the UI does
once /loginContext says a login is needed. The client itself can't tell a
refused token from a device that is down.
- localStorage keeps the schema by default. minify.py removes its work
folder even when a bundle fails. ADR 0005 records the two bundles.
- Smaller: ProtoSchema.ROWS/withoutRows, ProtoModel.ITEMS, named type
numbers, unused feeds map and FakeSocket.all gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- data-src/js: ProtoSchema (schema from the sync, short keys and names,
defaults, cached by hash), ProtoModel (rooms, shades, groups, repeaters,
header and status from the sync and the events) and ProtoClient (/ws,
hello, sync with next, op() as a Promise of its reply, events, feeds,
reconnect). Nothing uses them yet: 2b moves the UI onto them.
- minify.py joins js/*.js and index.js into index.js, and the three CSS
files into app.css, so a page load opens fewer connections.
- test/js: node --test on the three modules, replaying the recorded
fixtures; a CI job runs it and the firmware build waits for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>