The Propagation Model
What actually happens to a fact between injection and belief. The graph here has 1 s edge latency, 0.7 edge fidelity, and a deterministic seed.
Hops are scheduled events
Injection records the origin's belief immediately, then schedules one hop
per outgoing edge at now + latency_seconds. A background scheduler
(every RUMOR_SCHEDULER_TICK_MS, 1 s by default) delivers hops as they
come due; each delivery records a belief at the receiving node and
schedules that node's own outgoing hops in turn, up to RUMOR_MAX_HOPS
(32) from the origin. There is no global tick - a rumor crossing a
three-day edge simply surfaces three days later.
snug rumor tick <graph> drains due hops on demand and reports
hops_processed / beliefs_recorded / hops_scheduled. With the
scheduler running it usually finds nothing; it exists for deployments that
disable the scheduler and for deterministic tests.
Fidelity decay and distortion
Each hop carries a fidelity: the product of every edge fidelity along its
path. With 0.7 edges, the first hop arrives at 0.7 and the second at 0.49.
While carried fidelity stays at or above 0.6 the payload is copied
verbatim; below that threshold it mutates. The origin
injected {"claim": "the king is wounded", "severity": 2}, one hop out
the innkeeper held it intact at 0.7, and two hops out the guard held
{"claim": "the king is slain"} at 0.49.
Mutation is a built-in table applied to an object payload's claim
(string) and severity (integer, clamped 0-5) fields; payloads without
those fields pass through unchanged even below the threshold. The table
does case-insensitive substring replacement - wounded becomes slain,
ill becomes dying, delayed becomes lost, seen becomes
vanished, missing becomes dead, rumored becomes confirmed - and
a claim matching none of these gets an allegedly prefix or a
(distorted) suffix. Substring matching is literal: a claim about "the
mill" mutated to "the mdying" in live testing, because mill contains
ill. severity drifts upward on roughly half of mutating hops.
The graph's distortion config accepts a table_id and an
arbiter_paraphrase mode, but the current engine always applies the
built-in table; treat those fields as reserved.
Deterministic mode
Creating a graph with --seed enables seeded mode: every mutation draw is
keyed to the seed plus the fact id, sending node, receiving node, and hop
number. Replaying the same injection over the same topology reproduces
byte-identical distortion, which is what makes spread experiments and QA
comparisons meaningful. Without a seed, draws are keyed to the clock.
Confidence and trust
A belief's confidence is its carried fidelity times the receiving node's
trust in the network. Nodes without a trust_source trust fully (1.0), so
by default confidence equals fidelity - the 0.49-fidelity guard belief
above arrived with confidence 0.49. A node created with a trust_source
of the form {"reputation_index": "domain:kind:id"} instead looks up that
Reputation score at delivery time and maps it linearly (score -100 to
+100 onto trust 0.0 to 1.0, with 0.5 when the score is unavailable). See
Reputation.
Saturation and cycle blocking
A rumor never echoes. A hop is dropped when its receiver already knows the
fact, and a node never fans out toward any node already on the hop's
provenance path. Verified on a diamond graph (a to b and c, both to
d): d ended up with exactly one belief, one provenance path
(["a", "b", "d"]), and an unreinforced confidence of 0.49 - the second
delivery via c was discarded. Repeat deliveries do not boost confidence
or extend memory; only corrections punch through.
Forgetting
Every belief expires default_ttl_seconds (7 days by default) after it
arrives, per the graph's forgetting config. Expiry is enforced lazily:
reads purge expired entries, so beliefs, trace, and prevalence counts
only ever reflect live memory. There is no resurrection - once forgotten,
a node treats a re-arriving rumor as news.
Corrections
A correction re-seeds an existing fact_id from an origin node and chases
it through the same edges at the same speed. It differs from a plain
rumor in three ways:
- It never mutates - every node receives the corrected payload verbatim, regardless of fidelity.
- It overwrites - a node already holding the rumor keeps its provenance
and
fidelity_remainingbut takes the correctedform, is markedcorrected: true, gets a fresh expiry (whenreinforcement_extendsis on, the default), and gains confidence (the guard's 0.49 rose to 0.735). - It counts separately -
traceprevalence moves nodes fromtrue_formordistortedintocorrected, and the correction response reports theoriginal_footprintit must cover.
A correction follows edges, so it only reaches nodes reachable from its origin; seed it from a well-connected node or the rumor's own origin.
Quarantine
Quarantining a node makes it inert on the receiving side: incoming hops are consumed and dropped - no belief, no onward fanout, and no replay after release. Its existing beliefs are untouched and it can still be read. Quarantining a high-traffic hub is the built-in way to cut a spread off mid-flight before a correction lands.