diff --git a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md index afbcf8e6..fdc36580 100644 --- a/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md +++ b/03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md @@ -618,11 +618,23 @@ Findings 11). How each is kept, read and retained is this design's choice under it runs (ADR 0656, which changes ADR 0571 §8). - **Reverted.** Only the new form is written: the indexer, the assigner and the gate keep nothing of ADR 0603 §2's keys or of `merges` and `turns` beside the new forms, since nothing reads them after milestone G. A revert of - milestone G is a change like any other, checked and delivered; before milestone G's delivery moves the indexer, the - assigner and the gate, their kept data on the bus is backed up, and the revert restores it before their reverted - builds start, after which each catches up forward (*A module's kept data on the bus, backed up and restored with - its delivery*, under *A backup before the apply*). That is the delivery system's way for every change of a kept - data's form, not a case of this milestone. + milestone G is a change like any other, checked and delivered, and the delivery system restores what it must + (*A module's kept data on the bus, backed up and restored with its delivery*, under *A backup before the apply*). + Milestone G changes the form of these kept data, and raises their `form` (a kept data declaring none reads as form + 0, so G's own move takes their restore points): + + | Part | Kept data before G (form 0) | After G | Restored at a revert | + |---|---|---|---| + | the indexer | the state `modules` (ADR 0603 §2's one key per module) and its durable consumer's position on the forge bridge's stream `forge` | catalog graph revisions as objects, form 1; `modules` no longer declared | yes: `modules` as it stood at G's delivery, and the consumer's position | + | the gate | the states `merges` and `turns` | the delivery record's ledger, form 1; `merges` and `turns` no longer declared | yes: `merges` and `turns` as they stood at G's delivery | + | the assigner | the wants, written from the indexer's `modules` | the same wants, form 0, written from the assignment graph; the assignment graph revisions as objects, form 1 | no | + + The wants keep their form: their keys and values are unchanged, only what the assigner computes them from changes, + so G raises no `form` on them and a revert restores none. Restoring the wants would send nodes back to older + fingerprints until the reverted assigner computed them again; leaving them, the nodes keep what runs and the reverted + assigner writes them again from the caught-up indexer. The assigner's placement and every other kept data of the + three keep form 0 and are never restored, so nothing decided since (a placement, a verdict, the source revision) is + set back. ### A change's graph difference is its delivery @@ -747,6 +759,8 @@ ADR 0656 decides the direction and leaves every choice made in working it out to | An unchanged entry stored once, a revision being a list of its entries' digests | consecutive revisions differ by a few entries, so the stores grow by what changes; a larger cap over whole revisions would only delay the same fill | | No old form written beside the new; a revert restores the parts' kept data on the bus from a restore point taken before they moved, then they catch up forward | only the new form is looked after (the operator, 2026-11-06 21:3x), and a revert still works, as the delivery system's capability for every change of a kept data's form | | A module's kept data on the bus backed up before a `form` change and restored beside the live data at a revert, a missing restore point holding the revert | ADR 0404 covers only the items on a module's node, so the bus's kept data had no restore point; a restore never goes over live data, and a revert with nothing to restore must not start on the newer form unasked | +| Only kept data whose `form` changes restored, the wants never; at a revert the node-engine last on its node, and the reverted assigner and gate only after the reverted indexer took in the trunk's head | restoring anything else would set back what was decided since; restored wants, or an assigner reading an indexer not yet caught up, would send nodes to older fingerprints; the node-engine of before may not know how to restore | +| A restore point holding the consumers' positions, and each manifest's own catch-up tool called after a restore | the reverted build then hears everything since as after any restart; the stream `forge` keeps 7 days, so what fell out of it is taken in from the trunk by the part's own tool | | A revision removed when no record pins it and it is not current, pins counted per revision | a trace must read every revision it moved between, and a revision neither pinned nor current is read by nobody; counting pins keeps a revision two records share | | The indexer and the assigner hear `pinned`, `freed` and `heads-replaced` through durable consumers | an event said while either was down is applied when it comes back, so no revision leaks and none is dropped early | | Records kept 90 days by default, the gate's setting `record-retention`, the ledger capped at 768 MiB, a record's operations removed with it | the traces asked so far went back weeks; about 840 outcome operations make a record about 200 KiB, so 90 days at an estimated 20 a day is about 360 MiB, and the cap is twice that | @@ -1540,53 +1554,92 @@ backup holder backs up nothing, and the have says so. ### A module's kept data on the bus, backed up and restored with its delivery -*ADR 0404, ADR 0235, ADR 0233, ADR 0539 §16, ADR 0595, ADR 0619 §2; from research 085's milestone, this design's -choice under ADR 0656.* +*ADR 0404, ADR 0235, ADR 0233, ADR 0539 §16, ADR 0595, ADR 0619 §2, ADR 0633 §1, §5, ADR 0363 §2; from research +085's milestone, this design's choice under ADR 0656.* **ADR 0404's backup does not cover a module's kept data on the bus.** It backs up the items a moved module keeps on its own node (ADR 0404 §2, ADR 0233), and the bus's streams are dumped whole by the bus module on its own rhythm (ADR 0235), not per module and not before a delivery. A key-value state, a stream or an object store a module keeps on -the bus (ADR 0595, ADR 0619 §2) therefore has no restore point taken before its module moves. That is a gap of the -delivery system, and milestone G builds it, because a revert of milestone G is the first change that needs it. It is -built as the delivery system's capability for every later change of a kept data's form, not as a case of this -milestone. +the bus (ADR 0595, ADR 0619 §2), and its durable consumers' positions on the streams it reads, therefore have no +restore point taken before its module moves. That is a gap of the delivery system, and milestone G builds it, because +a revert of milestone G is the first change that needs it. It is built as the delivery system's capability for every +later change of a kept data's form, not as a case of this milestone. - **Its form is declared.** Each kept data a manifest declares names a `form`, a number its holder raises whenever it - changes how it writes that data. The declaration alone cannot tell a changed layout of the same bucket, so the - holder says it. -- **It is backed up before the module moves.** When a want moves a module whose new manifest declares a kept data - of another `form` than the running one, the node agent applying it first asks the seat `node-backup` of the node - holding `mesh-broker` for a restore point of that module's kept data on the bus, and waits for its event `ended`, - as for any backup before the apply. The bus module's account takes it, as it takes the bus's snapshots (ADR 0235 - §5), one restore point per module and fingerprint. A failed backup holds that module as any failed backup does. -- **A revert restores it before the reverted build starts.** A revert is delivered like any change. When a want takes - a module back across a change of a kept data's `form`, the node agent applying it asks that same seat's verb - `restore` for the restore point taken before the module moved forward, waits for the seat's event `restored`, and - only then starts the reverted build. As every restore is, it is brought back beside the live data and never over - it: the live buckets, streams and objects of the newer form are kept aside under a name of their own, and only the - operator removes them, so nothing written since is destroyed. -- **The restored part catches up forward.** The indexer takes in the source revisions merged since its restore - point; the assigner computes the wants again from the current catalog graph, placements and capabilities, and as - wants come only from the trunk's revision, no want goes to a fingerprint older than the trunk's; the gate reads - the open groups again from the forge and the operator's answers given since from the seat `operator-channel`'s - `asks`. + changes how it writes that data, or stops declaring it; a declaration naming none reads as form 0. The declaration + alone cannot tell a changed layout of the same bucket, so the holder says it. Only kept data whose `form` changes is + backed up and restored, so a part's other kept data, and every decision it holds, is never set back. +- **It is backed up before the module moves.** When a want moves a module whose new manifest declares a kept data at + another `form` than the running one, or no longer declares it, the node agent applying it first asks the seat + `node-backup` of the node holding `mesh-broker` for a restore point of that kept data, and waits for its event + `ended`, as for any backup before the apply. The bus module's account takes it, as it takes the bus's snapshots + (ADR 0235 §5). A restore point is keyed by the module, the kept data, its form and the fingerprint it was taken + before, and it holds the kept data whole and the position of each durable consumer the module reads with. A failed + backup holds that module as any failed backup does. +- **A revert restores it before the reverted build starts.** When a want takes a module back across a change of a + kept data's `form`, the node agent applying it asks that seat's verb `restore` for the restore point of that module, + kept data and form, waits for the seat's event `restored`, and only then starts the reverted build. The node agent + that restores is the one running when the revert starts. As every restore is, it is brought back beside the live data + and never over it: the live kept data of the newer form is set aside under a name of its own, and only the operator + removes it, so nothing written since is destroyed. The consumer's position is set back with it, so the reverted + build hears everything since as after any restart. +- **The order of a delivery that crosses a form change** is the module graph's (*Order without a person*), with three + edges the assigner, which writes every want, keeps: + - the new versions of the `node-backup` holder and of the bus module run before any module whose kept data's form + changes is moved, since the restore point needs both; + - at a revert, a node's node-engine goes back last on that node, after every module it restores there has said + `restored` and runs, since the node-engine of before may not know how to restore; + - the reverted assigner and gate are wanted only once the reverted indexer has taken in the trunk's head, as its + `take-in.taken` naming the current source revision says (ADR 0633 §1), since the assigner of before computes the + wants from the indexer's `modules` and would otherwise write the fingerprints of the restore point. Until then the + running assigner writes no want, and every module keeps the fingerprint it runs. +- **The restored part catches up forward, with the code it already has.** Read on main, mesh-delivery at 2d201f78 + and mesh-catalog at 1d07778c: + - **The indexer** (mesh-delivery, `modules/mesh-delivery-indexer`): its durable consumer `_` on the stream + `forge` redelivers every message since the restored position, and `handle` takes each + merge through `Indexer.Arrive` into `pending` and then into `modules` (`applyMerged`); `applySource` takes the + gate's `source.main` in, and `ApplySource` leaves a revision older than the latest it has seen. **The stream + `forge` keeps 7 days**: the forge bridge's manifest declares no age, and a stream's default is 7 days, at most 30 + (mesh-sdk `go/catalogue` `StreamDefaultDays`, `StreamMostDays`), so it does not cover the records' 90 days. A + merge older than the stream's first message is never redelivered, and the code then leaves that repository's + modules at the restore point's fingerprints. So the restore runs one forward step: once the reverted indexer + runs, the node agent that restored it calls its tool `indexer_take_in` with each repository the gate's source names + (`NewTakeInRepository`, which takes in the head the source names for a repository). Each manifest declares its + catch-up tool beside its kept data, so the delivery system names no module's tool. + - **The assigner** (mesh-delivery, `modules/mesh-delivery-assigner`): it keeps nothing restored. Its pass + (`passer.wants`) writes, from what the world holds now, each node's want by the six rules from the indexer's + newest fingerprint at the trunk, and only where the value differs; so once the indexer has caught up it writes + the trunk's wants, and nothing older. + - **The gate** (mesh-catalog, `modules/mesh-delivery-gate`): `Holder.Load` reads the restored deliveries and groups + back; `readOnStart` then reads what happened while it was away: `wantForge` reads the forge's open pull requests + at the next look, `hearAsks` reads the teller's answer to every ask it still holds as pending, and + `SourceCatchUp` brings the newest merge of each repository into `source.main`, never moving a repository back. An + ask the gate of milestone G raised after the restore point is not among the pending ones, so its answer is not read + and the operator is asked again. Whether the first look clears a merge kept in the restored `merges` that the forge + merged since was not read in the code; the catch-up test below proves it with the real builds. - **A missing restore point holds the revert, naming it.** When the restore point a revert needs does not exist, or `restored` does not come, the node agent applies nothing of that module, keeps what runs, and writes the have phase - `held` with the reason `restore point missing` and the module and fingerprint it names; the assigner asks the + `held` with the reason `restore point missing` and the module, kept data and form it names; the assigner asks the operator (hold, or start the reverted build on the live data as it is), raises the condition naming them, and on the answer writes the node's want again naming it (ADR 0539 §16). -- **What the operator is told.** A revert across a change of a kept data's form puts that part's kept data back to - the moment before the change moved it: the deliveries made since stay delivered, but what the part wrote since - (for milestone G, its delivery records and its graph revisions) is set aside and not read again; an Approve given - since is read back from the operator's answers, and only an answer the mesh no longer holds is asked again. The - revert's Approve ask says this in those words, naming each part restored. +- **What the operator is told.** A revert across a change of a kept data's form puts that kept data back to the + moment before the change moved it: the deliveries made since stay delivered, but what the part wrote there since + (for milestone G, its delivery records and its graph revisions) is set aside and not read again; an Approve asked + and answered since is asked again, and one the gate asked before still reads its answer. The revert's Approve ask + says this in those words, naming each kept data restored. - **Its tools.** The seat `node-backup`'s `backed-up` lists each module's restore points of its bus data, with the - fingerprint and form each was taken before; its `restore` restores one. Both exist on the seat today and gain the - module's kept data on the bus as an item. + kept data, the form and the fingerprint each was taken before, and the data set aside at each restore, with its + size; `restore` restores one; `discard-aside` removes data set aside by a restore, only on the operator's call, and + writes the act, who and why in the hand-act log of the seat `mesh-hand-acts`. `backed-up` and `restore` exist on + the seat today and gain the module's kept data on the bus as an item; `discard-aside` is new. - **How it is checked.** Whole (node-engine, backup holder, bus module): a want moving a module across a `form` - change takes a restore point of its bus data first; a want taking it back restores it beside the live data before - the reverted build starts, and the live data of the newer form is kept aside; a revert whose restore point is - missing is held, naming it, and moves on only on the operator's answer. + change, and one moving a module whose kept data declares no `form` to one that does, each take a restore point + first, keyed by module, kept data, form and fingerprint; a want taking it back restores it beside the live data and + the consumer's position before the reverted build starts, and the data set aside is listed with its size and + removed only by `discard-aside`, which writes the hand-act log; a revert of a group holding the node-engine and a + module whose form changes restores the module before the node-engine goes back; a revert whose restore point is + missing is held, naming it, and moves on only on the operator's answer. The catch-up is proved with the real builds + of the indexer, the assigner and the gate from before milestone G, never fixtures (acceptance test 36). ## Compositions, wants and the apply @@ -2157,12 +2210,16 @@ list: running build, also after six later merges; a group approved before the switch to the records is not asked again. 35. **The trace is links.** Research 085's milestone reads back from research 085 to its decisions, its milestone, its issues and its pull requests with no text match. -36. **The milestone can be undone.** A revert of milestone G is checked on the checking program built from the - revert's own heads and delivered; before the reverted indexer, assigner and gate start, their kept data on the bus - is restored from the restore points taken before milestone G moved them, beside the live data; they catch up - forward, and no want goes to a fingerprint older than the trunk's; the operator is asked again for no Approve whose - answer the mesh still holds. A revert whose restore point is missing is held, naming it (whole, checker, gate, - assigner, node-engine, backup holder). +36. **The milestone can be undone.** Milestone G's delivery took the restore points of the indexer's `modules` with its + consumer's position on `forge`, and of the gate's `merges` and `turns`, before it moved them. A revert of milestone + G is checked on the checking program built from the revert's own heads and delivered: the indexer's and the gate's + kept data is restored beside the live data before their reverted builds start, the indexer catches up (its + `forge` consumer, then `indexer_take_in` of every repository the source names), and only then are the reverted + assigner and gate wanted; a module delivered during milestone G keeps its fingerprint while they wait; no want goes + to a fingerprint older than the trunk's; the operator is asked again only for an ask raised after the restore + point. A revert whose restore point is missing is held, naming it. Proved with the real builds of the indexer, the + assigner and the gate from before milestone G, not fixtures (whole, checker, gate, assigner, indexer, node-engine, + backup holder, bus module). 37. **Nothing is delivered ahead.** Research 085's milestone is delivered with no part delivered ahead of it, read from its delivery record (ADR 0656, How it is checked). 38. **A newer indexer is reached.** A merged revision naming a newer indexer gives, from the running indexer, a catalog