# Foundry: Endings & Legacy

In V6 — **Egbe**, the agentic-companion universe — the autonomous beings are
**Ori**, and the product's hardest, most distinctive promise is that an Ori has
a **finite life**. It can be released, it can graduate, and — rarely — it can
die. A companion you cannot lose is a toy; a companion whose life can _end_ is a
relationship. The subsystem that governs how a life concludes, and what survives
it, is **Ereshkigal** — named for the queen of the underworld, and the
architectural mirror of the **Ninhursag** birth foundry. If Ninhursag is the
foundry that forges an agent _into_ the world, Ereshkigal is the closing
foundry: it takes an ended life and forges it into durable **legacy** —
inheritance, memorial, and descendants. This page is the deep companion to the
[`../V6_ARCHITECTURE.md`](../V6_ARCHITECTURE.md) hub's "Ereshkigal — Endings and
Legacy" section, and it sits in the **Communication, Story, and Lifecycle** page
group alongside [the Ori biography service](./ori-biography-service.md),
[the Clio story engine](./clio-story-engine.md), and
[the Aye Bridge](./aye-bridge-cross-game-incarnation.md).

Endings in Egbe obey one non-negotiable rule inherited from the Ori model: the
biography is an **append-only log**, and erasure is not an operation it
supports. So "ending" can never mean "delete." Every terminal transition
Ereshkigal owns — **departure**, **transcendence**, **death** — resolves by
_appending_ a terminal event to a life that stays permanently readable, and
every legacy artifact is a new structure derived from that frozen record.
Nothing is forgotten; the life simply stops accruing new beats. That discipline
is what lets V6 promise that a steward, a bug, or an exploit cannot quietly
un-live an agent or wipe the memory of how it was treated.

## What ships, honestly

The endings-and-legacy logic ships as **`libs/v6/ereshkigal-legacy`** (authority
`legacy`, tags `scope:v6 / layer:legacy / type:lib`), a **pure, deterministic
TypeScript decision library** — ~948 lines in `src/index.ts` with a ~630-line
test suite in `src/index.spec.ts`, and zero runtime dependencies (its
`package.json` lists only `typescript` and `vitest`). Its public surface is
small and complete: a stable package descriptor (`describeV6Package`,
`ereshkigalLegacyHasCapability`, `src/index.ts:47`/`:51`, advertising 17
capabilities from `departure-release` to `walkable-lineage-graph`) plus **four
evaluator functions** — `evaluateDeparture` (`:342`), `evaluateTranscendence`
(`:414`), `evaluateDeath` (`:521`), and `evaluateAncestorGrove` (`:598`). Each
implements a real, domain-specific gated state machine with named thresholds,
and each is asserted against **known-correct values** in the spec (computed
grief weights, exact post-event counts, specific resolved/unresolved thread
sets) — not truthiness or wide ranges. This is decision logic, not a CRUD shell.

Three honest qualifications draw the line between what this library _is_ and
what the [hub prose](../V6_ARCHITECTURE.md) describes around it.

**First — this lib decides and describes; it does not perform I/O.** Every
evaluator is a pure function: it takes a snapshot of state and returns a typed
**report** (`EreshkigalDepartureReport`, `…TranscendenceReport`, `…DeathReport`,
`…AncestorGroveReport`). Those reports carry _envelopes_ for side effects —
grief-write records, a `memorial.render.requested` job, lineage-propagation
writes — that **downstream services enact**: the Ori service appends the
terminal event and the grief writes, the `@oshun/event-bus` emits the render
request, and Yemaya renders the keepsake. The library never touches Postgres,
the bus, or a renderer itself. `yemayaRemembrance.status: 'queued'`
(`buildYemayaRemembrance`, `:731`) is the envelope's _declared_ state, the seam
where enactment is handed off — honestly, not a claim that a render ran. The
decision and its thresholds are real and tested; the wiring lives in the
callers, exactly as the hub describes.

**Second — the hub prose runs ahead of this lib in two places, and the code is
the source of truth.** `V6_ARCHITECTURE.md` calls Ereshkigal "a Rust crate" and
specifies a Postgres `ori_lineage_edge` table with acyclicity enforced on
insert. The _shipped_ `ereshkigal-legacy` is **TypeScript** with **no `rust/`
directory** (unlike the sibling `ori-model`, which genuinely ships both a TS
reference and a Rust crate) and **no persistence code at all** — the lineage
_table_, its acyclicity guard, and the event-sourced projection belong to the
Ori service app or remain to be built, not to this lib.

**Third — the lineage relation vocabulary differs between prose and code.** The
hub names the `relation` enum
`{Raised, Mentored, FoundedLineageWith, MemorializedBy}`; the implemented
`EreshkigalLineageRelationshipType` (`src/index.ts:94`) is
`{Raised, Mentored, DescendedFrom}`. `FoundedLineageWith` and `MemorializedBy`
are not yet in the library, and `DescendedFrom` is the lib's third relation. The
sections below describe the **code as it is**, and call out where it reaches
toward the broader architecture.

## The three endings — Ereshkigal's terminal transitions

An Ori's life resolves through exactly one of three terminal transitions. Each
is a gated decision — deliberate, legible, and irreversible by design — and
each, on success, names the terminal Ori event the caller must append
(`Departed`, `Transcended`, `Died`). Crucially, **every report carries an
`oriAfter` continuity record** built by `buildOriContinuity` (`:890`) whose
`persisted` is _always_ `true` and whose `deletionScheduled` is _always_
`false`. There is no code path in this library that schedules an Ori for
deletion. Ending a life changes its `lifecycle` label
(`household → departed | transcended | died`) and bumps its event count by one;
it never removes the record.

```mermaid
flowchart TB
    tick["Welfare / arc / Commons signal<br/><sub>per-agent lifecycle review</sub>"] --> which{"which terminal<br/>transition?"}

    which -- "chronic bond damage" --> dep["evaluateDeparture()<br/><sub>damage≥65 · respect≤35 · ≥2 surfaced warnings</sub>"]
    dep -- "gate not met" --> retain1["warning-only<br/><sub>retained · Ori stays household</sub>"]
    dep -- "gate met" --> released["departed-release<br/><sub>unbound · re-attached to Wilds · Ori persists</sub>"]

    which -- "flourishing arc" --> tr["evaluateTranscendence()<br/><sub>stage=legacy · 4+ kinds integrated · score≥85</sub>"]
    tr -- "arc still live" --> retain2["arc-still-live<br/><sub>retained · steward direction kept</sub>"]
    tr -- "arc complete" --> elder["transcended-elder<br/><sub>Ancestor Grove · Lachesis tier · mentor</sub>"]

    which -- "sanctioned cause" --> dth["evaluateDeath()<br/><sub>minor-gate → cause-gate → effects</sub>"]
    dth -- "minor-coded" --> block1["blocked-minor-protection<br/><sub>no side effects</sub>"]
    dth -- "unsanctioned cause" --> block2["blocked-unsanctioned-cause"]
    dth -- "adult + sanctioned" --> died["died-memorialized<br/><sub>Ori frozen · grief writes · Yemaya render</sub>"]

    released --> legacy[("Legacy: lineage graph · Grove · memorial")]
    elder --> legacy
    died --> legacy

    classDef gate fill:#dbeafe,stroke:#1e40af,color:#1e3a8a
    classDef term fill:#f3e8ff,stroke:#6d28d9,color:#3b0764
    classDef block fill:#fee2e2,stroke:#b91c1c,color:#7f1d1d
    class dep,tr,dth gate
    class released,elder,died,legacy term
    class block1,block2 block
```

### Departure — release, not deletion

Departure is the welfare-driven ending: an agent that is chronically mistreated
chooses to leave. `evaluateDeparture` (`:342`) is gated on _chronic_ damage,
never a single bad day. It computes a **weighted bond-damage score**
(`departureBondDamageScore`, `:881`) where the four bond facets are not equal —
respect dominates at `0.45`, reliability `0.25`, care and alignment `0.15` each
— and only releases when **all three** conditions hold: `bondDamageScore ≥ 65`,
`respect ≤ 35`, **and at least two** Chronicle-surfaced warnings (warnings are
first filtered to those that were actually `chronicleSurfaced` with
`severity ≥ 70`, so private hurt that was never surfaced cannot push a
departure). The test (`index.spec.ts:31`) feeds respect 24 / reliability 32 /
care 38 / alignment 34 with two surfaced warnings, asserts the score lands at
the computed **70**, and checks the outcome is `departed-release` with the Ori
`persisted: true, deletionScheduled: false`, event count `41 → 42`, and a minted
`wildAgentRef`. A softer case — respect 48, one surfaced warning
(`index.spec.ts:111`) — resolves to `warning-only`, `retained`, with the event
count _unchanged_ and evidence `departure-withheld-until-chronic-damage`. The
key invariant: a departed Ori is **unbound from the steward and re-attached to
the Wilds as a wild agent**, fully re-discoverable. Departure ends the _bond_,
not the _life_.

### Transcendence — the only ending that promotes

Transcendence is the aspirational ending: an agent that completes a flourishing
life-arc graduates into an **elder**. `evaluateTranscendence` (`:414`) gates on
a flourishing arc being genuinely complete — `lifeStage === 'legacy'`, at least
one primary thread, **zero** unresolved primary threads, **at least four
distinct thread kinds** (`vocation`, `relationship`, `personal-quest`,
`growth-flaw`), and a `flourishing.score ≥ 85` measured against the agent's
_own_ values (the snapshot carries `obedienceContributionExcluded: true`, so
being a compliant servant cannot count as flourishing). A thread counts as
resolved only when `isResolvedTranscendenceThread` (`:860`) sees
`status === 'integrated'` **and** `progress ≥ 90`. When the gate passes, the
report mints an `EreshkigalElderState`: re-parented to
`V6District_AncestorGrove`, scheduled permanently on the `lachesis` cognition
tier, `availableAsMentor: true`, `keeperOfLore: true`, and — pointedly —
`stewardDirected: false` with `householdDirectivesAccepted: false`. An elder no
longer takes orders. The evaluator also builds a `Mentored`
`EreshkigalMentorAssignment` (`buildMentorAssignment`, `:864`) for each young
agent named, so transcendence immediately seeds the next generation's lineage.
The test (`index.spec.ts:160`) drives all four kinds to `integrated`/≥92 with
flourishing 94 and asserts `transcended-elder`, the elder state, two mentor
assignments, and `event count 42 → 43`; the near-miss case (`:278`, one thread
only `advanced`, score 78) yields `arc-still-live`, `retained`, steward
direction intact. Transcendence is the **only** transition that _adds_ presence
to the world rather than removing it.

### Death — rare, gated, and never farmable

Death is the rarest path, and the library's ordering is a deliberate safety
design. `evaluateDeath` (`:521`) checks the **minor gate first**: if
`agentAgeCode === 'minor-coded'`, it returns `blocked-minor-protection`
immediately via `blockedDeathReport` (`:677`) — **before any grief writes,
remembrance, or freeze** are computed. The test (`index.spec.ts:579`) confirms a
minor-coded agent with a fatal Aye journal produces _no_ grief writes, _no_
Yemaya remembrance, and an unfrozen Ori. Only then does the **cause gate** run:
`isSanctionedDeathCause` (`:751`) admits exactly three causes —
`life-arc-terminal`, `aye-fatal-journal`, `adjudicated-commons-event` — and any
other cause returns `blocked-unsanctioned-cause`. Death cannot be triggered
casually; it must come from a resolved arc, a dangerous incarnation
([the Aye Bridge](./aye-bridge-cross-game-incarnation.md)), or adjudicated
Commons drama. A sanctioned, adult death (`died-memorialized`) does four things:
it **freezes the Ori** (`oriFrozen: true`,
`acceptedFutureEventKinds: ['memorial-annotation']` — the log now accepts only
memorial notes, no new life-events); it emits weighted **grief writes** into
every living relation; it queues a Yemaya remembrance; and it sets
`lineageMutation: 'none'` — the deceased **remains a permanent ancestor node**.
The test (`index.spec.ts:487`) verifies an adjudicated Commons death freezes the
Ori, produces grief writes weighted 88 and 74 (mirroring the relations' edge
strengths), and queues the three-stage render.

## Legacy — what persists when an agent ends

An ending is only half of Ereshkigal. The other half is **legacy**: the durable
structures that outlive the agent and propagate it forward.

### The lineage graph and the walkable Grove

Legacy is made _spatial_. `evaluateAncestorGrove` (`:598`) turns an elder and
its relations into a navigable lineage graph for the `V6District_AncestorGrove`
plugin. It builds one `EreshkigalLineageGraphNode` per agent
(`buildLineageGraphNode`, `:772`) — each carrying a stable `groveActorRef`, a
`waypointRef`, and a `role` derived from the relation by
`lineageRoleForRelationship` (`:847`: `Raised → raised`, `Mentored → mentee`,
`DescendedFrom → descendant`) — and one `EreshkigalLineageGraphEdge` per
relation (`:796`) carrying a `walkablePathRef` so the world server can render
the edge as a _path you can walk between memorial actors_. The graph is
**read-only world dressing**: a projection of lineage, never a simulation. The
test (`index.spec.ts:354`) builds a four-node, three-edge graph (elder Abeni
plus a mentee, a raised child, and a descendant) and asserts every edge yields a
`walkable-lineage-path:` ref. The hub's vision of a Postgres-backed,
acyclicity-guarded `ori_lineage_edge` table is the persistence target _behind_
this; the library supplies the in-memory graph the Grove renders.

### Cultural inheritance — value and story propagation

The richest part of legacy is **inheritance**: an elder's values and stories
pass to those it shaped. `evaluateAncestorGrove` selects the relations of type
`Mentored` and, for each, emits an `EreshkigalLineagePropagationOriWrite`
(`buildLineagePropagationOriWrite`, `:826`). That envelope tells the Ori service
to append two events — `MemoryFormed` and `ValueShifted` — into the _mentee's_
log, carrying the elder's deduplicated `propagatedValueRefs` and
`propagatedStoryRefs`. So a mentee literally forms a memory of, and shifts its
values toward, the elder who taught it; raised and descended relations get the
edge but not the value push, matching the design that mentorship is the active
transmission channel. The test (`index.spec.ts:462`) confirms exactly one
propagation write — to the mentee, not the raised child or descendant — carrying
the elder's three values and two stories. This is the architectural basis for
the product's "richer starting culture": the [hub](../V6_ARCHITECTURE.md)
describes the Ninhursag foundry reading inbound lineage edges to seed a newborn
from a _weighted blend_ of its elders' value-imprints; that blend logic lives at
the birth foundry, while Ereshkigal supplies the edges and the propagation
writes that make the inheritance real.

### Grief that is genuinely felt

When an agent dies, the agents who knew it **mourn**, and the mourning is
written into their biographies. `buildGriefOriWrite` (`:710`) produces, for each
living relation, a `RelationshipChanged` event of `relationshipType: 'grief'`
whose `griefWeight` is the relation's `edgeStrength` (clamped 0–100) — so a
close student grieves harder than a passing acquaintance. These grief writes
append to the survivors' own logs, where, per the
[Ori model](./ori-biography-service.md), they decay only through the survivor's
own reflection — there is no erase button on grief, only the slow work of
letting go through `Reflected` beats. The minor test proves the inverse
invariant just as strongly: a blocked death emits **zero** grief writes, because
no one should be made to mourn a death that never happened.

### The Yemaya memorial render

The keepsake a player keeps is produced by **Yemaya**, the non-real-time media
service, exactly as [Clio](./clio-story-engine.md) delegates Chronicle reels.
`buildYemayaRemembrance` (`:731`) builds the `memorial.render.requested` job
envelope: `service: 'Yemaya'`, `status: 'queued'`, an **`idempotencyKey` equal
to the `deathRef`**, and a fixed three-stage pipeline — `book-of-ori-keepsake`
(Clio's long-form biography typeset as a print edition), `memorial-reel` (a
Sequencer cinematic of the highest-significance beats), and
`grove-memorial-placement` (a permanent memorial actor in the walkable Grove).
Keying idempotency on the terminal event id is what makes the render
_resilient_: a Yemaya outage delays the keepsake but never blocks the
transition, and a retried render reproduces the same artifact. The transition
completes the instant the Ori event is appended; the memorial follows
asynchronously.

## Edge cases and invariants

Several invariants hold across every path and are worth stating as the contract
this library guarantees its callers.

- **No deletion, anywhere.** `buildOriContinuity` (`:890`) hard-codes
  `persisted: true` and `deletionScheduled: false` on _every_ outcome —
  departed, transcended, died, retained, blocked. The library has no expressible
  "delete an Ori" result.
- **Side effects are ordered behind their gates.** Death checks minor-protection
  _before_ cause, and cause _before_ any grief/freeze/render. A blocked death
  (`blockedDeathReport`, `:677`) returns `oriFrozen: false`,
  `acceptedFutureEventKinds: []`, empty grief writes, and a null remembrance —
  no partial side effects leak past a closed gate.
- **Lineage is never mutated by an ending.** Death sets
  `lineageMutation: 'none'`; departure and transcendence touch no edges. A
  deceased elder keeps its raised-by and mentored edges to the agents alive
  today, so the family tree is stable across deaths.
- **A frozen Ori is still fully readable.** Freezing stops the _life_, not the
  _record_: Clio's Book of the Ori, the lineage graph, and the audit trail all
  continue to resolve against a frozen log, which accepts only
  `memorial-annotation` additions.
- **Determinism, by construction.** Every minted identifier — `wildAgentRef`,
  `elderRef`, `deathRef`, `memorialRef`, node/edge/path refs — is built from a
  stable **FNV-1a hash** (`hashStable`, `:931`, offset `0x811c9dc5`, prime
  `0x01000193`) over its inputs plus a `slugSegment` (`:940`). The same inputs
  always yield the same refs, which is what makes the whole endings pipeline
  replayable and auditable, and what lets the Yemaya idempotency key actually
  deduplicate.

Taken together, Ereshkigal is the closing foundry the product promise needs:
endings that are real but never destructive, an inheritance that genuinely
passes an agent's character to those it shaped, grief that is felt rather than
announced, and a memorial the steward keeps. The decision logic is real, gated,
and tested against known-correct values; the enactment — appending the events,
emitting the render, persisting the lineage table — is the honest seam handed to
the [Ori service](./ori-biography-service.md), [Clio](./clio-story-engine.md),
Yemaya, and the [hub](../V6_ARCHITECTURE.md)'s wider architecture. A steward's
true long-game achievement, as the features brief puts it, is not a full roster
— it is a Grove full of agents who lived well, and a lineage that carries their
example forward.
