The numbering is the flow: decisions are 02, design is 03
papa-hq reads 01 research -> 03 decision -> 02 design. The order is a scar, not a choice: 02-DESIGN existed from its initial commit, and when adr/ was finally promoted on 2026-07-13 it took the next free number rather than its place in the sequence. By then design was too settled to renumber. hal-hq was three commits old, so it is not. adr/ becomes 02-DECISIONS and 02-DESIGN becomes 03-DESIGN, and following the folder numbers now walks the process in the order it happens: research produces a decision, the decision authorises a design. 00-GENESIS becomes 00-META, matching papa's rename from the same restructure. Every path reference rewritten across documents, frontmatter, playbooks and skills. All links resolve; all 58 frontmatter blocks parse and their path fields still point at files that exist.
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
---
|
||||
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. |
|
||||
| **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)
|
||||
|
||||
### 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.
|
||||
Reference in New Issue
Block a user