diff options
| author | tv <tv@krebsco.de> | 2026-11-12 06:10:02 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-12 15:26:53 +0100 |
| commit | ec5e0b47f0c6c1c9e3facda236efcd8aa3c23b65 (patch) | |
| tree | 760a51af34c919ccd858c62cfa489a4210011daa | |
| parent | df766dea6c4d8fd527af323b6ad101c682b9d104 (diff) | |
docs: federation: the fractions are numbers, a decision can be refused
What the maintainer answered to the design's last two questions, and
what follows from it:
* The fractions are numbers of the policy like the others, changed by
a decision to any value: the share of the voters present a decision
takes (two thirds recommended), the share of all of them (half), and
the share whose stamps make the swarm's time and a user gone (a
third). What is promised of decisions is argued for the recommended
ones; Why it holds says what other values carry.
* Refusing a decision: a node follows every decision that counts
unless its operator has it refuse, by bounds on the policy's numbers
or by hand. It then moves to the epoch built at the decision's
history without it, which is the same for every node that refuses
the same decision: those who think alike go on together without
arranging it. While a proposal's votes run, a node whose bounds it
breaks says so. A remake or a change of policy is refused by
staying.
* A decision gives a user name with its namespace, as designed.
* No open question is left. The options not taken that the questions
listed are among the roads not taken: first users voting as soon as
created, voters let in without a remake, other reaches of an
unvouch, a gone user coming back, first keys by those who vouch,
a registry of only what is signed, numbers the design fixes.
The attacks are 78; the stages name them by their numbers.
future-work.md: bounds on more than numbers.
| -rw-r--r-- | docs/federation.md | 290 |
1 files changed, 169 insertions, 121 deletions
diff --git a/docs/federation.md b/docs/federation.md index 96bbc21..6e1c87b 100644 --- a/docs/federation.md +++ b/docs/federation.md @@ -79,9 +79,9 @@ but for what the voters can do to a user, said with each and below): other party's consent; it counts at once, and reaches every honest node its nodes reach. -And for what the swarm decides together, with fewer than a third of the voters -present malicious, then or later (the voters are the users an epoch starts with, of -those the root brought in): +And for what the swarm decides together, with the fractions the design recommends +and fewer than a third of the voters present malicious, then or later (the voters are +the users an epoch starts with, of those the root brought in): 7. **Decisions by two thirds.** A remake, a new root, first keys for a user that lost its own, the names of a user that is out, a change of the numbers counts only once @@ -90,7 +90,8 @@ those the root brought in): one matter both count, and none counts that no honest voter voted for. With no voter malicious, no two do whatever the network does. A remake changes nothing in what counts: every node builds the next epoch itself, from the changes it holds. - Nobody is moved to other rules: a change of policy is followed by choice. + Nobody is moved to other rules: a change of policy is followed by choice, and a + decision that counts is refused by choice. What is not promised: @@ -115,6 +116,9 @@ What is not promised: * **A name through a long partition, for a user that is out.** Unvouched on one side of a partition that outlasts `gone`, it is gone, though someone vouched for it in time on the other. +* **That everyone follows a decision.** A party refuses one it won't bear, and goes + on without it, with those who think alike: two epochs, by choice (Refusing a + decision). * **A user put out by the swarm.** Nobody is put out by a vote: a user is in while one user that counts vouches for it (Unvouching). * **Decisions against a third of the voters present.** A third or more of them, @@ -184,12 +188,21 @@ value: | `limits.users` | 16 | users a user created that stand; the root: no limit | | `limits.vouches`, `limits.bans` | 64 | vouches, and bans, of a user that stand | | a kind's `limit` | none | names of the kind a user holds | +| `fractions.decide` | 2/3 | a decision takes more than this share of the voters present | +| `fractions.all` | 1/2 | and more than this share of all the voters | +| `fractions.time` | 1/3 | the share of the voters whose stamps make the swarm's time, and a user gone | Nothing constrains them: a number that makes no sense has the result it has (an -`absent` of nothing leaves nobody to decide). The fractions aren't numbers: two -thirds of those present, more than half of all, a third for the swarm's time and for -a user gone are what the promises are argued from. And what a node does for itself -alone (how fast it takes a party's changes) is its own setting. +`absent` of nothing leaves nobody to decide, a `fractions.decide` of nothing lets +one voter decide for all). Who won't bear a decision refuses it (Refusing a +decision). More than a share is strictly more; a share of the voters, for the time +and for a user gone, is the fewest voters that are that share at least, and one at +least. + +Where this text says two thirds, half and a third, it means the three fractions as +recommended. What is promised of decisions is argued for those; a swarm that sets +others has what its numbers carry (Why it holds). What a node does for itself alone +(how fast it takes a party's changes) is its own setting. Anything else in the policy changes by a change of policy, which is a fork (below). @@ -291,9 +304,9 @@ exactly: * **A vouch brings a user back whole,** with its names and what it signed in between, as long as it isn't gone. * **Out for long is gone.** A user is **gone**, at a set of changes, once a third of - the voters each have a node with two alive stamps `gone` or more apart, - the user out at both and at every stamp of that node between. Then its claims and - its creation stand no more: whoever comes first claims its names, and no vouch + the voters (`fractions.time`) each have a node with two alive stamps `gone` or more + apart, the user out at both and at every stamp of that node between. Then its claims + and its creation stand no more: whoever comes first claims its names, and no vouch brings it back. It comes in again by being created anew. Gone is read from the changes alone and never goes away. Fewer than a third of the voters can't bring it about early, and the time between two stamps is by one node's own clock. @@ -497,17 +510,18 @@ before out of reach (below). **Who is away.** The document gives a time. Each node's alive stamp says what its clock read *(checked: `alive`, Unix ms)*. The **swarm's time**, at a set of changes, -is the latest time that a third of the voters have a node stamped at or after. A +is the latest time that a third of the voters (`fractions.time`) have a node stamped +at or after. A voter whose nodes' last stamp is more than `absent` behind it, or that has no node, is **absent**: it neither votes nor counts, until a node of it stamps again. The voters **present** are those not absent. Fewer than a third of the voters can't move the swarm's time forward by lying, so they can't make the others absent; and those who left hold up nothing. -A decision also takes more than half of all the epoch's voters, absent or not -(below). So with no voter malicious, no two decisions of one matter both count, -however long a partition lasts: each would be taken up by more than half, and an -honest voter takes up one. Where half or fewer are left for good, they go on by a +A decision also takes more than half of all the epoch's voters (`fractions.all`), +absent or not (below). So with no voter malicious, no two decisions of one matter both +count, however long a partition lasts: each would be taken up by more than half, and +an honest voter takes up one. Where half or fewer are left for good, they go on by a fork that names who votes (A change of policy is a fork). **How.** @@ -516,12 +530,12 @@ fork that names who votes (A change of policy is a fork). 2. Voters **vote** for it: each a statement signed by the user, saying when the vote runs out, `window` from signing unless the user says sooner. One vote on a matter at a time; `release` takes one back. -3. Once more than two thirds of the voters present have votes for it in the - document, any of them **decides**: a statement naming the proposal, the votes, and - the decision of that matter before it, if there is one. Every node judges it as - written: the votes are there and not released, their users are more than two - thirds of the voters present there and more than half of all the voters, and no - other decision following the same one is there. +3. Once more than two thirds of the voters present (`fractions.decide`) have votes for + it in the document, any of them **decides**: a statement naming the proposal, the + votes, and the decision of that matter before it, if there is one. Every node + judges it as written: the votes are there and not released, their users are more + than two thirds of the voters present there and more than half of all the voters, + and no other decision following the same one is there. 4. Every voter **takes it up**, by one node: the one it named first of those that carry for it. When the decision reaches that node while the votes it names still run, by the node's clock, the node records so in its member entry. Of the @@ -531,7 +545,7 @@ fork that names who votes (A change of policy is a fork). from the document, the same by every node, and never goes away. Every node acts on a decision that counts, unless another following the same one -counts too. +counts too, or the node refuses it (Refusing a decision). **By any node.** A proposal, a vote, a vote's release and a decision are taken in any node's change: the signature is the voter's. So a voter votes at whatever node it @@ -548,21 +562,23 @@ of the matter names both. Two remakes are two epochs: a node is in the one it bu first, and moves to the other by its operator's word. **Decisions don't come from the past.** One that is crafted with old dependencies, or -kept back until its votes ran out, is taken up by no honest voter, so it has only -its makers' records. Those are enough only if they were two thirds of the voters -then: their keys, stolen later. Against that, a node that was up holds back a -decision that comes to count more than the absence period after its votes ran out, -and shows it, for its operator to say. A node that joins later takes the decisions -that count as it finds them; a remake puts everything before it out of reach. +kept back until its votes ran out, is taken up by no honest voter, so it has only its +makers' records. Those are enough only if they were two thirds of the voters then: +their keys, stolen later. Against that, a node that was up holds back a decision that +comes to count more than the absence period after its votes ran out, and shows it, for +its operator to say: follow it, or refuse it. A node that joins later takes the +decisions that count as it finds them; a remake puts everything before it out of +reach. The votes are the users' own, signed with their keys, and take the days people take. Taking up is their nodes', and takes as long as syncing does. **What is decided.** -* **The numbers**: any number of the policy, named by its place there, to any value. - It holds for what is made in sight of the decision. A lowered limit takes nothing - away: what a user has stays, and it gets no more until it is below. +* **The numbers**: any number of the policy, the fractions among them, named by its + place there, to any value. It holds for what is made in sight of the decision. A + lowered limit takes nothing away: what a user has stays, and it gets no more until + it is below. * **The root's seat** (below). * **A user's first keys**, for a user that lost them or had them stolen. The proposal names the user, the first keys it is to have, and a cut for those it has: what @@ -738,7 +754,41 @@ named beforehand, and nodes with the old rules go on with the old chain, the sam to there. Miners signalling for a change says how many will go, not who must. And a transaction that would count on both chains is kept to one by naming its chain. Here the height is the decision's base, the signalling is the vote, and the epoch in every -envelope keeps a statement on its side. +envelope keeps a statement on its side. And nodes that don't accept a change the +others made keep their rules, and with them their chain: here, refusing a decision. + +### Refusing a decision + +A decision that counts binds the nodes that follow it, and no node has to. By default +a node follows every decision that counts. Its operator has it refuse: + +* **By bounds** (`--bounds`, a file; `GET` and `PUT /admin/bounds`): for any number of + the policy, the least and the most the node goes along with. A decision that sets + a number outside them is refused as soon as it counts. Bounds that the policy + breaks as it stands refuse nothing: the node shows them. +* **By hand** (`POST /admin/decisions/refuse`, naming the decision): any decision, + whenever. + +What refusing does: + +* **Before.** While a proposal's votes run, a node whose bounds it breaks says so in + its member entry, so the voters see who would go (`GET /registry/decisions`). +* **The epoch without it.** A node that refuses a decision moves to the epoch built + at the decision's history, where it doesn't count yet: the registry as it resolves + there, the policy and the voters as after a remake at that base, and the digest of + the decision refused, which makes it no other epoch. Every node that refuses the + same decision builds the same epoch, whenever it does. So those who think alike + meet there without arranging it. +* **After**, as after a change of policy: the same swarm ID and the same history up + to the base, different epochs, no syncing between them. A node carries its user's + own statements over. On each side the voters who went the other way are absent + after the absence period, and a side with too few of them names its own. A node + moves to the other side by its operator's word. +* **A remake or a change of policy** is refused by staying: the epoch a node is in + goes on as it was. + +So every number is the swarm's to set, and each party's to bear or not. A decision +that lets one voter decide for all is followed by those who don't mind. ### What every node judges @@ -846,10 +896,10 @@ Three things are "conflicting data", and are dealt with apart. **Names claimed twice** are no partition: every node holds both claims and finds the same holder, or contested. The users see it and one releases; nobody drops anything. -**Two epochs**, after a change of policy or after two remakes that both count, are -a fork: each node is where its operator put it, or where it got to first, and moves -to the other side by being told to (it builds that side's snapshot from the base it -holds, and carries its own over). +**Two epochs**, after a change of policy, a decision some refuse, or two remakes +that both count, are a fork: each node is where its operator put it (by word or by +bounds), or where it got to first, and moves to the other side by being told to (it +builds that side's snapshot from the base it holds, and carries its own over). **Changes one side refuses** are a partition nobody chose. A node is cut off from the others when it holds a change they refuse, as everything it writes after builds on @@ -1020,7 +1070,15 @@ them, fewer than a third malicious. next is in the snapshot: the first users present at the base, for all to see before they vote for it. * *Nobody is moved.* A node follows a change of policy only by its operator's word, - and with it whoever the proposal names to vote. + and with it whoever the proposal names to vote; and it refuses any decision by its + operator's word or bounds. +* *With other fractions.* Write d, a and t for `fractions.decide`, `fractions.all` + and `fractions.time`. Two decisions of one matter are each taken up by more than d + of the voters present, so they share more than 2d − 1 of them: one per matter holds + while no more than that share is malicious, which at a half or less is nobody. + Honest voters alone never make two while a is a half or more. A decision no honest + voter voted for takes more than d of those present malicious. The swarm's time, + and a user gone, hold against fewer than t of the voters. **Unvouching** takes away no more than its signer could have kept from seeing: what the unvouched user signed stays if a node of the unvoucher or the root committed a @@ -1048,14 +1106,38 @@ back, so the point only moves forward as more of them show up. * **Votes by nodes, or by every user**: a party runs as many nodes, and brings in as many users, as it likes. Only whom the root brought in itself can't be multiplied by anyone but the root. -* **Two thirds of all the voters**, absent or not: no two decisions whatever the - network does, malicious voters or not, but a third that left for good ends all - decisions. Leaving the absent out, down to half, lets those who stay decide; the - price is a malicious voter on both sides of a long partition. -* **A majority, not two thirds**: with votes that take days and nodes that take a - decision up one by one, a voter that takes up two decisions of one matter must - not be able to tip both. Two thirds stand that against fewer than a third; a - majority stands it against nobody. +* **Recommending two thirds of all the voters**, absent or not: no two decisions + whatever the network does, malicious voters or not, but a third that left for good + ends all decisions. Leaving the absent out, down to half, lets those who stay + decide; the price is a malicious voter on both sides of a long partition. A swarm + that wants it otherwise sets `fractions.all` to two thirds. +* **Recommending a majority, not two thirds**: with votes that take days and nodes + that take a decision up one by one, a voter that takes up two decisions of one + matter must not be able to tip both. Two thirds stand that against fewer than a + third; a majority stands it against nobody. +* **Numbers the design fixes**, the fractions above all: they would keep a swarm's + voters from deciding badly by rules none of them chose. Every number is the + swarm's; whoever won't bear a decision refuses it, and goes on with those who + think alike. +* **First users voting as soon as they are created**: the root creates as many as it + likes, carries every decision, and is never replaced against its will. +* **Voters let in by a decision, without a remake**: nobody fills the votes, and + nobody waits for a remake. But the voters of before make a decision "of then" + later (the root alone, for the time it was the only one), which only nodes that + were up can tell. A remake is what puts that out of reach. +* **An unvouch undoing everything its user ever signed**: nothing to backdate, but it + takes back the user's releases, and no vouch brings the user back as it was. **Or + only what the user signs in sight of it**: the user goes on by never building on + it. **Or from where each node received it**: that is in no document, so two nodes + would resolve the same changes differently. +* **A user that was gone coming back by a vouch made in time**, out of the sight of + those who saw it gone: a vouch crafted with old dependencies then blocks any name + claimed in good faith since. +* **First keys given by those who vouch for the user**: fewer to convince, but a + user's creator takes its name where nobody else vouched. +* **A registry of only what is signed**, from the start: nothing unsigned ever + counts, but it is incomplete for as long as users take to come, and what reads it + needs the repository beside it meanwhile. * **The root's clock** for who is absent and when votes run out: the root is the one being replaced. * **A document per user**, each written by one party, a claim counted across them (as @@ -1091,7 +1173,8 @@ In continuum, as rules every node judges by and data that parametrizes them: use statements (creating, vouching and unvouching, keys, cuts, nodes that carry), the namespace rule, claims by kind with their rules and limits, late and contested, bans, decisions by the voters with the swarm's time, the numbers, the root's seat, a user's -first keys, remakes that every node builds, a change of policy as a fork, resolving +first keys, remakes that every node builds, a change of policy as a fork, refusing a +decision, resolving and its API, the drop an operator asks for, the links along the line. All of it is general: a swarm with other kinds, or none, uses the same. @@ -1109,12 +1192,13 @@ What changes in continuum besides the rules, under the federated policy only: po version 2; the envelope's payload names the user ID and the epoch; a node is given its root, syncs under no policy it doesn't know, takes tokens from its party only, writes no sessions into the document, keeps its creator's nodes as neighbours, answers for an -epoch it left while it keeps it, takes no remake but one its voters decided, and -rejoins no epoch because peers advertise it. No message changes. +epoch it left while it keeps it, takes no remake but one its voters decided, rejoins +no epoch because peers advertise it, and refuses what its bounds say. No message +changes. [`trust.md`](trust.md), [`access.md`](access.md), [`remakes.md`](remakes.md) and the glossary get the federated case: party, statement, line, first user, voter, claim, -cut, late, contested, settled, out, gone, the swarm's time, and a ban of a user beside -a ban of a node. +cut, late, contested, settled, out, gone, the swarm's time, bounds, and a ban of a +user beside a ban of a node. ## Attacks @@ -1209,35 +1293,37 @@ Decisions, the root, remakes: | 55 | Tells a node that was away of an epoch that isn't the swarm's | The node rejoins no epoch that peers advertise: it finishes the old one from archives and builds the next itself, or takes the ID its operator gave | 1 | sim: `away_over_a_remake`, `back_by_an_id` | | 56 | A node back after several remakes offers what its user signed epochs ago | Refuse: an envelope is taken in its epoch and the next. Quarantined, for the user to sign again | 3 | unit: `carried_over_one_epoch_only` | | 57 | The old root comes back after its seat went; crafts users "from before" | It is a first user; what the decision's history doesn't hold of it is an ordinary user's | 7 | unit: `the_old_root_comes_back` | -| 58 | Two thirds of the voters turn on the rest | They remake, seat a root, set the numbers, and give a user's first keys to another, or the names of a user that is out: a name taken, in the open. They forge no signature and move nobody to other rules; the rest ban, stay, or fork | not promised | argued (A change of policy is a fork) | +| 58 | Two thirds of the voters turn on the rest | They remake, seat a root, set any number (a share of the voters that lets one decide for all), and give a user's first keys to another, or the names of a user that is out: a name taken, in the open. They forge no signature and move nobody to other rules; the rest ban, refuse, or fork | not promised | argued (A change of policy is a fork, Refusing a decision) | | 59 | Offers a statement signed on the other side of a fork | Refuse: it names its epoch | 3 | unit: `signed_for_its_user_id_and_epoch` | | 60 | A change of policy with two thirds; a fork naming its proposer the only voter | A node follows only by its operator's word, which names the decision; what that says shows | 7 | sim: `a_fork_by_choice` | +| 61 | A decision breaks a node's bounds: the voters let one of them decide for all | The node refuses it and moves to the epoch built without it, the same for every node that refuses: they go on together | 7 | unit: `bounds_on_the_numbers`; sim: `those_who_refuse_meet` | +| 62 | Says it refuses a decision, or hands out the ID of an epoch without it, to draw nodes there | A node goes there by its own bounds or its operator's word only | 1 | unit: `refusing_is_ones_own` | Nodes and syncing: | # | The adversary | Honest nodes | Promise | Shown by | |---|---|---|---|---| -| 61 | Sends different changes to different peers, each under its own number | Take all: changes made at once | 2 | sim: `two_histories_merge` | -| 62 | Forks its node's actor | The nodes that took each split; one offered both holds proof and refuses the node; a side drops by its operator's choice | not promised | sim: `a_forked_actor_is_proven`, `a_side_drops_a_fork` | -| 63 | Holds changes back, or passes on some | They come by other nodes; a joiner caught up with it syncs on | 6 | sim: `withheld_changes_arrive` | -| 64 | Places its nodes around a victim by choosing their keys | The victim's node also syncs with its creator's | 5, 6 | sim: `around_a_victim` | -| 65 | Hands a joining node another root, or changes from before the policy | Refuse the handshake; there is no before | 1 | sim: `a_joiner_takes_its_root_only` | -| 66 | Signs a token for any user with its node's key | Not taken by another party's node | 3 | unit: `a_token_of_ones_party` | -| 67 | Lies in its member entry (ready, reached, stable) | Sync and trees bend; nothing gets in that way | 6 | argued (Reaching one's line) | -| 68 | Sends envelopes that don't check, without end | Refuse each (a signature costs about 30 µs to check *(docs)*); the node is refused as a whole after the first of its own | 6 | sim: `a_refused_node_costs_little` | -| 69 | Writes its own member entry without end; fills the waiting changes | Take them no faster than a budget per party: put off, never refused; a share of the waiting each | 6 | sim: `a_party_past_its_budget_waits` | -| 70 | Crafts a change Automerge won't take, or that writes in an object nowhere to be found | Refuse *(checked: the rules refuse the second today)*; only the message that brought it fails | 1 | unit: `a_change_writing_nowhere` | +| 63 | Sends different changes to different peers, each under its own number | Take all: changes made at once | 2 | sim: `two_histories_merge` | +| 64 | Forks its node's actor | The nodes that took each split; one offered both holds proof and refuses the node; a side drops by its operator's choice | not promised | sim: `a_forked_actor_is_proven`, `a_side_drops_a_fork` | +| 65 | Holds changes back, or passes on some | They come by other nodes; a joiner caught up with it syncs on | 6 | sim: `withheld_changes_arrive` | +| 66 | Places its nodes around a victim by choosing their keys | The victim's node also syncs with its creator's | 5, 6 | sim: `around_a_victim` | +| 67 | Hands a joining node another root, or changes from before the policy | Refuse the handshake; there is no before | 1 | sim: `a_joiner_takes_its_root_only` | +| 68 | Signs a token for any user with its node's key | Not taken by another party's node | 3 | unit: `a_token_of_ones_party` | +| 69 | Lies in its member entry (ready, reached, stable) | Sync and trees bend; nothing gets in that way | 6 | argued (Reaching one's line) | +| 70 | Sends envelopes that don't check, without end | Refuse each (a signature costs about 30 µs to check *(docs)*); the node is refused as a whole after the first of its own | 6 | sim: `a_refused_node_costs_little` | +| 71 | Writes its own member entry without end; fills the waiting changes | Take them no faster than a budget per party: put off, never refused; a share of the waiting each | 6 | sim: `a_party_past_its_budget_waits` | +| 72 | Crafts a change Automerge won't take, or that writes in an object nowhere to be found | Refuse *(checked: the rules refuse the second today)*; only the message that brought it fails | 1 | unit: `a_change_writing_nowhere` | Rules, and the swarm as it is: | # | The adversary | Honest nodes | Promise | Shown by | |---|---|---|---|---| -| 71 | A rule differs between versions (a bug) | Each side refuses, logs that the policies disagree, shows the peer refused; one side upgrades and drops | not promised | sim: `a_side_drops_and_comes_back` | -| 72 | A policy version a node doesn't know | It doesn't sync | 1 | unit: `no_sync_under_an_unknown_policy` | -| 73 | A root that lies and isn't replaced; a user nobody unvouches | The parties ban it from a cut on and read on without it | not promised | unit: `a_ban_for_those_who_follow` | -| 74 | A banned user's name claimed by one who bans it | The node refuses its own user's write: the others would | 1 | unit: `no_write_by_ones_bans_alone` | -| 75 | A partition that outlasts the absence period | One side at most decides: a decision takes more than half of all the voters. With a malicious voter on both sides of an even split, both may: the two undo each other, or are two epochs the parties choose between | 7, not promised | sim: `one_side_decides`; unit: `two_that_count` | -| 76 | None: a swarm that isn't federated | Everything as today | Optional | the existing tests, untouched; `bench_screening` | +| 73 | A rule differs between versions (a bug) | Each side refuses, logs that the policies disagree, shows the peer refused; one side upgrades and drops | not promised | sim: `a_side_drops_and_comes_back` | +| 74 | A policy version a node doesn't know | It doesn't sync | 1 | unit: `no_sync_under_an_unknown_policy` | +| 75 | A root that lies and isn't replaced; a user nobody unvouches | The parties ban it from a cut on and read on without it | not promised | unit: `a_ban_for_those_who_follow` | +| 76 | A banned user's name claimed by one who bans it | The node refuses its own user's write: the others would | 1 | unit: `no_write_by_ones_bans_alone` | +| 77 | A partition that outlasts the absence period | One side at most decides: a decision takes more than half of all the voters. With a malicious voter on both sides of an even split, both may: the two undo each other, or are two epochs the parties choose between | 7, not promised | sim: `one_side_decides`; unit: `two_that_count` | +| 78 | None: a swarm that isn't federated | Everything as today | Optional | the existing tests, untouched; `bench_screening` | ## The registry on it @@ -1280,12 +1366,12 @@ change of the document (the store's stream), it replaces the merge button. ## Stages Each leaves the system working, and is a few patches with its tests. At every stage -the existing tests pass untouched (76). +the existing tests pass untouched (78). 1. **A federated swarm's frame.** `--genesis-policy` (a file, written into the genesis change with the root, its keys and nodes); a federated node is given its root, syncs under no policy it doesn't know, takes no remake yet, takes tokens - from its party only, keeps ended sessions to itself. Tests: 65, 66, 72, 76, and + from its party only, keeps ended sessions to itself. Tests: 67, 68, 74, 78, and the policy's existing tests under a policy from the root. 2. **Statements.** The users' registers (`create`, `key`, `node`, `vouch`, `release`), the user ID and the epoch in envelopes, nodes carrying for users and @@ -1299,7 +1385,7 @@ the existing tests pass untouched (76). 5. **Out of sight.** Late, contested and settled, for names and for users' names; the root's node writing when a claim reaches it; `GET /registry/claims` with what makes a claim late; values marked in `GET /store`. The links along the line. - Tests: 8, 9, 23, 25, 26, 29, 30, 61, 63, 64. + Tests: 8, 9, 23, 25, 26, 29, 30, 63, 65, 66. 6. **Cuts.** `retire` and the keys above, a node that stops, what doesn't count left out, the value before read again, the client listing what stopped counting. Tests: 31 to 35, 37, 38, 39. @@ -1307,64 +1393,26 @@ the existing tests pass untouched (76). it, the names of a user that is out waiting, nothing taken from an unvouched user's nodes. Tests: 12 to 17. 8. **Coming back.** The drop an operator asks for, a forked actor proven and shown - with what the line holds, the budget and the share per party. Tests: 62, 68, 69, - 70, 71. -9. **Bans** for those who follow. Tests: 73, 74. + with what the line holds, the budget and the share per party. Tests: 64, 70, 71, + 72, 73. +9. **Bans** for those who follow. Tests: 75, 76. 10. **The registry.** Import, export, and a federated swarm of the simulations with the registry's kinds and a few hundred hosts. From here it can be used; it only grows. -11. **Decisions.** The voters a root change names, the swarm's time and who is absent, - `propose`, `vote` and `decide` taken from any node, taking up, what counts, `GET - /registry/decisions`. What is decided: the numbers, a user's first keys, the names - of a user that is out. A user gone. The simulations start from a root change - naming several voters, as a remake's does. Tests: 18, 19, 36, 40 to 47, 49, 50, - 75. +11. **Decisions.** The voters a root change names, the swarm's time and who is + absent, `propose`, `vote` and `decide` taken from any node, taking up, what + counts, `GET /registry/decisions`. What is decided: the numbers, a user's first + keys, the names of a user that is out. A user gone. The simulations start from a + root change naming several voters, as a remake's does. Tests: 18, 19, 36, 40 to + 47, 49, 50, 77. 12. **The root's seat.** Tests: 57. 13. **Remakes.** The base, the snapshot every node builds, carrying over from the epoch before and no further, what becomes final; peers answering for the epochs they keep, and saying which; a node walking them, or rejoining by an ID its operator gave, and by none that peers advertise. Tests: 51 to 56. -14. **A change of policy.** The fork, followed by an operator's word, with who votes - on its side. Tests: 59, 60. - -## Open questions - -Each with the options, and what I'd choose. - -1. **Are the fractions numbers too?** Two thirds of the voters present, more than - half of all, a third for the swarm's time and for a user gone. - * *No* (as designed): the promises are argued from them, and they change by a - change of policy, which each party follows or not. - * *Yes*, like every other number: then two thirds of the voters decide that a - majority decides, or that one voter does, for everyone. - - *No.* -2. **What a decision gives of a user that is out.** - * *Any of its names, its user name among them* (as designed): a namespace goes to - another user, who signs over what is there. - * *Only names it claimed*: a namespace then comes back to its user, or is free for - whoever creates the name anew, and is never handed on. - - *As designed.* - -Settled, as the design has it: - -* a name is contested, not the senior's, with `release` to give it up; -* one root, whose seat is decided anew; -* votes by users, over days: two thirds of those present and more than half of all, - the absent left out; -* who votes: the first users an epoch starts with; -* nobody is put out by a vote; -* an unvouch undoes from what its signer's nodes, or the root's, had seen; -* what a cut or an unvouch takes back leaves those who relied on it out, their names - waiting; out for `gone` is gone for good, and the voters free or give names before; -* first keys by a decision, several first keys later; -* every number in the genesis policy, changed by a decision without constraint; -* a node back after many epochs walks the archives, or is given an ID; -* a user without a node votes at any node; -* what the root holds unsigned counts until signed over; -* a change of policy is a fork; -* the mode is optional. +14. **Forks by choice.** A change of policy, followed by an operator's word, with + who votes on its side. Refusing a decision: a node's bounds, the epoch without + the decision. Tests: 59 to 62. ## What was checked, and what is assumed |
