The closed schema, parsed live
The ontology is frozen: exactly these classes and relations exist, versioned, changed only as a new logged version. This diagram is not a picture of the schema, it is the schema: fetched at page load from the same ontology.schema.ttl file every engine and every refusal reads. Anything not declared here cannot be silently invented anywhere in the system.
The live instance graph
The twin is one append-only table of events. Interpreted through the vocabulary above, those rows form this graph, reassembled by a live query on every render. Click any node to open its raw event rows. Click any edge to see the single database row that asserted it.
Deriving the graph live from the events table…
Two tables. That is the whole schema.
This is not a simplified view of a bigger system. The entire database behind everything on this site is two tables: events, the twin itself, append-only, one fact per row, and prov_log, the audit ledger, one row per question ever asked. Both shown below live, newest first. Click any events row to open that entity's full history.
| event_id | entity_id | field | value | valid_time | tx_time |
|---|---|---|---|---|---|
| Fetching the newest rows live… | |||||
| prov_id | actor | verb | question | asked |
|---|---|---|---|---|
| Fetching the newest rows live… | ||||
Top track: when a fact became true in the world (valid_time). Bottom track: when the twin learned it (tx_time). The risk was real for ten days before the system knew. The due date was corrected without touching history: a second row, a later tx_time, the same valid_time. "What did we know on date X" filters on the bottom track only, which is why history can be reconstructed but never silently rewritten. Click any point for its raw row.
Ingested feeds
The twin ingests these source systems as feeds, declared as named individuals in the ontology itself, so the claim of what the system has and has not seen is checkable in the same governed file as everything else. Any system of record maps into the twin the same way: a feed writing append-only events in the closed vocabulary. The vocabulary does not change when the source does.
For the IT team
The anatomy of one event row, fetched live
The entire twin is one table. Every fact, every edge of the graph above, is one row shaped like this, a real row fetched from the database as you opened this section:
Two clocks on every row is what makes time travel provable: valid_time is when a fact became true in the world, tx_time is when the system learned it. "What did we know on date X" filters on tx_time only, so history can be reconstructed but never silently rewritten. A correction is a second row, never an edit.
Why the graph cannot drift from the truth
There is no stored graph to go stale. Every render of this page re-derives nodes and edges from the events table at query time, the same discipline every answer engine follows: derived fields like an approval's idle days are computed from raw status events on demand and are forbidden from existing as stored state. The runtime database role holds SELECT on the events table and nothing else: no INSERT, no UPDATE, no DELETE. Append-only is a database grant, not a code review policy.
The closed vocabulary, enforced, not promised
Questions route against a fixed set of verbs by deterministic rules, no embeddings, so "no match" is a checkable statement. Status vocabularies are closed by SHACL shapes declared in the same ontology file, validated live by pyshacl on demand (the Prove SHACL button below runs it right now). When a question needs a class the ontology does not declare, the system names the missing class and the exact feeds it checked, and refuses. The refusal is parsed from the same file this page renders.
