The scheduler records an engine ranking in its last-emitted cache before the JSON-RPC notification write succeeds. If the write fails, normal reconciliation sees the same ranks as unchanged and suppresses a retry. scheduler:get-status also reports the failed update as delivered.
Reproduced on develop 20fc3db with the real Manager and JSON-RPC codec and a local io.ReadWriter that fails a frame before writing bytes. Restoring the writer and calling recomputeAll(false) leaves that engine with no delivered frame. A healthy second engine still receives its snapshot. Zero-byte writes have the same effect.
Only update the last-emitted snapshot and timestamp after Notify succeeds. Keep notification I/O outside the state mutex and preserve the existing recomputeMu serialization, per-engine independence, force-tick behavior and payload format. Local regression tests cover initial failure, retry, changed snapshots, and forced-refresh timestamps. No live engine or network is involved.
The scheduler records an engine ranking in its last-emitted cache before the JSON-RPC notification write succeeds. If the write fails, normal reconciliation sees the same ranks as unchanged and suppresses a retry. scheduler:get-status also reports the failed update as delivered.
Reproduced on develop 20fc3db with the real Manager and JSON-RPC codec and a local io.ReadWriter that fails a frame before writing bytes. Restoring the writer and calling recomputeAll(false) leaves that engine with no delivered frame. A healthy second engine still receives its snapshot. Zero-byte writes have the same effect.
Only update the last-emitted snapshot and timestamp after Notify succeeds. Keep notification I/O outside the state mutex and preserve the existing recomputeMu serialization, per-engine independence, force-tick behavior and payload format. Local regression tests cover initial failure, retry, changed snapshots, and forced-refresh timestamps. No live engine or network is involved.