Files
MeshTerm/tests/test_contact_score.py
T
Jean-Pierre MartineauandClaude Opus 5 92d31a3191 Every file is spelled the way the formatter spells it
`ruff format .` across the repo: 153 files, no behaviour change. This is the
second gate CONTRIBUTING.md promises, and until now it reported 154 files needing
reformat — so a first contributor ran the command the guide told them to run and
could not tell their own diff from the background.

Landed on its own, with nothing else in it, because a whole-repo reformat is only
safe to skip past in blame if it is provably nothing but layout. It was checked
that way rather than assumed: every changed file was formatted in memory and
compared by full `ast.dump()`, and 152 of 153 come out structurally identical
(the one exception was a docstring opening on a quote character, fixed in the
commit before this one). The string and comment token streams were diffed
separately, so a quote flip or an edited comment could not hide inside a
re-layout — five quote-style normalisations and sixteen implicit-concatenation
joins, all value-identical, and one commented-out line gaining the space after
its `#`. `meshterm specimen` is byte-identical on both platforms, and the suite
is 1888 green, gallery gate and `test_theme16` included.

What actually changed, in order of how much of the diff it is: wrapped calls and
signatures rejoin onto one line where they fit inside the hundred columns; the
magic trailing comma expands what it is there to expand; complex slices gain
their spaces (`[len(noise) :]`); a few redundant parens go. The tables that are
laid out to be read were fenced in the previous commit and are untouched here.

The aligned trailing-comment column is gone from about ninety lanes that were not
fenced — including the `heat.*` ladder in `MESH_THEME`, which cannot be fenced
where it sits. Every comment stays on the entry it describes, so nothing there
reads wrong; it just no longer lines up.

Add this commit to `.git-blame-ignore-revs`, which follows immediately.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 01:07:19 -04:00

337 lines
15 KiB
Python

"""Tests for rating contacts by how much they are worth a device slot (``core.contact_score``).
The scoring is pure — no device, no database, no screen — so these exercise the rules the
sweep's safety actually rests on: that an unknown signal is neutral rather than damning,
that an explicit choice outranks the arithmetic, that a newcomer is given time, and that
what a caller reads back is a percentile rather than a raw number.
"""
from __future__ import annotations
from meshterm.core.contact_score import (
PROTECT_ADMIN,
PROTECT_MESSAGED,
PROTECT_UNOBSERVED,
PROTECT_WATCHED,
ContactSignals,
percentile_rank,
protection_for,
rank_contacts,
sweep_candidates,
term_channel,
term_distance,
term_grace,
term_hops,
)
from meshterm.core.models import Contact
#: A contact whose evidence every test then varies one axis of.
_BASE = dict(heard_age_days=30.0, packets=10, known_days=200.0)
def _contact(name: str, *, lat=None, lon=None) -> Contact: # noqa: ANN001
"""A contact with a distinct key (so its hue and its node id differ from its neighbours')."""
byte = f"{(sum(map(ord, name)) % 256):02x}"
return Contact(name=name, public_key=byte * 32, key_prefix=byte * 6, lat=lat, lon=lon)
def _rank(*specs) -> list: # noqa: ANN001
"""Rank ``(name, signal-overrides)`` pairs, returning the scored contacts strongest first."""
contacts = [_contact(name) for name, _ in specs]
signals = {}
for contact, (_, overrides) in zip(contacts, specs, strict=True):
node = contact.public_key[:12]
signals[node] = ContactSignals(node=node, **{**_BASE, **overrides})
return rank_contacts(contacts, signals)
def _by_name(ranked) -> dict: # noqa: ANN001
"""The ranking keyed by contact name, for asserting on one row at a time."""
return {scored.contact.name: scored for scored in ranked}
def test_an_unknown_signal_scores_neutral_not_zero() -> None:
"""A contact that advertises no position lands mid-field on that axis, not at the bottom.
THE rule the whole sweep's fairness rests on. About half a real mesh advertises no
location at all, plenty of nodes are never overheard as a relayed packet so carry no hop
count, and a channel poster whose name matches no contact can't be attributed. If any of
those resolved to zero, every unmeasurable contact would sink together and the sweep
would be purging by how much metadata a node happens to broadcast.
"""
# Two contacts identical in every measured way; one is simply unplaced and unrouted.
ranked = _by_name(
_rank(
("Placed", {"hops": 2.0}),
("Unplaced", {"hops": None}),
# Two more placed contacts so the hop column has a median to fill from.
("Near", {"hops": 1.0}),
("Far", {"hops": 3.0}),
)
)
# The unmeasured contact sits exactly where the median of the measured ones puts it —
# between the near and the far, not beneath both.
assert ranked["Near"].score > ranked["Unplaced"].score > ranked["Far"].score
# And it is emphatically not at the bottom of the field.
assert ranked["Unplaced"].percentile > 0
def test_a_column_nobody_can_measure_changes_no_ordering() -> None:
"""When *no* contact can be scored on an axis, that axis shifts everyone equally.
The fill collapses to a flat 0.5, which is inert once weighted: it moves every score by
the same amount, so a signal the whole mesh is silent about can never reorder the field.
"""
ranked = _by_name(_rank(("A", {"packets": 40}), ("B", {"packets": 3})))
# Nobody carries hops, distance or channel attribution here, and the packet counts still
# decide it.
assert ranked["A"].score > ranked["B"].score
def test_an_unattributable_channel_name_reads_unknown_not_silent() -> None:
"""A contact whose channel posts can't be attributed is unmeasured, not proven quiet.
A channel frame carries no sender key — only a ``Name: `` prefix — so a name two
contacts share attributes to neither. That has to read as "we don't know", because
reading it as "posted nothing" would demote a node for a property of its *name*.
"""
unattributed = ContactSignals(node="a" * 12, channel_attributed=False, channel_posts=0)
silent = ContactSignals(node="b" * 12, channel_attributed=True, channel_posts=0)
from meshterm.core.contact_score import DEFAULT_WEIGHTS
assert term_channel(unattributed, DEFAULT_WEIGHTS) is None
assert term_channel(silent, DEFAULT_WEIGHTS) == 0.0
def test_distance_calibrates_against_this_mesh_rather_than_a_constant() -> None:
"""The distance midpoint is the population's own median, so it means the same everywhere.
50 km is far on a downtown mesh and unremarkable in a valley; a hardcoded threshold
would have to be wrong on one of them.
"""
near = ContactSignals(node="a" * 12, distance_km=5.0)
# On a tight mesh (median 5 km) a 5 km contact is average; on a sparse one (median
# 100 km) the same contact is *close*, and scores higher.
assert term_distance(near, 100.0) > term_distance(near, 5.0)
# Too few located contacts for a median to mean anything: the term goes unknown.
assert term_distance(near, None) is None
def test_a_newcomer_is_given_a_fortnight_to_earn_its_keep() -> None:
"""The grace bonus lifts a brand-new contact clear of the sweep, then fades to nothing.
Every other term rewards accumulated evidence, so a node first heard this morning is
arithmetically indistinguishable from one that has been quiet for a year — both have one
advert and no history.
"""
from meshterm.core.contact_score import DEFAULT_WEIGHTS as w
assert term_grace(ContactSignals(node="a" * 12, known_days=0.0), w) == w.grace
# Half-way through, half the bonus.
assert term_grace(ContactSignals(node="a" * 12, known_days=7.0), w) == w.grace / 2
# Past the window it is gone, and the contact competes on merit.
assert term_grace(ContactSignals(node="a" * 12, known_days=14.0), w) == 0.0
assert term_grace(ContactSignals(node="a" * 12, known_days=400.0), w) == 0.0
# End to end: a newcomer heard once outranks an equally thin contact known for months.
ranked = _by_name(
_rank(
("Newcomer", {"packets": 1, "heard_age_days": 0.1, "known_days": 1.0}),
("Stale", {"packets": 1, "heard_age_days": 0.1, "known_days": 300.0}),
)
)
assert ranked["Newcomer"].score > ranked["Stale"].score
def test_protections_outrank_the_arithmetic() -> None:
"""A star, a sent message, an admin login or an unheard contact is never a candidate.
A heuristic must not overrule an explicit choice, and it must not punish a contact for
MeshTerm's own ignorance.
"""
assert protection_for(ContactSignals(node="a" * 12, **_BASE, watched=True)) == PROTECT_WATCHED
assert protection_for(ContactSignals(node="a" * 12, **_BASE, dm_outbound=1)) == PROTECT_MESSAGED
assert protection_for(ContactSignals(node="a" * 12, **_BASE, has_admin=True)) == PROTECT_ADMIN
# No arrival time at all: the contact predates this history (or was added by hand), so
# every evidence term is empty for a reason that says nothing about the node.
assert protection_for(ContactSignals(node="a" * 12)) == PROTECT_UNOBSERVED
# Ordinary evidence, no claims: the score decides.
assert protection_for(ContactSignals(node="a" * 12, **_BASE)) is None
def test_inbound_messages_alone_do_not_protect() -> None:
"""Being messaged is not choosing to talk — anyone on the mesh can message you."""
inbound_only = ContactSignals(node="a" * 12, **_BASE, dm_total=20, dm_outbound=0)
assert protection_for(inbound_only) is None
def test_a_protected_contact_still_ranks_but_is_never_swept() -> None:
"""Protections are excluded from the victims, not from the population the rank is against.
A percentile that silently dropped them would not be a rank against *your contacts*.
"""
ranked = _rank(
("Strong", {"packets": 90, "heard_age_days": 0.1}),
("Starred", {"packets": 1, "heard_age_days": 500.0, "watched": True}),
("Weak", {"packets": 1, "heard_age_days": 500.0}),
("Weaker", {"packets": 0, "heard_age_days": 900.0}),
)
by_name = _by_name(ranked)
assert by_name["Starred"].protected
assert by_name["Starred"].percentile is not None # it is ranked like everyone else
# Keeping one unprotected contact sweeps the other two — never the starred one, however
# badly it scores.
victims = {v.contact.name for v in sweep_candidates(ranked, keep=1)}
assert "Starred" not in victims
assert victims == {"Weak", "Weaker"}
def test_a_protection_does_not_consume_a_kept_slot() -> None:
"""``keep`` counts unprotected contacts, so starring a node never deepens the next sweep.
Counting protections against the target would mean a star quietly cost some other
contact its place, which is the opposite of what a star is for.
"""
ranked = _rank(
("Starred", {"watched": True}),
("A", {"packets": 50}),
("B", {"packets": 20}),
("C", {"packets": 1}),
)
# Three sweepable contacts, keep two: exactly one goes, and the star is untouched.
victims = sweep_candidates(ranked, keep=2)
assert [v.contact.name for v in victims] == ["C"]
def test_victims_come_back_weakest_first() -> None:
"""The preview is read top-down, so the first rows are the least likely to be missed."""
ranked = _rank(
("Best", {"packets": 90}),
("Middle", {"packets": 20}),
("Worst", {"packets": 0, "heard_age_days": 900.0}),
)
assert [v.contact.name for v in sweep_candidates(ranked, keep=1)] == ["Worst", "Middle"]
def test_percentile_is_a_mid_rank_so_a_flat_field_reads_fifty() -> None:
"""Ties share their rank rather than all reading 0 or 100 — the standard definition."""
assert percentile_rank(5.0, [5.0, 5.0, 5.0]) == 50
assert percentile_rank(9.0, [1.0, 2.0, 9.0]) == 83
assert percentile_rank(1.0, [1.0, 2.0, 9.0]) == 17
assert percentile_rank(1.0, []) == 0
def test_direct_correspondence_is_the_heaviest_single_signal() -> None:
"""No other lane moves a score as far — a conversation took a decision on both ends.
Heaviest *single* lane, deliberately not heavier than two strong ones combined: a node
heard constantly and heard often is genuinely worth a slot, and one axis that could
overrule two others outright would be a weighting with a single point of failure.
Note what this comparison is really about. A contact you have *replied* to is protected
outright (:data:`~meshterm.core.contact_score.PROTECT_MESSAGED`) and never reaches the
arithmetic at all, so the DM term does its work on inbound-only history — someone who
messaged you and got no answer — which is exactly the case where it should count for a
lot but not for everything.
"""
quiet = {"packets": 2, "heard_age_days": 60.0}
ranked = _by_name(
_rank(
("Correspondent", {**quiet, "dm_total": 30, "dm_age_days": 20.0}),
("Chatty", {**quiet, "channel_attributed": True, "channel_posts": 100}),
("Near", {**quiet, "hops": 0.0}),
("Nobody", quiet),
)
)
# Against contacts alike in every other way, the conversation wins by the widest margin.
base = ranked["Nobody"].score
assert ranked["Correspondent"].score - base > ranked["Chatty"].score - base
assert ranked["Correspondent"].score - base > ranked["Near"].score - base
def test_no_single_signal_overrules_two_strong_ones() -> None:
"""A node heard constantly *and* heard often outranks one lane maxed out on its own.
The reason the score is a weighted sum with a bounded heaviest term rather than a
ranking with a dominant key: a contact that is genuinely present on the mesh should not
be swept because it never sent a direct message.
"""
ranked = _by_name(
_rank(
("Present", {"packets": 100, "heard_age_days": 0.1, "dm_total": 0}),
("Inbox", {"packets": 2, "heard_age_days": 60.0, "dm_total": 30, "dm_age_days": 20.0}),
)
)
assert ranked["Present"].score > ranked["Inbox"].score
def test_a_quiet_conversation_keeps_most_of_its_worth() -> None:
"""Correspondence ages far more slowly than adverts: it is a relationship, not an event."""
ranked = _by_name(
_rank(
("Recent", {"dm_total": 10, "dm_age_days": 1.0}),
("Lapsed", {"dm_total": 10, "dm_age_days": 120.0}),
("Never", {"dm_total": 0}),
)
)
assert ranked["Recent"].score > ranked["Lapsed"].score
# …but the lapsed conversation is still worth far more than none at all.
gap_to_recent = ranked["Recent"].score - ranked["Lapsed"].score
gap_to_never = ranked["Lapsed"].score - ranked["Never"].score
assert gap_to_never > gap_to_recent
def test_fewer_hops_ranks_higher() -> None:
"""Topological closeness, hyperbolic: zero-to-one matters, four-to-five barely does."""
from meshterm.core.contact_score import DEFAULT_WEIGHTS as w
direct = term_hops(ContactSignals(node="a" * 12, hops=0.0), w)
one = term_hops(ContactSignals(node="a" * 12, hops=1.0), w)
four = term_hops(ContactSignals(node="a" * 12, hops=4.0), w)
five = term_hops(ContactSignals(node="a" * 12, hops=5.0), w)
assert direct == 1.0
assert direct - one > four - five
def test_ranking_an_empty_table_is_empty_not_an_error() -> None:
"""A device with no contacts has nothing to rank — the sweep's own guard reads this."""
assert rank_contacts([], {}) == []
def test_a_contact_with_no_signals_at_all_is_protected() -> None:
"""A contact the history has never met is protected rather than swept as worthless."""
contact = _contact("Inherited")
ranked = rank_contacts([contact], {})
assert ranked[0].protection == PROTECT_UNOBSERVED
def test_reasons_name_the_weakest_lanes_in_plain_words() -> None:
"""Each preview row explains itself without the reader having to know the formula."""
ranked = _rank(("Quiet", {"packets": 3, "heard_age_days": 240.0, "dm_total": 0}))
reasons = ranked[0].reasons
assert "never messaged" in reasons
assert "3 pkts" in reasons
# The age reads in the fewest words that are still true — months, here.
assert any(r.endswith("mo") for r in reasons)
def test_a_stronger_contact_never_scores_below_a_weaker_one_on_every_axis() -> None:
"""Sanity: dominance is preserved — better everywhere means ranked above."""
ranked = _by_name(
_rank(
(
"Better",
{
"packets": 50,
"heard_age_days": 1.0,
"dm_total": 5,
"dm_age_days": 1.0,
"hops": 1.0,
},
),
("Worse", {"packets": 2, "heard_age_days": 300.0, "dm_total": 0, "hops": 4.0}),
)
)
assert ranked["Better"].score > ranked["Worse"].score
assert ranked["Better"].percentile > ranked["Worse"].percentile