Skip to content

Architecture invariants

Numbered properties the system must always hold — and the fitness tests that turn a paragraph of prose into a pass/fail CI check.

ARCHITECTURE_INVARIANTS.md (in the standards folder) lists the things that must always be true, each with a stable identifier from INV-001 to INV-027. They are Tier 0 — the highest authority short of a direct operator instruction. Four of them sit directly behind hard rules: INV-024 (secrets only on prontera), INV-025 (one brain, channels are thin), INV-026 (no AI attribution), and the newest — INV-027 (discovery precedes design; reuse before build) behind HARD RULE 16. Not every invariant carries a fitness test, though: INV-027 is a process rule with no mechanical backstop (see the coverage map).

Each invariant can carry a ### enforcement section containing a small block of structured rules. The fitness-test harness turns those into running checks. The pipeline has four stages:

ARCHITECTURE_INVARIANTS.md
│ 1. loader — find every "## INV-NNN: Title" heading,
│ then the first "### enforcement" block under it,
│ then the first ```yaml fence inside that.
list of rules (each rule is a dict with a "kind" field)
│ 2. runner — one pytest case per rule (parametrized),
│ so each failure is isolated and named INV-NNN/kind.
4 scanners 3. dispatch on "kind":
│ • forbidden_pattern — regex must not match file contents
│ • forbidden_dir — directory must not exist
│ • forbidden_compose_service— no compose service name matches
│ • forbidden_env_var — no compose env var matches a value
findings ──▶ 4. any finding ⇒ pytest.fail ⇒ red build

The loader parses the markdown the same way a person reads it: every ## INV-NNN: Title heading starts a new invariant; an optional ### enforcement sub-heading holds the machine part; the first fenced yaml block under it is the list of rules. Invariants with no enforcement block are kept as prose-only — they simply aren’t mechanically checked yet. The YAML must be a list of dicts and each dict must have a kind, or the loader raises rather than silently skipping.

Every rule becomes its own pytest case, parametrized so a failure points at exactly one invariant and one rule (the test id is INV-NNN/kind). Two guardrail tests sit alongside: one asserts the markdown parses and every rule’s kind is known, and one asserts at least one invariant still has an enforcement block — so if someone deletes the enforcement from the file, the build notices the absence rather than going quietly green.

Each rule’s kind selects one of four scanners. They are deliberately simple — stdlib plus a YAML parser, no heavy framework:

  • forbidden_pattern — a regex that must not appear in the contents of files matching a glob (with an optional list of exception files).
  • forbidden_dir — a directory that must not exist on disk (optionally only on named hosts).
  • forbidden_compose_service — no service whose name matches a pattern may appear in the compose files. This is what fails the build on a new channel-worker service (HARD RULE 12 / INV-025).
  • forbidden_env_var — a named environment variable in a compose file must not have a value matching a pattern.

A scanner returns a list of findings; an empty list is a pass. Any finding calls pytest.fail with the invariant id, the offending file and line, and the invariant’s stated reason. The build goes red.

INV-024 (“secrets live only on prontera”, the rule behind HARD RULE 10) is the most-developed invariant, with all four scanner kinds. The neatest is its forbidden_env_var rule, which uses a negative lookahead so that a broker URL is allowed only if it points at prontera, and forbidden otherwise:

value_pattern: "^(?!.*prontera\.sole-augmented\.ts\.net).*$"

In words: “match any value that does not contain the prontera host.” If a compose file ever sets the secret-broker URL to anything else, that regex matches, the scanner returns a finding, and the build fails — turning HARD RULE 10 from a paragraph into a wall.

Where invariants sit among the checkpoints

Section titled “Where invariants sit among the checkpoints”

The fitness tests are the CI-time enforcement of the invariants. They run on the diff before it can merge, in the same family as the CODEOWNERS gate. They complement the write-time enforcement done by the gate and the kernel wall of Landlock: the gate stops a bad write as it happens; the fitness test stops a bad property from ever reaching the main branch. Same policy, different checkpoints.