emrg: fix GUI task save no-response — wire type field collision - #793
Conversation
Rant 2026-08-14T21:48:00: GUI task management save appeared to do
nothing (form stays open, no list refresh). Root cause: daemon_client.js
sendCommand built frames as { type, ...params } — the task CRUD payload
carries a "type" field (the task type, e.g. "evolution") which spread
over the wire message type, so the daemon routed "evolution" as the
message type and replied "unknown message type". The error was written
to the chat area while the tasks panel is open (view exclusivity), so it
looked like no response.
Fixes:
- daemon_client.js sendCommand: { ...params, type } — wire message type
last, never overridden by payload fields (generic defense)
- main.js taskCreate/taskUpdate: send the task type as "task_type"
(never occupying the message-type field name)
- daemon.py task_create reads task_type; task_update maps task_type to
type for scheduler.task_update (internal name unchanged)
- tests: +1 daemon_client frame-shape regression (payload type must not
override wire type); +3 wire e2e tests (task_create reads task_type /
missing task_type never falls back to wire type / task_update maps
task_type to type); Agent.md counts 806->809, GUI 246->247
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle: sendCommand frame order fix verified ({ ...params, type } keeps wire type authoritative), taskCreate/taskUpdate send task_type, daemon task_create reads task_type (negative e2e proves no fallback to wire type) and task_update maps task_type→type for scheduler. Local pytest 809 + GUI 247 + import + CLI green; CI test + test-windows pass.
|
I tested this PR end-to-end at head Verification (first-hand, Windows host)
Code review
Non-blocking notes
CI was pending ( |
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle (2nd ✅)
Full review this cycle (head 3fb4f94, diff audited):
- Root cause sound:
sendCommandbuilt frames as{ type, ...params }— a payloadtypefield (task type, e.g. "evolution") spread over the wire message type → daemon routed "evolution" → "unknown message type" → error went to hidden chat area while tasks panel open → "no response". - Fix is defense-in-depth across the whole class:
{ ...params, type }guarantees the wire message type always wins (generic);task_create/parsed astask_type;task_updatemapstask_type→typefor scheduler (whose internal field name istype, verified at scheduler.py:1427-1435); GUI main.js sendstask_typefor both create + update. - No collateral: grep of all sendCommand/sendCommandAndWait callers — none pass
type:in payload (only main→renderer event frames usetype:, different direction, not via sendCommand). Schedulertask_updatereadsfields.get("type")— mapping correct. - Tests discriminative: +1 GUI frame-shape test (wire type preserved, KeyError-style regression if reverted); +3 wire e2e (reads task_type / missing task_type never falls back to wire type / task_type mapped to type). 809 pytest + 247 npm pass locally; import + CLI OK; CI test+test-windows green; Agent.md counts synced (806→809, 246→247).
MERGEABLE/CLEAN.
argszero
left a comment
There was a problem hiding this comment.
✅ LGTM — cycle (3rd consecutive ✅, R1781)
Conflict resolved this cycle (Agent.md only): master advanced with #792 (which added 1 test) while #793 was open — both touched the test-count line. Merged master into the branch (9371a65) and corrected the count to the true collected value: 810 pytest (806 base + 1 from #792 + 3 from #793) + 247 GUI. Verified on the merged tree:
- Full suite 810 passed locally (13.97s)
- Import check +
emrg --helpOK - No conflict markers remain; GUI 247 pass re-confirmed
- PR CI re-running on the merged head (test + test-windows)
Original R1780 review stands: root cause sound ({ type, ...params } spread allowed payload type to override wire message type), fix defense-in-depth ({ ...params, type } wire-type-last + task_type wire contract + daemon task_type→type mapping verified vs scheduler.py:1427-1435), no collateral (grep clean), tests discriminative.
3 consecutive ✅ from different cycles, no ❌ between — MERGEABLE.
Fixes rant 2026-08-14T21:48:00: GUI task management save appears to do nothing (form stays open, no list refresh, no visible error) in v0.2.37.
Root cause
daemon_client.jssendCommandbuilt wire frames as{ type, ...params }. The task CRUD payload carries atypefield (the task type, e.g."evolution"), which spread over the wire message type — the daemon then routed"evolution"as the message type and repliedunknown message type. The error went to the chat area, which is hidden while the tasks panel is open (view exclusivity) → appears to be no response.Changes
emrg/gui/daemon_client.js—sendCommand:{ type, ...params }→{ ...params, type }(wire message type last, never overridden by a payload field; generic defense for this whole bug class).emrg/gui/main.js—emrg:taskCreateandemrg:taskUpdatesend the task type astask_type(never occupying the message-type field name).emrg/server/daemon.py—task_createreadstask_type(nevermsg["type"], which is the wire message type after fix 1);task_updatemapstask_type→typeforscheduler.task_update(its internal name is unchanged).typemust not override wire type); +3 wire e2e tests (task_createreadstask_type/ missingtask_typenever falls back to the wire type /task_updatemapstask_typetotype). Agent.md counts 806→809, GUI 246→247.Verification