Modular Architecture Proposal — 5 Layers, Contracts, Federated Registry, Promotion by Blast Radius (DRAFT)
Modular Architecture Proposal
Status: DRAFT — not enacted. Authorizes nothing. Companion to architecture-survey.md; constitutional hooks in constitution.md (HP v4.7 DRAFT); operational standard in module-contract-standard.md; transition in migration-map.md.
Date: 2026-06-12.
Design rule used throughout: prefer the design that reduces full-system review, isolates module failure, makes rollback local, keeps contracts mechanically checkable, makes production-affecting changes explicit, and ships features at normal IT speed. Where a mechanism already exists in the enacted corpus, this proposal reuses it and says so; new machinery is introduced only where no primitive exists.
1. The five layers
┌────────────────────────────────────────────────────────────┐
│ L5 PROMOTION PIPELINE Level 0..4, lane chosen by class │
├────────────────────────────────────────────────────────────┤
│ L4 INTEGRATION BUS adapters, schema val, events │
├────────────────────────────────────────────────────────────┤
│ L3 MODULE SANDBOX own folder/tests/fixtures/rollback│
├────────────────────────────────────────────────────────────┤
│ L2 CONTRACT LAYER MODULE_CONTRACT/MANIFEST/...v1 │
├────────────────────────────────────────────────────────────┤
│ L1 CORE KERNEL identity·birth·registry·gates· │
│ rollback law·object model·audit │
└────────────────────────────────────────────────────────────┘
L1 — Core Kernel (frozen, scope-routed, never weakened)
The kernel is the part of today's system that must survive the rewrite unchanged in strength:
| Kernel element | Current implementation (kept) |
|---|---|
| Identity / birth authority | Đ0-G + QT-001/QT-002 (+ envelope birth, §7), fn_birth_register single register path, birth_registry, species (Đ29) for governed entities |
| Canonical/global registry | Family Registry + SCMR + Profile Registry (Đ44 stack, promoted from design) over today's collection_registry/dot_tools/normative_registry |
| Permission model | Đ32 APR quorum (high = president + 2 AI-council + 0 reject; no self-approve; reject not overridable) — extended with a scope column, never relaxed |
| Production gates | Đ20 Tier 3 explicit User approval; Tier-0 prod SQL guard (db=directus AND os_proposal_approvals>=1); Đ41 deploy corridor; per-action grants (REAL_RUN, permit, cutover each separately authorized) |
| Rollback law | Đ41 NT-VPS-8 (known-good only), FIX7 rule: rollback PROVEN_IN_STAGING before any apply; hardened validator gates (ROLLBACK_APPLY_DID_NOT_MUTATE, ROLLBACK_NOT_RESTORED_TO_PIN) |
| Global object model | UMC (P38-XC): 10 invariant elements; G1–G12 logical groups (Đ44) |
| Event/audit log | governance_audit_log, system_issues + fn_log_issue, Đ31 watchdog (always_fail liveness, independent alert channel), FK-RESTRICT audit preservation |
Kernel rule: a change to any row above is Class E by definition and takes the full current macro lane (authority → planning → dry-run → review → execution → review), unchanged.
L2 — Contract Layer
Every module publishes a small set of versioned, machine-checkable artifacts (full field definitions in module-contract-standard.md):
- MODULE_CONTRACT.v1 — what the module promises: exposed operations, input/output schemas, invariants, compatibility declaration, authority contract (what it may never do), mutation contract (what it writes, where), rollback contract, evidence contract.
- MODULE_MANIFEST.v1 — what the module is: module_id, version, owner, contract pointer + hash, module-registry pointer + hash, declared surfaces (tables, DOTs, routes, KB paths), declared dependencies (other modules' contracts only), promotion state, compatibility state.
- Promotion policy — which blast-radius classes the module's surfaces can generate and which pipeline levels each requires.
Lineage: the contract layer is the FIX7 manifest.json (authority string, denial flags, hash pins, mutation ledger) + O11 patch.meta.yaml (trust ladder) + Đ30/Đ31 contract files (owner/tier/enabled) generalized from per-packet/per-route to per-module. Contracts are data, validated by a fail-closed checker, never prose-only (NT14 applies: 6 questions answerable or the contract is not valid).
L3 — Module Sandbox
Each module gets an isolated development zone, modeled on Đ41 §2A + O11, with these invariants:
- Own folder (
modules/<module_id>/in the repo;agent_sandbox/tasks/<patch_id>/ledgers for agent work). - Own tests + fixtures + fake bad inputs. Bad-input probes are mandatory (TKT rule: enumerate defect classes, 100% fail-closed,
any_fail_open=false, detector-correctness, no PASS-token leakage). - Own rollback proof. Every change that mutates state ships a reverse path proven in staging (mktemp/sandbox-DB exercise) before promotion — FIX7
PROVEN_IN_STAGINGsemantics, locally. - Own local registry slice (§7): module-internal objects live in the module registry; only envelopes go global.
- No production access. Sandbox DB access follows Đ41 S-classes: S0/S1 freely; S2 (real-PG sandbox: separate DB/schema or
sandbox_run_id-tagged rows, sanitized snapshot, no prod secrets/roles, verified one-command cleanup) is the ceiling for module work; S3+ is trusted-agent/owner territory outside the sandbox. - DENY-list charter, fail-closed (O11 pattern): prod DB any-role, active deployed trees, runtime state, secrets/env, deploy/restart, KB/Directus write outside the module's declared paths, approval authoring, execution-flag flips.
L4 — Integration Bus
Modules never touch each other's internals. All cross-module interaction goes through declared seams:
- No direct hidden coupling. Depending on another module's internal files/tables/functions is a forbidden pattern (standard §forbidden). Dependencies are on contracts, by version.
- Adapters. Each module exposes input/output adapters that validate against the contract's published schemas. Lineage: Đ33's gateway-per-DB (E4) — one declared gateway per store; Đ43's metadata dispatcher — global surfaces assembled from per-module rows.
- Schema validation at the boundary. Every bus message/call validates against the consumer-declared schema version; unvalidated payloads are rejected (fail-closed), logged to the event log.
- Version negotiation. Contracts carry semver-like compatibility declarations; a consumer pins
contract@major.minor; the bus refuses pairs whose compatibility state isincompatible(computed from declarations, recorded in the global envelope). - Auth boundary. Bus calls carry the calling module's identity; the callee's authority contract decides; cross-module writes require the callee's mutation contract to allow them (never the caller's).
- Timeout/failure handling + fallback. Every bus dependency declares timeout, retry policy, and fallback behavior (degrade, queue, or fail) in the contract — Đ31
grace_seconds/2-pass-verify generalized. - Event log. Every cross-module call/event is logged with provenance (Đ39 edge-provenance discipline applied to runtime traffic); cross-module relationships are global edges in
universal_edges; module-internal edges stay local (requires enacting the P44-2-δ resolution — prerequisite, see migration map).
Physically, the bus starts as conventions over existing channels (PG functions fn_* as gateways, Directus REST, Agent-Data API, universal_edges) — not a new message broker. A broker is a later, separate decision; the law governs the seam, not the transport.
L5 — Promotion Pipeline
Five levels; a change stops at the level its blast-radius class requires:
| Level | Name | Gate | Reuses |
|---|---|---|---|
| 0 | Local module test | Module's own tests + bad-input probes green in sandbox; rollback path exists | Đ41 §2A test-for-real rule; TKT probe policy |
| 1 | Contract test | Mechanical contract conformance: schemas validate, declared surfaces match diff, manifest hashes recomputed, compatibility declaration checked against consumers | New checker (small), FIX7 commands.sh/RERUN pattern |
| 2 | Integration sandbox | Module runs against real contracts of its dependencies in a shared integration sandbox (S2-class PG, seeded envelopes); cross-module smoke + regression contracts for touched routes | P7B sandbox_tac precedent; Đ30 contracts scoped to module routes |
| 3 | Production readiness | Promotion packet assembled (manifest, evidence, rollback proof, bad-input results, compatibility report); reviewed per class lane; envelope update staged | FIX7 packet skeleton; TKT L0–L3 evidence ceiling |
| 4 | Production activation | Kernel gates: Đ32 APR per class routing; Đ41 deploy corridor (FAST/FULL computed, atomic swap, known-good rollback); per-action grants for prod-touching surfaces | Entire current kernel lane, unchanged |
A change of Class A legally terminates at Level 0+1. Class B terminates at Level 2. Class C at Level 3 (+ consumer sign-offs). Class D/E always reach Level 3–4 via the full current lane.
2. Module boundary rules
- A module ≈ one Đ44 family (or a declared small set of families) + its surfaces. The Family Registry entry IS the module's global identity;
family_code=module_idwhere possible. - A module owns: its tables (registered as envelope rows, §7), its DOT pairs, its routes/pages, its KB subtree, its tests/contracts, its module registry slice.
- Exactly one owner (person/agency seat) per module — Đ37 agency model; OP-B (owner agency vacancy) must be resolved per module at registration; 0..1 tolerated only at maturity M0–M1.
- One domain concern per module; if two modules need the same specialty content, Đ37 §4.12 SSOT-transfer decides the single owner — federation does not create content forks.
- Module boundaries are declared in the manifest and mechanically diffable: a change whose diff exits the declared surfaces is automatically reclassified (≥ Class C) by the classifier — never silently accepted.
- Shared mutable state between modules is forbidden unless declared as a bus contract (the declared exception: kernel registries and
universal_edges).
3. Blast-radius classes and lanes
Class is computed, not self-declared (Đ41 FAST/FULL lesson: the script decides from the diff, never the agent). The classifier maps the change's diff + declared surfaces + contract delta to a class; uncertainty fails closed to the higher class. Misdeclaration discovered later = incident + automatic lane upgrade for the module (probation).
| Class | Definition (mechanical test) | Lane | Approval |
|---|---|---|---|
| A — internal-only | Diff entirely inside module folder/registry slice; contract byte-identical; no kernel surface; no schema visible outside module | Level 0→1; merge on green | Module owner. No president, no council, no whole-system review |
| B — contract-compatible | Contract changes but compatibility declaration proves backward-compat (additive fields, new optional ops); consumers' pinned versions still satisfied | Level 0→2 | Module owner + automated consumer-contract re-test; notify consumers |
| C — contract-breaking | Contract delta breaks a consumer pin (removed/renamed op, schema tightening, semantics change) | Level 0→3; migration note + deprecation window mandatory | Module owner + each affected consumer owner sign-off; Đ32 APR low/medium per risk |
| D — governance-affecting | Touches laws, registries' schemas, classifier/lane definitions, quorum routing, evidence/promotion policy, or any module's authority contract | Full current macro lane (design → council review → APR medium/high) | Đ32 quorum (president), Council review per Đ37 |
| E — production/kernel-affecting | Touches kernel rows (§1 L1 table), production data/DDL/deploy/DOT-canonical surfaces, secrets, birth/approval machinery | Full current macro lane, unchanged, including per-action owner grants, dry-run, independent review, rollback proof, sealed packets | Đ32 high quorum + explicit Owner grant per action — exactly today's regime |
Anti-ceremony guard: Class A and B lanes have a fixed maximum required-artifact count (manifest + test result + rollback note; nothing else may be demanded). Adding any required artifact to lane A/B is itself a Class D change.
4. Federated registry model
Global registry stores only the module envelope. Envelope row (extends P44-1 Family Registry; one row per module):
module_id -- = family_code; immutable; namespace prefix for all module-local IDs
version -- module version (semver-like)
status -- proposed | active | deprecated | retired
owner -- owner seat (person/agency)
contract_pointer -- KB/PG ref to MODULE_CONTRACT.v1
contract_hash -- sha256 pin of the contract
module_registry_ptr -- where the module's own registry slice lives (pg.schema, kb path…)
module_registry_hash -- content/tree hash of the slice (drift detection)
hash -- envelope tree hash (FIX7 packet_tree convention)
promotion_state -- last pipeline level passed (L0..L4)
compatibility_state -- computed vs consumers: compatible | degraded | incompatible
aggregates -- published rollups for global pivots (counts per kind/status — Đ43 manifest pattern)
Module registry stores internal objects (module's tables, units, configs, internal edges, internal DOT runs) under the module's namespace prefix. SCMR entries cover the module's physical targets; conformance is judged at family aggregate (P44-2 rule), so internals can be N/A-mapped where legal.
Promotion test for globalization — an object leaves the module registry for the global registry only if it is at least one of: cross-module (another module references it), authority-bearing (grants/permits/approvals), production-bearing (touches prod surfaces), or kernel-bearing (kernel element). Everything else stays local. This is the inverse of today's default and the single biggest ceremony reduction.
Drift control (R4): a paired drift-checker DOT per module recomputes module_registry_hash and contract hash on schedule; mismatch ⇒ compatibility_state=degraded + system_issues row (jurisdiction = module_id). Envelope says X / slice says Y is detected mechanically, never by review.
Global scanners (orphan, phantom, Đ43 projection, pivots) read envelopes + published aggregates; a module-local scanner satisfies the global obligation if its liveness is watchdogged (Đ31 always_fail pattern): a module whose local scanner goes silent >SLA gets its envelope flagged, fail-closed.
5. Sandbox rules (normative summary)
- Module sandbox = own folder + ledger; created/wiped freely; never a SSOT.
- DB ceiling S2 (real-PG sandbox) with verified one-command cleanup; production access classes S3–S5 are outside module lanes entirely.
- DENY charter fail-closed (O11 list as template); isolation runner (low-priv user, fs pinning, no prod network, scrubbed env) must be provisioned before untrusted agents attach.
- Sandbox output is information (patch + meta + evidence), never an applied change; promotion is always an explicit gate action.
- Every sandbox ships fixtures + fake bad inputs from day one; a module without bad-input probes cannot pass Level 1.
6. Integration bus rules (normative summary)
- No hidden module-to-module coupling; contract-pinned dependencies only.
- Boundary validation fail-closed; version negotiation from compatibility declarations; incompatible pairs refused.
- Auth at the boundary by module identity; callee's contracts decide.
- Declared timeout/retry/fallback per dependency; failures logged with provenance.
- Cross-module edges →
universal_edges; module-internal edges → local (prerequisite: enact P44-2-δ resolution). - Bus seams first, transport later: no new broker is introduced by this proposal.
7. Migration strategy (old → new)
Strangler pattern; the old lane keeps working at every step; each phase has its own rollback (stop using the new lane). Detailed file mapping in migration-map.md.
- Phase 0 — prerequisites (decisions, no build): resolve P44-2-δ (internal vs global edges), OP-B (module owner seats), adopt blast-radius classes as vocabulary. Owner decisions; Class D.
- Phase 1 — contract standard + classifier (build, no lane change): enact
module-contract-standard.md(v1 schemas); build the fail-closed classifier + contract checker (these are the lane's enforcement; per R9 no lane opens before its checker exists, mode=block from birth — not warning). - Phase 2 — pilot module: wrap one well-bounded existing area (candidate: iu-cutter/O11 family, or the Đ43 context-pack builder — both already have charters and paired DOTs) in MODULE_CONTRACT/MANIFEST; register envelope; run Class A/B lanes in parallel with old process for 2–4 weeks; compare cost + incident rate (Đ38 R9 parallel-run precedent).
- Phase 3 — Đ32 scope amendment: add scope/jurisdiction routing to APR (the one kernel-adjacent change; Class E lane, Council + president). Until enacted, Class A/B lanes operate under the existing low-risk auto-approve rule (legal today) with president-visible audit trail.
- Phase 4 — federate registries: envelope columns onto Family Registry; module registry slices; drift-checker DOTs; global scanners read envelopes; HC-REG gains the envelope tier.
- Phase 5 — onboard modules by value: each onboarding is itself Class C-shaped (declared surfaces, consumer sign-offs). The full macro lane remains for Class D/E forever — it is not deprecated; it is reserved for what it was built for.
Exit criteria per phase, owners, and the enactment order of documents are in migration-map.md.