Jochen asked whether the order made sense. It did not -- it followed when things happened to be decided, which after consolidation is fictional anyway since record 5 alone folds decisions taken across a week. Concretely wrong before: the domain statement sat at 8, after five engineering rules; the constitution was scattered across 5, 12 and 17; the tiers landed at 15, 16, 21 and 22 with process records in between. Now it walks: what the mesh is (1-3), its tiers from the bottom up (4-8), what runs on them and how it gets there (9-10), how it is built (11-16), how it is checked (17-18), how we work (19-23). Two things made this safe rather than free. It is a permutation, not a compaction, so the renames go through temporary names -- otherwise two files want one slot and one is lost. And the reference rewrite is a single simultaneous pass, because almost every number moved into a slot another number was vacating; replacing one at a time would have cascaded and pointed things at the wrong record while still resolving. Verified: 284 [ADR NNNN](path) links across the repository, all with matching text and target. The ordering principle is now stated in 19 rather than left implicit -- the repository already said "the numbering is the flow" about its folders, and there was no reason for the records to be the exception.
101 lines
4.8 KiB
Markdown
101 lines
4.8 KiB
Markdown
---
|
|
layer: as-is
|
|
status: implemented
|
|
code: [hal]
|
|
updated: 2026-08-23
|
|
decisions:
|
|
- 02-DECISIONS/0010-delivery.md
|
|
- 02-DECISIONS/0010-delivery.md
|
|
- 02-DECISIONS/0010-delivery.md
|
|
---
|
|
|
|
# Delivery — from a push to a running node
|
|
|
|
One trigger, three silos, and a fan-out point that is the most consequential boundary in the
|
|
mesh.
|
|
|
|
## The trigger
|
|
|
|
A push to the forge. The forge calls a webhook; the receiving module verifies its signature
|
|
and emits an event. The coordinator resolves which modules the pushed commits affect, orders
|
|
them into dependency levels, and creates a pipeline per level.
|
|
|
|
There is no second path. A manual trigger exists for a module the push detection missed, and
|
|
using it routinely is a sign the detection is wrong rather than a workflow.
|
|
|
|
Detection is the pipeline's most fragile input. It has failed for reasons that have nothing to
|
|
do with the change: a webhook truncating its commit list on a large merge, a forge address
|
|
whose port broke the module-path matching. The characteristic outcome is the bad one — **a
|
|
merge that created no pipeline, and nothing said so**.
|
|
|
|
## Three silos
|
|
|
|
Cardinality is the whole point, and the three differ
|
|
([ADR 0010](../../02-DECISIONS/0010-delivery.md)):
|
|
|
|
| Silo | Runs | Where | Does |
|
|
|---|---|---|---|
|
|
| **build** | once per module feature | the build node | compile and bundle into a self-contained output |
|
|
| **publish** | once per module feature | the build node | package that output and upload it; a package-registry feature publishes here |
|
|
| **deploy** | once per module feature **per node** | every assigned node | install, configure, start, verify |
|
|
|
|
Commands and events are addressed per feature, not per module.
|
|
|
|
Build hands over a **staged tree**, not a package. Packaging belongs to publish, so a failed
|
|
upload retries by re-packaging rather than by re-sending something stale, and build never needs
|
|
to know how each module composes its artifact. The handover is a tree in a known location,
|
|
because the build's own working directory is reference-counted and may be gone by the time a
|
|
later stage runs.
|
|
|
|
## The artifact
|
|
|
|
The artifact is **build output** — compiled and bundled with its dependency graph inlined —
|
|
never a filtered copy of source ([ADR 0010](../../02-DECISIONS/0010-delivery.md)).
|
|
A deploy is extract-and-run and touches no network.
|
|
|
|
The consequence is the whole cost of the decision: **anything not in the build output does not
|
|
ship.** Every file kind had to be brought into that rule separately, and each was discovered by
|
|
something silently not happening after deploy — migrations reading a source layout, provisioning
|
|
scripts reading a source layout, selection files never packaged at all.
|
|
|
|
## The fan-out, and the build node
|
|
|
|
After publish, work fans out to every assigned node. The build node is the only node that has
|
|
already passed through two silos when this happens, and that asymmetry has its own defect
|
|
class: anything advancing a node's stage must account for **both** pre-fan-out stages. Code
|
|
that knew only about the first parked the build node forever while every other node deployed
|
|
cleanly — and the recovery sweeper, which knew the same subset, reported nothing to recover.
|
|
|
|
A recovery mechanism that knows less than the thing it guards is worse than none, because it
|
|
reports success over a stall it cannot see.
|
|
|
|
## Levels
|
|
|
|
A level completes before the next begins, so a module builds against its dependencies as they
|
|
were just published. The shared library is at level zero, which means anything that breaks it
|
|
breaks the first module of every cascade.
|
|
|
|
## What green proves
|
|
|
|
**A green pipeline proves transport, not effect.** The stages report that a message was
|
|
dispatched and accepted, which is not the same as the thing being running, correct, or present.
|
|
|
|
This is the mesh's most consistent failure shape and it is not incidental to the design — it is
|
|
what the stage reporting currently measures. Documented instances include a service reported
|
|
started when the container command merely returned, an image pull failure that did not fail the
|
|
deploy, a package install that 404ed from every mirror while the job went green (see
|
|
[`04-ISSUES/001`](../../04-ISSUES/001-failed-package-install-reports-success/00-report.md)),
|
|
and a node left on old code after a failed artifact download with a version marker that had
|
|
already advanced.
|
|
|
|
A verify stage exists to close this gap. It has been built and, for a period, was never
|
|
scheduled, because the coordinator's stage list did not include it.
|
|
|
|
## What is not covered
|
|
|
|
The end-to-end harness for this pipeline has not built since the workspace was removed, and
|
|
nothing reports that nothing runs it
|
|
([`04-ISSUES/005`](../../04-ISSUES/005-pipeline-test-harness-unbuildable/00-report.md)). The
|
|
pipeline's coverage is currently assumed rather than checked — which is the same class of claim
|
|
this repository exists to make people stop making.
|