Ghostlight/docs/architecture/ghostlight-library-extraction.md
Meta Vens d86ed9f4a2 Close L0: postmortem, ledger, target and state reconciled
The kernel extraction is finished. The world kernel is the ghostlight
library crate; Dungeon consumes it across a boundary sealed by admission,
proven from outside the crate.

The cut map records the last two fix batches and Q1-10, defaulted: the
minter scanner stays a tripwire, with Clippy recorded as the fix. The
subtraction ledger missed its estimate, +210 net source lines against about
+65. The reasons: the scanner grew chasing evasions, the boundary needed
about 90 more public items than planned, and the rejection tests buy a
ruling made after the estimate.

The postmortem lists what Soul caught, the operator corrections, the
incidents, and the open follow-ups. The target states which invariants
hold and how. The plan, map.yaml and the handoff point at L1. The L0
evidence record is rewritten as its distilled lessons; the previous text is
archived.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 12:24:49 +02:00

4.5 KiB
Raw Blame History

Ghostlight library extraction (plan step 15, L0)

Status: closed 2026-09-16. Landed in Ghostlight 108b691..ab95d78 and gamecult-ops 6aba281..803f2c7; the means and every Soul verdict are in ghostlight-library-extraction-cut.md, the scars in ghostlight-library-extraction-postmortem.md.

Reconciled with the Body. Invariant 1 holds as restated by Q1-9 and is proven by crates/ghostlight/tests/external_admission.rs; the compile_fail doc-tests prove "does not compile", not privacy, because stable rustc does not enforce their error codes. Invariants 2, 4, 6 and 7 hold as written. Invariant 3 holds for library source and tests: no Eve, Heimdall, AppSession or player vocabulary remains. Invariant 5 holds on Windows; the Linux release is unexercised until Idunn builds it. The open questions below were all ruled (Q1-1 through Q1-10 in the cut map) and are kept as history.

Target

The Ghostlight library is a crate of its own. It owns the world kernel and everything consumer-neutral around it: the ontology and reducer, the journal, the mailbox, controllers and the Projector-Persona-Interpreter membrane, elaboration and seeding, the cover, the clock, inference ports, evidence sources, and consumer patch admission. Ghostlight Dungeon is a crate that consumes it: the daemon binary, HTTP routes, Eve projection, Heimdall and app sessions, CultMesh publication, and Idunn health.

After the cut, "Dungeon cannot reach kernel internals" is a compile error, not a pub(crate) convention.

Invariants that must survive

  1. Sealed kernel at the crate boundary. The library's public API exposes create/open, immutable snapshots, command submission, typed receipts, and the runner and port entry points Dungeon needs. It exposes no mutable WorldState, canonical ID allocator, reducer entry, journal writer, or authenticated-caller constructor. Negative proofs are compile-fail tests from outside the library.

    Sealing means unforgeable admission, not unconstructible values (operator ruling Q1-9, 2026-09-16). Public ID types, ScopeDigest and DecisionOpportunity derive Deserialize because Dungeon's own Eve payloads carry them, so any caller can build a syntactically valid one. The kernel must reject every one it did not issue, and rejection tests written from outside the crate are the proof. A compile-fail test pins a path name and cannot see constructibility: adding a Default impl that mints an ID left all ten green.

  2. No behavior change. Every existing test passes unchanged in meaning. No schema string, command id namespace, digest preimage, or store layout changes: a world.cc and controller work store written before the cut open and replay after it.

  3. No Dungeon concept in the library. No Dungeon type, route, Eve or Heimdall type, HTTP framework, or principal format enters the library. The principal evidence the kernel needs crosses as a library-owned type that Dungeon constructs from its own sessions.

  4. Dependencies follow ownership. The library does not depend on axum, tower-http, jsonwebtoken, or the Heimdall and Eve surfaces. Dungeon depends on the library, never the reverse.

  5. The release path keeps working. The ghostlight-dungeon binary name, its --state-root contract, and the Idunn recipe's build and test invocations still resolve, or are updated in the same cut with their owners.

  6. Existing pins are unaffected. Epiphany's pin of ghostlight-persona-projection by revision still resolves.

  7. Build fan-out stays bounded. One new library crate, no new binary, no new feature matrix beyond what test support strictly needs.

Out of scope

  • Every library capability of plan step 15 L1–L4: lenses, detail rules, evidence binding, Draft sessions. L0 moves code; it adds no behavior.
  • Renaming schemas, stores, or wire documents.
  • Changing how external consumers reach the library over the network. The consumer patch HTTP route stays in Dungeon for now.
  • Deployment cutover (the deployment gate).

Open questions for Imagination to bring back

  • The library crate's name.
  • Whether vault.rs (markdown evidence source) and sdk_inference.rs (Claude SDK port) belong in the library, as consumer-neutral adapters, or in Dungeon.
  • The seam for principal evidence (app_session::VerifiedPrincipalEvidence).
  • How test fixtures that span the boundary are shared without making sealed constructors public.
  • Whether ghostlight-persona-projection stays a separate crate or folds into the library.