diff --git a/04-ISSUES/235-an-assignment-that-cannot-be-composed-is-recorded-anyway/00-report.md b/04-ISSUES/235-an-assignment-that-cannot-be-composed-is-recorded-anyway/00-report.md new file mode 100644 index 0000000..b23e037 --- /dev/null +++ b/04-ISSUES/235-an-assignment-that-cannot-be-composed-is-recorded-anyway/00-report.md @@ -0,0 +1,48 @@ +--- +status: open +opened: 2026-10-04 +located-in: [] +fixed-by: +amended-design: +--- + +# 235 — An assignment that cannot be composed is recorded anyway, and the node is one push from leaving the mesh + +## What was observed + +2026-10-04, assigning thirteen desktop modules to a workstation in one `assign`. The controller +answered `ok: false`. Its output first confirmed every module (` is assigned `, thirteen +times), then repeated the same reason eleven times: + +``` + is not counted as on the network: it does not resolve: these assignments cannot be applied: + - i3status-rust and pacman both declare the package "pacman-contrib" + is left out of the rest of the mesh: it does not resolve: … +``` + +and ended with the node's needs from the control node (artifact store, internal CA, package registry) +reported as unmet "because they are not both on the private network". + +The thirteen assignments stayed recorded. `plan` for the node failed until one module was unassigned +by hand. Had anything pushed in that window — a person, a plan rolling out a rebuilt module, another +session — the mesh would have composed every node without this one on the private network, and this +node without its own declaration. + +## Why it matters beyond this instance + +[ADR 0207](../../02-DECISIONS/0207-a-module-depends-on-the-node-seats-that-apply-its-resources.md) +says `assign` judges the modules together and refuses what cannot be met. It judges seats. A +collision found only at composition — two modules declaring one package, one file, one port — is +reported after the assignment is written, as if it were a warning. The result is the most dangerous +state a node can be in: assigned, unresolvable, and silently dropped by the next push of anything. + +The reason was also hard to read: one fault, said eleven times, with three follow-on complaints that +point at the network instead of at the collision. + +## Open questions + +1. Should `assign` compose the node with the new assignments before writing them, and refuse the + whole call when composition fails? The node would then never become unresolvable through `assign`. +2. When a node does not resolve for any reason, should a push of other nodes keep its last composed + state in theirs rather than drop it from the private network? +3. Should one composition fault be reported once, with the follow-on unmet needs folded under it? diff --git a/04-ISSUES/236-the-catalogue-check-passes-a-manifest-the-host-refuses/00-report.md b/04-ISSUES/236-the-catalogue-check-passes-a-manifest-the-host-refuses/00-report.md new file mode 100644 index 0000000..c0f4e3c --- /dev/null +++ b/04-ISSUES/236-the-catalogue-check-passes-a-manifest-the-host-refuses/00-report.md @@ -0,0 +1,37 @@ +--- +status: open +opened: 2026-10-04 +located-in: [] +fixed-by: +amended-design: +--- + +# 236 — The catalogue check passes a manifest the host refuses + +## What was observed + +2026-10-04. A login-manager module passed `mesh-controller module check`, was registered, built and +assigned. The first push of its declaration was refused whole by the host: + +``` +refused a declaration: this declaration is refused, and none of it was applied: + - resource "lemurs.service": a service that omits state leaves the unit's lifecycle to the + machine, and boot and takes-over are both its lifecycle +``` + +The rule is the host's declaration validation. The controller's check never applies it, so a manifest +can pass every check the catalogue has and still fail on the first machine that receives it. + +## Why it matters beyond this instance + +A refusal is whole, so one module with this fault blocks every other change for that node until the +module is fixed, rebuilt and pushed again. The fault is static: it is in the manifest, and could be +found before a module is merged. Today it is found by assigning the module to a live machine. + +## Open questions + +1. Should the host's declaration validation be importable, so that `module check` (and registration) + runs it over each resource the manifest declares? +2. Or should the controller validate the composed declaration before it sends it, and refuse to send + one the host would refuse? +3. Which other host-side rules are not visible to the catalogue check today?