The Three Planes
Blueprint separates a regulated system into three planes, stacked by when things become known. Every concept in the system lives on exactly one plane, and the value of the whole architecture comes from keeping the boundaries sharp.
Three planes, one grammar.
Declaration names the system, configuration binds it to a scope, and execution records what happened. Requests move across the planes without inventing a private runtime for each domain.
The Planes
1. Declaration
The blueprint itself: modules, entities, facets, fields, relationships, lifecycles, actions, rules, evidence requirements, audit postures, task templates, projections, and policy schemas with defaults and locks.
This plane is finite, versioned, and human-reviewable. It is the artifact a QA head or auditor can read and sign off on. Its value comes from staying small — reviewability, diffability, provenance. A blueprint that tried to enumerate runtime behavior would be a program, and programs cannot be audited by reading.
Fields and field types are the atomic vocabulary of this plane. Domain meaning is then composed with relationships, facets, actions, and especially predicates: predicates are where the blueprint says what must hold, what can happen, and what evidence a runtime must evaluate. The execution plane should not grow a special runtime for each entity or domain; it interprets the same declared atoms and predicate algebra everywhere.
2. Configuration
Scoped values bound to declared schemas: tenant and site policy values, assignment overrides, escalation timings, schedules. Governed by the policy scope ladder (global → tenant → site → module → entity → facet → action → instance), constrained by locks, and carrying provenance back to SOPs and regulations.
Larger than declaration, but still enumerable and still governed. This is where "Site B's rework tasks go to the night shift with a 24-hour expiry" lives — a policy edit, never a code change.
3. Execution
Requests, resolutions, and records: action requests, effective policies, effective assignments, action records, task rows, evidence rows, traces. Unbounded and growing forever.
The Closure Property
The execution plane is larger than the declaration plane in cardinality, not in vocabulary or domain-specific logic. The set of chess games is astronomically larger than the rules of chess, but no legal game contains a move the rules cannot name.
That property — closure — is what Blueprint actually sells: every fact the execution plane produces is an instance of a type the declaration plane defined, so "why did this happen?" always terminates, mechanically, in a versioned, declared artifact:
record → rule → condition → policy contribution → declared scopeThe EntityOriginGraph, effective-policy contribution trace, predicate evaluation traces, and ActionRecord lineage form this chain end to end. For regulated industries, the provenance chain is the product.
The Four-Role Grammar
Movement between the planes follows one grammar. Every surface is built from up to four grammatical roles:
| Role | Question | Lifetime | Naming |
|---|---|---|---|
| Declaration | What can happen? | Design-time, versioned with the blueprint | bare noun |
| Request | What does someone want to happen? | Transient intent, carries RequestContext | *Request |
| Resolution | What applies here and now? | Computed per scope/actor/moment | Effective* |
| Record | What did happen? | Durable, append-only, audit-bearing | *Record |
Rules:
- Not every surface needs all four roles. Queries have no resolution step; resolving a policy is not an event so it produces no record. The grammar is a menu, not a mandate.
- Every
Effective*type MUST carry a trace that can answer "why".EffectivePolicycarries contribution traces,EffectiveAccesscarries evaluation traces, the capability manifest carries denials with reasons, andEffectiveAssignmentcarries per-actor inclusion/exclusion reasons. In an audit, explainability of the resolution is worth as much as the record of the outcome. - When a new runtime concept appears, the question is never "should the blueprint grow?" — it is "which of the four roles does this play?" A concept that will not sort into any role is the signal that a vocabulary block is missing.
Worked example — the task grammar:
| Role | Task |
|---|---|
| Declaration | TaskTemplate, AssignmentSpec, selectors, strategies, escalation, separation-of-duties |
| Request | none new — claim/delegate/complete arrive as ordinary ActionRequests against the workflow module |
| Resolution | EffectiveAssignment (traced) |
| Record | none new — the task is an entity instance; every state change is an ActionRecord |
Only two genuinely new runtime concepts were needed; everything else reused existing machinery. That reuse ratio is the health metric for the grammar.
Litmus Tests
Does X belong in the vocabulary? Not "is X known at design time" — policy values are not known at design time either, yet PolicyParameter exists. The test is: does some tool other than the runtime need to reason about X? Compilers, validators, editors, and UI generators all consume vocabulary; if any of them needs X, X needs a declared shape.
Where do instances of X live? Declaration owns the schema and the defaults. Configuration owns scoped values within locks. Execution owns the resolved and recorded facts. Assignment is the canonical example: the shape of an assignment expression is vocabulary; the blueprint declares defaults; site policy supplies values; the resolver produces actors — and nothing concrete is ever baked into the blueprint.
Is the machine deterministic? Transition tables must remain functions of (from, trigger) — enforced by the validator. When one trigger seems to need two outcomes, the choice belongs to the caller (two actions), never to the machine.
What Declaration Can Say About Runtime-Varying Things
For any dimension that varies at runtime — who performs work, when it must happen — the declaration plane never states the concrete answer, but it is not limited to stating that the question exists. It owns four layers:
- Schema — what an answer even looks like (assignee selectors and claim modes; expiry and escalation shapes and what the clock anchors to).
- Defaults — a proposed answer, explicitly overridable (
role: operatoras a claim pool; a 48-hour window). - Invariants and bounds — constraints that survive configuration: locked separation-of-duties ("the completer is never the rejecter"), qualification conditions ("must hold GMP cleaning L2"), and lock-bounded ceilings ("no site may extend beyond 72 hours"). These are the most compliance-critical statements in the system, and they live in declaration precisely because they must not be configurable away.
- Consequences — the breach topology: escalate, then expire, then spawn a follow-up, then notify — with the missed deadline itself recorded as a queryable fact.
The principle: numbers and names are configuration; structure, bounds, and consequences are declaration. Locks are the mechanism that lets declaration bound the configuration space without collapsing it to a point.
A related precision about enforcement: preflight evaluates the full rule surface without committing — it powers UI affordances and "why can't I?" explanations. The enforcement moment is execute, where the same rules run again inside the server transaction. Preflight is a courtesy; execute is the gate. The UI is never the enforcement boundary.
Verification Moments
Declaration states predicates; configuration supplies witnesses. That split implies four distinct verification moments, each answering a different question:
- Declaration-time —
BlueprintValidator.validate: is the graph closed? Every ref resolves, every enum is typed and collision-free, every lifecycle is deterministic. Runs in CI; a regulator can read the input. - System readiness (configuration/state-time) —
SystemReadinessReport.evaluatevalidates the blueprint, compiles its database artifacts, compares declared and installed subscriptions, probes generated tables when a database adapter is supplied, and verifies whether the delivery worker is attached. It returnsready,degraded, orblockedwith typed findings and remedies. It is a commissioning and drift report, not an action gate inside the transaction. - Request-time preflight — this actor, this payload, this moment: advisory verdict with reasons.
- Execute — the same rules inside the transaction: the gate.
Events and Replay
Events are not a second source of truth. The append-only ActionRecord stream is the event log: every mutation flows through an ActionRequest into a record carrying its rule evaluations, failures, results, and effects — and queries produce QueryRecords too, so even reads sit on the same timeline. Events exist as projections and transports of record-facts, in three tiers:
- Declared domain events —
ActionDefinition.emitsnames what an action can produce; the event shape carries entity, facet, kind, and field-levelpreviousValue/nextValuedeltas. - Protocol events — every operation streams sequenced events (accepted, planned, executed, record produced, failure recorded, effect emitted), persisted by the executor.
- Effects through the outbox — durable, retried, causally linked (
rootRequestId,parentRequestId,commandPath). Database writes, audit writes, action/query record writes, outbox enqueueing, realtime signals, dry-run records, and custom integrations are all runtime effect kinds. Realtime is therefore a delivery/projection effect over committed record/outbox facts, not a second business runtime.
The supported replay surface is the durable record graph: action and query records, scope-local and global sequences, entity stream sequences, request lineage, snapshots, declared event rows, evidence manifests, effect state, and idempotency keys. The Execution Replay Contract defines how those persisted facts are correlated and verified.