Three things from walking a real dev cycle through 0063, all of which Jochen caught by pushing on where I had glossed. 0064 -- a build edge is a third kind. Research 011 established presence and instantiation, and both are RUNTIME edges: they answer what a module needs in order to run. Delivery needs a different question -- what has to be rebuilt when this changes -- and that relationship is fixed inside an artifact rather than negotiated when it runs. So the graph as designed could not drive delivery, which is the real reason 0063 was not approvable. It is derived rather than declared, read from what a module actually imports, because a declared list and the imports it describes drift and the imports are the true ones. The runtime edges stay declared, and that asymmetry is not an inconsistency: a runtime edge is an intention somebody has, a build edge is a fact about code that exists. It also makes design quality measurable. A module with many inbound build edges is one whose every change is expensive, and the current shared library is exactly that -- nobody could see it because nothing drew the edges. 0065 -- the core library is the mesh's domain. Jochen disagreed with 0030's "types, not behaviour" and was right: that guard is aimed at the wrong thing. A library everything depends on is a hub whether it holds types or code, and the fan-in is what makes a change expensive. So types ship with the module that owns them -- trading one wide edge for several narrow ones -- and the core library holds what is true of the mesh regardless of context, which research 011 already found: a module, a node, an assignment. The test is "would this still mean the same thing in a context that had never heard of the one it came from". A node does; a pipeline stage does not. Domain-driven is the point rather than the label: "who else might want this" always answers yes, which is how the current one grew. And it changes the check for the better. "The build output contains no runtime code" would have enforced a rule now withdrawn. Inbound build edges is a measurement rather than a prohibition, and it is visible while a hub is forming rather than after. 0063 revised on both counts, plus a third: I had written "the lab judges it" as though that were a step. A lab run takes tens of seconds, occupies a VM, and fails for environmental reasons -- and a shared-library change produces dozens. One expensive non-deterministic gate fails both ways, and neither failure looks like itself. Verdicts are now tiered, and a run that failed environmentally is explicitly not a verdict. 0063 also now carries what must exist before it can be implemented, rather than leaving that to be discovered.
5.3 KiB
status, date, deciders, reconstructed
| status | date | deciders | reconstructed |
|---|---|---|---|
| accepted | 2026-08-23 | jochen | false |
30. The repository structure, and the rule that names them
Context
The tiers are settled (research 006) and the product is named (ADR 0027), but the repositories themselves were only ever sketched in research. Two consequences had already appeared.
ADR 0029 makes the lab phase 0 of the entire migration and could not say where it lives, because no record named a repository.
And the research contradicted an accepted record: it listed mesh-hq for this repository, while
ADR 0028 had decided novox/hq and explicitly rejected that
name. A design resting on research is a design resting on something that can change without a
decision.
There is also an implied naming rule that has never been written down. ADR 0027 says
repository names take mesh; ADR 0028 gives this repository no prefix at all. Both are right,
for a reason neither states.
Considered options
Only the naming rule had genuine alternatives; the tier repositories follow from the tiers.
- No prefix —
novox/host,novox/control. The organisation already says Novox, so the prefix reads as stutter. Rejected once it was established that Novox delivers more than the mesh: with several products the prefix is not stutter, it is the product namespace doing real work, and the forge has no nested groups to do it instead. - An organisation per product —
novox-mesh/host. Puts the product boundary where the forge's only real grouping primitive lives, so permissions and teams attach to it. Rejected for now as premature: no per-product access boundary exists yet, and it costsnovox-repeated across every organisation. - Product-prefixed repositories in the company organisation. Chosen.
Decision
The naming rule: a repository that belongs to a product carries that product's prefix. A repository that is company-scoped does not.
That is why this one is hq and the mesh's are mesh-*. Both records were already correct;
the rule connecting them is stated here.
The repositories:
| Repository | Tier | Holds |
|---|---|---|
novox/mesh-host |
0 | the node host — the one binary installed by hand |
novox/mesh-substrate |
1 | the four pinned services, as declarations |
novox/mesh-control |
2 | the control plane and its contexts |
novox/mesh-surfaces |
3 | tools, web, cli — thin, no logic |
novox/mesh-sdk |
— | |
novox/mesh-lab |
— | the lab: scenario lifecycle, networking, placement |
novox/hq |
— | this repository. Company-scoped (ADR 0028) |
The lab is its own repository. Its lifecycle differs from everything else in the list: it is never shipped to a node, it outlives any single tier, and it drives virtualisation on a workstation — which nothing else in the mesh does. Putting it inside the host would couple development tooling to a shipped component; putting it inside the control plane would make the bootstrap scenario depend on a tier that does not exist when it is needed.
Tier 4 is deliberately not decided here. Whether the catalogue is one repository, one per
domain, or one per application remains open from
ADR 0015 and is blocked on
research 005: how many repositories hold
domains cannot be answered before what the domains are. Recording the gap is the point —
mesh-catalog appears in the research sketch and is not decided by this record.
Consequences
- ADR 0029 can name its target. Phase 0 has a home, which was the immediate blocker.
- The research sketch stops being load-bearing. It remains what it is — a sketch — and the design layer can now cite a record instead.
- Seven repositories where there is currently one, for a mesh that today lives in a single monorepo. That is the cost, and it is not small: seven release cadences, seven sets of dependencies, and cross-repository changes that were previously one commit. The offsetting argument is the tier rule — a boundary that only points downward is enforceable across repositories and merely conventional inside one.
- The prefix will read as redundant for as long as the mesh is the only product with repositories. That is accepted deliberately: the alternative is renaming everything at the moment a second product appears, which is the class of migration this project is trying to stop performing.
- Nothing is created yet. This records what the repositories are; creating them is part of phase 0 and after.
References
- ADR 0027 — the product name the prefix comes from.
- ADR 0028 — why this repository has no prefix.
- ADR 0029 — the lab, and why it is first.
- Research 006 — the tiers, and the sketch this supersedes as a source.