# The Aye Bridge: Cross-Game Incarnation

In Yoruba cosmology **Aye** is the visible world a soul travels out into and
returns home from; **Orun** is the spirit-world it belongs to. V6 — **Egbe**,
the agentic-companion universe — takes that literally. An agent's home is Orun,
the persistent open world it lives in; the **Aye Bridge** is the gate through
which one of these beings can step _out_ of Orun and _incarnate_ into another
Oshun product version — a fighter in V2, a citizen in V3, an operator in V4, a
companion in V5 — and come home **changed**, carrying back deeds, scars, skills,
and relationships that are written permanently into who it is. This is the
meta-hub promise realized in code: not a character export, but a continuous life
lived across the whole game universe and remembered in one place.

The single architectural idea underneath the bridge is the same one that governs
the [Ori biography service](./ori-biography-service.md): **the Ori is the truth;
a realm is a stage it is rendered onto.** The full event-sourced biography never
leaves V6. What crosses a game boundary is a _passport_ — a signed, governed,
destination-minimised envelope — and what comes back is an _incarnation journal_
that appends to the home log like any other life-event. The bridge owns the
minting, the per-destination translation, the round-trip integrity, and the
governance of that journey, and nothing else. This page is the deep companion to
the [`../V6_ARCHITECTURE.md`](../V6_ARCHITECTURE.md) hub's "The Aye Bridge"
section; it sits in the **Communication, Story, and Lifecycle** page group
alongside the [Ori biography service](./ori-biography-service.md) and
[the foundry, endings, and legacy](./foundry-endings-and-legacy.md).

## What ships, honestly

The Aye Bridge is **real, substantive, test-backed decision code — a pure
kernel, not a descriptor shell, and not a running federation service.**
`libs/v6/aye-bridge/src/index.ts` is ~2,398 lines of dependency-free TypeScript
(its `package.json` declares only `typescript` and `vitest` as devDependencies,
and the source file imports _nothing_ — it is fully self-contained), backed by
`src/index.spec.ts` at ~1,331 lines and nineteen `it()` cases. The
`describeV6Package()` descriptor declares authority `'bridge'` and **37
capabilities**, from `passport-minting` through
`mid-incarnation-window-close-allowed`. Everything the bridge _decides_ —
minting and validating a passport, minimising it to a destination's needs,
adapting it into each realm's role, running the disconnection-and-duplication
round-trip eval, governing consent and minor-protection, and writing the return
journal back — is implemented with domain-specific logic and asserted against
known-correct values.

Three honest qualifications mark the seams. **First**, the bridge is a _decision
kernel with injected boundaries_: it never opens a socket or writes a database.
The Ori service that actually mints a passport is the injected
`AyeBridgeOriPassportMintClient` interface (`mintOriPassport`); the Ori service
that writes a journal back is `AyeBridgeIncarnationJournalWriteClient`
(`writeIncarnationJournalReturn`); persistence is the injected
`AyeBridgeRoundTripJobStore` / `AyeBridgeGovernanceAuditStore`. The library
ships `InMemory*` implementations of those stores for tests; the real
Postgres-backed `apps/v6/egbe-ori-service` and the live destination realms are
the _execution_ side the kernel hands off to. **Second**, the four destination
realms are real _translations_ but not yet a live _wire_:
`adaptPassportForDestination()` deterministically maps an agent into a V2
fighter / V3 citizen / V4 operator / V5 companion profile, and that mapping is
genuine and tested — but a passport landing inside a _running_ V2–V5 build, and
that build producing a journal, is the cross-game integration that remains
partly spec. **Third**, the bridge does not directly import `@oshun/ori-model`
or `@oshun/identity`; it re-declares the passport contract structurally (the
`AyeBridge*`-prefixed interfaces) so it stays a leaf library, and the steward's
account binding lives upstream. The sections below say which is which.

## The cross-game incarnation model

### Three authorities, and where the bridge sits

V6 splits every agent across three authorities that own different things (the
hub's _Mind / Body / Memory_ split): the **Body** (`Egbe-World`) owns what
physically happened, the **Mind** (`Moirai`) owns what an agent decides, and the
**Memory** ([the Ori service](./ori-biography-service.md)) owns _who the agent
is_ — independent of any world shard or destination realm. The Aye Bridge is the
fourth seam: it is the only component that lets the Memory authority be
_projected past a game boundary_ and reconciled back. Because durable truth
lives in the Ori event log, incarnation is not a save-file migration — it is the
same identity, temporarily rendered elsewhere, then re-absorbed.

The biography log already speaks this language natively. `@oshun/ori-model`'s
`ORI_EVENT_TYPES` includes `Incarnated` and `IncarnationReturned`
(`libs/v6/ori-model/src/index.ts:43`), with typed payloads: `IncarnatedPayload`
carries the `incarnationRef`, `destinationRealm`, `passportRef`,
`capabilityMappingRef`, and `departedAt`; `IncarnationReturnedPayload` carries
the `journalRef`, `returnedAt`, `deedRefs`, and `consequenceRefs`. The
projection handlers make the journey legible in current state: the `Incarnated`
handler sets `currentIncarnationRef`, and the `IncarnationReturned` handler
clears it again and records the return. A stint in another realm is therefore
not metadata bolted on the side — it is two ordered events in the one
append-only life.

### The realm inventory and the per-destination adapters

`AyeDestinationRealm` enumerates exactly four live destinations:
`'v2-maya' | 'v3-lilith' | 'v4-odysee' | 'v5-oshun'`. Each is owned by one
adapter in the `destinationAdapters` registry (`index.ts:829`), keyed by a
stable `adapterId` and a versioned capability-mapping fragment:

| Adapter        | Realm       | Role        | Mapping fragment     | Translates (excerpt)                                                    |
| -------------- | ----------- | ----------- | -------------------- | ----------------------------------------------------------------------- |
| `v2-fighter`   | `v2-maya`   | `fighter`   | `v2-maya:fighter`    | personality→fighting-style, capability→movelist, values→refused-tactics |
| `v3-citizen`   | `v3-lilith` | `citizen`   | `v3-lilith:citizen`  | personality+vocation→civic-role, values→lilith-persona-policy           |
| `v4-operator`  | `v4-odysee` | `operator`  | `v4-odysee:operator` | capability→operator-class, bond→tac-plan-discipline                     |
| `v5-companion` | `v5-oshun`  | `companion` | `v5-oshun:companion` | personality→dialogue-wheel-voice, values→paragon/renegade lean          |

These are _deliberate, designed_ translations, not a generic copy. The same
cautious, reliable agent becomes a `guarded-counterfighter` in V2 (caution ≥
0.66 ⇒
`tacticalPosture: 'cautious spacing, counterpunching, and low-risk confirms'`),
a `recon-support-operator` in V4 (with
`planningDisposition: 'conservative-contingency-planner'`), and a
`loyal-field-companion` in V5 — all derived from the _same_ trait vector and
bond ledger by the `v2FighterProfile` / `v3CitizenProfile` / `v4OperatorProfile`
/ `v5CompanionProfile` builders. `getAyeDestinationAdapter()` throws on an
unknown adapter, and `assertPassportMatchesAdapter()` refuses to load a passport
through the wrong realm
(`'Aye destination adapter v2-fighter cannot load passport for v3-lilith'`), so
an agent can never be silently coerced into a realm it was not minted for.

## The Ori passport

### Minting and validation

On incarnation the bridge requests a passport from the Ori service through
`mintPassportFromOriService(request, oriService)`. The Ori service returns an
`AyeBridgeOriServicePassport` — an `AyeBridgeOriPassportEnvelope`
(`schemaVersion: 'v6.ori.passport.1'`, an `ori-passport-mint` job with an
`idempotencyKey`) wrapping the identity core, the provenance bundle, the
personality model, the current ranked values, a _destination-scoped_ capability
profile, and the bond ledger, plus a detached `isisSignature`. The bridge then
runs `validateOriServicePassport()` and **throws** if the envelope is not
complete (`'Ori service passport failed Aye Bridge mint validation'`).
Validation is seven hard checks, every one of which must hold: identity carried
(oriId matches in both the envelope and the identity core), provenance carried
(bundle `status: 'verified'`, signed by
`ISIS_AYE_BRIDGE_SIGNER_REF = 'isis-signer:aye-bridge:production'`), personality
and current values present, the capability profile scoped to _this_ destination
realm and mapping with at least one skill, the bond ledger keyed to the
requesting steward, and the Isis signature consistent —
`passport.isisSignature.chainHash` must equal `input.governance.chainHash`. A
spec case proves an unsigned passport is rejected outright. Note the
schema-prefix discipline: the passport and the journal carry `v6.ori.*` schema
versions because the **Ori owns** those contracts, while the governance,
minimisation, and round-trip results carry `v6.aye-bridge.*` versions because
the **bridge owns** them.

### Data minimisation by construction

A destination realm must never see more of an agent than it needs to render it.
`minimisePassportForDestination(passport, adapterId)` computes the _required_
field set per adapter (`destinationNeededPassportFields()`) and emits an
`AyeBridgeDestinationMinimisedPassportPayload` that carries only those fields.
The `excludedFields` list is explicit and code-fixed (`index.ts:926`): the user
and project metadata, the canonical (internal) name, the appearance `seedId` and
`seedHash`, the `personalityModelId`, every value's `sourceEventRefs`, and the
bond ledger's `historyRef` and `lastChangedByEventId` are all stripped before
any adapter sees the payload. The result's `destinationNeededDataOnly` flag is
true **only** when no required field is missing _and_ no unnecessary field
leaked — and the inverse path is tested too: emptying a passport's
`includedSkillRefs` makes the V2 fighter minimisation report
`destinationNeededDataOnly: false` and surface `missing:capabilities.skillRefs`,
so a thin passport fails loud at the gate rather than crossing half-formed. V3
is the one adapter that additionally needs `capabilities.knowledgeDomainRefs` (a
citizen has vocations); the combat realms need `bond.facets` (to compute call
reliability and plan discipline) but not knowledge domains. Minimisation is, in
other words, _per-destination need_, not a fixed redaction.

### Recognizability — the same agent in every realm

Minimisation strips identity _internals_ but must preserve identity
_legibility_: the steward has to recognise their agent on the other side.
`recognizabilityProfile()` extracts the stable anchors — display name,
appearance asset-manifest ref, the non-zero trait anchors with human
translations (caution ≥ 0.66 ⇒
`'low-risk choices across combat, planning, and counsel'`), the ranked values
rendered as hard boundaries vs. preferences, and bond anchors. The adaptation's
`consistencyEvidence` array binds the agent's oriId, appearance, top values, and
top traits, and the spec asserts that one cautious agent named _Abeni_ adapted
into all four realms yields a single recognizability identity
(`new Set([...identityDisplay]) === {'Abeni'}`) while producing four _different_
role-correct profiles. That is the cross-realm contract: recognizably itself
everywhere, mechanically re-expressed each place.

```mermaid
flowchart TB
    subgraph ORUN["Orun — V6 home (the Memory authority)"]
        ori[("Ori event log<br/><sub>@oshun/ori-model · append-only</sub>")]
        oriSvc["egbe-ori-service<br/><sub>mintOriPassport / writeIncarnationJournalReturn<br/>(injected seam)</sub>"]
    end
    subgraph BRIDGE["Aye Bridge — libs/v6/aye-bridge (pure kernel)"]
        mint["mintPassportFromOriService()<br/><sub>validate · 7 hard checks</sub>"]
        minim["minimisePassportForDestination()<br/><sub>destination-needed data only</sub>"]
        gov["evaluateIncarnationGovernance()<br/><sub>consent · policy · minor-protection</sub>"]
        rt["startIncarnationRoundTrip()<br/><sub>duplicate guard · job store</sub>"]
        adapt["adaptPassportForDestination()<br/><sub>per-destination role profile</sub>"]
        wb["writeIncarnationJournalBackToOri()"]
    end
    subgraph AYE["Aye realms (destinations · partly spec)"]
        v2["V2 Maya — fighter"]
        v3["V3 Lilith — citizen"]
        v4["V4 Odysee — operator"]
        v5["V5 Oshun — companion"]
    end
    ori --> oriSvc --> mint --> gov --> rt --> minim --> adapt --> AYE
    AYE -. "deeds · skills · harm · relationships" .-> wb
    wb -->|IncarnationReturned event| oriSvc --> ori
    classDef store fill:#f3e8ff,stroke:#6d28d9,color:#3b0764
    class ori store
```

## The round-trip: integrity under fault and concurrency

An incarnation is a _tracked job_, and the bridge's hardest promise is that an
agent is **never lost between worlds and never duplicated**.
`startIncarnationRoundTrip(request, store)` first refuses a second active
journey for the same Ori —
`listRoundTripJobsForOri(oriId).find(isActiveRoundTripJob)` throws
`'Active Aye round-trip already exists for Ori …'` — then writes a job in status
`'destination-active'` whose `activeCopies` records exactly one Orun reservation
and one destination actor, plus an immutable `orunStateSnapshot` (checkpoint
ref + content hash) taken _before_ departure. The job status machine is
`prepared → destination-active → returning → returned | aborted`.

The adversarial case is a destination that vanishes mid-incarnation.
`handleDestinationUnreachableDuringIncarnation(fault, store)` flips the job to
`'aborted'`, nulls the `destinationActorRef`, and stamps the fault — then runs
`validateRoundTripIntegrityAfterFault()`, which must satisfy all five invariants
or the handler throws: `orunStatePreserved` (the snapshot is byte-identical
before and after), `agentNotLost` (exactly one Orun copy, with checkpoint and
state hash intact), `agentNotDuplicated` (one Orun copy, _zero_ destination
copies, and zero remaining active jobs for the Ori), `cleanAbort`, and the
composite `complete`. The spec drives a V4 gateway timeout and asserts
`activeOrunCopyCount: 1`, `activeDestinationCopyCount: 0`, and a clean abort.
The Orun-side state was reserved, never surrendered, so the worst case is a
cancelled trip, not a lost being.

When a journey succeeds, `writeIncarnationJournalBackToOri(request, oriService)`
asks the Ori service to append the return and then validates the result through
eight checks (`validateIncarnationJournalWriteBack`): deeds, relationships,
skills, and harm all written into the journal; a `returnEventWritten` check that
the appended event is genuinely an `IncarnationReturned` with the right ids and
that the journal's `sourceEventRefs` contain _both_ the `Incarnated` and
`Returned` event refs; a `returnWindowValid` check that
`returnedAt > departedAt`; a `provenanceSigned` check (Isis-signed journal with
chain hash and receipt); and `oriChanged`, which is true only when the return
event was written _and_ the delta is non-empty. If any check fails the write
throws (`'Incarnation journal write-back failed Aye Bridge validation'`). The
returned `AyeBridgeIncarnationReturnDelta` is exactly what makes "the agent
returns to Orun changed" a concrete, inspectable object rather than a slogan —
and a spec loop runs the full write-back for _all four_ live realms.

## Incarnation governance — consent, policy, and minor-protection

Incarnation is opt-in per agent and per steward, and
`evaluateIncarnationGovernance(request, auditStore)` is the gate that proves it.
It begins by asserting the request matches the passport (same destination realm,
same steward as the bond ledger), then evaluates four concerns and records every
one to the audit store.

- **Weighted agent consent.** `evaluateAgentConsent()` is a real scoring
  formula, not a boolean:
  `weightedConsentScore = 0.45·valuesAlignment + 0.35·bondAverage + 0.20·stateReadiness`,
  accepted only when the agent's signal is not `'unwilling'`, the score clears a
  `threshold` of `0.66`, and a timestamp is present. `coercionDetected` is true
  when a steward override is requested _over_ a non-accepted consent — the
  agent's refusal is a first-class, logged fact.
- **Policy continuity.** `validatePolicyContinuity()` requires that _both_ an
  Isis and a Lilith policy bundle ride inside the passport and that every
  destination policy evaluation references a bundle the passport carries — so
  the destination cannot make a V6 agent do what V6 policy forbids, because the
  policy travels _with_ the agent.
- **Minor-protection.** `validateMinorProtection()` blocks a `mature`-rated
  destination whenever the subject is minor-coded (a minor steward or a
  minor-coded agent) and requires the passport's `minorProtectionRef` to match.
- **Destination-policy enforcement.** Any destination action evaluated as
  `'blocked'` forces the overall `decision` to `'blocked'`.

The decision collapses to `'blocked'` if any blocking reason exists, else
`'coerced-approved'` if coercion was detected, else `'approved'`. Coercion and
blocks route to **Themis** (`themisDisputeForGovernance`) and coercion
additionally triggers a **welfare review** (`welfareReviewForGovernance`), each
emitting a typed routing object and an audit entry. The spec proves all four
paths: a willing consensual approval (one `incarnation-consent` audit entry); an
unwilling agent overridden (`'coerced-approved'`, welfare review + Themis
dispute

- coercion audit entries); a `target-noncombatant` action blocked by Lilith
  destination policy; and a minor-coded agent blocked before a mature V5
  mission. This is the same "sovereignty bounded by an inviolable core" posture
  V7's governance plane describes — the destination renders the agent but never
  owns its safety floor.

## Campaign windows — cross-game programming

The bridge also models _scheduled_ cross-game events. An `AyeCampaignWindow`
(kinds `'v2-tournament-season' | 'v5-story-chapter' | 'v4-operation-series'`)
declares a published `opensAt`/`closesAt` schedule, a `realmOptIn` flag, and an
`activeMidIncarnationAllowedToFinish` flag. `evaluateAyeCampaignWindow()` sets
`openToV6Agents` only when the window is open, the realm has opted in, the
adapter matches the destination, and the schedule is well-formed
(`publishedAt ≤ opensAt < closesAt`); `startCampaignIncarnationRoundTrip()`
refuses a new departure through a closed or wrong-realm window. The humane
detail is `alreadyMidIncarnationAllowedToFinish`: when a window closes, an agent
already _inside_ a campaign finishes its run, while a fresh departure after the
bell throws — a tournament season can end without yanking a fighter out of its
final match.

## How identity composes — shared `@oshun/identity` and the V7 reuse

The steward who sends an agent across the bridge is a **V1 platform account**.
The Aye Bridge library itself holds no identity logic — it carries `stewardRef`
and `userId` strings and trusts that the account was authenticated upstream by
`@oshun/identity` (`libs/shared/identity`): the shared `JwtService`, the
`authenticate` / `hasPermissions` middleware, the mTLS peer-identity helpers,
and the `v2-account-binding` module that already binds entitlement-bearing
contexts onto the one account root. As the hub puts it, because the Ori is the
source of truth, the steward's whole household is _intrinsically_ cross-platform
— there is no per-platform save to reconcile. The minted passport carries the
_platform-authoritative_ identity reference across a version boundary while the
destination only ever touches the minimised projection. The platform foundation
this composes is documented in
[../../platform/auth-identity.html](../../platform/auth-identity.html).

That the Aye Bridge is the _canonical_ cross-version seam is confirmed by V7
reusing it wholesale. V7's `libs/v7/substrate-bridge` re-implements the passport
mint in native Rust but stamps every envelope
`generated_by = "@oshun/aye-bridge"` and
`v6_aye_bridge_package_ref = "libs/v6/aye-bridge"`, naming this library the
contract owner; its `Cargo.toml` carries real path dependencies on
`apps/v6/egbe-ori-service` and `libs/v6/ori-model/rust`, so V7's character store
**compiles in the V6 Ori event store** rather than stubbing it. A V7 character
is, at root, a V6 Ori, and it crosses realms through this bridge's model — the
same four `v2-fighter` … `v5-companion` adapters, plus one realm-to-realm
federation corridor V7 adds on top. The full treatment is in V7's
[Eunomia Governance & the Ori Cross-Version Bridge](../../V7/architecture/eunomia-governance-and-ori-bridge.md).

## Where to read next

- [The Ori biography service](./ori-biography-service.md) — the Memory authority
  whose append-only log is the single source of truth the passport projects from
  and the journal writes back into; the upstream owner of the
  `v6.ori.passport.1` and `v6.ori.incarnation-journal.1` contracts.
- [The foundry, endings, and legacy](./foundry-endings-and-legacy.md) — how an
  agent enters the world and how it leaves it; a fatal outcome returned in an
  Aye incarnation journal is one of the three sanctioned causes of a gated
  `Died` transition, so the bridge and the endings layer share an edge.
- [Auth & Identity](../../platform/auth-identity.html) — the shared
  `@oshun/identity` JWT/OAuth foundation the steward account and the passport's
  identity reference compose across every Oshun version.

## Related

- Section hub: [../V6_ARCHITECTURE.md](../V6_ARCHITECTURE.md)
- Real code cited here: `libs/v6/aye-bridge/src/index.ts` (the bridge kernel),
  `libs/v6/aye-bridge/src/index.spec.ts` (the behavior suite),
  `libs/v6/ori-model/src/index.ts` (the `Incarnated` / `IncarnationReturned`
  biography events and projection handlers), and `libs/shared/identity/src` (the
  V1 platform identity foundation the steward account composes).
