MetamodelAutoConfiguration

Wires the schema-governance loop: version stamps, a drift log, a snapshot of what the live graph holds, the comparisons between them, the runner that sequences a check, and the sweep a host calls when it decides to act on one.

The opt-in is a declared schema

Governance activates when the application supplies a DeclaredSchemaSource bean, and only then. With no declared schema there are no metamodel beans at all: no stores, no differ, no runner, no sweep. It is the same arrangement Spring Boot has with JPA and a DataSource.

There is no sensible default declared schema. A schema states what an application governs, and guessing one would either govern everything, turning every exploratory type an LLM extracted into reported drift, or govern nothing, leaving the loop a no-op that still logs as if it were working. Requiring the bean puts the opt-in in the consumer's own code, where a reader can see it.

embabel.dice.metamodel.enabled=false is a kill switch on top of that, for switching governance off in one environment while the bean stays in place. It is consulted only once the bean exists, so it changes nothing for an application that never declared a schema.

Nothing here runs, and nothing here quarantines

Every bean below is a capability sitting still. There is no scheduler and no startup hook: a check happens when the application calls DriftCheckRunner.run, from a cron, an admin endpoint or a migration script. A check reads, compares and writes a report, and no path through it moves a proposition.

Quarantine is a second, deliberate step. The DriftSweepCapable bean below is what performs it, and it performs it when a host calls DriftSweepCapable.sweep with a diff it decided to act on. Nothing in this class calls that method.

embabel.dice.metamodel.drift.mode picks whether the runner bean is registered at all: off for stamps and history alone, observe (the default) for the check as well. See DriftMode.

Status transitions reach the application's listeners

A sweep moves a proposition to QUARANTINED, and things downstream need to hear about it — ProjectionLineageStaleCascade marks the projection records derived from that proposition stale, and it can only do so if the transition is announced. So the sweep is built with every DiceEventListener bean the application registered, fanned out through a CompositeDiceEventListener, which makes each delivery exception-safe. An application with no listener bean gets DiceEventListener.DEV_NULL and the same behaviour otherwise.

Backend selection follows the store

The Drivine/Neo4j governance beans register under embabel.dice.store.type=graph, the same switch DiceStorageAutoConfiguration uses for the proposition store, and they are declared before their in-memory counterparts so the fallback resolves by registration order.

Under the default in-memory backend a host that declares a schema still starts. It gets the in-memory version store, the differ and the quarantine policy, and it gets the sweep when a PropositionStore is on the context. It gets no drift log and no observed-schema source, because both of those read a graph and there is no graph here, and therefore no drift-check runner: with nothing to observe, a check has no question to ask. Such a host can stamp schemas, compare declarations and sweep on a diff it built itself.

Defaults, and replacing them

Every default is @ConditionalOnMissingBean, and this is a real @AutoConfiguration registered through META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. That pairing is what makes "your bean wins" a guarantee: Spring Boot registers every application bean definition before it processes a single auto-configuration, so a consumer's bean is already there when these conditions are evaluated, whichever order the two were declared in.

The metamodel constraints ride along as a SchemaCatalog bean, the same way the proposition and lineage constraints do; Drivine's SchemaManager applies them idempotently on startup. The stores' MERGEs are only race-free under them, so they are required wherever the graph stores are.

Constructors

Link copied to clipboard
constructor()

Functions

Link copied to clipboard

What dice owns in this application, derived from the registered storage schemas.

Link copied to clipboard
fun driftCheckRunner(declaredSchemaSource: <Error class: unknown class>, versionStore: <Error class: unknown class>, observedSchemaSource: <Error class: unknown class>, driftReportStore: <Error class: unknown class>, declaredObservedDiffers: <Error class: unknown class><<Error class: unknown class>>, metamodelDiffers: <Error class: unknown class><<Error class: unknown class>>): <Error class: unknown class>

The shipped runner. It stamps the declaration, snapshots the graph, runs both comparisons and writes a report, and it touches no proposition on any path.

Link copied to clipboard
fun drivineDriftReportStore(persistenceManager: <Error class: unknown class>): <Error class: unknown class>
Link copied to clipboard
fun drivineMetamodelVersionStore(persistenceManager: <Error class: unknown class>): <Error class: unknown class>

The version store, returned as a SweptBaselineStore on purpose.

Link copied to clipboard
fun drivineObservedSchemaSource(persistenceManager: <Error class: unknown class>, ownedSchema: DiceOwnedSchema): <Error class: unknown class>
Link copied to clipboard
fun governanceOperationsService(declaredSchemaSource: <Error class: unknown class>, versionStore: <Error class: unknown class>, driftReportStore: <Error class: unknown class>, driftCheckRunner: <Error class: unknown class>, driftSweep: DriftSweepCapable, propositionStore: PropositionStore): GovernanceOperationsService

The one object a person or an agent reaches the loop through: read the drift log and the current declaration, run a check, release a quarantined proposition.

Link copied to clipboard
fun inMemoryMetamodelVersionStore(): <Error class: unknown class>

Schema history for a host with no graph. It keeps stamps and the swept baseline in the JVM, so a declaration can be stamped and compared against its predecessor before there is a database.

Link copied to clipboard
fun metamodelSchema(): <Error class: unknown class>

The uniqueness constraints the governance stores need. Declared as data in dice-storage so the constraint list and the label list the observed-schema source excludes stay one edit apart.

Link copied to clipboard

The metamodel store schema, registered so ownership derivation sees it: the drift observation excludes what the registered DiceStorageSchema beans declare, and without this bean governance would observe its own report bookkeeping as drift.

Link copied to clipboard
fun propositionStoreDriftSweep(propositionStore: PropositionStore, listeners: <Error class: unknown class><DiceEventListener>): DriftSweepCapable

The reference sweep over whatever PropositionStore the application has, wired with the application's own event listeners so a quarantine it performs is heard downstream.

Link copied to clipboard
fun structuralMetamodelDiffer(): <Error class: unknown class>

The shipped differ, registered under its concrete type so it resolves as both a MetamodelDiffer (two declarations compared) and a DeclaredObservedDiffer (a declaration compared against a live graph).