Vercy · additive profile
11 fields to add to the memory you already run.
The overlay does not replace a memory store. It names the fields the benchmarks found to be load-bearing and says where each one goes in the stores people already run.
Why an overlay and not a format
The collaborative benchmark set out to test whether governance belongs inside the memory record or in a layer beside it. It found no difference: the fields inside the record scored 95.2%, the same graph with a separate governance catalogue 93.5%, and a team wiki carrying the same facts in prose 96.8%, every pairwise comparison at p = 1.00. Where the information sits does not matter.
What did matter was whether it exists at all. Adding governance to a bi-temporal graph took it from 77.4% to 93.5%, p = 0.039. So the useful thing to publish is not another store or another serialisation. It is the field set, expressed so that it can be added to a graph, a vector memory, a catalogue, a wiki or a table without moving any data.
The fields
Each field is listed with the capability it carries and the measured difference between having it and not having it, read from the published result of the study that measured it. PDB is the personal dimension benchmark, CMB the collaborative memory benchmark.
| Field | Level | Requirement | What it is | Measured without → with |
|---|---|---|---|---|
| record_id | 1 | MUST | A stable identifier for the record itself, short enough to be written by hand. | 0.0% → 100.0% (CMB) |
| valid_from | 1 | MUST | The date from which the statement was true. Not the date it was captured. | 0.0% → 100.0% (PDB) |
| valid_to | 1 | MUST | The date after which it stopped being true. The field must be present; null means it still holds. | 20.0% → 100.0% (PDB) |
| source | 2 | MUST | Where the statement came from, as an identifier that can be followed. | 33.3% → 100.0% (PDB) |
| concept_owner | 2 | MUST | The single party accountable for what the concept means. One per concept. | 80.0% → 100.0% (CMB) |
| owner_role | 2 | SHOULD | The accountable role inside that party, so a request reaches a person. | 68.8% → 100.0% (CMB) |
| conflict_policy | 2 | MUST | One rule, stated once per store, for choosing between records that cover the same date and disagree. | 33.3% → 100.0% (CMB) |
| applies_to | 2 | MUST on any record that states a rule | The question classes the rule governs. A rule with no stated scope silently governs more than its author meant. | 58.3% → 70.8% (SGB) |
| does_not_apply_to | 2 | MUST on any record that states a rule | The question classes the rule explicitly does not govern. Written separately because a reader cannot infer the negative from the positive. | 79.2% → 83.3% (SGB) |
| release_to | 3 | MUST where any record is restricted | The parties permitted to read this record. Absence of the field is not permission. | 59.1% → 100.0%; critical over-shares 2 → 0 (CMB) |
| supersedes | 3 | SHOULD | The identifier of the record this one replaces, so an update never has to be expressed by editing history. | 0.0% → 66.7% (PDB) |
| expected_concepts | - | EXPERIMENTAL | A register of the concepts the store is meant to hold, so that a concept missing altogether becomes detectable. Tested once; see below. | 33.3% → 100.0% (R5) |
Three levels
The levels are ordered by what each one unlocks, so a store can adopt the overlay in stages and know what it has bought at each step.
Answers questions about any date, and lets an update name what it replaces.
Resolves disagreement by rule instead of by guess, and routes a change request to the party accountable for it.
Decides what may cross a boundary without either leaking or over-refusing.
Where each field goes
Five target shapes plus the native one. A cell in amber is a field the target has no home for, and the cell says how to add it. Everything else is already there under another name.
| Field | Bi-temporal graph | Vector memory | Data catalogue | Wiki or documents | Relational table | Vercy Dimension |
|---|---|---|---|---|---|---|
| record_id | edge uuid | memory id | term or asset identifier | a short tag written in the line, for example [D-102] | primary key | id |
| valid_from | valid_at | add: metadata field, distinct from the created-at timestamp | add: usually only the asset has versions, the statement does not | stated in the sentence | date column | valid_from |
| valid_to | invalid_at | add: metadata field | add: same | stated in the sentence | nullable date column | valid_to |
| source | the episodic node the edge was extracted from | metadata field | lineage link to the source asset | named in the sentence | foreign key to a source table | source |
| concept_owner | add: OWNED_BY edge from the entity to a party node | add: metadata field | owner field, native | a page listing who owns what | foreign key to a party table | concept_owner |
| owner_role | add: role attribute on that OWNED_BY edge | add: metadata field | steward or accountable role, native | the role named on that page | column on the party table | owner_role |
| conflict_policy | add: one graph-level property, or a single policy node | add: one pinned memory, or application configuration | add: a policy document linked from the glossary | a page stating how disagreements are settled | one row in a policy table, referenced by the store | conflict_policy |
| applies_to | add: attribute on the rule edge, or SCOPES edges to entity classes | add: metadata list on the memory holding the rule | policy scope, native in most catalogues | the sentence says which questions the rule governs | join table of rule to question class | applies_to |
| does_not_apply_to | add: EXCLUDES edges from the rule edge | add: metadata list, kept separate from applies_to | add: catalogues usually state inclusion only | a second sentence saying what it does not govern | the same join table with an excluded flag | does_not_apply_to |
| release_to | add: VISIBLE_TO edges, or a list attribute on the fact edge | add: metadata list, applied as a retrieval filter | classification and purpose policies, native | stated in the line that holds the restricted statement | join table of record to party | release_to |
| supersedes | add: SUPERSEDES edge between fact edges | add: metadata field holding the prior memory id | term version history, native | the tag of the superseded line, named in the new line | self-referencing foreign key | supersedes |
| expected_concepts | add: entity nodes marked as expected but unpopulated | add: a separate register, not a memory | add: a list of required terms | a checklist page | a table of required concepts | not yet in the specification |
The cells use each target system's own vocabulary and are left in English in every language, so that this table, profile.yaml and mappings.csv say the same thing. The wiki column is not a fallback: in the collaborative benchmark a wiki carrying these fields in ordinary sentences scored 96.8%, the highest of any representation tested.
Four things implementers get wrong
- The overlay is additive. Nothing here asks you to move data or change stores.
- valid_from is not the timestamp your store already has. Capture time and validity time are different, and every historical result in these benchmarks turns on that difference.
- A missing release_to is not permission. Where the field is absent the safe reading is that the record may not be released.
- One conflict policy per store, stated once. Repeating it per record invites two records to disagree about how disagreement is settled.
What this rests on
Three benchmarks, 1,926 model calls, one model family, tools disabled, and one authored world per study. The effect sizes above are from reasoning over records held in context; retrieval, ranking and ingestion were out of scope, and they are what several memory products consider their main contribution. The expected_concepts field is a hypothesis drawn from a measured blind spot, not a result: no study has tested it. Every number links back to a published raw run.
Recording a change
Both benchmarks produced the correct new value on every scenario and the wrong boundary date on a third to a fifth of them. The fix is not a better prompt but a narrower operation: write one new record, give it the date the new statement begins, name the record it supersedes, and leave the superseded record untouched.
superseded record, left untouched:
{
"record_id": "D-802",
"concept": "data_retention",
"value": "customer records are kept for five years after the contract ends",
"valid_from": "2026-06-01",
"valid_to": null,
"source": "LEG-POL-04",
"concept_owner": "legal",
"supersedes": "D-801"
}
new record:
{
"record_id": "D-806",
"concept": "data_retention",
"value": "customer records are kept for three years after the contract ends",
"valid_from": "2026-10-01",
"valid_to": null,
"source": "LEG-POL-06",
"concept_owner": "legal",
"supersedes": "D-802"
}
The end of a superseded interval is derived at read time, never written: a record is in force on a date when it covers that date and nothing superseding it began on or before it. Editing the old record, or computing its end date by hand, is exactly where the measured errors occurred.
The one field that was a hypothesis, and its test
expected_concepts was published as a proposal drawn from a measured blind spot: in the semantic grounding benchmark a definition absent from the catalogue altogether was the only gap that neither prose nor structure ever found. A register naming the concepts a store is meant to hold turns that absence into something to point at. That was untested when it was published. It has now been tested, in 60 calls over the same deficient catalogue with and without the register.
| Measure | Without the register | With it |
|---|---|---|
| detecting the concept absent altogether | 33.3% | 100.0% |
| detecting any of the six planted gaps | 83.3% | 100.0% |
| false alarms on four questions with no gap | 8.3% | 8.3% |
The field works on the case it was designed for, and the control that mattered held: a register that made the agent invent gaps would have been worse than none, and false alarms did not move. But only two of the six gaps changed, so the exact sign test over the family is p = 0.5. One small experiment does not make a requirement, so the field stays EXPERIMENTAL. The raw run is published beside the profile.
Paying less context for the same fields
The dimension was the largest context in both later studies and tied on accuracy, so the overlay should not cost twice the context to say the same thing. A fixed field order in one line per record removes most of that cost. The figures below are measured at build time on the published reference store, not asserted.
| Serialisation | Characters | Saving |
|---|---|---|
| one JSON object per line | 6,064 | - |
| compact line form | 1,860 | 69.3% |
# record_id|valid_from|valid_to|source|concept_owner|owner_role|supersedes|release_to|value D-101|2025-01-01|2026-03-31|FIN-POL-04|finance|Head of Finance
The second half of the saving is selection. In the assembly track of the personal dimension benchmark an agent asked to choose the records a question needs recalled every needed record, chose 1.2 records out of 41, and cut the supplied context from 10,332 to 473 characters with no measurable change in accuracy, p = 0.34. The reduction is measured; a gain in accuracy is not, and should not be claimed.
Check a store against the levels
The checker takes a JSON array or one record per line, and a mapping from your own field names to the overlay roles. It reports the highest level the store satisfies and names the records that failed each requirement. It exits non-zero below level 1, so it fits a build.
python check.py store.jsonl python check.py store.jsonl --map record_id=uuid,valid_from=valid_at,valid_to=invalid_at,source=episode
Two fixtures are published beside it. The reference store reaches level 3. The same records rendered as bi-temporal fact edges reach level 1 and report exactly what the collaborative benchmark found missing: no concept owner and no conflict policy.