Skip to main content

Module pair_proof

Module pair_proof 

Source
Expand description

The WFB pair-proof record: per-key evidence that a radio key has ever actually carried a link.

§Why this exists

Auto-pair used to decide “am I already paired?” by looking at the shape of the key file — 64 bytes with a fingerprintable peer-public half. That is a FILE check, not a LINK check, and a key left behind by a ground station that was since reflashed is a perfectly well-formed key. Two rigs sat unlinked for an entire session on exactly that: the drone injected into a void holding a structurally valid key from a peer that no longer existed, its own radio reporting rf_unverified (transmitting, zero confirmed reception), while auto-pair stayed permanently disarmed because the file looked fine.

§The rule this record encodes

Auto-pair may re-arm itself ONLY for a key whose fingerprint has NEVER ONCE been confirmed to work. The fingerprint is the lifetime key:

  • A stale key from a reflashed peer re-arms, because its fingerprint never entered the proof record — the peer that would have proven it is gone.
  • A healthy link NEVER re-arms. Once a fingerprint is latched as proven, no amount of downtime re-arms it, so a transient (or multi-day) RF dropout is structurally incapable of triggering a re-bind. Silently re-binding a proven pair would be a worse failure than the deadlock this fixes.
  • A fingerprint mismatch is a FULL reset, so a successful re-bind hands the new key a clean lifetime automatically.

Deciding to OPEN a bind window is all this governs. Whether a bind may then DECLARE a pair is unchanged: the orchestrator’s peer-evidence gate remains the sole authority on success.

§Where it lives

/var/lib, deliberately — NOT /run. On tmpfs a reboot would erase the episode budget and the cooldown, and a rig stuck in a boot loop would reintroduce the bind storm the budget exists to bound.

Two processes write it: the supervisor’s re-arm reconciler (every episode) and the operator force escape hatch on the auto-pair route. The record type and its one atomic writer therefore live here, beside the other sidecar records, rather than in either writer’s own crate.

Structs§

LoadedProof
The result of loading a record for a given role + key.
PairProof
The per-key proof record.

Enums§

ProofStamp
What a mark_proven call did, so the caller knows whether a write is owed and whether this was the first-ever proof for the key (worth an event).

Constants§

AUTO_PAIR_RETRY_PATH
The operator’s “retry the local link” request, consumed by the supervisor’s auto-pair loop.
PAIR_PROOF_MODE
File mode. World-readable so a diagnostic can show the latch state without root; only root writes it.
PAIR_PROOF_PATH
The pair-proof record path. Persistent by design — see the module docs.
PAIR_PROOF_SIDECAR_VERSION
The record schema version, stamped on write and checked (warn-only) on read.
PROOF_RESTAMP_INTERVAL_S
How often proven_at may be re-stamped while the key stays proven. The latch only needs the boolean, so the timestamp is a courtesy for an operator reading the file — and this is a flash card, so it is refreshed at most hourly rather than on every tick.

Functions§

load_for
Load the record for role + fingerprint, resetting on any mismatch.
read_pair_proof_from
Read + parse the record at path. None when absent or unparseable — both of which the caller must treat as never-proven with a zero budget, failing toward recoverability rather than crashing the loop.
request_local_retry_at
Record a local-retry request at path (the content is informational; the file’s presence is the request).
take_local_retry_request_at
Consume a pending local-retry request at path. true exactly once per request: the removal is the acknowledgement, so two ticks cannot both act on one request. An unreadable directory reads as no request.
write_pair_proof_to
Atomically write proof to path through crate::sidecar::write_atomic: unique temp sibling, explicit mode, fsync, rename, directory fsync. The fsync is the point — this record is the only thing bounding a bind storm across a reboot, so it must survive a power cut mid-write.