aboutsummaryrefslogtreecommitdiffstats
path: root/src/remake/snapshot.rs
Commit message (Collapse)AuthorAgeFilesLines
* remake: a backup's epoch as its snapshot names ittv2 days1-16/+27
| | | | | | | | | | | | Review 4, appendix: a document loaded from a backup was taken to be on the largest generation `_continuum/epochs` held as it stood, verified at its only root. In a swarm without a policy a member's own change could plant `_continuum/epochs/99`, and a backup then failed to load until it was removed. The generation is now read at the document's only change without dependencies (its snapshot writes its own entry and carries the earlier ones), as the rest of the protocol reads epoch metadata; the genesis change writes none, so a first-epoch backup is genesis whatever was planted. The test plants one.
* remake: earlier epochs' metadata carried as built, not as it standstv2 days1-5/+23
| | | | | | | | | | | | Review 4, F6: a snapshot judged which earlier epochs' metadata to leave out as the base epoch's snapshot built it (1254), but copied `_continuum/epochs` from the base as it stood. In a swarm without a policy, a member's rewrite of an entry (its window, kind, clock, translation) went into the next epoch, and was "as built" there; an entry it added was carried and never left out, one it removed not carried. Now `_continuum/epochs` is copied from the base epoch's snapshot change too (`as_built`), then pruned; the first epoch's base carries none. The test adds a generation and narrows a window after the snapshot: neither reaches the next one.
* access: ending a single sessiontv2 days1-0/+72
| | | | | | | | | | | | | | | | | | | | Logging out of the dashboard (`DELETE /auth/session`) only cleared the cookie: the session's tokens stayed taken until they expired, by every node. Ending them took `POST /auth/logout`, which ends all of a user's sessions. Now `DELETE /auth/session` ends the session of the token it comes with (the cookie, or a bearer token): where the swarm has a registry, it is recorded as `_continuum/sessions/<user>/<session>` (`registry::session_path`), its value until when the session would have lasted, and every node refuses the session's tokens once the change reaches it (`token::Refused::Ended`): the page's own, its narrow tokens, and one handed to another member's dashboard, all refreshed from it and keeping its ID. The rules take the entry from the user itself or one who manages users, as a logout. A remake's snapshot leaves out entries past that time, a user's map where none is left: their tokens are expired anyway. Without a registry the document can't record it: the node ending it refuses the session's tokens itself (`AppState::ended_sessions`, until it restarts), others take them until they expire, as a logout there is refused.
* remake: earlier epochs' metadata read as the snapshot built ittv3 days1-6/+45
| | | | | | | | | | | | | | A snapshot leaving out earlier epochs' metadata (`snapshot::left_out`) and a rejoining node (`catchup::prepare`) read it from the document as it stands. It is never writable through the store, and under a policy the rules take a change to it only from an epoch's first; but with no policy, screening judges only an epoch's root, so a member's own change could rewrite or remove an entry: a replay window narrowed or widened, a translation or a clock changed, a strict remake's entry gone. Now both read it at the epoch's snapshot change (`snapshot::as_built`), as `verify_document` reads the epoch's own: a snapshot from its base's epoch's, a rejoining node from the target's. Every earlier entry is a copy in that change, so what was written there since doesn't count. The first epoch follows none and has none.
* remake: leave out earlier epochs' metadata past the replay windowtv3 days1-4/+118
| | | | | | | | | | | | | | | | | | | | | Every snapshot carried the metadata of all earlier epochs (`_continuum/epochs`) forward, so it grew by an entry, a clock per actor among it, with every remake. Only a rejoining node reads an earlier entry: a node on epoch P reads P+1's (its clock, when it was proposed, its replay window) and every one up to the swarm's epoch (kind, translation, whether it was strict). It replays only while P+1's replay window covers it; beyond, its writes are quarantined whatever the entries say. So a snapshot now leaves out the generations older than the oldest whose replay window still covers a node on the epoch before it (`snapshot::left_out`), judged by the remake's `proposedAt`: the same on every node, and earlier than any rejoining node's clock, so nothing a node can still replay through goes. Metadata that doesn't read stays, with all after it. A strict remake's metadata stays for good: by it a rejoining node, however far behind, tells a strict remake of a swarm strict already (`catchup::prepare`, which reads the generations it finds). There is at most one, short of such a remake. No new key and no change to the rejoin: a node beyond the window that finds some entries and not others quarantines with "cannot translate" rather than "outside the replay window".
* document: tell whether a document holds a change without building ittv3 days1-1/+1
| | | | | | | | | | | | | | | With the policy's reads kept, judging a change still costs about one read (some 3.5 µs), and so does judging without a policy: what is left is At::new, which asks get_change_by_hash for each head. Automerge builds the change again from the document's operations to answer, at a cost growing with its history. Screening asks it again for every candidate and every dependency, and sync for heads. Ask by the missing dependencies instead (changes::holds), which look the hash up: one the document holds is not among them. A change queued in the document, waiting for its dependencies, isn't either; but then some are missing, and only then is it asked the slow way. Every check of whether a document holds a change goes through it.
* remake: turning a running swarm strict, keeping what an operator signedtv3 days1-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Until a swarm is strict, the user a change names is its node's word, so any member could have planted registry entries, policy, bans or user-signed values as any user, plain or signed by a key it put there itself; writing the strict policy trusted all of it as it was. A remake of a new kind, `strict`, turns a swarm strict instead: * Its content is a manifest (access::strict): the swarm, the strict policy, and each value kept at the places values are signed, by the SHA-256 of its JSON, signed by an operator (ssh-keygen -Y sign -n continuum-strict). * Every node builds the next epoch as compaction does, keeping at the signed places only the values the manifest names, as they were at the base, and writing its policy (RemakeKind::protocol, the one kind that changes protocol data). Writes after the base reach the new epoch only by replays, judged by the strict policy. * A node votes for one only with its manifest signed by one of --strict-keys, keys given out of the document; without any, for none (logged once, `Not voting for a strict remake`), unless --follow-strict-remakes. A coordinator proposes only what it would vote for (403). Once a majority commits one, every node switches, as with any remake: refusing to switch would only cut a node off. * GET /admin/strict-manifest gives the manifest keeping everything held now, the values for review and the heads they are at; continuum-signed strict shows them, signs once confirmed and proposes at those heads. The sim a_swarm_turning_strict_through_a_remake: a member plants a registry entry as a manager; the operator's manifest leaves it out; a and b, given the key, commit; c, without, follows; the entry is gone and the policy strict everywhere.
* rules: a carried remake record taken from the coordinator its snapshot namestv3 days1-0/+6
| | | | | | | | | | | | | | | | | Review finding 7, second part: a record carried into a new epoch whole (proposal and decision in one change) was taken from any member, for any remake ID. A member could write a forged record, decision included, for a fresh ID in a single change. The snapshot's epoch metadata now names the remake's coordinator, as the quorum built it. The carried-record exception holds only in a later epoch, only for the remake that made it, and only from the coordinator its snapshot names, where there is no record yet. Wire version 43: the snapshot, and so the epoch ID, changes. The review suggested carrying the record inside the snapshot instead. The snapshot can't hold the decision, which names the snapshot's own hash. So the snapshot vouches for who may carry the record instead.
* store: keys_at tells no map from an empty onetv4 days1-1/+2
| | | | | | | | registry::exists counted any value at _continuum/users as a registry; keys_at answers None where there is no map, and its users (records, members, forget records, remakes) say what they make of it. Auth plan M1 (fix).
* use Automerge as Document instead of AutoCommittv11 days1-45/+49
| | | | This allows a lot of operations to drop mut.
* tests write through document::testing helperstv11 days1-82/+84
|
* remake: drop parse_metadatatv12 days1-12/+8
|
* remove some dead commentstv2026-10-261-5/+3
|
* wrap unix timestamps in newtypetv2026-10-261-7/+8
|
* move protocol paths to dedicated moduletv2026-10-261-22/+11
|
* nodes keep list of every actor ID they've usedtv2026-10-251-1/+2
|
* add possibility to start with a documenttv2026-10-251-0/+53
| | | | The --recover-from option allows a node start with a given document.
* put swarm ID into the documenttv2026-10-251-0/+2
|
* add votes registertv2026-10-241-3/+15
|
* put remake content into blobstv2026-10-241-5/+5
|
* rename cluster to swarm everywhere!tv2026-10-211-8/+8
|
* add the replace kind of remaketv2026-10-211-1/+1
| | | | | | | | | | | | | | POST /admin/remakes accepts specs with replace kind, e.g.: { "kind": "replace", "baseHeads": ["..."], "spec": { "document": { "accounts": { ... } }, "rules": [ { "from": "users", "to": "accounts" }, { "from": "users/admin", "drop": true }, { "from": "", "to": "" } ] } }
* turn compaction into a kind of remaketv2026-10-211-7/+72
|
* rename compaction to remaketv2026-10-211-0/+637