Meaning, movement and behaviour: the three layers the platform is built in, the standards each stands on, and a measured account of what is built, partly built and absent at this build.
Run a health system for a while and the questions you ask of your software settle into three. What is this thing in front of me, and does it mean the same in the next system along? Where is this person, this referral, this bed, and where are they going? And what will the platform do about it, on its own, without me watching?
Those three questions are the shape of commvita. The first is a question of meaning, and it’s answered by holding every concept once, in published models. The second is a question of movement, and it’s answered by recording what happened, to whom, when, as events that can’t be edited afterwards. The third is a question of behaviour, and it’s answered by rules that live inside the platform and refuse when they should.
Everything below is measured. None of it is recalled from memory. The platform carries an endpoint that reads its own database schema and reports the position of each layer, and a build check that fails if a published figure drifts from the code. The screens are captured from the running system at build B-692, and the numbers are the ones it printed on 20 September 2026.
A concept defined in one place is the difference between a platform and a stack. commvita holds three models and never folds them together: a canonical model it doesn’t own, a semantic model it does, and the physical tables underneath both.
The canonical model is NHS England’s. The NHS Federated Data Platform publishes a canonical data model, and commvita pins a subset of it: sixteen objects, 507 fields, 111 link types. The pin is re-fetched from the publisher and compared field by field, and the last comparison on 18 September found no drift. That is logical conformance with a published specification, and the page says so; it isn’t physical parity with a running national instance, and no such comparison is attempted.
Two things on that screen matter to an operator. An object ringed in coral, Observation, carries no relationship inside the pinned set, and the platform says so instead of drawing one. And four links are declared from both ends of the national model and resolvable from neither, so they are reported as unchecked. The pin never guesses a relationship from a column that looks like a key. Inferring a join from a name is the single thing that turns a data platform into a source of confident wrong answers.
The semantic model is commvita’s own, and it’s a dictionary. It records what each column across the estate means, and whether two meanings are the same. Eleven concepts, 1,141 columns bound, six relationships recorded, and 27 name matches judged false, because a column called patient_name is a label and a column called patient_id on most tables isn’t the register key.
Every definition is local and every binding is a draft until a named person signs it off, and none has been. That is the honest state of the semantic layer: excellent machinery, and content that a deployment fills in and signs. The platform doesn’t sign for you.
The rest of the standards, and their state. FHIR R4 is real where it is claimed and answers from the record. SNOMED CT and dm+d are bound by jurisdiction, with a seeded subset of concepts and the binding mechanism built. OMOP is a working extract path for research, with its data-quality report saying review until a vocabulary is loaded. openEHR is the clinical record shape we’ve committed to and haven’t shipped: the repository is probed instead of assumed, a composition the platform wrote can be read back through the person, and the template repository exists and is empty. There are no archetypes, no query language, and the clinical source of truth is commvita’s own tables. Moving it is a clinical-safety decision that needs a named officer, and it hasn’t been taken.
Canonical pin verified with zero drift. Link types checked or named as unchecked. Semantic registry with not comparable as a first-class answer. FHIR R4 reading the record. OMOP extract with a data-quality report. Terminology bound by jurisdiction.
Bindings cover a fraction of the estate’s columns and none is signed off. Terminology is a seeded subset. openEHR: probe, read path and empty template store built; validation, source-of-truth move and query language not.
No crosswalk yet between the canonical and semantic models, and nothing claims one. No archetypes shipped. No OMOP vocabulary loaded. The behavioural half of a formal ontology, declared action types, isn’t in the national source either, so it can’t be pinned.
Nothing about a country is written into the code. Identifiers, terminology editions, data-protection rules, consent law, statutory reporting, the shape of the health system itself: fourteen domains, each an effective-dated entry with a source, an owner and a review date. Resolution walks up the tree from organisation to sub-jurisdiction to sovereign and takes the nearest value. Where there is no value, the capability that depends on it switches off and says why.
This is the screen a buyer should look at hardest, because it says the platform isn’t ready to run their country yet and tells them exactly why. A jurisdiction is deployable when its five mandatory domains are signed off and unexpired. None of the ten is. England holds 29 entries across ten domains, one of them signed off. The gap closes with research and sign-off by named people. It isn’t an engineering gap, and the board is how you watch it close.
The organisation spine sits alongside it. Levels are a jurisdiction binding instead of a constant, so the eight-level English chain from the Department down to a physical site is data, and a reorganisation is an event with a date and a restatement basis. The as-is and to-be views show only what has been recorded; nothing is extrapolated.
Read the yellow notice on that screen. The chain cites the Acts that establish each level, and it also says the build environment couldn’t reach the legislation site to read them, so the entries are draft and a deployment supersedes them with its own sourced values. That is the pattern everywhere on this platform: ship the machinery, let governed content arrive by configuration with its source recorded, and keep the screen honest while it’s absent.
Movement is the layer that turns a record into an operating picture. A digital twin without an event stream has no motion, and analysis over a static snapshot is search. So the first structural change in the alignment programme was an append-only, hash-chained events table, with admissions, transfers and discharges as its first producers.
On the demonstration system the spine holds fifteen events from two producers: the admission feed and the platform’s own mental-health bed occupancy. The chain verifies. One event has no resolvable subject, and the summary says why: no person holds that identifier. Three occurrences produced no event, and the summary says why: the discharge hasn’t happened yet. Events are emitted by a reconciler keyed on the producer row, with idempotency enforced in the database, so a row that arrives by seed, migration or integration is recorded once however it arrived.
Relationships are then derived from events, never typed. Two of the five relation types are drawn: admitted to a ward, discharged from a ward. Three are declared not derivable, with the reason on the methodology endpoint. The feed names a system, and a system isn’t an organisation. The feed carries a consultant’s display name, and a name isn’t an identity. Drawing those edges by loosening the match would attribute one trust’s events to another, so they stay undrawn.
Append-only hash-chained event spine, two producers, reconciler with database-enforced idempotency. Relationships materialised from events, two of five. Person resolution through one seam. GP Connect, master patient index and cross-border matching against the record. A connector register of real rows.
The admission feed endpoints now read their table, but the table is seeded and no interface writes to it. The connector board’s liveness is simulated and labelled as such. Outside the cross-border path the identity-match score is seeded on the demonstration records and isn’t computed. Timestamps: 444 columns still hold a time as text.
No message broker. No translation of an inbound feed’s payload into the canonical shape. No page yet reads the spine instead of its own store. No record locator. Only two producers, so the spine describes admissions and bed occupancy and nothing else.
This is the layer that’s most built, and the one a governance reviewer should test first. The rules are inside the platform, they run on the server, and a refusal comes with a reason.
Access is two separate things. Your role says what you may do. Your reach says which organisations you may do it in. A group grants reach only and can never grant a role, and a commissioning relationship grants no record access at all. Enforcement is on the server: a clinician outside the organisation a person is registered with gets a refusal naming the reason, and a read across a jurisdiction boundary returns not found, so the record’s existence isn’t disclosed.
The matrix above is published for every domain and enforced, as a server-side check on the routes, for three: genomics, protected characteristics and one more. For the rest the platform says, on its own enforcement endpoint, that the grade is a documented policy and not yet a control, and it lists what still bounds those routes: the graded role ladder, organisation scope and jurisdiction. An IG reviewer reading the matrix alone would over-read it. The platform tells them not to.
Approvals run as gates: a named authoriser or team, a quorum where one is required, a service level with automatic escalation, and a write-once audit trail whose hash chain is re-verified on read. And where a jurisdiction has no value for something the platform needs, the capability that depends on it switches off, across a long list of domains, with the reason shown instead of a neighbouring country’s value borrowed.
Role and reach separated and enforced. Server-side refusal with a reason. Not-found across jurisdictions. Approval gates with quorum, service level, escalation and hash-chained audit. Fail-safe on a missing jurisdiction value. The rule that no language model receives identifiers.
The permission matrix is enforced on three domains of twenty-three; elsewhere it is policy and says so. Two fail-safe registers still have open items. The organisation subtree is computed but three reporting surfaces don’t yet read it.
Prediction and simulation. The platform ships no inference library and makes no likelihood claims, and a class of such claims was withdrawn once already. Adaptation today means rules, and escalation that rises and falls with the signal. It doesn’t mean models.
An AI agent working in a health system needs three things it can rely on: what a thing is, what has happened, and what it’s allowed to do. Those are the three layers, and that isn’t a coincidence. A model given a governed door behaves differently from a model given a database.
Meaning first. An agent asked about a patient’s admissions has to know which of the estate’s many patient-reference columns is the register key, and which are labels or local references that resolve to nobody. The semantic registry records exactly that judgement, with the false matches marked. The canonical model gives it the national names for the objects. Without those, an agent reads column names and guesses, which is how a display name becomes an identity.
Then events. An agent reasoning about flow needs a record of what happened that can’t have been edited since. The hash-chained spine is that record, and its summary states its own ceiling, so an agent, or a person, reading it knows it covers admissions and bed occupancy and not the rest of the record yet.
Then permission. The same role, reach, gate and refusal rules apply to an agent’s calls as to a person’s, because they sit on the server and not in a screen. An agent can’t reach a person outside its organisation, can’t skip a gate, and can’t see an identifier or a token-vault mapping, because a standing rule in the platform forbids it and the evidence pack checks it. The AI provider is a component: three are configurable with keys held server-side, and with the AI switched off every module still runs.
The programme to close the gaps is phased and gated. Each phase ends with a number the platform can compute about itself and a build check that fails if it regresses. Phases 0, 1 and 2 are built: the measuring endpoint, the event spine, and edges derived from events. Nothing else in it is, and the position endpoint says so in its own words.
Four hundred and forty-four columns hold a timestamp as text. Each store gets a typed twin, dual-read and reversible, the nine event producers first. Nothing is deleted.
Eleven stores are eligible to produce events today. Then the missing middle of the kinetic layer: a store for the translation of an inbound payload into the canonical shape, so a feed lands as data the platform can act on.
The 1,141 drafted bindings and the jurisdiction profile close when named people sign. Code can’t close them. The deployability board is the progress bar.
A real repository in the loop, an archetype store populated by the deployment with its source recorded, validation of compositions against it, then the query language. The source-of-truth move waits for a named officer and a residual risk rating.
Only once the edges and events exist does a model over them mean anything. It arrives with a stated provenance or not at all.
| Screen | Route | What it shows | Status |
|---|---|---|---|
| Data models | /data-models | Canonical pin, semantic registry, physical schema, never folded together | ● Live |
| Semantic spine | /semantic-spine | Concepts, value sets, bindings, coverage, proposals | ● Live |
| Jurisdiction profile | /jurisdiction-profile | Fourteen domains, resolution tester, deployability board | ● Live |
| Organisation spine | /org-spine | Levels, structure, reorganisation as events, as-is and to-be | ● Live |
| Permission matrix | /rbac | Roles against domains, enforcement statement, scenarios, delegations | ● Live |
| Ontology position | /ontology/position | Measured position of each phase from the live schema (API) | ● Live |
| Event spine | /events/summary | Events by kind and producer, chain validity, unresolved subjects with reasons (API) | ● Live |
| openEHR status | /openehr/status | Probed repository mode, templates held, steps built and not built (API) | ● Live |
Live means the screen or endpoint reads the running platform and we exercised it while capturing this page. Where a figure on this page is a count, it is the one the platform printed on the day.