Files
MeshTerm/meshterm/persistence
Jean-Pierre MartineauandClaude Opus 5 81e58803ee Heard: our own ears outrank the sender's clock
A contact's heard time came straight from the firmware's last_advert,
which the advertising node stamps with its own clock. That makes it
hearsay, and advert_time can only refuse a stamp from the future — a
node whose RTC runs days behind reports a plausible-looking time that
never catches up, so the lane sits at "4d ago" while we are receiving
from it right now. Our own history, stamped when we actually received
something, could only fill the gap when the device reported nothing at
all.

So merge instead of fill: take the later of the device's time and ours.
A device time still wins whenever the firmware caught an advert we never
recorded, and we only override it with proof of a later reception.

A direct message now counts too. In this app's lexicon "heard" means
received from, and a message is received from its sender — but a DM
never touches last_advert and is stored as a message, not an
observation, so a node we chat with daily could read stale and be swept
by the purge ladder's quiet rungs while talking to us. Read from the
messages table rather than recording an observation: a routed message's
SNR belongs to its last relay, which is why heard_nodes excludes packet
rows, and counting it would inflate a lane that means overheard traffic.

The merge runs on every contacts fetch now, so both halves are GROUP BY
queries that aggregate in SQLite and yield one row per node, instead of
heard_nodes streaming all history into Python to build stat objects.

Node detail takes the merged contact time, so it and the contact list
can no longer disagree about one node.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 03:49:46 -04:00
..