Specification §2
Five statements that hold across every other section. The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are to be interpreted as described in RFC 2119.
FrogNet Specification — Draft 0.9, revision 2026-08-29. Cite a conformance claim against this revision, not against a section number alone.
Five invariants hold across every other section of this specification. They are not properties of the current implementation that a later one might improve upon; they are the contract. An implementation that relaxes any of them is a different system, and claims made about FrogNet do not transfer to it.
A connected pond MUST hold exactly one authoritative copy of each tuple, at the elected database host. No other node holds authority over a value.
Every node runs a database, and that is not a copy of the store. The local database holds the semantic layer's templates and per-peer references on every node, always; it holds the tuple space only on whichever node is currently the elected host (§11.14). A reader who sees a database per node and concludes that the memory is replicated has conflated the two roles, which is the single most common misreading of this architecture.
The invariant is about authority, not about location. A derivative copy — a materialization, a read cache — is permitted where its agreement with the store is either proven on the request or bounded and declared (§2.2), and it can never become authority. An implementation MUST NOT let a derivative answer become the value of record.
Consequence. Every reasoning pattern that begins "when the copies diverge" is inapplicable. There is never a field of candidate values to arbitrate between, so there is no authority rule, no conflict-resolution algorithm, no CRDT, no vector clock, no tombstone, no per-type merge law, and no causal history. The question "who decides when two values exist under one description" presupposes two values; a description holds a value.
What this does and does not forbid. It forbids a second authoritative copy. It does not forbid answering a read from RAM, and the reference implementation does so in two places. The line is standing: local state may answer a read only where its agreement with the store is either proven on that request, or bounded and declared.
| Permitted because | Mechanism |
|---|---|
| Proven equal on this request | The database host MAY serve a RAM materialization when a store-maintained generation counter shows it unchanged. The counter MUST be moved by database triggers so that every writer — another node, the local origin, a human at the prompt — moves it. The snapshot and the counter MUST be read in one consistent transaction. Where the counter or its triggers are absent the cache MUST disable itself for the life of the process. Fail closed. |
| Bounded and declared | A node MAY cache its own forwarded reads, invalidated by writes it observes and backstopped by a short TTL. This is bounded-stale current state, which is what a read returns in any case (§9.4). The freshness bound is evaluated by the store, on the clock that stamped the row; a reader MUST NOT judge staleness against its own clock (§9.4, §13.3). |
Violation signature. RAM answering a question it has no standing to answer. Two forms, both of which have occurred: a snapshot loaded once and never revalidated, so writes by any other route are invisible; and a cache that returns an empty result set as an authoritative answer because the query carried a parameter it could not express. An uncached node is slow. A node serving from a snapshot it cannot prove current is wrong, and wrong is not a performance trade-off.
Writes MUST be ordered at a single point, at the database host. Last write wins in arrival order at that point.
Consequence. The order is total and requires no agreement to establish, because it is the order of arrival at one place. This is the property that removes consensus from the design rather than solving it cheaply. It is also, exactly and inseparably, the write-throughput ceiling (§17.3): the coherence guarantee and the scaling limit are one fact stated twice.
The guarantee covers the write only. An application that reads a value and derives the next one from it has constructed a read-modify-write cycle and owns its races (§9.3).
An implementation MUST NOT replicate tuples, retain history, or perform any merge procedure. Nothing replicates on write; nothing ferries in the background; nothing merges on rejoin.
Consequence on partition. Each fragment elects its own host and has its own store. On reunion nothing is merged, nothing migrates, and no value travels. Values last written elsewhere remain observable until they age past the freshness window — which the store evaluates on the clock that stamped the row, never the reader on its own clock (§9.4, §13.3) — at which point they cease to be observable rather than becoming wrong (§6, §13).
Consequence on consistency. FrogNet is not eventually consistent and does not converge. A value is current or it is not. An implementation MUST NOT describe its behaviour as convergence; the word is reserved in this specification for discovery reaching a stable derived topology (§6.7).
The store holds current state, not history. State is time-ordered, idempotent under repetition, and forgiving of loss. For data of that shape a consensus round over a marginal link is not merely expensive but wrong, because what it agrees on is already stale.
Each node MUST derive topology independently from its own local observation. No controller distributes a view, and no node accepts a topology asserted by another.
Consequence. There is no coordinator to lose. A gossip layer exists (§4) and carries change notifications so that neighbours re-derive sooner; it never carries a derived view and never carries a tuple value. The tell is what a wave carries.
The same principle governs roles: every node publishes what only it can know, every node scores the same inputs with the same function, and all arrive at the same winner independently (§8). No vote is exchanged and no announcement is made.
An application MUST be able to publish state without identifying any consumer, and to read it without identifying any producer. Neither operation may be made contingent on the liveness, reachability, or prior registration of another participant.
Consequence. A reader observes values written before it started, and a value outlives its writer where the writer declared it unowned. Lifetime is a property the writer states (§10.3): an owned tuple is ephemeral coordination state and is reaped when its process exits; an unowned one persists and ages out. What is invariant is not persistence but independence — neither operation may be made contingent on the liveness, reachability, or prior registration of another participant.
This is what makes an offline node a whole network rather than a degraded participant, and it is why nothing in the system needs a delivery guarantee: nothing is delivered.
Each of the following is a category FrogNet is regularly read as, and none is a near miss.
| Not | Because |
|---|---|
| A distributed database | One store, no distribution of data (a) |
| A message broker, queue, or pub/sub | Nothing is delivered: no topic, no subscription, no consumer registry, and no notification when a value changes (e, §9.4). A node publishing its own state into the store is a write, not a publication in this sense. |
| Eventually consistent storage | No convergence; a value is current or it is not (c) |
| A mesh VPN | The tunnels are a bearer beneath the model, not the model (§7) |
| A cache | BLDC-1 re-executes against the origin and reports identity; it never answers from a stored copy (§11) |
| A compression product | The saving is structural, not statistical; no ratio is claimed for the codec itself (§11, §14) |
| New | Linda, Gelernter and Carriero, Yale, 1985. What is new is that the constraints which made it impractical are gone. |
Specification §9, §10, §6, §13, §17. Build manual: Croakus §18, §25.