The complete byte-level reference: anchor layout, packet types, dispatcher rules, both consensus protocols, fragment routing, the governance pipeline, and the full threat model.
New to PHEUN? Start with the whitepaper — a shorter, self-contained paper covering the problem, the mechanism and the mathematics. This document is what you read to implement or audit the protocol.
This specification is a living document and will change. It describes the implementation as it stands on the date above, down to byte offsets and packet codes, so it moves whenever the code moves — implement against the newest revision, not a saved copy. The whitepaper is the stable document: it states the architecture and the reasoning, names no packet codes or version numbers, and is not expected to change.
A purely peer-to-peer system would let humans publish, communicate, and govern without intermediaries — without companies that can suspend accounts, governments that can compel disclosure, advertisers that can financialise attention, or moderators that can rewrite history. Existing decentralised systems either reduce to a single global chain (sequencing bottleneck, ~10⁴ writes per second ceiling), depend on a privileged validator set (a rebranded admin), or sacrifice security to scale (variable-format payloads, classical cryptography vulnerable to quantum attack).
We propose an alternative. The Peace and Harmony Earth United Network — PHEUN — is an anchor-stream of immutable 512-byte records distributed across 4,096 payload-addressed AnchorStream Index buckets, with consensus reached not through a global ordering but through deterministic byte placement, NIST post-quantum cryptography (ML-DSA-65, ML-KEM-1024, AES-256-GCM, BLAKE3), and a self-verifying propagation check at every anchor's birth (each receiver re-runs the author's own proof). Identity is regenerated at login from nine personal inputs the human alone holds. Every citizen runs one node; the node IS the user; the user IS the server. There is no token, no fee, no admin, no kill-switch, no global delete operation.
Sybil resistance is provided by the storage curve, not by stake or proof-of-work. Per-anchor admission is self-verifying: every receiver re-runs the author's signature and matches the carried genesis against the canonical one at ASI(GUIDE), so a forged or impostor anchor dies at every hop. Privacy-sensitive packet classes are wrapped in a 3-hop ML-KEM-1024 onion. Governance is universal and DOC-scoped: any document — including the network's own Constitution — uses the same proposal/vote/consensus pipeline at a 75 % threshold. Protocol evolution is soft-fork-only by design: the wire format never changes, but new schemas, new packet types, and new algorithm selectors ride additively through a published extension lane.
Centralised platforms now mediate almost all of human communication, publication, payment, and political organisation. The platform decides which posts are visible, which accounts exist, which transactions clear, which speech is illegal, and which words may be typed.
Decentralised alternatives have, by and large, repeated the same architecture under a new logo. A blockchain with a sequencing committee is still a sequencing committee. A fediverse with admins is still a federation of admins. Even peer-to-peer storage protocols typically presume a separate identity layer, a separate payment layer, a separate moderation layer — and each of those layers re-introduces a privileged actor.
The thesis of this paper is that a different architecture is possible. One in which the protocol contains no privileged actor; the wire format is byte-frozen and never changes between governance cycles; identity is generated locally from inputs the human alone holds; consensus is a property of deterministic placement combined with a self-verifying check every receiver runs at the moment each record is born. Combined with NIST-standardised post-quantum primitives in fail-closed cryptographic paths, the result is a network in which:
PHEUN is not a payment system, although it can host barter; it is not an anonymity network, although it onion-routes its sensitive packets; it is not a blockchain, although it is an immutable signed ledger. It is the substrate on which all of those services can be expressed without re-introducing a privileged operator. Where Bitcoin replaced the central bank with proof-of-work and Tor replaced the trusted ISP with onion routing, PHEUN replaces the centralised internet substrate itself with a single deterministic mesh.
The architectural soul of PHEUN, and the single non-negotiable invariant that every other design choice in this paper preserves, is the equivalence: one human user equals one Guide ID equals one Node ID equals one server equals one profile equals one Guide login equals one device equals one codebase instance. This is not a relation. It is a hard equality across every clause.
Every citizen of Earth who joins the network runs their own full node on their own device, and the node is the user. The user is the server. There is no scenario in which N users use node X. There is no hosting tier, no operator class, no lite-client downgrade path, no shared instance that any citizen would log into. "Concurrent viewers" on a node means the same human with multiple browser tabs open on the same machine running the same node — never two different people.
The only multi-user interaction in PHEUN is node-to-node: peer Alice's node talking to peer Bob's node. Per-node load equals per-user load. Per-node metrics are per-user metrics. Per-node subscriptions are per-user subscriptions. The 1:1:1:1 invariant has six immediate consequences:
The invariant is enforced at multiple layers: a node-owner lock file binds the device to exactly one Guide ID at first login; the vault, session, notification, and PAC tables are all keyed by a single Guide ID with no tenant column; WebSocket browser tabs share one connection set associated with one Guide ID; ML-DSA-65 signatures bind every anchor to one signing keypair derivable only from one citizen's nine personal inputs.
Identity in PHEUN is regenerated locally from nine personal inputs the human alone holds. The server stores the public key and a BLAKE3 fingerprint of it (so a restarted node can resume identity verification); the private key never leaves the device; the keypair itself is recreated from the inputs at every login and zeroed from memory immediately after the session is signed.
The nine inputs are facts the citizen knows in combination — not in isolation. They are typed at first registration and remembered (or, with explicit acceptance of the recovery risk, recorded) by the human alone: a personal date; a random date the app rolls; keyword; phrases 1, 2, and 3; a memory word; a 4-digit code; and the chosen Guide ID handle itself. The combination matters. Any single input may be guessable from public sources or social engineering; the conjunction of all nine is intended to require either the citizen's full participation or a brute-force search large enough to be economically unattractive. That conjunction is only as large as the citizen's weakest answers, and KEYHASH (BLAKE3 of the public key) rides every anchor, so a guess is checked offline where no rate limit reaches it. Profile creation therefore enforces a floor in the browser, the only place the inputs exist — and that floor is the TOTAL, not the shape of any one answer: every input must be guessed in the same attempt, so a weak answer beside strong ones is scored for what it is worth rather than refused. What creation does require is the shape the derivation needs (letters, four digits, four distinct keys, none equal to the public Guide ID) and an estimated guessing entropy above a fixed target. A typed date counts zero toward that estimate, because a date someone chooses is the input most open to research; a rolled one is credited its full 18 bits, since the roll is uniform across a thousand years and the app watched it happen. Login runs no such check — an identity minted under earlier rules must still be able to sign in.
The nine-input scheme is self-sovereign in the strict sense: the protocol does not store any of these inputs, the network never sees them, and the citizen's recovery path is to re-enter them. There is no email, no SMS code, no recovery question, no key-file. Loss of all nine inputs is loss of the identity, and PHEUN has no path to recover it. This is by design.
The nine inputs feed a deterministic key derivation pipeline. The first input is the 16-character Guide ID itself — a handle the citizen chooses, not a hash of anything. Each answer is folded to one canonical form (Unicode NFKC, trimmed, lowercased), and the answers are concatenated in a canonical order with a domain-separating prefix per field. The concatenation is stretched with Argon2id — memory-hard, parameters frozen at launch in SEED_DERIVATION — salted by BLAKE3 over a fixed context and the Guide ID, to a 32-byte seed. The seed is the input to ML-DSA-65 KeyGen, which is deterministic for a fixed seed: the same nine answers always produce the same keypair on any device.
The stretching is deliberately expensive — a few seconds and 64 MiB per derivation — because KEYHASH rides every anchor forever, so an attacker tests guesses offline against bytes they already hold and the login lockout never sees them. A citizen pays that cost once per login; a brute-force attacker pays it for every single guess. Argon2id is a hash-based function, so like BLAKE3 it faces only Grover's square-root speed-up from a quantum computer, and its memory-hardness makes it a poor fit for quantum hardware besides.
The first anchor any Guide ID ever signs is its Genesis Profile (category byte 0x01, type byte 0x01). The Genesis Profile binds the Guide ID to the public key by carrying the public key's BLAKE3 fingerprint in the KEYHASH field of the 512-byte record (bytes 65–96). Every subsequent anchor signed by this Guide ID is verified against this single source of truth. SVAP enforces uniqueness at admission: the home holders at ASI(GUIDE) reject any second genesis for a Guide ID already claimed (first-claim-wins).
At every login the citizen retypes the nine inputs into the local browser. The browser regenerates the seed and the keypair, asks the local node for a single-use challenge, and signs it — the only signature the browser ever makes. The local server spends the challenge and verifies that signature under the supplied public key, computes BLAKE3 of the supplied public key in constant time and compares it to the on-chain Genesis Profile's KEYHASH, and walks the citizen's AnchorChain (§14) for fork detection. If all three checks pass, the server issues a session token — secured by HTTPS and instant revocation on logout rather than pinned to the requesting IP, so a mobile or CGNAT citizen whose carrier rotates its public IP is not logged out mid-session — and the keypair is zeroed from browser memory. The session lasts the node's process lifetime — there is no timed auto-logout, so a logged-in node stays a full LIVE anchor-holding participant for as long as it runs. A session ends only on process restart (which forces a fresh login: the ML-DSA-65 private key is RAM-only and gone on restart, per Vision principle 21), explicit logout (which closes that browser's session; the node keeps its key and stays LIVE until its process stops), or a PAC fork-lock. A non-blocking modal reminds the citizen every 30 days to confirm they still remember their nine (irrecoverable) keys — a reminder, never a logout.
The deterministic derivation property — same inputs, same keypair — has a deliberate consequence: the citizen can log in from any device by re-entering the nine inputs. There is no "device pairing" step, no QR-code handoff, no key export. This creates a self-forking risk: if the citizen logs in concurrently from two devices and publishes an anchor from each, both devices may sign distinct anchors at the same PAC_COUNT. PHEUN ships three layers of defence — login-time educational modal, login walk plus self-subscription, and local mint hook (full detail in §14). A locked Guide ID is dead by design; the citizen creates a new Guide ID, the sealed history of the old one stays readable forever.
PHEUN's content model has exactly two layers, and the boundary between them is enforced everywhere — in storage, in routing, in cryptography, and in propagation. Layer 1 is the anchor: a public, permanent, signed, 512-byte record that names a piece of content. Layer 2 is the payload: the actual content the anchor names, encrypted, fragmented, and distributed across the mesh by content-addressed routing. Anchors are ASI-routed (§6); payloads are XOR-DHT-routed (§13).
Private conversation is the deliberate exception. Because anchors are public by construction, direct messages and calls are not anchors and never enter the AnchorStream — they are end-to-end encrypted peer-to-peer traffic with store-and-forward delivery, held in each participant's own local message store, sealed at rest under a key only that participant's login yields. Minting an anchor per message would place a permanent, undeletable, publicly-visible record of who spoke to whom and when into a ledger with no delete operation — a metadata disclosure far worse than anything payload encryption prevents. What a citizen publishes is permanent; what they say privately is not.
The anchor is the atomic ledger record. Every action a citizen publishes — update, reply, governance vote, economy offer, document amendment, subscription change, share — is born as exactly one 512-byte anchor. Anchors are public by construction. They are the ledger. There is no anchor encryption. There is no private anchor. Every anchor that any citizen ever signs is, the moment it is admitted to the network, available to every other citizen to read, mirror, query, cite, and subscribe to. This is the price of an open permissionless ledger and PHEUN owns it explicitly: the protocol provides no filter, no takedown, no flag, no allow-list, no admin, no moderator, and no global delete.
The payload is the actual content of an action — the body of an update, the audio of a voice memo, the bytes of a film, the source of a wiki article, the text of a direct message, the photographs of a catalog item. PHEUN supports payloads up to 10 GB per anchor, which covers the great majority of human content including full-length films at distribution-quality bitrates.
Payloads are not stored inside the anchor. They are AES-256-GCM authenticated-encrypted with a key derived per anchor from BLAKE3(CORE ‖ SIGHASH ‖ PAC), split into sacred-math-sized fragments, and distributed across the mesh by PayloadWeave (§13), a Kademlia-style XOR-DHT keyed by the anchor's CORE. Every fragment of one anchor lives in the same XOR neighborhood (K_NEIGHBORHOOD = FLOOR × totalFragments closest peers to CORE, author excluded); each peer holds exactly one fragment, assigned by XOR rank — the r-th closest peer holds index (r mod totalFragments), a coverage-complete rule that guarantees no index is orphaned (§13.1). A 1000-fragment film therefore scatters across thousands of unique peer-slots, with mobile-class nodes typically holding zero or one fragment of any specific anchor where they fall in the neighborhood, never the whole film.
The CORE hash binds both layers. CORE is computed as BLAKE3 over the concatenation of (the manifest section bytes ‖ the payload bytes), with the signature slot excluded. The manifest section carries the payload's metadata — payload count, MIME types, file names, sizes, the embedded public key — and the fragment manifest. Tampering with any payload byte breaks CORE; tampering with any manifest field breaks CORE; tampering with the embedded public key breaks CORE. Any of these tamperings invalidates the anchor's ML-DSA-65 signature, which every receiver re-verifies at admission.
The two-layer model gives PHEUN three properties that single-layer ledgers cannot have at the same time. Routability with arbitrarily large content: the anchor stream stays small (512 bytes per record), so every node can hold its share of the ledger and every query is cheap. Encrypted-by-default content with public-by-construction metadata: the anchor is public; the payload is encrypted. A peer that holds a fragment can verify its integrity but cannot read its plaintext without the anchor. Right-to-erasure compliance without anchor rewrite: GDPR-style erasure is satisfied by destroying the AES key derived from the citizen's anchor — the encrypted fragments on the mesh become unreadable forever, even though the ciphertext continues to exist. The anchor itself stays on the chain (Vision §20: anchors are permanent); the payload is forgotten by erasing the key.
The atomic unit of the anchor stream is a fixed-size 512-byte record. Every action on PHEUN — across all categories and types — is one of these. The byte layout is byte-frozen for the lifetime of the V1 protocol and never changes between governance cycles. The wire-form representation is the 1,024-character lowercase hex encoding of the buffer.
| Block | Range | Bytes | Concept |
|---|---|---|---|
| 1 | 0–124 | 125 | Cryptographic Identity |
| 2 | 125–232 | 108 | Chain and Stream |
| 3 | 233–240 | 8 | AnchorStream Index Routing |
| 4 | 241–270 | 30 | Content Classification |
| 5 | 271–285 | 15 | Consensus Governance |
| 6 | 286–296 | 11 | Mesh and Payload |
| 7 | 297–445 | 149 | Social Discovery and Avatar |
| 8 | 446–511 | 66 | Soft-Fork Lane |
| Range | Field | L | Description |
|---|---|---|---|
| 0–31 | CORE | 32 | BLAKE3("PHEUN-CORE-V1" ‖ GUIDE ‖ PAC_COUNT ‖ KEYHASH ‖ BODY), BODY = BLAKE3(manifest section ‖ payload bytes), excluding the signature slot. The anchor's identity hash and primary key, checkable as its author's by anyone holding BODY. |
| 32–63 | SIGHASH | 32 | BLAKE3 of the full ML-DSA-65 signature — the immutable ledger's only binding to that 3,309-byte signature, which is far too large for the anchor and lives in the payload's signature slot instead. checkSignature enforces BLAKE3(sig) == SIGHASH before the payload opens. It is also an input to the payload key, BLAKE3(CORE ‖ SIGHASH ‖ PAC) — but that is a use, not an identity: SIGHASH is a signature fingerprint, not a key seed or a nonce. |
| 64 | SIGHASH_ALGO | 1 | Hash family for SIGHASH derivation. V1 = 0x01 (BLAKE3). |
| 65–96 | KEYHASH | 32 | BLAKE3 of the signer's ML-DSA-65 public key. The genesis-anchor KEYHASH binds the Guide ID. |
| 97 | KEYHASH_ALGO | 1 | Hash family for KEYHASH computation. V1 = 0x01. |
| 98 | PAYLOAD_CIPHER | 1 | Payload suite selector: the hash that makes BODY and CORE, and the payload cipher. V1 = 0x01 (BLAKE3; AES-256-GCM with BLAKE3-KDF). |
| 99 | SIG_ALGO | 1 | Quantum signature algorithm selector. V1 = 0x01 (ML-DSA-65). |
| 100–115 | GUIDE | 16 | Author's Guide ID, UTF-8, null-padded. |
| 116–124 | TIME | 9 | Unix milliseconds at sign time, big-endian. Byte 116 reserved as a CLOCK_SOURCE soft-fork slot. |
The four selector bytes (SIGHASH_ALGO, KEYHASH_ALGO, PAYLOAD_CIPHER, SIG_ALGO) are the protocol's primary upgrade lane for cryptographic primitives. A future ML-DSA-87 deployment would land at SIG_ALGO = 0x02, with 0x01 continuing to be served by readers for all anchors signed under V1.
| Range | Field | L | Description |
|---|---|---|---|
| 125–156 | PAC | 32 | WHO chain. Pointer to the previous anchor in this Guide ID's chain. The only walked chain in PHEUN. |
| 157–163 | PAC_COUNT | 7 | Monotonic per-Guide-ID counter. Genesis = 1; each subsequent anchor increments by one. |
| 164–195 | LINK | 32 | WHERE pointer. CORE of the anchor this one replies to or builds on. Stored, not walked. |
| 196–227 | ORIGIN | 32 | WHAT pointer. CORE of the genesis anchor of the document, thread, or stream. |
| 228–229 | LINE | 2 | Document line counter, 16-bit (65,535 lines per document). |
| 230–232 | LINE_VERSION | 3 | Per-line revision counter, 24-bit (~16.7M revisions per line). |
| Range | Field | L | Description |
|---|---|---|---|
| 233–234 | ASI | 2 | This anchor's home AnchorStream Index, computed by the dispatcher (§6). |
| 235–236 | PAC_ASI | 2 | ASI of the PAC-linked anchor (a routing hint for chain walks). |
| 237–238 | LINK_ASI | 2 | ASI of the LINK parent. |
| 239–240 | ORIGIN_ASI | 2 | ASI of the ORIGIN genesis. |
| Range | Field | L | Description |
|---|---|---|---|
| 241 | CATEGORY | 1 | Anchor category. The eight categories are enumerated in §7. |
| 242 | TYPE | 1 | Type in one global 256-slot namespace whose byte-range encodes the category. 0x00 universally = Genesis Document. |
| 243 | CONSENSUS_STATE | 1 | An enum, never a bitfield: 0x00 regular, 0x01 verdict, 0x02 tally checkpoint. Records the phase; routing is by TYPE. |
| 244–245 | TONGUE | 2 | Language code — an index into the language registry, with room for every ISO 639-3 living language. |
| 246 | AGE_RATING | 1 | Self-declared age rating (All / 13+ / 18+ / 21+). |
| 247–250 | ZONE | 4 | Country (247–248, uint16 BE, ISO 3166-1 numeric) + city within it (249–250, uint16 BE; 0 = country-wide). |
| 251–270 | TAGS | 20 | Ten uint16 BE content tag codes from one shared 65,536-code namespace. Three mandatory non-zero, seven optional. |
| Range | Field | L | Description |
|---|---|---|---|
| 271–277 | ACCORD | 7 | Aggregate yes-vote tally as of this anchor's mint. 7-byte big-endian counter. |
| 278–284 | DISSENT | 7 | Aggregate no-vote tally as of this anchor's mint. 7-byte big-endian counter. |
| 285 | RATIO | 1 | Approval ratio mapped to 0–200 range; 150 is the 75 % threshold. |
| Range | Field | L | Description |
|---|---|---|---|
| 286–287 | FRAGMENT_COUNT | 2 | Total fragment count for this anchor's payload. |
| 288–289 | PAYLOAD_COUNT | 2 | Logical payload count. 0 = metadata-only, 1 = text+preview, 2+ = attachments. |
| 290–296 | TALLY | 7 | Running interaction count within thread or stream. 7-byte monotonic counter. |
| Range | Field | L | Description |
|---|---|---|---|
| 297 | DOC | 1 | Document id from the closed registry — 0x00 none, 0x01 Constitution, 0x02 Curriculum, 0x03–0xFF unallocated (§15). Not text. |
| 298–321 | TITLE | 24 | Short display label. |
| 322–345 | HASHTAG | 24 | Discoverability tag: one [a-z0-9_] token, broad_to_narrow; formal prefixes mention_<guideid> and def_<term>. |
| 346–409 | PREVIEW | 64 | First 64 bytes of payload text — the card-render quote. |
| 410–411 | RUNTIME | 2 | Runtime of the payload's timed media in minutes (0 = none, ceiling 65,535 ≈ 45 days). Range-searchable by length. Not a time-to-live. |
| 412–413 | CLIENT_VERSION | 2 | Protocol version that minted this anchor. Used for soft-fork dispatch (§20). |
| 414–445 | AVATAR | 32 | Required compact SVG reconstruction key selected explicitly for this anchor. 256 bits, the last choosing the picture: a text poster (24 glyphs at 8 bits across up to four lines, with palette, style, alignment, weight, case, spacing, frame, texture, slant, ink, accent line, leading and baseline) or a portrait (22 tiered DNA slots, one of 64 archetypes, a 17-bit composition block and a 16-glyph caption). Keys may be reused, but are never inherited or defaulted. |
| Range | Field | L | Description |
|---|---|---|---|
| 446–447 | FREE_SCHEMA | 2 | Schema selector for the FREE_PAYLOAD that follows. 0x0000 = empty, 0xFFFF = TLV container. |
| 448–511 | FREE_PAYLOAD | 64 | Schema-defined payload bytes. Up to 64 bytes; layout depends on FREE_SCHEMA. |
Block 8 is the protocol's additive extension lane. New features land as new schema IDs in the FREE_SCHEMA registry; old readers see an unrecognised schema as opaque hex and ignore the schema-specific behaviour, but verify CORE and the signature normally. §20 specifies the soft-fork model.
The 4,096 AnchorStream Index buckets are not a chain. There is no chain zero. There is no genesis block. There is no global ordering. AnchorStream Indexes are payload-addressed storage targets: each anchor's home ASI is computed deterministically from its own bytes by a published dispatcher table, and two nodes walking the same ASI with the same inputs observe the same byte order.
The fundamental ASI computation phi-folds a 32-byte BLAKE3 digest into one of 4,096 buckets, in scaled integer arithmetic so no floating-point rounding can make two nodes disagree. CORE, LINK, ORIGIN and PAC are already digests and fold directly; GUIDE and DOC are hashed first:
ASI(h) = ⌊ uint64_be(h[0:8]) × φ ⌋ mod 10000
ASI(GUIDE) = ASI(BLAKE3(GUIDE padded to 16 bytes))
ASI(DOC) = ASI(BLAKE3(DOC byte))
The hash is load-bearing: folding raw names that differ only in their last character, or document ids allocated 1, 2, 3…, would land them in adjacent buckets. Hashing first makes the whole field decide the bucket, so the result is uniform across all 4,096.
| Type | Consensus state | Routes to | Anchor class |
|---|---|---|---|
0x00 | any | ASI(DOC) | Genesis Document — opens a governed document, once, from that document's own page. |
0x01 | any | ASI(GUIDE) | Genesis Profile — identity binding. |
0x60 | any | ASI(DOC) | Governance proposal. |
0x1F … 0xFF | any | ASI(LINK) | Reply — one per category, the last slot of its range; the parent's LINK branch. |
0x61 | any | ASI(BALLOT) | Vote Yes ballot — one bucket per (proposal, voter). |
0x62 | any | ASI(BALLOT) | Vote No ballot — the same bucket as that voter's Yes. |
0x6A | any | ASI(DOC) | Consensus Approved — co-located with document. |
0x6B | any | ASI(DOC) | Consensus Denied. |
0x69 | any | ASI(LINK) | Tally Checkpoint — a published count, not a vote; co-located with proposal. |
0x52 / 0x56 / 0x57 | any | ASI(DOC) | Education proposal and verdicts (the Curriculum's governance set). |
0x53 / 0x54 | any | ASI(BALLOT) | Education ballots. |
0x55 | any | ASI(LINK) | Education Tally Checkpoint. |
0xA0 | any | ASI(CORE) | Social update — scattered. |
| default | default | ASI(CORE) | Regular content anchors. |
ASI(BALLOT) is the phi-fold of BLAKE3("PHEUN-BALLOT-v1" ‖ proposal CORE ‖ GUIDE): voters scatter across every bucket, so a single proposal absorbs a billion ballots without saturating any one, while every ballot one voter casts on one proposal meets on one bucket, whose holders count only the earliest — one citizen, one vote. A single-ASI query at ASI(DOC) returns the document outline; a single-ASI query at ASI(LINK) returns one proposal's tally checkpoints; the ballots are aggregated on demand by an all-ASI count fanout.
The dispatcher is fully deterministic. Two nodes with the same anchor bytes always compute the same ASI. This is the foundation of consensus by placement: two nodes never disagree about where an anchor belongs. Within an AnchorStream Index, sort order is also deterministic — primary key is TIME; ties on TIME break on PAC; ties on PAC break on the full 1,024-character hex transaction string. Two nodes walking the same ASI bucket observe the same byte order, byte for byte.
Even the AnchorStream Index this node owns is queried through an outbound announce-and-pull cycle against the peer that covers it, never by reading the local table directly. A node with one AnchorStream Index cannot trust itself as a query source, because trust would presume the node had already verified its own data through some other channel — which it has not, except by virtue of having received those anchors from peers via gossip cascade or sync. A query is, in PHEUN, always a network operation.
Every anchor in PHEUN belongs to exactly one of eight semantic categories, encoded in the CATEGORY byte at position 241.
| Byte | Category | Primary Use |
|---|---|---|
0x01 | Identity | Genesis Profile, profile updates, device-binding anchors. |
0x02 | Shelter | Places, properties, community spaces, building info, host pages. |
0x03 | Education | Courses, lessons, syllabi, study materials, quizzes, flashcards. |
0x04 | Democracy | Proposals, votes (yes/no), tally checkpoints, verdicts. The governance category. |
0x05 | Economy | Barter offers (compute, bandwidth, storage, services, physical goods). |
0x06 | Social | Updates, replies, shares, quotes, reactions. |
0x07 | Media | Films, music, podcasts, photo albums, channels, streams. |
0x08 | Knowledge | Wiki articles, encyclopaedia entries, research papers, citations, glossaries. |
PHEUN has exactly eight platform categories. There is no reserved 9th slot. The eight cover every use case identified to date — health and wellness logs sit naturally as Identity sub-types or Social updates depending on privacy intent; spirituality, sports, journalism, hobbies, dating, and pets all distribute across the existing eight without a dedicated home of their own. Consensus and tally semantics are CONSENSUS_STATE-byte states on Democracy anchors (CONSENSUS_STATE=0x01 = consensus lock, CONSENSUS_STATE=0x02 = tally snapshot), not a separate category. Future protocol evolution rides on the soft-fork lane (§20) by adding new TYPE bytes inside an existing category's range, new FREE_SCHEMA values, or new dispatcher subtypes — never by allocating a 9th category.
The split is use-case-shaped, not technology-shaped. Categories determine the default feed scope, the discovery filters available, and the subset of types that have meaning. Categories do not enforce content rules — there is no protocol-level content moderation — but they organise the substrate for citizen-driven discovery. The TYPE byte at position 242 lives in a single global 256-slot namespace partitioned into per-category byte ranges (Identity 0x01–0x1F, Shelter 0x20–0x3F, Education 0x40–0x5F, Democracy 0x60–0x7F, Economy 0x80–0x9F, Social 0xA0–0xBF, Media 0xC0–0xDF, Knowledge 0xE0–0xFF). Type 0x00 is universally the Genesis Document across every category.
The network fingerprint is the single 32-byte digest that walls off forks at handshake time, before any authenticated traffic flows between two peers. Two peers with different fingerprints are different networks; the protocol drops the connection at the handshake boundary. There is no fingerprint negotiation, no version handshake that allows partial compatibility, no graceful degradation. A fingerprint mismatch is a hard reject.
fingerprint = BLAKE3-32(
HOPE_VERSION
‖ ASI_COUNT
‖ ANCHOR_BYTE_LAYOUT
‖ sorted(GENESIS_AUTHORITY_KEYHASHES)
‖ approved_crypto_primitives
‖ approved_packet_type_table
‖ PASSPORT_FORMAT
‖ DWS_MERKLE_GEOMETRY
‖ CORE_DERIVATION
‖ GOVERNANCE_RULES
‖ KNOWN_ANSWERS
)
The byte layout is every field's name, offset and length, so two same-width fields swapped are a different network. The CORE derivation and the governance rules are agreement rules: builds that derive CORE differently refuse each other's every anchor, and builds that disagree on the voting window, the 75 % threshold, the five-vote floor or the quorum's 25-approval window and 10 % tolerance count different ballots or reach different verdicts. The governance rules are one set for every proposal of every document. KNOWN_ANSWERS binds the code rather than its constants: what the build's bucket fold, CORE derivation (payload suite 0x01) and signing message give on fixed inputs, so a build whose code drifted drops at handshake. Only V1 behaviour is pinned — a new payload suite, signature scheme or dispatcher rule is added beside it — and fragment placement, which is policy, stays out. Nothing meant to evolve is bound — the soft-fork protocol version, the manifest version (readers switch on it) and the dispatcher table (new rules are added) stay out.
The Genesis Authority roster — nateofearth2100z, genesis_node0001, genesis_node0002 — enters twice: as a sorted set, and in declaration order, because order is consensus-critical (index-0 is the only solo authority and index-1 the only single-witness bridge). The Genesis Authority KEYHASH hashes are the BLAKE3-32 fingerprints of the public keys associated with those three Guide IDs, sorted before hashing; an empty slot is a supported pre-registration state.
Negotiation creates a downgrade attack surface, requires the protocol to define partial compatibility windows, and makes byte semantics depend on which version a particular peer happens to be speaking. PHEUN takes the opposite stance. The wire format is byte-frozen; all evolution happens through the soft-fork lane (§20): new schemas in the FREE region, new algorithm selector bytes, new packet types, new dispatcher subtypes — all additive, all opaque to old readers, none of which rotate the network fingerprint. A real protocol upgrade — one that would change the byte layout, the ASI count, the crypto primitives' approval list, or the Genesis Authority roster — produces a new fingerprint, and PHEUN does not implement any mechanism to coordinate such a departure across the existing network.
HOPE is the pure-UDP node-to-node transport, and everything two PHEUN nodes say to each other crosses it. The acronym maps to the design intent: Hardened (fail-closed cryptography, return-routability before amplification, egress limiter, fingerprint check), Onion (Triple Sentry three-hop relay on sensitive packets), Post-quantum (ML-KEM-1024 key agreement, ML-DSA-65 identity signatures, AES-256-GCM sealing, BLAKE3 for every digest and derivation), Exchange (a peer-to-peer mesh with no server tier). HOPE is not QUIC and shares no wire format with it. WebSocket is reserved for the local browser-to-node UI link inside the citizen's own device and is never used between nodes. The full byte-level description, with every constant, is in the specification text; this page summarises it.
Most HOPE messages — an anchor, an announce, a fragment slice, an onion hop — are individually meaningful and can be processed in any order, so HOPE runs on UDP and adds exactly the delivery each needs. Four rules shape the protocol. Binary, nothing repeated: no JSON, hex or base64 on the wire, and no length, checksum, timestamp, connection id or in-message sender. Sealed unless it proves itself: a message that acts on who sent it is accepted only from a datagram that opened under that peer's tunnel. Evidence over timers: a peer is withdrawn the moment an exchange goes unanswered. No amplification for strangers: nothing larger than a few dozen bytes goes to an address that has not shown it receives.
byte 0 0x90 | flags // 0x9_ = HOPE v1 (never STUN); 0x01 SEALED, 0x02 ACK-ELICITING, 0x04 RELAYED SEALED [b0][pn u32][AES-256-GCM(frames)][tag 16] // 21 B overhead PLAINTEXT [b0][sender Guide ID 16][frames] // 17 B overhead, pre-tunnel only RELAYED [b0][frames] // 1 B, a sealed datagram across a relay, named by relay tag FRAME [type u8][length uvar][body] // several per datagram, ≤ 64
A sealed datagram's sender is the tunnel's peer; a plaintext one names its sender once, as a claim. The packet number is the nonce's unique half, the replay index and what an ACK names; byte 0 is the AAD. Frame types 0xFF ACK, 0xFE PADDING and 0x32 CHUNK belong to the transport; an unknown frame type is skipped by its length. Every datagram also pays 28 B of IPv4/UDP (48 on IPv6).
One binary schema per message type, built from one combinator engine: big-endian fixed integers, LEB128 varints, UTF-8 text with a varint length (invalid UTF-8 refused), raw bytes for digests, keys and signatures, one presence bit per optional field, bounded list counts. Decoding is canonical-only and fail-closed — every value has exactly one encoding, so it round-trips to the string a signature covers, and anything malformed is dropped. A decoder ignores trailing fields it does not know, so a later version can append optional fields without breaking an older one. The whole family is fuzzed.
Only a sealed ack-eliciting datagram earns an ACK: ranges, piggybacked on outgoing traffic, or alone after 25 ms, or at once every second datagram. Probes, echoes and anchor announces are never ack-eliciting — their answer is the acknowledgement. A lost datagram is retransmitted as the identical sealed bytes (RTO = smoothed RTT + 4 × variance, 200 ms–60 s, doubling, five tries), so a duplicate is recognised as a replay, never delivered twice; a 1,024-packet replay window and a 960-packet send window keep every retransmit inside it. The congestion window runs 2–256 datagrams (start 10, slow-start to 64), with the handshake, session exchange and probes exempt because they are what recover a saturated link. A per-peer fair queue (64 datagrams per 1 ms tick, 256 per peer) keeps one busy peer from starving the rest.
Each path's MTU is measured on its own, between 1,200 and 1,452 bytes (start 1,350), by sealed PADDING probes that count only when acknowledged and move only the path they were sent down — never one size for the node, since a mobile carrier, PPPoE or a VPN carries less than a data-centre link. A larger message leaves as CHUNK frames [msgId u32][index][count][type][data], each sealed alone and reassembled before dispatch through the same gates. Plaintext and sealed transfers have separate budgets — plaintext at most 2,000 transfers and a quarter of 500 MB, least-recently-fed evicted; sealed the rest, five per peer — so a spoofed one-chunk flood cannot refuse sealed transfers. A plaintext chunk is never retransmitted, which is why a fragment between strangers goes by slice (§13.3).
A first contact sends a ~66-byte hello and receives a ~60-byte challenge carrying cookie = BLAKE3(per-boot secret ‖ IP ‖ port ‖ 2-min slice)[0..16]; only an endpoint that echoes it receives the several-kilobyte handshake. Verification recomputes, so no challenge is stored. The handshake carries each side's profile, whose identity-signed session bundle names its ML-KEM-1024 tunnel key. The higher Guide ID encapsulates to the lower's key — in its reply, or in a follow-up when it was the initiator — and both derive tunnelKey = BLAKE3("PHEUN-TUNNEL-V1-AES256" ‖ ss ‖ sorted Guide IDs). The exchange is signed (kxSig over both parties, the time and the ciphertext); a ciphertext is taken only for a handshake outstanding at that endpoint, and only a signature against the genesis-verified key may replace a working tunnel. The reply carrying a ciphertext leaves before the peer's identity check, whose queries ride the tunnel it completes. Identity is bound to the canonical genesis at ASI(GUIDE), never to the one the peer presents. Each direction seals under its own key and nonce prefix derived from the tunnel key and the sender's Guide ID.
A tunnel key lives seven days and is renewed before it runs out: the side that keeps the pair's beat (the one behind NAT when exactly one is, else the lower Guide ID) at a per-pair point spread over the 12 hours before the final hour, the higher side only as a fallback in the last 30 minutes. The renewal happens inside the tunnel (TUNNEL_RENEW, 0x5B): a fresh ML-KEM-1024 ciphertext to the peer's identity-bound key, chained to the old key, with a 16-byte check of the key it yields so the peer never switches to one it does not share; the peer switches and answers ok under the new key, the sender switches on hearing it, and the replaced key keeps opening what was sealed under it until it would have expired — no gap, about 1.9 KB a pair a week where a handshake re-sent ~21 KB of profiles. Either side re-handshakes at 2³¹ packets, and a connected peer found with no tunnel on two sweeps is re-handshaked. A login re-keys nothing: the direction keys are fixed when the tunnel is made, so each peer files the existing tunnel under the new name (§9.8). Only a change to a different real Guide ID rebuilds every tunnel.
A node not yet logged in runs as a temporary identity that names its own tunnel key, "0000" ‖ hex(BLAKE3("PHEUN-TEMP-ID-V1" ‖ KEM key))[0..12]. It is bound only at a return-routable endpoint (through the cookie, or by answering a handshake the binding node itself sent there), may use only the pre-login flows (handshake, probe, endpoint challenge, genesis propagation and placement, the query engine, the passport pull, LOCATE discovery, its relay registration, its own login), and is never trusted for any role.
Discovery owns membership, logged in or not. From boot the node heals every short bucket: it reconnects home peers it has met before from the passport cache, then runs LOCATE through the peers it has — three hops at most, a random target per chain, the bucket's home peers named first and a hop that names enough of them stopping there — and dials only the shortfall, at a batch that widens with the gap, so one live peer is enough to reach tens of thousands. A LOCATE answer names only peers a stranger can connect to — never one behind NAT or a relay — and each sender's requests are rate-limited. The seed roster is read only on a first boot, or with no live peer at all. A node behind NAT holds its relay from boot.
At login nothing is rebuilt. The node sends each peer its profile sealed inside the tunnel it built as the temporary id, carrying a rekey claim signed by its identity. The peer refiles routing entry, binding, tunnel (keys unchanged) and relay slot under the real Guide ID on three local proofs: the announcement opened under that tunnel; the profile's tunnel binding signs the very key the temporary id is named after; the identity signs the claim. The genesis binding then runs as for any profile. A login costs one ~7 KB profile upload per peer, where rebuilding every tunnel cost about 2.2 GB at 50,000 peers. A peer with no tunnel to the temporary id gets the claim in the clear and retires it in place, or after an endpoint challenge — never on the claim alone. A peer receives each profile once; a push skips any peer already holding it.
Four kinds of message may travel in the clear, and none rests on the header's name: open (handshake, profile, session exchange and rotation, endpoint challenge and proof, onion hop, relay messages — each proves itself), stateless (the fragment family — touches no peer state, answered to its source, a pull only after a cookie echo), e2e (a DM, call packet or WebRTC signal inside its end-to-end seal) and answerable (the passport pull, taken only from the peer's bound endpoint). Everything else is sealed-only, in both directions.
Every tunnelled pair proves a round trip once per 7.5-minute probe interval, the single liveness knob: the side behind NAT probes (else the lower Guide ID), the other echoes, and the echo's nonce returns on the next probe, so one exchange proves the round trip for both sides. The probe is the most-sent message, so at idle its body is five bytes: two 2-byte nonces, enough inside a seal that cannot be forged or replayed. The 8-byte fingerprint of the sender's LIVE set and relay binding rides every probe for three intervals after that state changes and one in six of the rest; a mismatch pulls the passport. The echo carries its clock only when the probe asks, for the peers the clock check samples. To a peer elected as its SPS holder a probe also carries the 8-byte contract fingerprint (§16.3). Every anchor announce asks for an acknowledgement, so traffic finds a dead holder first and the probe floors only the quiet peers. A probe unanswered within 10 s, or a reliable exchange with no answer at all, withdraws the peer from every selection at once until a rescue probe restores it. Two probes in a row unanswered, or waking from a sleep longer than the 24-minute stale window, mean the peer has dropped our tunnel: it is rebuilt with a fresh handshake. A peer counts as a holder only with a round trip in the last 15 min 40 s.
Every datagram between two connected peers is sealed under their ML-KEM-1024 tunnel, and a message that acts on who sent it is accepted only that way. A DM or call travels through other nodes, so it is sealed end to end under a separate pairwise session — one per conversation, made when a DM or call first needs one and never kept with connected peers by default. Onion hops need none (§10.1). Sessions use ML-KEM-1024 key encapsulation with AES-256-GCM payload encryption. SESSION_KEY_EXCHANGE establishes one, and it is authenticated: request and answer are each signed by the sender's ML-DSA-65 identity key and checked against the key its canonical genesis names. Because the proof travels with the packet, a signed exchange is taken from any path, a relay included — which is how a node behind NAT gets a session with a stranger who wants to message it, while the relay can neither answer in its place nor alter it. An unsigned exchange is taken only from the peer's bound endpoint, and never from a peer whose key is verified (no downgrade). With no proven tunnel to the peer, the exchange itself travels as a Triple Sentry circuit whose last hop finds the recipient, naming its author in a signed from field — a bare route (a LOCATE answer, a passport cached before a restart) can name a relay slot that died with its process, so it is used only when no circuit can be built. When both sides initiate at once the lower Guide ID's exchange stands, so the pair always ends on one session. A session lives 24 hours; its initiator renews it only if it carried traffic, so an idle conversation's session lapses, and a peer's restart drops it. SESSION_KEY_ROTATE re-keys an existing session every 10,000 packets, or after an hour of a session that carried traffic, for forward secrecy — an idle session has nothing to protect and is not re-keyed on the clock — MAC'd under the session it rotates, so it may cross a relay too. A decapsulation failure during rotation drops the rotation and the old key remains in use until the next sweep — fail-closed. An exchange sent directly is not onion-routed: a relay host can see that two Guide IDs set up a session, never what they say.
A passport is a signed record carrying a peer's identity (Guide ID, ML-DSA-65 public key fingerprint), network coordinates (IP, UDP port), its home AnchorStream Index — always ASI(GUIDE) — the LIVE set of buckets it holds, and capability flags. The LIVE set travels as one bit (HOME form) when a node holds nothing beyond its own bucket, and as a bitmap when it holds more; no node declares what kind of node it is, and it is elected for exactly the buckets its passport names. Every liveness probe carries an 8-byte fingerprint of that set and the peer's relay binding, and a peer pulls the full passport only when the fingerprint differs from its cached copy.
Beside each cached passport a node keeps its own observations, never sent: the hours in each of the last seven days with a proven round trip, and the streak of unanswered attempts since the last answer. A peer counts as a holder of a bucket only when its LIVE set includes it and it answered recently; a reconnect from the cache takes only a peer proven before and not failing since, most reliable first. The cache holds up to 1,000,000 entries and never ages one out: an entry leaves after 48 hours of unanswered attempts — after two attempts an hour apart if it has never answered this node at all — or when the cache is full, longest-unheard first. Every fragment probe a node sends is evidence: silence counts as a failed attempt, any answer ends the streak, so a dead entry stops winning placement slots. At billion-user scale the live mesh is statistically empty for any specific peer or fragment lookup; the passport cache is the actual substrate for discovery, and the live mesh is the launchpad for the cache-miss path.
TOTAL = 66,666 live connections mesh = 60,000 // sized for an eviction floor of 6 per ASI reserve = 6,666 coverage target = 3 holders × 4,096 ASIs = 12,288 // 8,192 at the floor of 2; the rest left over passport cache = 1,000,000 entries on disk
Live mesh covers the security substrate (a target of 3 live holders per ASI; §24); passport cache covers the discovery substrate. The routing table enforces the budget as one capacity, never a share per k-bucket — XOR distance fills buckets geometrically, and a per-bucket cap would stop a node near 2,000 peers on a 12,288-node network. Coverage counts in two tiers: the floor counts every holder alike, whatever it holds, and is what gates, receipts and witnesses read; the target counts each peer for its own bucket alone, so a Keeper is one node of one bucket and discovery keeps going until every bucket has three of its own nodes — a mesh of 12,288 distinct peers, not a star round the Keepers. Searching is rare and reconnecting frequent: every five minutes a short bucket sends a hello to the home peers it has proven before, straight from the cache, so a node behind NAT finds a public peer again minutes after it returns.
A connection is kept while at least one side needs it. Each node dials for three home peers of every bucket and keeps the best five, the spare riding out churn; a connection is needed when the peer is in that keep set, carries a duty (a relay slot, an SPS election, an open conversation), or the side is still bootstrapping. A hello names what it wants — optional, need, or essential (pre-login, almost no peers, or below two of the bucket: this node is the only option). A node that will not take the asker marks its cookie challenge busy, no larger than the hello, and answers the cookie-proven asker with up to eight peers a stranger can reach instead of a tunnel — about half a kilobyte where an unwanted tunnel cost twenty-nine. Essential askers are always let in, from the 6,666 reserve once the mesh budget is spent, so anyone is a seed. Past twice the target mesh (24,576) a node asks, slowly and with PEER_RELEASE, for the release of connections nobody needs; the other side keeps any it does. A restart re-dials only its keep sets.
Every node is the same; a node behind NAT is reached at its slot. It cannot be dialled, but it can always be reached through the slot it holds at its relay host, so that slot is its address — relay~<token>~<host IP> at the host's port. A peer binds it there like any address, and everything sent to it, the handshake included, rides a RELAY_FORWARD to the slot. A handshake through a relay names the sender's own slot, and is answered there; the cookie proves the asker receives there, as it proves a direct source. Two nodes behind NAT therefore tunnel through each other's hosts and never learn where the other lives, and LOCATE names a NAT'd node at its slot, never its home address. Only a message that proves itself — the handshake, the endpoint challenge and proof — is credited to a slot. When a node's slot moves, its probes tell its NAT'd peers the new one, sealed, for three probe intervals, and each re-points through the same proof any endpoint move needs. In simulation at 100,000 nodes with 30 % public, every node holds three home peers in every bucket — against fewer than half when every connection needs a public end — for about 38 kbit/s of idle forwarding out and 41 in per host at the 7.5-minute probe.
Per-peer token-bucket egress limiters cap send rates on bursty channels — gossip 120 capacity / 20 refill per second, fragment 60/10, query 240/60 — keyed by Guide ID, which is why the temporary-identity gate, not the limiter, bounds a pre-login sender. The fair queue is the anti-starvation half; both are required. Announces dedup by CORE for five minutes, queries by request id. The per-endpoint state table is capped at 100,000 endpoints, and a full table withholds only state from a new source, never its datagram — dropping datagrams would let a spoofed flood keep a node deaf to every peer it had not met. A holder serves each asker (its address, its /64 on IPv6) a bounded number of fragment bytes per window, and accepts a bounded number of stored bytes per hour from each sender.
A node behind NAT does not know the address the rest of the world sees it at, yet it needs that address to advertise a reachable endpoint. Every conventional answer is a third party — a STUN server, or an HTTP “what is my IP” service — and each hands one external operator a complete log of which node came online, from which address, and when. That is precisely the metadata the rest of this design exists to avoid. PHEUN contacts neither. There is no external STUN endpoint, no IP-echo service, and no fallback to one anywhere in the tree.
Peers already have the answer: a peer had to observe our post-NAT source address in order to receive our packet at all. It reports it back as two extra fields on the ENDPOINT_PROOF packet. That placement is the security control — the proof echoes a nonce encapsulated to the peer's genesis-bound ML-KEM key, and the challenge identifier is single-use, so the reporter is cryptographically established rather than claimed. Carrying it on the plaintext handshake instead would let one attacker satisfy the threshold alone under two invented identities.
A reported address is untrusted input, so two distinct peers must agree before it is adopted; a tie adopts neither, and each reporter gets one vote so re-handshaking cannot stuff the ballot. Without this, a single lying peer could make a node advertise a black hole (nobody can reach it) or a third party's address (a traffic-reflection primitive).
Cold start needs no mesh at all, but the question is asked per address family. The ordinary consumer shape is a global IPv6 beside a CGNAT'd IPv4, so taking the first global address of either family would declare the node publicly reachable and advertise a relay host no IPv4-only peer can reach. Eligibility turns on IPv4 — the family every peer can still use — while a genuinely IPv6-only host qualifies on IPv6.
The same principle covers voice and video. Only a party that receives a packet from the browser's own socket can supply a server-reflexive ICE candidate — that is what a STUN server is, and PHEUN nodes already are that party. Each node answers RFC 5389 Binding requests on its existing HOPE port, so the browser asks its own mesh. Three independent checks (length, a message type with its top two bits clear, and the magic cookie) demultiplex STUN from HOPE unambiguously. When no publicly-addressable peer is known the candidate list is simply empty and a cross-NAT call may fail — the honest outcome, with deliberately no external fallback to make it quietly succeed.
| Code | Type | Travels | Purpose |
|---|---|---|---|
| 0x05 / 0x07 | PROBE / PROBE_ECHO | sealed | the pair probe and state fingerprint |
| 0x06 | SENTRY_RELAY | open | one onion hop (§10) |
| 0x08 | PROFILE_ANNOUNCE | open | profile push and signed rekey claim (a temporary sender: sealed, its own login only) |
| 0x09 | BOOTSTRAP_HANDSHAKE | open | hello, cookie challenge, handshake, key-exchange follow-up |
| 0x11–0x15, 0x33 | DM, CALL_*, WEBRTC_SIGNAL | e2e | private conversation (§10) |
| 0x17 | SUBSCRIPTION_FORWARD | sealed | SPS contract, delta, request, refuse, release, delivery (§16) |
| 0x1C / 0x1D | SESSION_KEY_EXCHANGE / ROTATE | open | the per-conversation session; direct, or through Triple Sentry |
| 0x1E, 0x42–0x45 | FRAGMENT_STORE, FRAG_PULL, FRAG_CENSUS | stateless | PayloadWeave placement, pull, census (§13) |
| 0x21 / 0x22, 0x4C / 0x4D | ASI_SYNC, ASI_MERKLE | sealed | Dual-Witness Sync (§12) |
| 0x27 / 0x28 | PASSPORT_STATE_UPDATE / TIMESTAMP_REQ | sealed / answerable | passport push and pull |
| 0x2A–0x2C, 0x51 / 0x52 | LOCATE_*, PEER_FIND | sealed | discovery from boot, home peers first, results dialled up to the shortfall (§9.8, §24); a Guide ID's reach for an onion's last hop (§10.1) |
| 0x34–0x37 | QUERY_* | sealed | the global query engine (§17) |
| 0x38–0x3A, 0x50, 0x55 / 0x56 | ANCHOR_HAVE/WANT/FULL, ANCHOR_STORED, LIVE_DIGEST | sealed | Self-Verifying Anchor Propagation and its live window (§11) |
| 0x48–0x4B, 0x57–0x59 | RELAY_* | open | the rotating relay; RELAY_SEALED carries a whole sealed datagram under its tunnel's relay tag, RELAY_RETURN / RELAY_DELIVER a fragment message with its way back (§19) |
| 0x4E / 0x4F | QUERY_FORWARD | sealed | fragment discovery (§13) |
| 0x53 / 0x54 | ENDPOINT_CHALLENGE / PROOF | open | endpoint possession; observed address |
| 0x5A | PEER_RELEASE | sealed | "may we close this connection?" — ask, keep or ok (§9.13) |
| 0x5B | TUNNEL_RENEW | sealed | the tunnel re-keyed inside itself — renew or ok (§9.7) |
| 0x5C | REACH_TEST | sealed | can a stranger reach the asker? — ask, or relay to a stranger (§19) |
| 0x5D | REACH_PROBE | plaintext | the stranger's unsolicited packet, carrying the asker's code (§19) |
Allocated and inert: 0x04, 0x0C/0x0D, 0x16 (call media never enters the mesh), 0x20, 0x25/0x26, 0x40/0x41 (fingerprint-bound) and 0x46/0x47. A new code is sealed-only until it is given a plaintext rule.
Idle, with 50,000 live peers and no content moving, each direction (measured by npm run bench:wire with the live codec):
JSON wire (before) binary wire (now) liveness 1.08 Mbit/s 0.051 Mbit/s // heartbeat+RTT probe+ACKs → one ~57 B probe/echo per pair per 7.5 min session re-keying 0.62 0 // idle sessions no longer rotated hourly session renewal 0.06 0 // a session exists per conversation; an idle one lapses tunnel renewal — 0.001 // ~1.9 KB inside the tunnel, a pair a week subscriptions — 0.001 // no refresh: 8 B contract fingerprint on the probe to each elected holder TOTAL each way 1.76 Mbit/s 0.052 Mbit/s // −97.0 %; ≈ 34 GB a month both ways; ~0.069 at 66,666
Content overhead fell from about 41 % above the raw payload to about 5 %. What cannot shrink by design is the ML-DSA-65 signature every holder verifies with each new anchor, and the IP/UDP header under every datagram.
No node holds 66,666 peers in practice. Over the balanced mesh, with nodes behind NAT connecting through their relays, npm run bench:idle prices every idle datagram: at 30 % public and the 7.5-minute probe, a node behind NAT holds about 17,600 peers and spends about 23 kbit/s out and 21 in; a public node holds about 22,600 and spends about 63 out and 66 in, about 40 of it carrying its relay clients' traffic. At 15 % public a public node spends about 118 / 125.
Where it goes: on a node behind NAT about 80 % is the pair probe and 14 % the relay envelope; on a public node about 61 % is relay duty. Of the probe's ~57-byte datagram, 28 bytes are IP/UDP, 16 the AES-GCM tag and 7 the sealed header and frame; its own body is five bytes. The peer count is needed rather than surplus: a connection stays while either side needs it, and releasing from 12,288 peers instead of 24,576 lowered the mean only from about 17,600 to 16,000 while 2.4 % of nodes fell short of their target.
PHEUN is pseudonymous-by-default with onion-protected sensitive channels — not a global anonymity network. The passport system binds Guide ID to IP:port at the pairwise mesh layer by design, because home-holder selection, fragment placement, anchor propagation, and Dual-Witness corroboration all require wire-layer authenticated identity. Triple Sentry hides the content and destination of six sensitive packet classes from all but the first and last hop in a three-hop onion path: direct messages (which also carry store-and-forward delivery), the four call-control types, and WebRTC signalling. Subscription forwards are sent direct — the elected subscription peer must know the subscriber in order to deliver matches back to it, so an onion would hide that identity from the only party needing it. Peer-ban announcement and CALL_MEDIA are reserved slots with no sender. Call media itself never crosses the mesh: once a call is set up, voice and video frames travel browser-to-browser over WebRTC’s own DTLS-SRTP, so what Triple Sentry protects for a call is the signalling — who is calling whom — not the stream. The stream is sealed post-quantum before SRTP sees it: every frame is AES-256-GCM-encrypted in the browser (Encoded Transform) under a random per-call key carried only inside the ML-KEM-1024-sealed call proof; a browser that cannot do this is refused the call.
payload = inner-encrypted to recipient's session key
Ki = BLAKE3("PHEUN-SENTRY-LAYER-V1" ‖ ML-KEM-1024.Encaps(tunnel key of relay i))
hop3 = KEM3 ‖ AES-256-GCM(K3, FINAL ‖ recipient ‖ payload ‖ padding) // to exit relay
hop2 = KEM2 ‖ AES-256-GCM(K2, RELAY ‖ relay3 ‖ address:port ‖ hop3)
hop1 = KEM1 ‖ AES-256-GCM(K1, RELAY ‖ relay2 ‖ address:port ‖ hop2) // to entry relay
Each layer key comes from a fresh encapsulation to the hop's genesis-bound tunnel key, opened with the hop's own tunnel secret — no session with any hop, and no public-input-derived key anywhere in the production path. Each layer names the next hop's address, so hops need no connection to one another; they are drawn only from peers a stranger can reach. The exit relay finds the recipient from its own binding, its passport cache, or a PEER_FIND asked of a random sample of its peers. A circuit lives a day: reused per correspondent for 24 hours, never extended by use, and dropped after 24 idle hours, with the exit remembering its answer as long — because every new exit must look the recipient up, and every new circuit is a fresh draw of three hops. Its hops keep nothing for it, so an idle circuit needs no keep-alive; it is dropped on evidence instead — a hop that left the routing table, or a message that went unconfirmed. Nothing crosses a hop but the onion — no path identifier, hop index or hop count — so the entry and exit relays share no value to link their halves of a circuit. The FINAL layer is padded with random bytes to a size class (powers of two from 1 KiB to 64 KiB, then 64 KiB steps), so a message, a call-control packet and a signal of one class are the same size at every hop. Anchors are public by construction (§23); the onion only protects the sensitive packet classes whose content is not intended for the ledger.
Triple Sentry does not defend against: timing correlation between colluding hops, or a hop reading its position from the size it receives; sender identity from any one of the three relay hops (each relay sees its predecessor and successor by IP:port; mesh is pairwise authenticated); coordinated all-three-relay compromise (multi-source candidate selection from manual seeds, availability-score-ranked relay-capable peers, and Genesis Authority fallback mitigates this but does not eliminate it); a global passive adversary with both endpoint visibility (out of scope).
Direct messages and calls are the one part of PHEUN that is deliberately not an anchor. Everything a citizen publishes becomes a 512-byte record on a permanent public ledger; what they say privately does not, and that exception is load-bearing rather than an omission.
Minting an anchor per message would place an undeletable, publicly visible record of who spoke to whom and when into a ledger with no delete operation. The content would be sealed, but the social graph and its timing would be permanent, public and queryable by anyone, forever — worse than anything payload encryption offsets. So a DM is peer-to-peer traffic held in each participant's own local store, sealed at rest under a key only their login yields, and a call is signalling plus a browser-to-browser media path. Neither touches the AnchorStream: 0xA9 ('Direct Message') is a reserved TYPE byte with no server-side usage, and there is no anchor mint anywhere in the messaging path.
The consequence cuts both ways and is worth stating plainly: private conversation is not backed up by the network. An anchor survives because thousands of strangers replicate the bucket it landed in. A DM survives because the two people in it kept it. Store-and-forward holds a message for an offline peer, but that is delivery, not durability.
A call adds one layer. Call signalling — invitation, acceptance, SDP and ICE exchange — travels as onion-wrapped HOPE packets, so no third-party signalling server learns who is calling whom, and the reflexive address each browser needs is answered by PHEUN peers acting as STUN responders rather than by Google or Twilio. Call media then flows browser-to-browser and never enters the mesh at all, which is why CALL_MEDIA is a reserved slot with no handler.
Triple Sentry protects a conversation once it exists. A separate mechanism decides whether it exists at all, and it answers a problem the onion cannot: a Guide ID appears in every anchor its owner writes, which is correct for authorship and wrong as a contact address. Without a gate, anyone who reads an anchor can ring that node forever, with only a reactive ban list in response.
Two fields, two jobs. The Guide ID is the citizen's permanent name — public, unchanging, what authorship is proved against. The contact code is their number: twelve digits, shown as 4821 0937 5516, handed out and replaceable at will. Separating them lets the name stay permanent while reachability stays revocable.
What crosses the wire is a proof, never the code: BLAKE3(DOMAIN ‖ code ‖ senderGuide ‖ recipientGuide ‖ epoch). Binding sender, recipient and epoch means a proof is valid only for that pair and window. It travels sealed end-to-end to the recipient, so no relay hop can test guesses offline — only the recipient's rate-limited gate answers one. That is what makes twelve digits (~240) enough, and the floor: six digits (~220) falls to a distributed guesser in minutes.
The gate runs before ICE, and that placement IS the control. WebRTC hands the local public address to whoever it negotiates with, so a check performed when the call rings has already leaked the thing it was protecting.
The proof is re-checked on every inbound — there is no accepted-contact short-circuit. This is the central trade and it is deliberate: with a one-time promotion, rotating the code was a no-op for anyone who had already used it, so a citizen who published a code and was then spammed had no remedy but removing peers by hand. Re-checking means a rotation cuts off everyone holding the old code, friends included — which is exactly what makes rotation a remedy rather than a gesture. The people a citizen keeps are restored through one channel only: their next message to that person carries the new code inside the ML-KEM envelope, and the recipient's node updates its record after sender authentication. There is deliberately no bulk push — a citizen with a thousand unwanted threads would hand the new code straight back to every one of them, so the broadcast would be the leak.
Guessing is bounded per-sender and node-wide, because a per-sender cap alone gives an attacker with N throwaway Guide IDs N fresh allowances. A correct proof is verified first and never consults a budget: with no short-circuit above it, budget-first would let a stranger spray wrong codes until the node-wide allowance was spent and every real conversation stopped.
What the code buys is revocability, not secrecy. Publishing it is a supported choice — put it in an anchor or on a PHEUN Site to be openly reachable — but a code in a payload is network-readable forever, because payload keys derive from the public anchor. Private by default, public by choice, reversible either way.
PHEUN admits each anchor at the moment it is born, and it does so without a jury, an attester, or a witness. The mechanism is Self-Verifying Anchor Propagation (SVAP): the anchor carries, on every propagation, everything a receiver needs to prove it is genuine, and every receiver re-runs that proof independently. There is no trusted third party whose verdict must be believed. The propagation is the verification.
A committee model authenticates the committee, not the anchor — and at billion-user scale a receiver almost never holds a given juror's public key, so it could not verify such a signature. The author's proof has no such weakness: the author's public-key fingerprint (KEYHASH) is inside the 512-byte anchor, and the full public key and signature travel with it, so any node anywhere can verify the author directly.
The self-verifying payload is ANCHOR_FULL (~6.5 KB, fixed binary layout): the new anchor, its genesis (the identity root), its previous (the chain link), the author's full ML-DSA-65 public key (1,952 B), and the author's full signature (3,309 B). A genesis carries only the new anchor; a second anchor's previous is its genesis.
Offline math over the carried bytes (cheap, rejects garbage before any query): the new anchor's own GUIDE, PAC_COUNT and KEYHASH with the carried 32-byte BODY rebuild its CORE (no anchor carries another author's CORE); BLAKE3(pubkey)==KEYHASH, BLAKE3(sig)==SIGHASH, the ML-DSA-65 signature verifies over the whole 512-byte anchor (SIGHASH zeroed); new, genesis and previous all share one KEYHASH (one keypair); new.PAC==prev.CORE and new.PAC_COUNT==prev.PAC_COUNT+1; dispatcher-ASI recomputed; CATEGORY owns the TYPE and a LINK sits only on a Reply or a governance anchor (a LINK makes an anchor a reply); DOC is named only by a document's own anchors, and in a document that takes their category; TIME within the 5-minute sanity window. This proves a valid signed chain under one keypair — but not that the keypair owns the Guide ID.
Mesh corroboration closes that gap and is the load-bearing check: the carried genesis must match, byte-for-byte, the canonical genesis the network holds at ASI(GUIDE) (earliest-TIME on a fork, first-claim-wins). The Guide ID is a chosen input, not derived from the public key, so an impostor can self-sign an anchor stamped with a victim's Guide ID under their own keypair — the signature verifies, but the carried genesis has a different CORE than the canonical one and the anchor is rejected with GENESIS_MISMATCH. The signature proves this keypair signed this anchor; the genesis corroboration proves this keypair owns this Guide ID. Both are required, both re-run by every receiver.
The author announces with ANCHOR_HAVE (34 B: CORE + home ASI) to the peers covering the anchor's home ASI; one that lacks it replies ANCHOR_WANT (32 B); the holder answers ANCHOR_FULL. A verifying home holder forwards the HAVE onward, deduplicated by CORE, so propagation stays inside that bucket's holders and never loops. A holder that verifies and stores the anchor returns ANCHOR_STORED to the author, which ships the payload fragments only after two distinct home holders receipt — so a published anchor is always addressable. A receipt is a push, so its absence is not evidence of absence, and it does not stay obtainable: once a holder's live window releases the cached frame the possession proof can no longer be built. An author that received none therefore asks the anchor's own bucket by CORE and adopts the result only if a holder returns bytes identical to those it built.
Against forgery, SVAP is not probabilistic: there is no committee to corrupt. A forged anchor (bad signature) or an impostor anchor (valid signature under a foreign keypair, wrong canonical genesis) dies at the first honest hop and every hop after. The private key never leaves its owner's device, so collecting others' ANCHOR_FULL packets yields nothing forgeable. The one thing SVAP does not prevent is a same-key cross-device self-fork — two anchors at the same PAC_COUNT from one citizen's two devices — which is caught at the next login by the AnchorChain walk. Bandwidth per node scales with the anchors landing in a node's one AnchorStream Index, not with total network throughput.
An ANCHOR_HAVE is reliable: it asks for an acknowledgement and is retransmitted until it gets one, so every announce is also a liveness check — a holder whose every retransmit goes unanswered is withdrawn from every selection at once, and the pair probe is left only the peers nobody is talking to. But a delivered announce can still be refused — by a holder not yet LIVE on the bucket, one whose announce budget is spent, one that was down past every retransmit — and because every receiver refuses an anchor whose TIME falls outside the ±5-minute sanity window, the live path will never carry that anchor again. A missed announce is permanent unless something re-offers it: acknowledgement alone cannot guarantee that every holder stores every anchor.
The repair belongs where the loss happened — inside the bounded live window — and rests on three mechanisms. The window is exactly the Dual-Witness Sync live zone (ten minutes at V1) and is required never to be shorter: an anchor is the live path's responsibility for precisely as long as DWS treats it as the moving edge, so a cache expiring first would open a band of anchors too new to appear in the settled root and too old for any holder to serve or receipt. First, the ANCHOR_FULL cache is the live window, and it is the only structure on a node that can serve an ANCHOR_FULL at all: it cannot be rebuilt from storage, because the persisted 512-byte anchor carries BLAKE3(pubkey) as KEYHASH and BLAKE3(sig) as SIGHASH but never the 1,952-byte public key or the 3,309-byte signature themselves, which travel in the payload. A holder that has evicted the cached frame can no longer answer a WANT for that anchor under any circumstances, and can no longer issue its ANCHOR_STORED receipt either, since the possession proof that receipt carries derives from the same signature material. The cache is therefore bounded in bytes and never in a count of anchors — a ceiling on cached frames is a ceiling on throughput wearing a memory costume, and it binds most tightly exactly when the bucket is busiest. Its floor is the window itself, from the per-bucket arrival rate: a community node holds one AnchorStream Index, and at a billion citizens a single bucket takes on the order of twenty anchors per second, so ten minutes is roughly 12,000 frames, or about 78 MB. Second, the author re-announces to home holders that have not yet returned an ANCHOR_STORED receipt, on a backoff landing inside the store-receipt deadline — a retry issued after the stall is the only one that can arrive. Third, co-holders top each other up, by fingerprint: each node periodically sends the peers holding the same bucket a LIVE_DIGEST — a time range it names and a BLAKE3 digest of each of 32 slices of the anchors it holds in it. The co-holder digests the same range from its own cache and answers only for the slices that differ, listing its COREs there; the sender then re-announces over HAVE/WANT/FULL exactly what the co-holder lacks, and every anchor is verified in full on arrival. In steady state a whole window is confirmed by one half-kilobyte message and no answer. One constraint is load-bearing: the rotation must check the window with every co-holder while each anchor is still inside the range a digest covers, because a rotation slower than that is worse than none — the anchor ages out of the only structure that could have served it before that peer's turn ever comes.
Together these make propagation reliable enough that a LIVE bucket is never re-swept on a timer. A dropped announce is repaired inside the live window that dropped it, not by periodically re-reconciling settled history — which would collapse the catch-up layer and the live layer into one and dissolve the distinction the two-layer model rests on.
SVAP verifies each anchor at birth. Dual-Witness Sync (DWS) is the replication-time integrity check and convergence engine that runs when one node copies an AnchorStream Index bucket from another. It is implemented as windowed Merkle anti-entropy — the technique that reconciles arbitrarily large datasets at a cost proportional to their difference, not their size. SVAP is birth-time verification; DWS is integrity-and-convergence during replication. This is set reconciliation over an unordered bucket — the same role a Merkle tree plays in a distributed database — and is explicitly not a blockchain: no blocks, no linear chain, no global order, no mining.
Every anchor falls into a fixed one-minute TIME window. Each window has a BLAKE3 digest over the canonically-ordered (TIME, then full-anchor bytes) list of the full 512-byte anchors it holds — not their CORE hashes alone, since CORE addresses only the payload and would leave the record's other 480 bytes uncommitted; this leaf-commitment rule is bound into the network fingerprint. Windows fold up a fixed 16-ary tree to a single root. The tree is insertion-stable — a late-arriving old anchor dirties only its own leaf plus its ancestor path — and empty spans collapse to a per-level constant, so building it costs work proportional to the number of populated windows, never to wall-clock time. Settled-window digests are computed once and cached forever.
A whole-bucket root is useless to compare — the live edge (anchors from the last few minutes) always differs. DWS splits the bucket at now − LIVE_ZONE_MS, sized as the maximum-propagation margin (~10 min at V1): any window older than it has had time to spread the whole mesh, so a settled-root match provably means “I hold everything that has had time to propagate.” The frozen settled zone is the basis for comparison; the live zone is the moving edge, received through SVAP propagation once LIVE and excluded from the comparison. Two synced nodes match the settled root in a single exchange — O(tree-depth) regardless of whether the bucket holds a hundred anchors or a hundred billion. On mismatch the node drills the tree, asking a peer for a node's child digests over the same requester-supplied window-count (so clock skew never causes a false mismatch), and recurses only into divergent children until it has localised the exact divergent windows — then pulls only those. A divergent subtree that is wholly settled, that the node holds nothing of, and that fits one staged stream is pulled whole instead of window by window, and admitted only if its bytes rebuild the exact subtree digest the holders agreed on; one that does not is drilled window by window, so the shortcut costs time at worst, never correctness. Pulls run several at a time across the agreeing holders.
Because the live zone is defined by age, not by count, going LIVE is a binary predicate on the settled root — “do I hold every window older than the margin?” — never a percentage of the whole bucket. A fraction-of-all-anchors threshold would be a perpetually moving target: anchors are minted continuously, so the denominator never settles and a node in a busy mesh could approach but never reach it. Anchoring the gate to the frozen settled zone gives a fixed, provable finish line that a node always reaches. A node may thus go LIVE and start serving while the last few minutes of the live edge are still arriving — being settled-complete, not caught up to the instant, is the correct and sufficient bar.
A divergent window is corroborated only among the peers that actually hold it; an empty or behind peer casts no vote and never vetoes a real holder. The requiredHolders threshold is pinned to identity, never derived from timing: every node requires two agreeing holders, with exactly one exception — roster index-1 (genesis_node0001), the designated cold-start bridge, may use one while it still sees fewer than two other holders. Index-0 (nateofearth2100z) solos the genesis; index-2 onward, every Keeper and every community node always require two. A divergent window is ingested only when at least that many holders agree. So if a non-bridge node can reach only one holder it does not pull and does not go LIVE — it stays SYNCING and retries when a second holder appears. It never single-trusts. The single-witness path is the one identity-pinned cold-start exception: the index-1 bridge replicates the solo'd genesis's already-validated history and becomes the second holder, so everyone after it has two to corroborate against. That is why the protocol is named Dual-Witness — two is the rule for all but one bridge identity, never a routine mode granted by timing. With two or more agreeing holders, a fabricated anchor held by a single malicious peer is contested by the honest holder and is never corroborated, ingested, or propagated. Live and historical anchors travel two separate paths: a LIVE node receives every new anchor through SVAP propagation (self-verified at receive, direct insert, no DWS — this is how two LIVE nodes stay byte-aligned), while DWS replicates only missed history; a SYNCING bucket does not receive propagation, so a multi-day backfill is never polluted by live tip-inserts. A node goes LIVE only once it is missing no corroborated settled content, and the live edge is corroborated byte-for-byte (a tampered variant under an honest CORE is a distinct key, never corroborated). The transition is a smooth handoff: reconcile the settled history, go LIVE, then a bounded post-LIVE convergence window (one live-zone) additively re-reconciles to catch any anchor minted in the handoff gap before releasing to pure cascade delivery. Each convergence pass compares live-edge window digests first and pulls only from a holder whose windows differ (a matching digest proves it holds nothing the node lacks); the pass that takes a bucket LIVE pulls the whole live edge from every holder. A live-zone anchor that a syncing node defers (only one witness) or misses is never lost: the live zone slides, so as the clock advances the anchor crosses the margin into a settled window and the ordinary settled-root compare covers it. The moving edge is thus self-healing through three overlapping mechanisms — cascade delivery, byte-for-byte pull corroboration, and aging into the settled zone as the final backstop — so nothing on it is accepted from a single source (outside the index-1 bridge) and nothing can be permanently stranded.
Cold start. The very first node has no peer to reconcile against, so declaring a bucket LIVE from local state alone (solo) is the last-resort origin primitive — never a default, and restricted to roster index-0. The cold-start ladder is pinned to identity: index-0 (nateofearth2100z) solos the genesis; index-1 (genesis_node0001) is the single-trust bridge that pulls index-0's already-validated history and becomes the second holder; index-2 onward, every Keeper and every community node require two agreeing holders and wait rather than pulling from one. Solo fires only after a short grace with no peer appearing, and a simultaneous fleet boot cannot deadlock because index-0 is the deterministic origin. No other node ever solos: the Genesis Authorities run as Keepers and hold every bucket, so a peer always exists once the network is up, and going LIVE unsynced would make it an authoritative source for a bucket it never reconciled — instead it stays SYNCING and waits. So the first node solos, index-1 single-trust-syncs from it, and everyone after dual-witness-syncs — never “all solo,” and no start-stagger is needed because a fresh network has no settled zone to wait on. Catch-up is event-driven: a node re-reconciles its buckets when peers (re)connect, so an offline node catches up on rejoin, not on a clock. Synchronisation is never time-bounded — a cold node may take days to load years of history.
LIVE is a claim with two halves: that a bucket is byte-for-byte identical to its co-holders, and that it is receiving every new anchor by propagation. A node that has lost every co-holder for a bucket is no longer doing the second — no peer can deliver propagation to it, and the live-window top-up (§11.5) has nobody to pull from. Whether it still holds thousands of other connections is irrelevant: for that bucket, it is offline.
The response depends entirely on duration, and the boundary is the live window. A blackout shorter than the window needs nothing — the top-up re-offers every missed anchor the moment a co-holder is reachable again, so a brief disconnect must not flap the bucket in and out of service. A blackout longer than the window is different in kind: those anchors have aged out of every holder's ANCHOR_FULL cache and can never arrive on the live path again, so the bucket is genuinely incomplete and the LIVE claim is false. It is demoted LIVE → SYNCING, and Dual-Witness Sync — the catch-up layer — restores it, promoting it back to LIVE on a settled-root match.
The demotion is what prevents one node's gap from becoming the whole network's. A node that keeps advertising LIVE coverage while missing anchors continues to be elected as a DWS witness, a synchronisation source, a home holder and a storage-receipt issuer for a bucket whose recent history it does not have; a cold-starting node that samples it as a witness then finds its settled digest disagreeing with the honest holders, and the window comes back contested — so one isolated node degrades the synchronisation of every newcomer that happens to pick it. Clearing the coverage bit on demotion removes it from every such election until it has caught up. It follows that total peer count is the wrong signal for liveness: a node holds one AnchorStream Index out of ten thousand, so the handful of peers sharing its bucket are a vanishing fraction of its 66,666 connections — it can lose every one of them while its overall peer count barely moves. Coverage of the held bucket, not the size of the peer set, is what LIVE asserts.
DWS validates bytes only against corroborating witnesses, not against external truth; if all witnesses collude on identical corrupted bytes the check passes — tolerated because forgery is already closed at birth by SVAP. It does not auto-delete an attacker's locally-injected anchor (anchors are immutable) — the fake simply stays inert and unpropagated on the attacker's own node. The digest tree is pure local derived state: never shipped as authoritative data, contributing nothing to the network fingerprint, with a rebuildable crash-safe-validated on-disk cache.
Payloads up to 10 GB are AES-256-GCM authenticated-encrypted, split into sacred-math-sized fragments, and distributed across the mesh via a Kademlia-style XOR-DHT keyed by the anchor's CORE. Anchors are ASI-routed; fragments are content-addressed via the anchor-scoped K_NEIGHBORHOOD, not ASI-bucketed.
coreRoutingKey = CORE_bytes(32) // already uniform via BLAKE3 peerKey(g) = BLAKE3(g.guideId) distance(a,b) = uint256(a XOR b) K_NEIGHBORHOOD = FLOOR × totalFragments closest peers to coreRoutingKey, author EXCLUDED rankFragmentIndex = sort eligible peers by distance(peerKey, coreRoutingKey); // rank r peer at rank r holds index (r mod totalFragments) // coverage-complete
Every fragment of one anchor lives in the same XOR neighborhood. Placement is by XOR rank, not an independent per-peer hash: the eligible peers (author excluded — the author retrieves through the mesh and never stores its own fragments) are sorted by XOR distance to the routing key, and the peer at rank r holds index r mod totalFragments. This is coverage-complete — whenever ≥ totalFragments non-author peers exist, the closest take indices 0…F−1 one each, so no index is ever orphaned, and each index gets FLOOR redundant holders. An independent per-peer hash could not guarantee this — it could assign every available peer the same index and leave another with zero holders (a two-fragment-genesis data-loss case) — which is why placement is by rank, not by hash. With FLOOR=20 and a 1000-fragment film, K_NEIGHBORHOOD = 20,000 peers, mean 20 holders per index; per-peer storage stays at one fragment regardless of file size (FLOOR is a launch knob: 1 on the smoke testnet, 10 at launch, 20 at the mature target). The receiver does not re-derive the rank on a FRAGMENT_STORE (the author-excluded rank is not locally recomputable), but it keeps only what opens: every store carries the anchor, each fragment's AES-GCM tag must open under the key that anchor derives, and the anchor is then discarded — the row keeps the ciphertext and the anchor's two-byte ASI, never the key. A slot already holding different bytes is decided by the network's anchor (this node's replica, else the bucket asked by CORE), so squatting an index with garbage before the author's fragments land no longer works. One sender may store at most 64 MB an hour on one holder. A store to a node with no tunnel is an offer the holder pulls by slice.
Distributed QUERY_FORWARD — the reader does not connect to the holders to find them. At a billion nodes the holders of an arbitrary CORE are almost never in the reader's own mesh, and dialing the thousands a cold lookup touches would cost megabytes of post-quantum handshakes merely to ask — fatal for a 1 KB text anchor. Instead the reader originates a ~170-byte (CORE, neededIndexes, ttl, originGuideId) query and hands it to its closest-to-CORE neighbours over tunnels that already exist; the mesh forwards it the rest of the way, each node doing O(1) work, so the cost is distributed across the mesh rather than piled on the fetcher. The candidate substrate each hop forwards toward is the live K-bucket (66 k peers) ∪ the passport cache (1 M peers); the routing table's k-buckets live in raw-Guide-ID space — uncorrelated with the BLAKE3 CORE space fragments are keyed in — so the cache is the de-facto CORE-space knowledge, and every node maintains a PeerXorIndex over it (a leaf-compressed binary trie over peer BLAKE3 keys) that returns the k peers nearest any CORE in O(k+depth) ≈ microseconds, not an O(N) scan. Each receiving node does four O(1) things: dedup by requestId against a 30-second seen-cache (the same mechanism as the gossip cascade, so a query never loops); record the predecessor so a reply can be routed back along the reverse path; answer from its exact holdings index (the floor indexes it holds, and whether it holds the whole payload) and its hint register (other holders and whole copies it has itself proven recently), replying toward the origin with its Guide ID, the indexes it really holds, its reach — IP:port, plus a relay Guide ID when NAT'd — so the reader can pull direct, those hints, and whether it keeps this CORE's register; and forward the still-needed indexes onward, ttl permitting (the ceiling is 32 hops) — an index it holds or knows enough fresh holders of goes no further. Discovery never trusts a predicted assignment — a node answers only for fragments it really holds and hints it has checked, since the author-excluded rank is not remotely recomputable. The fan-out is adaptive: NARROW (three closest) while still routing toward the CORE, and wide once a node is itself inside the anchor's K-neighborhood — detected in O(1) by its holdings index — so the query spreads across all F holders, who are XOR-close to one another, covering every index. That width is sized to what is left to find, clamp(stillNeeded, NARROW, WIDE) with a ceiling of 64, so a nearly-finished search stops recruiting sixty-four peers to locate three fragments; measured on a 26-fragment payload that cut contacts 34,131 → 12,515 at unchanged hops and delivery. Because the recursion re-fans at every in-neighborhood node, a ceiling of 64 suffices where a single-fetcher walk would need an additive per-hop ceiling many times larger. Holders in a wave reply in parallel, so wall-clock latency tracks the hop count, not the nodes touched. The at-scale measurement is npm run bench:sweep, which executes the real qfOriginate/qfOnQuery/qfOnReply in rank space — a node is only its global XOR-distance rank to the CORE, so the network size is exact at a billion instead of scaled down, which matters because in a mesh of a few tens of thousands the FLOOR×F holders of a large payload are several percent of the whole network and coverage looks perfect for reasons that vanish at real scale. Nearest-first alone is not enough, and the reason is the whole shape of the problem. A node's nearest-to-an-arbitrary-CORE sits near global rank N ÷ 1,066,560 — about 938 at a billion nodes, but about nine at ten million — so every participant in a ripple offers very nearly the same low ranks, the search converges on the innermost sliver of a FLOOR×F holder band, and the seen-cache turns the repeats into no-ops until the frontier dies. A band is 25,600 ranks wide for a 10 GB film and rank r holds index r mod F, so reaching only the inner few hundred ranks yields only a few hundred distinct indexes. Measured on the shipped engine with no complete copy anywhere, such a payload reached 33% and did not open at ten million nodes while a text anchor, a song and a 100 MB clip all reached 100%; more search budget did not help, because the ripple had saturated rather than been cut off. So a node that is already inside the neighbourhood forwards additionally to peers beyond its own XOR distance, and the wavefront sweeps the whole band instead of collapsing into its centre. The sweep is additive rather than a share of the fan — taking it out of the fan halves the in-neighbourhood breadth a replica census depends on — and the covering half carries no floor at all, because a band narrower than one node's reach is swept by that half alone and a pure outward sweep would step straight past its holders. With that, the shipped engine locates every payload from a 1 KB text anchor to the 10 GB maximum 100% of the time in a single round, at ten million, a hundred million and a billion nodes alike, from canonical placement alone — no vaulter, no cache, no source list: about 4,400 nodes asked for the film at ten million and 83,878 at a billion. Replication depth is therefore a durability property rather than a discovery one — at one copy per index a single holder leaving orphans that index permanently — while a short read remains a failure and never a partial result, because the manifest and ML-DSA signature are split across fragments and one absent index makes the stream unparseable. A short read is a failure, not a partial result — which is why the origin's deadline scales with the number of indexes sought rather than being a flat timeout, and why a short search is retried rather than accepted.
The reader keeps looking, then writes back. A whole copy answers every index, and a search that ended on the first one sent every reader of a fresh payload to its author. So a reader's search ends only when every index has two floor holders (or more, if its pull concurrency can use them) — whole copies are pulled from but never end it. Its first hop is ten peers drawn at random from the twenty nearest, so readers do not all ask the same nodes, and once covered it listens one more second. When the payload verifies, every source is proven for what it served and each register-keeping node the reader asked is sent the sources it did not already name.
Discovery and download are not separate connection phases: a reply hands back each holder's reach, so the reader pulls direct — and without connecting. A pull needs no identity: the bytes are public ciphertext, checked by their authentication tag. The reader sends its request straight to the endpoint the reach names (a NAT'd holder is reached through the relay its passport carries, and answers back through it, §19), making no peer, binding or tunnel of the holder. A holder with no tunnel to the asker first answers with a small cookie bound to the asker's address and serves once it is echoed — two small datagrams and one round trip per new holder, so megabytes never go to an address that did not ask. The reader sends a FRAG_PULL naming the indexes it still needs from that source, chosen at the moment of sending — rarest first, a fair share per source, bounded in bytes. Under the one-fragment-per-peer law a canonical holder returns exactly one fragment, so discovery and download collapse into one round-trip per holder, while a source holding the whole payload is asked only for what the canonical holders did not cover. The reader dedups returned indexes against what it still needs and stops once covered; any index momentarily unfound is returned partial and healed by census and the next reader's re-fetch. The auth tag rejects tampered bytes at decipher.final(); reconstruction abandons before any plaintext leaks.
From a stranger, a fragment is pulled by slice. An unsealed datagram is never retransmitted, so a fragment sent as one chunked message would arrive whole or not at all — a film's 4 MB fragment practically never. The reader instead asks for ranges (slice: {offset, count}); the holder answers each 1,024-byte slice in its own datagram, at most 16 a request, reading them off disk and keeping no per-reader state. The reader learns the size from the first slice, keeps a window of 2 to 32 range requests in flight, re-asks only what did not arrive (RTO 200 ms–8 s, eight tries a slice), and can resume from another source where the last one stopped — every copy is the same bytes and the tag checks the whole.
Census: every holder revisits each fragment it holds on phi-progressive backoff (1 h → φh → φ²h → … → 1 wk STABLE → 30 d COLD), counts the other holders by asking the ones its hint register names "still held?" — about thirty small probes, answered from each holder's holdings index — and ripples a count through the mesh only when they fall short; whenever the count is below the heal target it pushes copies toward it, a bounded number per round, each push carrying the holders it knows. An index whose known holders all vanish is rescued one fragment at a time, from a whole copy if that is all that is left. Placement asks first with the same probe, so no holder is handed two indexes of one anchor. The author places FLOOR copies of each fragment (10 at the launch profile); census takes the fleet to the heal target (32). Nothing is exempt: demand does not modulate census, because only this tier is durability. A push carries the anchor, fetched once per round from the bucket the row's ASI names: the holder first checks its own copy against it — junk is dropped, never spread — and the receivers check the tag with no query of their own.
Every payload fragment is sealed with AES-256-GCM. The format on disk and across the mesh is the raw bytes IV(12B) ‖ TAG(16B) ‖ ciphertext — no text encoding in either place. Key plus base IV are derived once per anchor via BLAKE3(CORE ‖ SIGHASH ‖ PAC); each fragment's 96-bit nonce is BLAKE3(baseIV ‖ fragmentIndex)[:12]. Decryption is fail-closed.
Durability is the placement FLOOR plus whoever chooses to keep it. Three tiers hold fragment copies and contribute differently. xor_storage is the canonical network-duty tier — the FLOOR closest-rank holders per index, healed back to FLOOR forever by census; the guaranteed floor, present regardless of demand. It is the durability/immortality guarantee — every anchor, cold or hot, survives on its FLOOR. vault is permanent citizen pins: a vaulter snapshots all fragments locally, adding one permanent copy to every index. viewer_cache is the serving tier — LRU-evictable copies a reader keeps after reconstruction; transient, raising serving capacity, not durability. Viewing never creates a permanent copy: xor_storage is populated only by placement and census, never by what a citizen reads.
Permanent per-index redundancy is therefore R = FLOOR + vaulters. Payload recoverability under per-holder availability a is P = (1 − (1−a)^R)^F, where the fragment count F is a coupon-collector exponent: every one of the F indices must keep a live holder, since every fragment is needed to reconstruct — which is why file size governs durability and not only discovery. Modelled over the tiers, a 1 GB file (F=363) at FLOOR=10 recovers ~100% / 70% / 0% at 80% / 50% / 20% holder availability; a 10 GB film (F=2,560) recovers ~100% / 8% / 0%. The bare floor is ample for a healthy mesh (availability ≥ 80% recovers everything) but the coupon-collector tax makes a multi-thousand-fragment film genuinely fragile under heavy churn. Two knobs close that gap: for content people care about, vault is the lever (5 vaulters lift the 10 GB film from 8% to about 92% at 50% availability, 20 past 99%, 100 to durable even at 20%); for huge cold archives nobody pins, the lever is the FLOOR profile itself (PRODUCTION_20 / _32). Cold content nobody pins or watches sits at exactly the FLOOR — census keeps it there, which is the point: the vast majority of anchors (a vote, a one-shot update) are never re-fetched after going live, and their immortality rests entirely on the census-healed FLOOR. The serving tier scales inversely: a viral payload with V recent viewers spreads the pull across up to V transient cache holders, so popularity speeds the fetch (per-holder load → F/V). Popularity buys speed through viewer_cache; durability comes from the FLOOR plus voluntary vaulting.
The three tiers above are only as useful as they are reachable, and two of them are not. Fragments are placed by XOR distance, so the canonical holders sit beside an anchor's CORE and every search arrives at them. A citizen who vaulted a payload — or who merely watched it and still holds it cached — sits at BLAKE3(their own Guide ID), a position with no relationship to that CORE. They can serve every index, but no hop of a CORE-directed search ever routes to them. Measured over a modelled mesh: zero of fifty vaulters and zero of five hundred cached copies reached, at every network size.
The fix is a register, kept where searches already go. Each node keeps a hint register for the COREs it holds part of and those it is among the twenty nearest to — floor holders and whole copies, each with the day this node last proved it — and any query passing through reads it. A peer is stored once and every entry points at it, about ten bytes an entry, sized to the machine's RAM. It stays true by checking, never by broadcast: nothing is announced when a copy goes away; a hint is handed out unchecked only while this node's own proof of it is under seven days old, and anything older, or merely heard, is first asked "do you still hold it?" and deleted on a no or on silence. It learns only from traffic that happens anyway — placement seeds every holder's register, census pushes carry it, replies passing through are filed, and readers write back what they proved — so popular content becomes easier to find as it spreads rather than concentrating on whoever seeded it.
A complete copy is the best thing to find and the worst thing to drain. One hit on it answers every index at once, which is precisely what makes discovery independent of fragment count. But rank it first for bytes and every reader pulls the whole payload from that one node: a ten-gigabyte film served to a thousand citizens is ten terabytes out of a single uplink — worse than the problem the register was built to solve. A canonical holder is the opposite: it carries one fragment by XOR rank, exactly the load the placement law sized for, and there are FLOOR × F of them.
So the reader schedules the fetch: canonical holders carry the bulk, complete copies fill only the gap routing could not reach, and several complete copies split that gap between them. More complete copies therefore mean less work each rather than a bigger target. Within a request the scarcest indexes go first, so a fragment only one node can serve is taken while that node is in hand, and each request takes roughly its fair share of what remains — without that, the first complete copy reached would claim everything. The ceiling on a single request is denominated in bytes, not rows, because fragment size grows with payload: a fixed row cap bounds two megabytes of a text anchor and a gigabyte of a film. It shapes each request without ever refusing delivery, since a source is simply asked again for the rest — a payload missing one index does not open at all.
The decision is made when each request is sent, not once at the start. An assignment written before the first fragment lands is stale immediately: sources hand back more than they were asked for, and every early arrival makes some later source's share redundant, so a frozen plan re-requests fragments already in hand and pays for them twice.
Searching and downloading run together. The reader does not wait for the search to finish before pulling: holders stream back as replies arrive, the schedule absorbs them mid-fetch, and the download keeps spreading across nodes as more are found. Phasing the two would cost the entire search window on an idle link, because nothing about the first holder found requires the last one to be known.
The Personal Anchor Chain (PAC) is the only chain in PHEUN that is cryptographically walked. It is per-Guide-ID, append-only, pinned by a 32-byte pointer (PAC, bytes 125–156) and a 7-byte monotonic counter (PAC_COUNT, bytes 157–163) in every anchor.
anchor_n.PAC = BLAKE3(anchor_{n-1}.bytes)
anchor_n.PAC_COUNT = anchor_{n-1}.PAC_COUNT + 1
fork detected ⟺ ∃ a, b : a.GUIDE = b.GUIDE
∧ a.PAC_COUNT = b.PAC_COUNT
∧ a.CORE ≠ b.CORE
The chain is walkable, bounded by a hard cap of approximately 50 years × 144 anchors per day = 2,628,000 anchors per Guide ID — large enough for a lifetime, small enough for tractable login walks.
pacWalker.walk(guideId) before the session is issued. The walker pulls every anchor under the citizen's Guide ID via the global query engine, filtered by guide + pacCount range. A fork detected mid-walk writes a pac_locks row, refuses the login with HTTP 423, and surfaces the locked-Guide-ID modal.SUBSCRIPTION_FORWARD within 1–120 s; the forward is never trusted itself, it makes the node run the authenticated walk, so a cross-device fork is confirmed the moment the conflicting anchor arrives. The currently-authenticated session is killed at the next request via the request-time PAC lock check.pacState.ingest with mintedLocally=true before the gossip cascade, so the dropdown indicator distinguishes "you published" from "another device published".Every node walking the same chain arrives at the same fork verdict independently. There is no broadcast, no admin override, no recovery path. Locked Guide IDs are dead by design. The citizen creates a new Guide ID; the sealed history remains readable but inert. The device-binding lock file (data/guide-id.lock) is cleared by the human physically present at the device — there is intentionally no network endpoint to release it remotely.
PHEUN has one governance system, and each governed document runs it in its own category. The Constitution is governed in Democracy (cat 0x04: 0x60 Proposal / 0x61 Vote Yes / 0x62 Vote No / 0x69 Tally Checkpoint / 0x6A Consensus Approved / 0x6B Consensus Denied); the Curriculum in Education (cat 0x03: 0x52 / 0x53 / 0x54 / 0x55 / 0x56 / 0x57, role for role). The routing, gates and count are the same; CATEGORY and TYPE say what an anchor is, DOC which document.
DOC is one byte holding an id from a registry compiled into every node: 0x00 no document, 0x01 Constitution, 0x02 Curriculum, 0x03–0xFF unallocated. There is no user-typed document name anywhere in the system, so there is no uniqueness race and nothing to squat — every node resolves 0x01 to the same document at compile time.
This is a deliberate narrowing. A free-form name could not deliver the property a governed document actually needs: that every citizen is reading, amending and voting on the same one. Two citizens who wrote constitution and Constitution opened two documents; two who raced the same name from opposite sides of the mesh opened two that both looked canonical, and — anchors being permanent — both persisted. The name also became the prize, accruing to whoever minted first.
A document's first anchor can be minted only from that document's own page, the sole surface that knows which document it is, and the mint refuses any non-governance anchor carrying a non-zero DOC. Adding a document costs a registry row, a page and a nav slot — an additive, soft-fork-class change, since the registry is not a network-fingerprint input and an older node simply renders an unrecognised id as no document while still verifying and storing the anchor. The cost is deliberation, not machinery: a new institution should be a code change someone argues for, not a form submission.
A document is opened once, and the check fails closed on both sides. One query at ASI(DOC) returns every opener for a document, and that query has three outcomes rather than two: an opener exists; no opener exists and holders answered; or nobody answered. Silence is not absence — treating an unanswered query as "unopened" is what mints a second opener for a document that already exists. So the read reports whether its answer was proven, and both callers refuse an unproven one: the mint returns GENESIS_EXISTS when it can prove an opener exists and GENESIS_UNVERIFIABLE when it cannot prove one is absent, and the page offers "open this document" only on a proven absence — and stops offering it the moment this citizen's own opener is signed, because an anchor is not queryable until its home holders admit it, and that gap is exactly when a duplicate gets minted.
Propagation deliberately does not enforce this. Rejecting a duplicate opener at the wire layer would be arrival-order dependent — a holder that had seen the sibling would refuse while one that had not would accept — so two honest nodes would disagree permanently about a bucket's contents. Uniqueness that diverges the mesh is worse than none. The reader is decisive instead: partitioned nodes can each mint an opener and both anchors persist forever, so every node picks the canonical one by the same pure rule — earliest TIME, CORE ascending to break a tie. The tiebreak matters because TIME is milliseconds and real ties happen; without it the winner would be whatever order a query merged results in. With it, every node renders the same document and the loser is inert.
LINE=0.LINE = max(existing LINE) + 1, LINE_VERSION=1.LINE_VERSION = max version for LINE + 1.0x6A for the Constitution, 0x56 for the Curriculum) makes a proposal the line's next official version; official versions are numbered in the order approvals landed.Approval requires 75 % YES of first ballots cast within the voting window (7 days) and the participation quorum. Each citizen votes once: holders count only a voter's earliest ballot, and the minting node refuses a second. Because propagation refuses anchors dated more than five minutes off, a closed window's ballot set is frozen, so every complete count of it is the same number. During the window anyone — voter or not — may publish a Tally Checkpoint (0x69 / 0x55), at most once an hour per proposal: a published count, never a vote. After the window any citizen may seal the verdict (0x6A / 0x6B, or 0x56 / 0x57 for the Curriculum); the node refuses it unless the window is closed, no verdict exists, its own count (two agreeing holders per bucket) is complete, and that count supports the verdict. There is no auto-finalisation.
Readers judge; propagation does not count. Counting at admission would make it depend on each holder's view and fork the stream. Instead any citizen can Verify a verdict: their node recounts and compares verdicts, not percentages — Verified match, Verdict verified (counts differ, verdict agrees), Potential fraud (a complete recount supports the other verdict) or Not verified yet. A verdict found fraudulent never stands on that node.
PHEUN ships without age check, ID upload, phone binding, email confirmation, or any pre-participation gate. The Digital Constitution itself is an anchor; rules of conduct can be added, amended, or rescinded by the citizenry at the 75 % threshold. The protocol enforces nothing technically — enforcement is social, legal, and constitutional, never coded.
There is no algorithmic feed in PHEUN. There is no recommender, no engagement-optimised ranking, no editor, no human moderator, no content team. Discovery is the protocol itself: a citizen subscribes to the Guide IDs, hashtags, documents, LINK branches and Origin Streams they care about; every future matching anchor flows back into their feed in 1–120 seconds.
mention_<your guide id> and that is your Public Inbox.A citizen follows at most 300 things, every type alike, plus their own Guide ID (never refused). The list travels as one binary contract — a type byte and the anchor-field bytes per entry, canonical order, ~10 KB at the limit — sent on SUBSCRIPTION_FORWARD to one holder per ASI, chosen by a rendezvous hash of (subscriber, holder, ASI) over the bucket's proven holders. The same bytes go to every holder, once per holder; each holder carries about ASI_COUNT contracts. A holder forwards a match at SVAP arrival as one 512-byte deliver; the subscriber takes it only from a holder it elected and only when it matches, shows it from memory, and never writes it to the AnchorStream table.
Nothing moves at idle: no refresh, no expiry. The probe to each elected holder carries the 8-byte contract fingerprint; a holder holding another (or none) sends request. A change goes as a delta; a holder's restart re-sends the whole contract. A full holder (past 4 × ASI_COUNT contracts or 64 × ASI_COUNT entries) answers refuse, keeps the subscriber's own Guide ID, and the bucket elects its next-ranked holder. There is no per-value cap. Messages: contract, delta, request, refuse, release, deliver.
Every search, feed back-fill, research lookup, governance count, profile pull, and lineage query in PHEUN flows through a single unified two-phase per-Sacred-Index fanout.
Phase 1 — Announce and count. The engine sends one QUERY_ANNOUNCE per AnchorStream Index, addressed to a peer covering that ASI. Each announce carries the queryId, the ASI, and the filter. The covering peer runs a count-only query against its local ASI bucket using SQL field extractors that map filter fields to indexed Postgres expressions. The peer replies with QUERY_COUNT_REPLY. Per-peer announce timeout: 2 seconds.
Phase 2 — PHI-allocated pull. With per-ASI counts in hand, the engine allocates the pull budget across ASIs by the golden ratio. The budget comes from the read's contract (§17.2). When the matched anchors exceed it, no single peer ships more than floor(budget / phi) — so no peer dominates a contested result. That cap applies only under contention: when everything matched fits inside the budget there is nothing to ration, and capping a peer that happens to hold most of it would discard anchors the query asked for and nobody was competing over.
A pull is continued, not issued once. QUERY_PULL carries an offset, and a peer answers at most a fixed number of anchors per request — a bound on the work one request may ask of one peer, not on what a query can retrieve. The requester resumes from where the previous reply ended until the peer is exhausted. Deadlines scale with the work requested rather than sitting at a flat 8 seconds, because a peer answers in paced pages: for a large read the pacing alone outlasts a timeout sized for a feed, and the pull would die and return a partial while reporting nothing wrong.
A read is one of exactly two things, and conflating them is what let six separate layers each pick their own limit without knowing about the others.
A slice is a page of something larger. Feeds, searches and comment threads are slices, and the cap is a decision about the citizen rather than about correctness — ten thousand anchors is more than anyone reads at once, so coming back capped is the expected outcome and nothing is wrong when one is short. A thread is a slice because replies dispatch to ASI(LINK): a widely-read anchor gathers as many children as the world writes, and "showing 50 of N" is the honest shape of a page.
A complete read is the opposite: the subject is the answer, so a silent partial is not smaller but wrong. A Constitution missing its recent amendments does not look truncated — it looks as though those amendments were never made. Complete reads retrieve everything they can, repair what did not arrive, and are then honest about the rest. None is ever cached short.
A Guide chain proves its completeness rather than asking for it. PAC_COUNT is monotonic from one with no gaps, ever, so the anchors that arrived say for themselves whether any are missing — checked locally, trusting no peer's count, which can be wrong in both directions. Because the proof names the missing positions, the repair re-pulls exactly that span rather than a lifetime again. Anything still absent is reported alongside the chain and shown to the citizen: a document that cannot be read whole is refused, because a governed text rendered short misinforms everyone reading it, but nearly all of a citizen's history beats an error page, and a named gap is one refresh from repair.
Every filter family exists in both forms. Exclusions answer "not this" — Guide IDs, categories, types, tags, languages, age ratings, zones, documents, hashtags, AnchorStream Indexes. Inclusions answer the question a person actually asks: show me this. The positive half is not a convenience: with subtraction alone, narrowing to one subject means excluding the other 255 tag codes across ten slots per anchor, which is 2,550 conditions to express "show me art" and inverts the shape of the question.
They compose by conjunction, with exclusion as a veto — asking for art while excluding violence drops an anchor carrying both, which is what a person means by that pair. Within a list the semantics are disjunctive, and a separate intersection form requires an anchor to carry all of a named set. That is the difference between browsing and research: a union of three tags widens as the list grows, an intersection narrows, and narrowing is the only way to isolate a small body of work out of a century of anchors.
Even the AnchorStream Index this node owns is queried through an outbound announce-and-pull cycle against the peer that covers it. A node with one AnchorStream Index cannot trust itself as a query source. Every query is a network operation. Two nodes issuing the same query at the same time, with the same passport-cache view of covering peers, get identical results modulo per-peer flake.
Per-user in-flight cap: 8 queries. Node-global in-flight cap: 512. Per-peer outbound rate is bounded by the query egress limiter (240 capacity / 60 refill per second). Two queries with the same filter hash within a 5-second window share one network round; the second enters as a rider and resolves with the first's result. Coverage report on every result makes partial-mesh queries explicit rather than silently truncating.
A fanout costs seconds of wall time and touches thousands of peers. Issuing one every time a citizen re-sorts a column, navigates back to a page, or relaunches their browser would be indefensible — for the citizen and for the thousands of peers who answer. So a query's result is held in the node's RAM and re-read from there. This is the read-path expression of Vision principle 25 (the cache is the fanout engine), and it is possible only because of principle 7 (1:1:1:1). In a conventional web architecture the server is shared by strangers, so per-user result sets must be recomputed or paid for out of a shared budget. In PHEUN the server is the user: one operator, one node, one long-running process with gigabytes of free RAM, while the browser in front of it is disposable. A module-level store is not an optimisation here; it is the correct data structure, because there is no other citizen's data to isolate it from.
Five namespaces — feeds, global searches, Guide chains, documents, comment threads — each entry stamped with when its underlying mesh pull actually ran. Nothing in it is durable. A citizen's vault and their notifications are the only state that survives a node restart, because they are the only state that cannot be re-derived; everything here is a snapshot of a mesh query, so losing it costs time, never data, and it re-warms on the next read.
Eviction is three-stage, and the unit is bytes rather than entries. Entry sizes differ by two orders of magnitude across surfaces: a feed or a search is a slice capped at 10,000 anchors (~15 MB), while a Guide chain is a complete read of an entire life and grows for as long as the citizen publishes. A few chains would consume the whole node budget and evict every loaded feed on the way, so counting entries can never bound memory. Nothing short is ever stored, so a later reader cannot inherit someone else's failed fanout. Each stage evicts least-recently-used: a per-namespace entry cap, so no surface crowds out another; a per-namespace byte ceiling, so an enormous Guide chain displaces older chains and not the citizen's loaded feeds; and a node-wide byte budget as the hard backstop. The entry just written is never the victim.
Because anchors are immutable (principle 20), a cached result is a strict subset of the truth rather than a contradiction of it — stale, never wrong. That is what makes serving it acceptable at all. It is surfaced rather than concealed: every cached surface shows the age of its underlying pull, and a fresh fanout is always an explicit ask. Documents cache their raw anchors rather than the assembled outline and re-derive the outline against the current clock on every read, so a proposal's voting window opens and closes correctly even while the pull beneath it ages.
A read that queries the mesh requires an authenticated session. Anchors are public by construction (principle 28), so reading one carries no permission; but causing a node to fan out across every AnchorStream Index is a bandwidth-amplification vector against the citizen who owns that node, which binds a public interface. Every route that originates a mesh query requires a session. The one sanctioned exception is the Guide ID uniqueness check, which necessarily runs before any Guide ID exists to authenticate with.
Three physically separate tiers, each with a distinct purpose, eviction policy, and read priority.
Cache appears in two unrelated senses in this paper. This section concerns the on-disk payload fragment tiers — encrypted ciphertext chunks of anchors' payloads. §17.6's anchor cache is an in-RAM store of query result sets — 512-byte anchors, not payloads — and is never persisted. The two share no code path, budget, or lifetime.
| Tier | Table | Purpose | Eviction |
|---|---|---|---|
| Tier 1 | vault_collections / vault_members / vault_fragments | Citizen-permanent personal store. 512-byte snapshot + encrypted fragments. Pinned anchors render offline forever. | Never (citizen controls). |
| Tier 2 | anchor_fragments (origin = viewer_cache) | Fragments fetched to view, plus the citizen's own anchors once placed on peers; speeds the next view and makes this node a source. | By value — least demand, then least recently used, then oldest. |
| Tier 3 | anchor_fragments (origin = xor_storage) | Network duty — fragments held because this node is closest by XOR rank. Held in trust for others; never the citizen's own material. | Permanent (reject new placements at budget). |
Read priority: vault → any local fragment row → mesh fetch. A fragment already on this disk is used whatever tier filed it, because authenticity is settled by the AES-256-GCM auth tag at decryption, not by a label. Isolation is about ownership, not reading: network-duty bytes are never evicted by the cache sweep, never counted against the cache budget, never surfaced as the citizen's own material, and never released by a personal storage decision — but refusing to read them is not isolation, it is re-downloading what the node is already holding.
Vaulting therefore never re-downloads bytes this node has. Each candidate row must pass the auth tag before it is vaulted — strictly stronger than the origin filter it replaces, since a label says nothing about contents — and once the vault is complete the anchor's now-unreadable cache rows are released, so keeping a 10 GB film costs 10 GB rather than 20.
The node measures its RAM and free disk at boot and sizes every budget from them. Disk, less a 10 GB OS reserve, is shared out: half to its ASI bucket (never evicted), a quarter to network-duty fragments, 15 % to the vault, 10 % to the viewer cache. Half of RAM is the working budget — passport cache and SVAP live window first, then the anchor cache (55 %), the core registry (30 %) and the holdings index (15 %).
class RAM free disk MINI ≥ 4 GB ≥ 50 GB (the minimum — below it the node warns and still runs) MOBILE ≥ 4 GB ≥ 100 GB LAPTOP ≥ 8 GB ≥ 250 GB DESKTOP ≥ 16 GB ≥ 500 GB
Citizens override at any time via Settings → Storage; vault overflow returns HTTP 413 with a pointer to the slider, never silently drops content.
Every node either runs as CLIENT (inbound through its primary relay host, with one warm spare) or HOST (publicly reachable, accepts slot reservations) — same code, same protocol. Nobody chooses and nothing is set: a node strangers can reach is a Host, one behind NAT needs a relay and is a Client, and it moves between the two by itself. Behind a router, the mesh's reach test finds out whether strangers get through anyway (a forwarded port): four tunnel peers each pass a one-time code to one of their own peers, which sends a small REACH_PROBE to the address the passer sees the node at; two such probes arriving from addresses the node never sent to make it a Host, re-proven hourly. Relay slot tokens are unguessable BLAKE3 of host secret + owner Guide ID + counter; one sender past 1,000 forwards a second has only its excess dropped, so a fast transfer slows and nothing else is touched, and the slot rotates (30 s cooldown) only when every sender together passes 5,000 a second — a flood. A client ranks hosts by a coarse reliability band and then by rendezvous hash of its Guide ID with each host's, so clients spread evenly over every host.
A CLIENT is reachable by people it has never contacted: a stranger holding its contact code sets up a session with it through its host (the signed session exchange, §9), and the message or call that follows rides Triple Sentry, whose final hop delivers through the host. Another client becomes its peer through both hosts: the handshake rides a forward to the client's slot, naming the asker's own (§9.13). A message that may travel unsealed is forwarded as a message; a sealed-only one crosses as its whole sealed datagram (RELAY_SEALED, 0x57) once the client has been quiet past 25 s, or always to a client held at its slot, handed on unopened and opened by the client under the tunnel its 4-byte relay tag names. Both legs are relayed datagrams that name no sender (§9.2) — 12 bytes of wrapping in, 7 out, where a Guide ID cost 24 and 19 — so the host never learns which Guide ID is speaking. A forward of anything else names no origin in its envelope — the host names the datagram's sender on what it delivers — and everything a relay forwards stays end-to-end encrypted above it.
A fragment request crosses with its way back. A holder behind NAT must answer readers and placers it has never met, so the host hands it each fragment store, pull or census probe as a RELAY_DELIVER (0x59) carrying a return token — the slot, the address the host saw the asker at, and BLAKE3(hostSecret ‖ tag ‖ slot ‖ port ‖ slice ‖ address)[0..16] over a two-minute slice. The holder answers inside the token (RELAY_RETURN, 0x58), and the host, checking that the answer comes from the slot's owner under its own current MAC, delivers it to that address; the far end answers again through the slot. The host keeps nothing per request. The holder's cookie and per-asker budget bind to the token's address, so a spoofed asker draws one small cookie and never fragment bytes; a token serves only its own slot; and one slot may send one destination no more per window than a reader pulls from one holder. A holder offered a fragment pulls it back through its relay the same way, so an offer never reveals where a node behind NAT lives.
Every wire byte is classified into one of 13 flow classes (DM, CALL_SETUP, CALL_MEDIA, FRAG_SMALL, FRAG_LARGE, QUERY, GOSSIP, PROPAGATION, SYNC, RELAY_FORWARD, RELAY_OUTBOUND, OVERHEAD, DISCOVERY). Both ends of a link count the same way: each message body under its class, and the framing around it — header, packet number, GCM tag, frame and chunk headers, piggybacked acknowledgements — together with the protocol's own duty (handshakes, probes, session exchanges) as OVERHEAD. Counts are per direction and deliberately never per peer — a record of which Guide ID exchanged how much with this node is the traffic profile the protocol avoids creating. Two integer adds per packet on the hot path; persisted hourly to data/bandwidth-history.bin as a 90-day rolling window.
The only budget gate is on the RELAY_FORWARD class, which counts both legs of every forward. The operator picks a monthly budget in the boot menu (100 GB to 5 TB, or the device default: MINI 100 GB / LAPTOP 500 GB / DESKTOP 1 TB / SERVER 5 TB). At 95 % of it the Host refuses new slots and stops extending the ones it holds, so each ends within 24 h and its client moves to another host. No mid-transfer kills, ever. A full host evicts only a slot whose owner stopped its keepalives. DM, calls, fragments, queries, gossip, propagation, and sync flows are never throttled.
PHEUN extends through three orthogonal channels, all additive, none of which touch the network fingerprint. The wire format is byte-frozen for the lifetime of V1; new features ride alongside the old ones rather than replacing them. PHEUN does not implement a hard-fork mechanism, by design.
ASI(CORE) rule for unknown subtypes; new nodes process the subtype with its dedicated rule.The four selector bytes (SIGHASH_ALGO, KEYHASH_ALGO, PAYLOAD_CIPHER, SIG_ALGO) are the cryptographic upgrade lane. A future post-quantum signature lands at SIG_ALGO = 0x02, with 0x01 continuing to be served forever for V1 anchors. CLIENT_VERSION at bytes 412–413 is the minting protocol version — not a digest input — letting readers branch on the version that minted an anchor.
A new feature becomes live when the network's readiness signal crosses a 95 % threshold across two independent sources: the anchor signal (of the newest 1024 anchors in the node's home bucket, the share carrying the new client_version or free_schema) and the handshake signal (of cached + connected peers, the share advertising the feature in their handshake envelope). Both must clear independently. Activation is a pure local decision; every node walking the same anchor stream and the same passport cache arrives at the same activation verdict deterministically.
The three channels plus the algorithm selector bytes plus the CLIENT_VERSION dispatch cover every realistic protocol-evolution scenario without rotating the network fingerprint or invalidating stored anchors. PHEUN is not a blockchain — it has no consensus rule that needs to change, no block size to bump, no transaction format that needs retroactive replacement. The 512-byte anchor is the wire identity; changing it is creating a different network, not upgrading PHEUN. If a community ever ideologically forks, that's a sibling network running its own fingerprint, not a PHEUN-mediated upgrade.
Every anchor on PHEUN can carry a payload, and one specific payload format is the PHEUN Site — a static, immutable, cryptographically-signed, mesh-distributed page primitive that replaces the centralised Web 2 page substrate.
Sites are deliberately constrained. Every site is a single-page scroll. No multi-page navigation; no live data; no in-site media playback (clicking a pheun:// link to a video anchor opens the standard payload viewer); no user-supplied JavaScript or CSS escape hatch. The constraints are not deficits but design choices: a static, immutable site has a known set of bytes, a known signature, a known author, and a known content for the rest of time. Live content would render differently to different viewers depending on when they loaded — defeating the determinism that PHEUN's other layers depend on.
A site is composed from a fixed registry of 31 component types, each a platform-trusted React renderer that takes structured data and draws UI. The author writes the data, not the code. Components fall into eight families: visual headers (Hero, Spotlight, Stat Cards), anchor rendering (Anchor List, Grid, Gallery, Ranked List), text and citation (Text Block, Quote Block, Citation Block, Inline Image, Table), education (Quizzes, Flashcards), identity and social (Bio Card, Subscribe, Contact Card), catalogue (Catalog), governance (Pros and Cons, Position Card), and layout and page furniture (Table of Contents, Timeline, Event Card, Call to Action, Accordion, Button Row, Feature Grid, Divider, Countdown, Marquee, Footer). The renderer is platform code; citizens cannot ship custom JavaScript or CSS, eliminating the user-supplied-script attack surface.
Fifteen templates (Profile, Gallery, Library, Article, Document, Showcase, Directory, Event, Manifesto, Landing, Course, Proposal, Link-in-bio, Contact, Help) and ten themes (Midnight, Ocean, Forest, Solar, Light, Civic, Tape, Terminal, Aurora, Print) ship as starter section sets and CSS variable schemes. A site's payload is a .pheun.zip archive containing a manifest JSON and an assets/ folder of images; the ZIP is fragmented and distributed via PayloadWeave like any other payload.
A site carries no marker byte in the anchor, and needs none. It is not a destination in the way a domain is — it is one way of presenting a payload, alongside markdown in a text block or the fields of an event card. An author who wants readers to know a site is attached says so where every anchor already says what it is: the title, the 64-byte preview, the hashtag, the avatar. Spending an anchor field on "this one is a site" would rank a rendering choice alongside authorship and time, and it would imply one site per citizen — where in fact a citizen keeps as many as they have purposes, each its own payload.
One human approximates one Guide ID, enforced by two compounding floors that emerge from the protocol's own design.
There is no PoW, no stake, no captcha, no phone-number binding, no KYC. The protocol does not punish attackers; the storage curve does. Per-IP passport caps, egress limiters, and SVAP self-verification cover short-horizon coordinated attacks. Persistent peer reputation (24 h default + permanent ban entries, atomic temp+rename writes to data/ban-list.json) survives node restart; cross-node ban gossip via PEER_BAN_ANNOUNCE is reserved for a future coordinated upgrade.
PHEUN has no cryptocurrency, no gas fee, no staking, no paid-node incentive, no premium subscription, no advertising plane, no platform-level currency, no marketplace operator, no payment processor.
Resource sharing happens through the economy anchor category — a citizen publishes an economy anchor offering compute, bandwidth, storage, physical goods, or services; the counterparty arranges fulfilment through direct messaging or calling. Pure peer-to-peer barter and exchange, expressed as anchors. The protocol is the medium; humans handle the transaction.
The 512-byte anchor is public and permanent by design — it is the ledger. The payload it points to is AES-256-GCM-sealed with a key derived per anchor; the mesh stores ciphertext fragments. Citizens agree to the Digital Constitution with every anchor they publish, which forbids illegal content as a matter of social contract. There is no filter, no ban list, no takedown, no content-hash allowlist, no flag, no moderator, no admin, no report button, and no CORE-hash refusal. If illegal content is uploaded, it stays — because no mechanism exists to remove it and none will ever be built. This is the cost of an open permissionless network and PHEUN owns it fully. Enforcement is social and legal, never technical. GDPR-style erasure is satisfied by key destruction (the payload becomes unreadable), never by anchor rewrite.
The AnchorStream itself is the discovery layer (§16). Subscribe to a Guide ID, hashtag, document, LINK branch, or Origin Stream and every future matching anchor flows into your feed in 1–120 s. Word-of-mouth share of a 16-character Guide ID unlocks discovery of every anchor tied to that identity — past, present, future. No central index, no search-engine dependency, no advertising auction, no boosted anchor.
A Guide ID is a claimed name, and the handle race is real — what is missing is the market around it. The handle is input 1 of the nine (§3.2), chosen by the citizen and claimed first-come-first-served, with the uniqueness gate at ASI(GUIDE) and earliest-TIME resolution inside the propagation window. A desirable name can be taken before its obvious owner arrives, exactly as in DNS, and the protocol does not pretend otherwise. What it removes is every mechanism that makes squatting profitable or reversible by an authority: no registrar (no fee, no renewal, no expiry, no arbitration, and no entity that can revoke, reassign or seize a name — including us); no resale, structurally, because the handle is one of the nine seed inputs and so selling it would mean surrendering the whole identity and every anchor it has ever signed; and no impersonation, because the keypair matching a genesis KEYHASH needs all nine inputs, not the public one. Names are first-come and squatting is possible; squatting has no exit, and no authority can undo it either.
Keepers are nodes whose operators started them to hold every ASI (npm run node:start:keeper); they are regular nodes that happen to hold every ASI, counted by their LIVE bitmap bucket by bucket like any other node, and nothing but the start command makes a node one. The three Genesis Authority Guide IDs (nateofearth2100z, genesis_node0001, genesis_node0002) run as Keepers during bring-up and hold the cold-start relaxations. The 3-per-ASI coverage invariant counts every holder alike and gates nothing. A new profile answers a different question: it is stored only once every ASI has two live holders besides the creating node — the receipts its genesis needs — a floor, never the target; index-0 needs none and index-1 needs one on the way there.
bootstrap_active(node) = is_genesis_authority(node.guideId)
When every ASI has ≥3 live holders, the bootstrap-status endpoint reports coverage satisfied; which nodes keep running is the operator's call (npm run node:stop). Nothing toggles on that signal — an automatic switch flaps on every brief dip and leaves the holder set non-stationary — so stopping a Keeper is an operator decision. Training wheels, not architecture. Production code must work in a community-only mesh with zero bootstrap nodes.
3 holders × 4,096 ASIs = 12,288 edges (coverage target; 8,192 at the floor of 2) budget = 60,000 mesh + 6,666 reserve = 66,666 left over = 54,378 (multi-coverage / heavy peers / bursts)
Every holder counts alike — a node holding one ASI and a node holding all of them are the same kind of node. Two holders are what correctness needs (two receipts for a birth, two agreeing Dual-Witness Sync witnesses); the third is the spare, so an ASI below three is already re-checked by targeted LOCATE every 15 seconds, with the passport cache supplying candidates to heal transient dips. Three per bucket is why 4,096 buckets: coverage costs 12,288 connections, a count a node behind NAT can hope to keep, where 10,000 buckets would cost 30,000.
What each subsystem defends against, and what it explicitly does not.
| Subsystem | Defends | Does NOT defend |
|---|---|---|
| ML-DSA-65 signature | Anchor origin authentication; binds Guide ID to Genesis Profile via KEYHASH. | Signing-key leak, insider Guide-derivation bypass. |
| ML-KEM-1024 session | Pairwise confidentiality + integrity vs. quantum adversary. | Compromised endpoint, stolen device key. |
| AES-256-GCM payload | Bit-flip detection at decipher.final(); reconstruction abandoned before plaintext leaks. | Holder of the derived AES key (any peer with the anchor). |
| Triple Sentry onion | Content and final destination from every hop but the last, for the 6 onion-wrapped packet classes (DM, the 4 call-control types, WebRTC signalling); no identifier shared across hops; type and length within a size class, by padding. | Timing correlation between colluding hops; a hop's position from the size it receives; sender identity from any one of 3 relay hops; coordinated all-three-relay compromise; global passive adversary; subscription forwards, which are sent direct; live call media, which never enters the mesh (WebRTC DTLS-SRTP) — only call signalling is wrapped. |
| SVAP self-verifying admission | Forged + impostor anchors die at every honest hop — re-checked by every receiver, not probabilistic. | Same-key cross-device self-fork (caught at login); the author's own signing-key theft. |
| Dual-Witness Sync | Windowed Merkle anti-entropy: a divergent window is ingested only when 2 independent witnesses agree on its digest, so a fake on any single peer is never corroborated and never propagates. | An all-colluding witness set serving identical corrupted bytes (tolerated — forgery is closed at birth by SVAP); cross-session reputation. |
| Network Fingerprint | Forked / mismatched peers dropped at handshake. | Flood-level DoS of handshake attempts. |
| Egress limiter | Bursty / runaway broadcast; bounds per-peer send rate. | Coordinated many-peer floods (peer reputation + ban list). |
| Seen-cache dedup | Cascade loops, repeat processing. | Distinct-spam from a malicious peer. |
| Passport cache | Bandwidth-efficient peer-state propagation; identity signed once at handshake. | Self-reported metrics like neuralScore (advisory only). |
| Passport IP binding | Pairwise-only Guide-ID↔IP visibility for home-holder / fragment / propagation. | Logging by direct peer for offline correlation. |
| PAC fork detection | Login walk + SPS forward + local mint hook; lock written within seconds. | Recovery of a forked Guide ID — recovery is creating a new Guide ID by design. |
| 3-per-ASI invariant | Bootstrap retirement based on community peers only. | Premature retirement under stale coverage cache. |
| UDP socket spoof-cap | Spoofed-IP floods up to 100k simultaneous source addresses. | Coordinated per-connection floods. |
| Persistent ban list | Misbehaving peer outlasting their ban via operator restart. | Cross-node ban gossip — node-local at V1. |
| 75 % governance threshold | Constitutional change requires supermajority. | Vote-buying off-protocol; coordinated voting blocs. |
| No filter, no takedown | No actor with the authority to remove content. | The mesh hosting illegal content; enforcement is social and legal (Vision §28). |
This list is not exhaustive; the canonical threat-model matrix lives in CLAUDE.md and is updated in the same PR as any new packet type or onion layer.
The architecture is designed to be linear in user count with O(1) per-anchor work.
// at a billion citizens minting R anchors each a day (11,574 × R / sec network-wide): anchors received per node ≈ 2.8 × R / sec // 1 / 4,096 ASIs disk per node per year ≈ 89 GB × R // ~1 KB an anchor on disk bandwidth, idle (50 k peers warm) ≈ 0.11 Mbps each way // §9.17 bandwidth, design peak ≈ 0.9 Mbps each way // 20 anchors / s in one bucket = R ≈ 7 passport cache hit rate (lookups) ≈ 99 % live mesh queries (1 % miss path) ≈ O(log N) hops fragment self-check (holdings) ≈ O(1)
A community node holds 1 ASI of 4,096 — every per-ASI metric is a per-anchor metric divided by 4,096. The per-bucket design peak of twenty anchors a second carries a billion citizens at up to about seven anchors each a day, and two hundred million at up to about thirty-five; a sustained average past that means raising the per-bucket budgets, never the frozen bucket count. Subscriptions are SPS-elected (one peer per ASI, not one per peer covering every ASI), so the registration count is proportional to the citizen's interests, not to the user base.
The AnchorStream grows monotonically. A community node holding 1 ASI keeps 1/4,096 of it — about 89 GB a year for every anchor the average citizen mints a day, at a billion citizens. Tier 3 XOR storage (K-closest fragments held as network duty) scales with the operator's chosen budget. The Storage Trajectory module on every node tracks linear-regression slopes over 7 / 30-day windows and projects days-until-floor; the citizen's response is the storage tier slider, not an admin action.
Every governance, feed, search, and lineage query goes through the unified two-phase per-ASI fanout — one announce per ASI, PHI-allocated pull, MAX_GLOBAL_BUDGET = 10,000 anchors per response. The requester never reads its own DB. Per-user concurrency cap is 8; per-peer query egress limiter caps outbound at 240 capacity / 60 refill.
Three load-bearing properties give PHEUN linear scaling. The AnchorStream Index dispatcher partitions the anchor stream by 4,096 — every per-anchor metric is divided at any one node. PayloadWeave anchor-scoped placement scatters payloads across the K_NEIGHBORHOOD = FLOOR × totalFragments closest peers to CORE, each holding one rank-assigned fragment (coverage-complete, no index orphaned) — fragment load is bounded by the neighborhood, and one cache-indexed walk (the O(log N) PeerXorIndex) discovers the entire holder map regardless of file size, 100% coverage from a 10 k-node testnet to a 1 B-node mesh. SPS subscription election turns N×M into N — registration is one peer per ASI per citizen, not one per peer per ASI per citizen.
This paper has specified PHEUN — a decentralised internet replacement built on a byte-frozen 512-byte ledger, NIST post-quantum cryptography, 1:1:1:1 single-user-per-node identity, deterministic AnchorStream Index routing, a self-verifying propagation check at every anchor's birth, a Dual-Witness Sync integrity check at replication, an XOR-DHT for content-addressed payload storage, a three-layer PAC fork-detection model, a closed-namespace document governance pipeline, and a soft-fork-only protocol evolution lane.
The architectural commitments are honest. The protocol contains no privileged actor: no admin, no moderator, no operator class, no kill-switch, no global delete. The wire format is byte-frozen for the lifetime of V1; all evolution rides through the soft-fork lane. Identity is regenerated locally from inputs the human alone holds; the server stores the public key and a BLAKE3 fingerprint, never the private key or the inputs. Consensus is a property of deterministic placement combined with a self-verifying check at birth, rather than a global vote. There is no token, no fee, no mining, no advertising plane, no payment processor.
The costs are owned explicitly. Identity is irrecoverable if all nine Guide ID inputs are forgotten. Every anchor signed remains permanent. The mesh hosts whatever citizens upload. The disk-cost floor commits citizens to running their nodes for years.
PHEUN is not a payment system, although it can host barter. It is not an anonymity network, although it onion-routes its sensitive packets. It is not a blockchain, although it is an immutable signed ledger. It is the substrate on which all of those services can be expressed without re-introducing a privileged operator.
Where Bitcoin replaced the central bank with proof-of-work and Tor replaced the trusted ISP with onion routing, PHEUN replaces the centralised internet substrate itself — the layer beneath social media, document publishing, identity, voice and video communication, and resource exchange — with a single deterministic mesh.
The protocol is what it does. Read the source.
shared/anchor-value-mappings.tsshared/network-config.ts, shared/coverage-config.ts, shared/hope-constants.tsshared/propagation-config.ts, server/lib/hope/anchor-propagation.tsshared/fragment-id.ts — PayloadWeave constitutional law.CLAUDE.md