Merge pull request 'Design 25 bindings-first-view §9: compose a bucket's binding from the bus module's list answer, breaking the registry circle (issue 1966)' (#549) from design/25-bindings-from-the-list into main
This commit was merged in pull request #549.
This commit is contained in:
@@ -28,7 +28,9 @@ holds and composes the bindings from it; the owner answers for its own data. Wit
|
|||||||
ADR 0595 §1 and §7 (the binding is the bus module's to say and the grants part's to write), ADR 0596 §2 (another
|
ADR 0595 §1 and §7 (the binding is the bus module's to say and the grants part's to write), ADR 0596 §2 (another
|
||||||
module's data is asked through its seat, never read from its bus state) and the first-view rules of ADR 0615 §3 to
|
module's data is asked through its seat, never read from its bus state) and the first-view rules of ADR 0615 §3 to
|
||||||
§6, which decide them for the indexer's and the assigner's state and which this milestone applies, as the design's
|
§6, which decide them for the indexer's and the assigner's state and which this milestone applies, as the design's
|
||||||
choice, to the bus module's. Each choice below says so.
|
choice, to the bus module's. Each choice below says so. The operator, 2026-11-11 13:30 CET (in the terminal, to lead-47), asked whether
|
||||||
|
the grants part should take a bucket's binding from the bus module's existing `list` answer when the new field
|
||||||
|
`binding` is missing, to break the circle §7 names, answered "Yes, build it": §9.
|
||||||
|
|
||||||
**Cited as** "design 25 bindings-first-view §n". It amends design 25 bus-state §4, which says so.
|
**Cited as** "design 25 bindings-first-view §n". It amends design 25 bus-state §4, which says so.
|
||||||
|
|
||||||
@@ -86,7 +88,9 @@ choice, to the bus module's. Each choice below says so.
|
|||||||
on `created`, where it holds none, and rewrites it, as on `recreated`, where it holds a different one; where it
|
on `created`, where it holds none, and rewrites it, as on `recreated`, where it holds a different one; where it
|
||||||
holds the same, it writes nothing. Each binding written or rewritten is said in its log, naming the module, the
|
holds the same, it writes nothing. Each binding written or rewritten is said in its log, naming the module, the
|
||||||
local name and the first view as the cause, and recomposes that module's memberships as an event's would. An entry
|
local name and the first view as the cause, and recomposes that module's memberships as an event's would. An entry
|
||||||
listed without a binding (§2) changes nothing the grants part holds for it. **A binding the bus no longer
|
listed without a binding (§2) changes nothing the grants part holds for it, but for an entry the bus holds in an
|
||||||
|
answer of a bus module's build from before this milestone, which carries no `binding` on any entry: §9 composes
|
||||||
|
that binding, and it is then applied by this line as one the answer carried. **A binding the bus no longer
|
||||||
lists is kept, never removed by a first view**: the grants part removes a binding only on `dropped` (ADR 0595 §1,
|
lists is kept, never removed by a first view**: the grants part removes a binding only on `dropped` (ADR 0595 §1,
|
||||||
§7), so a bus module whose own state `asked` was lost or rebuilt, and answers few entries or none, strips no
|
§7), so a bus module whose own state `asked` was lost or rebuilt, and answers few entries or none, strips no
|
||||||
module of its data. Instead it raises the condition `mesh-grants.binding-unlisted`, one per such binding, naming
|
module of its data. Instead it raises the condition `mesh-grants.binding-unlisted`, one per such binding, naming
|
||||||
@@ -110,7 +114,8 @@ choice, to the bus module's. Each choice below says so.
|
|||||||
§8; from G, G's own checks of §383 and §387.
|
§8; from G, G's own checks of §383 and §387.
|
||||||
- §6 **The tools that read and steer it.** `grants_first_views` shows the first view `bindings` beside the others:
|
- §6 **The tools that read and steer it.** `grants_first_views` shows the first view `bindings` beside the others:
|
||||||
the seat and verb (`mesh-broker.list`), when it was asked and answered, how many entries the answer listed, how
|
the seat and verb (`mesh-broker.list`), when it was asked and answered, how many entries the answer listed, how
|
||||||
many bindings it wrote and rewrote, the bindings it found unlisted, how many asks and hand acts, and whether its
|
many bindings it wrote and rewrote, how many of those it composed by §9 and the entries §9 left unbound (by module,
|
||||||
|
local name and storage type), the bindings it found unlisted, how many asks and hand acts, and whether its
|
||||||
condition is raised, kept in the grants part's own state `user-list` under the key `first-views` as the others are.
|
condition is raised, kept in the grants part's own state `user-list` under the key `first-views` as the others are.
|
||||||
`grants_first_view_again` takes `bindings` among its `state` values, by a person's act with why, recorded as a hand
|
`grants_first_view_again` takes `bindings` among its `state` values, by a person's act with why, recorded as a hand
|
||||||
act; its description names it. From G these two tools are served by mesh-sdk's `go/views` as every part's are
|
act; its description names it. From G these two tools are served by mesh-sdk's `go/views` as every part's are
|
||||||
@@ -119,12 +124,19 @@ choice, to the bus module's. Each choice below says so.
|
|||||||
- §7 **What exists today, and its fate.** The live-event path stays whole (design 25 bus-state §4). The bus module's
|
- §7 **What exists today, and its fate.** The live-event path stays whole (design 25 bus-state §4). The bus module's
|
||||||
`list`, `show` and `orphans` keep every field they answer and gain `binding`. The grants part reads no other
|
`list`, `show` and `orphans` keep every field they answer and gain `binding`. The grants part reads no other
|
||||||
module's bus state and gains no grant on the shared stream `EVENTS` beyond its durable consumer of the three events:
|
module's bus state and gains no grant on the shared stream `EVENTS` beyond its durable consumer of the three events:
|
||||||
a missed event is recovered by asking its owner, never by reading the stream back by hand. The order between the
|
a missed event is recovered by asking its owner, never by reading the stream back by hand. **The order, and what
|
||||||
three repositories needs no edge of the module graph: a grants part that meets an answer without `binding` (a bus
|
the first wording missed.** This line first said the order between the repositories needs no edge of the module
|
||||||
module's build from before this milestone) writes nothing from it, says so once in its log naming the seat and
|
graph, because a grants part meeting an answer without `binding` wrote nothing from it and kept working on the
|
||||||
the verb, and keeps working on the events, and the edges between the grants part and the bus module lie on the
|
events. It missed that the bus module's own build goes through the registry (corrected 2026-11-11, issue 1966): its
|
||||||
foundation's cycle, where ADR 0615 §2 has the owner's answer and the reader's wait carry the order. One delivery
|
image build asks the seat `container-image-registry`'s `mirror` for its base image, which the registry holder
|
||||||
carries mesh-contracts, mesh-sdk, the nats module (mesh-catalog) and the grants part (mesh-delivery).
|
serves only with its state `mirrors`, a binding whose `created` the grants part never heard; so the bus module's
|
||||||
|
new build could not be built while the grants part waited for that build's `binding`, a circle. §9 breaks it: the
|
||||||
|
grants part composes the key-value and object-store bindings from the running bus module's answer, so it reaches
|
||||||
|
the machines in a delivery of the grants part (mesh-delivery) alone, with no new build of the bus module (the
|
||||||
|
operator, 2026-11-11 13:30 CET, in the terminal: "Yes, build it"). The order is then the grants part with §9
|
||||||
|
before the bus module's build of this milestone, which mesh-contracts, mesh-sdk and the nats module (mesh-catalog)
|
||||||
|
carry; the edges between the grants part and the bus module otherwise lie on the foundation's cycle, where ADR 0615
|
||||||
|
§2 has the owner's answer and the reader's wait carry the order.
|
||||||
- §8 **How it is checked.** **Whole**: a case in the grants part's existing whole-module integration test (mesh-delivery
|
- §8 **How it is checked.** **Whole**: a case in the grants part's existing whole-module integration test (mesh-delivery
|
||||||
is over its integration budget, so no new test function): a fixture bus module answers `mesh-broker.list` with an
|
is over its integration budget, so no new test function): a fixture bus module answers `mesh-broker.list` with an
|
||||||
entry whose `created` was never said, and after the grants part starts, the module's membership holds that
|
entry whose `created` was never said, and after the grants part starts, the module's membership holds that
|
||||||
@@ -135,4 +147,35 @@ choice, to the bus module's. Each choice below says so.
|
|||||||
**Unit**: the bus module's tools (§2), the grants part's tools (§6), and a table of the grants part's reconcile
|
**Unit**: the bus module's tools (§2), the grants part's tools (§6), and a table of the grants part's reconcile
|
||||||
with one row per case of §4. **Live**: after the delivery, at the grants part's first start, the registry holder's
|
with one row per case of §4. **Live**: after the delivery, at the grants part's first start, the registry holder's
|
||||||
membership names every entry its manifest asks for (`grants_membership`), and `grants_first_views` shows
|
membership names every entry its manifest asks for (`grants_membership`), and `grants_first_views` shows
|
||||||
`bindings` answered with no binding unlisted.
|
`bindings` answered with no binding unlisted. **§9's cases**: unit rows in the same reconcile table, one per
|
||||||
|
case of §9 (a key-value and an object-store entry composed; a stream and a ledger entry left unbound and logged;
|
||||||
|
an entry without `settings` left unbound; an entry whose `settings` lack the bus object named from its `bus-name`
|
||||||
|
left unbound and logged; an answer carrying `binding` taken as it is, nothing composed). **§9 live**: after the
|
||||||
|
delivery of the grants part alone, before any new build of the bus module, `grants_membership` for the registry
|
||||||
|
holder on the machine it runs on lists `holds`, `windows` and `mirrors` beside the entries it held, and
|
||||||
|
`grants_first_views` shows `bindings` answered with those three composed by §9.
|
||||||
|
- §9 **An answer without `binding` is composed from the bus module's own fields, for the storage types it names
|
||||||
|
whole.** A bus module's build from before this milestone answers `list` with no `binding` on any entry; each entry
|
||||||
|
still carries its `module`, `local-name`, `bus-name`, `storage-type`, `template`, `options`, `fill`, and `settings`
|
||||||
|
keyed by the bus object's name (a key-value bucket's stream as `KV_` and its bus name, an object store's as `OBJ_`
|
||||||
|
and its bus name, a stream by its own name). For an entry of such an answer the grants part composes the binding
|
||||||
|
only when its `settings` hold the bus object its `bus-name` names (so the bus holds it, as §2 has `binding`
|
||||||
|
present only on a held entry), and only for the storage types whose binding the answer names whole: for
|
||||||
|
`key-value`, `local` from `local-name`, `storage` from `storage-type`, `template` from `template` and `bucket` from
|
||||||
|
`bus-name`; for `object-store`, the same with `object-store` from `bus-name`. It composes nothing for a `stream`
|
||||||
|
(the answer does not carry its subjects) or a `ledger` (it does not carry its parts), nor for an entry whose
|
||||||
|
`settings` lack its bus object: those are left as today, unbound until the bus module's `created` or `recreated`,
|
||||||
|
or a later answer that carries `binding`. An answer is taken as one without `binding` only when no entry in it
|
||||||
|
carries the field; an answer where any entry carries it is applied by §4 alone, nothing composed. **It is the bus
|
||||||
|
module's own word**: every field the binding takes is the bus module's answer about what it holds, from its seat,
|
||||||
|
and the grants part adds no name and reads no bus state of its own, so ADR 0595 §1 and §7 (the binding is the bus
|
||||||
|
module's to say and the grants part's to write) and ADR 0596 §2 hold. **How it is said**: once per answer, a log
|
||||||
|
line of the grants part naming the seat `mesh-broker` and the verb `list`, that the answer carries no `binding`,
|
||||||
|
how many bindings it composed and every entry it left unbound by module, local name and storage type; each
|
||||||
|
binding then written is logged by §4 with the cause "first view, composed from `list`'s fields". `grants_first_views`
|
||||||
|
shows the same (§6). **Its fate**: it stays after the bus module's build of this milestone is everywhere, since it
|
||||||
|
acts only on an answer no entry of which carries `binding`, which that build never gives, and covers a bus module
|
||||||
|
held back or set back to an earlier build. Why: the operator's answer of 2026-11-11 13:30 CET (in the terminal,
|
||||||
|
to lead-47, for issue 1966), under ADR 0595 §1 and §7; the fields, the storage types and the log are the design's
|
||||||
|
choice following that answer and the bus module's `list` answer as it stands today (issue 1966, read live
|
||||||
|
2026-11-11). How it is checked: §8, §9's cases and §9 live.
|
||||||
|
|||||||
@@ -738,7 +738,7 @@ tools, then follow its events.
|
|||||||
| A module asking bus state waits for the bus module | the module graph's table test: a manifest with a ledger entry has a requirement edge to the module providing `bus-state`, one without has none (ADR 0614 §5) |
|
| A module asking bus state waits for the bus module | the module graph's table test: a manifest with a ledger entry has a requirement edge to the module providing `bus-state`, one without has none (ADR 0614 §5) |
|
||||||
| A foundation part's first view | unit tests of each owner and reader (ADR 0615's How it is checked), as table cases, and these cases of the whole-module integration tests that exist today (mesh-delivery is over its integration budget, so no new test function): the indexer's (`modules/mesh-delivery-indexer`, its one whole-module test, which the milestone's packages test merges into), the assigner's (`modules/mesh-delivery-assigner`) and the grants part's (`modules/mesh-grants`), and the tool runner's in mesh-tools: the owner answers its verb at once from what it holds, with its revision, before its own first view; the reader asks once at start, then only on a gap in revisions; a reader whose owner is down raises its condition only past the bound and never reads the owner's state, and the owner's answer clears it; an empty answer at revision 0 drops no login; an owner's event carries the changed value whole, and a reader applies a put and a delete from the events alone and never asks the verb; a revision lower than the one held makes the reader ask its first view again; an existing waiter on `manifest-accepted` or on the assigner's `put` does not wake on the new families; for the indexer's `verdicts` (ADR 0622), called by the grants part while the node's tool runner is stopped, it answers, and from any other account, the indexer's own included, it is refused; a missed revision on `manifest-refused` makes the grants part ask `verdicts` once more; the grants part and the indexer started at the same moment, `verdicts` answers within the bound with its revision; with the indexer down past the bound the grants part raises the condition naming the indexer and `verdicts` and never reads the indexer's state, and the answer clears it; for the indexer's `graph` (ADR 0631), called by the assigner it answers with its revision, and from any other account, the indexer's own included, it is refused; a missed revision of the bucket `graph` on `indexer.views` makes the assigner ask `graph` once more; started with the indexer down, the assigner raises past the bound the first-view condition naming the indexer and `graph` and reads nothing of the indexer's state, and the answer clears it; the read tool shows the revision each reader holds, and the re-read tool asks once and records the hand act; in the assigner's whole-module test, the assigner starts before any new-form bus state exists, with no binding of the bus module, and the indexer, the grants part and the tool runner each get their first view of it. Live, after the delivery: the indexer's `indexer_old_sections`, which the milestone extends to count the `reads` entries on each owner's state, reads 0 declared `reads` entries on the indexer's state and 0 on the assigner's, and says the node-engine's reads granted in the grants part's code remain (§ 12.6); and each owner's read tool of § 12.2 answers what its bucket holds, each status view tool answers a session's call as before the move, and `mesh_search` finds each owner's read tool |
|
| A foundation part's first view | unit tests of each owner and reader (ADR 0615's How it is checked), as table cases, and these cases of the whole-module integration tests that exist today (mesh-delivery is over its integration budget, so no new test function): the indexer's (`modules/mesh-delivery-indexer`, its one whole-module test, which the milestone's packages test merges into), the assigner's (`modules/mesh-delivery-assigner`) and the grants part's (`modules/mesh-grants`), and the tool runner's in mesh-tools: the owner answers its verb at once from what it holds, with its revision, before its own first view; the reader asks once at start, then only on a gap in revisions; a reader whose owner is down raises its condition only past the bound and never reads the owner's state, and the owner's answer clears it; an empty answer at revision 0 drops no login; an owner's event carries the changed value whole, and a reader applies a put and a delete from the events alone and never asks the verb; a revision lower than the one held makes the reader ask its first view again; an existing waiter on `manifest-accepted` or on the assigner's `put` does not wake on the new families; for the indexer's `verdicts` (ADR 0622), called by the grants part while the node's tool runner is stopped, it answers, and from any other account, the indexer's own included, it is refused; a missed revision on `manifest-refused` makes the grants part ask `verdicts` once more; the grants part and the indexer started at the same moment, `verdicts` answers within the bound with its revision; with the indexer down past the bound the grants part raises the condition naming the indexer and `verdicts` and never reads the indexer's state, and the answer clears it; for the indexer's `graph` (ADR 0631), called by the assigner it answers with its revision, and from any other account, the indexer's own included, it is refused; a missed revision of the bucket `graph` on `indexer.views` makes the assigner ask `graph` once more; started with the indexer down, the assigner raises past the bound the first-view condition naming the indexer and `graph` and reads nothing of the indexer's state, and the answer clears it; the read tool shows the revision each reader holds, and the re-read tool asks once and records the hand act; in the assigner's whole-module test, the assigner starts before any new-form bus state exists, with no binding of the bus module, and the indexer, the grants part and the tool runner each get their first view of it. Live, after the delivery: the indexer's `indexer_old_sections`, which the milestone extends to count the `reads` entries on each owner's state, reads 0 declared `reads` entries on the indexer's state and 0 on the assigner's, and says the node-engine's reads granted in the grants part's code remain (§ 12.6); and each owner's read tool of § 12.2 answers what its bucket holds, each status view tool answers a session's call as before the move, and `mesh_search` finds each owner's read tool |
|
||||||
| The owners' first views are their own tools, in a runtime of their own (ADR 0621) | cases of the indexer's and the assigner's whole-module integration tests: each first-view tool, called from a reader's account while the node's tool runner is stopped, answers (§1); each answers its granted readers and refuses every other account, the owner's own included (§2); the two runtimes started at the same moment, each asking the other's first view at start, both answer within the first-view bound with their revisions (§3); and the milestone's group passes its merge check with no change to the manifest validator's known fields for these verbs (§4) |
|
| The owners' first views are their own tools, in a runtime of their own (ADR 0621) | cases of the indexer's and the assigner's whole-module integration tests: each first-view tool, called from a reader's account while the node's tool runner is stopped, answers (§1); each answers its granted readers and refuses every other account, the owner's own included (§2); the two runtimes started at the same moment, each asking the other's first view at start, both answer within the first-view bound with their revisions (§3); and the milestone's group passes its merge check with no change to the manifest validator's known fields for these verbs (§4) |
|
||||||
| The grants part's first view of the bindings (design 25 bindings-first-view) | the cases of design 25 bindings-first-view §8: a case in the grants part's existing whole-module integration test, where a binding whose `created` was never said is written after a start; unit rows of the bus module's tools and the grants part; live, the next start after the delivery |
|
| The grants part's first view of the bindings (design 25 bindings-first-view) | the cases of design 25 bindings-first-view §8: a case in the grants part's existing whole-module integration test, where a binding whose `created` was never said is written after a start; unit rows of the bus module's tools and the grants part, §9's rows among them (a binding composed from an answer without `binding`); live, the next start after the delivery, and §9's live case after the grants part's delivery alone |
|
||||||
| A foundation part's first view comes within its bound | live, after the delivery: each reader's read tool (`grants_first_views`, the mesh MCP server's `mesh_first_views`, `indexer_first_views`, `assigner_first_views`) shows, for the indexer's and the assigner's verbs, the time from its ask to the owner's answer under the two-minute bound, and no first-view condition raised by the delivery |
|
| A foundation part's first view comes within its bound | live, after the delivery: each reader's read tool (`grants_first_views`, the mesh MCP server's `mesh_first_views`, `indexer_first_views`, `assigner_first_views`) shows, for the indexer's and the assigner's verbs, the time from its ask to the owner's answer under the two-minute bound, and no first-view condition raised by the delivery |
|
||||||
| The bus module's first view | cases in the nats module's one integration test: a replayed verdict older than the first view is not applied; an `indexer_bus_state` that does not answer turns the health unhealthy naming it and is asked again on the backoff; a set-aside manifest missing from the first view keeps its `asked` key, an empty `manifest-accepted` removes it; a deleted module's entry, after its empty `manifest-accepted`, is listed by `orphans` and raises `orphaned`, and a set-aside module's entry is neither; `nats_first_view_again` asks at once and records the hand act |
|
| The bus module's first view | cases in the nats module's one integration test: a replayed verdict older than the first view is not applied; an `indexer_bus_state` that does not answer turns the health unhealthy naming it and is asked again on the backoff; a set-aside manifest missing from the first view keeps its `asked` key, an empty `manifest-accepted` removes it; a deleted module's entry, after its empty `manifest-accepted`, is listed by `orphans` and raises `orphaned`, and a set-aside module's entry is neither; `nats_first_view_again` asks at once and records the hand act |
|
||||||
| `manifest-accepted` is never lost silently | unit tests of the indexer: a failed publish is published again, and one still failing writes the finding; `indexer_say_accepted` says it again for one module from the verdict held, and refuses a module with no accepted verdict |
|
| `manifest-accepted` is never lost silently | unit tests of the indexer: a failed publish is published again, and one still failing writes the finding; `indexer_say_accepted` says it again for one module from the verdict held, and refuses a module with no accepted verdict |
|
||||||
|
|||||||
Reference in New Issue
Block a user