Skip to main content

The Metadata Graph

The MetadataGraph is the central object in AUSUS. It is the compiled, immutable description of an application — every entity, action, policy, workflow, and projection, validated and frozen into one value.

Everything downstream — persistence schema, the runtime, the HTTP API, the rendered UI — is derived from this single graph.

What is in the graph

A MetadataGraph (in ausus/kernel) holds:

FieldContents
hasha SHA-256 content hash of the canonical graph
kernelVersionthe kernel contract version the graph was compiled against
entitiesmap of FQN → EntityNode
actionsmap of FQN → ActionNode
policiesmap of FQN → PolicyNode
workflowsmap of FQN → WorkflowNode
projectionsmap of FQN → ProjectionNode

Each node is a final readonly value object. The graph has no methods that mutate it — once compiled, it does not change.

Compilation

The Compiler takes a list of plugins and produces the graph:

use Ausus\Compiler;

$graph = (new Compiler())->compile([new HelloInvoiceDsl()], kernelVersion: '1.0.0');

Compilation does three things:

  1. Collect — each plugin's describe() output contributes entity, action, policy, workflow, and projection nodes.
  2. Validate — see below.
  3. Canonicalize and hash — node maps are key-sorted, serialized to a canonical JSON form, and hashed with SHA-256.

Validation

The compiler rejects an incoherent graph at compile time, not at runtime:

  • DuplicateRegistration — two plugins declare the same action FQN.
  • DanglingReference — an action points at an entity or policy that is not registered; a workflow points at a missing entity; a transition points at a missing action.
  • WorkflowCoherence — a workflow's state field is not on its owner entity, or a transition's source/target is not one of the workflow's declared states.

If validation fails, compile() throws — you cannot build an invalid graph.

Content-addressable hashing

The graph hash is deterministic: the same plugins always compile to the same hash. This is used as an identity and integrity check.

A concrete consequence, verified in the playground: the HelloInvoice domain written with the DSL and the same domain written as hand-built descriptor arrays compile to a byte-identical hash. The DSL is pure sugar over the descriptor form — it adds no semantics.

:::note What the v0.1.0 hash covers The v0.1.0 canonical form hashes the set of node FQNs (entity, action, policy, workflow, projection names) plus the kernel version. It is a strong identity for graph shape. A future revision may extend the canonical form to cover full node contents. :::

Why a graph

Because the application is a single declarative value, the same domain description drives every layer without re-statement:

  • SchemaDeriver reads entities to emit CREATE TABLE statements.
  • The Invoker reads actions, policies, and workflows to execute calls.
  • ProjectionRenderer reads projections to produce ViewSchemas.

No layer re-describes the domain. They all read the same graph.

Current v0.1.0 limitations

  • The graph is compiled in-process at boot. There is no on-disk compiled artifact or graph cache in v0.1.0.
  • The canonical hash covers node FQNs and kernel version (see the note above), not full node bodies.
  • There is no graph diffing or migration tooling.