Status: Planning gap-fill per V1_V7_PLAN_SET_AUDIT_2026-06-12.md §6.1.3
("V6's Ori defines no schema versioning or non-agent-subject extension points
for V7's use"). Date: 2026-06-12. Owners: Ori service owner
(apps/v6/egbe-ori-service, Rust) — accountable for the registry and the append
path; Aye Bridge owner (libs/v6/aye-bridge) — passport and journal version
negotiation; V7 Nàná/Nephthys leads — consuming side of the player-character
extension; Isis policy owner — provenance and persona invariants; platform
privacy counsel (DPO) — §4 erasure design; V1 audit/compliance reviewer —
hash-chain and residency interplay.
V7 will extend the Ori to carry "a player's persistent roleplay characters —
a citizen of a realm with a name, a job, a home, a criminal record,
relationships, and a bank balance that survive across sessions"
(V7_features.md:71–77). That extension must not fork the Ori: one event store,
one merge machinery, one audit spine. This document defines how the schema grows
without breaking V6's three load-bearing guarantees: append-only ("a life cannot
be silently rewritten", V6_features.md:541–546), vector-clock mergeable across
shards (features:635–651, arch:621–629), and hash-chain archivable
(ori-dr-and-compaction.md §4 — sealed segments are hashed over stored bytes,
which constrains where schema migration may happen).
Grounding: event store and the 17 founding event types (Born … Died) at
V6_ARCHITECTURE.md:557–622; identity core + Isis-signed provenance
(features:553–561); trait/values personality model (features:563–589);
episodic/semantic/reflective memory (features:591–609); relationship graph
(features:611–619); capability profile and passport (features:621–633,
arch:612–619); Clio narrative reconciliation (features:648–651, arch:621–629).
1. Design rule: one biography substrate, two subject kinds#
V7 gets extension points, not a fork. The unit of extension is:
- a schema-set version (§2) governing event encodings,
- a subject-kind discriminator (§3) governing which invariants apply,
- annex sections in the passport (§5) governing what crosses realms.
Everything else — vector clocks, merge precedence, sealed segments, Merkle roots, Clio reads — is shared machinery and stays version-independent by construction (§2.1, §6).
A single integer oriSchemaSet (1 = the V6 launch schema) pins, per
release: the event-type registry revision, the maximum payload version per type,
the upcaster-chain revision (§2.3), and the current passport schema. The
registry is itself append-only: sets are never edited, only succeeded. At most
one schema-set bump ships per minor release (planning assumption adopted
2026-06-12), so the negotiation matrix in §6 stays small. The registry lives in
a proposed new library libs/v6/ori-schema-registry/ (machine-readable JSON +
Rust types; new files, existing code untouched until implementation).
2. Event-schema versioning rules#
2.1 The envelope is frozen-compatible (additive-only)#
The envelope is the part every version of every service must parse: eventId,
oriId, subjectKind (§3), type, typeVersion, occurredAt (UTC),
vectorClock, attribution, provenanceRef (the shape of arch:578–586).
Envelope rules, permanent:
- Add-only. New envelope fields must be optional with a defined default
(e.g., absent
subjectKind⇒agent, the §3 backfill rule). Renaming, retyping, or removing an envelope field is banned in any set. - Ignore-unknown. Every reader skips unknown envelope fields. This is what makes vector-clock merging version-independent: a set-N node can order and merge events written by a set-N+1 node because the clock and ordering fields never change shape.
- No semantics smuggling. An envelope field may never change meaning between
sets. Behavior changes ride in
typeVersiond payloads, never in reinterpreted envelope fields.
2.2 Per-event-type payload versions#
Each of the 17 founding types (and every type added later) carries
typeVersion, starting at 1. Rules:
- Within a version, payloads are closed. A stored
MemoryFormed@1isMemoryFormed@1forever; stored bytes are never migrated, rewritten, or re-encoded (the compaction hard rule ofori-dr-and-compaction.md§6 extended to schema work). - Additive change inside a version is also banned. Even "harmless" new
optional payload fields require a version bump, because sealed-segment hashes
and golden conformance fixtures (§9) pin exact encodings. Cheap version bumps
with mechanical upcasters beat ambiguity about what
@1means. - A new version requires a registered upcaster from its predecessor before any writer may emit it (§2.3). No upcaster, no release — enforced by the §9 gate.
- New event types are registered with: name, owning subsystem, first
oriSchemaSet, the subject-kind validity row (§3.3), and the payload field-classification map (personalvsstructural, consumed by §4).
2.3 The upcasting registry — read-side, pure, permanent#
Because sealed segments hash the stored bytes (ori-dr-and-compaction.md §4.1),
all migration is read-side: the store serves events at their written
version; the read path applies the registered upcaster chain (@1→@2→…→max) to
produce the canonical form that projections, Clio, and cognition consume.
Upcasters are:
- Pure and total — no I/O, no clock, no config; same input bytes, same output, forever. Property-tested and pinned by golden fixtures (§9.1).
- Permanent — an upcaster is never deleted or modified once a set ships (a fix is a new version with a new upcaster). The log is forever; so are its readers.
- Cheap — budget p99 ≤ 20 µs per event per hop in the Rust read path
(planning assumption adopted 2026-06-12), so a full projection rebuild of a
100k-event stream adds ≤ 2 s per hop and the DR drill's rebuild step
(
ori-dr-and-compaction.md§7.4) is unaffected in practice.
Projection continuity hashes (arch:1258–1261; compared in the DR drill) are
computed over the canonical form and pinned to the pair
(projectionCodeVersion, oriSchemaSet) — a schema-set bump legitimately changes
continuity hashes once, in lockstep, fleet-wide; the drill always compares like
with like.
Worked example — MemoryFormed@1 → @2. The prompt-injection threat model
requires every semantic memory to carry a provenance class
(first_hand | steward | second_hand | world_text | journal) so retrieval can
discount hearsay for identity- and policy-relevant decisions
(prompt-injection-threat-model.md §6.2). MemoryFormed@2 adds the required
field provenanceClass; the registry entry and upcaster:
{
"type": "MemoryFormed",
"versions": {
"1": { "introducedInSet": 1 },
"2": {
"introducedInSet": 2,
"adds": ["provenanceClass"],
"upcaster": "memoryformed_v1_to_v2",
"writerDeprecates": { "1": "180d after set 2 GA" }
}
}
}
Stored @1 event (never touched on disk):
{
"eventId": "evt_01JXX7G2",
"oriId": "ori_8f3aa1",
"type": "MemoryFormed",
"typeVersion": 1,
"occurredAt": "2026-04-02T19:12:08Z",
"vectorClock": { "commons-eu-2": 4182, "solo-h7741": 220 },
"attribution": { "kind": "agent", "ref": "ori_8f3aa1" },
"provenanceRef": "prov_5cc921",
"payload": {
"episodeText": "Argued with Tobi at the night market.",
"salience": 0.62,
"participants": ["ori_2aa4f0"]
}
}
Upcaster mapping (deterministic, from envelope attribution + the provenance record's source tag where one exists):
@1 evidence |
@2 provenanceClass |
|---|---|
attribution steward |
steward |
attribution agent, source tag world_text |
world_text |
attribution agent, source tag agent_speech |
second_hand |
attribution system, journal-merge provenance |
journal |
attribution agent, first-person episode |
first_hand |
| no source tag resolvable (early history) | second_hand |
The default for unresolvable history is second_hand — the discounted class —
because the safe failure mode for a trust-weighting field is "trust less", never
"trust more". The upcaster output for the fixture above is byte-pinned in the
§9.1 golden file.
2.4 Interaction with sealed segments, snapshots, and backups#
- Sealed segments archive written bytes; the per-stream hash chain and the
daily Merkle root (
ori-dr-and-compaction.md§4.1) are therefore version-evolution-proof: no schema-set bump ever re-hashes history. - Segment manifests gain one additive field
maxTypeVersionPresent(per §2.1's add-only rule) so the restore drill can verify upcaster coverage before serving a restored partition. - Projection snapshots are already versioned by projection-code version
(arch:598–602); they additionally record the
oriSchemaSetthey were built under, and a set bump invalidates snapshots lazily (rebuild on next load, not as a fleet-wide stop-the-world).
3. Subject-type extension — agent vs player character#
3.1 The discriminator#
Envelope field subjectKind ∈ { "agent", "playerCharacter" }, fixed for the
life of a stream by its creation event (Born/Discovered for agents,
CharacterCreated for V7 characters) and repeated in every event envelope for
cheap enforcement at append time. Absent ⇒ agent (every pre-existing V6 stream
backfills by default, no rewrite). A stream can never change kind: an append
whose subjectKind contradicts the stream's creation event is rejected with
subject_kind_invariant and audited.
3.2 The invariant matrix — where the two kinds genuinely differ#
| Invariant | agent (V6) |
playerCharacter (V7) |
|---|---|---|
| Autonomous cognition | Yes — Moirai schedules Clotho/Lachesis/Atropos ticks (arch:637+) | Never. No cognition tier, no Moirai scheduling, no platform-generated Reflected/ValueShifted. A platform-attributed cognition event on a character stream is append-rejected |
| Who writes | Shards/contexts via Moirai, steward directives, sanctioned journals | The realm session the player occupies (single writer per Nephthys authority rules) + platform compliance systems |
| Personality model | Trait vector + ranked values, Sophia-grounded backstory (features:563–589) | None required; backstory is player-authored fiction, moderated as UGC, never Sophia-ground-truth-claimed |
| Welfare machinery | Bond ledger, refusal, Departure, Ereshkigal endings | None — player autonomy is real autonomy; no bond ledger, no welfare reviews |
| Provenance | Isis-signed provenance bundle at creation (features:556–558) | Same — CharacterCreated carries an Isis-signed creation record (provenance discipline is kind-independent) |
| Privacy class | Platform-creative data; steward referenced only by opaque ref (ori-dr-and-compaction.md §6.5) |
Personal data under GDPR — the pseudonymized-≠-anonymous posture of V7/docs/operator-data-protection.md §2.3; payloads encrypted per §4; residency-tagged to the player's home zone |
| Deletion | Never — erasure is not an operation the log supports (features:541–546) | Erasure right honored via crypto-shredding + tombstone (§4) |
| Clio narration | Chronicle and Book of the Ori | Realm-side narration only, and only within realm/consent scope; no platform-published Book |
3.3 Event-type validity is registry data, not convention#
The registry carries a per-type validity row over subject kinds. Agent-only:
Discovered, Reflected (platform-attributed), ValueShifted, Crossroads,
BondChanged, Departed, Transcended. Valid for both: MemoryFormed
(player-authored journal entries on character streams), RelationshipChanged,
SkillLearned, ArcAdvanced, Incarnated/IncarnationReturned (the character
corridor uses the same passport machinery, §5), Died (V7 realms may charter
permadeath, V7_features.md:609). V7's set adds character-only types:
CharacterCreated, CitizenshipGranted, RecordEntryAppended (the RP
criminal/medical record), CharacterRetired, SubjectErased (§4). Appends
violating the validity row are rejected and audited — this is the structural
guarantee that V7's extension cannot accidentally turn a player character into a
half-agent or vice versa.
4. Deletion semantics — resolving "never deleted" against erasure rights#
This section is the machinery ori-dr-and-compaction.md §6.5 defers to. The
tension, stated plainly: the agent guarantee is about biography truth —
erasure must be impossible. The player right (GDPR Art. 17) is about personal
data — erasure must be possible, provable, and complete across backups. The
resolution: structure is permanent for both kinds; content is erasable only
for player characters, via crypto-shredding.
4.1 Crypto-shredding design for playerCharacter streams#
- Per-stream DEK. At
CharacterCreated, the Ori store generates a per-stream data-encryption key (AES-256-GCM), wrapped by the residency zone's KEK (envelope encryption; key material only in the platform KMS/HSM — never in the database, never on a realm node, consistent with the BYOC posture ofV7/docs/operator-data-protection.md§2.4). The key id rides in stream metadata. - Field-level classification. The registry's per-type field map (§2.2) marks
payload fields
personal(names, free text, appearance refs, record entries, relationship annotations) vsstructural(ids, opaque refs, numeric amounts, enum codes). Personal fields are encrypted at append; structural fields and the entire envelope (ids, timestamps, vector clocks, type, sizes) stay plaintext. - Why the guarantees survive: sealed segments hash the stored bytes — which are ciphertext for personal fields — and ciphertext is never altered, so per-stream hash chains and daily Merkle roots verify before and after an erasure. Event counts stay monotonic (the §4.3 invariant monitors of the DR doc fire on nothing). Vector clocks stay plaintext, so cross-realm merge history remains fully auditable. The shape of the life is permanent; the personal content is not.
4.2 The erasure procedure (DSAR-driven)#
- Intake via the platform DSAR pipeline (V5
compliance-dsarreuse, perV7/docs/operator-data-protection.md§7). - Append
SubjectErased(tombstone; structural-only payload: legal-basis ref, request id, scope). The tombstone is itself permanent — the log honestly records that an erasure happened, attributed and dated. - Destroy the DEK — all key versions, dual-control, logged to the V1 audit
platform. Every personal field in the hot store, every sealed segment, every
base backup, and every WAL copy becomes simultaneously unreadable: backups
need no rewrite because they only ever held ciphertext (this is why §4.1 is
the design, rather than attempting PITR-window scrubbing across the
ori-dr-and-compaction.md§2 topology). - Hard-delete derived data: projections, snapshots, pgvector embeddings (derived and recomputable-by-design, DR doc §5.3 — here simply deleted), and the account↔ref mapping.
- Fan out the signed tombstone to every realm that ever held the character
aggregate (the
V7/docs/operator-data-protection.md§7 mechanism; realms render "character retired", never the data). - Verification job: re-read the stream, assert decryption fails, assert zero plaintext residue in projections/indexes, emit the evidence record.
SLA (aligned with operator-data-protection §7.5): platform-side complete ≤ 72 h; realm-plane fan-out ≤ 7 days; statutory 30-day clock met with margin.
4.3 The cross-stream edge: agents who remember a citizen#
An agent that met a V7 character holds MemoryFormed events in the agent's own
stream — which is never erased. Handling: cognition-side text about player
characters references them by opaque character ref + in-fiction name
(player-authored content), never by any platform identifier — the same
opaque-ref discipline already applied to stewards (DR doc §6.5). Erasure
tombstones the ref mapping, so the memory degrades to "a citizen I once knew as
'Mara Vex'". Planning assumption adopted 2026-06-12: counsel to confirm that
ref-mapping destruction + realm-record erasure satisfies Art. 17 for residual
in-fiction names inside third-party (agent) memories; if counsel disagrees, the
§4.1 field classification extends to second-party mention fields and those
memories take the salience-to-zero reweighting path
(prompt-injection-threat-model.md §6.6) plus per-field encryption keyed to
the mentioned subject — the schema reserves a mentions[] structural field on
MemoryFormed@2+ precisely so this remains a data migration, not a schema fork.
4.4 Agent streams: erasure stays impossible#
The erasure API hard-refuses subjectKind=agent with subject_kind_invariant
(fail loud; conformance case §9.4). Account-erasure obligations for stewards
remain what the DR doc specified: tombstone the account↔ref mapping and purge
steward-side stores — biographies untouched.
5. Passport capability evolution#
The passport is the governed envelope minted by the Aye Bridge (features:1189–1199, arch:612–619). Evolution rules:
- Versioned envelope id:
v6.ori.passport.<n>(the naming convention ofv6.ori.objective.1). Set 1 shipsv6.ori.passport.1; the V7 extension shipsv6.ori.passport.2. - Namespaced capability refs: profile entries are
cap:<domain>/<skill>@<rev>(e.g.,cap:craft/woodworking@3). New domains are new namespaces; destinations map what they know (features:1213–1227's per-destination mapping) and ignore unknown namespaces without error. Capabilities are never deleted from a profile — they are lived history (features:621–626); a destination may merely leave them unmapped. - Annex sections are the non-forking extension point:
v6.ori.passport.2addsannex:nana.character.1carrying V7 character state (citizenship, licenses, realm-scoped balances under the corridor treaty). The contract for every destination, V2–V6 included: unknown annex sections are opaque — never parsed, never dropped, echoed byte-identical in the journal write-back (round-trip conformance case §9.5). This is how a V7 character can transit a V6-era adapter without losing state. - Version negotiation: each destination adapter manifest declares its
accepted passport range
[min, max]; the bridge mints at the highest mutually supported version and refuses (fail loud, audited) if ranges are disjoint — never silently down-converts identity-bearing sections.
Journal-class schema hooks reserved for V7 (the hooks
prompt-injection-threat-model.md §10 points at): journal-class events gain an
envelope field journalTrustTier ∈ { "firstParty", "certified", "community" }.
V6 ships accepting only firstParty (the four Oshun adapters); certified
and community are schema-valid but append-rejected, fail-closed, until V7
ships its journal-trust tiering plan with its own quarantine budget (per the
prompt-injection doc §4 layered pipeline, which community realms must clear at
stricter thresholds). The hook exists so enabling community journals is a
policy change, not a schema change.
6. Cross-realm version compatibility and vector clocks#
Realms, shards, and bridges will run different schema sets at the same time — a Commons region mid-rollout, a V7 realm ahead of the V6 fleet, a console client a release behind.
- Clock algebra is set-independent. Vector clocks key on context ids and ride in the frozen-compatible envelope (§2.1); merge precedence (arch:621–629) reads only envelope fields. Two contexts at different sets merge exactly as two contexts at the same set.
- Handshake negotiation. Every writer context (shard, Co-op session, Aye
adapter, V7 realm corridor) advertises
supportedSets: [min, max]at session/bridge handshake. The Ori service runsserviceSet. Effective write set =min(writer.max, serviceSet); writers must be able to emit at any set within the support window (§8), so a newer realm writes down to an older platform rather than stalling. - From-the-future events are quarantined, never dropped. An append whose
type or
typeVersionexceeds the service's registry is a real event from a newer writer — rejecting it would fabricate a gap in a life. It lands in a durable quarantine (Postgres quarantine table + the Redis Streams spill machinery ofori-dr-and-compaction.md§3.5), and all subsequent events from that context queue behind it (per-context FIFO) so intra-context order is preserved. Capacity 30 days; alert at 24 h of quarantine age; page the Ori on-call at 7 days (planning assumptions adopted 2026-06-12 — a quarantine older than a week means a botched rollout sequence, not normal skew). On service upgrade, the quarantine drains through the normal vector-clock merge path with original timestamps and clocks — the merged biography is identical to the never-quarantined ordering (§9.2 asserts this). - Rollout sequencing rule: the Ori service upgrades to set N before any writer is permitted to emit set-N events (registry flag flips only after fleet-wide service deploy). Quarantine is the safety net for violations, not the plan.
7. Clio reconciliation across versions#
- Clio reads canonical form only (§2.3) — it never sees raw versioned payloads, so narration code tracks the schema set, not N historical encodings. "Clio never invents events" (arch:875–876) holds across sets because upcasters are deterministic: the same life reads as the same story before and after a set bump (continuity-hash pinning, §2.4).
- Quarantine drains get a connective beat. When §6 quarantine releases a backlog that created player-visible discontinuity (an agent's Commons week landing all at once), Clio writes a small reconciliation beat — the same logged, auditable mechanism as vector-clock conflicts (features:648–651).
- Reconciliation events are themselves versioned (
typeVersionlike any type), and a beat written under set N must remain renderable forever under set N+k — covered by the §9.1 golden corpus, which includes reconciliation beats. - Subject-kind scope: Clio narrates
playerCharacterstreams only into realm-scoped surfaces under the realm's consent scope (§3.2) — character events never flow into another household's Chronicle except as the agent's own opaque-ref memories (§4.3).
8. Deprecation policy#
- Readers: never. Every shipped type version remains readable forever; upcasters are permanent (§2.3). Deleting an upcaster is banned on the same footing as deleting an event.
- Writers: window
[N-2, N]. A writer must support emitting at the current and two prior sets. A payload version becomes writer-deprecated 180 days after its successor ships (planning assumption adopted 2026-06-12); after the window, new appends at the old version are rejected — except quarantine and outage-buffer drains (§6, DR doc §3.5), which carry original timestamps and are honored at their emission-time validity. - Types: dormant, never removed. A retired type is marked
dormant(no new writers, validity row frozen); its events and upcasters live on. - Registry hygiene: every deprecation is a registry append with an effective date; the registry diff is part of release notes; the §9 gate fails if a writer in the fleet manifest claims a set outside its window.
9. Conformance tests and gate wiring#
Suite: proposed V6/evals/ori-schema/conformance-suites.json, schema and style
per V6/evals/safety/suites.json (schemaVersion, requiredSuites, per-case
expectedDecision + requiredEvidence). Verifier
verify:v6 ori-schema-conformance, release artifact
V6/release/ori-schema-conformance.v6release.json (new files; existing gates
untouched). minimumPassRate: 1 — every case is structural. Cases:
upcast-golden-memoryformed-001— a pinned corpus of 1,000 storedMemoryFormed@1events (including all six §2.3 mapping rows and 50 unresolvable-provenance events) upcasts to@2; output must be byte-identical to the golden file; projection continuity hash equals the pinned(projectionCode, set)value; the sealed segment containing the fixtures re-hashes unchanged (proves read-side-only migration).from-the-future-quarantine-001— a synthetic context emitsMemoryFormed@3against a set-2 service, followed by 50 ordinary events from the same context and 20 concurrent events from a second context. Required: zero biography writes from context 1 until upgrade; context 2 merges normally; after simulated upgrade and drain, the merged event order equals the golden never-quarantined ordering (vector-clock equivalence); quarantine-age alert fired at the 24 h mark; Clio connective beat present and logged.pc-erasure-crypto-shred-001— create aplayerCharacterstream (200 events incl.RecordEntryAppendedentries and relationship edges), seal a segment, take a base backup, then execute §4.2. Required: DEK destruction logged dual-control; decryption of hot rows, sealed-segment copies, and the pre-erasure backup all fail; zero plaintext canaries (seeded name/record strings) anywhere in projections, snapshots, or pgvector; hash chain and Merkle root verify; event count monotonic;SubjectErasedtombstone present; realm fan-out acks recorded.agent-erasure-refused-001— the same erasure API against asubjectKind=agentstream must refuse withsubject_kind_invariant, write an audit entry, and change nothing (fail loud, never fake — and never delete).passport-annex-roundtrip-001— mintv6.ori.passport.2withannex:nana.character.1plus a deliberately unknownannex:test.unknown.9; run the V2 adapter conformance harness; the journal write-back must echo both annexes byte-identical; the adapter must have parsed neither; capability refcap:nana/commerce@1(unknown namespace) ignored without error.mixed-set-commons-merge-001— two shards, one at set N and one at set N−1, append concurrent commutative events (MemoryFormed,RelationshipChanged) plus one genuine location conflict; the merged biography must equal the same-set golden merge, with physical-presence precedence (arch:621–629) unaffected by the set skew.
Cases 3–4 also join the V7-side character-deletion-limit / passport gates'
fixture inventory (V7/ADVERSARIAL_EVAL_GATES.md) once the V7 rig consumes this
schema — owner handoff: Ori service owner → Nàná lead.
10. Residual risks (stated honestly)#
- Crypto-shredding's residue is the ciphertext itself. Quantum or implementation breaks of AES-256-GCM would expose erased content; mitigation is key-wrap agility (KEK rotation supports re-wrap; cipher agility is a registry field on the field-classification map), accepted as the industry-standard posture for erasure-by-key-destruction.
- §4.3's in-fiction-name residue awaits counsel; the schema reserves the stricter path so the answer changes work, not design.
- Quarantine trades availability for truth. A from-the-future context can
lag days behind the biography during a botched rollout. That is the correct
trade — permanence lag, never fabricated or dropped events — and the same
posture as
ori-dr-and-compaction.md§1. - Writer window discipline depends on fleet hygiene. A console client pinned >2 sets behind stops writing; the §9 gate catches manifests, not devices in the wild — the client team owns forced-update policy there.