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,86 @@
|
||||
---
|
||||
layer: as-is
|
||||
status: implemented
|
||||
code: [hal]
|
||||
updated: 2026-08-23
|
||||
decisions:
|
||||
- 02-DECISIONS/0004-managed-files-are-generated-never-edited.md
|
||||
- 02-DECISIONS/0005-capabilities-are-provisioned-on-declaration.md
|
||||
---
|
||||
|
||||
# Configuration and secrets
|
||||
|
||||
Every value a module reads at runtime comes from a file on a node's disk. Every one of those
|
||||
files is **generated**.
|
||||
|
||||
## The rule
|
||||
|
||||
A managed file is derived from the mesh database. A synchroniser rewrites it when the values
|
||||
behind it change. The write path is the mesh operation that owns the value; the file is an
|
||||
output ([ADR 0004](../../02-DECISIONS/0004-managed-files-are-generated-never-edited.md)).
|
||||
|
||||
An edit to a managed file survives until the next synchronisation and is then overwritten
|
||||
silently, taking whatever it was fixing with it — bringing back the bug the edit had removed,
|
||||
with a delay, and with no error to connect the two events.
|
||||
|
||||
There is a way to ask whether a given file is managed. That question has to be asked, because
|
||||
the answer is not visible from the file.
|
||||
|
||||
## What is managed
|
||||
|
||||
Generated environment files for each module, service definitions in each module's runtime
|
||||
directory, managed configuration files a module declares, and node-level settings. The list is
|
||||
not a category — it is whatever a synchroniser claims, which is why the question is asked of
|
||||
the tooling rather than answered from a rule.
|
||||
|
||||
## How a value is decided
|
||||
|
||||
Values resolve by precedence, highest first:
|
||||
|
||||
1. **A database override** — set deliberately, or written by a provisioner.
|
||||
2. **The value already in the generated file** — preserved for anything without an override.
|
||||
3. **A generated value** — a random secret, a template composed from other variables, or a
|
||||
value pulled from the node's own record.
|
||||
4. **The manifest default.**
|
||||
|
||||
Two consequences follow, and both are subtle enough to have caused confusion.
|
||||
|
||||
The second rule is what keeps a generated password **stable** across regenerations. It is not
|
||||
an oversight; without it every regeneration would issue a new secret and break whatever holds
|
||||
the old one.
|
||||
|
||||
The same rule means that **changing a manifest's default does not change anything already
|
||||
using it**. The existing file's value wins. The new default reaches only installations that
|
||||
never had one.
|
||||
|
||||
Removing a declaration is worse than changing it: the old override row and the file it produced
|
||||
are both left behind. Configuration is additive in practice, whatever the manifest says.
|
||||
|
||||
## Secrets
|
||||
|
||||
Generated secrets are produced by the mesh, never authored. Provisioned credentials arrive as
|
||||
database overrides written by the provisioner and are marked as such, so they can be
|
||||
distinguished from a deliberate override and cleaned up when the grant is removed
|
||||
([ADR 0005](../../02-DECISIONS/0005-capabilities-are-provisioned-on-declaration.md)).
|
||||
|
||||
Nothing in the repository contains a credential. The repository has no per-node content at all,
|
||||
which is what makes that guarantee structural rather than a matter of care.
|
||||
|
||||
Two known weaknesses, both recorded rather than resolved:
|
||||
|
||||
**Generated environment files were world-readable.** The mode passed at write time only applies
|
||||
when the file is created, so regeneration left the previous mode in place. The class of bug is
|
||||
worth remembering beyond the instance: a permission set at creation is not a permission
|
||||
maintained.
|
||||
|
||||
**Rotation is not a mesh operation.** Secrets can be generated and granted; there is no
|
||||
mechanism that rotates one and informs everything holding it. Where a rotation has been done,
|
||||
it has been done by hand, and doing it wrong has taken services down.
|
||||
|
||||
## Node-level and mesh-level values
|
||||
|
||||
A node-level value applies to everything on one node. A mesh-level value applies everywhere and
|
||||
is read by every node — the broker's location is the canonical example, and a wrong one is how
|
||||
a mesh fails to form.
|
||||
|
||||
Neither is a file that anyone edits. Both are database records that produce files.
|
||||
Reference in New Issue
Block a user