A skeleton laid out against the stated requirements rather than derived from the current shape: four tiers, repositories at the root, and a dependency rule that only points downward. Four moves the current shape does not have. The substrate is applied by the agent from a pinned bundle, not delivered by the pipeline. That is the bootstrap circularity removed rather than worked around — the first node is the ordinary path with no control plane on the other end, which also makes it the cheapest lab scenario instead of the one nobody exercises. One agent binary with a detected capability profile — managed, user, edge. A phone becomes a capability question rather than a platform question, so it needs no second implementation. Modules declare which profiles they can land on, and an impossible assignment fails at declaration. Connectivity becomes a context. ADR 0015 names nine and none owns the overlay, resolver, firewall or ingress, while research 005 measured reachability as the only cluster in the catalogue that genuinely changes together under one intent. Gap and evidence point the same way. That is an addition to an accepted record, so it needs its own record and is not written here. Feature splits into artifact (built once per version) and part (selected per node). The conflation of those two cardinalities under one word is what makes the delivery pipeline hard to reason about. Also makes explicit in how-we-build that the main-branch rule covers this repository too. The rule already said 'without exception'; nothing was amended, so nothing is recorded.
191 lines
10 KiB
Markdown
191 lines
10 KiB
Markdown
---
|
|
status: canonical
|
|
updated: 2026-08-23
|
|
derives: knowledge-base constitution page
|
|
decisions:
|
|
- 02-DECISIONS/0009-the-mesh-is-governed-by-a-constitution.md
|
|
---
|
|
|
|
# How we build
|
|
|
|
The rules that hold across the mesh. Short, and each one earned.
|
|
|
|
**This document is the source of the mesh constitution.** The governed page the mesh injects
|
|
into design sessions is *derived* from it, section for section, and carries the rules without
|
|
the reasoning. Never edit that page directly — an edit there survives until the next sync and
|
|
then vanishes, taking its reasoning with it. The sync is playbook
|
|
[`process/05-constitution-sync.md`](process/05-constitution-sync.md), and it is how the claim
|
|
"HQ is the source" is checked.
|
|
|
|
Section numbers are stable. The orchestrator and the review fragments cite them.
|
|
|
|
---
|
|
|
|
## 1. Purpose
|
|
|
|
These are the principles and guardrails every piece of work in the mesh is checked against —
|
|
design sessions, analysis gates, reviews, and agents acting on their own. A rule stated here is
|
|
non-negotiable unless amended per §6.
|
|
|
|
They exist because each was violated first. Where a rule reads as arbitrary, that is a sign the
|
|
incident behind it is not written down, and the fix is to write it down, not to relax the rule.
|
|
|
|
---
|
|
|
|
## 2. Non-negotiables
|
|
|
|
| Rule | What it means |
|
|
|---|---|
|
|
| **Never write to a production database directly** | No insert, update, delete or schema statement executed against production by hand. Schema changes go through numbered migrations; data changes go through application code or the module's own capabilities. Raw statements skip every side effect the proper path has — events, audit, cache invalidation, fan-out. |
|
|
| **Every schema change is a migration** | Numbered, in the module's own language, compiled with it. Both a baseline for a fresh installation *and* an incremental migration for installations that already exist. If code references a column, the migration creating it must exist. [ADR 0006](../02-DECISIONS/0006-schema-changes-are-numbered-migrations.md) |
|
|
| **Never bypass the pipeline** | No manual database edit, no manual restart as a workaround. Fix the cause and deploy. A workaround that works is a workaround that is never removed, and the next person cannot tell the node from its declaration. |
|
|
| **Never create a symlink** | A hand-made link caused production data loss through container volume resolution, and the judgement needed to make a safe exception is exactly the judgement unavailable at the moment it matters. Today the installer owns and reconciles the links the mesh still uses [ADR 0011](../02-DECISIONS/0011-the-installer-owns-linking.md); the intent is that the mesh creates none at all [ADR 0018](../02-DECISIONS/0018-the-mesh-creates-no-symlinks.md). Neither reading permits you to make one. |
|
|
| **Never push directly to the main branch** | Branch, push, review, merge. Every merge is a human checkpoint, without exception — **including in this repository**. A documentation repository is not a lower tier of care; a decision record lands the same way a service does. |
|
|
| **One change per pull request, and never merge your own** | Unrelated improvements bundled together cannot be reviewed or reverted separately. Self-merging removes the checkpoint that is the entire point. |
|
|
| **Never open a pull request unprompted** | A permissions list saying it is allowed is not a request. |
|
|
| **A failed step fails the job** | A sequence that continues past a failure does the next thing in the wrong place. Gate each step on the last. [ADR 0008](../02-DECISIONS/0008-a-failed-step-fails-the-job.md), and §5. |
|
|
|
|
### A failed step must stop the steps after it — how it was earned
|
|
|
|
A worktree creation failed because the branch name collided with an existing namespace. The
|
|
change into that worktree failed too. The copy, the staging and the commit that followed all
|
|
ran in the shared checkout and committed to a local main. The error was printed and scrolled
|
|
past.
|
|
|
|
This is the same shape as the faults the mesh's whole refactor exists to remove: a step
|
|
reported failure, nothing stopped, and the damage happened somewhere nobody was looking.
|
|
|
|
---
|
|
|
|
## 3. Module and infrastructure rules
|
|
|
|
### Manifests
|
|
|
|
- **Never bump a version by hand.** The builder owns versioning. A version change in a diff is
|
|
a defect; revert it.
|
|
- **Features are detected, not declared.** The installer discovers what a module carries from
|
|
what its directory contains. A declared list and the directory it describes drift, and the
|
|
directory is the one that is true.
|
|
- **Every runtime variable is declared.** A variable the module reads and the manifest does not
|
|
declare is invisible to the mesh: it will not be generated, injected, or audited.
|
|
- **Provisioned credentials arrive through declared requirements**, never hardcoded in code,
|
|
compose files or scripts. [ADR 0005](../02-DECISIONS/0005-capabilities-are-provisioned-on-declaration.md)
|
|
- **Never install a package by hand.** A package is declared in the manifest and arrives the
|
|
way every other package does. A hand-installed package is invisible to the mesh: it is not
|
|
declared, not reproduced on the next node, and not present after a rebuild — and the node
|
|
works until it doesn't.
|
|
|
|
### Placement
|
|
|
|
- **Core modules belong to the monorepo** — the runtime, delivery, provisioning, configuration,
|
|
knowledge, and the shared infrastructure the mesh provisions against.
|
|
- **Every standalone application gets its own repository**, with a manifest at its root,
|
|
registered as a build source. Creating an application directory in the monorepo is a
|
|
convention violation and reviewers reject it.
|
|
[ADR 0010](../02-DECISIONS/0010-applications-live-in-their-own-repository.md)
|
|
|
|
### Migrations
|
|
|
|
- Numbered, idempotent, and safe to re-run. Guard every statement.
|
|
- The initial migration is **frozen** once it has run anywhere. Change is a new number.
|
|
- Numbers are unique. A duplicate prefix is a defect, not a style question.
|
|
|
|
### Managed files
|
|
|
|
**A file edited on a node is a bug with a delay on it.** Everything under the mesh's managed
|
|
surface is regenerated from the mesh database; a local edit survives one synchronisation and is
|
|
then silently overwritten, bringing back whatever it fixed. Use the mesh operation that owns
|
|
the value. If unsure whether a file is managed, ask the tooling — the answer is not visible
|
|
from the file. [ADR 0004](../02-DECISIONS/0004-managed-files-are-generated-never-edited.md)
|
|
|
|
---
|
|
|
|
## 4. Naming and boundaries
|
|
|
|
### Name a context after its aggregate, not after a metaphor
|
|
|
|
A context named `agents` owns **Agent**. A *brain* — memory, thoughts, cognition — is something
|
|
an agent **has**: a concept inside the aggregate, not a module.
|
|
|
|
The cost of getting this wrong is visible today. An anatomy name points at the node runtime, so
|
|
the most evocative word in the system names infrastructure; another describes itself as "mesh
|
|
messaging" in its manifest while the anatomy documentation calls it the interactive runtime —
|
|
and it runs on no node at all.
|
|
|
|
Anatomy makes attractive names and poor boundaries. Name the thing the domain calls it.
|
|
|
|
### Group by domain, not by single function
|
|
|
|
A module is a purpose, not a piece of software. Four modules that together constitute "how a
|
|
node is reachable" and cannot be assigned, versioned or replaced as one thing are four
|
|
accidents, not four boundaries.
|
|
[ADR 0017](../02-DECISIONS/0017-modules-outside-the-core-are-grouped-by-domain.md)
|
|
|
|
### Contexts integrate through the record, never through a shared schema
|
|
|
|
Publish to the stream; do not join across a boundary. Today several domains share one
|
|
forty-five-table schema, which is why work belonging to one context keeps having to be
|
|
implemented in another.
|
|
|
|
---
|
|
|
|
## 5. Evidence and verification
|
|
|
|
### Ubiquitous language is checked, not assumed
|
|
|
|
**If a document states a rule about the mesh, it says how the rule is verified.** This
|
|
repository has a documented requirement that every capability-exposing module declare the core
|
|
runtime as a dependency. Zero modules do.
|
|
|
|
An unenforced rule is indistinguishable from a wrong one, and costs more, because people
|
|
believe it.
|
|
|
|
### Behavioural criteria require runtime evidence
|
|
|
|
A criterion of the form *"the script runs"*, *"the endpoint answers"*, or *"the migration
|
|
applied"* is satisfied only when the change has actually been exercised: a real run, a real
|
|
request, a pipeline log, a live query showing the expected result.
|
|
|
|
**Marking a runtime criterion verified from a diff is itself a violation.** A reviewer who
|
|
finds one names the evidence required and returns the work.
|
|
|
|
The reason is the mesh's most consistent failure shape: a green result proves transport, not
|
|
effect. Absence reads as success unless something looked.
|
|
|
|
### Search the record before forming a hypothesis
|
|
|
|
The first action on any error message, failing service or unexpected behaviour is to search the
|
|
operational memory for the literal error text — before a hypothesis, not after one fails. The
|
|
knowledge base is indexed on symptoms.
|
|
|
|
This fires hardest on *familiar* ground, where a confident trail feels like progress. Two
|
|
entries were each rediscovered from scratch over several hours in a single session because the
|
|
search was skipped. Both were already written down.
|
|
|
|
---
|
|
|
|
## 6. Amendment
|
|
|
|
This document is governed. It does not change by commit message or unilateral decision.
|
|
|
|
1. **Propose** — a change stating what rule is changing, why the current wording is
|
|
inadequate, and what reviewed it.
|
|
2. **Review** — sign-off by reviewers who are not the proposer.
|
|
3. **Record** — the change is a decision and gets a record in [`02-DECISIONS/`](../02-DECISIONS/), because a
|
|
rule the mesh enforces is architecturally significant.
|
|
4. **Sync** — playbook [`process/05-constitution-sync.md`](process/05-constitution-sync.md)
|
|
publishes the derived page. An unsynced rule is a rule the mesh does not enforce, whatever
|
|
this document says.
|
|
|
|
No drive-by edits. Every change traces to a recorded decision.
|
|
|
|
---
|
|
|
|
## 7. Overrides
|
|
|
|
A team or product may define additional constraints that **narrow or tighten** these rules.
|
|
They may never relax them.
|
|
|
|
An override says which rule it tightens, or which gap it fills, and follows the same amendment
|
|
process. Absence of an override means these rules apply unmodified.
|