From the review of 7723711:
- The assembler is locked: a client closed for a full queue is closed
by the task that was sending, loop(), whose disconnect dropped the
buffer while async_tcp could be copying into it. A whole message is
taken out of it, so a disconnect can't free it while it is read.
- loop() expires a message stalled for 10 s, freeing its buffer and
telling its client, instead of holding it until another client came.
A binary message is refused before it can touch another's buffer.
- Each edit takes only the fields its route reads; one it would ignore
is refused by name. linkRemote's rolling code goes in under the
route's name, so applyModelEdit is unchanged again.
- An edit refused for an id that doesn't exist replies not found
(edit_result_t::missing). A reply that doesn't fit its buffer goes
as an internal error, so the op still gets one.
- The TYPE table says what becomes of each op (proto_op_t), which the
socket switches on. The reply address is one proto_reply_to_t. The
routes and the ops start and queue an edit the same way
(newModelEdit, submitModelEdit). The full-list texts and the offered
remote address rule live in ModelEditor.
- e2e: the sort order test skips a list that it would renumber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shadeCommand, groupCommand, tiltCommand, repeatCommand, setPositions,
setSensor, setMyPosition, unpairShade, setRollingCode (types 16-24) are
read on async_tcp by ProtoOps and handed to loop() through the
LoopQueue, which replies once the request has run: ok, not found or
radio unavailable. A bad payload, a paused radio or a full queue is
answered straight away. sendRemoteCommand (25) touches nothing of the
shade model, so it goes to the radio from async_tcp like its route.
ShadeRequests::run() now says how a request went, not only whether
the radio took it. An op reads only the fields that were sent, so
setPositions can leave the tilt as it is. The shadeCommand event is
renamed shadeCommanded, since the op has the route's name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the review of #99:
- A sync could stall when a client took a slot the moment another left:
loop() used up the new client's sync on the old one. The slots move
to ProtoSlots, a pure module with native tests, and loop() takes a
slot's wants only for the client it read (takeWants).
- Deleting a group sends its shades, whose inGroup changed. Deleting a
shade unlinks it from its groups and sends them, so a new shade given
its id doesn't join them.
- next and sync with an id get an ok reply, and a message in pieces
gets one bad request, not one per piece.
- Feeds check for loop() before they write the event buffer, and log
an event too large, as events do.
- editChanges() (ModelEditor, native tests) says what clients get after
an edit; the edit result carries the shade a group gained or lost.
order() takes a sort_list_t.
- The frame writers move to ProtoFrame. Renames: pf to proto_field_t,
the X-macro letters to TYPE/FIELD/ERR/FEED, proto_request_t to
proto_message_t, REQ_* to WANTS_*, fmt to eventJson. The event
bodies share sendItem(), the connection type name lives in
ESPNetwork, and the loop() task check in SocketEmitter.
- e2e: the heap floor check skips when the low since boot is already
under it; tests for replies to next and sync and a long message.
- SECURITY_PLAN.md splits step 1 into 1a-1d.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The /ws endpoint runs next to the old socket on port 8080. The
handshake checks the token under security, the device sends hello,
then a sync of the schema (unless the client has it), header, rooms,
shades, groups, repeaters and status, paced by the client's next.
Events go out with the old ones: shadeState or the whole shade on a
config change, groups, rooms, removals, orders, repeaters,
shadeCommand, memory, wifi, ethernet, and the frames and
frequencyScan feeds.
The table of types, fields, errors and feeds is defined once and is
sent as the schema. The writer, item writers, sync and client frame
parser are pure and natively tested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>