fix(server): COALESCE diagnostic columns so v1.0 heartbeats don't clear v1.1 data

store_heartbeat_diagnostics() unconditionally SET each diagnostic column
to its parameter, so a v1.0.0 heartbeat (which omits the five v1.1.0
fields and leaves them as None after Pydantic parsing) erased previously
stored diagnostics for that device. Wrap each parameter in
COALESCE(?, column_name) so omitted fields preserve the existing value.

Found via adversarial review (gpt-5.5 reviewer, run 2026-05-01-191359).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-01 13:19:23 -07:00
parent 2226c1b4ca
commit e2dbe6a2d5

View File

@@ -70,13 +70,15 @@ def store_heartbeat_diagnostics(
else None else None
) )
cursor = db.cursor() cursor = db.cursor()
# COALESCE preserves existing column values when the v1.0.0 payload omits
# diagnostic fields (Pydantic resolves them to None).
cursor.execute( cursor.execute(
"""UPDATE heartbeats """UPDATE heartbeats
SET reset_reason = ?, SET reset_reason = COALESCE(?, reset_reason),
heap_free = ?, heap_free = COALESCE(?, heap_free),
heap_min_free = ?, heap_min_free = COALESCE(?, heap_min_free),
last_disconnect_code = ?, last_disconnect_code = COALESCE(?, last_disconnect_code),
recent_events = ? recent_events = COALESCE(?, recent_events)
WHERE device_id = ?""", WHERE device_id = ?""",
( (
hb.reset_reason, hb.reset_reason,