# Chapter: Covenants

---
title: "Covenants"
plain_name: "Design rules index"
original: https://hexanomicon.dev/adr/
guide: https://lychd.snayu.ai/docs/adr/
---

# Covenants (Design rules index)

## Plain-English summary (Snayu)

**What it is:** The index of LychD's 43 numbered design rules (Architecture Decision Records, called Covenants), grouped by area: foundation, core runtime, agents and memory, and senses and networking. Each rule records a decision, its constraints and consequences.

**Why it matters:** Start here to find which design rule owns a question before you change architecture, or to check what a change must preserve.

- A design rule says what was decided; it does not prove the feature is built. Check What Actually Works (State of Work) for that.
- The list is closed at 42: amend the smallest existing rule instead of adding a new number.
- Every change keeps three things in step: the rule (law), the how-to page (operation) and the evidence (source, tests, receipts).

## Original text (Hexanomicon)

> _The Word binds what the Will would raise._

A Covenant explains an architectural choice and what a future change must preserve. Each
numbered record gives the decision, the constraints that shaped it, and its consequences.
Read the current text for current law; version history preserves earlier rulings.

For a first reading, follow [Doctrine](01-doctrine.md), then the question that brought you here.
For an operating procedure, enter the [Sepulcher](../sepulcher/index.md). For an implementation
claim, consult [State of Work](../state-of-the-work.md): a decision can govern a body part long
before that part can be used.

## The Return from Myth to Law

The Great Work gives architecture its constitutional pressure. To act on that pressure,
engineering needs invariants it can implement, test, refuse, and repair. The table traces that
return from myth to law; the images themselves supply no technical proof:

| Constitutional pressure | Engineering return | Owning Covenants |
| --- | --- | --- |
| A boundary creates perspective without claiming the whole | explicit scope, isolation, and least authority | [Security](09-security.md), [Layout](13-layout.md), [IAM](38-iam.md) |
| A name makes an act answerable | stable identity, attribution, and consequence | [Graph](24-graph.md), [Identity](32-identity.md) |
| Memory must remain corrigible | provenance, retention, correction, and recovery | [Persistence](06-persistence.md), [Memory](27-memory.md) |
| Imagination cannot write reality by itself | isolated simulation and an explicit promotion gate | [HitL](25-hitl.md), [Simulation](31-simulation.md) |
| Another center remains real | consent, refusal, revocation, and bounded delegation | [HitL](25-hitl.md), [IAM](38-iam.md), [A2A](26-a2a.md) |
| Coherence must not require one planetary throne | operator-controlled runtimes, node-local refusal, and bounded federation | [Containers](08-containers.md), [Orchestrator](23-orchestrator.md), [A2A](26-a2a.md), [Multinode](42-multinode.md) |
| A changed form does not erase its source | privacy lineage, local transformation, and exact declassification | [Security](09-security.md), [Persistence](06-persistence.md), [Context](21-context.md) |
| Power must meet consequence | correlated evidence and adversarial evaluation | [Observability](29-observability.md), [Evaluation](34-evaluation.md) |
| Repair may change the vessel | versioned creation, rollback, evolution, and promotion | [SDLC](16-sdlc.md), [Evolution](18-evolution.md), [Assimilation](35-assimilation.md) |

The full cosmology lives in [Transcendence](../divination/transcendence/index.md). A Covenant may
name the telos it serves, but its decision must stand on technical requirements and consequences.

## Foundation and Governance

| Question | Covenant |
| --- | --- |
| Which reciprocal boundary and contribution terms govern covered code and separate work? | [00 — License](00-license.md) |
| How do lore, evidence, code, and the current documentation topology govern one another? | [01 — Philosophy](01-doctrine.md) |
| Which historical stack and register discipline formed the Hexanomicon? | [02 — Documentation](02-documentation.md) |
| Which tools and gates define repository quality? | [03 — Quality](03-quality.md) |
| Which tests prove which kinds of behavior? | [04 — Testing](04-testing.md) |
| How may native and external organs extend the body? | [05 — Extensions](05-extensions.md) |

## Body, Host, and Runtime

| Question | Covenant |
| --- | --- |
| Where does committed state live? | [06 — Persistence](06-persistence.md) |
| What must a recoverable snapshot bind together? | [07 — Snapshots](07-snapshots.md) |
| How are rootless service bodies manifested? | [08 — Containers](08-containers.md) |
| Which trust boundaries protect the host, data, and network? | [09 — Security](09-security.md) |
| How are privileged effects proposed, authorized, and recovered? | [10 — Privilege](10-privilege.md) |
| Which application architecture governs the Vessel? | [11 — Backend](11-backend.md) |
| How are Settings and Runes loaded, composed, and validated? | [12 — Configuration](12-configuration.md) |
| Which paths does LychD own, preserve, or refuse to delete? | [13 — Layout](13-layout.md) |
| How are durable jobs executed and recovered? | [14 — Workers](14-workers.md) |
| Which browser architecture and transport boundary govern the Altar? | [15 — Frontend](15-frontend.md) |
| How does a software change move from intent through verified delivery and subsequent revision? | [16 — SDLC](16-sdlc.md) |
| How are source, packages, images, and receipts bound into a release? | [17 — Packaging](17-packaging.md) |
| How may the body alter itself without severing recovery? | [18 — Evolution](18-evolution.md) |
| Which command grammar and destructive safeguards govern the Pulse? | [19 — CLI](19-cli.md) |

## Agency, Memory, and Consequence

| Question | Covenant |
| --- | --- |
| What is an Agent and how is its capability assembled? | [20 — Agents](20-agents.md) |
| How is bounded Context assembled and governed? | [21 — Context](21-context.md) |
| How are capability demand, state, and grants resolved? | [22 — Dispatcher](22-dispatcher.md) |
| How are physical readiness and scarce resources converged? | [23 — Orchestrator](23-orchestrator.md) |
| How do graphs checkpoint, pause, resume, and delegate? | [24 — Graph](24-graph.md) |
| How does human consent survive pause and re-admission? | [25 — HitL](25-hitl.md) |
| How may sovereign Liches address one another? | [26 — A2A](26-a2a.md) |
| How are Seeds admitted, retrieved, corrected, and reanimated? | [27 — Memory](27-memory.md) |
| Who owns an application, its exact score, casting, coordination, and protected authorship? | [28 — Workflow](28-workflow.md) |
| Which evidence makes an execution legible without granting authority? | [29 — Observability](29-observability.md) |
| How are search, fetch, render, and extraction effects contained? | [30 — Webcrawler](30-webcrawler.md) |
| How are speculative worlds isolated, judged, and promoted? | [31 — Simulation](31-simulation.md) |
| How are Persona, Sigil, attribution, and revision bound? | [32 — Identity](32-identity.md) |
| How are training corpora admitted and resulting weights promoted? | [33 — Training](33-training.md) |
| How are capabilities tried, calibrated, and compared? | [34 — Evaluation](34-evaluation.md) |
| How does foreign craft pass through Lab, test, and promotion? | [35 — Assimilation](35-assimilation.md) |

## Senses, Network, and Federation

| Question | Covenant |
| --- | --- |
| How are visual artifacts transformed with provenance intact? | [36 — Vision](36-vision.md) |
| How are speech and audio transported, retained, and interrupted? | [37 — Audio](37-audio.md) |
| How do Sigils, roles, grants, and revocation enforce identity? | [38 — IAM](38-iam.md) |
| How does the Tether admit remote peers and routes? | [39 — VPN](39-vpn.md) |
| How does the Veil terminate transport without becoming application authority? | [40 — Proxy](40-proxy.md) |
| How are paid effects reserved, signed, committed, and reconciled? | [41 — Toll](41-x402.md) |
| How may many physical nodes serve one sovereign control plane? | [42 — Multinode](42-multinode.md) |

## Changing a Covenant

The numbered Covenant register ends at **42** and is closed. Find the smallest existing Covenant
that owns a new architectural decision, then amend or rewrite it. Do not add another Covenant
number. When a decision is reversed, version history keeps the displaced law legible.

Every change preserves three seams:

1. **Law:** the Covenant states the decision and its invariants.
2. **Operation:** the owning Sepulcher, Altar, or Composition page shows how that law is used.
3. **Evidence:** State and its linked source, tests, lockfiles, or receipts show what has entered
   matter.

Authoring mechanics and verification commands belong in
[CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md#implementation-conventions).

---
title: "0. License"
plain_name: "Design rule 00: The license"
section: "Covenants"
original: https://hexanomicon.dev/adr/00-license/
guide: https://lychd.snayu.ai/docs/adr/00-license/
---

# 0. License (Design rule 00: The license)

## Plain-English summary (Snayu)

**What it is:** Explains why LychD uses the MPL-2.0 license (the Iron Pact): changes you distribute to core files must stay open, while separate files you add can carry their own terms.

**Why it matters:** Read this before shipping modified LychD code or building private add-ons, so you know what must be published and what can stay private.

- If you distribute modified core files, their source must be made available to recipients under MPL-2.0.
- Separate, non-covered files can use other terms; private or in-company use requires no publication.
- Contributions come in and go out under the same MPL-2.0 terms; the repository LICENSE file is the binding text.

## Original text (Hexanomicon)

## Context

An operator must be able to compose private organs around LychD while sharing distributed
changes to its covered core. MPL-2.0 supplies that file-level boundary. This Covenant calls it
**the Iron Pact** and explains the choice; the binding text remains the repository
[LICENSE](https://github.com/hexanomicon/lychd/blob/main/LICENSE), which this ADR does not amend.

## Requirements

- Distributed modifications to covered core files remain open to their recipients.
- Separate, non-covered files can carry their own terms; private use, including intra-organization
  use, does not require publication.
- The project uses an OSI-approved license, and contributions enter and leave on the same terms.
- MPL's Secondary License compatibility remains available unless a later Covenant changes that
  choice.

## Options

| License family | Pressure that ruled it out |
| --- | --- |
| MIT / Apache-2.0 | Broad reuse, but a distributor may close modifications to the core itself. |
| AGPL-3.0 | Its network trigger is broader than the desired boundary for private and local composition. |
| LGPL-3.0 | Tuned to a library boundary, not this daemon and composed runtime. |
| BSL / SSPL / FSL | Use restrictions or non-OSI status conflict with the intended pact. |
| Unlicense / WTFPL | No chosen reciprocity, patent, or distribution terms. |
| MPL-2.0 | File-level reciprocity permits a Larger Work of genuinely separate files. |

## Decision

LychD is licensed under MPL-2.0.

The boundary follows covered source files. Distributed Source Code Form containing Covered
Software, including a Modification, stays MPL-2.0. When an executable contains Covered Software,
its distributor must make the corresponding Source Code Form available as the license requires.
A Larger Work can still contain separate files under different terms: a new file containing no
covered code does not become a Modification merely by being compiled or bundled with the work.

Private use and modification require no publication. Network serving alone is not distribution
of server code, although client code actually delivered raises its own distribution question.
Local sovereignty also needs architectural support: local-first operation, portable custody, and
replaceable composition must make the legal freedom usable.

## The boundary of the Pact

The project may use mythic names for ownership, but MPL follows covered source—not anatomy.

| Material | Result |
| --- | --- |
| LychD source containing covered code | MPL-2.0 governs it. |
| A modified covered file, when distributed | Its modification is MPL-2.0 to recipients. |
| Separate extension with no covered code | It may use other terms. |
| File copying or incorporating covered code | It is a Modification regardless of name or directory. |
| Phylactery data, secrets, configuration, prompts, and model artifacts containing no code | Not covered merely because LychD stores or processes them. |
| A2A or REST peer | Protocol use alone neither copies nor distributes covered server source. |

Independent implementations of an architecture or protocol remain possible because MPL does
not make abstract ideas proprietary. Copying covered expression is a different act, governed by
the license. Calling copied core code an Extension does not change that boundary.

## Contribution terms

Contributions are inbound under MPL-2.0 and distributed outbound under MPL-2.0. There is no CLA,
no relicensing grant, and presently no DCO or required `Signed-off-by` trailer. Any future DCO
must add its certification, instructions, and enforcement together.

The repository does not use MPL Exhibit B. Secondary License compatibility is therefore available
under MPL section 3.3 unless a later Covenant deliberately changes that position.

## Consequences

The Iron Pact keeps distributed changes to covered files open while leaving separate code and
private material to their proper owners. To resist cloud capture, LychD must also provide a body
that can run locally, preserve its state, expose provenance, and be left. The license cannot do
that architectural work alone.

---
title: "1. Philosophy"
plain_name: "Design rule 01: Development philosophy"
section: "Covenants"
original: https://hexanomicon.dev/adr/01-doctrine/
guide: https://lychd.snayu.ai/docs/adr/01-doctrine/
---

# 1. Philosophy (Design rule 01: Development philosophy)

## Plain-English summary (Snayu)

**What it is:** Sets out how LychD is built: Docs-First Development (xDDD), where the written spec comes first, then the domain model, tests, code and observed results. It also explains how the fantasy names relate to real engineering.

**Why it matters:** Read this to understand why docs lead code in this project and where each kind of truth (design, how-to, evidence) is supposed to live.

- Order of work: write the intent, derive the domain, prove the contract with tests, write code, report what actually happened.
- Lore names are memory aids only; they must never hide a command, schema, log or recovery step.
- Each fact has one home: design rules hold decisions, guides hold operation, State of Work holds implementation evidence.

## Original text (Hexanomicon)

## Context

Reject the dogma and instead forge a middle path — one that respects the narrative density of
**Lore** while demanding the rigorous purity of **Code**.

LychD gives lore and engineering distinct work. Lore carries the telos of a bounded, relational
intelligence: answerable to consequence, capable of memory and repair, and unwilling to mistake
power for totality. Engineering must make that purpose exact enough to build and judge.
Architecture, implementation, delivery, and evidence therefore remain distinct kinds of truth;
neither lore nor engineering can stand in for the other.

Names such as Phylactery, Vessel, and Invocation offer cognitive cartography: they help a reader
remember jurisdiction. Their usefulness ends where they obscure a command, schema, log, recovery
step, or contract. The same test applies to method. Methodologies are **tools, not chains**;
the workflow imports only what it needs.

## Decision

LychD adopts **eXtreme Documentation Driven Development (xDDD)**:

> establish the Logos → derive the domain → prove the contract → manifest code → return observed consequence.

Exploration may precede a stable test. Completion requires executable behavior, architectural law,
the public delivery boundary, and routes into that truth to agree.

xDDD distills these practices, utilizing AI to dial the knobs to **11**.

### 1. eXtreme Programming (XP)

!!! success "Simplicity"
    **Simplicity is brilliance — Open for Grandeur, Closed for Stability.** Avoid over-engineering;
    extend where a concrete requirement calls for it.

!!! success "Courage"
    **The `'del'ete` Spell.** Reject the Sunk Cost Fallacy and do not be afraid to change course.

!!! success "Respect"
    **There is one obvious way to do it.** Frameworks are followed, not fought.

The Navigator may be an LLM. Close feedback and engineering judgment still govern the work.

**Abstract Spec is written first.** The vision must be solidified in text to guide the summoning.
**Code is the Documentation** regarding implementation details. Low-level mechanics are not
duplicated in the prose.

> _Travel light, but prepared._

### 2. Domain-Driven Design (DDD)

Software structure reflects the Vision. Lore (Map) and Code (Territory) remain distinct, with
their shared vocabulary kept in the [Lexicon](../lexicon/index.md).

**Domain Isolation:** Separation of concerns is mandatory. The Domain is isolated from the
Infrastructure. Bounded domains keep ownership clear and separate intent from effects.

Lore is welcome in documentation, docstrings, and CLI messages where it helps understanding.
Commands, schemas, operational logs, and low-level contracts must stay exact. A metaphor earns its
place by making the boundary easier to see.

### 3. Test-Driven Development (TDD)

Tests turn intent into executable examples and regression checks, binding the manifestation to
what it was meant to do. Their value lies in that feedback; blind adherence to an order of
operations does not establish correctness.

**Strict Test First** can stifle exploration. Prototyping is encouraged, provided tests are
backfilled before the final commit. Test order cannot substitute for judgment.

### 4. Readme/Specification-Driven Development (RDD/SDD)

Write the user-visible contract before committing to its implementation. This ensures the right
thing is being built before the thing is built right.

Documentation deals in abstract ideas and interfaces, avoiding redundant repetition of code logic.

### 5. Agile Methodology

Rapid iteration and adaptation are prioritized. Change is not feared. TDD loops and prototyping
keep feedback close to the work.

**The Ritual (Scrum/Sprints):** Artificial time-boxes are viewed as fractures in the vision.
**Flow is prioritized over sprinting.**

### 6. Waterfall Model

Adopt Waterfall's demand for foresight. Writing the **Prophecy (Documentation)** before code
exposes architectural mistakes while they are still cheap to change. Deliberate before an
irreversible act, and revise the plan when implementation contradicts it.

## Constitutional telos

“Plain truth opens the door. The symbol opens the cosmos. The cosmos returns to the next exact act.”

LychD is the software body. The Lich is the recurrent whole: Vessel, Phylactery, identity,
orchestration, action, consequence, memory, repair, and relation. A model is one organ.

Myth establishes its own register. When it returns to engineering, it returns as an invariant that
can be implemented, observed, refused, or repaired. The [Covenant registry](./index.md#the-return-from-myth-to-law)
maps constitutional meaning into its technical owners.

## Documentation Topology

This section owns current placement. ADR 02 preserves the historical choice of documentation stack
and registers; it does not compete for topology law.

| Repository door | Office |
| --- | --- |
| `README.md` | Public foyer: maturity and next act. |
| `CONTRIBUTING.md` | Setup, commands, rules, and conventions. |
| `AGENTS.md` | Stable agent entry and progressive router. |
| `ROADMAP.md` | Short entry to the owning public roadmap. |

| Published surface | Office |
| --- | --- |
| `docs/index.md` | Prophecy and reader paths. |
| `docs/adr/**` | Architectural law. |
| State of Work | Shared whole-system delivery boundary and evidence envelope. |
| `docs/roadmap.md` | Public direction, founding-year story and orienting weekly horizon. |
| Lexicon | Canonical meanings. |
| Compositions | Native reference reusable application contracts, Product boundaries, and worked examples; local delivery notes only where needed for interpretation. |
| Sepulcher | Anatomy, operation, and recovery. |
| Divination / Altar | Meeting the running body. |
| Transcendence | The Great Work and constitutional meaning. |
| Summoning | First-life operation. |
| Directory indexes | Maps to their smallest useful owner. |

Tracked `.agents/scopes/**` cards route agents but own no truth. Tracked `.agents/workflows/**`
playbooks preserve procedure, load after scope, and yield to canonical owners.

### Router delegation

A router helps the reader choose the next useful edge. It gives task triggers and explicit
links, and identifies each destination as a scope branch, canonical owner, or workflow playbook.
That role tells the reader whether to continue discovery, establish truth, or load procedure.
When the destination is another router, it owns the deeper routes; the parent keeps the branch
discoverable without copying its contents.

Follow only the branches required by the task. Cross-domain links make another scope tree
reachable without requiring its wholesale ingestion. Workflows load after the matching scope.
Routing grants no new authority, launches no work, and does not itself assemble a fresh Context.
[Discovery in Spellweaver](../sepulcher/extensions/weaver/discovery.md) shows the passage from
scope discovery to workflow selection and a bounded task handoff.

### One home per truth

| Truth | Owner |
| --- | --- |
| Architecture | Covenant |
| Delivery | State of Work |
| Direction and founding-year story | Roadmap |
| Terms | Lexicon |
| Operation and recovery | Sepulcher or Altar topic |
| Application contract | Composition |
| Constitution | Transcendence |
| Routing / choreography | Scope / workflow |

Begin at the fitting door, follow parent indexes as maps, and read the smallest owner. Other
pages may summarize that owner's truth once and link to it. An executable claim must eventually
reach source, tests, lockfiles, artifacts, or maintained receipts. Scratch notes, searches, and
generated indexes can help discovery, but own no truth.

Architecture and application pages explain a coherent system through its responsibilities,
records, handoffs, decisions, and recovery. State these contracts directly, without maturity
badges or `Designed` suffixes on headings. State of Work gathers the implementation evidence and
missing pieces. A local limitation belongs on the contract page only when it changes an operation
the reader can perform, an exact compatibility boundary, or the reading of a worked example.
Explain that concrete limit and link its evidence instead of repeating a delivery category.

## Repository Source Topology

The repository contains one authoritative LychD system and separately tooled delivery clients.
`src/lychd/**` is the Python distribution and domain source. Native first-party Composition truth
enters `src/lychd/compositions/<identity>/**`; a Portfolio page alone remains design, not delivery.

A delivery client keeps its complete project root under `clients/<target>/**`. It may own presentation,
platform integration, connection mechanics, and bounded local interaction state, but its separate
toolchain does not grant it Composition records, policy, effect authority, or finish judgment. The
web project lives at `clients/web/**`; the Android project lives at `clients/android/**`.
Each project keeps the source layout native to its toolchain. The current web source lives at
`clients/web/src/**`; the Android application module uses
`clients/android/app/src/main/**`. Repeated inner `src` names express separate build ownership
rather than one mixed repository source tree.

## Consequences

!!! quote "The Final Truth"
    When matter contradicts the Word, repair the one that lied.

**The Path Remains Local.**

The method is not the magic. The ultimate goal is the fulfillment of the
[Prophecy](../index.md), not religious adherence to this document.

Lore can remain vivid without pretending to prove a feature, and engineering can remain exact
without abandoning constitutional purpose. A change that alters several kinds of truth may require
several owners to change.

> Use the ritual to manifest the Vision. If the rules bind, **break them.**

---
title: "2. Documentation"
plain_name: "Design rule 02: Documentation tooling"
section: "Covenants"
original: https://hexanomicon.dev/adr/02-documentation/
guide: https://lychd.snayu.ai/docs/adr/02-documentation/
---

# 2. Documentation (Design rule 02: Documentation tooling)

## Plain-English summary (Snayu)

**What it is:** A historical record of why the official docs are plain Markdown built with Zensical and kept in the same repository as the code, and how different kinds of writing (rules, guides, lore) are kept apart.

**Why it matters:** Read this if you edit the official docs and want to know why they are structured and written the way they are.

- Docs live beside the code and are versioned and reviewed together with it.
- Markdown was chosen over Sphinx, wikis or external documents because humans and coding agents can read it easily.
- Current placement rules live in design rule 01 and CONTRIBUTING; this page is the original decision record.

## Original text (Hexanomicon)

## Historical record

This Covenant records the decision to select the Markdown/Zensical Hexanomicon and its register
discipline. For current placement rules, follow
[ADR 01](./01-doctrine.md#documentation-topology); for authoring and verification, use
[CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md).

## Context and requirements

The Hexanomicon must remain versioned beside the body it describes so that readers can review
the two together. Its Markdown source must be plain enough for humans and coding agents to read,
while the rendered work stays accessible, visually its own, and quick to preview. Within that
shared medium, law, operation, threshold, and myth retain their distinct burdens.

## Options

| Option | Decision pressure |
| --- | --- |
| Sphinx / reStructuredText | Strong reference tooling, but heavier syntax and a poorer fit for this grimoire. |
| Hosted wiki | Convenient editing, but detached from repository history and review. |
| External documents | Useful exploration, not canonical law. |
| Zensical | Markdown-native, versioned locally, fast to preview, and visually capable. |

## Decision and invariants

Zensical renders `docs/`. `zensical.toml` owns extensions, theme, and deploy metadata. Native
Awesome Nav reads the top-level order from `docs/.nav.yml` and each section's navigation from
its own `.nav.yml`; navigation stays beside the content it arranges.
`docs/overrides/stylesheets/hexanomicon.css` supplies the visual layer. Admonitions, details,
snippets, and Mermaid are used when they clarify. Snippets stay short and use repository-root paths.

| Register | Surface and burden |
| --- | --- |
| Law | Covenants and accepted Compositions: exact decisions, invariants, failure, recovery, compatibility, consequence. |
| Iron | Commands, config, troubleshooting, recovery: literal, copyable, observable, recoverable. |
| Threshold | README, Prophecy, Map, State, indexes: lucid enchantment followed by a next act. |
| Operated doctrine | Sepulcher and Altar: anatomy joined to concrete ownership and use. |
| Great Work | Transcendence: full mythic voltage, formative movement, correspondence, and vow. |

A page's placement establishes its register. Myth can speak fully where it belongs; technical
pages must support their mechanisms without borrowing scientific or mystical certainty.
Likewise, publication in the Portfolio accepts a Native Reference Composition and its application
contract, but does not prove executable delivery. State of Work holds the shared whole-system
evidence envelope. A leaf needs a local delivery note only when that limit materially changes
how its contract should be read.

## Progressive revelation

1. Give the first viewport purpose and voice.
2. Put vocabulary beside the thing; the Lexicon is reference, not initiation.
3. Give each page one office.
4. Prefer one image to repeated representations.
5. Link rather than recap an owner's deep truth.
6. Keep useful etymology and correspondence visible.
7. Make new terms earn a stable distinction.

## ADR presentation

An ADR normally leads from context and pressure through requirements and alternatives to a decision and
its invariants. It then explains failure, recovery, compatibility, and consequence. Live
implementation stays in source. When a short snippet helps, name its repository-root path and
link explicitly to the source; use a stable named section only where the source accepts it.
Page view/edit actions do not establish an included target. Links carry readers across register
seams, and the current [Covenant registry](./index.md) routes architectural questions.

## Consequences

The historical decision supports a distinctive, reviewable manual without merging every register
into one voice. It does not authorize deep operational duplication: authoring remains in
[CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md), and current
topology remains ADR 01.

---
title: "3. Quality"
plain_name: "Design rule 03: Code quality tools"
section: "Covenants"
original: https://hexanomicon.dev/adr/03-quality/
guide: https://lychd.snayu.ai/docs/adr/03-quality/
---

# 3. Quality (Design rule 03: Code quality tools)

## Plain-English summary (Snayu)

**What it is:** Fixes the shared Python toolchain - uv for dependencies, Ruff for linting and formatting, BasedPyright for strict type checks and pytest for tests - all run through one Makefile so any failure can be reproduced.

**Why it matters:** Read this before setting up your environment or touching lint, typing or dependency configuration.

- Use uv for dependencies and keep uv.lock committed; Ruff rules and exceptions live in pyproject.toml.
- BasedPyright checks src/lychd in strict mode, the same way locally and in CI.
- The Makefile is the single command entry point; any tool exception must appear in reviewed configuration.

## Original text (Hexanomicon)

A contributor should be able to reproduce a failed check without reconstructing someone else's
workstation. LychD therefore keeps a small, shared toolchain and makes each gate explicit about the
claim it can support.

## Decision Outcome

The Python environment uses **uv**, **Ruff**, **BasedPyright**, and **pytest**. The Makefile gives
contributors and automation one command grammar; [CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md#setup-and-commands)
owns setup and exact command examples.

### The Python Pillars

| Tool | Responsibility |
| --- | --- |
| uv | Resolve dependencies, retain `uv.lock`, and execute tools in the managed environment. |
| Ruff | Lint and format under the deliberate rules and exceptions in `pyproject.toml`. |
| BasedPyright | Check `src/lychd` in strict mode, with the same implementation locally and in CI. |
| pytest | Establish regression evidence within the taxonomy and limits of [Testing](04-testing.md). |

Reproducibility depends on committed configuration as well as tool choice. The selected tools
share that configuration, and dependency changes go through the uv environment; any exception
must appear in reviewed configuration. The older Poetry, mypy, Flake8, and Black/isort stack was a
credible alternative, but divided environment and lint/format responsibility among more
independently configured tools.

### Cross-stack gates

A complete change can cross several evidence boundaries. Keep their results separate:

| Gate | What it establishes |
| --- | --- |
| Python umbrella | Non-mutating lint, format, strict typing, and ordinary tests. Applying formatting requires an explicit command. |
| Disposable PostgreSQL | Explicit database and lifecycle receipts against the selected container profile. |
| Altar check and build | Generated OpenAPI agreement, client checks, and the compiled static projection under `src/lychd/public/`. |
| Companion interaction | Kotlin/JVM compilation and client-local state traces under the pinned Gradle harness; no Android device or native service qualification. |
| Companion Android | Application compilation, lint and ViewModel checks; separate instrumented Activity checks establish behavior only on the selected emulator or device. |
| Documentation build | The published Hexanomicon can be generated from its maintained source and navigation. |

Frontend work has its own gates, as does Android work; neither runs silently under the Python
umbrella. Both frontend gates regenerate the API contract, and the build also updates the tracked
static projection. Review that output with the source that produced it. A generated diff guard
catches disagreement.

Automatic pull-request, `dev` and `main` checks run repository lint, formatting, strict typing and the
explicit core test selection owned by `make test-ci`. That selection uses in-process substitutes
and excludes real host and container qualification. The full four-lane Repository Checks workflow
remains manual while host-runner compatibility is unresolved; changes still require the broader
gates appropriate to their boundary. The Pages workflow separately supplies the clean documentation
gate and deployment artifact on `main`. The tag/manual release-candidate workflow remains separate:
a green core check does not bind release archives or prove installation on a host.

[Frontend](15-frontend.md#decision-lock-and-reopening-gate) owns the exact Node/npm pins and
single client vocabulary. Bun, a second lock/runtime, Tailwind, or another styling compiler must
meet that Covenant's reopening gate before admission. The client currently uses strict
TypeScript, `svelte-check`, and Vitest/jsdom, with native CSS inspected directly. Editor
configuration selects `markdownlint` for Markdown and Red Hat YAML for YAML and Docker Compose.
TOML and JSON have no repository-selected formatter; editor assistance is not another CI receipt.

The Companion client keeps its Gradle wrapper, Kotlin and Android plugins, strict dependency
locks, and artifact verification under the Android client root. JDK 17 runs both the SDK-free
interaction checks and the opt-in application build. The
[client README](https://github.com/hexanomicon/lychd/blob/main/clients/android/README.md) owns exact
setup and commands. Wrapper and dependency changes carry their pins and checksums. A passing
interaction test does not establish device behavior; application and device checks do not establish
native Companion authority or qualify every declared Android version.

## Consequences

A tool or configuration change must carry its lockfile, generated-output, and documentation
consequences with it. Shared gates then make defects reproducible, while each gate's declared
scope keeps a repository pass from becoming an unsupported host or production-browser claim.
[State of Work](../state-of-the-work.md) owns delivery interpretation;
[Packaging](17-packaging.md) owns artifact identity and promotion boundaries.

---
title: "4. Testing"
plain_name: "Design rule 04: Testing approach"
section: "Covenants"
original: https://hexanomicon.dev/adr/04-testing/
guide: https://lychd.snayu.ai/docs/adr/04-testing/
---

# 4. Testing (Design rule 04: Testing approach)

## Plain-English summary (Snayu)

**What it is:** Defines how LychD is tested: pytest with typed fixtures and Polyfactory test data, run inside a dedicated test container, with markers that say what kind of evidence each test provides.

**Why it matters:** Read this before writing or running tests, so you put each test in the right category and run it the supported way.

- All core tests, lint and type checks run in the OCI test image (Containerfile.tests) via the Makefile, never as host pytest.
- Tests run serially by default; bounded pytest-xdist parallelism is opt-in.
- Testing inside the container is not a deployment; proving the installed runtime needs the real built server image.

## Original text (Hexanomicon)

A test is useful when it can fail for a reason the contributor understands. Its setup, assertion,
and execution boundary should make that reason recoverable. LychD chooses ordinary typed fixtures
and explicit evidence classes over a second language for describing behavior.

## Decision Outcome

**pytest** is the primary engine. Its fixtures and parametrization fit the repository more directly
than verbose `unittest` scaffolding or keyword-heavy BDD. **Polyfactory** builds valid Pydantic
models and plain types where fabrication helps; an explicit local factory remains appropriate
when the fixture's meaning is part of the assertion.

### 1. The Engine (Pytest + Xdist)

All Core test, lint, format-check, type and coverage processes run in the explicit OCI image
built from `Containerfile.tests`, selected through the Makefile and `scripts/container_checks.sh`.
The host harness may build and launch that image; it does not execute a host Vessel or fall back
to host pytest when the engine is unavailable. Application construction and ASGI/domain helpers
inside the image are test techniques, not another deployment profile. Installed-runtime
qualification instead needs the actual rebuilt production Vessel image and declared boundary.

Some probes share host-resource boundaries, so tests run serially by default. Callers may select
bounded `pytest-xdist` parallelism. An ordinary invocation gets unique scratch under the
disposable container's `.cache/pytest`, captured logs, and pytest's native compact report without
an output wrapper. Caller-owned scratch and verbose diagnostics require explicit choices;
[CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md#test-selection)
owns the exact switches.

Start with the smallest relevant source boundary. The directory layout makes that selection
visible:

| Directory | Evidence sought |
| --- | --- |
| `tests/unit` | Isolated domain, utility, and adapter contracts. |
| `tests/integration` | The named cross-layer, filesystem, database, or substitute conjunction. |
| `tests/architecture` | Package boundaries, release declarations, public contracts, and documentation topology. |
| `tests/web` | HTTP and browser-projection contracts at their declared server boundary. |

### 2. The Taxonomy (Markers)

Markers use strict `pytest.mark` semantics: `unit` names isolated contracts, `integration` names
joined layers, `container` selects explicit disposable-container receipts, and `slow` marks
expensive work such as heavy model loading. Strictness catches misspelled markers; it does not
populate them. Most present selection follows directories: `unit` and `slow` are unapplied, and
only a few integration tests carry `integration`. Consequently `M=unit` collects nothing today;
select the directory instead.

By default, `make test` and `make check` exclude `container`. An explicit marker expression
replaces that exclusion. `make test-containers` admits that profile with its separate dependencies
and an explicitly admitted Docker daemon socket through the Docker-only PostgreSQL harness. Ordinary checks receive no daemon
socket or network; this separate PostgreSQL harness has its own declared socket/network authority. Host and external
systems stay opt-in and need named receipts. Network and provider dependence enter a deterministic
test only when its declared integration boundary requires them.

### 3. The Fabricator (Polyfactory)

Generated fixture data must remain valid under the actual schema; a factory helps construct it.
The test still needs to show which property matters and satisfy any validator prerequisites.
Keeping those responsibilities visible lets a contributor distinguish a failed fabrication from
failed system behavior.

### 4. The Quality Gate (Coverage)

`pytest-cov` measures branch coverage against the `pyproject.toml` **80%** floor and deliberate
structural exclusions. `make coverage` enforces it serially with the ordinary `not container`
selection. Default tests, the Python umbrella, pull-request checks, and release-candidate CI do
not pass `--cov`. Coverage is an opt-in gate, not an implicitly passed release condition.

Pull-request, `dev` and `main` Core Python CI runs the explicit `make test-ci` selection, using
in-process substitutes inside that OCI image, without a model or daemon socket in the test
process. The outer build/launch still requires a working OCI engine. Full ordinary tests and
disposable PostgreSQL receipts remain separate jobs in the manually dispatched Repository Checks
workflow. A core-CI pass does not establish those broader results or waive affected-boundary
verification. The normal `make test` and `make check` selections remain unchanged.

### 5. Runtime Surface Probes

A repository test establishes its recorded conjunction. Real systemd, Podman, PostgreSQL, GPU,
model, and browser behavior requires the corresponding maintained operator receipt; mocks do not
inherit the authority of the systems they replace. [State of Work](../state-of-the-work.md)
records that distinction. Host-native Core deployments and their test fixtures are retired;
frozen native-profile receipts retain only their dated historical scope and cannot qualify the
current test image or a rebuilt production image.

Altar and GenUI probes may inspect rendered semantic contracts and preserve DOM or screenshot
evidence. A missing prerequisite is `BLOCKED`, not a fabricated behavioral `FAIL`. Server state
remains authoritative, and a rendered success message must not substitute for the effect record.

## Consequences

Keep a failure together with the test that reproduces it. Select directories, marks, and opt-in
boundaries to match the claim, widening the checks when a change crosses those boundaries. An
exception needs its own stated scope and receipt. This gives contributors both a suite they can
reason about and an exact account of what still needs to be witnessed on real iron.

---
title: "5. Extensions"
plain_name: "Design rule 05: Extensions"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/05-extensions/
guide: https://lychd.snayu.ai/docs/adr/05-extensions/
---

# 5. Extensions (Design rule 05: Extensions)

## Plain-English summary (Snayu)

**What it is:** Decides how features plug into LychD: either as trusted in-process Python contributions accepted by a named owner, or as separate external services. Defines the vocabulary of Plug-in Areas (Extension Domains), packages, contributions and providers.

**Why it matters:** Read this before writing an extension or adding a new capability, to choose between in-process code and an external service.

- In-process extensions share the server's memory and can crash it, so only trusted, explicitly selected code gets that path.
- A contribution is a typed addition accepted by one explicit owner (a core office or a Plug-in Area), not free-form app mutation.
- External services give process isolation and their own lifecycle; MPL-2.0 lets private extensions stay private.

**Status:** Partial. Extension activation works; the general service surface and package API are designed only.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    LychD admits native Python where it needs its speed and reach, while keeping authority with
    the explicit Core office or Extension Domain that receives a Contribution. The architecture
    must also leave a real boundary for separate engines, dependencies, images, and lifecycles.
    The operational journey is owned by [the Extensions Sepulcher](../sepulcher/extensions/); this
    leaf states the constitutional boundary.

## Decision Outcome

An extension can join LychD as an admitted, protocol-bound native contribution or as an external
service. Native Python provides direct access where the receiving owner accepts that trust;
external protocols provide isolation or independent deployment where those are required. Making
every extension an external service would impose latency and deployment costs. Sandbox scripting
remains a future containment option, with no second language or runtime promised today.

The Extension Protocol joins local-package admission and external-provider integration without
conflating their trust or lifecycle boundaries. Semantic contract and profile identities remain
separate from their concrete Provider implementations. A future Forge lock lifecycle must pin
foreign source and physical inputs; selected import shims alone are not reproducibility evidence.

An **Extension Domain** is one of the fifteen stable user-facing jurisdictions. An **extension
package** is selected code. A **Contribution** is a typed addition accepted by one explicit
receiving owner, which may be a Core office or an Extension Domain. A **Provider** is a concrete
engine or service behind a typed contract. Domain presence proves neither a package nor delivery;
activation is of a concrete package or declared instance, never an abstract Domain. Compositions
use Domain contracts without becoming their owners. Packages may contribute across several Core
offices and Extension Domains, and one receiving owner may admit many packages or Providers.

A **Registrant** is Core or one explicitly selected extension package performing registration. Its
host-assigned `registrant_id` (`core`, `builtin:<activation-id>`, or
`crypt:<activation-id>`) records registration provenance; it is not Provider identity and never
turns the Registrant into an engine or service Provider.

Do not compress authority owner, package provenance, Contribution kind, Provider or external
attachment, profile, and maturity into one union category. State the exact applicable facets.
Every operational reference resolves to its concrete Core office or Extension Domain,
Contribution, Provider or attachment, profile revision, and Registrant provenance as required by
the contract.

### Vocabulary Boundary: Domain Is Not Package

Core owns schemas, policies, lifecycle, and host effects. A package can add only the explicit
shapes accepted by a receiving owner. Keeping Domain and package separate therefore lets each
contribution state its provenance, trust, evolution, and configuration without making import
location stand in for those decisions.

### 1. The Federation Strategy

The host federates selected in-process Python packages and uses external protocols when needed.
It initializes the extension context once at boot, from configuration, only for selected built-in
and Crypt packages. It discovers neither the environment nor entry points.

Built-ins live under `src/lychd/extensions/builtin/`; Crypt packages are explicitly selected local
`register.py` shims. Installed never means active. The selector is not the future Forge manifest,
which must eventually pin source, dependencies, and physical substrate.

```toml
[extensions]
builtins = []
crypt = ["my-private-organ"]
```

`lychd init` may show commented choices, but the default is inert. A selected package is
imported and calls `register(context)`. Enabling it permits schemas, hydrators, and store
registration; it does not start an instance. Codex receives the resulting schema list, not a
package scan. Built-in dependencies are explicit catalogue edges: selecting a concrete Animator
runtime assembles the shared `animator` base once, under its own provenance, before the runtime.
Crypt activation resolves only that exact `register.py`; it performs no package or entry-point
discovery. The shim is loaded in an injectively named synthetic package so ordinary relative
sibling imports work without making neighboring Crypt packages active.
If import or `register()` fails, the manager removes that synthetic package namespace before
surfacing the error, so a repaired retry cannot inherit half-imported module state.
Activation ids must already be canonical POSIX-relative paths: aliases, traversal, absolute paths,
empty segments, and control characters are refused before import.

#### One process, one extension generation

The selected package set is assembled as one process generation. Registration mutates only a
fresh assembly context; successful assembly seals membership before runtime consumers receive
their projections. LychD does not hot-load, hot-replace, or unload executable extension code
inside a live Vessel. A change to code, dependencies, package selection, or contribution
contracts is an [Evolution](18-evolution.md) of the body: prepare an inactive candidate, settle
admitted work, replace the Vessel generation, and reconstruct volatile state from validated
configuration and durable truth.

Process replacement keeps one executable generation coherent. A fine-grained lifecycle can
reverse registrations and resources only when it mediates them: references, closures, background
tasks, caches, foreign-library state, and already-emitted filesystem, database, or network effects
can escape its ledger. Removing a module therefore cannot prove that old and new memory no longer
coexist. LychD treats process memory as disposable instead of requiring perfect effect capture
throughout the system. Ordinary shutdown must still quiesce owned workers and resources. That
teardown hygiene neither authorizes live code replacement nor proves external effects rolled back.

A future declarative catalogue generation may activate without Vessel replacement only when it
introduces no new executable implementation and its owner supplies atomic durable generation and
pinning semantics. Otherwise activation follows [SDLC](16-sdlc.md),
[Packaging](17-packaging.md), and Evolution into a new process generation.

### 2. The Registration Surface (The Extension Context)

The context has shaped stores for `runes`, `soulstones`, `portals`, `transmutation`, and
`delegated_runtimes`. New contribution kinds need an explicit owner. Patterns, Compositions,
status, routes, tools, workloads, operations, and migrations are not implied merely because a
package registers. A minimal contribution is explicit:

```python
context.runes.add_schema(RuneConfig)
```

The manager owns the root context and passes each Registrant a registrant-bound
`ExtensionRegistrationContext`. User activation IDs remain the Settings and filesystem selectors;
audit provenance uses disjoint trust-domain identities: `core`, `builtin:<activation-id>`, and
`crypt:<activation-id>`. Its shaped store facades capture one fixed `registrant_id` and do not
expose the root provenance mutator; even a retained facade cannot inherit a later Registrant's
identity. Stores retain that provenance, reject another Registrant's replay even when the
Python value is equal, and seal membership after the one assembly pass. `AssembledExtensions`
exposes read projections plus the sealed root context; retained registration methods remain
present for assembly compatibility but reject every post-assembly write. It is not a live registry
that arbitrary runtime code may extend. This seal does not recursively freeze trusted contributed
Python objects; each Contribution contract must provide its own immutability or defensive-copy
boundary.

The v1 Animator catalogue retains these registration records through hydration. Capability
specifications, grants, Orchestrator status, and Nexus response rows carry the host-assigned
`registrant_id` separately from runtime and Provider identity. Adapter-supplied attribution cannot
override it. Direct adapter injection without a registration record remains explicitly
unattributed (`None`); it does not acquire Core provenance. This metadata changes neither the
persisted capability key nor eligibility or effect authority.

The accepted general-service capability surface is Designed and is not present in that context.
It requires separately owned and sealed contribution stores for semantic interface revisions,
immutable profile revisions/digests, Connector dialect-driver revisions, evidence bindings, and
runtime/Portal activation definitions. Registration of one kind grants none of the others:

- an interface defines semantic request/result, operations, typed facets, and failure meaning;
- a profile closes exact model/tool/graph/workflow inputs, licenses, formats, languages, limits,
  resources, and evidence references;
- a dialect driver speaks one exact protocol subset and owns no semantic eligibility;
- an activation definition binds an admitted profile and driver to one Rune schema and lifecycle;
  and
- an evidence binding points to producer-attributed results and an admission decision by the
  target contract owner.

Every registered identity includes a safe stable id plus immutable revision or digest, one
explicit receiving owner, its Contribution kind, and Registrant provenance. A
Provider-facing identity separately pins its concrete Provider. Cross-store references are
resolved and validated as one staged assembly before membership seals. Registering a Rune schema,
Python client, URL, or familiar "OpenAI-compatible" label cannot synthesize any missing
Contribution.

A versioned application deployment profile is another receiving-owner contract, not raw unit text
or authority inherited from a Composition name. The future sealed `deployment_services` surface
may admit exact service-role contributions from Core or an Extension Domain; Containers owns the
`ApplicationDeploymentManifest@1` physical schema and compiler, Configuration owns selection and
generation assembly, and the application profile owns which registered roles its workload needs.
A contribution pins its owner, implementation revision, IPC contract, lifecycle, secret, network,
mount, resource, and recovery requirements. Registration starts no service and cannot add an
undeclared port, command, mount, network, credential, migration, or dependency during compilation.
This surface is Designed and absent from the current `ExtensionRegistrationContext`.

Future Spell and Scroll contribution preserves that boundary. Spellweaver-owned stores may admit
portable Spell contracts and Scroll declarations; executable implementation and adapter stores
remain separately owned by Extension and effect Domains. Contract publication, implementation
registration, Scroll publication, and activation are distinct acts. None is implied by the current
registration context or by the presence of an equally named package.

Web-acquisition providers preserve the same rule. A package may register an Animator definition
for a search or browser service, but a `SoulstoneDefinition`, `PortalDefinition`, or raw
`ToolConnector` is not a Scout provider registration and grants no Search, Fetch, Crawl, Render,
or Extract authority. The future provider contribution surface must be explicitly Scout-owned,
effect-specific, provenance-preserving, and sealed with the other registration stores. Until that
surface exists, provider-facing toolsets remain incapable of constituting a delivered Scout path.

### 3. Contributions as Organs

Runes, Soulstones, Portals, and Transmutation admit active schemas and definitions. A
`SoulstoneDefinition` couples its schema to an Animator-owned runtime adapter and registers that
schema into the shared rune store. Runtime schema discovery imports only the selected package; a
loader is the singular TOML parser and validator, not a ledger. `__subclasses__` may audit an
already-loaded process but cannot establish registration or change whether an admitted schema is a
file-owning leaf. Branch ownership is computed from the exact admitted schema generation. Exact
repeat registration is idempotent
only for the same Registrant. Rune schema admission also reserves its exact filesystem anchor; a
different schema cannot claim the same `relative_path`. Soulstone registration identity is the
runtime name, Rune schema, and adapter type. The same runtime or schema with another owner fails
closed instead of silently preserving first registration. Portal schemas likewise have one exact
factory owner. The Vessel composition root passes the definitions, not an ordered list of anonymous callables;
runtime dispatch looks up the Portal's exact Rune schema. A broad factory cannot claim another
package's declaration, and a factory is total for every value its schema admits. Each definition
also owns its optional typed probe strategy. A Portal that requests a live probe without that exact
strategy fails closed; connector shape or a coincidental method name never selects an egress
protocol. The factory protocol is total: schema validation must refuse values its exact owner
cannot construct.

The Rune registry deep-copies admitted schema metadata and every returned snapshot, including
nested mutable values. Membership sealing and snapshot isolation are separate laws: trusted
contributors may still own mutable runtime objects, but callers cannot mutate canonical Rune
metadata through a value returned by the registry.

Every selected `register(context)` shim is a synchronous boot hook and must return `None`.
Awaitables and other return values fail assembly; an async function is never silently admitted as
an unexecuted registration. Crypt failure clears that activation's synthetic import generation.
Live Animator Rune, group, and capability projections add their own defensive-copy boundary before
values cross into orchestration, policy, or adapter code.

The built-in `delegation` extension has one no-network reference adapter and fail-closed
declarations for provider-backed candidates. A declaration describes immutable transport,
delivery, security, and limitation; it never executes a matching binary by itself. Registration
supplies neither persistence nor infrastructure authority: those need accepted ordering, recovery,
export, deletion, and uninstall contracts.

### 4. Substrate Injections

Operating-system libraries, binaries, images, services, resources, licenses, and wider substrate
requirements enter through the Extension Protocol and Forge manifest, not the boot context. Forge
is where platform validation and operator consent can be made explicit.

### 5. Runtime Schema Discovery

A schema makes TOML loadable; a Domain's runtime definition and hydrator make the configured
capability usable. Codex validates the configuration, an adapter builds state, and the resulting
LychD-facing `Runic[T]` handle retains its `.rune` provenance. A foreign object becomes `Runic`
only through such a wrapper. Foreign internals remain sovereign even when a system uses rune
machinery: translated configuration is the stable boundary.

### 6. The MPL 2.0 Shield (Private Extensions)

MPL 2.0's file-level terms allow a proprietary separate extension to link with LychD. That is not
a trust decision. A private in-process package can access process memory, so admission remains an
intentional operator and owner choice.

### 7. Extension Compatibility Tiers

#### The Built-in Direct Path

`src/lychd/extensions/builtin/` is core-owned. It may use internals and ABCs because it releases
atomically with the core and is selected by convention.

#### The Private Coupled Path

Crypt packages may live outside the tree while importing internals and `RuneConfig`. This is a
Magus-local, refactor-risking path; Assimilation may repair it, but no compatibility guarantee is
made.

#### The Independent Extension Package Path (v1+)

An independently released extension package is deferred until a versioned public API, conformance tests, and Forge
packaging exist. No SDK is created now and no independent compatibility promise is implied.
Foreign agent frameworks are not first-class in-process runtimes: use an external-service
Animator, A2A Emissary, or `DelegatedAgentNode` adapter, or assimilate their useful patterns.

| Property | Built-in Direct | Private Coupled | Future Independent Package |
| --- | --- | --- | --- |
| Location | `src/lychd/extensions/builtin/` | Magus-owned Crypt space | Forge-managed distribution |
| Coupling | Core internals and subclasses | Internals by choice | Versioned public API only |
| Loader | Selected import + `register(context)` | Selected shim + `register(context)` | Deferred, manifest-gated |
| Release cycle | Atomic with Core | Operator-owned | Independent |
| Stability | Core-maintained | Local repair only | Not promised until productized |

#### Rune And Runtime Boundary

Schemas and wrappers separate `SoulstoneDefinition` from its runtime adapter. Provenance travels
with a rune, not an assumption that foreign objects share core identity.

#### Delegated-Agent Runtime Adapters

An adapter has a schema and declared limits, not a node class. Its exact non-shell builder covers
one audited runtime/version range; it starts, polls or streams, cancels the process tree, and
settles results. Untrusted provider output becomes an `AgentJob` result or event, subject to
usage/rate-limit, reset, health, and provenance observations. It receives a secret-free grant and
[Coffin](./09-security.md#the-coffin-delegated-agent-profile)—not graph access, persistence,
quotas, credentials, promotion, or reanimation—and may emit bounded redacted JSONL, never a hidden
graph or chain-of-thought record. A new provider is an adapter plus configuration contribution, not
a node class or second orchestration kernel. A Provider aggregator is admitted through a
Portal/provider gate and an allowlist.

#### Cross-Language Organs

There is no stable cross-language ABI. Coupled code may be composed and repaired through Forge;
the future public API is the only route to independence. External services provide the present
true separation. LychD performs no blind `.so` scan: binary loading requires the Forge manifest,
platform validation, and explicit operator consent before runtime import.

### Consequences

Admitting in-process code means trusting it with the daemon's memory and stability: it can crash
or corrupt the process. Only trusted, admitted source receives that path, with explicit selection
and contracts. External protocols provide process isolation and independent lifecycle. A future
public extension-package API is still required for in-process refactor independence; a package
name grants none of these properties.

---
title: "6. Persistence"
plain_name: "Design rule 06: Persistence"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/06-persistence/
guide: https://lychd.snayu.ai/docs/adr/06-persistence/
---

# 6. Persistence (Design rule 06: Persistence)

## Plain-English summary (Snayu)

**What it is:** Decides that all committed data lives in one PostgreSQL database, the Memory Vault (Phylactery), accessed through async SQLAlchemy and asyncpg. The vault owns connections, transactions and migrations; each feature area owns the meaning of its records.

**Why it matters:** Read this before adding tables, migrations or any stored state, or before considering a different storage mechanism.

- PostgreSQL is the only deployed store; no loose files or in-memory stores may act as a shadow database.
- Only the Memory Vault builds engines, sessions and runs migrations; extensions get no ambient migration authority.
- Claims, checkpoints and consent records use database transactions and constraints so jobs survive restarts.

**Status:** Partial. Core persistence works; artifact custody (Reliquary) and several bindings are designed only.

## Original text (Hexanomicon)

!!! abstract "Context"
    The Phylactery is LychD's jurisdiction for committed truth. It gives one body a transactional
    home for relational records, JSON documents, vectors, execution history, and recoverable graph
    state; it does not decide what a Domain record means.

## Decision

PostgreSQL is the single-node persistence backend. Ordinary application transactions
use async SQLAlchemy and `asyncpg`; the exceptional claim observer below uses one
disposable native `asyncpg` connection. The Phylactery alone owns connection and
engine construction, codecs, sessions and transaction boundaries, migration order,
and schema admission. Domains own record meaning and lifecycle; neither they nor
extension packages gain ambient migration authority.

A deployed **Phylactery means PostgreSQL**: the one database cluster assigned to an application
partition. Domain repositories isolate SQL mechanics, allowing bounded test substitutes and the
explicitly isolated, disposable [developer fixture](11-backend.md#isolated-developer-fixture-designed).
Those techniques do not make a process-local or in-memory store a deployed Phylactery. Committed
application truth stays under PostgreSQL transactions, constraints, and migrations, without loose
application-managed files forming a shadow database. The Phylactery is therefore neither a generic
storage facade nor an interchangeable save/retrieve backend abstraction.

Future delegated-host attempt records and dispatch/closure tombstones belong to this Phylactery,
through an explicitly admitted schema and narrow typed store. The
[host handoff contract](14-workers.md#host-dispatch-and-irreversible-closure) owns their meaning;
AgentJob remains submission/adoption truth. Executor observations corroborate physical state,
not a second application ledger. This placement grants neither a guest database access nor a
host broad credentials, connection construction or migration authority. No host-attempt schema,
store or restore qualification is delivered by this decision.

### Schema admission

Core owns the schema-admission seam across native and extension models. Every admitted model
derives from Core's `UUIDBase`; an extension explicitly calls `register_model(MyModel)` during
initialization; Core aggregates those references before Alembic derives migration order. Runtime
package scanning is not admission, and migration generation or application remains an explicit
release or operator act. Colliding models, table names, or migrations refuse before a schema is
changed.

The `delegated-host-disposition@1` precursor stores one restrictive, create-once record per
AgentJob. The typed store owns exact canonical preparation bytes, their digest, optional one-time
dispatch identity and logical intake-closure tombstone; it serializes every mutation on the
existing AgentJob row. Database constraints retain complete-or-absent preparation and dispatch
fields and bound the preparation to two MiB. A restrictive ownership relation prevents ordinary
AgentJob or Run deletion from erasing no-reuse history. No cleanup operation is admitted; a
locked downgrade takes the strongest parent AgentJob table lock before the child table lock,
retains both through its guard and drop, and refuses any retained row. These records confer no
database access on a guest,
no host connection/migration authority, no positive owner authorization and no physical closure
or restore qualification.

The Archive `local-public-notes@1` profile retains its namespace binding, immutable attributed
note revisions, exact intake replay bindings, lifecycle versions, and text-free recall receipts in
separate PostgreSQL tables. All operations serialize on the namespace row, including recall and
receipt resolution, so promotion, correction and revocation share one decision order. The query
filters namespace and promoted lifecycle before lexical matching or content projection. Explicit
transaction-local statement and lock timeouts are five and two seconds respectively; a timeout
aborts the operation rather than becoming an empty result. Current authorization is rechecked
after transaction cleanup before response disclosure; refusing that response cannot undo a
committed mutation, whose retained replay identity and lifecycle version govern recovery. Explicit
revocation clears controlled text while retaining the minimal source identity and digest needed
to prevent replay. Existing Karma rows are neither migrated nor recalled by this profile.

The schema migration is transactional and linear. Downgrade takes exclusive table locks and
refuses while notes, replay bindings, receipts, or namespace bindings remain; it never interprets
rollback as permission to erase Archive history. Reconstruction uses retained rows and freshly
injected current authority, never process-local cache or a previous authorization receipt.

Optional Archive derivation adds immutable generation manifests/tombstones and one latest-attempt
row per exact source and generation. Composite namespace foreign keys prevent cross-namespace
pairs. A running row owns a token, version and fixed DB-clock expiry; a complete row alone owns
its vector. Source lifecycle changes and retirement clear vectors and invalidate attempts within
the same namespace transaction. Completion includes the exact source/generation/token/version/
deadline predicate and checks the canonical float32 digest after pgvector reload. Source inference
and lease cleanup happen outside database transactions. Status reads do not hydrate vectors.

Migration 0013 adds no extension or automatic backfill. The normal bootstrap migration-then-grant
sequence admits runtime DML on the new tables; runtime retains no DDL or extension privileges.
Downgrade locks namespace, source, generation and derivation tables before checking emptiness and
refuses any retained derivation history, including failed or retired tombstones. It never drops
pgvector or older Archive history to make rollback succeed.

### Database credentials and runtime authority

The configured `database.user` and administrative password retain the bootstrap/migration
identity, including an existing installation's `lich` owner. They never enter the Vessel.
The separate marked runtime role receives application-database CONNECT, public-schema USAGE,
table SELECT/INSERT/UPDATE/DELETE and sequence USAGE/SELECT; Alembic and SAQ version tables
remain read-only. It has no superuser, role/database creation, replication, BYPASSRLS, role
membership, schema CREATE, or application-object ownership. Every new application runtime connection must pass the same authority check:
SQLAlchemy installs it at connection creation, and the disposable claim observer
performs it before reading application records. SAQ verifies schema instead of
initializing or migrating it at worker startup.

The explicit migration gate verifies administrative identity and SCRAM TCP policy, refuses
unmarked or overprivileged existing runtime roles, provisions distinct credentials, applies
Alembic and SAQ migrations as administrator, grants runtime data access, and verifies that actual
runtime credential and queue schema before dependents start. Phoenix has a distinct marked role
for its dedicated database. Only known legacy administrator-owned Phoenix relations and enums
transfer to it; unrelated database owners refuse before mutation. PUBLIC database access is
revoked to keep these runtime roles out of one another's database. No general reassignment,
automatic demotion, database reset, or deletion is part of this gate.

The generated versioned HBA file is mounted read-only and selected explicitly on PostgreSQL
startup, covering existing as well as fresh PGDATA. TCP, including shared-Pod localhost, requires
SCRAM; local trust is confined to the private PostgreSQL-container Unix socket. An old MD5-only
administrator verifier cannot authenticate under this policy: startup of dependent services
fails closed until the operator converts that verifier through the private administrative path.
Preserved data and a known backup precede such operator repair; replacing a Podman secret cannot
change a password already stored by PostgreSQL.

The target chambers are deliberately logical rather than a claim of present deployment:

| Chamber | Responsibility |
| --- | --- |
| `public` | relational state, configuration, and extension registries |
| `vectors` | attributed vector material, including its trust status |
| `traces` | execution and observability traces |
| `queue` | durable work distribution |
| `verbatim` | JSONB exact values that must be consulted before semantic retrieval |

`vectors` status can distinguish, for example, speculative material from governed precedent;
consecration records authority, not universal factual truth.

### Default topology and scale seam

The default topology is one LychD host with one Phylactery—one PostgreSQL cluster—for its
application partition. Capacity scales up before it scales out: an operator may enlarge or
relocate the physical storage beneath the admitted `postgres/data` mount without changing
application authority. Member disks, filesystems, and volume topology remain host substrate rather
than domain or table-routing facts. The move must preserve [Layout](13-layout.md) identity and use
a PostgreSQL-consistent [capture or restore](07-snapshots.md); this decision promises no automatic
or online storage expansion.

#### Retention before expansion

Scale-up does not imply indefinite retention. Every persisted record class must
declare its owning lifecycle, holds and terminal eligibility, compaction or archival, deletion or
tombstone and derivative handling, and operational maintenance before automated retirement is
admitted. Neither age nor disk pressure grants deletion authority. The
[Reaper](31-simulation.md#the-branch-reaper) performs Shadow-owned branch hygiene and has no ambient
authority to trim Phylactery records.

#### Storage placement inside one cluster

One cluster does not require every PostgreSQL object to occupy the same physical storage tier. A
measured later schema may use native partitioning and tablespaces to place identified relations,
indexes, or partitions across local SSD, NVMe, or HDD mounts while callers continue to query one
logical relation. This is physical placement inside one Phylactery, not an application storage
adapter, independent backup target, or shard. Before admission, [Layout](13-layout.md) and
[Containers](08-containers.md) must bind every durable mount, while [Snapshots](07-snapshots.md)
must capture and restore `PGDATA` and every tablespace at one PostgreSQL-consistent boundary. The
current topology admits only the `postgres/data` mount; this decision promises neither a partition
policy nor tablespace delivery.

#### Separate stores and application partitions

A future Domain may admit a separate, named store only by amending the smallest existing Covenant
that owns the responsibility and introducing its typed port. Such a store is not a Phylactery
backend, inherits no authority over Phylactery relational records or PostgreSQL transactions by
proximity, and must define its authorization, commit or handoff, retention and deletion, backup,
restore, and reconciliation contract. A filesystem path alone is storage geography, never
application authority.

This decision neither delivers nor promises sharding. A later amendment may assign different
whole application partitions to separate PostgreSQL Phylacteries, with routing completed before a
unit of work opens and typed handoffs between partitions. It admits no shared `PGDATA`, routing
implementation, table-level, row-level, or intra-partition sharding, and no cross-Phylactery
transaction. A [Portal](../sepulcher/animator/portal.md) remains a remote capability road, while
[Intercom](26-a2a.md) and [Legion](../sepulcher/extensions/legion.md) carry bounded work or references; none forms a
shared database fabric.

## Reliquary custody (Designed)

Reliquary gives artifact custody a separately named store and one typed port. It shares no
PostgreSQL transaction and is not a Phylactery backend. Its first profile,
`same-host-trusted-bootstrap@1`, retains bounded immutable bytes supplied by trusted local
composition; Echo's canonical PCM inspector is the first consumer. This decision accepts that
custody contract. [State](../state-of-the-work.md#artifact-reference-contract) supplies the
implementation evidence.

### Identity and quarantine

An explicitly selected `native-candidate-json@1` profile reuses this same physical custody
and lifecycle for bounded immutable candidate JSON bytes. It accepts only
`application/vnd.lychd.native-candidate+json`, with the same 1 MiB payload bound; the default
`same-host-trusted-bootstrap@1` profile remains restricted to WAV. Profiles do not mix within a
root. Candidate inspection requires canonical typed JSON binding an inactive stage, base commit
declaration, purpose, exact selected and allowed logical paths, and regular-file bytes with
`0644` or `0755` modes, sizes and digests. Required Core, coupled-extension, lock, configuration,
schema, Pattern, policy, history and recovery declarations name only selected files; every file
has a declaration. Empty declarations explicitly describe their absence. Duplicate or ambiguous
paths, unknown kinds, undeclared bytes and mismatched references refuse inspection. This profile
accepts no filesystem source input or archive extraction. Admission proves structural custody
only: it authenticates neither the declared Git base nor compatibility, owner verdicts,
candidate construction, execution, promotion or activation under [Evolution](18-evolution.md).

An import binds a store UUID and caller-owned request UUID to
`urn:lychd:artifact:<store-uuid>:<request-uuid>`. Only validated internal UUIDs determine storage
names; an arbitrary reference, producer label, path, or URL never supplies a filesystem component.
The first profile accepts immutable `bytes` of at most 1 MiB with declared `audio/wav` media type.
It accepts no source path, stream, URL, producer inode, or provider handle. A malformed WAV may
enter quarantine; it cannot pass the separate PCM admission check.

One immutable envelope commits the raw bytes with at most 16 KiB of canonical, versioned
metadata. The complete reference describes the raw payload, including its computed SHA-256 and
size. The record also retains its trusted owner, importing subject, store/profile and request
identity, import fingerprint, manual-retention basis, and audit time. Declared producer and source
claims remain bounded, attributed claims; missing provenance stays unknown. They cannot replace
trusted importing identity. Classification, ownership, provenance, and payload never mutate in
place; changed material needs a new identity. This profile creates no derivative graph.

Import success establishes quarantine only. Quarantine inspection, admission, ordinary read,
hold, hold release, and deletion are distinct object actions under
[IAM](38-iam.md#trusted-local-custody). Every lookup compares the full retained reference, including
identity and classification. Bounded metadata may be read internally to decide authority, but a
failed lookup or authorization discloses neither metadata nor payload. Reading a reference or
possessing an earlier decision never grants present access.

Echo's trusted admission handler retrieves the retained bytes under quarantine-inspection
authority and reruns its real PCM inspector. It does not accept a caller-constructed observation
as proof. A separate current admission decision permits an immutable receipt binding the complete
record, reference, inspector revision and measured facts. Structural success alone publishes no
admission. An admitted read checks current authority again before returning the retained bytes;
this proves neither speech eligibility nor provider compatibility.

### Publication and continuity

The caller supplies an isolated private root and retains its explicit binding: profile/schema,
store UUID, invoking UID, and root device/inode. No default XDG path or container mount is added.
[Layout](13-layout.md#publish-an-owned-object) governs safe ancestry, pinned descriptors and
no-clobber publication. One lifetime exclusive process lock and an internal operation lock
serialize all state transitions. The lock is an owned, regular `0600` single-link inode; ordinary
operation never replaces or removes it.

The envelope and immutable control receipts use the same publication mechanism: write a new
owned `0600` inode, flush and `fsync`, publish without replacement, re-attest the public identity,
remove only its exact owned private staging name, and sync the namespace before reporting
success. Every envelope, control, and lock read opens without following links or blocking on
special files, then checks the opened inode's type, owner, mode, link count and bounded size
before reading. A producer retains no write descriptor or hardlink to the owned copy.

An exact import retry with the same request fingerprint returns current retained custody after
fresh authorization. Different bytes or immutable metadata conflict without replacing the
original. A tombstone permanently forbids reuse. A lost response after a proved commit therefore
permits exact lookup; uncertain publication never permits blind replay.

Clean same-root restart verifies the retained root binding, bounded envelope metadata, control
bindings and file identities. Activation reads no payload region. Each later protected access
checks the complete retained record and current authority before reading payload bytes, then
verifies their size and digest before disclosure; reopening alone proves no payload integrity.
Unknown entries, unexplained private stages, extra aliases, malformed records, replacement or
uncertain settlement are preserved as typed recovery. A filename alone grants no cleanup
authority. The first profile need not guess how to repair every interrupted state automatically.

### Retention and deletion

Retention is manual. Up to sixteen distinct hold identities may be recorded over one artifact's
lifetime; exhausting that bound refuses another hold. Each immutable hold binds its UUID, reason,
subject and exact record. Hold authorization sees that proposed UUID and reason. Release names
the exact retained hold and its digest, exposes that target to current release authorization,
and cannot affect a later hold. Hold IDs are never reused; elapsed time releases nothing.

Hold changes and deletion share the serialized operation boundary. Any active hold refuses
deletion without changing bytes or policy. Deletion first publishes and directory-syncs a
permanent tombstone binding the retained record, exact payload identity, deletion request and
decision, and hold-release basis. That tombstone takes precedence over admission and denies both
ordinary and quarantine reads, even when physical cleanup fails.

Only then may the adapter retire the exact owned, regular, single-link payload identity and sync
the resulting namespace. Its result distinguishes payload absence, cleanup pending, and recovery
required. A fresh authorized retry may finish retirement of the recorded identity; it cannot
adopt a foreign replacement. Tombstones remain indefinitely and import identities cannot be
reused. This promises logical unavailability and observed local cleanup, not secure media erasure
or deletion of copies outside the store. Native Linux retirement remains a separate physical
verification obligation.

### Backup and restore boundary

This first profile supplies no export, clone activation, or restore-reactivation operation.
Copying a directory is not an admitted backup or restore. A known restoration, lost control
history, or uncertain continuity disables activation. Future restoration must enter an inactive
target and reconcile against separately retained, nonrollback deletion and hold authority;
without it, activation refuses. [Snapshots](07-snapshots.md#rehydration-and-reckoning) cannot revive
material merely because an older capture lacks a later tombstone.

Root UUID and inode checks verify ordinary binding continuity. They cannot establish freshness
after an out-of-band in-place rollback. This trusted-host profile does not protect storage against
malicious same-UID processes or an operator rewriting it. Revalidating hashes within that same
root cannot detect all such changes and does not establish protected recovery against them.

## Wire and work contracts

### Codecs and detached values

The async boundary uses the repository JSON serializer and deserializer. PostgreSQL binary `json`
is the JSON payload; binary `jsonb` prefixes it with the `\x01` format-version byte. The connection
hook registers separate codecs for those wire shapes. Focused hook tests pin their exact framing,
and a disposable PostgreSQL receipt round-trips both a plain `json` expression and JSONB through
the production engine factory. Avoiding an intermediate text conversion is not zero-copy storage.

The loop-confined Run-ledger adapter deep-detaches mutable Run records, nested manifests, and event
metadata on write and every public read. That matches the database adapter's value boundary: a
caller cannot mutate canonical truth through an object it was handed. This parity rule does not
turn the memory profile into durable evidence.

The same value boundary applies to loop-confined consent and Bridge-session stores. Censored
arguments, turns, fragments, and model-history values are detached both when retained and when
projected; mutating a submitted object or a read view cannot rewrite the store's canonical value.

### Atomic claims and checkpoints

Workers select pending work under row locks with `SKIP LOCKED`. Selection, ownership transition,
and all facts that establish the claim commit atomically: no two workers may own one labor unit.
The replaceable JSONB `run_checkpoint` is one unique, cascading row per `run`; it is recovery
state, not the ordered `run`/`step` ledger.

An exact Run claim first locks the Run by identity, then its exact delivery, in
the existing SQLAlchemy transaction. It proves the unclaimed prestate before any
mutation or autoflush can occur, retains the conditional Run and delivery updates,
and commits them atomically. A conditional mismatch after that locked proof is an
attempt failure. Queue selection's `SKIP LOCKED` rule does not govern these exact
identity reads.

After an eligible completed claim failure, the Phylactery may open one disposable
native `asyncpg` observer using the same configured endpoint, database, runtime
role, loaded runtime password, and connection-security policy. It executes the
existing `RUNTIME_AUTHORITY_QUERY` and `require_runtime_authority`; only exact
positive verification permits application reads. Authority refusal remains an
authority error. There is no administrative fallback, alternate endpoint, pool
checkout, connection reuse, or retry.

The observer starts one READ COMMITTED, READ WRITE transaction and takes bounded
blocking locks on the Run identity, then its exact delivery. Bound parameters and
the owned model identities define its narrow detached scalar projection. It issues
no application DML or claim commit. A skipped lock or a nonlocking `QUEUED` read
cannot establish claim loss.

One absolute five-second monotonic deadline covers connection establishment,
authority verification, transaction setup, both reads, detached-value construction,
any normal rollback, and synchronous handle termination. Each operation consumes
the remaining budget; nonzero server statement and lock limits must not round to
zero or restart that budget. An explicit cutoff check rejects incomplete or late
evidence before return.

Every acquired observer handle is synchronously terminated before completion and
never returned to a pool. Failure cleanup begins termination before graceful close
and does not await rollback or close during deadline unwind. No detached
application observer task is admitted.

This is a cooperative observation-acceptance boundary. It proves neither server
rollback completion nor universal resource reclamation. Startup and CancelRequest
transports, callbacks, and possible DNS executor work can remain library-owned
after cancellation. Acceptance on the admitted Linux profile requires adverse-
transport and connection-count recovery evidence for both startup and command
cancellation. [State of Work](../state-of-the-work.md#topology-a-local-runs) records
implementation and qualification status.

### Deployment authority and edge journals

One application partition has exactly one active Phylactery—one PostgreSQL cluster—and authority
epoch. PostgreSQL is never exposed, shared, synchronously replicated, dual-written, or failed over
across a WAN.
Backups and inactive migration restores are recovery artifacts, not live authorities. Moving
authority requires a quiesced, typed export/import that preserves schema, labels, dedupe and
external-effect identities; it never copies an unrelated home partition by implication.

A platform adapter on another host may own a bounded durable journal for immutable envelope bytes,
digests, external identities, attempt generations, and observed receipts. That journal proves only
transport or effect custody. It cannot admit or settle application truth, own a Run, Context, Ward
decision, Sigil, corpus judgment, or become a Phylactery replica. The authoritative body adopts
events and settlements through typed authenticated operations. Loss or ambiguity remains explicit
and never triggers silent application replay.

### Delivery and recovery identities

Each Run hop also owns one `run_delivery` row. Run admission or wait re-admission and its exact
delivery identity commit together; broker publication happens afterward under an idempotent key.
`HELD`, `PENDING`, `PUBLISHED`, `CLAIMED`, and `SETTLED` distinguish admission custody from broker
acknowledgement and execution ownership. One partial unique index permits only one unsettled
delivery per Run, while `(run_id, enqueue_seq)` permanently fences old workers. A process-owned
relay repairs publication without treating the broker as canonical Run truth.

Migration `0004` refuses both introduction and removal of that delivery authority while any Run is
nonterminal. PostgreSQL transactional DDL leaves the schema revision and outbox intact on refusal;
an operator must settle or explicitly fail the work before crossing the boundary. This is a narrow
delivery-schema compatibility fence, not a general application rollback mechanism.

#### Nexus request identities

Operator Nexus transitions reserve their caller-owned request id in `nexus_swap_request` before
launch. The unique request id and immutable first target are a durable duplicate-effect fence, not
a transition state machine: loss of the process-local ticket causes exact retries to refuse without
relaunch rather than inventing an outcome. Migration `0007` refuses downgrade while any request
identity remains; erase or archive is an explicit operator act, not an incidental rollback.
The downgrade holds an `ACCESS EXCLUSIVE` lock through the refusal check and table removal so a
concurrent old writer cannot create a request identity between inspection and DDL.

#### Consent and delegated-wait evidence

Consent waits persist their exact owner on `Run.consent_id`; newest-row ordering is not ownership.
Settled Consent rows require a decision principal and decision time, while terminal delegated jobs
require result evidence whose job and status match the durable row. Migration `0008` refuses an
upgrade that would have to infer an existing consent-wait owner or accept settled rows without that
evidence. Its downgrade refuses while any Run remains `AWAITING_CONSENT`, so exact ownership cannot
be erased underneath live work.

#### Consent history custody

[Consent history](25-hitl.md#consent-history-and-proposal-branches) retains proposal identities,
validated revision links and ordered attributable records alongside the current Consent
projection. Appends use a unique producer/record identity: the same identity and content return
the retained record, while changed-content reuse refuses. Proposal creation and its initial
record, and each consent mutation and corresponding judgment record, commit together. Restart
cannot expose a settled decision without its history or manufacture missing past judgments.
Existing rows may be imported only as explicitly attributed legacy snapshots; absent proposal
ancestry, review facts or intermediate events remain unknown.

The executor owns each effect receipt. History adopts an exact reference through an idempotent,
recoverable delivery or reconciliation path. Publication failure cannot authorize re-execution.
Per-proposal sequence orders admitted records only; it imposes neither remote physical order nor
a global order across owners. [Graph](24-graph.md) retains checkpoint/wait ownership.

History has an explicit retention policy independent of execution cleanup: deleting a Run must
not cascade through the journal or erase a decision's identity and lineage. Missing execution
objects leave unavailable references and grant no replay. The current Consent model's cascading
Run relation does not supply this guarantee; migration must preserve retained bindings and
refuse unsupported writers before the new journal is admitted.

Append-only governs ordinary updates, not perpetual retention of private material. The history
stores censored metadata and authorized artifact references, not raw arguments, diffs, secrets or
review bodies by default. An authorized erasure/retention operation may remove governed content
and leave only the non-sensitive tombstone and linkage permitted by policy. Reads report
unavailable evidence without reconstructing erased content or treating a digest as disclosure
permission. The journal does not bypass an artifact owner's access, revocation or retention law.

#### Native Consent bindings (Designed)

The [native review contract](25-hitl.md#required-review-for-native-actions-designed) adds explicit
`native_review_required` and optional `native_binding` fields to Consent. Existing rows retain a
false requirement and no binding, without rewriting their verdict or attribution. New native rows
retain the requirement and complete binding together; missing or unsupported binding cannot be
interpreted as legacy consent. Application decision updates preserve both fields.

Removing this schema must refuse while any required-native or native-bound Consent remains,
including settled history. The refusal check and schema removal hold a table lock that excludes
concurrent writes, so a new binding cannot arrive between them. Rollback cannot erase or detach
these records to make itself succeed; any custody or deletion decision is a separate owner act.
This is **Designed** compatibility law, not an executed migration receipt. It adds no native action
store and does not give Consent's Run lifecycle ownership of application recovery records.

#### Blockworld placement custody (Designed)

Blockworld's bounded placement keeps its admitted mission and native action in separate
application records. The action retains its frozen command, exact Pattern and preparation/review
identity, Consent identity, issuance disposition, judgment evidence used at issuance, and receipt
or exact non-completion. Its immutable Run and Consent identifiers are references, not cascading
ownership: deleting Core execution or Consent records cannot delete or detach this application
truth. The action's mission reference restricts mission deletion while an action remains.

Before issuance, a missing Run or Consent refuses the action. After issuance may have begun,
missing execution or Consent records permit only reconciliation of the retained action; they never
grant another issuance. Preparation, its Consent and any consumed bounded preauthorization share
one transaction. Conditional issuance serializes the mission cursor and action; verified receipt,
mission cursor and placement budget settle in one transaction. An uncertain commit is resolved by
retained identity before further mutation.

A terminal refusal before action creation is retained on the mission. Re-entry returns that result
without creating Consent, consuming preauthorization, or reopening placement.

This first schema has no automated retirement or deletion path. Removing it refuses while any
mission or action remains, including settled history. The refusal check and removal lock both
tables against concurrent writes in a fixed order. Export, explicit erasure, archival and
incompatible-record migration require a later owned operation; downgrade cannot erase or rewrite
retained records to make itself succeed.

### Inactive native candidate custody

An explicitly tagged `native-candidate-inactive@1` path reuses Creation's case, admission and
append-only feedback records. It binds one exact Reliquary candidate record, structural admission,
literal bundle digest, known selected Core/coupled closure and review plan. It has no execution
slot, model attempt, Run or semantic verdict. The preparation deadline governs initial binding;
later review does not renew it. Existing public-source investigation rules remain separate and
refuse this profile.

The native admission retains the bounded complete binding; the case retains a bounded reference
and digest rather than copying source payload bytes. Independently attributed assessments and
hold/reject decisions retain exact targets and permanent caller-owned identities. Current Ward
authority and attribution participate in their insertion transaction. Exact retries return retained
truth after fresh authorization; changed bodies conflict. Lost acknowledgements require exact
identity lookup, never another semantic append. Physical custody survives a failed case transaction;
neither owner claims atomicity with the other or erases uncertainty by replay. Existing retained
Creation history and its downgrade refusal continue to apply; no new generic ledger is introduced.

### Atlas records

The initial Atlas Project is one versioned aggregate scoped to a Sigil. Its validated JSONB document
retains the brief, concern definitions, append-only assessments and decisions, and explicit
references to existing sessions and Runs. Assessments retain their judged text and revisions;
editing current requirements cannot rewrite their historical basis. Reference identities are
related activity, not copied execution evidence. A missing target remains an unavailable
reference rather than becoming a successful result.

Project mutation locks the owner-scoped aggregate and commits its new version together with a
request receipt. A receipt binds the exact request payload to its Project; reuse with different
content refuses. An exact replay returns current retained Project truth without repeating the
mutation. Creation similarly binds a caller-generated Project UUID to its initial payload.
The memory profile implements the same detached-value and replay behavior for bounded tests;
only PostgreSQL supplies restart persistence.

No Project, concern, assessment, decision, or reference deletion is admitted in the initial
surface. Closing a Project retains its records and does not cascade into sessions or Runs.
Migration `0009` adds Atlas without rewriting execution identity. Its downgrade takes an
exclusive table lock and refuses while any Project remains, preserving operator material across
an attempted rollback. Deployment migration remains an explicit operator act.

### Independent Concern retention

[Frontend](15-frontend.md#independent-concerns-decomposition-and-addressing) defines
Concerns with identity and authorization independent of optional Project membership. Their
definitions, attributed relation revisions, proposal provenance, and judged bases must survive
independently of a Project's lifecycle. Removing an association cannot erase the Concern or
reinterpret another context's judgment. Shared relations refer to retained identities rather than
copying a Concern's mutable definition into each Project.

An assessment must keep the exact Concern, context, and relation basis it judged. Its source and
target locators bind the actual revision or content identity inspected; a mutable URL or unchanged
Covenant number cannot identify that basis. Updates keep prior bases and use owner-scoped version
checks and retry receipts. Migrating the initial Project aggregates must preserve existing Concern,
assessment, reference, and retry identities with their Project context. Similar text cannot justify
inventing shared identities. Delivery needs a new explicit schema and migration contract;
migration `0009` provides only the initial Project aggregate.

## Outbound Intercom custody

The Designed [public-text peer profile](26-a2a.md#peer-task-jsonrpc-1) keeps immutable peer identity,
credential history, current policy/revocation generations, attributed public-source declarations,
sealed task intent/outbox, each physical transmission decision/claim and authenticated received
result in dedicated custody. It does not borrow AgentJob, consent or a fabricated Run owner.
An operator operation has its own typed identity. The
[native public peer station](26-a2a.md#native-public-peer-station) binds a real Run and station
through typed immutable ownership, never by putting that operation id into a Run field.

Exact task and outbox intent commit before network admission. Each physical attempt independently
commits conservative use, complete application-byte and bounded network-byte capacity before
issuing one process-local activation. Stable host, purpose, peer and task ceilings span new
operation, request, credential and configuration labels; no claim is refunded or reset after
refusal, expiry or uncertainty. Pending network output is limited to that committed allowance.
Observed accepted bytes and conservatively charged capacity are separate evidence.

Mutations lock capacity in a fixed scope order, then peer/current credentials, task and
transmission. Peer-only policy changes never acquire capacity after holding peer/task locks.
A later Graph transaction starts with its Run and does not acquire it while holding a task lock;
terminal reception and Run resume are separate idempotently reconciled transactions.
Native ownership transactions lock Run first. A unique Run/station/request relation owns one
task, source/target binding and original expiry. Its single current Run wait pointer is exclusive
with consent/delegation and survives the queued/running successor. Park and resume reread the
canonical relation; resume also requires open adoption and a correlated admissible terminal or
explicit local disposition, never caller-supplied success. No task-lock holder later acquires Run.
Task preparation, source attribution, charged attempts and remote uncertainty survive checkpoint
deletion. Retained native relations restrict Run deletion; downgrade refuses to erase them.
Changed-content identity reuse refuses. Only an acknowledged fresh commit can mint local
activation; rows, copied objects, reads and restart cannot restore it. Commit uncertainty permits
reconciliation, never another submit. Known foreign task ids may support fresh read polls.

Result admission verifies exact pending request, peer/key, task/schema/context and current policy;
the first admissible terminal wins. Conflicting or late responses cannot reopen a locally closed
task. Local refusal, expiry, revocation, cancellation intent and unknown foreign execution remain
distinct from authenticated peer completion. An old terminal does not grant a fresh read or effect.
Custody retains restricted sealed public-task bodies and verification evidence, not credentials,
raw private Context, source spans or general pseudonym maps. It offers no normal deletion or
reset path. Immutable execution references restrict cascading history loss where present.

One metadata-derived PostgreSQL migration enters this schema transactionally. Downgrade locks
every owned table against concurrent writers and refuses while any retained peer, key, capacity,
declaration, task or transmission remains. Actual PostgreSQL concurrency, lost-acknowledgement,
separate-owner recovery, schema/catalog parity and nonempty downgrade refusal are required.

## Privacy and delivery boundary

Persistence is designed to retain the labels and lineage defined by
[Context](21-context.md#privatization-and-the-privacy-cut): defaults may originate in table or
column metadata, policy may refine them by row, subject, or namespace, and derivatives retain
their material sources and transformations. Checkpoints, history, memory, artifacts, and delegated
records retain the applicable label or omit sensitive content. Missing ORM annotation never makes
raw data public.

These persistence rules support storage and information flow; they do not declassify material.
Context owns the Privacy Cut. Security owns declassification, and its trusted
[Security Egress Gate](09-security.md#portal-privatization-and-egress) enforces the resulting decision
immediately before transmission. Dispatcher can provisionally refuse or bind a capability but
cannot declassify bytes. [State of Work](../state-of-the-work.md#phylactery-first-light) sets the
delivery boundary for the exact label schema, row policy, and full production persistence.

### Closed disclosure-accounting custody

The `closed-diagnostic-recording@1` qualification profile retains transmission identity,
canonical restricted preparation/decision bytes and digests, exact Cut and host binding, Run
and delivery generation, claim identity, charges and terminal settlement. Ordinary custody
contains no raw source, source spans, candidate body, subject name, credential or reversal map.
Its concrete recorder is bounded process-local test material, not another persistent payload store.

One capacity table retains stable host, purpose and per-Cut rows. Limits and configuration
identity are immutable; consumed uses and bytes only increase. Purpose and host accounting span
fresh Cuts and Runs, and changing configuration cannot silently create new underlying capacity.
One transmission table owns exact request/occurrence identity and the one-shot claim. Retained
execution references use `RESTRICT` or an explicitly immutable noncascading identity; normal Run
cleanup cannot erase disclosure custody. No normal reset or deletion API is admitted.

Mutations lock capacity rows in a deterministic order, then transmission, Run and its exact
RunDelivery. Admission checks actual retained intent/Pattern bindings, running state, delivery
generation, claimed delivery, queue and priority before atomically retaining the decision and
consuming capacity. Only an acknowledged fresh commit can issue local activation. Missing
owners, changed-content identity reuse, stale delivery or mismatched host authority refuse.

Commit acknowledgement loss returns no activation. Reads and duplicates return retained status;
they never recreate a live claim. Abandoned claims reconcile to absorbing uncertainty without
refund. A failure after recorder handoff but before settlement also remains uncertain; identical
owned settlement is idempotent and conflicting or foreign completion refuses. Restart retains
charges and replay fences, while losing activations and the process-local Cut seal. New
preparation remains subject to the original host and purpose capacity.

Schema changes and both custody tables enter one PostgreSQL migration transaction. Downgrade
takes exclusive locks in the same table order and refuses while either table contains any row,
including unused capacity. Empty round-trip, schema/model parity, concurrency, ambiguous commit
and separate-instance recovery require actual PostgreSQL evidence. This custody law does not
deliver peer identity, a transport, Intercom inbox/outbox, a native peer wait or durable Cut authority.

### Reversible maps and the Privacy Vault

A reversible Privacy Cut persists no pseudonym map in Run, Graph checkpoint, receipt, event, or
general Phylactery row. Those records may hold one opaque `PseudonymMapLease@1` reference.

Mapping bytes require the Context-owned lease registry and rehydration port backed by a deployment-local
Privacy Vault with exact Cut/Run/attempt ownership, idempotent claim CAS, key epoch, TTL, access
audit, and one per-lease data-encryption key that never enters ordinary backup.

Expiry, revocation, consumption, or abandoned-work cleanup destroys that key; a restore drill proves any retained
ciphertext undecryptable and never claims physical erasure from opaque provider media. Loss or
expiry means rehydration is unavailable and never permits raw-history reconstruction.

The accepted Vault profile also contains transient plaintext: its map pages are unswappable or the
host swap is disabled, core/crash dumps and debugger attachment are disabled, buffers are bounded
and zeroized after use, and map material is excluded from traces and allocator diagnostics. A
deployment unable to verify those properties cannot enable reversible Cuts.

## Consequences

One logical state transition can share a PostgreSQL transaction, while write-heavy queue and trace
tables need workload-specific retention and autovacuum policy. The delivery outbox is transactional
with Run truth but not with the external SAQ transaction; its relay and exact keys close that gap.
Step/event publication still lacks a transactional outbox, and memory profiles do not have complete
behavioral parity with PostgreSQL repositories. The offline lifecycle receipt and its limits are
recorded in the [current evidence envelope](../state-of-the-work.md#current-evidence-envelope);
real host/model/browser operation remains unproved.

---
title: "7. Snapshots"
plain_name: "Design rule 07: Whole-system snapshots"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/07-snapshots/
guide: https://lychd.snayu.ai/docs/adr/07-snapshots/
---

# 7. Snapshots (Design rule 07: Whole-system snapshots)

## Plain-English summary (Snayu)

**What it is:** Defines how a whole-system checkpoint must be taken and restored: stop new work, drain or park running jobs, pause writers, then capture every store together with a manifest of exact code, config and image versions.

**Why it matters:** Read this before building backup, restore or upgrade features, since a pile of separate backups does not count as a valid snapshot.

- Order is fixed: close admission, drain work, quiesce writers, capture and seal, then reopen.
- Only a successful seal makes a valid snapshot; a failed capture leaves no seal and the system stays paused for repair.
- The manifest pins immutable revisions (Git commit, lockfile and image digests, schema version, extensions).

**Status:** Designed. The protocol is designed; whole-body capture and restore are not built.

## Original text (Hexanomicon)

!!! abstract "Context"
    A whole-body checkpoint binds the body revision, its configuration and extensions, durable
    stores, and the admitted work that may survive recovery. Workflow checkpoints support replay
    inside one revision through the Phylactery. This Covenant governs the coordinated capture and
    restore of the body itself.

## Decision: the Checkpoint Protocol

The coordinator performs this order without omission:

1. close admission for the affected body;
2. drain work to a declared boundary, park it, or mark it for abandonment;
3. quiesce queue, graph, migration, and application writers;
4. write a manifest; capture every durable store at its own consistency boundary; then seal the
   manifest and captures as one checkpoint;
5. resume admission only after that seal succeeds or the freeze is explicitly aborted.

Only a successful seal establishes a capture. If capture fails, no valid seal is written; the
body returns to its pre-capture state where possible and otherwise stays paused for repair.
A set of nearby backups cannot substitute for that coordinated result.

## Manifest and capture

Every source repository names an immutable revision: a Git commit object, or Jujutsu's hexadecimal
**Commit ID**, never its mutable alphabetic Change ID. The manifest also fixes lockfile digests,
image or built-artifact digests where relevant, active extension identities, Rune/configuration
provenance, schema revision, and storage-driver identity, version, and parameters. An annotation
may name a Jujutsu Change ID, but restore identity may not.

PostgreSQL consistency comes first. A Btrfs driver may then accelerate the dedicated-subvolume
capture and records filesystem UUID, subvolume ID, generation, mount identity, and database
recovery metadata. A Btrfs snapshot is neither a general transaction nor a substitute for a
database boundary. A portable driver instead uses a PostgreSQL-supported physical or logical
capture and staged, integrity-checked copies of manifest-bound files. Other drivers may implement
the protocol without altering its restore semantics.

## Rehydration and reckoning

Restore begins with an inactive target and opens admission last. First it verifies the seal and
manifest, supplies the exact revision and locks, and restores stores through the recorded driver.
It then verifies schema/configuration/artifact/extension/storage identity, performs only the
rebuilds required by the manifest, and reconciles. Any mismatch stops reanimation. Moving to a
newer body requires an [Evolution](18-evolution.md) act rather than being treated as restore.

Reconciliation revokes vanished leases and worker attachments, re-admits only work parked at a
declared checkpoint edge, and marks all other in-flight work `abandoned`. It identifies external
commitments beyond captured custody—messages, payments, host transitions, and outside writes—taints
the related work, and refuses unsafe replay pending explicit review. Local restoration never
pretends to rewind an external effect.

The recovered cut is the sole durable truth. Work admitted after it is absent and must be
resubmitted, never reconstructed.

That cut cannot override a separate store's surviving deletion or hold authority. The initial
[Reliquary custody profile](06-persistence.md#backup-and-restore-boundary) admits no restore or
clone activation: an older capture cannot revive material by omitting a later tombstone or hold.
Known loss or uncertainty of that control history keeps the store inactive. A future restore must
reconcile independently retained, nonrollback authority before opening admission; inode, UUID and
in-root hash checks alone do not establish that freshness.

Each participating owner keeps its responsibility during recovery: [Workers](14-workers.md)
owns queue claim and retry, [Graph](24-graph.md) owns graph re-admission,
[Orchestrator](23-orchestrator.md) owns physical convergence, and [Evolution](18-evolution.md)
owns source selection. The coordinator composes their work without absorbing their authority.

## Delivery boundary

This protocol is designed. Filesystem preparation does not prove freeze, PostgreSQL capture,
restore, or reconciliation. [State of Work](../state-of-the-work.md#whole-body-snapshot-restore)
is the delivery authority.

## Consequences

Whole-body recovery has one verifiable cut, at the cost of a bounded admission freeze and explicit
operator review wherever local custody cannot settle an external effect.

---
title: "8. Containers"
plain_name: "Design rule 08: Containers and services"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/08-containers/
guide: https://lychd.snayu.ai/docs/adr/08-containers/
---

# 8. Containers (Design rule 08: Containers and services)

## Plain-English summary (Snayu)

**What it is:** Decides that LychD runs as rootless Podman containers managed by systemd user units (Quadlets), with no external control plane. The Engine Room (Vessel) always runs in its container; host-native deployment is retired.

**Why it matters:** Read this before touching deployment, Apply Config (bind) output, or how services are started and ordered.

- Apply Config compiles one container server plus its PostgreSQL, migration and extension services; no uncaged alternative exists.
- Only free and open-source hosts are supported, so the operator can inspect and replace every layer.
- Installed-runtime acceptance must use the real built server image, not a test shortcut.

**Status:** Partial. Plan compilation works; real-host systemd and Podman runs await operator proof.

## Original text (Hexanomicon)

!!! abstract "Context"
    LychD manifests its one-host service body as rootless Podman Quadlets and systemd user units.
    systemd and cgroup v2 supply supervision, dependency ordering, and observable physical state;
    rootless Podman supplies containers. There is no external control plane.

## Core deployment and verification

The Vessel runs in its managed container. Core has no host-native deployment or test-deployment
profile. Bind compiles one container Vessel with its declared PostgreSQL, migration and extension
services; it does not generate an uncaged alternative. The `--native-only` and `--uncaged` bind
options are retired. Existing native bindings are preserved and refused for mutation; there is
no implicit conversion or stop.

Core tests and quality gates run in an explicit OCI test image. A test process may import the
application directly inside that container; this does not create another supported deployment.
Installed-runtime acceptance must exercise the actual built Vessel image and its declared
boundary. A PostgreSQL container beside an application on the host cannot qualify that claim.
The host CLI, Reactor and test harness retain their separately owned host responsibilities;
they do not run a host Vessel. No container test gains production credentials or broad host
access merely to simplify verification.

## Supported host policy

LychD is committed to developing and supporting free and open-source (FOSS) software on FOSS hosts
only. Every layer entrusted with host authority, isolation, lifecycle, or recovery must remain
operator-inspectable, modifiable, rebuildable, and replaceable. The operator must retain full
control over host integration and removal.

Linux with systemd, cgroup v2, and rootless Podman/Quadlet is the supported substrate. macOS,
Windows, and other non-FOSS host stacks are unsupported hosting platforms. Running LychD in a
Linux VM or container on a non-FOSS host does not change that support boundary: the outer host
still controls its execution and storage.

Private extensions and Portals retain their separate admission boundaries under
[Extensions](05-extensions.md). Admission does not bring their implementations or host platforms
into Core's support scope. Neither may become a required owner of LychD's continuity.

### Rationale: FOSS commitment and the agentic transition

The operator must be able to inspect, rebuild, replace, and reshape the host through authorized,
recoverable changes. That open-host commitment keeps agentic control accountable across the
software stack. A proprietary host would place part of the body's authority beyond the project's
ability to maintain and replace it.

Supporting macOS or Windows would require separate integrations for service supervision,
networking, filesystem ownership, privilege boundaries, secrets, CLI control, and recovery. Each
would add an ongoing implementation and verification burden. We commit that effort to deep Linux
integration and the guarantees of one supported host architecture.

Our strategic forecast is that the approaching agentic revolution will converge on Linux and
displace proprietary operating systems. **We do not expect Windows or macOS to survive that
transition.** We will not spend LychD development time sustaining compatibility with platforms we
expect that transition to leave behind.

Linux-only hosting and FOSS support are permanent project commitments. We deliberately accept a
smaller reachable user base to strengthen operator freedom and create an incentive to adopt an
open host stack. Native macOS and Windows backends, compatibility shims, and degraded hosting
profiles are outside the project's scope. Independent ports or forks carry their own maintenance
and support obligations; they create none for LychD Core.

## Decision: the manifested body

The generated topology contains `lychd.pod`, one `lychd-animator-*.target` for each
lifecycle-managed Soulstone, compatible `lychd-coven-*.target` aggregates, the migration gate,
Phylactery and Vessel, and admitted extension units. A Portal is a logical remote connection; it
does not summon a local container.

### Current unit graph

A generated Quadlet manifest is a Bind/Scribe deployment artifact. A live Animator retains its
Rune identity, Connector, and typed runtime surfaces; it never owns the generated manifest.
`RuntimePlan` compilation is available through the bind planner, not through the live
`AnimatorRegistry` surface.

Joined containers set `StartWithPod=false`: creating the shared namespace must not awaken every
Soulstone. Core ordering starts Phylactery, then the migration gate, then the Vessel. Only
`persistent_resident` Animator targets join normal boot; dedicated non-residents require the
Orchestrator or explicit break-glass operator action.

`groups`, `concurrency.conflict_domains`, and `alliances` are different declarations. Groups make
an operator-facing Coven; conflict domains declare finite-hardware exclusion; alliances grant
neither. The compiler forms the exact conflict graph: an explicit empty set declares coexistence;
an omitted dedicated non-resident domain becomes compiler-owned `default-exclusive` and conflicts
with every non-empty effective domain; residents may not declare a non-empty conflict set. It emits
one Animator target per Soulstone, its target/service ordering and binding, and one lexically
ordered `Conflicts=`/`After=` edge for each conflicting pair. Friendly grouping never implies safe
coexistence.

Each Animator and Coven target is `PartOf=` and explicitly `After=` the Pod service, retaining
systemd default dependencies. Each Animator target also orders after its conflict predecessors,
`Requires=` and is `Before=` its service; the service `BindsTo=` and is `After=` the target. A Coven
`Wants=` and orders after its compatible member targets, whose members are `PartOf=` that Coven.
Attestation requires each member's inverse `Before=` edges to every containing compiled Coven
alongside its own service ordering. A compiler rejects a Coven with an internal conflict before
it writes units.

### Compiler input

`QuadletConfig` names the reusable OCI image mechanism. It is a frozen non-Rune value object,
embedded in operator intent as `quadlet`, for an admitted owner to compile into a Quadlet-backed
service. Soulstone and Phoenix Runes are its current consumers. Only their common OCI image
invariant belongs to this shared object.

Lifecycle, mounts, devices, secrets, ports, commands, placement, and policy remain explicit fields
of the receiving owner rather than generic raw-Quadlet authority. `QuadletContainer` is the later
physical manifest model. Embedding `quadlet` declares the requested body but does not bypass the
owner-specific contributor or compiler that admits those policies. Container secrets use the typed
`secrets` field so Bind can validate their source names and presence. Raw Podman arguments are a
closed set of explicitly supported, complete values. Other values, aliases, short flags, and extra
tokens are refused; they cannot introduce an independent secret, mount, device, publication, or
network-policy path. There is no `Stone`, `ServiceStone`, or `AmbientStone` base type:
**Soulstone** is the sole accepted service term using that suffix.

### Versioned application deployments

A future `ApplicationDeploymentManifest@1` admits a complete application-specific service body
without granting a Composition raw Quadlet or systemd authority. It binds one immutable application
profile and its exact Composition/Pattern revisions to registered service-role implementations;
images and commands; dependency/start/stop order; local IPC and service identities; migrations;
mounts and durable volumes; ingress, egress, and isolated networks; secret references; ports;
resource ceilings; readiness; backup/restore; reconciliation; and removal policy. Unknown,
unowned, cyclic, overlapping, or undeclared edges fail before unit generation.

Configuration selects and assembles one registered profile generation. A multi-host profile closes
separately compiled per-host manifests plus one compatibility/enrolment receipt binding profile
revision, deployment and authority epochs, manifest digests, service Principals, protocol/schema
ranges, and exact private-route generations. It does not create a distributed control plane:
each host compiles and attests only its own Codex, secrets, volumes, and units. Each Core or
Extension Domain owns its typed service contribution. The Containers compiler arbitrates each
whole physical manifest and Scribe alone emits the units and receipts. A profile may place a
hostile parser, credential edge, or browser outside `lychd.pod` in a dedicated rootless network
zone, but it cannot create a second application authority, raw unit fragment, Podman socket route,
or lifecycle channel.

Operator provisioning supplies the one non-root host account and platform floor; LychD services
receive no account-creation or cross-user authority.

#### Gateway placement

An exact profile may place Veil on a separate
[Gateway Host](../sepulcher/gateway.md). That host is a deployment trust role, not a Composition,
Extension Domain, second Vessel, or application authority. Its manifest closes the public
listeners, typed Veil routes, exact authenticated backend, firewall flows, management boundary,
edge-only secrets, optional Tether attachment, resources, readiness, reconciliation, and removal.
It also binds or attests the independently enforced network zone, its router/firewall, L3-switch,
or cloud-network policy, and the receiving Core-firewall policy. The Gateway workload cannot widen
those controls; its local firewall rules remain defense in depth. The Core manifest accepts only
that backend identity and flow. The reference
placements **Home** and **Remote** reuse this role with different physical and custody boundaries;
a hostname, RPi, VPS, or boolean toggle cannot synthesize either topology.

#### Profile delivery and transition

The first concrete consumers are the designed, mutually exclusive
[Reach deployment profiles](../compositions/reach/deployments/index.md). No application selector,
deployment-profile registry, service-role contribution store, manifest compiler, or effectful host
receipt ships; the current generated topology above remains authoritative delivery truth.

A profile transition closes admission, drains or classifies every external effect, fences the old
generation, stops and revokes its credential owner, and activates the replacement authority last.
Two manifests for one profile never license two Phylacteries or Gateway owners. Downgrade or
rollback refuses when it would erase live custody; after the new authority admits work, return to
the old body is another quiesced migration rather than process restart.

## Three authorities, one transition

A lifecycle transition crosses three authorities. The [Orchestrator](23-orchestrator.md) decides
admissibility, the [Dispatcher](22-dispatcher.md) grants capability, and systemd performs the
physical unit transaction. Before contacting systemd, the application closes relevant admission,
drains leases, revalidates configuration and the observed world, and attests the generated
target/service/Coven graph and its loaded sources against Scribe ownership. It then submits the
transition and observes settlement, readiness, and recovery under [Privilege](10-privilege.md).
Each office keeps its own responsibility. A direct target start bypasses these gates and is
break-glass only.

Every mount, device, secret, port, and network edge is declared per unit. Joined containers share
a Pod network and therefore need service authorization as well as mounts; generated host ports are
explicitly `127.0.0.1:`. `UserNS=keep-id` belongs at the Pod and application units use `User=%U`;
the Phylactery explicitly sets `User=postgres` and its data mount uses `:U,Z`. These identities
allow assigned paths, not ambient Crypt access. The Tomb is a separate Security/Workers boundary,
not a safer Pod member.

`keep-id` maps the invoking host UID/GID into the Pod; process `User=` and each mount's
ownership and access policy remain separate decisions. It does not nest a second rootless
runtime or make an arbitrary image user match the host. Initial host layout creation belongs
to the invoking non-root account. Explicit `User=postgres` prevents `keep-id` from replacing
the image account with the invoking UID; `:U` supplies that account's mapped datastore ownership
before the PostgreSQL entrypoint initializes it. This requires no host-root setup. `:U` may
recursively change host-visible ownership and therefore belongs only on that
dedicated datastore, never a shared model shelf, home directory, Codex, or Reactor journal.
Existing mapped datastore ownership is preserved under [Layout](13-layout.md).

Soulstone data mounts cannot request recursive ownership changes (`:U`), host credential or
configuration roots, container storage, kernel/control filesystems, or existing sockets,
devices, and FIFOs. Host aliases are resolved before this check. Read-only access still discloses
credentials and may allow use of a Unix socket, so `ro` does not exempt these sources. Ordinary
explicit model and runtime-data mounts retain their declared access. This compiler check is not
a scan of every file inside an operator-selected data directory or a runtime inode attestation;
the operator must keep that directory free of unrelated private data and control endpoints.

Trusted Vessel and migration code is image-root-owned and their root filesystems are read-only;
declared writable tmpfs and application mounts supply runtime scratch and state. Their compiler
enables a fixed 1 MiB tmpfs at `/run/secrets`, owned by container root with mode `0755` and
`nosuid,nodev,noexec`, to supply mountpoints for the separately declared read-only secret files.
This leaves configurable secret names and their individual mounts intact; it grants no writable
image root or arbitrary tmpfs declaration. This rule must
hold for different host UIDs, including the image's historical application UID. It does not
assert that third-party images support a read-only root or that a rendered manifest proves
working subordinate-ID maps, SELinux labels, or filesystem permissions on an operator host.

Current Soulstone compilation joins every service to `lychd.pod`. That topology is not admissible
for a browser-bearing Scout renderer. Such a Soulstone must compile into a dedicated rootless
containment and network zone with no route to Core peers, Phylactery, host control sockets, wallets,
or unrelated secrets; its target egress must cross the Scout-owned destination gate. Until the
Rune, `RuntimePlan`, compiler, and effectful containment tests can express and prove that topology,
the Crawl4AI renderer candidate remains Designed rather than deployable.

## Scribe inscription

Scribe materializes one validated generation transactionally: render and validate in staging,
verify the prior ownership receipt and exact binding sites, make same-filesystem backups, replace
the declared files, remove only stale receipt-named files, publish the new receipt, and daemon
reload. A changed source, generation, site, secret, filename, mode, symlink, or foreign collision
refuses; a failed transaction restores the previous files and receipt. Ambiguity authorizes no
deletion. Filename resemblance never proves ownership.

Before planning, the complete ownership manifest also requires a one-to-one mapping from every currently runtime-bearing `.container`,
`.pod`, and generated/plain systemd source to its resolved runtime unit; different source names
that systemd would collapse onto one unit refuse together.

Compilation and materialization are available within their declared State boundary. A rendered
generation supplies no receipt that an operator's host actually started Podman, systemd, GPU, or
a model. [State of Work](../state-of-the-work.md#systemd-podman-embodiment) owns that distinction.

## Consequences

The generated graph is inspectable and rootless, but it is not authority to start arbitrary
services or to infer host execution from a rendered unit.

---
title: "9. Security"
plain_name: "Design rule 09: Security boundaries"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/09-security/
guide: https://lychd.snayu.ai/docs/adr/09-security/
---

# 9. Security (Design rule 09: Security boundaries)

## Plain-English summary (Snayu)

**What it is:** Defines the trust zones of LychD - the server, an optional gateway host, sandboxes for running untrusted code (Tomb) and for foreign agents (Coffin) - what each may hold, and how data leaving for cloud models passes a Privacy Filter.

**Why it matters:** Read this before adding anything that runs code, holds secrets, talks to the network or sends data to cloud models.

- The server holds data and provider credentials but must never run arbitrary shell or Python code.
- Sandboxes get only a narrow job and a disposable workspace, never database secrets or host access.
- If a required boundary is unavailable, the action is refused; designs need containment evidence before being trusted.

**Status:** Partial. Local loopback protections work; sandboxes and the cloud privacy gate are mostly designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    Security separates the secret-bearing Vessel, disposable execution, foreign delegated agents,
    and the host. It is a containment design for a trusted Linux kernel, rootless Podman, and the
    Magus's unprivileged host account; kernel/runtime escapes, hostile host administration, and
    compromise of that account are outside its protection.

## Decision: trust zones

| Zone | May hold | Must not hold |
| --- | --- | --- |
| Vessel | durable control-plane state, trusted provider and database authority | arbitrary shell/Python execution, writable trusted code |
| Gateway Host | edge certificates and routes, local defense-in-depth firewall intent, one backend service credential, optional tunnel key, bounded transport evidence | database or application authority, private Context, provider credentials, Sigils, corpus, general LAN route, ingress-derived host administration |
| Platform edge | one platform credential, service credential, bounded transport/effect journal, and typed adapter | provider/database credentials, corpus, private Context, policy, home Sigil, arbitrary home route or host administration |
| Tomb | a narrow execution-job hand and disposable child workspace | agent/LLM authority, provider or broad database secrets, host capability, Host Reactor access |
| Coffin | one foreign agent under one `AgentJob` and a revocable Gate bearer | queue/database credentials, promotion, authoritative VCS, host effects |

A [Gateway Host](../sepulcher/gateway.md) is an optional separate ingress placement, not an
Extension Domain, Composition, caller, or second authority plane. Veil owns its admitted routes;
Tether may supply an exact private road; the receiving Ward and application still authenticate
and authorize every request. The Core host accepts only the named backend flow from the Gateway
identity. Policy outside the Gateway host—a router/firewall, L3-switch ACL, or cloud-network rule,
together with the receiving Core firewall—enforces the zone's public listener and exact backend
flow. Rules controlled only by the Gateway itself are defense in depth and cannot prove containment
after host compromise. A same-host proxy is Veil but not a Gateway Host. Operator administration
uses a separate infrastructure path whose credential is unavailable to ingress and backend
workloads.

Gateway compromise closes the route, revokes edge certificates, backend and tunnel credentials,
fences its deployment generation, quarantines bounded transport evidence, and rebuilds the host.
It does not justify rotating disjoint Core credentials unless evidence shows they crossed, and it
never upgrades forwarded identity or authorizes an effect.

A remote platform edge translates an application's platform traffic. Its assertions alone cannot
authorize a caller: where upstream events lack an independently verifiable end-user signature,
a compromised edge can fabricate that evidence. Enrolled/private Context and consequential
effects therefore require independent proof presented to Ward. On edge compromise, revoke
platform, workload, tunnel, and edge-epoch credentials, quarantine the journal, and reconcile
external identities. Disjoint home/provider credentials are implicated only if boundary evidence
shows they crossed.

### Tomb Execution Contract 

The Tomb is deliberately non-agent: its child has a task-scoped workspace and artifacts, filtered
environment, zero network, outer-enforced resource limits, and complete-process-tree cancellation.
It requests data through its supervisor and reasoning through the Vessel's typed path. A Coffin is
not a more capable Tomb; it is its own delegated-agent boundary.

Rootless Podman maps the Pod with `UserNS=keep-id`; application units select `User=%U`, while the
Phylactery explicitly selects `User=postgres` and a `:U,Z` data bind. This maps assigned paths,
not cross-service authority. Exact mounts, service credentials, and network policy remain the
boundary: lower-trust units receive no writable authoritative checkout, no whole Crypt, no
browser/keychain/home state, and no Podman socket. A host Reactor is a host boundary, never a
container capability.

Joined containers share localhost and routes, so a mount does not protect a reachable service.
Generated ports bind loopback, which is not authentication. The local operator must also present
a dedicated high-entropy HTTP Basic credential before receiving the fixed local Sigil. The
credential belongs only to the Vessel and the host operator; shared Pod membership grants no
access. Unsafe requests with a foreign Origin are refused even when their CSRF token is valid.
This local credential does not establish remote identity, object isolation, or effect-time
revocation. Dedicated-profile browser operation remains subject to its acceptance evidence.
The [isolated developer fixture](11-backend.md#isolated-developer-fixture-designed) may use its
configured loopback Vite proxy while retaining the same authentication, Host, CORS, Origin, and
CSRF checks. Peer access, production access through a proxy, tunnels, and non-loopback operation
remain refused. The raw SAQ administrative UI is disabled: its traceback and broker-mutation
surfaces are not admitted operator projections.

### Local installation-stop admission

The former `native-owned-lifespan@1` host-Vessel stop profile and its HTTP admission route are
retired with native deployment. Historical signed-stop receipts remain dated observations of
that removed profile; they cannot authorize a current container operation.

A future container lifecycle port must authenticate exact installation intent, retain current
binding and process/container authority, close admission before retirement, and independently
verify the owned terminal outcome before stopping dependencies. Unknown, lost or forced outcomes
preserve dependencies for reconciliation. No native-profile rename, inactive unit alone, successful
manager reply or direct fallback can establish that contract. Current active-Vessel lifecycle
operations refuse until that passage is implemented and qualified.

Ordinary local HTTP Basic, Host, Origin, CORS and CSRF boundaries remain authoritative. Retiring
the special stop route removes its middleware exceptions; it creates no replacement bypass.

Secrets remain references in Codex and Runes, are emitted only for a unit that needs them, and are
absent from lower-trust child environments, receipts, errors, and command lines. A Tomb supervisor
may receive only job claim/settlement database authority; a Coffin receives none.

### The Coffin Delegated-Agent Profile

A Coffin is one foreign runtime for one delegated occurrence. It needs an outer rootless service
boundary, inner job-scoped `nono` policy, and externally enforced resource ceilings. `read` gets an
immutable task projection; `candidate` gets a disposable copy-on-write or jj worktree. Workspace,
scratch, and artifacts are canonical, disjoint strict children of one job root, each granted once;
only `candidate` makes workspace writable. A `verify` specialization may add audited tools but may
not widen those roots or authorities.

The profiles return only analysis/bounded artifacts, a candidate patch/bounded artifacts, or
verification receipts respectively. They do not turn a provider name, blocked tool, failed test,
or expired budget into authority to widen a root, tool, network path, or credential.

The command is literal argv with a canonical absolute executable—no shell resolution, traversal,
controls, relative executable, or unbounded argv. Admission fails closed unless a reviewed
qualification binds the exact `nono` source revision and patchset, dependency lock/build inputs,
canonical executable digest, selected policy and outer runtime, and target platform to an audit
receipt and an explicit disposition of applicable security advisories. A version string, moving
series, latest release or upstream audit sponsorship establishes none of that closure. Applicable
known defects require inspected fixes and regression evidence; an excluded mechanism requires
justified, enforced non-applicability. Unknown fix status, provenance or applicability refuses.

The former 0.66-series baseline is retired: later upstream advisory ranges include it. Neither a
downgrade to that series nor a newer release is admitted by this amendment. The
[dated containment study](../sepulcher/extensions/weaver/coding-runtime-research.md#containment-version-selection)
keeps the primary-source findings and their limits. Landlock ABI 6+ and the required filesystem,
TCP, signal, process, endpoint, environment-filtering and outer resource-enforcement capabilities
must still be observed for the exact profile. Requested limits are not measured ceilings. Its
environment is an allowlist, with known provider credential variables denied. Candidate output
stays quarantined pending trusted admission. No executable or host profile is qualified here.

#### Provider Gate

The Provider Gate is the Coffin's sole network destination: one exact TLS port-443 destination and
admitted POST path, never a general proxy. Direct provider, registry, LAN, web, and other loopback
access is denied. The guest receives only a short-lived opaque or phantom credential; the real
credential and its reference remain in the trusted Gate.

A live grant binds bearer, job, provider, model, expiry, and monotonic request/token/spend budgets.
Cancellation, settlement, revocation, expiry, route mismatch, or budget exhaustion denies the
call. The Gate resolves a real credential only after this check. It cannot declassify content: its
grant, the Portal decision, and any admitted transformation must agree without widening one
another.

### Portal Privatization and Egress

[Context](21-context.md#privatization-and-the-privacy-cut) owns labels, influence lineage, the
Privacy Cut, transformation evidence, and Cut verification. Security owns declassification for
every remote disclosure, not only model calls. The trusted Portal Egress Gate is the first
implementation name for this general byte-time boundary.

#### Target and disclosure basis

`EgressDecision` carries one tagged `RemoteTarget`:

- `PortalTarget` binds the actual recipient provider/service, operation, model when applicable,
  and a protocol-specific endpoint: canonical origin and exact request target for HTTPS, or
  fixed resolver protocol, literal endpoint and exact question for DNS. It also binds an
  immutable custody-route digest when an intermediary exists;
- `A2ATarget` binds the enrolled peer Principal, public task schema, adapter revision, and canonical
  origin; and
- `DelegatedRuntimeTarget` binds the foreign runtime, containment profile, job, adapter revision,
  and destination when the runtime itself is remote.

It also carries one tagged `DisclosureBasis`: `RawEligible` binds the exact classification,
category, target, purpose, and policy facts that make untransformed bytes eligible;
`CutEvidence` binds the exact `PrivacyCut@1` instance/digest, final candidate digest, terminal
transformation-receipt-chain digest, and `CutVerification@1` digest. A nullable Cut revision or a
transformer claim alone is not an admissible privacy basis. The Gate verifies that this basis,
candidate/wire digest, target, purpose, policy, expiry, and remaining disclosure use all agree.

An HTTPS site's identity is distinct from the native Scout adapter implementing the contact.
DNS resolution and TLS hostname disclosure precede the HTTP request and need their own admitted
handoffs; a resolver decision cannot authorize the site. DNS custody includes the selected
resolver's forwarding or recursive-resolution policy. A fixed resolver address does not establish
that policy, and unknown custody facts refuse whenever disclosure policy depends on them.

The [trusted local Scout profile](38-iam.md#trusted-local-scout-profile) may admit an explicit
public-locator declaration from an authenticated operator separately authorized to classify that
source. The declaration binds the exact complete URL, subject and authentication generation,
purpose, source/influence manifest, classification, category and policy revision. It is an
attributed operator assertion, not a proof of publicness. The host verifies this basis before
issuing `RawEligible`; authentication, public reachability and the subsequent consent click do
not supply classification. Ordinary chat, model output or copied Context cannot inherit the
declaration merely by containing the same URL. Missing lineage, known restricted influence and
prohibited categories retain the refusal rules below.

The [outbound public-text peer profile](26-a2a.md#peer-task-jsonrpc-1) has a separate dedicated
operator-authored-text source adapter. It requires actual local authentication and a distinct
current classification action, and binds the exact complete text, source/influence facts,
category, purpose, enrolled target and policy generation. This is an attributed assertion of
publicness, not a PII detector or proof of original authorship. Known restricted ancestry,
unknown lineage, prohibited categories and local-only constraints still refuse. Text equality,
ordinary chat, ASR, model output and a serialized declaration cannot supply this authority.

Each child provider request from a coding runtime needs its own `PortalTarget`. The outer job
decision cannot authorize an unknown series of model calls. Automated remote execution therefore
requires the runtime's network to remain behind the admitted Provider Gate; a black-box runtime
that cannot do so is ineligible. Transparent MITM, ambient proxying, and caller-supplied target
fields cannot establish this boundary.

#### Decision identity and local custody

The decision is explicit, never inferred consent, and binds opaque Principal identity plus Sigil
identity/revision digest—not either object—Run/occurrence/attempt/transmission generation, purpose,
exact target, canonical wire or exported-artifact digest, source
manifest and influence-label digests, safe residual-disclosure evidence digest, opaque restricted
lineage references, policy and disclosure-basis revisions, expiry, budgets, and allow/deny result. It contains no
caller-supplied full `ArtifactRef`, raw subject, filename, material-parent, source span, reversal
value, credential, or live Sigil/capability/grant/lease handle.

Within the trusted local Scout profile, its host-bound local subject and authentication generation
occupy the identity binding without claiming an enrolled Ward Principal or remote credential.
The public-text peer profile likewise binds its authenticated local initiator separately from
the enrolled workload/remote peer identities. Its explicit operator-operation binding is an
alternative to native Run binding, never a UUID placed in a Run/occurrence slot by convention.

`EgressDecision` is restricted, local-only, non-exportable, and non-bearer evidence. It never enters
the provider, peer, runtime, callback, log, Loom, or telemetry payload. The Gate passes only the
already sealed application bytes to transport; it neither appends decision metadata nor lets an
adapter serialize the verdict. A public projection uses only an opaque event id or the keyed
evidence form below.

Evidence can itself disclose private facts. A plain hash of a short prompt, filename, identifier,
or stable manifest can become a dictionary and linkage oracle, so canonical raw payload, source,
manifest, and content digests remain restricted local evidence. Exported, logged, or operator-wide
evidence instead uses a random opaque id or `EvidenceDigest@1`: a deployment-local,
domain-separated keyed digest scoped to consumer, purpose, record class, key epoch, and retention.
It receives no raw low-entropy metadata and makes no claim to anonymize its input.

#### Transmission and redelivery

Every actual transmission, including exact same-envelope redelivery, settles a fresh
`EgressDecision` before its first byte and atomically consumes the declared transmission/disclosure
budget. Transport redelivery under one road-owned attempt preserves the sealed bytes, target,
external/idempotency identity, road decision, and—when present—Cut/token namespace. Changed bytes,
target, actor, policy, custody route, semantic retry, resume with changed body, or fallback creates a
new road decision and, when transformation is required, a new Cut. Uncertain effects reconcile;
they never silently become a new semantic attempt.

#### Offline disclosure-accounting qualification

`closed-diagnostic-recording@1` is a local qualification profile for durable disclosure
admission and consumption. It accepts only the complete canonical bytes of the existing
`closed-diagnostic@1` candidate, under a separately host-pinned synthetic **export** binding.
The expected actor, Sigil digest, consumer, purpose and exact target cannot be taken from the
candidate's own Cut as their authority. This profile neither declares an enrolled A2A peer nor
admits a Portal, credential, network destination or arbitrary source material.

An acknowledged fresh database claim consumes one use and the complete candidate size against
stable host and purpose capacity and the individual Cut's disclosure ceiling. Host and purpose
identity are independent of Cut, attempt, transmission and Run identities; a new identifier,
renamed configuration or changed policy cannot reset retained capacity. Configuration changes
that disagree with retained ceilings refuse rather than minting a fresh account. No charge is
refunded after a claim, including refusal, expiry, cancellation or uncertain recording.

Only the trusted recording owner may turn its fresh claim into one process-local activation.
It consumes that activation before invoking its concrete bounded synchronous recorder, after
rechecking the host binding, Cut, expiry, current policy and exact Run effect fence. No await
separates the final check from the recorder handoff. The recorder receives exactly the candidate
bytes, without a decision envelope; no callback, caller-selected implementation, URL or filesystem
destination is admitted. Claim and completion shapes, copied objects and restored rows are not
live authority.

This profile linearizes admission before a local recorder call. A database Run lock does not
fence a later cancellation after commit, and no transaction spans an external effect. A future
transport owns its additional effect-time and complete-wire obligations: wrappers, authentication,
headers, polling and artifact requests cannot inherit this candidate's verification. Offline
recording is an acceptance witness for the accounting primitive, not evidence of A2A exchange,
remote disclosure safety, general anonymization or a normal application egress path.

#### Public-text peer network handoff

The Intercom profile requires its own typed network admission and custody. A closed diagnostic
recorder claim, Cut shape, Scout locator declaration or transport class grants it no authority.
Policy-independent pinned socket/TLS mechanisms may be reused under the mandatory Intercom gate;
Scout's source/locator policy is not peer trust.

The gate verifies the independently admitted public source and exact enrolled `A2ATarget`, then
seals the complete application request after authentication headers are prepared. Public protocol
wrappers, workload identifiers, nonce, path, poll parameters and TLS hostname have explicit
disclosure bases too. Every connect/TLS/application send checks current authority and consumes
its finite committed allowance in the same loop turn as the nonblocking syscall. TLS ciphertext
is bound to the complete sealed application value; the gate never claims to reconstruct it by
decrypting traffic. No private decision, source manifest, operator subject, credential or receipt
metadata may be appended to wire. No DNS or ambient proxy/redirect/retry road is opened.

Fresh physical signature wrappers over one retained semantic body require a new complete-wire
decision; they do not authorize repeating an unknown effect. Poll and cancellation requests have
their own exact source/target/purpose decision. Durable counters charge full declared application
bytes and conservative network allowance without refund; observed accepted network bytes are
reported separately. Failure to commit, verify current authority or reconcile an old attempt
cannot activate transport. This public-input profile does not authorize private Context, a
general anonymizer, voice offload or a new provider/peer fallback.

The [native public peer station](26-a2a.md#native-public-peer-station) adds an exact real
Run/station/source/target association. A process-owned live permit requires actual current
operator authentication and canonical ownership; retained admission, Sigil and checkpoint shapes
cannot construct it. Fresh authenticated reauthorization after restart cannot rearm a claimed or
closed semantic task. Run/claim fencing is checked at each physical handoff and before adoption
or resume. Trusted local cancellation may close adoption and retire local exchanges without
remote permission; remote poll/cancel still requires its own current exact authority and capacity.

#### Thresholds and refusal

Consent cannot repair missing lineage, override a prohibited category, or broaden named content and
destination. On the `0.0` public-safe to `1.0` strictly-private scale:

- below `portal_threshold`, raw egress remains eligible under destination, purpose, and category
  policy;
- at or above `portal_threshold`, a satisfying Privacy Cut is required; and
- at or above `forbidden_threshold`, raw egress is forbidden.

`portal_threshold` is the compatibility configuration name for the general remote-disclosure
threshold until a versioned policy schema replaces it. A target-specific rule may narrow that
baseline; peer trust, local ownership of a VPS, or containment of a coding runtime cannot widen it.

Non-declassifiable categories remain forbidden regardless of weight, and a failed, uncertain, or
expired Cut fails closed. Unknown recipient, retention, training, subprocessor, or custody facts
also refuse whenever policy depends on them. Current local-only source has no hostile-network
authorization and does not deliver this general egress gate; [State of
Work](../state-of-the-work.md#context-privatization-and-portal-egress) owns that boundary.

Several sanitized payloads can together reveal a stable identity or reconstruct withheld context.
Disclosure accounting must therefore cover related calls, retries, delegated child requests, and
intermediaries across one purpose. A future gate must enforce that cumulative policy before
transmission and keep enough bounded local evidence to detect reuse without exporting a
correlation identifier. Per-call censorship cannot guarantee anonymity. Resistance to semantic
re-identification needs adversarial evaluation against the stated observer and workload; neither
a general proof nor an implemented cumulative-disclosure gate is claimed here.

### Return Quarantine 

Tomb/Coffin stdout, artifacts, patches, and structured returns are untrusted bytes. They enter only
as provenance-tagged, instruction-fenced blocks in volatile Context layers; structural validation
does not grant them instruction authority. They are scanned for path and secret-scope violations,
but scan results do not execute commands or promote content. Promotion requires separate trusted
admission. The same quarantine applies to assimilated material and A2A returns.

### Refusal, compromise, and evidence

Missing containment, policy observation, revocation, credential separation, resource enforcement,
or audit receipt disables lower-trust execution. Suspected compromise revokes leases and Gate
grants, terminates or quarantines the process tree, quarantines workspace/output, taints associated
work, rotates credentials that crossed the supervisor boundary, preserves bounded secret-free
evidence, and requires trusted re-admission. Uncertain termination, revocation, or effect state is
not success.

Pure policy tests prove compilation, not containment. Containment needs effectful cross-boundary
receipts for mounts, environment and `/proc`, endpoints, descendant cancellation, ceilings,
credential absence, Gate races, quarantine, and recovery. Coffin/Gate policy is Designed; no
hostile-runtime containment or Provider Gate implementation ships. Hostile browser safety and
effectful provider service likewise remain unclaimed according to [State of
Work](../state-of-the-work.md#delegated-agent-execution).

The general Egress Gate additionally needs allow/deny fixtures for every `RemoteTarget`; canonical
wire/export digest mismatch; target, model, peer, runtime, path, and custody-route substitution;
expired Cut/verifier/consent/policy; prohibited categories and unknown recipient facts; replay and
concurrent revocation; nested coding-agent child calls; first-byte enforcement; and proof that no
provider adapter, proxy, or A2A callback can bypass it.

Audit records correlate the admitted job/occurrence, profile, roots, policy and receipt revisions,
Gate decision, measured ceilings, terminal classification, and quarantine handoff. A provider
status message or fluent completion is attribution, not a host-observed effect receipt.

At minimum, privileged host intents, secret provisioning or binding failures, Shadow dispatches,
policy denials, Portal egress and Privacy Cut decisions, and compromise quarantine or revocation
emit structured security events. [Observability](29-observability.md) owns their record shape and
retention.

## Consequences

An unavailable boundary requires refusal, and policy shapes still need containment receipts before
they can support execution. Once delivered, local transformation and gated containment may make
lower-cost remote computation possible without handing the provider raw authority-bearing
context. Economic advantage cannot relax the boundary or justify widening an execution profile.

---
title: "10. Privilege"
plain_name: "Design rule 10: Host privileges"
section: "Covenants"
status: "Operator validation"
original: https://hexanomicon.dev/adr/10-privilege/
guide: https://lychd.snayu.ai/docs/adr/10-privilege/
---

# 10. Privilege (Design rule 10: Host privileges)

## Plain-English summary (Snayu)

**What it is:** Defines how actions that change the host (starting services, writing units) are requested and performed. The server never gets a shell, root or the Podman socket; it hands typed requests to a host-side helper (Host Reactor).

**Why it matters:** Read this before writing code that touches systemd, Podman or host files, or anything needing elevated rights.

- Initialization refuses to run as root; host changes belong to the invoking user and rootless Podman.
- Host tools are trusted only if safely owned and unwritable; all mutating actions share one lifecycle lock.
- State is rechecked under the lock right before change; partial failure triggers one bounded undo.

**Status:** Operator validation. The mediated protocol passes isolated tests; real host transitions still need proof.

## Original text (Hexanomicon)

!!! abstract "Context"
    The Vessel does not receive a shell, Podman socket, user-systemd bus, or general root authority.
    The managed Vessel crosses the Host Reactor boundary for privileged effects. The typed direct
    systemd adapter remains a host-side mechanism exercised by explicit OCI tests, not a
    host-native Vessel deployment. Both accept the same closed transition word; trusted
    construction selects the effect owner without granting the container host control authority.

## Decision: authority before effect

Effectful initialization refuses effective UID 0; root may inspect a zero-effect dry run but does
not acquire initialization authority. Host mutation belongs to the invoking user, its user manager,
and rootless Podman/Quadlet. Layout owns which paths may exist or be retired.

Host tools are never trusted from spelling alone. Discovery accepts only an executable regular
file that is UID-0-owned or lies on a kernel-reported read-only filesystem. Neither the file nor
any ancestor may be group/other-writable or writable by the caller; the resolved absolute path,
device, and inode remain in the authority token. The systemd user-generator search follows
directory priority: the first matching entry wins, and an unsafe, empty, non-executable, or
`/dev/null`-linked entry masks every lower-priority copy.

Binding sites are real non-symlink, invoking-user-owned safe directories. All real
initialization, binding, deletion, direct-systemd actuation, and Host Reactor consumption share one
non-blocking lifecycle lock under `/tmp`. It is opened without following symlinks and must be a
regular caller-owned `0600` file. Dry runs do not acquire or create it; contention is a no-effect
refusal.

Foundation, desired bytes, source and secret generation, tool/site identities, and live
configuration are revalidated under that lock immediately before mutation. A state mismatch is a no-effect
refusal.

`TransitionIntent` is frozen, `extra="forbid"` data: a 32-hex correlation ID, forward or exact
compensation operation, configuration digest, canonical Animator and capability, ordered
evict/launch sets, and exact expected active world. It carries no command, unit name, path,
environment, or arbitrary payload. A host consumer or extension escalation needs an equally closed
typed class, trusted producer and consumer, configuration owner, recovery states, and boundary
tests; extension import grants no host authority.

## The physical transaction

Physical truth comes from observed state. For an admissible transition, the actuator first
validates the word and policy, preflights and attests the loaded Scribe-owned topology, rejects
relevant pending jobs, and compares the exact observed pre-world. It records intent before
actuating generated Animator targets, then obtains terminal readback and attests the result.
Client exit status cannot supply that proof: a successful receipt requires the observed desired
state, making the effect accountable.

The direct `systemd` actuator uses only the injected, attested absolute `systemctl` under the
lifecycle lock. It submits only generated target identities and observes both target reservations
and services. Cancellation and partial failure obtain one bounded inverse transaction. The prior
world reopens admission only when exact readback proves it.

The caged `host-reactor` default gives the Vessel a write-only owner-mode inbox and a read-only
host journal. It publishes one bounded typed JSON intent; the host claims it before parsing through
a no-follow descriptor, independently rechecks schema, ownership, topology, policy, digest, and
world, then acts. The journal distinguishes no-effect decline, completed desired state, proved
restoration, malformed rejection, processing uncertainty, and containment. Claimed work and
containment keep admission closed; terminal filenames never form a writable reply command. This
local file boundary is not remote authentication.

Claim first moves producer bytes into `.acquiring.json`, which never authorizes an effect or
recovery. The host captures a bounded no-follow read into a new private `0600` inode and writes
a separate host-owned, versioned custody companion binding its exact content digest. Both are
durable before `.processing.json` can authorize actuation. A producer-held descriptor or hard
link therefore cannot rewrite admitted or completed evidence. Processing and compensation
reads require matching custody; a marker inside producer-supplied JSON is not custody proof.
Interrupted acquisition without processing is rejected without effect. Missing, legacy, or
mismatched processing custody remains fenced for operator reconciliation; old completed files
without proof cannot authorize compensation and are never automatically certified or replayed.

| Receipt | Meaning | Admission result |
| --- | --- | --- |
| `.acquiring.json` | producer bytes claimed, host custody not yet established | remain closed; reject interrupted acquisition without effect unless durable processing already exists |
| `.processing.json` | claimed work without a terminal physical observation | remain closed |
| `.completed.json` | exact desired world observed | proceed to separate readiness |
| `.declined.json` / `.rejected.json` | no-effect precondition refusal / invalid delivery | fail closed; only a decline may reopen the initial barrier |
| `.restored.json` | exact prior world observed after failure or cancellation | reopen with a typed restored result |
| `.contained.json` | neither desired nor prior world proved | latch containment |

## Materialization and retirement

Scribe's ownership receipt bounds every Quadlet/plain user-unit file that binding may write.
Under the lifecycle lock, binding stages and validates the full generation, rechecks
foundation/sites/secrets/generations, replaces exactly the declared set, and reloads systemd.
Failure restores the previous set. Foreign units, ambiguous ownership, unsafe names, changed
identities, and unknown files cause refusal rather than deletion.

Deletion is a separately fingerprinted, revalidated sequence—quiesce, runtime, storage, unbind,
secrets, filesystem, package, verify. It stops only exact owned units and recursively retires only
init-attested dedicated roots through pinned no-follow descriptors. An exact, init-created
Phylactery Btrfs subvolume may need root; LychD proves mount/device/filesystem/subvolume identity,
prints a narrow trusted root handoff, writes a protected continuation receipt, and never invokes
`sudo` itself. Any ambiguous mount, replacement, interruption, or root outcome preserves evidence
and blocks continuation.

## Containment rule and delivery boundary

Compensation can reopen the prior world only after exact proof of its restoration. When the
physical result remains indeterminate, containment latches and recovery is required; another retry
cannot supply that recovery. Signal authority stays equally narrow: the trusted Vessel alone
writes the Reactor inbox, and the host consumer alone claims it. Tombs, Soulstones, and untrusted
extensions receive neither inbox nor journal.

The mediated protocol and its isolated receipts are available within their stated boundary, but no
repository test proves an operator's Quadlet/Podman/GPU host. [State of Work](../state-of-the-work.md#host-reactor-protocol)
and [its systemd/Podman embodiment record](../state-of-the-work.md#systemd-podman-embodiment) own
that delivery distinction.

## Consequences

Host mutation remains attributable and recoverable, but an uncertain physical outcome deliberately
costs availability until an operator establishes a safe recovery boundary.

---
title: "11. Backend"
plain_name: "Design rule 11: Server application"
section: "Covenants"
status: "Available"
original: https://hexanomicon.dev/adr/11-backend/
guide: https://lychd.snayu.ai/docs/adr/11-backend/
---

# 11. Backend (Design rule 11: Server application)

## Plain-English summary (Snayu)

**What it is:** Decides that the Engine Room (Vessel) is one Litestar web application built once in create_app(), run as a single Granian process and event loop, with HTTP, database, extensions and workers assembled and shut down in order.

**Why it matters:** Read this before adding routes, startup logic or background work to the server.

- src/lychd/app.py:create_app() is the only production composition root; imports must not mutate the app.
- One process, one event loop: blocking code in any callback can stall HTTP for everyone.
- The CLI works without building the web app; extensions contribute typed records, not arbitrary routes or middleware.

**Status:** Available. The server runs; the isolated developer fixture and sandbox plane are separate work.

## Original text (Hexanomicon)

!!! abstract "Context and decision"
    The Vessel is one explicitly composed Litestar application. Its HTTP, persistence, extension,
    and worker collaborators are assembled once, published only when whole, and retired in reverse
    dependency order.

## Decision

`src/lychd/app.py:create_app()` is the production Vessel composition root. It creates one Litestar
application with `AppInit`; imports and route declarations do not mutate a pre-existing app.
Core controllers and the compiled Altar fallback are collected there. Extensions are selected
explicitly, receive a host-created context, and contribute shaped records rather than arbitrary
route or middleware mutation. There is no delivered extension route bundle.

The host Click CLI works without constructing an application graph. Help, `init`, `bind`,
lifecycle commands, and ordinary operator commands do not build the ASGI application. The
`database` command delegates lazily to Litestar, while the managed image owns application startup.

### Process and listener boundary

The runtime is one Granian/Litestar process and one event loop. A shared launcher explicitly owns
the application's lifespan around an embedded Granian no-lifespan ASGI worker. Required startup
or closure failure and unexpected HTTP-worker termination propagate as process failure. The HTTP
worker and every admitted Python ASGI callback, including post-response background work, must
retire before application services close; successful process exit cannot conceal a
failed application shutdown. Signals request ordinary worker retirement and do not certify its
completion. The user manager retains its outer stop-timeout and forced-stop semantics.

The managed Vessel image selects its fixed internal `0.0.0.0:8000` listener behind generated
loopback-only host publication. There is no host-native Vessel launcher, alternative native bind
generation or host Core test deployment. The image entrypoint and `create_app()` preserve the
single-process/no-reload policy and reject unsupported upstream supervisor or alternate-listener
configuration. Existing images must be rebuilt to acquire changed runtime behavior.

The read-only developer fixture also runs in the explicit container test/development image,
with a fixed internal listener and loopback-only host publication. Its test records and security
remain separate from production authority. Direct application construction inside an OCI test
process is an in-process test technique, not another deployment profile.

The old native-only signed-stop profile is removed. Container startup and shutdown still own the
application lifespan and propagate failure; public active installation-stop completion remains
unavailable until its own authenticated container lifecycle is implemented and qualified.

The run-event bus, cancellation coordinator, services, and SAQ workers are process-local. This is a correctness boundary, not a
scalability claim or permission to use another launcher.

## Lifespan and ownership

Production initialization creates the typed Settings generation, selected extension assembly, and
validated Rune registry; installs routes, middleware, framework plugins, and dependency providers;
then enters its lifespan. Startup crosses these boundaries in order:

1. Wait for the Host Reactor fence and connect both queues.
2. Build durable dependencies and services; hydrate runtime registry material off the event loop,
   then obtain any missing initial capability observations before recovery. Metadata-only binding
   does not satisfy readiness; an existing observation is not automatically replaced or made WARM.
3. Recover durable authority, including preauthorization policy, cancellation, terminal evidence
   and checkpoints, orphaned Runs, consent, delegated waits, and pending delivery.
4. Start the maintenance relays, then publish the shared run substrate and `app.state.services`.

Durable startup must recover PostgreSQL authority before admitting work. A failed or degraded
required reconciliation aborts startup before workers can claim work or HTTP can resolve services.
The memory profile permits best-effort reconciliation because it has no cross-process state to
recover; that exception does not weaken durable startup. [Workers (14)](14-workers.md) owns the
exact recovery order and settlement law.

Any failed startup follows the same reverse order as shutdown: stop in-process workers, withdraw
the run substrate, close services, then disconnect queues. A collaborator therefore cannot outlive
what it reads. The application-owned queue plugin constructs both workers without the unused
batched heartbeat thread; Run invocations retain their own broker heartbeat. The required Altar
lifespan is the sole worker retirement owner; the queue plugin registers startup only.
There is no hot-reload contract.

### Isolated developer fixture (Designed)

One explicit developer entry may compose a disposable, read-only fixture for local browser work.
Production remains the default. The fixture is selected before ambient Settings sources, Rune or
extension discovery, or database and SAQ construction can run. It receives explicit Settings,
fresh fixture-only credentials, and empty Rune and extension assemblies; it reads no operator
configuration, secrets, or runtime control files.

The fixture shares the real controllers, dependency providers, OpenAPI, authentication, Host,
CORS, Origin, and CSRF boundaries. An additional admission guard refuses every unsafe HTTP
method before controller or domain admission, including unversioned routes. Valid credentials
do not permit fixture mutations. Reads remain free of execution and host effects. The common
pure server policy still requires one process, one event loop, and the fixed internal
`0.0.0.0:8000` TCP listener behind loopback-only host publication,
refusing reload, extra workers, alternate sockets, and a separate metrics listener. This fixture
grants no VPN, tunnel, or remote access.

Existing memory repositories retain one visibly labelled synthetic conversation and terminal
Run. Bridge and Orb project that same Run and link its exact registered Pattern revision into
Loom. Its terminal status is sample data, never evidence of graph, model, or host execution.
The real service graph receives a refusing implementation through the existing `RuntimeActuator`
port at construction; its queue collaborators also refuse execution. No model or delegated
runtime is registered, and omitted queue or runtime authority is reported unavailable.

A dedicated lifespan owns construction, warming the empty registry, seeding, publication, and
closure. It publishes services only after the fixture is whole, withdraws any publication on exit,
and closes constructed collaborators on shutdown or failed startup. It performs no Host Reactor
admission or durable recovery, connects no queues, and starts no workers or maintenance relays.
All fixture state ends with the process; durable operation retains the production startup and
recovery contract above.

This option admits a development composition, not a deployed Phylactery or production macOS
support. [State of Work](../state-of-the-work.md#current-evidence-envelope) owns its delivery and
receipt boundary; [CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md#browser-development-and-its-backend)
owns the startup and browser workflow when supplied. This design alone establishes neither.

### Where implementation belongs

The application layer owns HTTP admission and dependency wiring. Domain code speaks ports,
repositories, and services; persistence adapters own SQLAlchemy sessions and explicit statements
needed for locking or aggregate transitions. Controllers never issue database queries directly.
The Nexus controller uses a profile-bound request-admission port before it creates a physical
transition task; PostgreSQL owns the cross-process uniqueness transaction while the controller
retains only short-lived ticket projection.
The system layer owns host adapters and lifecycle effects. [Persistence (06)](06-persistence.md),
[Configuration (12)](12-configuration.md), and [Security (09)](09-security.md) retain their
respective transaction, configuration, and trust laws.

## Interfaces rather than rows

The public API is defined by versioned Pydantic or dataclass DTOs and named operations. A true
CRUD projection may use an explicitly bounded `SQLAlchemyDTO`, but its ORM shape must never become
the API accidentally. Includes, exclusions, aliases, nested depth, input rules, SSE envelopes,
and compatibility all belong to tested interface contracts.

Litestar owns typed HTTP/OpenAPI and JSON serialization. Runtime and offline export share one
JSON-only OpenAPI configuration. Controller validation and mapped application/repository failures
retain Litestar's declared JSON shapes rather than an undeclared Problem Details transform;
boundary middleware may still return its own non-API rejection. The static server delivers
compiled Svelte assets, not browser state or templates. Mermaid is sent as inert source for
client-side rendering. Structlog is present instrumentation; an uninstalled OpenTelemetry exporter
does not establish external tracing.

### Captured credentials and database wire values

The production process owns one async SQLAlchemy engine/session factory. Connection and signing secrets load
once with Settings as excluded `SecretStr` fields; consuming components read the captured values
without reopening environment variables or files. [Configuration (12)](12-configuration.md)
owns precedence, explicit reload, and secret-free serialization.
The asyncpg hook registers separate binary codecs: JSONB adds and removes PostgreSQL's version
byte, while plain `json` passes its unversioned bytes directly. Focused hook tests pin both wire
shapes; this is a correctness contract, not a throughput claim.

## Trust boundary and evidence

The Vessel is the trusted control plane: HTTP admission, orchestration, persistence access,
runtime projection, and its static client. Its default browser seam admits literal loopback Host
authorities on the configured external port and detected listener port, same-origin requests, and
only explicitly configured loopback CORS origins. Protected requests additionally require the
dedicated local possession credential before receiving the fixed bootstrap Sigil; Host and CORS
checks alone provide no authentication. This local gate supplies no remote person identity.
Wider browser controls and queue/execution isolation belong to
[Security (09)](09-security.md). Tomb is a designed, not delivered, execution plane; there is no
Tomb queue, executor, credential, mount, sandbox, or promotion authority here. Its delivery
boundary is maintained by [State of Work](../state-of-the-work.md#tomb-untrusted-execution).

Focused tests cover memory-profile composition and web contracts. An HTTP assembly fixture
uses the real factory and security configuration with memory services, without entering lifespan;
it proves Host, credential, CORS, Origin, and CSRF admission, not startup. A disposable two-boot receipt
exercises the real application factory, PostgreSQL, in-process SAQ, and asyncpg installation with an
offline model and HTTP test client; a focused disposable receipt round-trips both plain `json` and
JSONB through the same engine factory. Neither proves a real browser, inference engine, or deployed
host. [State of
Work](../state-of-the-work.md#current-evidence-envelope) owns the evidence envelope.

## Consequences

- Framework upgrades must reprove initialization, dependency injection, serialization, OpenAPI,
  and ordered shutdown.
- Current streaming and cancellation semantics require one process. A multi-process Vessel needs
  durable event and ownership protocols, not a changed worker count.
- Explicit DTOs may deliberately duplicate stable storage facts; migrations do not thereby set
  the HTTP compatibility contract.

---
title: "12. Configuration"
plain_name: "Design rule 12: Configuration"
section: "Covenants"
status: "Available"
original: https://hexanomicon.dev/adr/12-configuration/
guide: https://lychd.snayu.ai/docs/adr/12-configuration/
---

# 12. Configuration (Design rule 12: Configuration)

## Plain-English summary (Snayu)

**What it is:** Defines how settings are loaded: one typed Settings model from lychd.toml in the Settings Folder (Codex), plus validated Service Config Files (Runes) for models and services, all checked before they can generate infrastructure.

**Why it matters:** Read this before adding a setting, a config section or a new kind of Service Config File.

- Precedence is fixed: explicit values, then environment (SECTION__FIELD), then lychd.toml, then file secrets, then defaults.
- Unknown or obsolete fields are rejected; loading is read-only and never repairs or creates files.
- Each process keeps one loaded settings generation; a live config writer is designed separately.

**Status:** Available. Settings and Rune loading work; a live config writer and some selectors are designed.

## Original text (Hexanomicon)

!!! abstract "Context and decision"
    The Codex holds declared operator intent. A single typed Settings root and anchored Rune
    instances are read, validated, attributed, and assembled before they can project infrastructure.

## Settings: one immutable generation

`lychd.toml` is the global Settings document under the Codex. Its only top-level sections are
`server`, `orchestration`, `extensions`, `weaver`, and optional `archive`. `Settings` is the sole `BaseSettings` model; nested
strict `BaseModel` sections reject unknown and obsolete fields. The public Python entry is
`lychd.config.settings`, not its internal section modules.

### Load and retain one generation

Source precedence is fixed:

```txt
explicit construction → environment → lychd.toml → Pydantic file secrets → model defaults
```

Environment names use the root `SECTION__FIELD` grammar. There is no dotenv source and nested
sections do not load separate environment, TOML, or secret sources. Loading is read-only: it does
not create Codex files, repair input, generate credentials, or mutate the environment.
`get_settings()` retains one loaded generation per process. Runtime consumers use its stored
values; they never reopen environment variables or secret files. Reload requires an explicitly
constructed new `Settings` instance or a process restart. `SettingsSnapshot` retains a secret-free
serialized declaration and the already-loaded credentials separately in memory as `SecretStr`.
Each preview/apply phase revalidates its own copy without running settings sources again.

An accepted Settings field needs a real consumer. `server.port` is exposed today, but runtime
policy fixes the managed image listener independently of TOML. The obsolete `server.host`,
`server.reload`, `server.keep_alive`, and `server.web.url` inputs are rejected and omitted from
generated configuration. Launcher flags and environment cannot reintroduce them as Codex intent.

### Current selections

`[extensions]` selects permitted built-in and Crypt packages; it neither selects an application nor
creates a runtime. Settings also owns the fixed `runs` and `rites` physical queues and their
concurrency; routing can name only those queues. Global port claims and Rune port claims are
arbitrated before any unit is written.

The bounded Core Bridge selector uses optional `[weaver.bridge]` to select the registered
`bridge_chat@2`; omission keeps `bridge_chat@1` active. Revision 2 admits exactly one of an exact
`capability_key` or a versioned `preference`. The preference grammar has `schema_version = 1`
and exactly two distinct route entries, each containing a literal canonical registry
`capability_key` of at most 512 characters and a strict integer `weight` from 0 through 1,000,000. Booleans, coercion,
aliases and a zero total are refused. Zero disables that route's eligibility; larger weights rank
first, with ascending canonical key breaking a tie. Weights are unitless ordinal preferences
without normalization, not traffic share or measured quality. Both declarations must satisfy the
local Chat/tools contract in
[Dispatcher](22-dispatcher.md#bridge-preference-at-admission), including a disabled route.

Admission resolves an existing idempotent Run before considering current policy or readiness.
A fresh preference admission retains its immutable policy and weights, canonical policy digest,
safe phase observations, server-observed observation and batch times, closed exclusion codes and
selected exact key in the existing Run intent JSONB before publication. The digest is SHA-256 of
canonical typed policy bytes, including `schema_version = 1`, not a generated JSON Schema
fingerprint. Concurrent admission losers return the retained winner. This metadata is server-owned;
callers cannot supply or replace it. Graph state retains the selected key across pauses; replay
and restart use that key without
another preference selection. A changed Settings generation affects new admissions only.
Retention excludes free probe reasons, endpoints, principals, credentials and authentication
generations. This remains capability identity pinning rather than a durable
executable/declaration-generation fingerprint or the general portable Resolution Lock.

This admission policy preserves the existing `bridge_chat@2` Pattern, calls, tools, consent,
retries and token bounds. It supplies no post-selection fallback. The Altar must explain the
retained policy, observations, exclusions and selection at admission, the absence of fallback,
and the distinct replay/restart and new-admission semantics before this feature is published.
Display neither grants authority nor establishes current readiness. Implementation and delivery
evidence remain owned by [State of Work](../state-of-the-work.md).

An explicit `revision = "3"` selects the read-only Archive answer profile and additionally
requires an `archive` binding with exact `local-public-notes@1` profile, namespace UUID, trusted
local subject, and policy revision. It is valid only with PostgreSQL and the same-host bootstrap
custody profile. The whole binding is retained at Run admission; changed settings cannot rewrite
an admitted casting. This selector grants no remote identity, namespace access, ingestion, or
embedding capability. Intake and promotion remain separate explicit Archive operations.
Revisions 3 and 4 continue to require their exact `capability_key` and their own Archive or Scout
binding respectively; neither accepts `preference`.

### Exact delegated casting selection

Optional `[weaver.delegation]` selects `revision = "2"`, one exact registered `runtime`, and
`profile` (`read`, `candidate`, or `verify`) for new `/delegate` admissions. Omission retains
the effect-free `delegated_rite@1` reference route. The configured revision retains its runtime
binding in Run intent and Graph state; idempotent admission and restart use that retained binding,
not the current Settings generation. Unknown adapter names refuse assembly. Registration and
selection do not establish host readiness, containment, privacy, or permission to launch.

The adapter's trusted host remains responsible for effect-time admission. This selector carries
no command, executable, environment, provider credential, model alias, alternate list, or fallback
switch. A failure, policy refusal, or uncertain start leaves the exact casting in place; it cannot
redirect to another runtime. Provider/Gate configuration and compatible-road fallback require
their own admitted contracts.

### Exact Creation investigation selection

Optional `[weaver.creation]` selects `revision = "2"` and one exact `capability_key` for
`creation.investigation@2` / `creation.investigate@2`. Omission disables its admission. This
bounded application requires PostgreSQL, current local operator policy and its fixed
[public-source profile](../compositions/creation/index.md#admit-one-question). The captured local
shared vLLM/Qwen Chat declaration must match its generation and policy; no alias, fallback,
remote route or hardware transition is supplied by selection.

Creation retains source bytes, criteria, complete role bindings and reservation under its own
case before releasing held Run delivery. Current settings cannot rewrite an existing request;
an eligible explicit continuation retains the same case/profile and its original deadline.
Settings carries neither source/prompt material nor a credential or authority grant. The
application rechecks current credential-backed object/action policy at use. This typed selection
does not introduce a general SDLC coordinator or portable Resolution Lock.

### Exact finite Scavenger selection

Optional `[weaver.scavenger]` selects Composition `revision = "3"` and one explicit `scout`
configuration with `rss-public-feed@1` for the source-built `scavenger.observe_market@2` Pattern.
Omission disables new Scavenger admission while retaining its exact registered Pattern for
historical resolution. The selection requires PostgreSQL and the actual same-host startup
credential owner; settings loading and assembly perform no acquisition, model readiness,
reservation or migration. It accepts no capability key, model, arbitrary source locator,
implementation name or fallback. A separately configured ordinary Bridge remains independent.

The first native profile permits one active Scout binding in a fresh profile database. It cannot
coexist with Bridge revision4's page binding. Existing page/RSS budget rows reject a changed
binding without mutation; changing the selector never resets spent counters or unknown claims.
The profile pins its exact native resolver/custody assertion, CA/extractor runtime, current policy,
finite allowance/host ceilings and review expiry. These are declarations, not containment or
source-publicness evidence. The exact advertised Bazoš PC feed and consumer projection remain
owned by [Scout](30-webcrawler.md) and [Scavenger](../compositions/scavenger/market.md#finite-feed-observation).

The complete supplied campaign seed and initial filter enter Scavenger's protected application
admission, never Settings or a model prompt. Their immutable consumer/digests bind the held Run
before publication. Current application read/filter/delete policy is distinct from acquisition
consent and expiry; configuration cannot refresh a retained grant, refetch lost material, rewrite
a committed field or resurrect a tombstone. Selected assembly, API/UI and deployed evidence remain
owned by [State of Work](../state-of-the-work.md).

### Independent public Archive selection

Optional `[archive]` selects `profile` independently of Bridge. Its profile retains the exact
`local-public-notes@1` schema. Existing `weaver.bridge.archive` configuration remains valid;
when both are supplied they must match exactly, and assembly uses one effective binding.
Omission preserves the existing Bridge selection and disables independent derivation.

Optional `archive.derivation` supplies a generation UUID and an exact Core `EmbeddingBinding`
(capability key, profile digest, `model.embed@1`). The configured registry must admit that local
static profile before assembly succeeds. An HTTP caller cannot provide an endpoint, model,
manifest or fallback. Loading settings and assembling services neither registers a generation
in PostgreSQL nor prepares a model. Explicit authorized registration retains the configured
manifest; explicit derivation requests perform bounded synchronous work.

The derivation Dispatcher shares the application's exact registry and lease ledger but has no
Run event sink. A supplied Run UUID is caller attribution only: it neither establishes a Run
relationship nor permits events or writes to that Run. The existing Graph dispatcher is unchanged.

## Runes: location, provenance, semantics

A Rune is one validated top-level TOML instance in the Codex `runes/` tree, not a runtime object
or generated unit. Each concrete `RuneConfig` supplies one safe `path_fragment`; direct Python
subclassing forms one anchor ancestry, and `relative_path` is computed from it. A fragment is one
segment matching `^[a-z0-9](?:[a-z0-9_-]{0,48}[a-z0-9])?$`. Distinct registered schemas cannot
own the same exact anchor; nested anchors remain distinct and express declared class ancestry.
Nested non-Rune Pydantic value objects may contribute shared validated structure without joining
or branching that anchor ancestry. The delivered `QuadletConfig` is embedded under the `quadlet`
field of Soulstone and Phoenix Runes and shares only the minimum OCI image invariant; it supplies
neither a Rune path nor raw unit, lifecycle, mount, network, secret, or command authority.
Generic sample generation renders required embedded values as typed TOML inline tables; maintained
hand-authored examples may use the equivalent named table form such as `[quadlet]`.
Branch classes are namespaces and cannot own TOML files; only leaf schemas may have one or more
instances. A file's path supplies its identity and `source_file` provenance. Duplicate identity,
files in branch anchors, arrays-of-tables instance encoding, unsafe fragments, and schema
violations abort discovery.

Three terms describe a Rune's location. An **Anchor** owns a directory territory; a **Fragment**
is its safe local path segment; and an **Instance** is one leaf TOML document. The instance carries
provenance into runtime, but provenance is not a TOML field. Validation freezes instances so that
resolvers can derive effective state without changing Codex intent.

Filesystem ancestry names type, not semantic defaults. Named leaf profile instances supply
family-specific defaults; a capability-bearing Rune references profiles and applies local overlays.
Resolvers combine profile, runtime/family defaults, local overlay, then request-time override.
Presets such as a `llama.cpp` router `.ini` are typed, readable references: they tune their runtime
but cannot change port arbitration, coven exclusivity, or host ownership. Upstream precedence is
`CLI arguments > model-specific preset section > global [*] section`; a generated CLI override
that deliberately shadows a preset value must remain visible to the operator.

### General-service declarations and current model blocks

The accepted general-service Rune shape uses first-class `[[capabilities]]` entries. Each entry
references one registered semantic interface and exact immutable profile, declares its permitted
operations and invocation mode, and pins the runtime driver/dialect, conformance evidence, resource
envelope, and containment profile required to make that instance honest. Definitions are typed
Contributions governed by their receiving Core office or Extension Domain and retain the
Registrant's `registrant_id`; an implementation profile separately names its concrete Provider. A
Rune selects those definitions and supplies instance-local endpoint, secret reference, lifecycle,
and explicit overlay values. It cannot redefine their schemas, licenses, or proved limits inline.

Current source delivers only `[[models]]`: models behind one Rune instance with closed families,
input modalities, Chat or Responses surface, tool support, context size, and generation overlays.
Streaming support and output modalities have no configurable v1 fields. Those blocks remain v1
compatibility sugar for exact admitted model-interface projections; non-model services never
invent a `model_id` or generation overlay merely to become loadable. Neither form encodes multiple
Rune instances.

The single `GenerationProfile` owns the common context, output-token, temperature and top-p
overlays. Its optional closed `thinking = "qwen3.8-non-thinking"` policy is model-local: only an
explicit `[[models]]` generation block for local vLLM `Qwen3.8-27B` on the Chat surface may select
it. Runtime defaults, Soulstone-wide defaults, Portals and other model/runtime/surface combinations
refuse a non-null policy before publication. Omission preserves the existing request. This is one
admitted self-hosted chat-template dialect, not arbitrary provider settings or model-name inference.

For the current v1 path, capability synthesis begins with text input. Field precedence
is Rune hint, then live probe or adapter-discovered runtime fact, then runtime profile default. An
explicit modality hint replaces discovered and default modalities; when omitted, probed modalities
may enrich the runtime base. In v2, open facts are profile-specific and a live probe may establish
readiness but never invent an interface, operation, language, format, dialect, or permission.
[Dispatcher (22)](22-dispatcher.md) may verify a declared capability only by downgrading it.

## Extension activation and application selection

Selected extension registration shims add `RuneConfig` types to `context.runes`; the loader is
given that explicit schema list and never scans packages. A `Configurable` extension registers its
schema through this contract, then separately registers any runtime definition or adapter in its
own domain store. Importing a package does not register it; registering a schema does not create a
service. Extensions cannot introduce custom loaders, source precedence, parsers, or `type=`
dispatch. [Extensions (05)](05-extensions.md) owns compatibility tiers.

The complete preauthorization Rune generation is validated before durable reconciliation.
Duplicate slugs fail deterministically, and an incoming Rune cannot replace a row whose durable
owner is not `codex:rune`. Only after those checks may one transaction refresh Rune-owned rows,
retain their usage and operator-enabled state, mark absent Rune-owned policies unavailable, and
publish newly admitted policies.

## Realization and the writable Codex

`init` and `init --dry-run` derive the same `LifecyclePlan`. The real command rejects UID 0,
inscribes missing anchors and inactive leaf samples, and must round-trip a generated Settings TOML
through fresh validation. Marked samples are ignored until their marker is removed. `bind` first
uses one immutable Settings/extension/Rune generation to compile declarations, then revalidates
the foundation, secret presence, generations, and receipts under the lifecycle lock immediately
before mutation. A content-identical reconciliation is a no-op; an indeterminate mutation keeps
recovery evidence. [Layout (13)](13-layout.md) owns path creation, locks, receipts, and filesystem
attestation; [Privilege (10)](10-privilege.md) owns trusted host executables and their permissions.

Assembly proceeds from Settings to selected schemas, then to discovered and validated Rune
instances. It enforces identity, domain policy, and ports before projecting exact Scribe-owned
units. Downstream registries consume that generation rather than reopening the Rune filesystem.
Read, syntax, and schema-validation failures identify the source file; schema failures also retain
their field diagnostics and original validation cause.

A sanctioned live Codex writer is designed separately from current sample writing. It must stage a
typed request, validate the complete staged tree as bind would, atomically rename only after that
validation, and use an explicit reload signal. It has no ambient authority from Smith or Altar.
Core promotion needs live HitL; a narrower preauthorization must be expressly lawful. No hot
reload is delivered. [State of Work](../state-of-the-work.md#smith-forge-promotion) records this
path as Designed.

## Secrets, privacy, autonomy, and projections

Codex stores only secret references (including `*_secret`), never values. Settings sources resolve
the database password and application signing key once during construction into excluded,
non-repr `SecretStr` fields. Explicit construction and root-grammar environment values take
precedence over the existing `LYCHD_DB_PASSWORD` / `LYCHD_APP_SECRET_KEY` environment aliases,
then their `*_FILE` paths, then `/run/secrets/<declared-name>`. TOML credential values are rejected.
An absent default mount leaves the credential unset so host `init` and caged `bind` can run before
provisioning; database/web assembly rejects unset runtime credentials without further I/O.
Explicit file overrides must be readable and nonempty at Settings construction. Nested settings
models perform validation only; explicitly supplied section instances are complete overrides.
Bind preflight requires the Codex secret file to be Magus-owned with
group and other permissions closed. Generated caged units use file form and scope mounts to the
unit that needs them. Filesystem permissions do not isolate code within that unit.

### Retired native credential selection 

The host-native `LYCHD_RUNTIME_SECRETS=podman-core@1` Settings source and its capture/provenance
fields are retired. Explicit use of that selector refuses before credential I/O rather than
falling back to another owner. Container startup consumes its narrowly mounted `/run/secrets`
inputs through the ordinary sources above. The host operator's trusted Podman secret adapter
retains its separate bind/access responsibilities; it is not application startup credential
transport. No replacement source, automatic conversion, rotation or credential export is added.

### Policy and derived projections

In the accepted design, Codex also sets the privacy/egress baseline (thresholds, anonymization requirement, destination
and purpose eligibility, non-declassifiable categories, transformer/verifier profile, receipt
lifetime, revision) and autonomy baseline. The designed Policy Ward rejects adaptive Phylactery state that
is more permissive than Codex. Absent explicit authorization, effects require HitL or are denied;
confidence does not authorize core promotion, migrations, destructive deletion, secret changes,
egress broadening, host authority, excessive spending, or cross-identity memory sharing.

Vessel configuration is the source of truth. A future Tomb envelope is derived, secret-free, and
cannot alter queues, network, mounts, privacy, autonomy, approval, or authority. Tomb receives no
Codex mount. [Security (09)](09-security.md) owns credentials and isolation; the Tomb delivery
boundary remains [Designed](../state-of-the-work.md#tomb-untrusted-execution).

## Future selectors

### Application and Gateway profiles

Any further application selector requires its own accepted Spellweaver schema and
may resolve only one registered exact profile revision, such as one of the mutually exclusive
[Reach deployment profiles](../compositions/reach/deployments/index.md). In Reach, for each
Discord application and Habitat partition, that immutable selection binds one authority epoch,
one Discord edge epoch, one
active Phylactery, one Gateway/delivery credential owner, and the exact per-host role set. Unknown
mixtures and boolean authority switches such as `trusted`, `use_vps`, `local_db`, or `tether`
fail before Bind. The selected profile contributes no raw units: one immutable generation resolves
its exact Composition/Pattern revisions and registered service roles into the
[`ApplicationDeploymentManifest@1`](08-containers.md#versioned-application-deployments), then
revalidates global ports, routes, secrets, mounts, migrations, dependencies, and resource policy
before Bind.

A change of profile or authority location requires a typed Evolution effect. Settings reload
cannot perform it. The transition quiesces admission, settles or preserves external-effect
identities, fences the old epochs, and revokes old routes and credential owners. Where authority
moves, it transactionally restores an admitted partition. Only then does it activate the new
generation; an old or simultaneous generation fails closed.

Gateway placement follows the same exact-profile law. [Home and Remote](../sepulcher/gateway.md)
are reference placements of one separate Gateway Host role, not applications, Extension
Domains, or free configuration literals. A selected deployment profile either omits that role or
binds its exact per-host manifest, Veil routes, optional Tether generation, backend identity,
service Principals, edge secrets, firewall and management boundaries, and recovery contract.
Loose fields such as `gateway=true`, `rpi`, `vps`, or an arbitrary proxy target cannot assemble a
partial edge.

### Palette configuration

Presentation configuration obeys the same typed-source law when it is admitted. In particular, a
future [Altar palette](15-frontend.md#canonical-appearance-and-bounded-palette-configuration) may
enter only through an explicitly owned validated Settings field or another Covenant-owned typed
source with declared precedence; it is never an unmodelled TOML table, raw CSS file, selector, or
extension side channel. Frontend owns the finite semantic colour roles and accessibility rules,
while Configuration owns loading, validation, attribution, and immutable generation. Current
Settings contains no palette field and changing the accepted root shape requires an implementation
and State update.

### General casting selection

A future [Spellweaver configuration-to-casting selector](28-workflow.md#configuration-to-casting-spine)
follows the same root-shape law. Local TOML may select exact already-registered Scroll, Spell
implementation, `AgentSpec`/Posture, and Context projection revisions plus bounded policy, with the
Agent references resolved only through an exact placement; the portable Scroll remains canonical
JSON. Configuration never names Python imports, BaseNodes, graph edges, callables, prompts, source
bytes, credentials, or live handles, and it cannot turn schema registration into executable
activation.

---
title: "13. Layout"
plain_name: "Design rule 13: Folder layout"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/13-layout/
guide: https://lychd.snayu.ai/docs/adr/13-layout/
---

# 13. Layout (Design rule 13: Folder layout)

## Plain-English summary (Snayu)

**What it is:** Defines where LychD keeps files, following XDG: Settings Folder (~/.config/lychd), Data Folder or Crypt (~/.local/share/lychd) and a disposable build cache (~/.cache/lychd), and which paths it may create, change or delete.

**Why it matters:** Read this before writing code that creates, moves or deletes files on the host.

- src/lychd/system/constants.py is the executable path contract.
- LychD never recursively owns shared XDG parent folders; it removes only identities it recorded creating.
- The Data Folder holds PostgreSQL data, triggers, snapshots, lab and extensions; the cache is disposable.

**Status:** Partial. The CLI path works; real-host lifecycle proof is still pending.

## Original text (Hexanomicon)

!!! abstract "Context and decision"
    XDG geography tells LychD where an object belongs; typed creation and binding receipts decide
    what it may later change or remove.

## The three domains

`src/lychd/system/constants.py` is the executable path contract. `~` is the effective LychD
user's home. Shared XDG parents are never recursively owned by LychD.

| Domain | XDG root and default | LychD root | Purpose |
| --- | --- | --- | --- |
| Codex | `XDG_CONFIG_HOME` or `~/.config/` | `~/.config/lychd/` | `lychd.toml`, lifecycle receipt, Runes |
| Crypt | `XDG_DATA_HOME` or `~/.local/share/` | `~/.local/share/lychd/` | durable data, triggers, PostgreSQL, Lab, Core, Extensions |
| Forge | `XDG_CACHE_HOME` or `~/.cache/` | `~/.cache/lychd/` | disposable assembly staging |

The Codex contains `lychd.toml`, `.lychd-lifecycle.json`, and `runes/` including the Animator,
Soulstone, and Portal anchors. The Crypt contains the Vessel's `runtime-guard`, `triggers/inbox` and `triggers/journal`,
`postgres/init_db.sh`, `postgres/pg_hba_v1.conf`, `postgres/data`, `snapshots`, `lab`, `core`, and `extensions`.
`postgres/data` may be an ordinary directory, external mount, or LychD-created Btrfs subvolume.
The Forge contains `assembly`. [Configuration (12)](12-configuration.md) owns what these paths
mean; Security owns credentials and network policy.

Binding takes place in shared host namespaces: `~/.config/containers/`,
`~/.config/containers/systemd/`, `~/.config/systemd/`, and `~/.config/systemd/user/`, with XDG
overrides applied. The lifecycle and Scribe receipts identify exactly which names and objects
LychD owns there. These regular, non-symlink, invoking-UID-owned `0600` files grant no authority
over the shared parents.

## Creation, binding, and deletion authority

`init --dry-run` describes a plan without mutation; `init` journals only successful creation
identities. At the shared binding sites, init creates missing components as `0700` and preserves
safe existing modes. Planning and execution refuse symlinks, non-directories, foreign ownership,
unsafe effective access or group/other writability, and unsafe ancestry (except an appropriate
sticky root/invoker-owned directory or a foreign read-only mount). `bind` applies the same
binding-site law while planning and committing, but never creates a missing site. The
per-UID/per-Codex lifecycle lock is under fixed host `/tmp`, not caller-selected `TMPDIR`.

The exact existing PostgreSQL `data/` leaf is a preservation-only exception to host-UID
ownership: rootless PostgreSQL may own it through a subordinate UID. Init verifies its real,
host-owned parent through no-follow descriptors and observes the leaf without entering it;
neither may be group/other-writable. It neither changes that ownership or mode nor adopts the
leaf into ordinary directory deletion authority. This observation proves safe preservation,
not container access, database readiness, or permission to repair an arbitrary foreign directory.

### Publish an owned object

Every traversal is descriptor-relative and no-follow. A missing component is made under a private
same-directory staging name, opened and device/inode-attested, then atomically published without
replacement. The receipt records the opened identity and parent descriptor authority rather than a
replaceable pathname. File publication follows the same rule: write and `fsync` a candidate,
publish no-clobber, re-attest through the pinned parent, `fsync` the directory, then journal. A
race winner, replacement, ambiguous result, or failed journal is preserved or quarantined as typed
recovery; it is never broadened into deletion authority.

The Designed [Reliquary profile](06-persistence.md#reliquary-custody-designed) binds an explicitly
supplied isolated private root to its exact owned identity; it introduces no implicit Crypt path
or container mount. Artifact identifiers and producer labels never supply unchecked path
components. Reads and publication re-attestation use nonblocking, no-follow opens and verify the
opened inode before reading. Payload retirement follows a durable tombstone and exact identity
attestation, then namespace sync. Unknown names, extra hardlinks, replacements and interrupted
outcomes remain recovery evidence rather than deletion authority.

### Retire only recorded identities

After a complete transaction, the receipt may adopt the exact device/inode identities of the
dedicated Codex, Crypt, and Forge roots. Shared XDG parents, mounts, source checkouts, and external
model shelves remain outside that grant. `del` is a separately confirmed destructive lifecycle:
it joins receipt authority to a live inventory, stops managed installation state, and refuses
unknown mounts, identity mismatches, invalid receipts, foreign objects, or ambiguous ancestry. Recursive
walks reject mount crossings and possible Btrfs root/stub signatures. Deletion moves a
re-attested leaf to a collision-resistant private sibling before type-specific removal; mismatch or
failure restores it when possible, otherwise leaves a typed recovery marker. Published init
creations are never pathname-deleted as rollback.

## PostgreSQL substrate

Only an absent PostgreSQL `data/` target on trusted Btrfs may receive a new subvolume and `+C`
attempt. Creation addresses the leaf through its inherited parent descriptor. Identity observation
uses a bounded, fixed read-only helper with only the opened leaf descriptor: it requires a real
Btrfs root directory and a supported kernel ABI before reading its own UUID and ID through
`BTRFS_IOC_GET_SUBVOL_INFO`. No privileged path or snapshot lookup is required. No-COW mutation
and before/after confirmation remain descriptor-bound. A successful subvolume records canonical
UUID and non-reserved ID as well as device/inode in the version-2 lifecycle receipt. Existing
storage is never retrofitted; `+C` is only an inheritance policy and a false result is a warning.

Retiring a subvolume requires identity established at creation; observing an existing subvolume
cannot adopt it or fill in a missing identity. A mounted Phylactery requires complete live mount
and Btrfs agreement. An unmounted one requires the exact version-2 creation receipt, matching
live identity, and a safe top-level mapping. Once those checks succeed, LychD emits the attested
`btrfs subvolume delete --subvolid ID TOP_LEVEL` operator handoff and waits for proven absence
before generic retirement. It never invokes `sudo`.

## Host and container geography

The Vessel uses identical host/container targets: Codex is read-only; `lab` and `runtime-guard` are read-write; `core`
and `extensions` are read-only; and when selected, Reactor inbox is read-write and journal is
read-only. PostgreSQL data belongs to its PostgreSQL unit; there is no blanket Crypt mount.
`~/work/` is an explicit read-write Outland mount and never gains Three-Domain lifecycle authority.

Tomb's reserved task, workspace, artifact, and cache targets sit beneath
`~/.local/share/lychd/tomb/`, but it receives no Codex and no trigger/signalling path. Its envelope
is secret-forbidden. This is a designed trust delta, not an executor: [Security (09)](09-security.md)
owns its credentials/network/isolation and [Workers (14)](14-workers.md) any executor.

## Consequences

XDG overrides relocate roots while preserving relative topology and ownership law. Knowing an
object's location helps find it; only the appropriate ownership evidence permits adoption,
overwrite, or deletion. The implemented CLI path is Partial, with real-host lifecycle proof still
separate. [State of Work](../state-of-the-work.md#core-cli-rites) owns that maturity boundary.

---
title: "14. Workers"
plain_name: "Design rule 14: Background workers"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/14-workers/
guide: https://lychd.snayu.ai/docs/adr/14-workers/
---

# 14. Workers (Design rule 14: Background workers)

## Plain-English summary (Snayu)

**What it is:** Defines how jobs run: each job is first recorded as a Job Record (Run) in the database, then executed by in-process SAQ queue workers (Ghouls). Waiting, cancelling and crash recovery update that record rather than trusting the queue.

**Why it matters:** Read this before touching job execution, retries, cancellation or anything that waits for approval or hardware.

- Two fixed SAQ workers (runs and rites) run inside the one server process; a blocking task can impair HTTP.
- Each delivery claims exactly one step; duplicate or stale deliveries are skipped.
- On startup, reconciliation repairs orphaned work; approval waits survive restarts, live hardware waits do not.

**Status:** Partial. Local runs work; some failure-custody and recovery paths are not yet built.

## Original text (Hexanomicon)

!!! abstract "Context and decision"
    A Run ledger records the work before SAQ sees it. Each delivery claims one exact hop; waiting,
    cancellation, cleanup, and recovery move that ledger rather than trusting a queue result.

## Topology and limits

A Run is the canonical workflow record. A worker is the long-lived SAQ engine, and a Ghoul is
one task invocation; several sequential Ghouls may carry one Run. Queueing lets that work outlive
a request without providing process isolation.

The Vessel runs two fixed PostgreSQL SAQ workers, `runs` and `rites`, in its single process and
event loop (`separate_process=False`, no SAQ server lifespan). The application constructs these
workers explicitly and does not register the raw Litestar `workers run` process launcher.
The unused optional batched heartbeat manager is disabled at construction; the live Run
heartbeat below remains invocation-owned. Both use SAQ's separate autocommit
pool and tables; Run, Step, checkpoint, consent, and delegated-job records remain LychD data.
Lifespan connects queues before publishing the run substrate and disconnects them in reverse order
after workers stop. Per-queue concurrency is bounded, but it is not an admission quota, CPU cap,
memory limit, or producer throttle for slow subscribers. A blocking Ghoul can impair HTTP and an OOM or
interpreter crash kills the Vessel.

| Queue | Default source | Registered work |
| --- | --- | --- |
| `runs` | Bridge and CLI workflows | `perform_run` |
| `rites` | background workflow intents | `perform_run` |

These are physical delivery lanes, not Spellweaver service classes. A future `foreground`,
`deadline_windowed`, or `spare_capacity` admission may be delivered through either lane or another
bounded topology; queue name, source, worker concurrency, and scalar priority cannot substitute for
the persisted temporal contract. Work that is not yet eligible must remain with Spellweaver's durable
Occurrence truth rather than occupy a Ghoul while sleeping for its window.

`reconcile_runs` is called directly by lifespan startup with its captured boot cutoff. It is not
registered as broker-callable work, because an invocation without that process boundary could
misclassify live current-boot Runs as orphans.

Tomb still has no delivered queue, executor,
credentials, workspace, or cancellation protocol. [State of Work](../state-of-the-work.md#tomb-untrusted-execution)
owns that delivery boundary.

## Admission and exact claim

`RunEngine.submit()` is the sole admission path:

1. `WorkflowRegistry` selects the Pattern and `QueueRouter` chooses queue and doctrine priority.
2. One transaction records the canonical `QUEUED` Run and exact `RunDelivery` at sequence zero.
   The delivery is `HELD` when caller-owned admission context must still be retained; otherwise it
   is `PENDING`.
3. Any optional caller-retention hook completes, then atomically releases `HELD` to `PENDING`.
   Failure, including an error learned while the caller itself is cancelled, settles only that
   exact unpublished held generation. A release error is resolved from durable delivery state:
   an already advanced delivery remains admitted, while only a proven `HELD` delivery may fail.
4. The engine opens the local event channel and publishes `perform_run` under
   `run:<run_id>:<enqueue_seq>`; broker acknowledgement moves the delivery to `PUBLISHED`.

### Idempotent admission and session order

A surface may supply one scoped idempotency key. The ledger derives a server-owned deterministic
Run UUID, atomically creates Run plus delivery once, and returns the prior admission only when its
session, prompt, source, Sigil, scopes, content, and requested priority still match. Topology A
single-flights concurrent same-key retention and publication; PostgreSQL primary-key conflict
resolution provides durable cross-request convergence. Key reuse for different work fails closed.

Before returning, a replay classifies the prior exact delivery. An unresolved `HELD` admission is
re-retained through the caller's idempotent context hook and released; a held admission with no
retention owner fails loudly. No successful handle may leave custody stranded. An exact `PENDING`
delivery is published again before replay returns, while an already published or claimed hop is
only observed.

The returned Run and retained turn remain the canonical admission. Replay does not consult the
current workflow router, so a later registry generation cannot invalidate already admitted truth.

Bridge additionally requests a Topology-A session fence. The process-local admission coordinator
serializes that session's admission decision, permits an exact idempotent replay, and otherwise
refuses a second nonterminal Run through a bounded ledger lookup. Durable terminal Run truth
releases the policy naturally; no process-local active-session marker becomes recovery authority.
This is a one-process conversation causality rule, not a cross-process quota.

### Publication and exact-hop claims

Run plus delivery intent are transactional; PostgreSQL plus SAQ publication are not one
distributed transaction. A broker error or caller cancellation after durable admission leaves the
Run `QUEUED` and its exact delivery recoverable. The process-owned relay probes the idempotent job
key and republishes the same hop when absent. It never guesses a new resume mode from Run status.
Migration 0004 refuses any legacy nonterminal Run because old rows cannot reveal whether their
current hop was fresh or resumed; it does not synthesize history. The migration holds an
`ACCESS EXCLUSIVE` lock on `run` through that refusal check and its transactional DDL so an old
writer cannot create ambiguous work between inspection and outbox installation or removal.

SAQ receives the Run id and exact sequence; it rebuilds all state and authority from the ledger.
The legacy broker `resume` argument remains accepted but is ignored: the claimed `RunDelivery`
owns fresh-versus-resume truth. `perform_run` waits at the global claim gate, then atomically claims
only matching `QUEUED` status and sequence as `RUNNING`. A stale or duplicate delivery returns `skipped`.
The claim moves that exact delivery to `CLAIMED` in the same transaction. Terminal settlement is
fenced by the claimed sequence and settles its delivery; an old Ghoul cannot rewrite a later hop.
`started_at` records the Run's first successful claim and remains stable across resume hops, so boot
ownership is not rewritten by later deliveries.

The worker also verifies the pinned Pattern and, for a resume, the typed checkpoint and its current
wait owner before the first native builder station runs. LychD's serial adapter owns persistence;
upstream builder scheduling does not authorize checkpoint replay. Decodable pending/running/error
history does not replace a created resumable cursor. `retries=0`;
`timeout=0` disables only SAQ's generic wall clock, while each operation retains its own bound.
Each Run job carries a 120-second SAQ heartbeat and its live invocation refreshes broker `touched`
truth every 30 seconds until the hop returns. This makes abandoned active jobs sweepable without
putting an arbitrary wall-clock limit on a valid graph.

Doctrine priority is 0–100, higher first. PostgreSQL SAQ dequeues lower values first, so the
enqueue edge writes `100 - priority` exactly once. Priority does not preempt an active Ghoul.
Both configured routing rules and explicit `Intent.priority` overrides validate the same range.

### Failed claim acknowledgements

Within Topology-A, one per-Run guard remains held from the authoritative unclaimed
prestate through the claim attempt and any failed-acknowledgement resolution. An
outer `QUEUED` read is only a fast rejection; it supplies no ownership proof.
PostgreSQL establishes the prestate in the same transaction that will claim the
Run, under [Persistence's exact row order](06-persistence.md#atomic-claims-and-checkpoints).
The memory adapter checks and mutates without an intervening await.

Both adapters apply these prestate rules:

| Current prestate | Outcome |
| --- | --- |
| Run absent | Acknowledged skip; no attempt. |
| Well-formed Run with another sequence or a known non-`QUEUED` status | Acknowledged skip; an old delivery is not required. |
| Exact `QUEUED` Run with exact `HELD` delivery | Acknowledged skip; admission has not released it. |
| Exact `QUEUED` Run with exact `PENDING` or `PUBLISHED` delivery | Establish the unclaimed prestate and enter one claim attempt. |
| Malformed Run status, or exact `QUEUED` Run with missing, malformed, or inconsistent delivery authority, including `CLAIMED` or `SETTLED` | Fail before mutation; no observer or settlement. |

The last rule deliberately makes corrupt delivery authority an invariant failure.
It grants no terminal, containment, or checkpoint-deletion authority.

The ledger returns one immutable, invocation-local outcome: acknowledged win,
acknowledged skip, failure before mutation, or failure after entering the attempt.
It records entry into the attempt immediately before the first mutation or mutating
await, after proving the prestate and before any write can occur. The complete
outcome covers the operation, commit, and session exit, retaining original body
and cleanup errors. Callers inspect its explicit fields; there is no Boolean
compatibility facade, mutable receipt, durable token, or ownership registry.
The worker directly awaits this boundary inside its existing shielded claim task.

Recovery requires the attempt fact and an eligible interruption. Each retained
body and cleanup error must independently be an ordinary exception, including an
ordinary exception group, a direct cancellation, or a whole cancellation group
admitted by the terminal-settlement rule. A fatal leaf in either error forbids
observation, containment, settlement, and Graph execution. A later cleanup error
has outward precedence, retaining the original body error and its existing causal
chain; otherwise the original body error propagates. Groups remain unsplit.

Only after the original mutating coroutine has completed with its failed outcome
may the worker invoke the exceptional observer. Under the uninterrupted guard,
its fresh transaction must resolve the exact Run and delivery together:

| Authoritative observation | Permitted result |
| --- | --- |
| Same sequence, `RUNNING` Run and `CLAIMED` delivery | This guarded attempt won. |
| Exact cancellation or terminal authority | Relinquish to its existing owner. |
| Same sequence, `QUEUED` Run and `PENDING` or `PUBLISHED` delivery after the prior transaction is fenced | This attempt did not acquire durable ownership. |
| Successor, park, inconsistent or missing proof, failed observation, or expired observation budget | Unresolved; preserve that state and acquire no authority over it. |

A proved interrupted winner never enters Graph. Release the observation guard
before invoking `_settle_interrupted_claim`, which rechecks the exact generation
and may reacquire the guard for containment. Only the owner of the terminal commit
emits terminal evidence. Loss or unresolved proof permits no containment, terminal
write, checkpoint deletion, or later unguarded adoption.

Caller cancellation continues waiting for the shielded claim task's actual
outcome. A claim-operation failure retains precedence over caller cancellation;
successful settlement or relinquishment propagates the elected original
interruption without replacing its causal chain. A resolution failure propagates
with the elected interruption retained in its causal chain and grants no ownership.
Settlement-helper failure retains the existing outward precedence and context rules.

The observer's deadline does not bound the original claim operation. This contract
never abandons a live mutating coroutine or releases its guard while it could issue
another claim command. It provides no cross-process attribution or automatic retry.

## Events, settlement, and waits

`perform_run` alone drives Graph execution and publishes semantic lifecycle events. Replay and each
live subscriber queue retain at most 256 events. A cursor outside replay or a live reader that falls
behind receives one `resync` boundary at the current cursor; its authoritative snapshot replaces
everything through that boundary before live tailing continues.
An ordered asynchronous tee writes non-token events to Step rows; token deltas are live-only and
settled text belongs in the session record. Terminal paths wait for that run's writer chain before
closing their channel, so recovery does not report completion while its terminal Step is merely
scheduled. A failed Step append is surfaced at that barrier but cannot roll back already committed
Run truth, so this evidence remains `durable_best_effort`, not a transactional event outbox or
durable live stream.

The bus detaches mutable event metadata at every replay, subscriber, snapshot, and persistence
boundary. All waiters on one failed writer generation observe the same latched failure. If terminal
evidence persistence fails, the closed process-local channel is discarded; startup or a later
single-flight repair confirms canonical terminal truth, starts an explicit fresh writer generation,
seeds a fresh sequence, and retries the missing Step exactly once.

### Terminal settlement

Normal return, failure, and cancellation settle the claimed status/sequence under shielding.
Early refusal for an unavailable Pattern or missing checkpoint also contains correlated effects
before committing failure.
Terminal Run state commits before contextual release and best-effort stasis deletion. The channel
accepts one terminal `DONE`, rejects later events, then closes after subscribers drain or grace
expires. Cleanup failure cannot conceal terminal truth.

A cancellation exception group, including nested groups with ordinary failures, follows the same
exact-claim settlement and cancellation-election rules. Successful settlement or relinquishment
propagates the original unsplit group. If settlement itself fails, that failure propagates with
the original interruption as context; unresolved containment retains nonterminal truth. Groups
containing other process-control exceptions remain outside this cancellation rule.

Within Topology-A, claims, durable park commits, and worker failure containment share a per-Run
process-local guard. Failure re-reads the exact sequence and active status before touching child
or consent authority and holds the guard through containment and settlement. A stale Ghoul cannot
cancel a successor's effects, and a committed park survives a lost commit acknowledgement.
Resume publication occurs outside the guard. API cancellation uses its durable `CANCELLING`
fence independently, so waiting for broker abort does not deadlock the worker's acknowledgement.

### Durable consent, delegated and peer waits

Consent and delegation release their Ghoul but retain the Run. Consent persists the checkpoint and
Consent row before one Run transaction verifies that authority, parks `AWAITING_CONSENT`, and
settles the claimed delivery while storing the exact owner in `Run.consent_id`. Startup recognizes
the narrow crash window after checkpoint plus Consent but before that park only when the first
resumable node snapshot binds both the same Run id and the exact latest non-cancelled consent id;
parking then makes that id authoritative. An already decided owner is parked and then re-fired.

The same exact-state rule recovers a checkpointed delegated job before its Run park. Delegation
parks atomically `AWAITING_DELEGATE` with its exact `AgentJob` owner.

A verdict or terminal job CASes status/owner and creates the next `PENDING`
delivery in one transaction. That transaction re-reads the exact persisted Consent owner and
requires decided, non-cancelled truth with a decision principal and timestamp, or re-reads the
same-run `AgentJob` and requires a shape-valid terminal result matching that job and status. The generic
status writer cannot move either wait state back to `QUEUED`; only the owner-specific CAS may do so.
Both consent verdicts resume and Graph reads the durable decision.

The Run's consent, delegated-job and peer-task pointers identify its single current durable wait,
not history. Each park sets its exact owner and clears the other pointers atomically; the related
Consent, AgentJob, peer custody and event records retain history. That single owner survives
re-admission and claim.
Before the first restored node executes, the worker requires its station kind and checkpoint
owner id to match the Run's current owner. Missing, ambiguous, or stale bindings fail without
executing the checkpoint. Switching between wait kinds therefore cannot resurrect a historical
approval or job. In-process hardware re-entry after this check does not reconsume the wait owner.

Concurrent handlers converge. Publication failure leaves the new `QUEUED` hop for the relay; no
wait state is recreated and no possibly published key is reused. Delegation additionally requires
terminal truth for the same job.

The [native public peer station](26-a2a.md#native-public-peer-station) prepares its immutable task
without contact, checkpoints it, then parks `AWAITING_PEER`. Only that committed owner may send.
Its owner-specific CAS rereads canonical same-Run task and admissible terminal/disposition under
current authority, creates one successor delivery and refuses generic wait-to-queue writes.
Exact created checkpoint recovery follows the consent/delegate pre-park rule; prepared rows alone
never authorize replay. A bounded relay exits each iteration and holds no Graph capability lease.

Consent and delegate re-admission remain cancellable: interruption before their atomic transaction leaves the
wait; interruption after commit leaves the exact pending delivery for recovery. Optional broker
error diagnostics do not defer cancellation. Required containment of a late published job retains
its separate cancellation shield.

### Live hardware waits

During hardware stasis, the Run keeps the same Ghoul. That Ghoul checkpoints, marks
`AWAITING_HARDWARE`, awaits a bounded orchestrator transition, returns to `RUNNING`, and resumes
from persistence. It holds no capability lease while waiting but continues to occupy its worker
task, unlike a durable consent or delegated wait.

## Cancellation, mutation, and recovery

### Cancel and contain

API cancellation elects one process-local writer, locks the Run, and commits nonterminal
`CANCELLING` to freeze its exact delivery generation. The broker parent job is abort-fenced first;
only after that acknowledgement does the engine make its final bounded sweep of every correlated
delegated job and pending Consent, so the parent cannot create an effect behind the sweep. All must
acknowledge containment before the fenced `finish_cancel` transaction can expose `CANCELLED` and
settle that delivery. Failed, timed-out, or cancelled containment leaves honest, retryable
`CANCELLING`; startup retries it
with authority to fence a pre-boot SAQ job. Only after terminal truth does the engine persist
terminal evidence, close the channel, and best-effort delete stasis. Re-reading an already
`CANCELLED` Run repeats the child/consent sweep before repairing evidence and cleanup debt.
A Ghoul observing its exact generation in `CANCELLING` releases volatile execution resources so
the broker can acknowledge containment, retaining its durable checkpoint until terminal commitment.
An interruption before that commit waits only for the local election or leader failure, then re-reads durable truth; it never waits for full API settlement, which may
itself need that worker to exit. If election failed, the worker may attempt its exact-generation
`FAILED` transition. Completion may win before election and makes cancellation an idempotent
no-op. This coordination is valid only in the one-process topology.

Sovereign peer work has a narrower local obligation: durable closure of result adoption for every
bound task and actual retirement of all Run-owned local exchanges must acknowledge before terminal
cancellation or orphan failure. That closure does not require remote authentication or a foreign
task id. After it and all ordinary local containment succeed, local `CANCELLED` may commit while
retaining explicit remote outcome uncertainty. Remote cancellation is separate bounded
reconciliation and asserts no process containment or rollback; an unreachable sovereign cannot
retain local continuation authority. This exception never applies to AgentJobs, owned children,
managed service execution or unresolved local cleanup. Retained peer debt survives terminal
checkpoint deletion and is visible through an authorized status projection.

### Close admission before mutation

Runtime mutation closes affected capability lease admission and the global pre-claim gate, then
waits for those exact leases to drain. `pause_queues()` is only that gate: SAQ may still dequeue a
task which then waits before ledger claim. Queue depth and
worker count do not prove quiescence. Pre-effect drain timeout, cancellation, or failure reopens
the gates. A submitted mutation reopens them only on verified no effect, observed success, or exact
restoration under
[Orchestrator's settlement law](23-orchestrator.md#host-mutation-port-and-privilege-boundary);
uncertain physical outcomes retain containment.

### Startup reconciliation

Startup classifies existing work in this order:

1. Synchronize standing policies, retry `CANCELLING` Runs, repair missing terminal evidence
   across every canonical terminal status, and perform paged retries of idempotent checkpoint
   deletion across all terminal Runs.
2. Fence every pre-boot SAQ generation before failing orphan `RUNNING` or `AWAITING_HARDWARE`
   work as lost. Recover an exact checkpoint-plus-Consent or delegated-job pre-park crash window
   by parking. For the remaining orphan failure paths, contain correlated effects before
   terminal failure. Uncertain containment retains nonterminal Run truth and degrades required
   startup.
3. Inspect the exact delivery for every `QUEUED` Run and apply the matching case below. An
   active broker row without a trustworthy start timestamp degrades recovery.

    | Queued-delivery case | Action |
    | --- | --- |
    | `HELD` admission is still unresolved | Refuse. |
    | Current-boot broker work is active or queued | Retain. |
    | A pre-boot active broker generation is proven | Terminally fence it, probe again, then rotate delivery. |
    | No broker job exists | Republish the same key. |
    | A terminal broker record exists | Use a new sequence, retaining the stored fresh/resume mode. |

4. Reconcile Consent using the owner persisted on the Run, never the newest consent row.
   Re-admit decided consents and terminal delegated waits before a second delivery flush.

Delivery pagination orders by the Run’s eligibility-changing `updated_at` plus identity.
Creation time is unsuitable: an older parked Run that becomes `QUEUED` after a cursor has passed
must appear on a later page. Begin the scan from every queued Run so missing delivery rows
remain visible as corruption; a join must not filter them away. Missing or mismatched delivery
truth, an unavailable queue, an unprobeable broker, or an unfenced orphan degrades the pass. If
required reconciliation is degraded, abort PostgreSQL startup before publishing workers or HTTP
services. The memory profile remains best-effort.

### Ongoing recovery and fairness

After startup, lifespan-owned delivery, delegated-wait, and consent relays repeat bounded recovery.
One internal page scheduler retains every distinct degraded, caller-held, or clean-but-still-active
external-wait page and alternates queued revisits with forward cursor progress. Multiple old poison,
live broker, unfinished delegate, pending consent, or not-yet-released pages therefore neither
disappear from repair nor starve newer identities. Exceptions are isolated per owner within a page.
Each consent owner has one ten-second deadline covering lookup and re-admission, including broker
publication. A timed-out owner remains eligible for a later pass while the page advances to others.
The same consent/delegate bounds cover the worker's optional probe after a durable park. Reference
delegate result adoption is cancellable; acknowledged projection retirement finishes under
shielding, and a later terminal read repairs retirement after an unknown commit outcome.

The lifespan supervisor restarts any relay that exits before shutdown with deterministic
exponential backoff capped at five seconds. Delegated and consent probes share their timeout-bounded
reconciliation paths with startup; a verdict or terminal child committed after an earlier clean
probe is therefore re-fired without requiring another process restart.

Recovery stops at declared checkpoints. The relays preserve Graph effects' claim-sequence
fences and idempotency law; they do not provide generic SAQ retry, a periodic workflow scheduler,
or public failed-Run retry. Uncheckpointed process death is recorded as failure rather than
guessed forward.

### Shutdown order and deadline

Shutdown cancels all maintenance relays and stops every in-process worker before shared services or
queue pools are dismantled. A relay timeout or worker-stop failure raises and leaves those shared
dependencies live.

Teardown must prove that worker tasks have ended before closing what they use. A stop method's
return is insufficient if its captured worker task remains live. Lifespan therefore owns both
the stop coroutine and SAQ's captured launcher task, cancels the launchers, and proves every
observed worker task ended under one 30-second deadline. Otherwise teardown would manufacture
use-after-close behavior.

Queue teardown then attempts every configured disconnect and reports the grouped failures
instead of abandoning later pools after the first error. Cancellation is retained but deferred until
the queue currently closing has completed and that reverse sweep has attempted every queue. The
PostgreSQL queue facade is installed before
connect and explicitly closes a managed pool if SAQ opens it but fails schema initialization before
marking itself connected; SAQ's disconnected-flag no-op cannot leak that partial owner.

### Unsettled failure and late publication

A Ghoul retries transient child-authority containment before committing worker failure. Persistent
failure remains explicit nonterminal Run truth because `FAILED` would falsely claim required
locally owned effects are contained. Sovereign peer tasks retain the local closure and remote
uncertainty distinction above. There is not yet a same-boot failure-custody watchdog or a dedicated `FAILING` state;
restart orphan reconciliation is the current final recovery boundary.

A publisher that loses its acknowledgement after cancellation re-probes and retries exact broker
abort three times before surfacing failure. That fence completes under caller cancellation before
the disconnect is propagated. Persistent late-job abort failure remains fenced by the Run/delivery
claim CAS and is retried by explicit cancellation or startup reconciliation; it is not misreported
as physical containment.

The memory persistence profile and `LiveStasisPhylactery` are test/local process state. PostgreSQL
checkpoint shapes exist, but the standard suite does not prove checkpoint-plus-consent restart on a
real PostgreSQL lifecycle.

## Service job attempts

Long-running image, video, Form, Kinesis, Scanner, Scout, speech, engine, or provider work is not a
broker retry and cannot be represented by a live Connector handle in Graph state. The accepted
common mechanical envelope is `ServiceJobAttempt@1`; source, migrations, adapters, and restart
receipts are not delivered yet.

Before the first local or remote submit, the owning domain Worker persists an attempt containing:

- owner job and Run/station-attempt identity, exact request digest, idempotency identity, and retry
  generation;
- one discriminated execution binding: either a capability-backed interface, immutable profile
  revision/digest, operation, driver and dialect revisions; or a direct-tool-backed Spell
  implementation and Resolution Lock, immutable `ToolProfile`, and executor or Tomb profile;
- classified source and working `ArtifactRef`s, destination, purpose, consent/egress decision, and
  relevant policy revisions;
- state, provider/executor job identity when known, progress cursor, result and diagnostic refs, usage,
  cost, warnings, cancellation request, and reconciliation evidence; and
- for managed local resident or scarce substrate, the exact durable Orchestrator-visible
  reservation/fence that prevents readiness from disappearing while the effect can still execute.

The mechanical attempt states are:

```text
PREPARED → SUBMITTING → ACCEPTED → RUNNING → SUCCEEDED | FAILED | CANCELLED
               |             |         |
               +-------------+---------+→ INDETERMINATE
```

`PREPARED` proves no submit has started. A CAS to `SUBMITTING` occurs before the driver is called,
and the exact idempotency identity accompanies every permitted transmission. The returned
provider/executor job identity is persisted before `ACCEPTED`. A timeout, disconnect, crash,
malformed acknowledgement,
or lost cancellation acknowledgement after submit stays `SUBMITTING` or settles
`INDETERMINATE`; it never fabricates failure or authorizes a new effect. Reconciliation first looks
up the same provider/executor identity and idempotency identity. Re-submit is legal only when its
evidence proves no effect occurred, or when the admitted adapter proves atomic server-side same-
key/same-payload replay that returns the original effect/job identity and rejects changed-content
key reuse. The domain retry policy must admit the same generation, sealed bytes and target must be
unchanged, and each physical transmission obtains a fresh EgressDecision. A provider or executor
unable to offer that idempotency guarantee or lookup cannot host autonomously repeatable durable
effects.

Cancellation records intent, asks the exact attempt owner, and continues reconciliation.
`CANCELLED` means execution containment is proved, not merely that a request was sent.
Containment also closes pending launch authority: a paused dispatcher, delayed request or executor
restart must not create work after cancellation acknowledges. The actual executor release owner
must order release against irreversible closure for the exact occurrence/generation, or prove all
old launch-capable actors and pending requests irreversibly drained. A database CAS, lease, PID,
unit name or empty hierarchy alone is insufficient. If release wins, cancellation contains that
in-flight effect and closes its generation; if closure wins, old release/create/start/restart
requests refuse. Unknown ordering or closure remains unresolved, with no `CANCELLED` receipt.
Local reservation release follows terminal containment; an indeterminate local or paid remote attempt
keeps the relevant fence or operator-visible containment instead of guessing. The common envelope
owns delivery, reconciliation, cancellation, and settlement mechanics. Scanner, Prism, Form,
Kinesis, Foundry, Scout, Echo, and each Composition retain their domain request/result contracts,
validation, acceptance, and finish law.

After checkpoint and exact attempt ownership are durable, the parent Run may park as
`AWAITING_SERVICE`. Only an owner-specific CAS from a proved terminal attempt creates the next
`PENDING` delivery; the generic status writer cannot resume it. Startup and the lifespan relay page
every service wait, reconcile the same attempt under a deadline, and contain unresolved effects.
No live Connector, grant, SDK client, stream, tensor, process, or session enters the checkpoint.

## Delegated `AgentJob` labor

Delegated work is neither Tomb execution nor a broker retry. The coordinator has idempotent typed
`AgentJob` submission/adoption/cancellation, parks the graph with exact ownership, and resumes one
bounded hop. The selectable `reference` adapter is deterministic and effect-free; it may rebuild
its process-local result projection from the persisted request before restart-time refresh or
cancellation, retains that projection across a failed store adoption, and retires it only after
authoritative terminal settlement. Its effect-free echo remains `SUCCEEDED` when the generated
text exceeds the result limit: the retained text is bounded with an explicit truncation marker
and can still be reconstructed for cancellation. This demonstration does not permit truncating
an effectful runtime's required result or terminal evidence into success. Effectful runtimes require lookup by
durable provider/executor identity and must never replay submission. Reference-only recovery cannot
stand in for an effectful adapter's durable lookup, containment or artifact custody. [State of
Work](../state-of-the-work.md#delegated-agent-execution) owns current delivery evidence.

Codex and Claude have bounded one-shot protocol adapters behind a refusing-by-default host port.
The command intent pins the CLI version, exact request and job, literal argv, stdin, isolated
environment and roots, and finite capture/wall limits. It is not an execution permit. A future
trusted host must retain that exact launch identity before effects and return its original limits
and matching whole-job containment evidence on lookup. Changed configuration cannot rewrite a
retained launch. Malformed, incomplete, conflicting or oversized protocol output cannot become
success; a timeout requires containment before terminal classification. Neither adapter is
registered by default, and no subprocess launcher or Provider Gate bridge is delivered.

Polling and containment use the exact store-retained request with its job reference. The
coordinator obtains that request from its current authoritative read. For the reviewed CLI
protocols, the prompt is exactly its UTF-8 stdin; lookup and cancellation never recreate a
submission. Both operations require the retained-request argument on the Python adapter port,
and built-ins change atomically under [Extension compatibility](05-extensions.md#7-extension-compatibility-tiers).

### Versioned CLI intent and owner binding

The existing `DelegatedAgentRequest` is the unchanged legacy request: no discriminator or policy
is backfilled, and its request, nested job and launch encodings retain their original meaning.
Reference work and retained Pattern revisions remain unchanged. Fresh legacy CLI starts refuse
before calling a host; historical lookup and containment retain their narrower request/stdin
correlation, without inventing previously unretained model, roots or limits.

A sibling `DelegatedCliRequestV2` uses the exact discriminator
`request_schema="lychd-delegated-cli-request@2"`. In addition to the existing occurrence and prompt
fields it requires immutable `cli_intent` and `owner_binding`. Its runtime is exactly `codex` or
`claude`. The intent pins `compiler_revision="official-one-shot@1"`, the exact reviewed CLI version,
canonical executable, explicit model, one parent `job_root` with three pairwise-disjoint strict
children, and all four existing capture and wall limits. The pinned compiler alone derives literal argv, replacement environment and stdin.
No arbitrary settings, added CLI flags, reasoning alias or model default enters that interpretation.
Current runtime defaults cannot reinterpret retained V2 work.

The first owner-binding namespace is `operator-campaign@1`. Each of its four references has an
immutable `record_id`, `revision` and lowercase `sha256:` content digest; identifiers are bounded
ASCII identifiers and revisions cannot mean `latest`. The binding also names the independent
`verifier_id`. These are opaque owner-qualified identities, never paths to resolve by the runtime:

- `task` binds the principal, campaign/task/attempt, acceptance and non-goals, standing authority,
  tools/effects, all budgets, cancellation, termination and separate promotion owner;
- `projection` binds the exact base plus admitted dirty patch and selected untracked bytes,
  their manifest and allowed paths;
- `custody` binds output format, quarantine, destination, retention and permitted downstream use;
- `verification` binds fixed commands, tool versions, environment, deadlines, pass criteria,
  independent verifier identity and reserved verification capacity.

A trusted injected owner-admission port, absent or denying by default, checks current owner truth
before V2 start. Its closed positive observation binds the exact job occurrence, canonical request
and intent digests, all four references and verifier, an admission identity, aware issue/expiry
instants and a nonnegative bounded generation. The consumer requires issued <= trusted now < expiry
and a positive validity window no longer than one day. Missing, denied, malformed, expired or
mismatching observations refuse before host launch. A caller cannot serialize a positive observation
into the request. The port checks existing admission; this passage grants no budget reservation or
execution permit. Current authority and generation are the producer's responsibility, not proved by
consumer equality checks. Poll and cancellation need no fresh owner admission, including after its
expiry or revocation, and never launch.

Explicit request decoding selects legacy only when the discriminator is absent, V2 only for its
exact tag, and refuses unknown/null tags and extra fields without fallback. The same codec governs
store writes, exact replay, detached reads and nested job JSON. Unknown stored versions remain
unchanged and unavailable; they are not translated or rewritten. Legacy launch digests remain
unchanged. V2 uses separate request/intent digest domains and a tagged launch encoding containing
the complete request and existing launch specification. Canonical bytes are sorted compact UTF-8
JSON with nonfinite numbers forbidden; this internal identity claims no general JCS/signature
canonicalization. Retained work keeps its compiler and codec versions.

For V2 lookup and containment, independently compile the complete expected specification from the
store-retained request and exact job, then compare the host specification and matching receipt.
Consistent substitutions of model, executable, argv, environment, roots, limits or owner bindings
must refuse even when the host recomputes its receipt. The host must additionally retain the exact
versioned launch and owner decision durably before effects, with create-once exact-job ownership;
lookup never repairs an absent record by resubmission.

Consumer conformance with an inert positive owner fixture is a mechanical prerequisite only. It
proves no actual owner-record producer, source-byte closure, current authorization/revocation,
custody service or verifier reservation. Those owners must be delivered and independently checked
before usable admission, including changed dirty/untracked bytes under unchanged names. The four
CLI limits do not supply ADR 09 CPU, memory, process, disk, provider or artifact budgets. Physical
host retention, enforcement and Gates remain separate prerequisites. Neither this contract nor a
migrated-store test registers a CLI or delivers native Creation.

### Host dispatch and irreversible closure

A future delegated-host attempt specializes [Service job attempt](#service-job-attempts) mechanics
under the existing AgentJob. It binds the exact versioned request/specification and digests,
actual owner decision, selected host policy, executor generation, dispatch/closure disposition,
and containment/custody evidence. [Phylactery](06-persistence.md#decision) owns its admitted
persistence. It introduces no competing generic attempt lifecycle, task selector, retry policy,
acceptance judge or promotion owner. AgentJob and `AWAITING_DELEGATE` keep their existing truth;
host disposition cannot independently resume Graph or create `AWAITING_SERVICE`.

Create-once exact-job ownership commits before a guest effect. The conditional
`PREPARED → SUBMITTING` handoff consumes dispatch before calling the executor. Conflict preserves
the original; absent or uncertain commit permits no release. A consumed dispatch can yield zero
executions if its owner dies before contact. This CLI profile does not inherit a service adapter's
conditional retransmission permission: an uncertain dispatch, lost acknowledgement, missing
lookup or lease expiry allows exact lookup/containment only, never replacement submission.
At-most-one admitted dispatch is not exactly-once execution or completion.

The trusted host must re-observe the actual owner producer over the exact retained identities
after preparation/queue/reservation waits. Forwarded runtime observations are historical evidence,
not live permits; `launch(spec)` can retain its shape only when trusted host construction supplies
that producer and the required release boundary. Source projection remains immutable through
release. Complete budget, custody and independent-verification reservations must actually exist;
Admission-consumer equality and its four capture/wall bounds establish none of them. A new positive
owner operation or host handoff needs its own accepted typed contract, rather than silently
expanding the existing observation port into reservation or authority.

Current admission, expiry/revocation and physical release must share the selected executor's ordered
release/closure boundary. A fresh check followed by an arbitrary pause is insufficient. The
executor must reject all stale create/start/restart requests after irreversible generation
closure, or the host must prove equivalent draining and loss of every old launch capability.
Containment evidence binds that generation, existing descendants and absence of pending/future
release. If that proof is unavailable, cancellation remains unresolved; neither an empty lookup
nor a mocked receipt permits `CANCELLED`. No selected executor supplying this boundary is delivered.

Dispatch and closure history cannot disappear through ordinary cleanup while an old occurrence
could be reused. Known database restore, lost control history or uncertain authority epoch closes
fresh launch until independently surviving executor/owner evidence and explicit authority
reconcile the generations and effects. Restored counters or old `PREPARED` rows cannot prove an
unspent occurrence. Missing evidence keeps launch closed; this decision creates no nonrollback
store and claims no machine/power-loss recovery profile. Return custody remains pending until
its actual owner seals the bounded artifacts and references; coordinator adoption failure never
permits relaunch or deletion of required evidence.

#### Mechanical host disposition precursor

The first `delegated-host-disposition@1` profile retains mechanical intent before usable host
admission. It is not the complete admitted host attempt above: no actual owner decision,
reservation, guest release, containment or custody is supplied. One permanent AgentJob row
serializes preparation, dispatch consumption and logical intake closure even before a
disposition record exists. Preparation retains the exact tagged V2 request and job, immutable
proposed host-policy identity and executor generation, and independently compiled launch digest
in bounded canonical bytes. Reconstructing the complete specification from that retained request
must reproduce the digest; a caller-supplied digest alone cannot establish it.
This precursor admits only complete canonical current stored V2 shape: decoding and re-encoding
must preserve its canonical JSON bytes, including scalar types and explicit defaults. Omitted
defaults or numeric aliases refuse without rewriting the stored request or changing the global
V2 codec's compatibility contract. Preparation, consumption and prepared-history reads all apply
that admission; logical close remains available without decoding damaged intent.

Only a newly inserted, acknowledged preparation yields one nonserializable handle owned by the
issuing adapter instance. Reads, exact replay, process replacement and retained PREPARED records
yield snapshots only. Consuming the handle retires it before the first asynchronous operation and
conditionally commits the one PREPARED-to-SUBMITTING disposition. Failure or uncertain commit
cannot reissue that opportunity, even if the retained preparation remains unconsumed. Such loss
may produce zero dispatches. No returned value is an owner permit or a capability to launch.

Logical intake closure is monotonic and may be retained before preparation. Closure that wins
prevents later preparation or dispatch consumption for the same AgentJob; changing policy or
executor generation cannot reopen it. Dispatch that wins remains potentially in flight when
logical close is recorded. This acknowledgement proves only that the store will admit no new
logical handoff; it cannot settle AgentJob CANCELLED, emit containment evidence or release a
reservation. Physical release and irreversible executor closure retain the separate law above.
The profile adds no registration, restore-reactivation, retry or positive owner operation.

The decisive future fixture pauses dispatcher A after admission/dispatch claim, lets B cancel or
close, then releases A. Either A is rejected after closure, or B cannot acknowledge cancellation
until A's in-flight release is contained and fenced. Repeat across lost acknowledgements, restart,
stale generation, expiry during a paused release, changed mounted input and restored records. Pure doubles prove protocol logic,
PostgreSQL proves its transaction claims, and a real selected executor proves physical fencing,
containment and ceilings. None substitutes for the absent owner producer, Gate or host qualification.

### Delegated settlement

`LOST` is terminal for result adoption and ordinary polling, but it is not evidence that an external
process stopped. Parent cancellation must still call the owning runtime's containment operation and
may record `LOST → CANCELLED` only after that operation returns.
An unclassified exception raised by `runtime.start` records `LOST`, never proof that the job failed
or stopped. Start-error diagnostics are bounded to the result contract, with an explicit truncation
marker when necessary; an oversized diagnostic cannot prevent settlement. Exact-request replay
retains the original job; late success is inert, and explicit cancellation still calls its owning
runtime. A failure before that invocation may record `FAILED`. An effectful adapter additionally
needs a proved definitely-rejected outcome and durable provider/executor lookup before its
reconciliation contract can be admitted.

Once start returns, the coordinator finishes one acceptance write despite repeated caller
cancellation. If that write raises an ordinary exception, observation and conditional settlement
share the store's
authoritative mutation lock. A committed `RUNNING` row or an existing terminal remains unchanged;
only a row still `PREPARING` under that lock may settle `LOST`. A prior snapshot of `PREPARING`
does not authorize settlement. This operation neither repeats submission nor retries the
acceptance write. Preserved `RUNNING` or terminal truth returns the original job reference;
newly recorded `LOST` propagates the original write failure. Caller cancellation propagates
after a known disposition. Failed locking, observation, or settlement remains an explicit
unresolved failure with the initiating write failure or interruption retained as context.
These rules neither reopen `LOST` nor replace owning-runtime containment.

Background work on `rites` now uses ordinary `perform_run` execution; the former no-effect
`perform_rite` placeholder has been removed. There is no Rite registry or Rite handler. Admitting
one later would require typed identifiers, extension provenance, payload schema, authorization,
idempotency, queue policy, and settlement.

## Consequences

- Exact hop keys and conditional settlement prevent an old delivery from rewriting a later resume.
- Pending broker work survives a Vessel restart and transient broker publication failure; active
  uncheckpointed execution does not.
- The [current evidence envelope](../state-of-the-work.md#current-evidence-envelope) records the
  tested persistence and recovery wiring with offline collaborators. Their composed behavior,
  real host/model/browser operation, and checkpoint-plus-consent restart still need separate proof.

---
title: "15. Frontend"
plain_name: "Design rule 15: Web control panel"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/15-frontend/
guide: https://lychd.snayu.ai/docs/adr/15-frontend/
---

# 15. Frontend (Design rule 15: Web control panel)

## Plain-English summary (Snayu)

**What it is:** Defines the Control Panel (Altar): a static SvelteKit front end with no server-side rendering, using TypeScript types generated from the backend's OpenAPI. The backend keeps all validation and data changes; the browser only displays.

**Why it matters:** Read this before changing the web UI, its API contracts or how live updates reach the browser.

- Litestar owns validation, permissions, approvals and every data change; browser state is never authoritative.
- Screens: Project Board (Atlas), Run Inspector (Orb), Model Status Board (Nexus), Workflow Viewer (Loom), plus a Chat dock (Bridge).
- Browser state rebuilds from a snapshot plus event cursor; model or extension supplied HTML or JavaScript is never rendered.

**Status:** Partial. All screens exist in limited form; chat is text-only and several views are incomplete.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    The Altar gives a browser form to conversation, bounded Run evidence, capability transitions,
    and Pattern inspection. It is a disposable projection: Litestar and the Phylactery retain
    validation, policy, lifecycle, and durable mutation. Static output needs no JavaScript production
    server; it does not make browser state authoritative or the loopback surface safe for hostile
    remote use.

## Requirements

- Litestar owns validation, caller scope, consent, persistence, workflow movement, and every
  durable mutation. The retired Jinja, HTMX, Alpine, and island paths are not compatibility APIs.
- Browser contracts derive from Altar-controller OpenAPI. Framework-neutral TypeScript owns
  generated types, transport, runtime validation, and event reduction.
- SvelteKit supplies static routes and layouts only: no SSR, server loads/routes, form actions,
  remote functions, or JavaScript production server.
- A snapshot plus event cursor must reconstruct browser state. Connection, animation, and canvas
  layout never prove execution.
- Atlas, Orb, Nexus, and Loom are work routes; Bridge is a shell-owned conversation panel available
  beside every work route. Existing Bridge URLs retain explicit server fallbacks and exact session,
  Run, consent and focused-application navigation. Generated UI is closed descriptors, never model-
  or extension-supplied HTML, JavaScript, Svelte, or imports.
- Circle is the Invocation-shaped focus within Bridge, not a separate instrument or a claim
  that the current run strip already composes every owning projection.
- Native CSS includes keyboard access, visible focus, non-colour cues, reduced motion, named
  regions, and visible unknown/error states.
- The Altar ships one canonical built-in appearance, **LychD Dark**. Its semantic colour boundary
  must remain closed enough for a future validated operator palette override without promising a
  second built-in theme, arbitrary CSS, or extension-owned UI.
- The Altar keeps a replaceable localization boundary for interface copy, accessibility labels,
  pluralization, locale-sensitive formatting, and text direction. Interface locale never rewrites
  Intent, model output, artifacts, or evidence.
- Every executable software dependency in the supported client, build, and renderer path is
  locally operable FOSS under OSI-approved terms; non-code data may use reviewed
  public-domain-equivalent terms such as CC0. Proprietary services and source-available-only
  packages are not admitted. Dependency closure, licence compatibility, and notices are reviewed
  with [Packaging](17-packaging.md) before admission.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| Server-rendered hypermedia with Svelte islands | Rejected | It preserves two projection contracts; historic hypermedia is evidence, not a supported surface. |
| React 19 with Vite | Rejected under current requirements; eligible only through the reopening gate | Its explicit external-store and renderer-change seams are useful, but they do not by themselves establish domain intent, lifecycle safety, static routing, or lower whole-system maintenance. |
| Plain Svelte SPA | Rejected | Components alone do not establish the selected route, layout, fallback, deep-link, and static-build conventions. |
| Svelte 5 with static SvelteKit | Selected and reaffirmed | Svelte supplies the view language; SvelteKit and `adapter-static` supply the client router and static artifact while framework-neutral TypeScript owns transport and projection contracts. |

## Decision Outcome

The canonical Altar is a Svelte 5 static SPA. `clients/web/src/routes/+layout.ts` sets `ssr = false`
and `prerender = false`; `adapter-static` writes `index.html` and assets to `src/lychd/public`.
Litestar redirects `/` to `/bridge`, admits the instrument/deep-link shells, and mounts hashed
assets at `/_app`. New Svelte uses runes, current event attributes, snippets, and native CSS.
`+page.server.*`, `+layout.server.*`, `+server.*`, private server modules, form actions, remote
functions, and a SvelteKit production server are forbidden. Node 24.20 and npm 12.0 are build
pins; Litestar/Granian alone serves production requests. Installed tools, lockfile, generated
output, and focused tests are evidence; [State](../state-of-the-work.md#altar-and-observability)
owns delivery.

<span id="the-four-instruments"></span>

### The five instruments

| Instrument | Browser contract | Current limit |
| --- | --- | --- |
| Atlas | Versioned Projects, concerns, attributed judgments, decisions, next steps, and explicit activity references | Initial planning surface; no autonomous continuation or automatic coverage. |
| Bridge | Session selection, single-active-Run text admission, reconstruction, semantic stream, consent, closed fragments, and bounded Creation investigation intake/report focus | Partial: text only; live reconstruction and tokens are process-local. |
| Orb | Paged Run catalogue, parallel graph field, and bounded selected-Run evidence feeds with gaps, capture labels, and links | Partial: no complete trace store, nested subworkflow identity, or annotation. |
| Nexus | Timestamped capability observations, non-binding plan preview, typed request, and ticket stream | Partial: observations and tickets are process-local and not restart-complete. |
| Loom | Immutable Scroll/Pattern-revision graph and station/permission outline | Partial: fixed registry reader without independent Spell identities, editing, teaching, or publication. |

The shell owns navigation, source identity, pending-consent count, transient notices, and the
persistent Bridge presentation. Each other instrument owns its route-local presentation.
`/scrying`, `/reliquary`, `/bindings`, and ambiguous unversioned Loom detail are deliberately absent
from the route contract. Scrying names Orb's act. Artifact references and configuration
observations let the browser show context without acquiring custody or configuration authority.

The browser shell retains drafts by exact session and the last explicit Bridge session path
for its own lifetime. The global Bridge control opens that session without a Run hint.
The global Orb link opens the parallel Run field at `/orb`. Until an explicit Bridge session
path is selected, its global link stays at `/bridge`;
the server's default session does not establish browser navigation memory. This is recoverable
navigation state, not a durable dossier or execution truth. Cross-instrument links preserve an
explicit Run and selected event where supported; Orb's contextual Bridge return focuses that
Run's turn. A selected historical consent event may also carry a bounded Consent reference to
that exact session and Run. Orb retains only the syntactic historical reference, without resolving
current status, review, or decision authority. Bridge resolves the exact Consent and requested Run
against its currently authorized session snapshot; a missing, settled, foreign, or unbound request
is visibly unavailable and never falls back to another request. Request focus belongs to that
navigation and does not recur on stream refresh. An event return preserves the originating Run
and selected record. A stale or unavailable selection is reported, never silently replaced with
another Run.

[Circle](../divination/altar/circle.md) is likewise not a separate instrument or route in the present
contract. One Bridge séance may contain many Invocation/Run projections; a future Circle focus may
compose authorized Loom, Nexus, and Orb lenses around exactly one of them without importing their
authority into browser state. The current run strip is only its delivered seed.

### Creation investigation within Bridge

The existing `/bridge` route may focus the protected public-source Creation investigation through
an explicit `investigation` query: `new` opens intake; a case UUID selects retained state. This is
Bridge admission and a Composition-owned reply, not a sixth instrument or ordinary chat turn.
Creation creates its own admission and Session. Orb keeps the exact returned Run's retained
evidence; Atlas next steps remain recorded text, never queued admission. The global Bridge link
continues to return to the last explicit ordinary session without this focus. Investigation
navigation must preserve ordinary session drafts, unresolved offerings and consent state.

Only the case UUID belongs in navigation. Source text and the immutable submitted body remain
transient browser-document state, without hidden durable storage. Once POST may have left,
freeze its UUID/body; an ambiguous result never causes automatic retry or a new UUID. Explicit
Check reads that case, and a 404 while admission may still be in flight does not resolve the
ambiguity. Identical replay is an explicit action available only while the original body remains;
reload cannot reconstruct it from a UUID. Editing authorizes a deliberately different request.

The browser uses generated Creation transport and existing authentication/Origin/CSRF gates.
The local role owns its cases; navigation grants no authority. Case reads use current authority
through awaited storage, guard late responses against changed selection, and clear protected
material on refusal. The detail read may perform existing expiration and transport retained
operational records; it is not the non-mutating Orb metadata feed. Render only validated retained
request, candidate, citations and separate verdict as text. Run completion, native case status,
external assessment and owner disposition remain distinct. Later changes require explicit
Refresh; viewing grants no continuation, cancellation, feedback mutation or successor action.

The report may explicitly load the existing protected historical feedback projection. It starts
not loaded and performs no automatic read on mount, selection or later changes. The server's
current assessment and decision IDs select current judgments; a newer assessment cannot inherit
an older hold. Empty unassessed, external not-assessed, review-required, refused and unavailable
states remain distinguishable. Selection changes and teardown fence and abort owned reads;
current-authority refusal clears protected feedback. Render the current report, owner reason and
supplied annotation coverage as escaped text, validating unknown dictionary fields before display.
Native acceptance, external assessment and owner disposition confer no browser execution or
promotion authority. An explicit reload uses current read authority; disclosure appends no feedback.

### Public notes within Bridge

The `/bridge` route may focus explicit public-note work through one `notes` query:
`manage` opens metadata, `new` opens intake, and a record UUID selects exact metadata. Invalid,
duplicate or simultaneous investigation/note focus is unavailable without effect. The focus keeps
ordinary Session drafts, unresolved offerings and Consent separate; the conversation rail is not
an Archive source list. Only mode/record identity enters navigation, never note text or a request
body. This adds no instrument or automatic conversation-to-memory admission.

Reload recovers the authorized configured profile and bounded all-lifecycle metadata pages from
the server. Exact-record reads work independently of the loaded page, so the browser need not own
record custody. The management API provides no public-note text for preview or prefilled editing.
A correction supplies complete new text under a different immutable source revision and needs
separate promotion. Revocation retains the minimum source identity; it does not erase earlier
answers or backups.

An independent authorized current-default projection identifies the admission engine's actual
Pattern and complete managed-profile match. Show requested, not requested, unavailable and failed
states distinctly. Configuration is neither readiness nor the next routed Run; a historical Run
retains its own admitted profile. Browser revision checks or fetching conversation history cannot
supply this projection.

Every intake freezes its UUID, exact UTF-8 digest, observation time and public declaration before
submission. Only an explicit identical intake replay may reuse that retained body; navigation,
refresh or failure starts no retry or replacement UUID. A metadata match recovers a source record,
not proof of which intake occurrence committed. Lifecycle actions pin the record and expected
version, with no optimistic state or replay. After an uncertain response, Check reads current
metadata; an unchanged version or missing record cannot establish that an in-flight action failed.
A newer version establishes current state, not causal authorship. A fresh explicit decision may
use the recovered version without reclassifying the earlier occurrence as successful or rolled back.

Drafts and frozen bodies remain transient to the browser document, with departure/reload warnings.
GETs are abortable and late responses remain fenced by selection, profile and lifetime. Current
authority refusal clears protected material. The focus uses generated transport, existing local
Origin/CSRF/access gates, escaped text, semantic forms, keyboard controls and visible uncertainty.
Intake, metadata and lifecycle management create no browser ledger, consent authority, recall
operation or model request.

A separate explicit preparation section may operate on the exact selected public-note revision.
It discovers configured generation metadata without preparing anything. **Register configured
generation** is a named shared-generation mutation using that exact reference; it neither embeds
nor reactivates a retired generation. **Check preparation** is a protected metadata-only POST for
the exact generation and source reference. Neither opening, navigation, checking nor promotion
registers a generation or derives a note automatically.

**Prepare this promoted revision** requires an explicit review of the current profile, generation
and full source reference and may incur one local embedding operation under Archive authority.
It sends no source text from the browser, activates no model and chains no recall or answer Run.
Its existing request has no occurrence UUID or caller attempt-version precondition; row and attempt
versions describe latest durable state, not authorship or the cost of one HTTP invocation. A lost
response stays unknown after a status check. A further explicit preparation decision may repeat
compute even with the identical body; only the server can establish eligible completed replay.
DB-observed expiry does not prove cancellation or stop earlier work.

Frozen preparation references and status remain document-local. Historical status after a
lifecycle change needs the original exact source reference; reload cannot invent an old lifecycle
version. Local preparation and note-write gestures are serialized. Profile, generation, selection,
operation and lifetime fences reject stale responses; current authority refusal clears protected
management and preparation display. Departure or read abortion grants no cancellation or rollback
claim. Preparation adds no browser ledger, bulk/background worker, automatic retry or readiness
service.

The separate `recall` notes focus is an explicit sources-only consumer of Archive's schema2
semantic API. Opening, typing, navigation and metadata refresh perform no semantic query or source
resolution. Authorized profile/configured-generation discovery is metadata only; it establishes
neither semantic opt-in, an active registered generation, eligible derivations nor runtime warmth.
The operator separately prepares the runtime, generation and promoted sources under their current
owners. Recall never activates, registers, derives, falls back or changes ordinary Bridge3.

One explicit submission freezes a fresh request UUID, exact query/namespace/generation, user-supplied
finite minimum similarity and visible result/character bounds. It may compose recall with exact
receipt-digest resolution in that same gesture. Display only the resulting currently authorized,
ordered source projection with source/revision identity, similarity and coverage/omissions;
similarity grants no answer-confidence or truth claim. Selection time and resolution time stay
distinct. Source bodies, queries and request bodies never enter navigation or browser persistence.

After an unknown query outcome, an explicit check may inspect only the frozen full request without
inference or hydration. An absent receipt does not establish that an in-flight query failed. A
recovered selection needs explicit current-source resolution; there is no automatic recall retry
or exactly-once inference claim. Current refusal/profile change/lifetime replacement fence late
responses and clear protected projections. Waiting is HTTP presentation state, not a durable Run;
leaving or aborting a request does not claim to cancel model work or undo retained selection.

### Scavenger finite observation application

`/scavenger` is an application working view within the Altar, separate from the five
operator instruments. Its optional `observation` query contains only a retained admission UUID.
Opening or refreshing it reads protected application state; it never acquires a source.
The selected Scavenger 3 / observe_market 2 configuration owns the finite Bazoš PC RSS profile;
omission is visibly unconfigured, not ready or silently routed to chat.

Explicit submission supplies every CampaignSeed fact and a literal initial filter. Freeze the
request UUID and complete body before sending. An uncertain response remains unconfirmed;
only an explicit Check or identical replay may reconcile it, never an automatic retry or new UUID.
Request bodies and private drafts remain document-local, without URL, storage or Bridge history
copies. Leaving/reloading warns about unresolved actions and cannot imply cancellation.

The canonical seed document is also supplied as protected text for exact display: JSON number
parsing in a JavaScript client must not round retained 64-bit budget or preference facts. It is
rendered as escaped text and is subject to the same custody, clearing and deletion boundary.
Scavenger routes opt out of generic request/response body capture, including operator-enabled
body diagnostics, and their responses forbid HTTP storage. SQL parameter diagnostics are hidden; SQL engine result-row diagnostics are disabled even at a
requested DEBUG level. Application transaction/decoder failures expose closed reasons without
payload-bearing exception chains.

The protected field presents source/time/coverage/omissions, all occurrences and local filtered
counts, duplicates, missing titles and unassessed facts. Item locators are inert displayed text,
with no prefetch or preview. Re-filtering uses the server's versioned literal projection over the
same retained digest; changing the filter does not acquire. Current pending, consent, unavailable,
unknown and deleted states remain distinct, including empty field versus zero matches.

The existing native consent card and Core verdict endpoint retain review-binding and current
caller authority; the application adds no decision authority. Run cancellation remains an explicit
Run action. Deletion is a separate confirmed exact-digest action and is offered only for a supplied
terminal disposition. Unknown custody cannot be cleared by deletion or by a new request. Current
refusal clears protected content, and changed selection/teardown fences late reads. No browser
connection, refresh, rendering, configuration observation or Run completion substitutes for native
consumer commitment. State owns delivery, including any unqualified browser or restart boundary.

### User-specific working interfaces

The [Ward account and profile contract](38-iam.md#profiles-and-working-interfaces) permits different
Users of one instance to receive different applications, navigation, screens, and workflow views.
The built-in operator instruments are not a compulsory interface for every household member,
guest, or employee. A shared client may select named working views, and a dedicated client may
present a narrower application experience; neither becomes a separate identity or effect authority.

The current Principal and objects determine which projection the server may supply. The client
then applies admitted presentation defaults and device affordances. A profile label, an open route,
or a hidden control grants no permission. Different working views preserve a Run's identity and
admitted score, and offer only actions allowed by both workflow state and current authority.

Client connection choice is not mobile-only. Browser and native clients may offer saved
instance/account selections and refresh their working interface during use. A browser may navigate
to an instance-served frontend or, where explicitly supported, select another backend within a
persistent client; dedicated fixed-instance clients remain valid. These are optional client
designs, not requirements for a universal client or simultaneous connections. Interface refresh
uses supported presentation contracts; it does not admit arbitrary remote UI code.

Selecting another account or instance is distinct from changing a working view, or reaching the
same verified instance through another network address. Each selected context uses its own
applicable credentials and current Ward authority. A switch does not itself transfer history,
admitted sessions, or active work, imply cancellation of server work, or authorize replay at the
new destination.

Client state must remain bound to the selected instance and account. Switching either, signing
out, or losing access clears or isolates affected drafts, cached records, subscriptions, and
pending presentation so another user cannot inherit them. Outstanding requests and callbacks
remain bound to their originating context: late results cannot populate another context, and
pending submissions cannot be retargeted by a connection change. Reconnect revalidates access
before receiving protected state or submitting work. These requirements do not turn the fixed local
bootstrap into a delivered multi-user browser surface; [State](../state-of-the-work.md#remote-iam)
retains that boundary.

### Reading hierarchy and visual direction

#### The shared workbench and Bridge dock

The top masthead presents Atlas, Orb, Loom and Nexus as icon-and-label navigation. Applications
is a bounded disclosure for Canvas and other admitted applications; hover, click and keyboard
focus can open it, Escape dismisses it, and moving into the menu keeps it reachable. Bridge is
an always-available conversation surface, not a competing top-level instrument tab. Existing
`/bridge` links remain valid compatibility and focus destinations; exact session, Run, consent,
Project, investigation and public-note intent must survive the composition change.

The dock can open or collapse, occupy either side and resize through a pointer or keyboard
separator. A wide workbench allocates real width beside it; it does not cover the work. A narrow
workbench uses an explicitly modal overlay with focus containment, Escape and an opener return.
Width, side and collapsed state may be remembered as bounded local presentation preferences;
conversation text, attachment bodies, consent and request identities do not enter that store.
Resizing preserves the working view and Canvas camera scale instead of rearranging document
objects or fitting the board automatically. Collapsing the dock or changing an instrument neither
cancels a Run nor admits another offering. The selected conversation and its transient recovery
state remain alive across ordinary work-route changes. Current-authority refusal still clears
protected projections under the existing rules.

The canonical LychD Dark workbench uses an untextured black work plane, neutral graphite chrome,
icy-blue interaction and focus, restrained green confirmation/activity, and bounded deep-purple
secondary surfaces. Text stays neutral and readable. Icons supplement visible labels. Surfaces
use crisp geometry and restrained separators; status, consent and uncertainty remain explicit
words rather than colour or decorative motion. Canvas has no dotted background. Its optional
freehand lasso selects whole intersecting objects without adding the selection loop to source
ink; rectangle and semantic-list selection remain available. A selected scope is still only a
proposal boundary, never a model transmission or execution permission.

The Altar should read as a quiet observatory. Work holds the focal point; restrained surfaces,
typography, and fixed brand art provide identity around it. Its five instruments retain their
single-word names, with Bridge always available as the conversation dock. Their distinct reading
tasks determine their form, rather than a repeated dashboard or universal graph. No instrument
becomes another owner of an existing action:

| Instrument | Primary reading order | Role of a graph |
| --- | --- | --- |
| Atlas | Concerns, their decomposition and where they are addressed; current assessment basis; optional Project brief and next step | An optional selected-concern relation lens distinguishing decomposition, sources, addressing, and assessment citations. |
| Bridge | Conversation and offered text; the exact Run's reply, consent or unresolved admission; next draft | No default graph. A future Circle composes authorized lenses around one Invocation. |
| Orb | Parallel Run groups; selected Run and capture limits; ordered evidence; selected record; bounded delegated jobs | Zoom discloses supplied Run, station, occurrence, and record membership; declared permissions and observed records remain distinct. |
| Nexus | Snapshot and containment; observed capabilities; explicit preview and request; ticket and physical observations | A native board remains primary. Planned evictions and launches are more useful than an inferred topology map. |
| Loom | Exact registered revision and entry; stations and allowed successors; selected station; immutable identity | A read-only score can explain declared branches, joins, and loops, using the same permission data as its outline. |

This is the composition target, not a delivery claim or a second implementation specification.
The [Altar guides](../divination/altar/index.md#presentation-direction) own worked reading and
stress scenarios; [State](../state-of-the-work.md#altar-and-observability) distinguishes current
forms from later presentation work.

Use one dominant work area and disclose secondary identity, history, or raw records as needed.
Consent, unknown outcomes, capture gaps, containment, and preview consequences remain visible at
the point where they affect a choice. A selected inspector starts with the selected object's
identity and meaning, not an unexplained action. Preserve a valid opener on return, and give
keyboard users a focusable start of the detail plus a route back to the selected record. New
activity does not take a reader away from older work without an explicit return-to-latest action.

Reading text and controls use legible system typography; serif headings and monospace identities
have bounded roles. Reduce competing glow, nested frames, repeated metadata, and decorative
motion before adding more cards. Dense event reading and spacious conversation may use different
spacing within the same native CSS system. Essential meaning never depends on tiny captions,
colour, hover, or motion. Large illustration belongs at the empty entrance, away from operational
evidence and consent. Fixed art retains its own provenance; a quieter footer does not remove
licence or source-distribution obligations.

Graph and list are two views of the same supplied identities and relations. In Loom an edge means
only a declared permission: placement cannot invent a branch condition, read/write effect, or
observed transition.

In Orb order and subject lanes describe retained records, with unknown
subjects and gaps explicit across the view. Equal spacing is ordinal unless a served timestamp
supports an explicitly labelled time axis. Job and Run sequences remain separate unless the
server supplies their correlation.

In Atlas, decomposition, source inspiration, and where a
concern is addressed remain distinct from the evidence chain: concern, assessment, cited
reference, and activity destination. A shared destination cannot collapse the reference records
or make an uncited relation into evidence. A selected-concern list precedes any optional diagram
until the diagram demonstrably answers that same question better.

At narrow widths, start from a readable outline or list instead of shrinking a graph's labels.
Keep selection equivalent across views and preserve an explicit user choice where it remains
usable. The production renderer must satisfy the existing semantic-twin, lifetime, and editing
gates; a hand-drawn example is not its admission receipt. Unknown, stale, empty, filtered-empty,
denied, and failed reads remain distinguishable. Evaluation includes exact cross-instrument
return, keyboard-only reading, long text and identities, 320 CSS-pixel reflow, 400% zoom, reduced
motion, and contrast in bright and dim conditions. These checks do not promise remote-device
access, a second supported palette, or localization.

Implement in three bounded stages: improve hierarchy over existing contracts; admit the shared
Loom/Orb supply and renderer with equivalent semantic views; then add separately owned server
contracts where larger collections, complete fold membership, event seeking, physical impact
mapping, or restart recovery require them. Hidden DOM rows, geometric clustering, a new request
identity, or persuasive copy cannot supply those contracts.

### Canvas portable board authoring

[Canvas](../compositions/canvas/index.md) is the Composition for visual board authorship and
reviewed transformations. Its first `/canvas` profile is a browser authoring draft with explicit
portable document import/export. Native SVG captures actual ink and projects draft objects;
the existing Loom/Orb renderer and read-only contracts are unchanged. This bounded authoring
surface does not introduce a second graph engine or make layout a source of workflow meaning.

Canvas owns the file/proposal schemas and pure admission rules under its Composition source.
The browser holds disposable authoring state; it claims no server retention, publication,
execution or native media custody. Text remains native editable text, independent of optional
local PNG artwork. Imported bytes are bounded and validated; remote image URLs, SVG, HTML and
executable proposal content are unavailable. The real API exports the schemas for generated
client aliases and provides stateless CPU validation, not a board persistence service.

Selection capture binds exact object identities, world bounds and scene revision to source
geometry and a same-revision crop. Proposals may change selected objects and create explicit
connections to supplied context, while leaving other objects untouched. Preview is inert;
acceptance is atomic and reversible. Any committed edit invalidates an older proposal. Undo/redo
create fresh revisions. Arrangement is bounded, respects pins and measured dimensions, pauses
during gestures and records one deliberate edit. Keyboard object controls and reduced motion
remain equivalent ways to work. Model transport, microphone capture and generated imagery
are separate capabilities with explicit unavailable states until independently qualified.

### Atlas and continuity across Invocations

Atlas maps Concerns: what needs attention, how it decomposes, where it is addressed, and what
supports a judgment. A Concern can begin with an idea or question before any Project exists.
The independent Concern contract is [Designed](#independent-concerns-decomposition-and-addressing).
The initial server-owned Project aggregate holds a
brief, concerns, attributed assessments and decisions, a proposed next action, and explicit
references to existing Bridge sessions or Runs. A Project may begin without a conversation or Run
and may describe continuing stewardship. Its identity survives individual Invocations. It owns
neither a reusable Composition or Pattern nor a Suite's live coordination.

Atlas begins as a native list and detail board. References connect it to conversation and
consent in Bridge, execution inspection in Orb, exact scores in Loom, and physical readiness in
Nexus. Those links make navigation possible without changing ownership: membership must be
explicit, never inferred from geometry, tags, prose similarity, or a selected browser tab. Linking
a session or Run neither injects a Project dossier into model Context nor changes execution
permissions.

Project lifecycle is `active`, `paused`, or `closed`, with explicit reopening. These are planning
states: they neither cancel admitted Runs nor enforce a future admission pause. A proposed next
action is recorded text, not a queued Intent. Opening a reference performs navigation only.
Continuing a next action offers linked conversations or an explicit conversation chooser with an
inert Project return hint. Navigation never selects an unrelated latest conversation on behalf of
that Project. Multiple concern references to one conversation remain separate evidence relations
but share one continuation destination.

A concern states a question or acceptance condition. Its attributed assessments retain the
statement, criteria, and brief revision actually judged, the rationale, and any explicitly cited
Atlas references. A recorded `sufficient`, `insufficient`, or `disputed` judgment is the author's
assessment, never an automatic consequence of Run success. No assessment means `unassessed`.
Changing the brief or concern makes an older assessment visibly require review without erasing
its original basis. Decisions and assessments append; earlier judgments remain inspectable.
Board summaries distinguish current insufficient and disputed judgments from unassessed concerns
and stale assessments; none of these counts determines Project lifecycle or Run success.

Litestar validates every mutation under the caller's Sigil and Atlas write scope. The current
loopback bootstrap remains the security boundary, not multi-user authentication. Project reads
and writes are owner-scoped, reference admission checks the existing target, and foreign Project
identities are unavailable. Every mutation of an existing Project names its expected aggregate
version and a retry identity. An atomic version check refuses stale edits; exact retries cannot
duplicate a concern, decision, reference, or assessment. Failed or conflicting saves retain the
browser draft and require explicit reconciliation. Reads and mutation responses are fenced by
selected Project identity and component lifetime.

An unknown save outcome keeps its immutable retry payload even after a later middleware refusal.
A store-confirmed conflict carries `extra.code = atlas_write_rejected`; this follows the locked
replay check and permits draft comparison after an earlier lost response. An untagged refusal
does not establish whether that earlier write committed.

[Persistence](06-persistence.md#atlas-records) owns transactional retention and migration law;
[Atlas](../divination/altar/atlas.md) owns operation, and
[State](../state-of-the-work.md#atlas-projects) owns the delivered boundary. AI proposal generation,
automatic concern coverage, autonomous continuation, graph clustering, and implicit shared
Context remain outside this initial contract.

### Independent Concerns, decomposition, and addressing

A Concern has its own stable identity, authorization owner, revisioned statement, and optional
criteria. It can stand alone, concern an idea or an application, or participate in explicitly
associated Projects. Project membership is optional context; it does not establish Concern
identity or authorization. A shared Concern retains one identity across its relations. A materially
different question or acceptance basis gets a distinct Concern with an explicit derivation link.
Neither a Project nor a Conversation, Run, Composition, or Covenant is required to create one.

A dedicated Concern surface lets a reader begin with the question itself: inspect its meaning
and criteria, break it down, find what remains unaddressed, follow the parts to their destinations,
and inspect the judgments and evidence. A Project view gathers the same material in its brief's
context while preserving that independent entrance.

The relation contract distinguishes:

| Relation | Meaning |
| --- | --- |
| Decomposition | A parent question is developed into smaller Concerns, with a reason for each part and any remaining scope made explicit. |
| Addressing | An exact part of a proposal, decision, document, application contract, implementation, or procedure is intended to address a Concern, with its contribution and limits stated. |
| Source | A Concern was inspired by or derived from identified material, or is constrained by a rule explicitly adopted in its context. Inspiration and adopted obligation remain distinguishable. |
| Assessment citation | A judgment uses particular retained references as evidence against an exact Concern and context basis. |

Decomposition is acyclic and may share a child between parents. A view preserves those shared
identities instead of duplicating the questions. Decomposition does not imply complete partition,
execution order, or sufficiency: the parent retains its own criteria, unresolved remainder, and
judgment even when every child has a sufficient assessment. General relatedness is not a
decomposition or an addressing claim.

Addressing is many-to-many. Each relation retains its author, rationale, exact target locator and
revision or content identity, and whether it names proposed or accepted material. The map exposes
missing, partial, conflicting, unavailable, and changed targets without equating a link with
implementation or proof. Decisions can name the Concerns they address. For application design,
this account explains how the parts serve the Concerns and which needs still have no home. An idea
or ordinary application need not become a native LychD Composition to be mapped. When the target
is a native Composition or Pattern, [Workflow](28-workflow.md#concerns-and-application-design)
keeps its contract and publication authority with that owner.

An assessment binds the exact Concern revision and any context it judges. When it relies on
decomposition, child judgments, source obligations, or addressing relations, it retains those
specific revisions as part of its basis. Relevant changes require review while preserving the
original judgment. A judgment made for one Project's brief does not silently become a judgment
for another context. Summaries retain the difference between an addressing claim and assessed
sufficiency; child counts and completed Runs cannot create a coverage verdict.

Concerns are authored directly or proposed through decomposition or selected source material.
An idea or Project may develop its own Concerns and its own Covenants. A Concern may motivate a
Covenant; an adopted Covenant may in turn suggest further Concerns. LychD's Covenants are an
optional source of inspiration, with no default import or authority over unrelated work.
Other sources and Concerns without any Covenant remain equally admissible.

Seeding or spawning produces attributable proposals: the used source and exact revision or
content identity, the relevant passage, and the interpretation for the intended context remain
inspectable. Acceptance explicitly creates or revises the selected Concerns and relations;
regeneration proposes a comparison instead of overwriting authored meaning. A source change
requires review of affected derivations without silently rewriting them. Generated proposals do
not adopt a Covenant, assess coverage, publish an application, or admit execution by themselves.

[Persistence](06-persistence.md#independent-concern-retention) owns retention and
migration. The initial Project aggregate and activity-only references do not implement this
independent identity, relation model, or proposal flow; [State](../state-of-the-work.md#atlas-projects)
keeps that delivery boundary explicit.

### Projection law

> The Vessel emits validated snapshots, semantic events, and admitted mutation intents. The Altar
> projects them; it does not settle system truth.

Loom and Orb share one framework-neutral graph-projection supply in ordinary immutable TypeScript:
stable server identities and revisions, validated snapshots and ordered deltas, semantic nodes and
relations, declared fold groups and their membership counts, presentation-local selection and
viewport intents, and revision-fenced mutation intents. Folding and the semantic twin derive from
this supply, so both survive a renderer change and neither is owned by a dependency. Each instrument
derives its own view model over one shared renderer adapter. The supply contains no runes,
reactive proxies, XYFlow, Sigma, or Graphology objects, renderer geometry, or durable policy.
Mutating Loom gestures become explicit server commands; authority replaces the structural
projection after acceptance, rejection, gap recovery, or resync, while local camera, selection,
and focus are restored only while their identity and generation remain valid. A complete keyboard
and screen-reader twin derives from the same supply. This reuse is not a universal Graph or domain
model.

Browser reconstruction has three replaceable layers. A validated snapshot provides the base;
ordered deltas advance its cursor; URL, selection, layout, draft, focus, and related presentation
sit above them. Refresh, remount, a numeric gap, or `resync` replaces the projection from a
snapshot. An animation or open `EventSource` supplies no evidence of commitment.

Use `$state` only for template, `$derived`, or external-synchronization reactivity; use
`$state.raw` for large unit-replaced API objects, `$derived`/`$derived.by` for computation, and
`$effect` for DOM, browser, or network synchronization—not state propagation. Props change,
collections key by stable identity, and runes stay in components or presentation-owned
`.svelte.ts`. Snapshot or unwrap reactive values before Fetch, SSE, structured clone, IndexedDB,
worker, or extension boundaries. Generated contracts, Zod, Fetch wrappers, reducers, and domain
decisions remain ordinary TypeScript; a guard rejects runes in framework-neutral `.ts`.

### Typed JSON and semantic SSE

`scripts/export_openapi.py` builds a small schema application from production Altar controllers
and dependencies. Runtime and exporter share the same deterministic JSON-only OpenAPI
configuration; generated controller errors use Litestar's JSON `status_code`, `detail`, and
optional `extra` fields. The exporter does not run `create_app()` or its middleware, exception
handlers, lifespan, database, SAQ, or security configuration. The chain is:

```text
Altar controllers → clients/web/openapi.json → openapi-typescript
  → clients/web/src/lib/api/openapi.d.ts → aliases + openapi-fetch
```

Controllers own operation identifiers. Release regeneration and clean-source preflight expose
schema mismatches; a local command may rewrite tracked output, whose diff still needs review. SSE stays
outside `openapi-fetch`: Zod schemas, constrained to generated types, validate version,
identifiers, sequence, kind, and envelope. Kind-specific interpretation remains explicit because
run `payload` is currently a broad string-keyed record, not a generated discriminated schema.
Operations that raise a real not-found response explicitly publish the shared `FrameworkError`
schema; generated clients never infer success-only behavior for those paths.

#### Snapshots, streams, and recovery

Bridge is text JSON only: no voice upload, file/media admission, audio output, or streaming voice.
Its named JSON SSE envelope carries `schema_version`, `run_id`, producer-stable `event_id`, `seq`,
`kind`, `occurred_at`, and `payload`; kinds are `token`, `status`, `node`, `dispatch`,
`transition`, `fragment`, `consent`, `log`, `done`, and `resync`. The server observes
browser-managed `Last-Event-ID`, sends keepalives, and projects its process-local bus. Terminal
runs receive `resync`, not invented token replay.

The Bridge archive rail loads at most 50 session identities per page, ordered by exact creation
timestamp and stable identity. An opaque, validated keyset cursor and visible **Load more** retain
access to older conversations. Archive queries select metadata without hydrating other sessions'
turns or model history; pending-consent counts are grouped for the requested page. A selected
conversation remains independently addressable even outside that page. This bounds amplification
across the archive, not the selected conversation's retained turns, model history, or Run list;
those still load for the selected session and need a separate retention or history-pagination law.

HTTP Run event streams reserve process-local capacity before response headers: at most four per
Run and 32 per process. Excess streams receive `429` and `Retry-After`; closing, cancellation,
and failure before the first event all release the reservation. A stream limit never drops a
settled turn or changes Run execution. Existing bounded subscriber queues still replace overflow
with explicit `resync`, and browser reconnect uses its transport backoff.

The browser also bounds pending Run envelopes to 256 while an authoritative refetch is in flight.
Overflow closes that subscription and invokes bounded snapshot recovery; teardown clears pending
envelopes and fences late completion. A permanently closed native EventSource requires explicit
recovery rather than a claim that browser retries continue. This is an envelope-count limit, not
a payload-byte limit or a deadline for the snapshot request.

The client seeds from the snapshot cursor, serially validates and reduces events, ignores applied
sequence numbers, and refetches on gap or `resync`. Its initial cursor is reducer state: the
current `EventSource` constructor does not send an explicit cursor. A run or ticket identity
mismatch, invalid data, or failed authoritative refetch permanently closes that channel. Bridge
and Nexus immediately mark the projection stale and attempt one bounded authoritative recovery;
a second failure remains visibly stale rather than animated as live. Each Bridge Run projection
retains its applied cursor and a browser-local authority generation; a delayed recovery may replace
that Run only while both still match the request it began from. Ordinary transport errors remain
transient while `EventSource` reconnects. Durable terminal Run status overrides a lagging
process-local channel. Its retained agent answer and fragments take precedence over incomplete
live deltas while the captured stream cursor stays intact; absent a retained turn, live content
remains the fallback. Only a retained agent turn retires that terminal projection from the
selected session. Token deltas and channels are neither durable nor cross-process; retained
structural Step evidence is best-effort. Nexus uses its own versioned transition envelope with the
same retention boundary and completion-driven single-flight polling. Closing a channel fences
already-queued callbacks, so an event from a superseded ticket cannot overwrite the replacement
identity. Orb pagination likewise merges only when both the requested and current snapshot still
name the same Run; its Loom link additionally requires the entire valid pinned manifest to equal the
registered revision, as worker replay does.

Orb's catalogue reads metadata across Run statuses in newest-first creation-time/id pages, with
an opaque continuation cursor and at most 50 identities per request. It does not hydrate prompts,
manifests, or event histories. A selected snapshot supplies a workflow graph only when its full
pinned manifest equals the registered revision; a missing graph remains explicit.

Orb's separate retained-evidence SSE polls the ledger once per second, serving at most 100 records
per batch under the shared HTTP stream budget. Its versioned `evidence`, `reset`, and `settled`
envelopes bind Run identity, requested `after_seq`, delivered `cursor`, and the safe snapshot.
Live reads start at the snapshot's ledger head while history pagination keeps its own boundary.
`Last-Event-ID` overrides the initial query cursor on reconnect. Metadata-only updates may retain
the cursor; omitted sequence intervals remain explicit gaps. A future cursor requires snapshot
replacement. Ledger-terminal status drains the currently retained account before `settled` closes
the feed; this does not promise that every best-effort observation was retained. Token deltas and
private bodies never enter this feed. Slow readers delay their next bounded read without queuing
producer events. Disconnect closes the source and releases its reservation.

An optional Creation summary resolves the selected Run through its retained exact admission link.
The HTTP boundary checks current Creation read authority for every snapshot and stream poll; it
supplies only bounded metadata through a dedicated persistence read that cannot expire or settle
custody. Absence discloses neither case existence nor application configuration. Case status,
response adoption, native verdict, latest external assessment and current owner disposition stay
distinct from Run status. An earlier admission is explicitly historical: the supplied case-current
outcome may include later admissions. Metadata updates can retain the ledger cursor, and revocation
clears the summary. This does not extend terminal stream lifetime; later assessments or decisions
require an explicit authoritative refresh. Browser playback never rewinds this current metadata.

The parallel field opens at most three Run lenses and keeps at most 100 records in each. Its
counts describe loaded membership, and omitted older records remain available through selected-Run
pagination. Run changes, closed lenses, and teardown fence callbacks and abort owned reads.

#### Teardown

Component destruction advances the same local authority boundary. A request that settles after
teardown cannot attach a stream, mutate component state, schedule another poll, or navigate. Loom
uses its load generation for this rule; Orb aborts owned catalogue, snapshot, and pagination reads
and closes its streams as it advances that generation; Bridge and Nexus likewise fence stream
callbacks and timers.

### Closed rendering, readable form

#### Fragment descriptors

The Vessel validates `FragmentCall`s through a closed Pydantic registry and emits inert descriptors.
Svelte maps admitted kinds to compiled renderers and exposes unknown descriptors explicitly.
`{@html}` is forbidden and statically guarded. Invalid or unknown model fragments are dropped and
logged before settlement; client fallback merely contains malformed or newer descriptors. Settled
turns retain the complete validated descriptor, including props, so terminal refresh reconstructs
the same compiled component rather than preserving only its key. Legacy rows that predate descriptor
retention are normalized to inert schema-zero key-only descriptors with empty props; they remain
readable through an explicit inert fallback and never enter a current-version component renderer.

#### Consent and Bridge admission

Consent appears in its Bridge context and the shell count. The client submits one typed
approve/deny intent with the configured CSRF header; the Vessel rechecks identity, state, scope,
and idempotency before resume. Snapshot application versions selected-Bridge consent authority, so
an older decision response cannot overwrite a newer snapshot; after Run cancellation the selected
Bridge immediately revokes its visible consent cards and count, then refetches its snapshot. Root
route cancellation uses the selected snapshot session as that authority rather than a route prop. A
failed refetch cannot restore the revoked local authority. Instrument attention
events are invalidation hints only: the shell always re-reads the cross-session status endpoint and
request-version fences overlapping reads, so an arriving local count never becomes global truth.
The shell's attention link opens an explicit chooser of conversations with pending consent.
Per-session counts come from the server's consent-to-Run-to-session relation; the selected
conversation never presents the global count as its own attention.
The existing browser-shell workspace retains in-flight and uncertain consent verdicts by consent
id across refresh and navigation. Only the same verdict may retry after uncertainty, including a
later middleware refusal. Late responses invalidate their owning session for reconciliation;
newer snapshots retain authority. Unresolved decisions also trigger the document-unload warning.
Bridge message submission likewise retains one client UUID across an ambiguous response, and durable
Run admission maps that identity to exactly one canonical Run. A replay repairs an unresolved held
turn-retention gate before publication. Within one Bridge session, process-local admission permits
that exact replay but refuses a different message while any prior Run remains nonterminal; terminal
ledger truth admits the next turn without a separate active marker. The fixed visible `Magus` Sigil
is local bootstrap context, not an authenticated person. Applying a refreshed root snapshot for the
same canonically selected session preserves the unsent draft. Drafts and immutable unresolved
submission envelopes survive instrument navigation within the browser shell, separately for each
session. A later middleware refusal cannot establish that an earlier unknown admission did not
commit. Retry explicitly resends that same envelope; a new offering cannot replace it before
authoritative resolution. An in-flight response settles browser recovery state even if its view
has unmounted. Leaving the browser document warns while drafts or unresolved admissions remain;
this initial recovery state does not claim persistence across reload or browser termination.

#### Nexus request and refresh identity

Nexus retains an ambiguous transition request UUID per target, so inspecting another target cannot
discard the only safe retry identity. A lost-ticket conflict retains that UUID and refuses a fresh
physical launch. Only an initially definitive rejection clears that target; an earlier unknown
outcome survives later rejection. Leaving Nexus with in-flight or unresolved admission requires
explicit discard, while same-document inspector navigation retains the retry identity. Authoritative
refresh rebinds the inspector to the exact request id so a settled ticket cannot leave stale
pre-refresh transition detail selected. Board
refresh remains single-flight, but a refresh requested while one is in flight marks a dirty trailing
pass; the settling read cannot erase a newer invalidation.

#### Renderer and native CSS boundaries

Extensions have no UI source, template, script, import, or third-party sandbox surface.
Loom and Orb use one `@xyflow/svelte` adapter over their immutable semantic projections. Its
coordinates, camera, selection, and motion remain disposable presentation. The keyboard-operable
station outline, Run list, and record inspectors remain available when rendering fails. Neither
canvas admits publication, execution, connection editing, or durable layout mutation. Installation
does not discharge the lifecycle and semantic-twin admission gates below; State owns the receipt.
Plain-text source lives below `/api/v1/loom/source/workflows/{workflow}` and
`/api/v1/loom/source/patterns/{pattern_id}/{revision}` so every legal two-segment exact Pattern route
remains addressable. Exported Mermaid retains the exact Pattern key and revision in its title and
the manifest digest as inert source metadata. Mermaid source is not Pattern data or proof of
execution.

Recorded graph playback uses an explicit Run sequence cursor over loaded structural evidence.
It filters node observations and supplied Animator grant identities at that cursor, while current
Run status and connection state remain separately labelled. A grant records selection, not a
model-call duration or an Animator uptime interval. Missing lifecycle evidence remains unknown;
current Nexus readiness cannot fill a historical gap. Hover discloses semantic detail without
changing selection, cursor, authority, or the declared score.

Native CSS uses custom properties, cascade layers, media queries, semantic classes, and state
attributes. Type, label, icon, shape, and copy carry meaning without colour; the stylesheet has a
skip link, visible focus, hidden labels, narrow layout, and `prefers-reduced-motion`. Inspectors
restore their live opener after closing when one exists; deep links use router focus reset.
Tailwind, Sass, project-owned PostCSS, and a parallel styling vocabulary are forbidden. Transitive
Vite packages in the lockfile are not a styling API.

### Decision lock and reopening gate

A greenfield review compared React 19 with Vite, Node with Bun, native CSS with Tailwind,
shared with separate Loom and Orb renderers, and a Rust/Wasm frontend. It reaffirmed the following
architecture. The renderer qualification and editing gates below remain binding on the
read-only projections described above and any later expansion.

- **Svelte 5 with static SvelteKit remains the Altar framework.** React's more explicit effect
  diagnostics and React Flow's tagged renderer changes are real advantages, but renderer changes
  are not domain commands. They did not establish that Svelte cannot preserve the same authority,
  recovery, accessibility, route, and release contracts with less total maintenance.
- **Node 24.20 with npm 12.0 remains the only verified JavaScript build grammar.** Bun is not a
  supported installer, runner, or runtime: adding it beside Node/npm would create a second runtime,
  lock, and command meaning without replacing the accepted path. Reopening requires one complete
  matched repository receipt that replaces or passes every Vite, Vitest, browser, notice, and
  release gate—not install speed.
- **Native semantic CSS remains the only styling vocabulary.** A large stylesheet is repaired by
  token, base, shared-chrome, graph-seam, and instrument ownership—not by adding Tailwind's scanner,
  utility grammar, or a parallel cascade truth.
- **Loom and Orb share one DOM renderer.** A second renderer buys a second adapter, semantic twin,
  teardown audit, licence review, and browser-quirk tail; no measured workload requires that cost.
  They share immutable TypeScript contracts, identities, commands, selection/camera protocols,
  telemetry, folding, and a model-derived semantic twin. They do not share instrument view models,
  and shared code never lets one instrument's authority reach the other.
- **Nexus remains a native semantic control board.** Its cards, preview, ticket, and inspector are
  primary. The first trial for a future body map is a read-only Svelte DOM/SVG projection; it does
  not need an editor or dense-graph engine without a measured topology requirement.

Reopening requires evidence of a failed product contract. Popularity, hiring pool, model-training
volume, community enthusiasm, articles, polls, toy examples, source-line count, bundle size and
isolated microbenchmarks may suggest an investigation; they cannot settle it. Reopen the Svelte
decision only when an executable product-shaped receipt
shows that the accepted stack cannot meet a required security, packaging, accessibility,
deep-link, recovery, lifecycle, or measured workload contract and a named replacement passes that
same contract. A replacement must also preserve every existing Litestar route, generated API,
focus-reset, asset-mount, API-404, notice, and release-artifact gate.

#### XYFlow admission

The shared XYFlow adapter remains subject to a measured qualification gate. Its [shared pan/zoom
implementation](https://github.com/xyflow/xyflow/blob/main/packages/system/src/xypanzoom/XYPanZoom.ts)
creates a `ResizeObserver` that its destroy path does not disconnect, and upstream declares that
omission deliberate: `destroy()` also runs to pause zooming during a user selection, so
disconnecting there would leave the extent cache stale. Under the
[observer-lifetime rule](https://drafts.csswg.org/resize-observer/#resize-observer-lifetime) an
observer dies only when it holds no scripting reference **and** observes no target, so an
unreferenced observer that still observes is retained by the specification alone. Collection
therefore depends on the engine holding its target weakly, which Blink does; Gecko and WebKit are
unverified. Counting live observers still measures upstream intent rather than retained memory, but
the specification does not by itself clear this path. The gate is measured retained heap: repeated
mount, replacement, settlement, and HMR cycles followed by forced collection must show no growth on
every supported engine, and reasoning does not substitute for that measurement. A candidate must
also prove,
through public APIs and without a maintained fork, private-store access, whole-flow remount, or
renderer-state authority, that drag, keyboard movement, resize, measurement, selection, connect,
reconnect, delete, rejection, and resync preserve the authoritative semantic twin.

#### Loom workload and editing gate

Loom’s designed editing workload is a workflow score. The registered Bridge and delegated-rite
Scrolls place five and three stations over six and three permitted edges, respectively; the latter
includes the [delegate's durable re-entry loop](28-workflow.md#pattern-identity). Admitted Suite
grammar keeps this workload in the tens to low hundreds. Orb is bounded by folding rather than by
volume. Neither workload justifies a dense engine, and a dense engine supplies neither Loom's drag,
connect, reconnect, and handle grammar nor a DOM-native accessible twin.

Loom's editing admission is separately gated on contract, not on renderer. The served semantic score
carries no position, and the Scroll grammar declares no layout document, so no drag may be admitted
before authority owns layout and mutation intent. Until then Loom is a read-only projection over a
computed layout. XYFlow also has no keyboard path to create a connection; its connection handles are
not focusable. Loom therefore either owns that path above the renderer or admits editing without it,
and admitting editing without it would break the keyboard twin this Covenant requires.

### Folding, not scale

Folding keeps a field readable at every camera scale. An unreadable field cannot serve as
evidence, regardless of the renderer. Bounding the rendered set follows from that reading rule
and is what keeps a DOM renderer sufficient.

Folding follows structure the authority already declares—for Orb, Run, then station subject, then
occurrence, then event, with delegated jobs as their own declared groups. Zoom may choose among
these levels; explicit detail controls provide the same operation without a zoom gesture. A group states
its loaded membership count, names any unknown total or unloaded members, carries its declared name,
and remains selectable and expandable through the same
typed identities. Geometric or computed clustering is not admitted: proximity would assert a
relation no authority declared, and a group must never be readable as evidence LychD did not record.

Folding is presentation only. It never merges, omits, or reorders retained sequence truth, and an
unexpanded group whose members were never served is an explicit unknown, exactly like a sequence
gap. Bounded expansion remains a Vessel contract: authority serves what was asked for, and the
browser holds only what it was served. Folding belongs to Loom and Orb through their shared supply;
Nexus folds by disclosure in its own board and inherits no renderer.
Current Pattern manifests do not supply nested subworkflow or parent-Run identities. A station,
delegated job, or shared name cannot manufacture that hierarchy; deeper nesting remains unavailable.

### Deferred dense renderers

Sigma with Graphology and cosmos.gl are mapped, not admitted, and are reopened only by a measured
field that folding cannot bound—not by node count alone. Both are FOSS: Sigma's closure is MIT
throughout; cosmos.gl became admissible only after moving to the OpenJS Foundation under MIT, its
predecessor having carried non-commercial terms that failed this Covenant outright.

The mapping gives later reviews an evidence base. Zoom-driven aggregation remains LychD's
responsibility: neither candidate, nor any surveyed commercial alternative, supplies it. That is
why aggregation is a supply rule above rather than a selection criterion. Sigma re-indexes its
whole graph on node removal, while bounded expansion requires eviction. cosmos.gl has no link
removal path, so any edge-touching patch rebuilds the whole link set; its identity-keyed streaming
API is published only in the separately sold non-commercial tier. Neither handles WebGL context
loss or supplies an accessibility surface, leaving a second semantic twin to build and synchronize
indefinitely. G6 was rejected outright: its published maximum-scale demonstration fails, combo
collapse is a pointer-triggered action on hand-declared groups rather than zoom-driven aggregation,
and teardown discards its context while asynchronous work still holds it.

Admission would still require realistic scale, incremental patch, camera/selection recovery,
WebGL-context loss, teardown, complete semantic-twin, licence, and notice receipts, and any admitted
graph structure would remain a disposable projection cache, never Run truth. Custom WebGPU or a
narrow Rust/Wasm worker is an escalation only after profiling proves that this path cannot meet the
same contract; it is not a route to rewriting the browser shell.

### Canonical appearance and bounded palette configuration

The canonical Altar has one complete built-in appearance: **LychD Dark**. Dark is the product
default and the only appearance Core currently designs, releases, and supports. The document and
native controls use a dark colour scheme; Core does not follow `prefers-color-scheme`, expose a
light/system selector, or create presentation state merely to imply choice. “Readable by day and
night” remains an acceptance target requiring contrast plus bright- and dim-environment browser
receipts, not a conclusion inferred from dark tokens.

The styling boundary nevertheless stays configurable in one deliberately narrow direction. A
future operator-local palette may provide a partial map over an allowlisted set of semantic colour
roles—for example page and panel surfaces, primary and secondary text, focus/rune, ready, active,
warning, refusal, borders, and decorative accent. Resolution starts from the complete pinned LychD
Dark palette, applies valid overrides, and falls back per missing value. The public configuration
names semantic roles rather than CSS variable or selector identities; Frontend owns their meaning,
while [Configuration](12-configuration.md) must admit any future typed source and precedence before
it is delivered.

An override value uses a restricted, resource-free colour grammar and cannot contribute selectors,
declarations, functions that fetch resources, `url()`, fonts, layout, visibility, opacity,
animation, HTML, Svelte, JavaScript, routes, or assets. Validation preserves required contrast,
visible focus, forced-colour behavior, non-colour status distinctions, and the legibility of
consent, refusal, fault, unknown, and evidence states. Missing roles inherit their canonical
values; an explicitly invalid map is refused before application rather than producing a
half-themed Altar.

Components, diagrams, and overridable artwork consume the resolved semantic palette or declare
themselves fixed LychD brand assets outside it. Mermaid, browser chrome, native controls, static
art, and generated surfaces cannot keep an undisclosed second palette. A future named palette
package may serialize this same finite map only after Extensions and Packaging admit its
provenance, licence, static build, compatibility, and accessibility receipts; it never opens a
runtime CSS plug-in surface.

Palette choice is local presentation configuration. It never changes a Run, Pattern, event,
artifact, consent, authority, status, or retained evidence, and it cannot remove their textual and
structural cues. The current implementation has only the fixed LychD Dark palette and no operator
override source; [State](../state-of-the-work.md#altar-and-observability) owns that boundary.

### Interface locale and content language

The future localization boundary uses ordinary framework-neutral message catalogues and
locale-aware formatters for Altar chrome. Canonical route, API, Pattern, Spell, Run, event, status, and field
identities remain stable and untranslated. Components consume message identities and typed
parameters; a translator or model never supplies HTML, Svelte, executable templates, or domain
keys. Catalogues are reviewed static client assets under the same FOSS, notice, CSP, and release
boundary as the rest of the Altar, not a runtime translation service.

The FOSS reference Altar deliberately targets English as its sole required interface locale. This
keeps the reference implementation, review surface, release evidence, and contributor obligation
small; it does not permit English grammar, word order, or left-to-right layout assumptions to enter
canonical identities or application contracts. A multilingual interface remains permitted future
work rather than a current Product goal. Another locale may enter later as an optional, reviewed
static catalogue and formatter contribution with exact compatibility, provenance, licence, and
accessibility evidence. It is not a skin, arbitrary client-code plug-in, or support claim merely
because a community translation exists.

Under that contract, locale resolution is explicit Altar choice, then an admitted Principal preference, then a browser
language hint, then an admitted operator default, then English. The current loopback `magus:*`
bootstrap is not an authenticated Principal and may retain only a presentation-local choice.
Applying a locale sets document `lang` and direction and governs dates, times, numbers,
pluralization, visible copy, and accessibility text. Every admitted locale owes fallback,
missing-message, overflow, keyboard, screen-reader, and bidirectional-layout receipts; a catalogue
claim alone does not establish support.

Interface locale is separate from content language. A Magus may use a Slovak Altar while reading
an English prompt, original Japanese evidence, or another language selected for speech, image,
video, or music. Changing locale never translates retained content. Translation is an explicit,
attributed semantic transformation that preserves source text, target language, implementation
revision, declared loss, and authority. Persona language or a model's detected language never
silently changes the Magus's interface. Speech input and output may support additional languages
while the Altar chrome remains English; speech capability does not imply an installed or supported
interface catalogue.

The delivered Altar remains English-only: it has no message catalogue, locale selector,
Principal-preference binding, or right-to-left receipt. Browser-native formatting that happens to
follow a device locale is not this contract; [State](../state-of-the-work.md#altar-and-observability)
owns the exact material boundary.

### Build boundary, security, and reopening

Development runs Vite on `127.0.0.1:5173`, proxying `/api` and `/schema` to the loopback Vessel.
Production serves static Atlas, Bridge, Orb, Nexus, and Loom shells; unknown APIs and retired paths stay
404. Every operation that raises a runtime not-found across those verticals declares the shared JSON
`FrameworkError` contract. `npm ci`, OpenAPI and notice generation, compilation, and Python build share a release source.
Audit verifies source identity, compiled `index.html`, and archive notices—not a real browser or
running image. Only `src/lychd/public/_app` is broadly mounted; the two known root artifacts,
`/altar-lightning.svg` and `/THIRD_PARTY_NOTICES.txt`, have narrow typed Litestar handlers.

The Altar is loopback-only. Defaults use same-origin CORS, accept only explicit loopback Origin
exceptions, constrain Host to literal loopback authorities, and expose schema JSON without remote
documentation assets. CSRF remains an unsafe-method layer, not authentication; ordinary requests
still receive the fixed bootstrap Sigil. The foreground launcher can expose configuration the app
cannot observe, security-header and production-browser receipts are absent, and no remote
principal exists. The [isolated developer fixture](11-backend.md#isolated-developer-fixture-designed)
may use its configured loopback Vite proxy under [Security's](09-security.md) bounded exception.
Remote access, production access through a proxy, tunnels, direct-image-public access, and
untrusted-browser use remain unsupported. Authenticated browser acceptance of the fixture
remains pending.

Focused checks cover Svelte/TypeScript; frontend API, cursor, remount, stream, focus-return, and
GenUI tests; Python routes, controllers, consent, SSE, fixed root assets, and the instruments;
guards for unsafe HTML, server modules, styling, and misplaced runes; plus static build and archive
audit. They do not establish Playwright against `create_app()`, full keyboard/a11y behavior,
hostile-browser security, performance budgets, Node-free production image, or durable
cross-process events.
The [decision lock](#decision-lock-and-reopening-gate) is the exhaustive reopening rule. A build,
security, or renderer task applies that gate rather than starting another framework comparison.

## Consequences

!!! success "Positive"
    One generated protocol and Svelte projection replace the hybrid stack; snapshots, cursors,
    stable identities, and visible gaps keep loss explicit.

!!! failure "Negative"
    The SPA needs JavaScript, process-local streams cannot recover token history, and browser
    accessibility, lifecycle, root-asset, performance, and hostile-browser receipts remain open.

---
title: "16. SDLC"
plain_name: "Design rule 16: Software change lifecycle"
section: "Covenants"
original: https://hexanomicon.dev/adr/16-sdlc/
guide: https://lychd.snayu.ai/docs/adr/16-sdlc/
---

# 16. SDLC (Design rule 16: Software change lifecycle)

## Plain-English summary (Snayu)

**What it is:** Defines how a code change moves from request through candidate work, verification and delivery: each handoff keeps its evidence, and only the owner of the target system may apply the change.

**Why it matters:** Read this before building or using automated code-change workflows, or when deciding how a change gets promoted.

- Flow: change request, candidate, verification, promotion request, then the target owner applies the effect.
- A candidate never runs inside the live server; promotion starts a new system generation instead.
- Verification only permits a promotion request; commands, versions and results are kept as receipts.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    Software delivery begins with a need and continues through design, construction, verification,
    release, operation, and revision or retirement. File control protects one part of that passage;
    the software development lifecycle (SDLC) must also preserve intent, acceptance, evidence,
    authority, and recovery across its handoffs. Autopoiesis may eventually let LychD extend itself,
    but a candidate becomes part of the body only through its target owner's admitted effect.

## Requirements

- Bind the intended outcome, current-state evidence, scope, acceptance criteria, and affected
  owners before committing to construction; unresolved choices need bounded inquiry.
- Carry those decisions through candidate work, verification, delivery, and observed outcomes.
  Changed intent or acceptance requires an attributable revision and renewed affected checks.
- Candidate writes must not alter the active source tree or running package.
- A candidate must bind its base revision, patch or artifact digest, principal, tools and
  dependency inputs, declared effects, and resource budget.
- A workspace is not a sandbox: processes, network, credentials, databases, and host effects need
  separately admitted boundaries.
- Commands, versions, environment, result, and error class must be retained as verification
  receipts.
- The eventual target owner—not the creator—must recheck current state, authority, evidence, and
  recovery at promotion time.
- The target owner must compare a candidate with any base-revision Protected Region manifest;
  overlap requires an exact live human verdict and cannot use standing preauthorization.
- Lineage and terminal disposition must remain attributable, so interrupted work can resume or be
  discarded without touching the live body.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| Live hot-reload | Rejected | It mixes candidate and active object graphs before promotion; cleanup can prove only mediated registrations, not restoration of process memory or external effects. |
| Ordinary pull request | Safe current route | Human review and merge remain a fallback, but do not encode admission, budgets, execution isolation, or receipts. |
| Shadow candidate and owned promotion | Selected design | It makes candidate failure external to the body and keeps the final effect with its proper owner. |

## Decision Outcome

LychD carries a software change through explicit handoffs: intent, candidate work, verification,
delivery, and subsequent change each retain their evidence.
**[Creation](../sepulcher/extensions/weaver/creation.md)** is the practical workflow for that
passage. This Covenant owns lifecycle invariants and the candidate-to-effect boundary; Creation
provides the repeatable method, including Inquiry, task decomposition, review, and human decisions.

Its candidate-to-effect chain is:

`Creation Request → Candidate → Verification → Promotion Request → target-owner effect`

A candidate never mounts, imports, or executes as a plugin in the active Vessel, even as a
temporary trial. Removing callbacks or a module would not prove that its objects, tasks, caches,
foreign-library state, or emitted effects had vanished. Promotion therefore selects a new body
generation rather than trying to clean a candidate out of the current process; continuity crosses
that boundary only through owned durable records and explicit recovery semantics.

The lifecycle currently proceeds through ordinary operator-controlled development and review,
with checks run through development and CI. Verification authorizes only a request for promotion;
it does not execute the live effect.

`PATH_LAB_DIR` and its read-write Vessel mount support trusted preparation in the Lab; the image’s `/app` remains read-only. This writable directory supplies neither an operational code Forge nor execution isolation.

[Creation investigation](../compositions/creation/index.md) revision 2 fixes the narrower native
application contract for immutable public-source questions, retained analysis candidates and
separately attributed verdicts. Its Pattern is `creation.investigate@2`; the wider Creation method
does not become one application or coordinator. That profile creates an artifact without an
executable workspace and requests no promotion. The broader custody, compatibility, review and
promotion records below remain accepted design. No autonomous repair loop, Tomb executor, verified
package promotion, compatibility gate, rollback controller or self-extension runtime follows from
publishing the investigation contract. [State of Work](../state-of-the-work.md#smith-forge-promotion)
owns implementation and delivery status.

### Retain external assessment before another change

Creation may append an externally supplied assessment to exact retained investigation evidence,
then retain an explicit local owner's hold or rejection. Preserve the report bytes and claimed
reviewer separately from authenticated submitting authority and any submitter annotations. Native
verdict, external judgment and owner disposition remain distinct; completion, agreement and a
recorded decision grant no execution or promotion authority. The
[bounded application contract](../compositions/creation/index.md#external-assessment-and-owner-hold)
fixes custody, settlement, replay and authority. This attachment is no native Drift Outcome and
changes neither Drift's evaluation jurisdiction nor delivery status. A successor needs its own
inputs, acceptance, admission and lineage; no automatic successor follows from feedback.

### Lifecycle and ownership

When evidence defeats a premise, the lifecycle can return to the relevant question while retaining
the prior decision and outcome. That return identifies which checks must run again. Acceptance
criteria must exist before the verification they judge; revising them creates a later comparison
and cannot turn the previous failure into a pass.

| Passage | Required handoff | Owning law |
| --- | --- | --- |
| Need and design | Intended outcome, present evidence, alternatives, scope, acceptance, and a settled direction | This Covenant; [Doctrine](01-doctrine.md) governs documentation-first design. |
| Construction | Attributable candidate, exact base and inputs, bounded workspace and execution, declared effects | This Covenant; [Security](09-security.md) governs containment and [Workflow](28-workflow.md) governs an executable score. |
| Verification and review | Reproducible checks, independent findings, unresolved gaps, and an exact review target | This Covenant; [Quality](03-quality.md), [Testing](04-testing.md), and [Evaluation](34-evaluation.md) retain their separate gates. |
| Release and adoption | Verified artifact identity, current authority, compatibility, and recovery evidence | [Packaging](17-packaging.md) binds release artifacts; [Evolution](18-evolution.md) owns changed-body adoption; each effect remains target-owned. |
| Operation and revision | Attributed outcomes, failures, and proposed corrections for another admitted change | [Observability](29-observability.md) and [Evaluation](34-evaluation.md) supply evidence; this Covenant governs the next candidate. |
| Retirement | Explicit disposition of the capability, affected work, retained records, and outstanding effects | The capability and effect owners apply their shutdown and recovery law; [Persistence](06-persistence.md) governs retained state. |

Learning from delivery may change the next question, Context, procedure, or implementation.
[Memory](27-memory.md) and [Training](33-training.md) separately govern retained lessons and
weight changes; [Assimilation](35-assimilation.md) governs incorporating foreign craft. Closing
one software task neither initiates training nor authorizes another live change. The lifecycle
connects these decisions without creating a universal executor or absorbing their authority.

### The agentic Graph of Creation

The [Transmutation](../divination/transmutation/index.md) reading path connects the
[Tree of Life correspondence](../divination/transmutation/genesis.md#tree-of-life) for differentiated powers bringing purpose
into form with the operating methods below. LychD's **agentic Graph of Creation** is the engineering interpretation:
admitted intent and present evidence become alternatives, discriminated decisions, a verified
candidate, and an attributable owner effect. The sefirot do not prescribe ten Agents, replace the
four coequal offices of the inner instrument, or supply executable Graph contracts.

The [Creation workflow](../sepulcher/extensions/weaver/creation.md) applies bounded exploration,
independent evidence-sufficiency judgment, and Crucible first to direction and again to
construction where the decision warrants it. Its operation remains subject to the candidate,
verification, and promotion law below. An application must publish its exact Pattern before this
method becomes a LychD casting; the diagram alone registers no Pattern or coordinator.

[Ouroboros](../sepulcher/extensions/weaver/ouroboros.md) maps the return from outcomes and human
correction through evaluation to separately admitted memory, procedural change, or training.
Autopoiesis names the wider horizon of recurrent self-formation, not an exception to effect
ownership. Drift findings cannot mutate a candidate or score; Soulforge cannot promote its own
weights; a changed body follows Packaging and Evolution. Each successor retains lineage and its
own admission. The dependency map does not combine those owners into one hidden Run or make the
whole recurrent process a DAG. Immutable records of its unfolded occurrences may form a causal DAG.

### Progressive bootstrap and recurring work

Operator-controlled campaigns are the initial execution road. They retain their actual platform,
task, worker and artifact identities, observed permissions and explicit evidence gaps; they do
not manufacture native Runs, containment receipts or evaluation records. A native coordinator
can replace a handoff only after its typed contract, admission, custody, settlement and recovery
are proved. Foreign harnesses retain private planning while LychD retains task semantics and
receiving-owner authority. An executable development application must publish its own exact
Pattern before assuming native coordination; this law creates no general SDLC or Assimilation
coordinator. The [bootstrap procedure](../sepulcher/extensions/weaver/development-bootstrap.md)
orders the small implementation gates. The first external CLI owner binding may use the
operator campaign's immutable task, projection, custody and verification records under
[ADR 14's versioned intent contract](14-workers.md#versioned-cli-intent-and-owner-binding).
Those references preserve attribution; their parser and a fixture admission are not an owner
record service or proof of source closure, authority, custody or available verification capacity.
The actual producer must check that closure before usable admission. This does not manufacture a
native Creation Request, Run or generic SDLC coordinator.

Recurring or spare-capacity work selects from owned, eligible tasks under current standing
authorization. Each occurrence requires a named acceptance owner, observable benefit, exact
inputs, scope, acceptance, termination, and reserved verification/review and recovery capacity
within the global budget. Capacity includes human attention and pending candidates, not only
model tokens. Missing capacity, expired authority, exhausted budgets, unresolved external outcomes
or absence of useful eligible work stops dispatch. Numerical concurrency and retry limits belong
to a versioned operating policy, not a universal model topology.

Completion authorizes no successor or authority expansion. A successor is independently admitted
under the standing scope; a retry records its changed hypothesis or justified replication and
consumes the same parent budget. Proposed changes to evaluators, protected cases, acceptance,
budgets or promotion policy are separately reviewed candidates. They cannot retroactively make
a failed artifact pass. Recurrent construction, procedural improvement, training and live body
adoption remain separately owned passages.

### External workflow research

A future local implementation or explicit service integration may draw candidate SDLC contracts
and evaluation cases from an independently operated workflow forge. The external owner keeps
its scope and delivery evidence, and reuse requires neither migration nor retirement of that
project. Each admitted reuse must separately prove this Covenant's admission, candidate,
verification, and promotion boundaries. A graph, trace export, or favorable benchmark cannot by
itself import runtime behavior or grant LychD effects.

### Admission and candidate identity

The bounded investigation profile retains its literal source bytes, declared base, criteria,
role bindings, reservations and reports under its Composition. It implements its own current
local object/action policy; fixed Sigil scopes or historical authentication attribution do not
authorize another startup. A fresh, eligible continuation is a separately admitted Run against the
same immutable case, never generic orphan replay. Complete packet bounds, uncertain-inference
custody and release conditions belong to its versioned profile.

A Composition may expose explicit successor admission from exact settled feedback. Its contract
must bind the parent target, current assessment and owner decision to fresh child inputs,
acceptance, authorization and a finite allowance before publishing execution. Admission consumes
that allowance durably; publication failure does not silently refund it or authorize another
identity. Replay preserves original attribution and repairs only the same held delivery under
current authority. The Composition owns whether later feedback makes lineage historical; it must
not rewrite the parent or turn a hold into permission. The
[bounded Creation contract](../compositions/creation/index.md#explicit-successor-admission)
allows one independently authorized child and no descendant chain. This supplies no recurring
work selection, parent-budget renewal or measured improvement claim.

For code-producing work, an immutable **Creation Request** names the principal and intent; exact base revision, admitted
source-tree digest, and allowed paths; tools, effect classes, credentials, network policy, and budgets; required verification and
retention; and the promotion owner and authorization class. It then receives a candidate identity
and allocated workspace. Lab's writable directory conveys no subprocess or network containment.

Each Shadow branch retains the request and exact parent state, but has its own lineage, budget,
outputs, and disposition. Branches do not share a mutable workspace. The
[Shadow contract](31-simulation.md) owns branch records and collapse. A VCS revision—including a
Jujutsu change—proves comparison and provenance, not hidden model reasoning or execution
containment. [The Call](../sepulcher/lich/call.md) gives this opening its correspondence, not its
storage or authority rules.

### Candidate work and proof

Candidate work may write only its allocated workspace. Any command with process, package,
credential, port, database, or network effect needs its own admitted executor and policy; path
restriction alone is insufficient. Independent work may run in independent workspaces, with an
explicit merge boundary. Its output is an immutable patch or artifact reference with structured
observations and declared effects. [The Blade](../sepulcher/lich/blade.md) names discrimination
among possibilities; it is not an acceptance rule.

The request pins its verification plan: commands, tool versions, environment inputs, timeouts,
expected artifacts, and pass criteria. Lint, types, unit tests, build, and migration probes remain
separate from heuristic review such as [Drift](34-evaluation.md). A qualitative verdict cannot
override a failed deterministic gate. A failure can consume a bounded repair attempt; exhausted
budgets or missing premises settle as noncompletion with retained evidence. Candidate-declared
database, package, install, and recovery checks use disposable state where appropriate and prove
the recorded execution, not production fitness.

Today those checks are operated through development and CI. Workers or Tomb may dispatch admitted
work only after their execution boundaries exist; this ADR does not claim that
[Ghouls](14-workers.md) verify generated code today.

### Promotion is an owned effect

A **Promotion Request** carries the exact candidate-record binding, current-base and source-tree preconditions, receipts, declared
effects, compatibility evidence, and rollback or compensation instructions. It neither moves Lab
into Crypt nor assumes a federated lockfile. At effect time the target owner must:

1. revalidate the live base, source tree, and candidate identity;
2. evaluate [Consent](25-hitl.md), or a narrowly bounded preauthorization; a
   [Protected Region](28-workflow.md#authorship-provenance-and-protected-regions) forbids
   preauthorization and binds live review to the exact candidate;
3. confirm that the evidence is current for this effect;
4. use its own transaction and recovery boundary; and
5. verify the resulting state or invoke rollback or compensation.

Source, package, and extension movement belongs to [Packaging](17-packaging.md),
[Evolution](18-evolution.md), and [Assimilation](35-assimilation.md). Database, credential,
host-lifecycle, and external-service effects remain separately owned; a VCS merge cannot make
them atomic.

### Changed state, conflict, and recovery

A changed base or source tree, or an unresolved conflict, stops promotion. Keep the candidate and
its evidence for diagnosis; neither discard them silently nor apply them over operator work.
Continuation requires a new base, resolved conflict, renewed invalidated checks, and fresh
authorization when the effect changed. Any external effect already produced remains its owner's
reconciliation responsibility and cannot be hidden by VCS cleanup.

An implementation must demonstrate candidate identity and workspace containment, refusal of
active-tree mutation, receipt capture, crash recovery, refusal after state changes, effect-time
authorization, target-owner promotion, and rollback or compensation. Untrusted execution additionally needs the
Tomb controls owned by Security.

## Consequences

!!! success "Positive"
    Candidate failure stays outside the active body, while identity, evidence, authorization, and
    disposition remain attributable.

!!! failure "Negative"
    Isolation, retained proof, revalidation, and owner-specific recovery cost time and storage;
    external effects still require compensation rather than one universal transaction.

---
title: "17. Packaging"
plain_name: "Design rule 17: Packaging and releases"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/17-packaging/
guide: https://lychd.snayu.ai/docs/adr/17-packaging/
---

# 17. Packaging (Design rule 17: Packaging and releases)

## Plain-English summary (Snayu)

**What it is:** Defines how source, dependencies, the built web UI, license notices and build evidence are bound into inspectable release artifacts. A successful build never means permission to publish, migrate or restart.

**Why it matters:** Read this before changing dependencies, build scripts, images or the release process.

- Runtime imports belong in wheel metadata; developer tools stay in dependency groups.
- A running server never installs or rewrites its own trusted dependencies.
- Each candidate binds one clean Git commit, version, built UI and legal notice set; archives are checked outside dev environments.

**Status:** Partial. Candidate auditing exists; the public release chain and automatic rebuild are designed.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    The Forge binds source, dependencies, generated client material, notices, and build evidence
    into inspectable artifacts. Rebirth is a later activation decision: a successful build is not
    permission to publish, migrate, restart, or activate a body.

## Requirements

- Runtime imports live in wheel metadata; contributor tools stay in dependency groups.
- Every candidate binds one clean Git object, version, generated Altar, and legal set.
- Archives are inspected outside a populated developer environment.
- A running body does not install or rewrite its own trusted dependencies.
- Future composed bodies need an inspectable closure and conflict report before activation.
- Keep collaboration, canonical source selection, verification execution, release authorization,
  artifact publication, and public projection as separately evidenced and replaceable offices.
- Bind any collective release authorization to an immutable source object, artifact closure,
  verification evidence, and versioned signer policy rather than a branch, pull request, runner,
  or forge account.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| Install into the running Vessel | Rejected | It merges build and runtime authority and defeats review, rollback, and notice accounting. |
| Let one builder define the architecture | Rejected | BuildKit, Nix, or another tool may change; inputs, outputs, and receipts are the contract. |
| Source-bound wheel, sdist, static client, and Vessel image | Selected foundation | Present Python, npm, OCI, and repository tooling can inspect these artifacts. |
| Automatic synthesis and Rebirth | Designed | Useful future law, but no end-to-end Forge or promotion controller exists. |

## Decision Outcome

A release candidate is eligible for review only when its source identity, version, dependency
declaration, generated client, notices, and checks agree. LychD calls this **source-bound
packaging**. The repository implements it for Python release-candidate archives and retains a
checked-in Vessel definition. Publication, synthesized extension bodies, and activation remain
separate work.

The [Ouroboros map](../sepulcher/extensions/weaver/ouroboros.md#from-a-useful-lesson-to-a-changed-body)
places this artifact boundary between candidate work and governed Evolution. Conversational or
A2A collaboration can change how work is requested while exact source identity, verification,
publication and activation keep the separate meanings defined here.

### Candidate identity and archive audit

`src/lychd/__about__.py` is Hatch's version source. Version preparation changes reviewed files;
it does not commit, tag, push, or publish. `pyproject.toml` separates installed CLI, application,
database, worker, and agent dependencies from documentation, test, lint, and typing groups.
`postgres-binary` is a local convenience extra, not a production dependency. `uv.lock` records a
resolved Python closure and hashes for frozen repository and image builds; a wheel carries
compatible constraints, neither that lock nor vendored dependencies.

The wheel contains `src/lychd`, including compiled Altar material under `src/lychd/public/`. The
sdist keeps the Containerfile, strict `.containerignore`, Python and frontend locks, frontend
source, scripts, source, tests, and legal files.
The auditor requires one wheel and one sdist for the declared version; checks MPL-2.0 metadata,
byte-identical notices, exact-source Altar payloads, required sdist members, any `v<version>`
release tag; and writes SHA-256 checksums.

Its isolated-install gate creates a fresh environment, resolves and installs the wheel and its
dependencies, checks consistency, invokes the CLI, imports the Litestar root, and exercises
internal Reactor and database help. That establishes sufficient metadata for that resolution, not
package-for-package equality with `uv.lock`.

### One body before any build

Before building a coupled body, a future Forge must bind Core and organ revisions, manifests,
locks, build tools, platform, base-image digests, and system packages. It resolves dependency and
platform conflicts away from the active runtime, then records every input, generated file, legal
obligation, and output digest. Separately compiled deployment intent remains bound through
[Containers](08-containers.md) and [Configuration](12-configuration.md). The whole body must pass
verification before promotion.

Pre-v1 in-process organs are coupled source, not an extension ABI. Compiled organs require an
explicit manifest, platform check, and activation path; arbitrary shared-object scanning is
forbidden. External-service Animators remain the independent compatibility boundary. This is
Designed: no Crypt scanner, signed synthesis manifest, or packaging-to-materialization coupling
exists.

### Vessel image and Rebirth boundary

The checked-in multi-stage `Containerfile` uses frozen, non-development, non-editable `uv` sync;
its `.containerignore` admits only declared build inputs from a checkout or source archive;
passes its built virtual environment to the runner; uses `psycopg` with Debian `libpq5` and rejects
`psycopg-binary`; carries project notices and a fail-closed installed-distribution inventory; and
defaults to an unprivileged user with non-writable `/app`.

Those are inspectable image laws, not a hardening or reproducibility certificate. Python and uv
base images plus Debian packages are not all content-pinned or snapshot-pinned; the candidate
workflow builds and retains no OCI image. LychD makes no byte-identical Vessel-image claim. A
future builder, including Nix, must emit equivalent or stronger source, dependency, platform,
legal, and digest receipts.

Candidate construction begins from a clean checkout whose `HEAD` is a full 40- or 64-character
lowercase Git object ID. Frontend verification leaves tracked contracts clean; the exact-source
Altar build may change only `src/lychd/public/`. The candidate target runs Python and frontend
gates, Altar and Hatch builds, archive audit, isolated install, and checksums. Its hosted workflow
has read-only repository permission, short-lived archives, and no publication authority.

A passing candidate is review evidence. Public promotion needs a separately authorized binding of
tag, source revision, archives, image, SBOM or equivalent inventory, and clean-host operation
receipts. [Evolution](18-evolution.md), [Privilege](10-privilege.md), and
[Human in the Loop](25-hitl.md) own migration, restart, and judgment.

### Trust profiles and delivery boundary

Security's profiles need their own dependency closure, entrypoint, policy, legal inventory, and
digest; a shared base layer does not merge authority. The Vessel has a checked-in definition but
no maintained published-image receipt. Tomb has no image, queue, executor, or `nono` integration.
Delegated execution retains typed containment-profile intent and a no-effect reference adapter, but
Coffin and Provider Gate policy remain Designed with no lower-trust image or effectful supervisor.
The [public release chain](../state-of-the-work.md#public-release-artifact-chain),
[Tomb](../state-of-the-work.md#tomb-untrusted-execution),
[delegated execution](../state-of-the-work.md#delegated-agent-execution), and
[Smith/Forge promotion](../state-of-the-work.md#smith-forge-promotion) own their actual state.

### Future forge-neutral source and release trust 

GitHub is the current public early-development surface for discovery, review, manually dispatched
candidate workflows, and published documentation. It is not a permanent constitutional
dependency: candidate identity is the full Git object ID, evidence is portable, and no GitHub
branch, pull request, Actions run, Pages deployment, organization role, or account is sufficient
release authority. Website and CDN projection remain separable from source custody.

[Radicle's Git replication protocol](https://radicle.dev/guides/protocol) is the first concrete
candidate for a future distributed source canon, not a current dependency or delivery claim. It
may provide replicated repository identity, namespaced signed references, and
[threshold canonical references](https://radicle.dev/2025/08/12/canonical-references); it does not
replace the website, discovery surfaces, package registries, builders, verification plans, or
artifact mirrors. Forgejo, GitHub, and later projections remain valid collaboration surfaces. Once
an explicit cutover selects another canon, however, they are downstream mirrors rebuilt from it:
there is no bidirectional “newest branch wins” merge and no second canonical `main`. Contributions
arriving through a mirror are proposals until admitted by the canonical-source policy.

#### Human seats and source selection

The proposed source policy uses an open, versioned roster of independently accountable human
maintainers. Membership grows through demonstrated stewardship of the shared Core, including
extension development, compatibility work, review, and constructive discussion of concerns with
the community. Employment, founding status, salary, and a fixed team size confer no seat.
Extension developers participate in the same admission path as Core contributors. Ongoing
discussion in the shared Discord helps surface concerns; decisions and supporting evidence must
return to durable repository records rather than remain chat-only authority.

Each governance epoch explicitly names eligible people, their credential scopes, and its source
selection threshold from documented compromise, unavailability, conflict, safety, and liveness
assumptions. The policy requires approval by multiple independently accountable people and must
tolerate its declared maintainer absences, including the founder, without a personal veto or
unilateral source-selection key. No initial roster size or numeric threshold is prescribed here.
Before cutover, current repository governance records human approval of the exact initial roster,
admission policy and threshold, together with their rehearsals; later membership and threshold changes require the
preceding epoch's authorization. A hiring change, extra contributor, or mathematical majority
never changes the policy implicitly.

A person receives one vote regardless of device count. Maintainers publish work under personal references
or branches and collectively nominate an exact Git object; they never share one private “main
key.” Signed namespaced references show that eligible protocol keys published that object, and a
canonical reference may be synthesized when the configured threshold agrees. A separately
verified epoch roster must bind each eligible key to one human seat. These facts do not by
themselves prove conscious human review, successful verification, release approval, or safe
activation.

#### Credential custody and roster recovery

Seat authority is independent from protocol and machinery. A Radicle identity or delegate set
cannot silently redefine LychD's release roster. Seed nodes, mirrors, bots, CI runners, and
deployment hosts are not human seats. Seed-only transport credentials remain separate from human
seat authority. A reviewed source protocol may intrinsically couple a maintainer's transport
identity to namespaced-reference signing, as Radicle does; that combined credential is limited to
source publication and receives no CI, promotion, deployment, migration, or lifecycle authority.
Those higher-trust domains use distinct individual credentials and never share a team key.
Promotion credentials should be more strongly protected than ordinary online collaboration keys
and are never installed in an untrusted builder. Rotation or revocation changes future eligibility
without rewriting historically valid evidence.

An ordinary roster transition requires the preceding epoch's threshold authorization. Any
exceptional recovery rule must itself be threshold-authorized and bound into that preceding epoch,
may only reconstruct the roster under its stated failure conditions, and cannot endorse a
candidate or authorize a live effect. Key loss or compromise without either freezes selection and
promotion rather than revealing a founder master key.

#### Portable verification

Verification travels as a versioned plan and receipts. That interface lets a local workstation,
isolated host or VM, GitHub or Forgejo runner, or future Radicle adapter execute the same plan.
Each receipt binds the exact source object, resolved inputs, plan and tool versions, platform and
containment context, command results, and output digests. Host-level Podman, systemd, migration,
and recovery claims still require [Testing's](04-testing.md) operator boundary: a green container
cannot attest its own host. A change to the candidate or a bound input invalidates affected
receipts and signatures. Deterministic failure cannot be outvoted.

#### Conditions for a canonical cutover

Radicle becomes eligible for canonical use only after all of these gates pass:

1. A reviewed public-history boundary contains only material intended for durable replication;
   peer-replicated Git objects must be treated as difficult or impossible to retract.
2. An explicitly accepted roster and threshold have independent human credential custody,
   documented admission, rotation and revocation, and rehearsed loss, compromise, founder-absence,
   tolerated-unavailability, no-quorum, stale-signature, and replay cases. Admission is open to
   demonstrated community maintainers and is independent of the paid team's headcount.
3. At least two independently administered availability domains seed or replicate the repository,
   maintainers retain recoverable copies, and loss plus mirror-rebuild drills pass. Storage,
   bandwidth, upgrade, and monitoring cost is measured on the intended operating hardware.
4. The exact-object verifier, portable attestation receipts, and signed promotion envelope exist
   independently of any forge or CI product.
5. Adoption review pins and tests the then-current protocol and implementation, including identity
   amendments, device and key recovery, canonical-reference quorum, partition and cross-version
   behavior, and the current
   [signed-reference security record](https://radicle.dev/2026/03/30/disclosure-of-vulnerability-in-signed-references).
6. [State of Work](../state-of-the-work.md#smith-forge-promotion) records the proven topology and
   recovery evidence before the canonical cutover.

Until those gates pass, GitHub remains the current collaboration route and Radicle may be used only
as an experimental replica. No distributed repository identity, canonical-reference verifier,
maintainer quorum roster, key-custody system, independent attestation plane, or Radicle node is delivered today.

## Consequences

!!! success "Positive"
    Archives retain reviewed source and legal material, generated frontend differences are bounded, and
    forge and builder choices stay replaceable because immutable objects and receipts—not vendor
    vocabulary—define success.

!!! failure "Negative"
    Candidate work repeats substantial Python and frontend checks; resolver installation and
    mutable operating-system inputs leave reproducibility gaps, while publication and activation
    await separately authorized promotion. Distributed custody later adds roster governance, key
    operations, independent replicas, monitoring, and recovery drills.

---
title: "18. Evolution"
plain_name: "Design rule 18: Updating the system"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/18-evolution/
guide: https://lychd.snayu.ai/docs/adr/18-evolution/
---

# 18. Evolution (Design rule 18: Updating the system)

## Plain-English summary (Snayu)

**What it is:** Defines how LychD adopts upstream updates while keeping local changes: the update is built, merged, migration-rehearsed and verified as an inactive candidate, then started as a new generation with a recorded recovery point.

**Why it matters:** Read this before working on upgrades, merging upstream changes or anything that alters the running system.

- Flow: update request, inactive candidate, verification, promotion request, then each owner applies its own effect.
- Conflicts, missing evidence or changed state block promotion; every live effect rechecks authority.
- Internal imports are not a stable API before v1, so private extensions must be tested with each candidate.

**Status:** Partial. Offline candidate comparison exists; update orchestration and promotion are designed only.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    Evolution governs adoption of upstream source while retaining deliberate local changes. An
    update can alter source, dependencies, configuration, schemas, artifacts and services together.
    Each affected owner needs compatibility evidence and a recovery plan before the changed body
    can be activated.

## Requirements

- Bind installed and upstream revisions, local delta, locks, configuration, extension set, schema
  head, and platform.
- Build, merge, migration rehearsal, and verification occur in an inactive candidate.
- Test the selected built-ins and private in-process extensions with the candidate Core; pre-v1
  internal imports are not a stable API.
- Keep source, package, database, runtime, and external recovery with their own owners.
- Changed state, conflict, missing evidence, and exhausted repair budgets block promotion; every live
  effect rechecks state and authority.
- Keep source selection, verification evidence, collective promotion authorization, and each
  target owner's live effect as distinct decisions even when the same humans participate.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| Upgrade the active environment in place | Rejected | Acquisition, resolution, migration, and activation share a running body without recovery proof. |
| Hot-replace modules inside the Vessel | Rejected | Old and new object graphs can coexist while only mediated effects can be unwound; process memory is not a recovery coordinate. |
| Never update | Rejected | An immutable artifact need not abandon reviewed security and compatibility work. |
| Inactive candidate with owned promotion | Selected design | Local work survives only when it still verifies; activation remains separately authorized. |

## Decision Outcome

This update law applies [SDLC](16-sdlc.md) and [Packaging](17-packaging.md) to a Core update.
[Illumination](../divination/transcendence/illumination.md#i-the-ouroboros) keeps the wider meaning
of Ouroboros; the [operating map](../sepulcher/extensions/weaver/ouroboros.md) connects that return
to SDLC, evaluation, training and separately owned activation. The update passage is:

`Update Request → Inactive Candidate → Verification → Promotion Request → owned effects`

Candidate verification is not activation. The repository audits source-bound wheel and sdist
candidates, renders an Alembic one-shot before Vessel start, and has a mediated Host Reactor for
typed Animator transitions. It does not acquire upstream, orchestrate updates, rebase local work,
repair compatibility, checkpoint or restore a whole body, promote a package, replace a body, or
restart through Ouroboros. The [public release chain](../state-of-the-work.md#public-release-artifact-chain),
[whole-body recovery](../state-of-the-work.md#whole-body-snapshot-restore), and
[Smith/Forge promotion](../state-of-the-work.md#smith-forge-promotion) remain Designed.

This law concerns LychD and coupled local extensions, not the release process of an external
service or peer. Built-ins and private in-process extensions that import internal modules are
structural dependants of the exact Core: imports, registration, configuration, and behavior may
break. The selected set must build and test with the candidate; no Smith repair guarantee exists.
[Extension law](05-extensions.md#7-extension-compatibility-tiers) owns the tiers. An
external-service Animator is decoupled only where its declared protocol and adapter remain
compatible.

### One lineage, many developer-owned projects

Evolution governs the next generation of one declared software lineage; it does not require every
developer-owned project to become part of Core. A separately named Extension Domain, Composition,
or external service may keep its own purpose, release cycle, and ownership while using LychD as its
upstream substrate. A private coupled extension or local Core delta remains part of the selected
body and must verify with that body's candidate; an independent boundary receives only the
compatibility its versioned public contract proves. [Extension law](05-extensions.md) owns those
forms and promises.

A derivative that selects its own canonical source policy, promotion authority, or incompatible
contracts becomes a separately governed lineage. It may continue to study or reconcile later LychD
changes, but the LychD source-selection and promotion rosters govern only the shared LychD Core,
not that derivative's source or activation. The derivative must own its exact upstream or base,
local delta, evidence, recovery, and maintenance; common ancestry grants neither automatic
compatibility nor an upstream repair obligation.

Returning work to the shared line is a separate decision from updating a local body. A developer
may propose a generally useful change through [SDLC](16-sdlc.md), source governance, and
[Packaging](17-packaging.md); once admitted into canonical upstream, each downstream body chooses
and verifies its adoption through its own Evolution. A foreign pattern instead enters through
[Assimilation](35-assimilation.md), which yields an attributable local candidate; activating that
candidate still passes through Evolution. Assimilation is therefore neither an upstream update nor
an automatic contribution channel.

### Reconcile concurrent contributors and recurring candidates

Concurrent contributors can work in separate candidate surfaces, each bound to its admitted
upstream/base and local input closure. Their integration creates an attributable successor
candidate that needs its own verification; individual branch receipts cannot establish the
combined object's compatibility. Changes to base, dependencies, configuration, schema, or selected
extensions invalidate affected evidence and authorization. A clean textual merge or automated
conflict repair still needs proof of semantic compatibility.

An idle-development coordinator may prepare candidates under SDLC admission but gains no
source-selection vote, promotion credential or activation authority. Current branch, review and
exact-object promotion procedure remains in
[CONTRIBUTING](https://github.com/hexanomicon/lychd/blob/main/CONTRIBUTING.md#branches-and-everyday-collaboration).
Future quorum and target-owned activation retain their separate eligibility and recovery gates.
Downstream adoption never silently overwrites operator changes or makes upstream maintainers
responsible for repairing a separately governed lineage.

### Synchronic Syncretizer 

!!! quote "Synchronic Syncretizer — continuity through synthesis"
    The Arbiter of Evolution asks what deserves to survive, what may end, and which differences
    can coexist or form a better successor. Continuity preserves attributable consequence and
    answerable obligations; it does not require every old implementation to remain executable.

**Synchronic Syncretizer** names the bounded judgment that decides adoption in Evolution. It
consumes verification receipts, [Drift's findings](34-evaluation.md) where available, required
owner verdicts, and retained history. Evaluation stays with its evaluator, and effects stay with
target owners. Changing selection criteria or an evaluator requires a separately reviewed
candidate; a candidate author cannot use that proposal to rewrite a failed comparison.

A comparison binds the installed and candidate closures, exact base and local delta, selected
extensions, predeclared acceptance and policy revisions, and the history selected for this
question. Its history manifest identifies predecessor decisions, obligations, failures and
unresolved effects, with selection reasons and omissions. It retains supporting evidence,
contradictions, dissent and uncertainty rather than compressing them into one quality score.

Each affected obligation receives an attributable disposition:

| Disposition | What must remain explicit |
| --- | --- |
| **Retain** | The behavior or boundary to preserve, its consumer and evidence against the exact candidate. |
| **Reconcile** | The incompatibility and proposed successor combining the chosen parts; that combined candidate needs its own verification. |
| **Replace** | What deliberately ends, why its retirement is justified, affected consumers and unresolved work, and their authorized transition or refusal. |
| **Reject** | Why the proposed change is refused and which evidence or changed condition could reopen it. |

Blocking a candidate does not make a known harmful baseline acceptable. Security revocation may
forbid an old executable closure while preserving its attributable history. Independent lineages,
policies, and capabilities may also coexist; synthesis cannot demand one universal agent,
paradigm, or canonical body for every participant.

Missing mandatory evidence, an unresolved required owner verdict or an unowned transition blocks an
eligible Promotion Request. Changed base, candidate, relevant environment, policy or evaluation
invalidates the affected comparison and requires a new attributable decision. Identical
redelivery must preserve the admitted comparison identity; a new semantic attempt cannot erase
the earlier failure. The result is a retained disposition and, only when eligible, an **inert
Promotion Request**. Source selection, collective promotion approval and each target owner's
fresh effect-time checks remain separate. A recorded judgment neither migrates nor activates.

### Retain an inactive local judgment

An isolated native candidate consumer may retain exact inactive bundle custody, an assigned
independent reviewer's assessment and a current-attributed hold/reject decision through the existing
Creation owner. Structural admission proves the retained canonical bytes only. A reviewer report
remains an attributed claim with explicit exposure, observations and limitations; self inspection,
mechanical comparison or a passing subset cannot become independent compatibility evidence.
Deferred constructor containment and missing mandatory receipts remain explicit hold reasons.
This passage launches no foreign runtime, creates no positive OwnerAdmission and authorizes no
promotion request, repository write or activation. Its separate blocking host authority boundary
is governed by [IAM](38-iam.md#closed-inactive-candidate-operation).

### Start the changed body as a new generation 

A promoted Core or coupled extension change activates as a new Vessel process generation.
Evolution never imports replacement modules into the live Vessel and never carries its
process-local object graph across that boundary. Listeners, caches, coroutines, dependency
handles, and other volatile objects belong to the old generation and die with it.

Before replacement, the old generation closes admission and drains, parks, or resolves owned
work under its domain contracts. The new generation rebuilds volatile state from the attested
manifest, validated configuration, and compatible Phylactery records. Unresolved work and emitted
external effects still follow [Graph](24-graph.md), [Workers](14-workers.md), and
[Reanimation](../sepulcher/phylactery/reanimation.md) law. Replacing the process cannot rewind them.

This boundary optimizes for coherent recovery, not uninterrupted availability. Death of a Vessel
running the same body is Reanimation. Deliberately starting a changed body is Evolution. In both
cases durable truth, rather than surviving process memory, is the continuity substrate.

### Record the recovery coordinate

The update record captures the exact installed artifact or image, source revision, dependency
locks, configuration identity, selected extension revisions, schema head, active topology,
requested upstream revision, and local delta. Before promotion, every affected owner supplies a
tested recovery coordinate or declares forward-only risk and obtains authority for it. A future
[whole-body checkpoint](07-snapshots.md) may bind them; VCS history plus a database backup is not
one atomic snapshot.

### Reconcile into a candidate

An inactive candidate starts from an immutable upstream commit and reapplies admitted local
changes with provenance. Jujutsu implementations record hexadecimal commit IDs for identity;
mutable change IDs and branch names are annotations only. The installed body need not contain a
source repository. Any conflict or changed base blocks promotion. Bounded repair produces a new
candidate and repeats invalidated checks and authorization. [Shadow](31-simulation.md) and
[Assimilation](35-assimilation.md) provide future branch and repair law, not a delivered rebase
service.

Its pinned dependencies and platform manifest require Core tests, typing, lint, build, archive
audit, and isolated install; each manifest-bound built-in or private extension; configuration and
registration; migration rehearsal from every declared source head; startup, readiness, and
affected behavior; and changed external protocol/adapter boundaries. “All active extensions” is
this manifest-bound set, not runtime discovery. A tested external protocol proves that contract
only; deterministic failure rejects the candidate regardless of review or repair proposals.

### Promote across the temporal boundary

Only an immutable, verified artifact with a request naming each live effect may promote. Under the
lifecycle boundary, owners revalidate revision, schema, configuration, and authorization; close
or drain admission; stage without changing the active body; migrate through the
[Phylactery](06-persistence.md); activate through an attested [Privilege](10-privilege.md)
boundary; verify schema, readiness, registration, and affected behavior; then reopen only after
success or proved recovery. A migration declares an expand/contract path, tested downgrade, or
forward-recovery plan compatible with activation and rollback. The Host Reactor can transition
typed Animators, not replace the Vessel or accept `INTENT_RESTART_VESSEL`.

Before any live effect, retention policy may discard or retain a failed candidate. Afterwards,
each owner invokes tested rollback, compensation, or forward recovery: a source selection cannot
undo a committed migration or external effect. Terminal evidence retains the request, candidate,
effects, checks, traces, recovery attempts, and observed final state. An indeterminate result is
contained for the operator; a revised attempt has a new identity and repeats relevant gates.

### Trust split

Humans and CI currently acquire, build, and review. The designed coordinator owns identity,
policy, evidence, promotion requests, and recovery orchestration. Untrusted build, test, and
repair commands belong in [Tomb](../state-of-the-work.md#tomb-untrusted-execution) only after that
plane exists, without signing keys, migration credentials, durable workflow ownership, or host
lifecycle authority.

### Future quorum roster and promotion envelope 

The proposed future **quorum roster** is a versioned roster of active human maintainers, open to
contributors who demonstrate care for the shared Core through extensions, implementation,
compatibility work, review, and sustained community discussion. It has no founding headcount or
reserved employment seats. A maintainer receives individually scoped credentials through an
explicit admission decision; Discord membership or message volume alone grants no key.
It is not a delivered LychD runtime object, remote identity service, or reason to share credentials.
A seat belongs to one accountable person, not to each of that person's devices; automation, seeds,
mirrors, runners, and agents receive no seat.

The roster's source-selection law and key separation live in
[Packaging](17-packaging.md#forge-neutral-source-trust). Evolution adds a separate promotion
decision. Each governance epoch explicitly fixes the promotion roster and threshold before use,
with no prescribed initial number; changing the paid team cannot change them. Its policy requires
independent approval from multiple people and tolerates its declared maintainer absences,
including the founder, without a personal veto or unilateral promotion credential. The same humans
and threshold may select the canonical source reference, but those
signatures are not interchangeable: selecting a Git object does not approve its artifacts,
evidence, recovery plan, or activation. Quorum removes the single-absent-founder bottleneck
without creating a shared key, founder veto, or unilateral recovery key.

#### The signed candidate and its effects

A future portable promotion envelope is the signed representation of Creation's Promotion
Request. It binds the governance epoch and replay boundary; exact source object and artifact
closure from [Packaging](17-packaging.md); versioned verification plan and receipt digests;
required Protected Region and owner verdicts; intended migrations, restarts, publications, and
other effects; and tested rollback, compensation, or forward-recovery coordinates. Each trustee
signs those exact bytes with a promotion credential distinct from source, CI-attestation, seed,
deployment, migration, and lifecycle credentials. CI and builders may produce evidence but never
hold quorum or effect authority.

The epoch's required signatures make an unchanged candidate eligible; they do not make a failing candidate true.
Missing mandatory evidence, deterministic failure, an adverse required verdict, stale state, or a
target owner's failed precondition blocks the Evolution regardless of votes. Every target owner
still authorizes and records its own live effect at the temporal boundary. Rewriting a Jujutsu
change, changing the Git object, artifacts, plan, or bound inputs invalidates affected evidence and
authorization.

#### Eligibility at the first effect

The envelope carries a unique promotion-attempt identity and monotonic sequence. Immediately
before the first live effect, the verifier rechecks the current epoch, every signer's eligibility,
quorum, replay and expiry state, withdrawal, and conflicts with another envelope for that attempt.
An unexecuted envelope from a replaced epoch or revoked seat loses eligibility unless the successor
epoch explicitly carries it forward; its signatures remain historical audit evidence.

Before the first effect, a trustee may withdraw and quorum is recomputed. A seat's conflicting signatures for
different candidate closures or effect sets under one attempt count toward neither once the
conflict is observed; pending eligibility is recomputed and the affected credentials enter
containment and governance review. The designed promotion coordinator and ledger atomically claim
the attempt and sequence before admitting the first effect, reject a stale or competing envelope,
and order later effect admission without taking any target owner's authority.

#### Recovery after an effect

Recovery, rollback, or compensation already bound into an active authorized attempt remains an
owner-executed recovery effect and cannot be delayed waiting for a new quorum vote. Withdrawal or an
epoch change after the first effect cannot erase the emitted effect, its audit record, or the bound
owner recovery authority. A conflict discovered only after that boundary cannot retroactively undo
the effect; it triggers credential containment and governance review, while every remaining
planned effect revalidates and may block. Deliberately selecting an older body as a later steady
state is a new governed Evolution, not a mutable-ref rewind.

#### Roster recovery and adoption

Key loss, compromise, or loss of quorum fails closed. Promotion-key rotation and roster membership
changes create a new governance epoch through the preceding epoch's threshold authorization. An
exceptional roster-recovery rule is valid only if that preceding epoch already authorized and
bound it; it is limited to reconstructing membership under declared failure conditions and cannot
approve a candidate or live effect. Revocation does not erase evidence that was valid in its
historical epoch. Founder absence, the epoch's declared tolerated unavailability, compromised-key
removal, total mirror loss, stale-envelope replay, conflicting signatures, and an unrecoverable
quorum must be rehearsed before this design can move from Designed to Delivered.

During early development, maintainers continue to collaborate through branches and reviews on
GitHub while exact-object checks and human approval remain procedural. The future protocol should
be implemented only after the forge-neutral gates in Packaging pass. Radicle can be added later
without changing candidate identity or Evolution semantics; adopting it early merely as an
experimental replica confers no canonical or promotion authority.

## Consequences

!!! success "Positive"
    Local change remains attributable, compatibility and recovery are candidate-bound, and failure
    can be contained before activation. The future threshold path permits maintainer continuity
    without making one forge, runner, shared key, or permanently present founder sovereign.

!!! failure "Negative"
    Rehearsal, coupled testing, and recovery checks add latency; schemas and external effects may
    demand forward recovery, and no autonomous update exists until all promotion boundaries exist.
    Governance epochs, separated credentials, portable receipts, and quorum-loss recovery add substantial
    operational and human ceremony before they can safely replace the early GitHub workflow.

---
title: "19. CLI"
plain_name: "Design rule 19: Command line"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/19-cli/
guide: https://lychd.snayu.ai/docs/adr/19-cli/
---

# 19. CLI (Design rule 19: Command line)

## Plain-English summary (Snayu)

**What it is:** Defines the Command Line (Pulse), the lychd command: a small, closed set of verbs (init, bind, start, stop, status, logs, access, del) that name operator intent and delegate to typed services.

**Why it matters:** Read this before adding or changing any CLI command or option.

- The root command list is closed; extensions cannot add top-level commands.
- Commands describe intent, not internals like systemd or Podman; --dry-run previews the same plan later executed.
- Help and host-only commands work without the web app, database or server running.

**Status:** Partial. Commands exist; full rootless deployment and container lifecycle remain unqualified.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    Pulse is LychD's one host-side operator language: inscription, binding, bounded lifecycle
    control, observation, work admission, and retirement. It is a small local adapter over owned
    services, neither a daemon nor a catalogue of framework organs. Help owns current spelling;
    source, focused tests, and [State](../state-of-the-work.md#core-cli-rites) own delivery.

## Requirements

- The root grammar is closed: internal frameworks and extensions add no public root command.
- Commands name operator intent rather than Litestar, systemd, Podman, database, queue, or worker
  topology. Click validates and renders; typed services retain authority.
- One source-owned target vocabulary supplies observation, with a safely actuable subset for
  lifecycle. A future extension-operation namespace must remain beneath a single host-owned verb.
- A mutating `--dry-run` previews the same typed plan or request later admitted for effect.
- Help and host-local rites do not need ASGI, Postgres, or a Vessel. Effects revalidate exact
  ownership while serialized, and only documented machine projections are stable.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| One command per organ | Rejected | It leaks topology, expands without bound, and fragments safety and output contracts. |
| Extension-owned Click callbacks | Rejected | It allows namespace collisions and unreviewed host execution without common admission. |
| Closed verbs with typed targets and operations | Selected | It preserves one public language, authority boundary, and safe extension contribution point. |

## Decision Outcome

The installed command is **`lychd`**. `PulseGroup` owns the closed grammar and the exact `st`
alias for `status`; `lychd --help` is its executable inventory. No `lych` alias is promised.
Generated services and development machinery have hidden entrypoints, but hidden registration is
not public compatibility. The managed image uses the fixed process entrypoint
defined by [Backend](11-backend.md#process-and-listener-boundary). There is no host Vessel `serve`
entrypoint. Database commands retain their
lazy framework delegation. The root verbs are `init`, `bind`, `start`, `stop`, `status`/`st`,
`logs`, `access`, and `del`; no run-operation, snapshot, restore, selector shorthand, recovery, promotion, or
consent spelling is reserved by the grammar.

### Inscribe, then bind

`lychd init` establishes the layout and creation evidence that later commands rely on. It
inspects the host, plans canonical XDG layout, and records lifecycle and root authority without
binding declarations or starting services. `--dry-run` renders the same plan without
LychD-managed mutation. Probes are bounded, but an inspected tool may write its own metadata, so
the preview makes no bit-for-bit host no-effect claim. Only unsafe or impossible inscription
blocks `init`; missing runtime capabilities remain for `bind`.

Effectful `init` rejects effective UID 0 before Settings, host inspection, locks or filesystem
effects. It then takes the lifecycle lock and requires the previewed plan to remain unchanged.
Execution creates only planned paths, journals confirmed progress, verifies convergence, and
records exact device, inode and mount authority for dedicated Codex, Crypt and Forge roots. It adopts an existing dedicated root only through that
verified receipt. Shared XDG parents, source checkouts, foreign mounts, and the mounted
Phylactery are never recursively adopted. Dry-run is available under effective root because it
does not grant LychD mutation authority.

`lychd bind` compiles one immutable snapshot of Settings, extensions, Runes, runtime declarations,
secrets, and host foundation into the exact Scribe-owned fileset. Its dry run validates and renders
without LychD-managed mutation. Effectful bind reacquires the lifecycle lock, repeats preflight,
and requires trusted executables, effective generator, sites, desired and observed files, Settings
generation, and secret generation to remain equal before commit. Missing or unsafe sites block;
bind does not create the sites that init owns.

Apply provisions only authorized absent core secrets, commits the exact fileset, and reloads the
user manager once. A late failure reports confirmed progress rather than claiming no effect;
cancellation survives cleanup classification. Planned binding truth belongs here; current host
inventory belongs to `status`.

Bind compiles the container Vessel only. The former `--native-only` and `--uncaged` options are
usage errors before host inspection or effects. A retained native Vessel source or owned runtime
identity blocks bind, including locked revalidation. Bind cannot silently replace, remove, adopt
or migrate it. There is no host-native test profile; tests use the OCI verification path under
[Containers](08-containers.md#core-deployment-and-verification).

### Start, stop, observe, and read

For `lychd start [TARGET]` and `lychd stop [TARGET]`, omission means the source-owned `system`
target. Direct control accepts only the help-advertised lifecycle subset and exact Scribe-owned
user units. Before an effect it holds the lifecycle lock and revalidates binding generation, unit
identity/state, and Vessel authority, refusing unknown, split, or ambiguous state.

Before direct `start system` submits the owned Vessel start, a separate bounded observation of
its exact opposite fixed Vessel name must prove it quiescent. The counterpart may be loaded or
manager-attested not-found, but must be inactive/dead with no main/control process or pending job.
A successful exact property reply is required; failed, unknown, malformed, nonzero or transitional
observations refuse. This check follows owned-generation/state revalidation under the lifecycle
lock. It grants no ownership or authority to stop, replace or disable the counterpart and does not
change storage-only control or stop admission. The observation is not an atomic reservation of
the user manager namespace: other manager clients can race after the final check. Retiring the native
profile does not remove the possibility of an existing legacy counterpart.

Active container-Vessel lifecycle completion remains unavailable until its own authenticated
admission and exact container/service settlement are implemented and qualified. Current active
operations refuse before effects; they do not fall back to direct stop, a retired native launcher,
or another transport. The removed native stop protocol cannot certify container cleanup.

A retired native Vessel identity blocks lifecycle mutation and retirement; read-only inventory
may still name it so the operator can reconcile the existing installation separately. Removing
support does not grant ownership, stop authority or migration authority. The opposite-Vessel
start observation above remains a bounded legacy-conflict guard.

Direct control handles only its safe inactive bootstrap subset. It does not run migrations,
evaluate application readiness or execute a general dependency graph. Graceful admission closure,
lease-aware draining and force semantics need their own delivered container lifecycle contract.

`lychd status [TARGET]` and exact `st` inspect bounded local evidence. The default is `system`,
and fixed choices are published by help. `--json` is the stable machine result; Rich is for humans.
It inventories local ownership, exact user-unit state, declarations, storage, configuration,
bindings, workers, and locally visible runs. It does not attest HTTP/database health, migration
currency, queue readiness, durable run health, model warmth, or extension status; silence is not
proof.

`lychd logs [TARGET]` maps a target to exact owned units and takes one bounded journald tail; Click
validates and help advertises the line bound. It has no follow mode or joined container, run-event,
or Oculus evidence view.

### Admit work without ceding the language

`lychd access` explicitly displays the local Altar address, fixed operator username, and dedicated
HTTP Basic password to the invoking host operator. It reads the configured runtime credential or
its exact Podman secret through the trusted host adapter; it neither starts the Vessel nor opens
a browser. Ordinary help, status, logs, startup, generated units, and URLs never contain that
password. Replace its external secret and restart the Vessel to rotate access. This is a local
operator credential, not Ward enrollment or a remote CLI admission interface.

A future host-owned run-operation verb may become the sole extension execution namespace.
Registration would contribute inert, typed identity, inputs, authority/scope, mutation and consent
characteristics, and progress/result shape; it must never grant an extension-owned Click callback
or arbitrary host execution. No run-operation catalogue, schema help, injected client seam, or
Ward-authenticated CLI admission route is delivered today.

### Delete only what the body can name

`lychd del` retires an installation through init's separately confirmed destructive counterpart.
It may remove only what receipts and live revalidation prove it owns; familiar paths, units,
object names, and mounts are insufficient. Planning is staged and fingerprinted. Dry-run reaches
the same authority and blocker decisions without deleting. For effect, the command requires
confirmation unless explicitly supplied, recomputes and revalidates under the lifecycle lock, and
passes the displayed fingerprint to execution. Any blocker suppresses every deletion effect.

The executor stops exact owned units, clears exact Scribe bindings, traverses receipted dedicated
roots without following symlinks or crossing mount authority, quarantines and re-attests names
before irreversible removal, and retains typed recovery evidence when restoration fails to
converge. It preserves unreceipted Podman objects, secrets, package installations, source
checkouts, and storage; it never calls `sudo`. Privileged Btrfs is a handoff: copyable arguments
appear only after the unprivileged plan is executable and mounted or receipt-backed unmounted
subvolume identity is attested, then execution waits for reconciliation. A blocked dry run or
incomplete effect exits 2.

### Shared target, recovery, and adapter laws

One fixed `OperatorTarget` enum/resolver supplies delivered targets. `status` and `logs` can
observe its whole set, while `start`/`stop` accept only its explicit lifecycle subset. Each target
resolves visible resources and exact ownership, never arbitrary units, containers, paths, or
tables. Adding a target therefore requires source, authority mapping, help, tests, and delivery
evidence. Observation grants no actuation. Dynamic targets and extension status remain Designed;
this source is not a runtime extension registry.

Whole-body capture and restoration remain Designed. A future inventory may project through status,
and mutation may use a typed operation or lifecycle target only after freeze, durability,
confirmation, and reconciliation law exists.

Importing or rendering the root does not construct Litestar, connect Postgres, start workers,
initialize models, or load the Altar. Host planning and observation call bounded services directly;
run help loads inert metadata lazily. ASGI, database, and Reactor consumers are hidden process
entrypoints. The hidden `reactor recover-soft ACTIVATION_ID` is a bounded host recovery operation:
it verifies the exact durable activation record, current declarations and owned topology, and cold
Vessel and target Animator before clearing the fence. It accepts no arbitrary path or unit and
never stops or starts a service. [Orchestrator (23)](23-orchestrator.md) owns that recovery law;
this spelling adds no public root verb or stable machine projection. A handler validates input, forms a typed request,
delegates, renders deterministic human or documented machine output, and translates typed refusal.
It does not reimplement lifecycle, authorization, persistence, deletion, or orchestration.

Read-only status and logs do not acquire lifecycle authority. Init, bind, direct control, and
deletion serialize under the lifecycle lock and revalidate the authority they consume. An active
Vessel is preferred authority; direct user-manager control serves only safe bootstrap or inactive
Vessel state, when no active or retired Vessel requires a separately admitted lifecycle operation.
Recovery does not authorize an emergency root or raw substrate argument.

Normal dispatch installs structured logging before execution; effectful root rejection in init
comes earlier. Results go stdout; logs and diagnostics stderr. `status --json` alone is a stable
machine projection. Status 0 means help, successful read/effect, or unblocked dry run; 1 means
ordinary refusal, unavailable run transport, effectful root init, or concise ritual failure; 2
means Click usage, blocked `del --dry-run`, or partial deletion. Confirmation abort and native
cancellation remain nonzero. Ritual-wrapped bootstrap failure emits one `cli_command_failed` event;
ordinary CLI errors do not disclose a traceback.

## Consequences

!!! success "Positive"
    Operators gain one small language bounded by ownership proof; extensions describe work without
    acquiring roots or host callbacks; host recovery probes survive application-stack failure.

!!! failure "Negative"
    New targets and operations need typed evidence; human output stays non-API, while several verbs
    deliberately expose refusal or a narrower surface until authenticated runtime ports arrive.

---
title: "20. Agents"
plain_name: "Design rule 20: Agents"
section: "Covenants"
status: "Available"
original: https://hexanomicon.dev/adr/20-agents/
guide: https://lychd.snayu.ai/docs/adr/20-agents/
---

# 20. Agents (Design rule 20: Agents)

## Plain-English summary (Snayu)

**What it is:** Defines an Agent as one typed thinking step with fixed instructions and output contract, while the model, settings, tools and permissions are attached fresh for each step. Built on Pydantic AI.

**Why it matters:** Read this before creating an agent, giving it tools, or changing how model calls are made.

- An Agent is not a model, workflow or persona; its recipe and output contract are separately inspectable.
- Tools and delegation never gain authority from prompt text or model output.
- The model and permissions are bound late, per step, through the Traffic Controller (Dispatcher).

**Status:** Available. The Pydantic AI adapter works; shared usage limits and binary media are not yet.

## Original text (Hexanomicon)

!!! abstract "Context"
    A model call is not an Agent. An Agent is one typed cognitive step whose instructions and
    result contract remain stable while the selected model, generation settings, tools, and
    authority arrive for the particular step. This permits the Vessel to change intelligence
    without relocating policy, identity, or durable execution into an adapter.

## Requirements

- An Agent must be distinct from a model, Graph, Pattern, Persona, Posture, and Lens.
- Its stable recipe, available capability, fresh dependencies, output contract, and result limits
  must be inspectable and separately owned.
- Tools and delegation must not acquire authority through prompt text, construction, or a model
  result; durable truth remains at domain, Graph, identity, consent, and persistence boundaries.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| Put model, credentials, tools, and workflow in one prompt-defined actor | Rejected | It erases capability admission, tool policy, durability, and attribution boundaries. |
| Make Pydantic AI the dispatcher and workflow ledger | Rejected | It owns the inner model/tool loop, not LychD's control plane. |
| Typed spec with late-bound capability | Selected | It keeps cognitive construction stable and binds per-step authority at the Dispatcher seam. |

## Decision

LychD uses in-process **Pydantic AI**, at lockfile-pinned `pydantic-ai-slim==2.55.0`. The
[State](../state-of-the-work.md#pydantic-ai-adapter) owns present cognitive adapter evidence;
[native Graph integration](../state-of-the-work.md#pydantic-ai-v2-migration) preserves LychD's
serial checkpoint and wait-owner contract.
The adapter sets `end_strategy="early"` explicitly: a valid final output does not execute sibling
function tools. The v2 SDK's `graceful` default would change this effect boundary. Any later
workflow that needs sibling completion must declare and verify that policy separately.

An Agent joins immutable `AgentSpec`, process-local `AgentForge`, a step-scoped model-shaped
`CapabilityGrant`, fresh `LychDDeps`, and a declared output union. This is the delivered model path;
ADR 22's general grant union does not turn every service into an Agent dependency. The boundaries
are deliberate:

| Concern | Owner |
| --- | --- |
| Instructions, output types, retry ceiling, optional declared toolsets | `AgentSpec` |
| Construction and process-local cache | `AgentForge` |
| Model, settings, runtime toolsets, capability lease | [Dispatcher](./22-dispatcher.md) and `CapabilityGrant` |
| Workflow order, persistence, suspension, recovery | [Graph](./24-graph.md) |
| Permission to act | [Security](./09-security.md), Sigil, grant, and tool handler |
| Durable identity and attribution | [Mirror](./32-identity.md) |
| Consequential human authority | [HitL](./25-hitl.md) |

Pydantic AI owns the inner loop, never a second dispatcher, identity system, ledger, or control
plane.

## The Agent specification

`AgentSpec` is frozen and hashable, with `name`, `instructions_key`, `instructions`,
`output_types`, optional `toolset_names`, `writes`, `retries`, and default `max_tokens`.
`AgentForge.agent_for(spec)` selects a registered builder and caches by the whole specification;
changing any field makes a distinct entry, while an unknown name or toolset fails construction.

`build_agent` binds no model. It can bind named construction-time toolsets, but omits a mutating
set when `writes` is false. Absence is the first gate; a present tool still checks live Sigil,
grant, input, and domain policy at the handler.

### The First One

The delivered Bridge Agent, `THE_FIRST_ONE_SPEC`, returns `BridgeReply | DeferredToolRequests`,
has no construction-time toolsets, and cannot request transition of the substrate leased to it.
Its stable instructions receive the Context Orchestrator's floor at run time. `BridgeReply` is text
plus `FragmentCall`s: each names a Vessel-owned registry entry and parameters, never markup, and
the registry validates it before projection. `Bottleneck` represents contradiction, missing input,
policy block, or unavailable dependency, but while Bridge can settle it as workflow state, it is
not in The First One's current output union.

## Late-bound capability

For each Bridge inference step, the current workflow asks the Dispatcher for a v1 `chat` grant
containing capability specification and state, step/run lease, resolved generation profile, a
required hydrated Pydantic AI model, and agent-loop toolsets only when the capability explicitly
declares `supports_tools = true`. The grant exposes neither its Animator nor Connector. Bridge
passes `grant.model` through a request-scoped [Context](./21-context.md#governors) capacity wrapper,
along with `grant.model_settings()` and `grant.toolsets`, to `agent.run_stream_events`.
Bridge owns the event stream's async scope so toolsets close on consumer failure before the
Dispatcher closes the model-provider scope and releases its lease.
Agent specifications therefore name neither endpoint nor credential;
the specification needs no separate model/tool-provider pair.

One spec can run with any admitted model meeting the adapter contract. A foreign framework is not
an in-process Agent by analogy: it remains a typed delegated runtime or Animator boundary until a
later amendment to the owning Covenant admits a versioned interface.

### Delegated runtimes and remote attempts

A **coding agent** is a delegated runtime when an external process owns an iterative planner/tool
loop and receives an exact repository or workspace projection under an `AgentJob` `read`,
`candidate`, or `verify` profile. One native Agent step using a remote model is instead a Portal-
backed Agent call; a sovereign node accepting a public task is A2A. These classifications follow
labor and authority, not the model brand. A coding agent may obtain cognition through a local
capability or its job-scoped Provider Gate, but every child remote payload remains a separate
Security-admitted Portal attempt. The outer job never conveys provider credentials, a general
network route, authoritative checkout, or promotion authority.

The accepted remote-attempt law also applies inside a native Agent loop: validation repair, tool-result follow-
up, changed history, or another model round creates another canonical payload and therefore another
Portal road decision/EgressDecision. One grant or first-round approval never authorizes the whole
loop's future payloads.

At that boundary the trusted Portal adapter or job-scoped Provider Gate freezes the canonical
child body and presents it to Spellweaver's road-decision service under the pinned parent placement
policy. It must obtain a fresh road decision, a consumer-specific Cut when transformation is
required, and the byte-time EgressDecision before sending. A native model loop or Coffin runtime
cannot mint, cache, widen, or reuse them; inability to obtain the full chain refuses that round.

### Provider compatibility under the pinned adapter

Provider Portals route their declared alias through the matching Pydantic AI provider or
model-profile resolver, including unsupported-setting filtering. OpenRouter, LiteLLM, and Ollama
use their provider resolvers; Google's OpenAI-shaped endpoint uses the Google model profile over
the OpenAI transport. Generic OpenAI-compatible endpoints and local runtimes instead select
LychD's conservative inline-schema, non-strict-tool profile. That local profile replaces resolved
provider defaults: a local alias such as `o3` does not inherit OpenAI reasoning policy or a
provider-derived context window. Selecting Responses does not also admit its optional
input-token-counting endpoint: the generic local profile disables that endpoint. Named provider
resolution remains on the provider's `model_profile(model_name)` contract, separate from v2's
resolved-profile transformation callback.
OpenRouter ids must retain their
`provider/model` namespace. Under the pinned adapter, Google, LiteLLM, and Ollama aliases are
Chat-only; Responses is admitted only for OpenAI, OpenRouter, or an explicitly compatible generic
endpoint. This does not claim a native Gemini transport or providers outside the registered
aliases.

An explicitly admitted `qwen3.8-non-thinking` generation policy reaches the call through the
immutable capability grant. The grant requires its hydrated Chat model and compiles only
`extra_body.chat_template_kwargs.enable_thinking = false`; Bridge uses the existing settings
handoff. It does not translate this dialect into generic SDK `thinking` or `reasoning_effort`,
mutate model defaults, expose arbitrary request-body fields or create another provider route.
The policy bounds a declared request mode, not separate hard reasoning/final token quotas, semantic
quality or an entire Agent loop's budget. Any applicable byte-time egress decision still covers
the final child payload.

## Run dependencies

Every step receives fresh, frozen `LychDDeps`:

| Field | Contract |
| --- | --- |
| `sigil` | Acting identity and scopes. |
| `grant` | Capability grant for this step. |
| `dispatcher` | Narrow grant-service port for tools. |
| `orchestrator` | Narrow lifecycle-transition port. |
| `context` | Context Orchestrator for the assembled floor. |
| `run_id`, `step_id` | Correlation identities. |
| `priority` | Admitted run priority. |

It carries no database session, raw settings, or secret. The control plane consumes credentials to
construct connectors; persistence and domain services remain narrow ports rather than cognitive
smuggling.

## Typed results and truth

Pydantic validation establishes a typed result's shape. Its prose can still be false, and its
type establishes neither an effect's validity, claim identity, nor permission to publish or
promote. Those proofs remain
with deterministic validators, domain handlers, Sigil, grant, receipts, evaluation, HitL, and the
Phylactery. `AgentSpec.retries` bounds validation repair; tool arguments may use Pydantic AI
retries. Policy refusal and missing premises settle explicitly instead of demanding success
without bound.

### Semantic answer completion

When the semantic source-answer casting generates an answer, it classifies the final SDK response
before ordinary answer settlement. A known normalized `length` finish is an `answer_output_limit` refusal, even when the
SDK returns a nonempty string and marks the received response `complete`. It must not assign that
partial result as the normal answer or new settled message history. Already-streamed text remains
provisional and may remain in Run evidence; refusal does not erase earlier observations.

This check follows the existing failure path after the admitted call, without SDK repair,
automatic retry, a larger generation budget, or another capability selection. Inspect the last
response's completion metadata; an earlier response's limit is not the final response's outcome.
Absent or other finish metadata retains current adapter compatibility and proves no natural stop.
A named qualification may require the stronger explicit `stop` criterion. RunDONE still records
successful Graph termination under its implemented checks, rather than factual truth, groundedness
or a universal output-completeness certificate. A successful current recall selecting no sources
may instead settle the deterministic, source-limited abstention owned by [ADR27](27-memory.md#native-semantic-source-answer-consumer).
That branch has no Chat response or SDK history suffix to classify; it cannot fabricate provider
completion, usage, dispatch or token events. Other castings keep their own result contracts.

### Mechanical cognitive postures

A **Posture** constrains an act through instructions, output schema, model settings, and tool
grant. A durable revisioned **Persona** names the actor and may wear different Postures. A
**Lens** supplies a Posture template to diversify [Simulation's](./31-simulation.md) isolated
Shadow branch. Expansion, review, repair, and red-team work belong in separate runs when a
proposal would otherwise grade itself. These distinctions are enforceable only where types,
grants, settings, and Graph placement preserve the claimed separation.

[Crucible](../sepulcher/extensions/weaver/crucible.md) uses explicitly biased Postures to pressure
one decision from several declared angles. Every advocate receives the same pinned evidence and
acceptance criteria, names its burden of proof and defeat condition, and runs separately from the
Lead that synthesizes its claims. The posture label is neither a Persona nor authority, and a
second-round rebuttal receives attributed opponent claims rather than hidden reasoning or an
unbounded sibling transcript.

A local Privacy Agent is a Posture at an explicit Spell placement. It receives bounded raw material
to produce a sanitized candidate and findings, but no Portal tool or declassification authority;
its confidence is not permission. Deterministic control comes first, policy can require an
independent verifier, and Security's trusted Portal Egress Gate makes the exact decision.

## Streaming, history, and limits

`pump_agent_events` streams one hop: text starts and deltas become raw Oculus token events, while
the final result supplies typed output and Pydantic AI history. The workflow serializes complete
history and the new suffix separately for settlement or suspension. Bridge reserves the grant's
output allowance and enforces the remainder as a per-request input-usage limit. Pre-request
counting requires a counting implementation. For the pinned OpenAI Responses counter, Bridge also
honors the resolved profile's endpoint support; method presence alone does not establish it.
Generic local Responses and current OpenAI Chat models therefore use reported response usage,
which cannot guarantee a preflight fence. Named Responses providers retain their own profile
policy, and other counting implementations retain their pre-request checks. ADR 21 owns the
separate character governor.

LychD does not yet share one `UsageLimits` object across a child-Agent tree. Future nested native
Agents need explicit budgets. Opaque delegates receive serialized limits through their own grant;
they inherit no `RunContext`, live toolsets, provider objects, or leases.

## Consent suspension

The delivered deferred substrate allows one model round to return exactly one approval request and
no external deferred calls. It serializes suffix and call identifiers—not a live
`DeferredToolRequests` object—plus the capability key, durable toolset id and type, tool name,
project-owned effect id and revision, and prepared-definition digest. Resume reacquires a fresh
grant and refuses execution if that binding changed before supplying `DeferredToolResults`;
approval-required tools without an effect id and revision in the current prepared model round
cannot park; an earlier round's binding supplies no authority. The tool owner must revise
the effect revision whenever executable semantics change without changing the prepared definition.
The parked binding is checked in the resumed round before dispatch. After that round, a completed
one-shot tool may leave the prepared catalogue; this must not turn its executed effect into a
reported refusal. Any subsequent approval captures its own current binding.
Multiple approvals and generic `CallDeferred` labor fail truthfully because the record cannot
represent them. A policy stop preserves completed tool results and closes only the known refused
deferred requests as denied before appending its reply; it cannot erase earlier effects or label
uncertain work as unexecuted. No tracked production toolset currently originates an approval request; the
executable path is exercised by test-injected toolsets only. Delegated labor is a separate Graph
node with its own job and trust boundary; ADR 25 owns durable consent ordering and recovery.

## Artifacts and multimodality

An Agent can return immutable `ArtifactRef` metadata, but metadata does not supply the payload.
LychD does not yet materialize authorized blobs as Pydantic AI binary content. Image, audio, and
other bytes need a Vessel-owned materializer that enforces authorization, media constraints,
and provenance.

## Correspondence

The Agent is where **the Call** becomes bounded labor and **the Blade** gives its answer form. A
model opens possibilities and a schema cuts a result; neither crowns itself true. [The Lich's First
Invocation](../sepulcher/lich/index.md#the-first-invocation) owns the mythic correspondence.

## Consequences

!!! success "Positive"
    Definitions survive model and hardware change; outputs, dependencies, retries, and tools stay
    inspectable; the same Agent can use a deterministic offline model.

!!! failure "Negative"
    Schemas and tools need deliberate maintenance, adapter compliance is required, and suspension,
    recursive budgets, artifacts, and foreign delegation need explicit LychD machinery.

## Verification

`tests/agents/test_factory.py`, `test_the_first_one.py`, `test_bridge_chat_graph.py`,
`test_consent_resume.py`, and `test_state_serializable.py` exercise construction, cache identity,
tool absence, typed output, grants, streaming, settlement, continuation, and the durable Graph
boundary. Dependency, message-schema, deferred-API, or stream changes require those tests and
State to move before this law claims new behavior.

---
title: "21. Context"
plain_name: "Design rule 21: Briefing pack assembly"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/21-context/
guide: https://lychd.snayu.ai/docs/adr/21-context/
---

# 21. Context (Design rule 21: Briefing pack assembly)

## Plain-English summary (Snayu)

**What it is:** Defines how the Briefing Pack (Context) given to a model is built: typed, ordered layers - stable rules, environment, history, continuation and the query - kept within the model's limits. If required material does not fit, the call fails rather than silently truncating.

**Why it matters:** Read this before changing prompts, history handling or what data is sent to a model.

- Context is typed, ordered and bounded, never a hidden mutable prompt string.
- Limits come from the actual model selected for the step, not a global guess.
- Before sending to a cloud model, a Privacy Filter (Privacy Cut) must rebuild the context without raw history.

**Status:** Partial. Layered assembly works; digests, privacy labels and some projections are designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    An Agent cannot receive all LychD knows. It receives a bounded, ordered field in which stable
    law, present environment, completed history, required continuation, and query survive changing
    model limits. If its non-negotiable material does not fit, assembly fails before inference; it
    never hides truncation in an attractive answer.

## Requirements

- Context is typed, ordered, bounded, and attributable rather than a hidden mutable prompt bag.
- Stable material has a reproducible digest, while history and query remain explicitly volatile.
- The Dispatcher-selected capability must rebind context before inference; a Privacy Cut must not
  reuse raw history, provider cache identity, or declassification authority.

## Considered Options

| Option | Decision | Why |
| --- | --- | --- |
| One mutable accumulated prompt | Rejected | It hides order, limits, lineage, and authority behind incidental text. |
| Static global context limit | Rejected | The executing grant, not a guess, determines the usable window. |
| Layered assembly with conservative governors | Selected | It makes floor, history, continuation, and query independently inspectable and bounded. |

## Decision

`ContextOrchestrator` owns the active field as typed, hashed `Block`s:

| Layer | Name | Current content |
| ---: | --- | --- |
| 1 | Identity | The First One's fixed instructions. |
| 2 | Codex | Reserved and empty. |
| 3 | Environment | Granted capability and observed warm Coven. |
| 4 | Karma | Session-keyed, reserved and empty. |
| 5 | State | Governed complete Pydantic AI message groups. |
| 6 | Query | Current request. |

Layers 1–4 make the **Stable Floor**. A designed `prefix_digest` witnesses ordered content known
to LychD; it neither proves provider KV-cache reuse nor attention or latency improvement.

## Blocks and assembly

A complete designed Block has layer, key, text, and SHA-256 content hash, and the orchestrator
derives `prefix_digest` from ordered stable blocks. The current `Block` carries layer, key, and text;
the current `AssembledContext` exposes those blocks, bounded settled history, an indivisible
continuation, query, and known active context window, but no content or prefix digest. The First One
binds layer 1 as static instructions and its dynamic hook renders non-empty layers 2–4. State
becomes model history and Query the user prompt, so the six-layer account does not duplicate them
as instructions.

Assembly detaches nested history and continuation values from their callers. Cache reads and
model-history projections also detach mutable messages, so downstream edits cannot change the
retained assembly or the input against which its budget was checked. Immutable Blocks may be shared.

Context preserves its declared semantic order. Exact append-only transcript groups may extend a
reusable prefix for a compatible connector while all earlier wire serialization remains
byte-identical; rewritten summaries and replacement
[Execution Projection](28-workflow.md#execution-projections-for-procedural-agent-placements)
values do not preserve that identity. Cache remains a connector/provider optimization, never a
Context source, authority, or receipt; Context does not reorder or pad admitted input merely to
obtain cache eligibility.

The run-id assembly cache lasts only for the process and releases after terminal Run settlement,
not when the session turn is written. Layer 3 snapshots are shared by exact environment key while
any referencing Run remains active; terminal settlement releases that Run's leases and evicts a
snapshot after its final reference. Durable conversation belongs to the session ledger and durable
suspension to [Graph](./24-graph.md).

## Grant-aware rebinding

Bridge assembles an initial field to enter the workflow, then reassembles inside `Converse`
once [Dispatcher](./22-dispatcher.md) has granted the actual capability. Consent continuation
also reassembles after acquiring its grant. This binds the field to the capability that will
execute it: the resolved generation profile's `max_context` takes precedence over the
specification's discovered maximum.

Environment records only granted capability key (or `none`) and sorted warm/active capability keys.
Its key is `(session, capability binding, grant epoch)`. Bridge uses the Dispatcher-issued grant id
as the epoch in both `Converse` and consent continuation, so every fresh grant observes a fresh
warm-Coven snapshot even when it selects the same capability binding. Reassembly within the same
grant remains byte-stable; exact same-key snapshots can be shared, one Run cannot evict another's
lease, and the final referencing terminal settlement releases the snapshot. VRAM, power,
connectivity, and Sigil scope are absent; the Sigil belongs in
[`LychDDeps`](./20-agents.md#run-dependencies), where tools can enforce it rather than prompt prose.

## Governors

The present governors are twenty complete message groups by default and a 96,000-character cap.
With a grant window, the effective cap is the smaller configured cap or three characters per model
token: deliberately conservative, not tokenizer accounting. Assembly reserves layers 1–4, query,
and complete continuation before history. If they overflow, `ContextBudgetExceededError` stops the
run. Continuation never splits; remaining space retains newest complete groups, up to the turn
window, never cutting a request from response to keep an older fragment. A nonpositive turn window
retains no settled history and leaves required continuation intact.

Bridge separately bounds each model request by the actual window remaining after output
reservation. Tool follow-ups and validation retries each receive that same capacity; accumulated
Run usage is accounting, not the context occupancy of the next request. A request-scoped model
wrapper checks provider-reported input usage before the response can advance the agent loop.
Pydantic AI pre-counts only for models implementing `count_tokens`, using the same per-request
bound. Current OpenAI-compatible models instead enforce provider-reported input usage after a
response. The character governor and usage limit are therefore independent bounds, not exact
cross-provider token equivalence or a universal pre-request fence. Pydantic AI's separate request
count ceiling remains in force.

### Explicit Archive projection

The opt-in `bridge_chat@3` public-note profile resolves an exact durable Archive recall receipt
into a transient, attributed data message. Recalled bytes never enter the Stable Floor's
instruction blocks, the caller's prompt, Graph checkpoints, or the SDK's retained source messages.
A request-scoped model adapter adds the projection only to outbound model input and resolves the
same receipt under current authority before each request, stream, and supported pre-count.
It must preserve the wrapped model's token-count limitations. Context reserves the complete
projection within its character bound; the provider request bound includes those same bytes.

This revision has no model tools, consent continuation, or settled-history replay. Its final
answer and normal turn messages remain retained and may quote or reflect sources; revoking a
source prevents future recall but cannot erase that prior influence. Missing, changed, archived,
superseded, or revoked receipt material refuses the casting rather than silently searching again.
An empty successful receipt remains a visible miss, distinct from service failure. Revisions 1, 2 and 4 do not receive this Archive
projection. This narrow local profile does not implement the
general Privacy Cut or remote disclosure admission below.

Archive's durable text-free receipt can explain a selection matching an exact admitted Run after
Context-cache release. This separate authorized metadata view does not reconstruct the Stable
Floor, total assembly budget, history, actual wire input or provider attention. A matching retained
request is not proof of workflow consumption or transmission; omitted capture stays unknown.
Current source eligibility is a separate check, not a revision of that historical selection.

The separately selected semantic source-answer casting follows the same outbound-only boundary,
with its own schema2 envelope. It preserves the generation/reference, threshold, result/character
bounds, coverage and omissions alongside exact attributed source revisions. Schema2 never appears
as a lexical receipt. Similarity locates potentially relevant context; it is neither answer support
nor confidence. Instructions require explicit uncertainty, unsupported questions and conflicting
claims, including when nonempty context does not answer the question. Partial coverage and budget
omissions must not be described as an exhaustive corpus search. Full escaped-envelope reservation,
current authorization on each outbound boundary, no tools, no settled-history replay, and final
settlement revalidation apply independently of retrieval type. State owns delivery acceptance.

## Stable history

Settled history is grouped by LychD `run_id`. For legacy messages, a user request starts a group
only when it has no tool-return or retry parts. A request with those continuations stays with its
exchange even if it also carries user-prompt content; trimming must never separate a tool return
from its call. At consent pause, the current logical-turn suffix is held apart from settled
history. Resume re-bounds the history under the new grant and supplies the required continuation
unchanged, leaving the old provider's live objects and assumptions behind. ADR 25 owns consent
record and verdict order; this Covenant owns the field's shape and budget after re-entry.

## Privatization and the Privacy Cut

Designed `PrivatizationLabel` and immutable source lineage attach to every Block. A label carries
class (`public`, `internal`, `private`, `restricted`), policy weight, categories, known subject or
namespace, material parents, and handling constraints; it does not substitute for factual trust,
instruction authority, Sigil scope, consent, or quarantine.

`AssembledContext` joins labels for exact blocks, history groups, continuation, query, tool
material, and artifact projections entering one model call. It preserves highest class and weight
plus the union of categories, subjects, and material parents. Copying, summary, aggregation,
embedding, captioning, transcription, and model transformation do not lower influence. A producer
may identify exact contributors to avoid unrelated overtaint; unknown lineage is `restricted` at
egress.

Source influence and disclosure risk are separate facts. Transformation never relabels ancestry as
public; a residual-disclosure assessment says only what one exact recipient may receive for one
purpose under one threat model. Pseudonymized material remains private while a reversal or likely
linkage path exists. A distinctive private repository, diagnostic, or relationship graph may be an
authorized sanitized disclosure without being anonymous.

A **Privacy Cut** forms a new recipient- and purpose-specific sanitized branch without mutating raw
material or reusing continuation, serialized history, tool bodies, attachment projections, or
provider prefix-cache identity. Its `DisclosurePlan@1` binds the consumer kind and identity, purpose,
minimal-projection manifest digest plus an opaque restricted local ref, semantic invariants,
threat-model and retention profiles, maximum transmission/disclosure uses, and proposed remote
target; it does not embed source bytes or identities in broadly retained evidence. Every
transforming stage emits immutable non-authorizing
`TransformationReceipt` evidence. When stages compose, receipts form an ordered digest-bound chain
whose terminal receipt binds the exact final candidate and all parent receipts. A semantic Privacy
Agent proposes findings and typed operations only; a deterministic applicator creates any changed
candidate and terminal receipt. An independent local verifier emits `CutVerification@1`; Context
seals a `PrivacyCut@1` only when source, final candidate, plan, complete receipt chain, verifier
verdict, policy, and expiry all match. Security alone admits the exact wire/export branch.

Designed receipts retain digests, revisions, typed operations and safe category summaries—not raw
spans, credentials, subject names, filenames, material-parent identities, or reversal data. A Cut
that destroys the identifiers, dependency relations, citations, or diagnostics needed for its
declared task refuses that road rather than call privacy alone a success.

An irreversible Cut has no reversal map and promises no rehydration. A reversible Cut stores the
map only through an encrypted local `PseudonymMapLease@1`: the map itself enters no prompt, log,
checkpoint, receipt, or remote request; a checkpoint may retain only an opaque lease reference.
Context owns the lease lifecycle and a narrow rehydration port; a deployment-local Privacy Vault
alone holds encrypted map bytes and their per-lease data-encryption keys. The lease binds Cut, Run,
attempt, target/purpose, an unpredictable keyed token namespace,
source/candidate digests, key epoch, authorized rehydration station, expiry, and cryptographic
erasure. If its durability cannot cover the remote deadline and return window, a Pattern that
requires rehydration remains local or refuses. A missing, expired, or unrecoverable lease never
licenses reconstruction from raw history or retransmission under a new namespace.

The non-bearer lease's success path is `ACTIVE -> CLAIMED -> CONSUMED`. Expiry or revocation can
terminate either nonterminal state as `EXPIRED` or `REVOKED`; every terminal enters key destruction.
Claim is an idempotent compare-and-set over authorized
Principal/Sigil, Run, attempt, station, and quarantined-return digest; callers never receive the
map. Rehydration recognizes only exact lease-issued tokens that appeared in the disclosed candidate
and only at output-schema paths explicitly marked for their category, cardinality, and purpose. It
rejects invented, altered, cross-namespace, cross-category, wrong-path, over-cardinality, or
replayed tokens and never scans arbitrary prose for placeholder-shaped strings.

The port returns a candidate plus `RehydrationReceipt@1` binding Cut/lease, quarantined-return and
final digests, typed substitution counts, verifier/policy revisions, and the restored influence-
label digest without raw values. The result regains its original label, remains local, is validated
again, and cannot flow directly into an executable field, effect, public delivery, or another
remote call. Its `purge_at` is no later than the earliest source expiry, Cut expiry, or Composition
retention maximum. Mapping ciphertext uses a per-lease data key excluded from backup; cleanup
destroys that key and proves restored backup material is undecryptable rather than claiming every
physical backup byte was erased. If no accepted Vault profile is available, every durable remote
wait uses an irreversible Cut.

The accepted Vault profile must also contain plaintext during transformation and rehydration:
mapping pages are locked against swap or host swap is disabled; core/crash dumps and debugger
attachment are disabled; bounded buffers are zeroized; and traces, allocator diagnostics, and
support bundles exclude the map. Acceptance tests exercise crash and memory-pressure paths. Failure
to prove this profile disables reversible Cuts rather than weakening the erasure claim.

The first bounded implementation profile is `closed-diagnostic@1`. It accepts a complete typed
projection of blocks, history, continuation, query, tools, and artifacts. Every character must
belong either to an explicitly sensitive span or to an independently checked item from a closed
public diagnostic vocabulary. The complete grammar fixes dependency, status, diagnostic and
citation positions; only the declared owner-value slot admits a sensitive span. Bounded metadata
joins refuse excess ancestry rather than dropping references. Uncovered text, unknown lineage,
prohibited categories, ambiguous spans, or lost utility refuse preparation. This profile cannot classify arbitrary prose or code;
adding a detector does not turn a missed identifier into evidence of safety.

Its deterministic Censor creates an irreversible candidate, and a separate verifier checks exact
reconstruction, utility, plan, and ordered receipts before an in-memory authority seals the Cut.
The seal is process-local preparation evidence, not a durable disclosure grant. Restart requires
new preparation. Source influence remains unchanged; broadly visible evidence contains only a
random event identifier. No source digest or candidate body is a public receipt.

Context Blocks default to unknown, restricted influence. Assembly joins block influence and treats
ungoverned query, history, continuation, and reserved transient material conservatively. A transient
character reservation carries unknown influence without retaining those bytes in the Context cache.
These labels do not qualify governed
SQL/tool/artifact source adapters or end-to-end derivation lineage. The semantic Privacy Agent,
pseudonym-map vault, provider-specific sanitized branch, and trusted Egress Gate remain
undelivered; [State of Work](../state-of-the-work.md#context-privatization-and-portal-egress) owns
the executable evidence boundary.

## Typed Codex material projections

Layer 2 will accept only explicit, attributed material references selected for one Run and Spell
placement. Each contribution binds an immutable artifact or contained workspace-relative source,
its content digest, normalized file kind/media type, classification and lineage, required/optional
status, byte/character budget, and an exact registered projection-profile revision. Typed local
configuration may select only already registered projection profiles, rules, and bounds. The
digest-bound material reference itself comes from the authorized Invocation or Scroll placement,
not global TOML; neither path carries source bytes or raw prompt text.

The first closed projection modes are `structure` and `verbatim`:

- `structure` is a deterministic parser-owned view, not an Agent summary. A Python profile may
  expose the module docstring, import facts, declared public symbols, class/function signatures,
  and stable source locations only when its exact profile says so. Parser and projection revisions
  participate in identity. Parse failure yields an explicit unavailable contribution or fails a
  required placement; it never falls back to full text.
- `verbatim` is an explicit request for exact decoded material under pinned encoding, newline, and
  line-provenance rules plus hard byte and character bounds. Truncation is declared by the profile
  and visible in the Block lineage, or the contribution refuses; it is never silently substituted
  for `structure`.

Rules are keyed by an admitted normalized file kind or media type, not by ambient package scans,
environment inference, arbitrary globs, Python import paths, or caller-supplied formatter code.
Content is read through the owning artifact/workspace boundary after digest and scope validation.
The resulting Blocks remain ordered, labelled, and attributable at the exact placement that asked
for them. A Reader projection grants no filesystem mutation; a Writer still needs a separate typed
tool/effect contract and Sigil authority.

Compression is also an explicit derived-material operation, never a hidden governor. A Compressor
cannot rewrite Identity, omit the non-negotiable Stable Floor, or turn missing fit into an
apparently complete answer. Its output is a new labelled Block and receipt linked to its sources,
profile, budget, retained invariants, and declared omissions; the uncompressed attributed material
remains owned by its source. If required material cannot fit without violating that contract,
assembly fails before inference.

Deterministic, non-model projection compaction may be part of an exact projection profile. Semantic
model compression is different: it is a separately resolved `AgentSpec`/Posture and Spell placement
with its own capability grant, typed result, budget, lineage, and explicit omissions. The
`ContextOrchestrator` never hides a recursive model call inside a formatter. A semantic summary
inherits its sources' privacy and instruction non-authority and cannot replace canonical source or
history truth.

An Agent may propose when and what to retain, compress, or omit in response to task progress as
well as budget pressure. These proposals remain subject to the derived-material and
[Execution Projection](28-workflow.md#execution-projections-for-procedural-agent-placements)
contracts; Context continues to enforce protected inputs, attribution, and assembly limits.
[Context Language Models](https://arxiv.org/html/2609.37725v1) reports benefits from model-directed
context editing in its tested settings. That evidence motivates adaptive proposals within these
boundaries; it establishes neither universal performance gains nor LychD delivery, and does not
require adopting the paper's separate approximate suffix-cache reuse mechanism.

## Execution Projection input

At one explicitly declared procedural Agent placement, a Composition-owned and Pattern-pinned
[Execution Projection](28-workflow.md#execution-projections-for-procedural-agent-placements)
may replace settled message history for that model call. Context receives the exact bounded,
attributed projection and fresh admitted observations from their owners, retaining lineage,
classification, revisions, declared omissions, and required/optional status. It orders and budgets
them beside the Stable Floor and exact Query. Context cannot infer a schema from Graph state,
decide domain truth, apply Agent operations, or silently summarize missing material. Required
state or observations that do not fit cause refusal before inference.

Exclusion from one model call never deletes or relabels canonical sources, conversation history,
events, receipts, artifacts, or audit evidence. The Stable Floor, exact Query, and any indivisible
provider/tool or consent continuation remain governed inputs; the state-centric mode cannot replace
them. The delivered Layer 5 still carries governed complete Pydantic AI message groups. Execution
Projection rendering, observation envelopes, and a history-free procedural Agent call remain
Designed rather than current source behavior.

## Designed extensions

Codex may hydrate the typed material projections above; Karma may admit governed Archive results;
exact tokenization may replace character estimation; measured policy may select corpus, retrieval,
or iterative aggregation; richer Environment may record admitted hardware; and typed bounded
formatters may gain explicit layer placement. No projection profile, automatic CAG/RAG threshold,
dataset ingestion, repository-path inference, quality-deviation injector, Compressor Agent, VRAM
estimator, or formatter extension surface currently exists.

## Correspondence

Context is the present surface of **the Spirit**: Identity, Codex, Environment, and Karma form the
floor; State carries movement; Query disturbs it. Selected memory is **Seed** and changing field
is **Flux**. The image explains shape; hashes, budgets, groups, and focused tests establish law.

## Consequences

!!! success "Positive"
    Stable material has one ordered receipt, history keeps whole logical groups, continuation stays
    intact, and capability can change the budget before inference.

!!! failure "Negative"
    Character estimates can underuse a window; snapshots vanish after their final active Run or a
    restart, process death loses the cache, and a stable prefix helps only when the provider actually
    supports it.

## Verification

`tests/unit/domain/cortex/test_context.py` covers newest complete groups, grant-bound environment
replacement, same-key sharing and release bounds, generation-window precedence, floor overflow,
and continuation. Bridge graph tests prove grant-id epoch binding and retain Context through graph
completion; worker tests prove release only after terminal Run settlement. Consent-resume tests cover
two-stage assembly and re-entry.
[State](../state-of-the-work.md) owns the public delivery boundary.

The full Privacy Cut profile additionally requires governed-source lineage; direct, quasi-, and
semantic identifier fixtures; isolation/linkage/inference and utility verdicts; transformer/
verifier disagreement; consumer and target substitution; secret-free receipt projection; fresh
namespace per new semantic attempt; bounded exact transport redelivery retaining the sealed
namespace while a fresh EgressDecision consumes its disclosure-use ceiling; and two-boot
`PseudonymMapLease@1` access, expiry, key rotation, loss, and verified purge without map material in
checkpoints, logs, backups, or remote payloads.

---
title: "22. Dispatcher"
plain_name: "Design rule 22: Model selection"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/22-dispatcher/
guide: https://lychd.snayu.ai/docs/adr/22-dispatcher/
---

# 22. Dispatcher (Design rule 22: Model selection)

## Plain-English summary (Snayu)

**What it is:** Defines the Traffic Controller (Dispatcher), which matches a request's needed capability to a ready model and issues a temporary Model Pass (grant). It never starts or stops model runtimes; that is the Stage Manager's job.

**Why it matters:** Read this before changing how a request gets routed to a local or cloud model.

- Only a model that is ready (WARM) can receive a pass; an unavailable exact choice is never silently substituted.
- Starting, stopping or loading models belongs to the Stage Manager (Orchestrator), not the dispatcher.
- Today a narrower v1 chat-model path is delivered; the general service model is designed.

**Status:** Partial. The v1 chat dispatch path works; general service capabilities are designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    A request says what faculty it needs; a model name does not say whether that faculty exists,
    accepts the necessary material, or is ready now. Local Soulstones and remote Portals change
    state independently of the request. LychD needs one admission office that can bind semantic
    demand to a live capability without acquiring the right to move the machine.

## Decision

**Dispatcher** selects a capability and admits a temporary grant. It never starts, stops, loads,
or evicts an Animator. [Orchestrator](23-orchestrator.md) owns those transitions; [Graph](24-graph.md)
owns whether a wait stays live or becomes durable.

The accepted general-service boundary is deliberately narrow:

```text
typed demand → interface/profile declaration → fresh state → exact WARM grant → registered lease
```

A capability-bearing Animator is the route; there is no semantic provider-pair abstraction.
Dispatcher emits its authoritative dispatch event only after lease admission. The delivered source
implements the narrower v1 chat-model and toolset compatibility path described below; the
general-service records and discriminated grant union remain Designed.

The live Animator is a capability/runtime handle, not a deployment document. It carries its exact
Rune identity, Connector, and typed runtime surfaces while
[Containers](08-containers.md), Bind, and Scribe retain physical compilation authority.

## Capability Binding Cartography

A capability binding lets the reader trace demand to use: what was requested, what was declared,
what was tested, what was observed, and what may be used now. Keeping these five questions
separate prevents a declaration or observation from standing in for a grant.

| Record | Office |
| --- | --- |
| `CapabilityDemand@1` | Exact interface, operation, typed material, feature facts, invocation mode, and policy constraints required now. |
| `CapabilitySpecV2` | Immutable declaration of Animator, interface, exact profile, operations, invocation mode, driver, and route shape. |
| `CapabilityEvidenceRef` | Reference to exact producer-attributed conformance evidence; neither admission nor current readiness by itself. |
| `CapabilityState` | Latest observation for that exact declared binding and, when required, operation. |
| discriminated capability grant | Temporary, WARM binding exposing only the callable surface for one admitted operation. |

Designed v2 keys are `{animator}:{interface_id}:{profile_ref}` where `profile_ref` includes a safe
stable id and exact immutable revision or content digest. They cross registry, Dispatcher,
Orchestrator, events, Workers, and Graph; after a pause a consumer re-fetches this canonical
identity, never a mutable handle. The operation remains explicit in demand and grant rather than
being hidden in profile identity.

Every component uses the closed slug grammar owned by [Capabilities](../sepulcher/animator/capabilities.md#stable-identity);
colons, paths, whitespace, controls, and floating revisions are forbidden.

### Delivered v1 compatibility projection

Current `CapabilitySpec` keys are `{animator}:{family}:{model_id}` and the single
`CapabilityGrant` class contains either an admitted Pydantic AI chat model with explicitly
declared agent-loop toolsets, or a non-empty `tool_execution` toolset surface. The closed families
are `chat`, `vision`, `embedding`, `stt`, `tts`, `tool_execution`, and `rerank`; `model_id` remains
required. Only `chat` and non-empty `tool_execution` can issue this v1 grant. The other family
labels remain routing metadata and fail closed at issue; they do not prove an executable STT/TTS
call, visual or embedding job, rerank call, Scout effect, host tool, or live session merely because
the vocabulary can name one.

Current `[[models]]` declarations may project into v2 only through an explicit compatibility map
from an exact family/model pair to an exact interface/profile. Persisted v1 keys are never silently
reinterpreted and an unknown family never becomes a generic service.

### Interfaces, profiles, and material

An interface defines the versioned semantic ABI, for example `model.chat@1`,
`echo.transcribe@1`, `prism.image@2`, or `prism.scanner@1`. Its implementing profile pins the exact
model, weights, graph, workflow, configuration, dependencies, licenses, formats, languages,
limits, and conformance evidence. Operations then name the admitted acts, such as `generate`,
`edit`, `transcribe`, `segment`, or `search`.

A demand matches only its exact interface and operation, typed I/O contract references, every
required material facet and feature fact, invocation mode, and eligible profile. Unknown support
never admits work. Image-capable chat remains chat; speech emitted by a chat model is not thereby
an eligible synthesizer; `tool` is never a universal effect interface.

### Declaration and observation

The v2 declaration holds animator/runtime/source kind, interface/profile, operations, typed I/O,
invocation mode, driver/dialect, feature facts, conformance evidence, resource envelope, dynamic
trait, and concurrency intent. The current v1 declaration retains family/model, input modalities,
tool support, generation, and context fields; connector-local model summaries select Chat or
Responses. The v1 dispatch demand cannot require streaming support or output modalities.
`is_dynamic` says a running local runtime may load a model; it is not readiness. The observed
phase is `COLD`, `ACTIVATABLE`, `WARMING`, `WARM`, `ERROR`, or `UNKNOWN`.

Soulstone declarations compile from Runes and selected adapters; probes update state and may fill
explicitly open runtime facts. An unknown local runtime stays passive unless an explicit adapter
and dialect profile give it semantics. "OpenAI-compatible" without a named, proved dialect gives
it none. Generic command planning synthesizes no Connector, model catalogue, or readiness.
The supported llama.cpp profile disables engine idle sleep: healthy fixed-runtime inventory can
survive sleep, and router `autoload=false` does not prevent a sleeping child from waking during
inference. Managed argument vectors begin with `--sleep-idle-seconds -1`; `extra_args` cannot
contain another sleep control. Passthrough vectors must begin with that exact pair, either at
the start for an image entrypoint or immediately after a non-option executable token. Later sleep
controls, underscore aliases, and equals spellings are refused. Admitted passthrough bytes remain
unchanged. Arbitrary wrappers that cannot honor this flag are outside this profile. This is command admission,
not attestation of a running engine, external mutation, or a shared endpoint's actual configuration.
Unregistered OpenAI-shaped aliases fail Soulstone capability-coverage validation before Bind or
registry publication. A Portal creates routes only for capabilities declared in its Rune; zero declarations
mean zero routes. Portal routes are non-dynamic and non-dedicated.
Their default `probe = false` makes no discovery egress, and a readiness probe never authorizes
private transmission. That unprobed route is projected as `UNKNOWN` and unverified, never fabricated
as `WARM`, so it cannot receive a grant.

OpenAI-shaped transport construction binds only the declared endpoint and API credential. It
does not retain ambient SDK organization, project, webhook, admin credential, or custom-header
configuration. Environment headers cannot override the declared credential or reach another endpoint.
Model, readiness, and local control-plane HTTP clients ignore ambient proxy configuration and do
not follow redirects. Model transport performs one physical transmission per invocation: implicit
SDK retries are disabled, including after a lost acknowledgement. Agent validation repair remains
an explicit model round under its existing budget; this transport rule authorizes neither another
provider nor blind replay of an ambiguous effect. Model-client close and re-entry retain the same
transport policy.

### Runtime hydration

Soulstone adapter ownership is the adapter's exact declared runtime key; registration cannot claim
another adapter's runtime. Registry hydration is staged and rejects a runtime unless it retains the
exact input Rune and its name equals the Rune name. Every synthesized specification must then
name that Animator, the Rune's canonical runtime, source kind and concurrency intent, and the canonical
`{animator}:{family}:{model_id}` key before any snapshot is published.
An adapter constructs its runtime catalogue once per hydration. Capability synthesis consumes
that runtime's captured model summaries and generation defaults instead of re-reading a preset or
independently rebuilding the connector's catalogue. Bind uses the same construction boundary to
check capability coverage without probing or activating the runtime.
A model-local request policy is validated against the resolved runtime, exact model and Chat
surface during synthesis, before a registry snapshot is published. Its generation value is frozen
into the specification and grant; issuance must not reopen the Rune or recover settings from model
names. The hydrated model must retain the admitted Chat transport before the policy can become
outbound settings. A v1 Run still pins its capability key, not a durable declaration-generation
fingerprint: this policy grants neither live reconfiguration nor policy continuity across arbitrary
operator changes. Construct and qualify an immutable assembly for fresh admissions.

Endpoint hydration preserves which fields the operator supplied: allocating a port must not turn
omitted managed-command defaults into declarations that conflict with an explicit `exec` command.

### Probe completeness and invalidation

A probe is a total observation of the exact requested capability-key and operation set. Duplicate, missing, or
foreign keys are contract failures; a successful result replaces that Animator's cached states as
one operation, while an exception, cancellation during the probe, or malformed result invalidates
the affected prior observations.
A failed full-registry refresh invalidates the full cached observation set rather than preserving
stale warmth. Initial
hydration probes the complete staged snapshot and publishes neither runtime nor state until every
result validates, so a failed first probe leaves the registry retryable. Portal egress probing is
selected only by the exact Portal definition's typed strategy.

## Resolution

### Candidate selection

Designed resolution receives `CapabilityDemand@1`, run and station-attempt identity, deadline, and
priority. It removes ineligible declarations and orders the rest deterministically under
an admitted selection policy. This is readiness matching, not a judgment of quality, price,
privacy, or correctness.

Current `lease_grant` retains its narrower family/model/modalities/tools
signature, an optional exact `capability_key` constraint, and deterministic
open/non-error/active/warm/name/key order. Cached observations rank eligible routes; they are not
permanent denial. The exact key intersects every other demand constraint; it cannot bypass readiness, drain
admission, or Portal quarantine. A model alias alone still denotes an eligible pool. An unknown,
incompatible, or unavailable exact key never substitutes another candidate.

### Bridge preference at admission

The bounded revision-2 [Bridge preference](12-configuration.md#current-selections) ranks only
the two configured literal registry keys before a fresh Run is admitted. Validate both complete
declarations before probing: each must have `SourceKind.SOULSTONE`, family `CHAT` and
`supports_tools = true`. Zero-weight routes are disabled, not exempt from declaration validation.

For positive-weight routes, perform one successful direct
`refresh_capability_states_for_animator` batch per distinct Animator and consume its returned
immutable states. A complete Animator batch may include a zero-weight capability sharing that
Animator; its phase/time are omitted from the retained decision and it remains ineligible. Never
substitute cached observations through a refresh-or-cached helper.
The complete probe batch has one fixed five-second **cooperative** timeout and no retry.
Timeout, cancellation, malformed observations or operational probe failure abort admission with
content-free public refusal codes; an earlier successful route is not selected after a later
probe fails. Existing adapters retain ownership of probe cancellation and cleanup. Five seconds
does not establish a hard process, network or cleanup containment limit.

After all probe awaits, recheck that the validated declarations are unchanged and read current
lease admission. A changed declaration aborts admission. Capture each Animator's admission
generation before its probe; a changed generation at the final check excludes its routes with
the safe `readiness_changed` code, even if admission has reopened. Only a positive-weight route
with a successfully observed `WARM` phase and currently `OPEN` admission is eligible. Other
successfully observed phases and closed admission are bounded exclusions. Select the greatest
weight among eligible routes, breaking a tie by ascending canonical key; an empty eligible set
refuses admission without activation, grant preparation or model entry.

Retain server-observed times and the bounded observations under Configuration's custody law.
The batch is not an atomic cross-Animator readiness snapshot or a reservation. It cannot promise
that the selected route will remain ready through persistence, queueing or execution. Existing
exact-key Dispatcher issue and generation checks still apply; execution may enter Stasis or
refuse, and never substitutes the other preference route. This policy changes neither grant,
provider-entry, cleanup nor Bridge call/tool/consent/token-budget semantics.

### Refresh the selected route

An invalidated or absent cached observation ranks as `UNKNOWN`, so the selected
declaration can be freshly observed on a later request. It never recovers cached warmth.
An eligible cached `ERROR` ranks behind other candidates with the same admission state and is
freshly observed when selected. Recovery therefore needs no unrelated transition or polling
service. A fresh `ERROR` still refuses the request without grant or hardware transition; v1 does
not retry another candidate after its chosen route fails.

The chosen record is refreshed immediately before issue.
Capability specifications, observations, generation profiles, and model summaries are frozen value
objects with immutable nested fields. Registry and adapter projections may share those values;
ordinary consumer mutation cannot rewrite the canonical declaration. Animator Runes freeze group
membership and both explicitly supplied and omitted environment/secret maps. Inventory collections
use immutable sequences. These in-process value contracts are not a sandbox for extension code.

| Observation | Result |
| --- | --- |
| `WARM`, admission open, executable v1 surface admitted | Issue and register a grant. |
| `WARM`, metadata-only or empty v1 surface | `CapabilityUnavailable`. |
| `COLD`/`ACTIVATABLE`/`WARMING`, dedicated | `HardwareTransitionRequired`. |
| Those phases, shared or non-managed | `CapabilityUnavailable`. |
| `ERROR` | Unavailable with observed reason. |
| `UNKNOWN` | Re-probe; unavailable if still unresolved. |
| Drain closes during issue | Transition required, and only this race is translated. |

### Refusal and transition signals

Known metadata-only v1 families are refused before readiness probing or a drain wait:
hardware convergence cannot create their missing executable surface. The final registry
issue probe can observe a different phase from Dispatcher's earlier probe; its typed
readiness failure returns that exact observation to the same phase decision table.
Hydration, policy, and malformed-probe failures remain ordinary failures and never become
hardware requests merely because issue failed.

The transition signal contains capability key, Animator name, and optional ready estimate—no
connector, model, lease, or service handle. Graph may release its edge, ask Orchestrator to
converge, and dispatch afresh. Dispatcher never calls `activate_capability` or `await_warm`.

### The Grant Lease Doctrine

Registry issue permits only a `WARM` record. The designed discriminated union exposes one of:

- `ModelGrant`: a Pydantic AI model and admitted agent-loop toolsets;
- `CallGrant`: one typed bounded call driver;
- `JobGrant`: typed submit, status, cancellation, result, and reconciliation surfaces; or
- `SessionGrant`: one typed, bounded, epoch-fenced live-session driver.

Every variant contains the exact specification, operation, warm observation, lease identity,
holder, issue time, scope, and only the live surface it admits.

Current source delivers one frozen
v1 compatibility grant: `chat` must hydrate its Pydantic AI model and receives agent-loop toolsets
only when `supports_tools = true`; `tool_execution` must hydrate at least one toolset and receives
no model. All other v1 families fail closed because no typed executable surface exists. The grant
does not expose its Animator or Connector. Specifications and observations share immutable nested
values; only explicitly admitted model or toolset handles remain live process objects.

The registry creates the identity; Dispatcher registers it in the process-local `LeaseLedger`.
Its context manager releases on ordinary exit, body failure, and observation failure. Duplicate
ids are defects. A closed drain gate or fresh dedicated `COLD`/`ACTIVATABLE`/`WARMING`
observation turns into Stasis; unknown, erroneous, shared, or non-readiness issue failures do not.
The same scope owns the model's provider context. It closes the provider before releasing the
lease, including caller cancellation and refusal during admission; provider-profile adapters
forward this lifecycle to their transport. A cached, model-free Agent owns no grant client.

Drain truth is absence of ledger leases on an Animator. Admission closes before drain waits, so
new work cannot enter an eviction set. A completed drain and reopen also invalidates grant
preparation that began before that drain. Dispatcher captures the Animator's process-local
admission generation before asynchronous grant issue or provider entry; the ledger checks that
generation and open admission together before registering the lease. A changed generation returns
the same handle-free hardware-wait signal after provider cleanup, without publishing a dispatch
event. Unrelated Animators retain their own admission generations.
A run waiting for its remedy owns no lease. `expires_at` is
recorded but unenforced: there is no renewal or distributed stale-grant fence. Grants contain
trusted live objects and may not enter Graph state, persistence, or delegated processes.

### From a grant to an enduring effect

An immediate bounded call owns its lease only for the call's duration. An asynchronous effect
needs durable execution ownership before its first local or remote submission, transferred to a
persisted `ServiceJobAttempt@1`. Managed resident or scarce local substrate also needs an exact
Orchestrator-visible reservation and fence. Live work instead uses its domain-owned bounded
session record; no common `SessionAttempt` is accepted yet. Process-local leasing cannot prevent
duplicate remote effects or fence local residency. [Workers (14)](14-workers.md#service-job-attempts)
owns this Designed handoff.

## Durable Content and ArtifactRef

The Designed content path requires Runs and checkpoints to name content with `ArtifactRef`, never
embedded bytes: identity, `sha256:` digest, media type, byte size, and
`public`/`internal`/`private`/`restricted` classification. Media-type projection to input modality
for matching remains Designed.

Current code defines this immutable metadata shape and carries references in delegated-job
requests and results. Ordinary `Intent` and Bridge admission remain text-only; they neither carry
artifact references through the Run ledger nor infer required modalities from media types.
Dispatcher filters explicitly supplied modality requirements. A separate, unregistered
[trusted-local custody adapter](06-persistence.md#reliquary-custody-designed) provides bounded
retention under an injected current authorizer. Bridge artifact admission, credential-backed
authority, and provider materialization remain separate work.

## Explicit local embedding compatibility profile

An exact configured `embedding` family/model pair may additionally declare an immutable
`model.embed@1` profile. This does not change `lease_grant`: unprofiled embedding labels and
embedding requests through the chat/tool grant path still refuse before readiness or host work.
The separate `lease_embedding` entry requires the canonical capability key, profile digest and
operation (`embed_document` or `embed_query`). It admits only local Soulstones, reuses fresh
issue-time readiness, drain generations and lease accounting, and exposes only a bounded driver.
Provider entry precedes lease registration; cleanup completes before release, including cancellation.
A driver cannot execute outside its entered lease or execute another operation than its grant.

The first explicitly selected profile is one fixed Qwen3-Embedding-0.6B Q8_0 artifact and llama.cpp
b9445 dialect, with last pooling, 1024 dimensions and L2 normalization. Its immutable manifest
binds model/image/build digests, exact query/document rendering, tokenizer options, conformance
receipt and input/output/deadline bounds. It accepts one input per call, at most 4096 rendered UTF-8
bytes and 511 runtime tokens. Oversize input refuses; truncation is forbidden. Runtime configuration
selects a managed single-model command with no passthrough, router, environment, model or profile
overrides. Configuration and a prior conformance receipt establish admission, not fresh attestation
of a mutable externally replaced process or artifact.

A source-bearing call requires a current-authority callback immediately before tokenization and
embedding transmission. Source eligibility and stale-completion fencing remain the caller's domain
obligations; no database lock spans runtime work. The local dialect accepts only a literal loopback
HTTP endpoint, disables ambient proxies and redirects, bounds raw response bytes before parsing,
and validates indexed output identity, count, dimension, finite numbers, nonzero norm and usage.
Returned execution values contain vectors and digests, not original text or raw provider responses.
Errors expose safe codes. No Portal, general SpecV2, detached job, semantic recall, ANN or training
operation is authorized by this compatibility profile.

The fixed profile requires an explicit port and literal-loopback `base_url` so it does not
inherit hostname resolution or generic endpoint allocation. For example, a local Soulstone
may select `embedding_profile = "qwen3-06b-q8-b9445@1"`, `port = 8080`,
`base_url = "http://127.0.0.1:8080/v1"`, `model_path = "/models/embedding.gguf"`, and
`quadlet.image = "ghcr.io/ggml-org/llama.cpp@sha256:39f4f2c5fd4537f85208f905e70269b5b691fbc6de00fd916c37a60a710b7d52"`.
The operator supplies the public artifact through the existing mount configuration. Model path,
image and profile are configured admission evidence: replacing a mounted file is not detected by
health/inventory probes. The retained public manual fixture in
[`tests/fixtures/embeddings/qwen3-06b-q8-b9445.json`](../../tests/fixtures/embeddings/qwen3-06b-q8-b9445.json)
is dialect qualification, not fresh runtime attestation or proof of Orchestrator activation.
Its laboratory RLIMIT and network isolation do not become general deployment resource guarantees.

The output scalar encoding is `float32-le`: provider numbers are explicitly projected to IEEE754
binary32, then checked for finite values, dimension 1024 and L2 norm within `1e-4`, without
renormalization. Vector digests hash the concatenated little-endian binary32 bytes. This same
canonicalizer is required at a durable pgvector handoff and after reload; JSON decimal formatting
is not the storage identity. Receipts bind vector digests and input/rendered digests without raw
source text or duplicate vector coordinates.

A driver closes admission and joins or cancels its outstanding requests before Dispatcher releases
the lease. Failing or cancelled driver entry owns its own partial cleanup; the fixed driver entry
has no suspension. Safe refusal codes replace provider bodies and transport exception causes.

## Policy boundary

Selection is mostly a future enforcement seam, not a complete policy engine. One coarse rule is
delivered now: every `SourceKind.PORTAL` candidate fails closed before grant, including direct-key
dispatch and direct registry issue, because no typed egress admission path exists. This quarantine
is not privacy-safe Portal operation. Sigil visibility, Portal secure mode, Toll arbitration, Censor/Privacy
Cut/`TransformationReceipt`/Egress Gate, unsupported-modality planning, A2A, and delegated-agent
choice are unwired. They must compose one typed, fail-closed path before grant; none may create an
alternate route around Dispatcher.

[Security](09-security.md#portal-privatization-and-egress) requires both admission before a Portal
grant and a decision over the exact canonical payload immediately before transmission. Dispatcher
will compose those decisions; it does not transform data or currently admit any Portal grant. A
future path must not allow retry, fallback, delegated child, or consent to reuse an obsolete verdict.

## Declaring and reading capabilities 

Use [Capabilities](../sepulcher/animator/capabilities.md) for declaration formats and the meaning
of observed readiness. The guide relates these records to the capability an operation actually
needs and distinguishes the current compatibility surface from the general-service design.

## Consequences

!!! success "Accepted"
    - Requirements, observed readiness, usable runtime handles, and drain accounting are separate.
    - A hardware wait is handle-free and cannot deadlock on its own lease.
    - Local and remote routes share typed grant law without sharing lifecycle authority.

!!! failure "Cost"
    - Registry and lease coordination are process-local.
    - Order ignores quality, price, privacy, and Sigil visibility; Portal sources are quarantined and incomplete probes can refuse a viable local route.
    - The matcher picks one candidate and does not score or explain alternatives.

## Verification

Current Dispatcher unit tests cover v1 matching, deterministic preference, generation settings,
and frozen compatibility grants. The current dispatch decision table covers every readiness row,
grant/drain race, event ordering, and release on failure; registry, Portal, adapter, and lease tests
cover v1 synthesis, fresh pre-issue probing, fail-closed family surfaces, opt-in probes, hydration,
and drain accounting. The fixed embedding profile additionally has configured registry/Dispatcher
HTTP integration tests for exact wire bytes, bounded responses, stale authority, cancellation and
float32 identity, plus a retained manual dialect fixture. General interface/profile catalogs, grant
variants, service attempts, and capability-set placement remain Designed. [State of
Work](../state-of-the-work.md#animator-dispatch-spine) owns delivery claims.

---
title: "23. Orchestrator"
plain_name: "Design rule 23: Model runtime management"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/23-orchestrator/
guide: https://lychd.snayu.ai/docs/adr/23-orchestrator/
---

# 23. Orchestrator (Design rule 23: Model runtime management)

## Plain-English summary (Snayu)

**What it is:** Defines the Stage Manager (Orchestrator), the single owner of starting and stopping local model runtimes. It plans swaps from fresh state and declared conflicts, drains active passes first, and performs host changes through systemd.

**Why it matters:** Read this before working on model loading, GPU conflicts or anything that starts or stops a model service.

- Only dedicated local models are managed; shared runtimes and cloud models are never started or stopped.
- New passes stop and existing ones drain before a swap; stale state declines before any effect.
- Host changes go through a frozen typed transition request, never a raw command or unit name.

**Status:** Partial. Conflict switching works; VRAM-aware scheduling, watchdog and leasing are designed.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    A selected local capability may be cold because its runtime conflicts with work already on the
    host. Stopping and starting it is a physical transaction with active leases, a possibly stale
    world, and an outcome that can remain unknown. LychD needs one serialized readiness owner.

## Requirements

- Orchestrator alone owns application-initiated readiness transitions; systemd remains the physical transaction engine.
- Fresh capability observations and the compiled conflict graph determine one plan.
- Dedicated local Soulstones alone are lifecycle-managed; shared runtimes and Portals may be warm routes but are not managed.
- Admission closes before complete affected-set lease drain; stale truth declines before effect.
- Host work crosses a frozen TransitionIntent, never a command, path, environment, unit, or generic payload.
- Reopen only after success, proved no effect, or exact restoration. Contain uncertainty.
- Priority orders waiters and may decline a hard swap; it never preempts a submitted transaction.

## Considered Options

| Option | Result |
| --- | --- |
| Dispatcher activates selected runtime | Rejected: matching would acquire mutation authority and race drain. |
| Domain policy scripts stop/start | Rejected: it duplicates the compiled systemd graph. |
| Proxy controls lifecycle | Rejected: it cannot attest local ownership or settled units. |
| Serialized planner plus structured actuator | Selected: policy admits; trusted host validation performs one bounded transaction. |

## Decision Outcome

| Office | May do | Must not do |
| --- | --- | --- |
| [Dispatcher](22-dispatcher.md) | Match and issue warm grants; register leases | Activate or mutate lifecycle |
| Orchestrator | Plan, prioritize, close/drain, converge, compensate, contain | Choose semantic provider or Graph meaning |
| Adapter | Probe and supported runtime-native activation | Cross-Animator eviction |
| Actuator/systemd | Attest, transact target, classify settled world | Invent policy |
| [Graph](24-graph.md) | Stasis and retry after convergence | Mutate hardware |

A non-warm managed route arrives as handle-free HardwareTransitionRequired; canonical registry
truth is fetched again.

### Current conflict policy

After refreshing every managed Animator, the current policy gives NO_OP to a warm/open target,
SOFT_SWAP to a started but non-warm dedicated runtime, HARD_SWAP to a down dedicated runtime, and
refuses every non-warm shared/non-managed runtime. A hard plan selects active exact neighbours of the undirected
conflict_domains graph. Omitted conflict on dedicated non-resident means conservative
default-exclusive; only explicit [] claims coexistence. Coven membership aggregates metadata: it
never creates or relaxes conflicts. Bind rejects unadvertised Soulstones, conflicting Covens, and
non-dedicated or persistent-resident Animators with non-empty conflicts.

Leased neighbours remain evictees: a lease forces drain; it does not make incompatible work
immortal. Affected set means evictees plus launch targets.

### Arbitration and planning budget

TransitionArbiter has one owner. It orders contenders by descending priority, then FIFO.
Requests for the same capability at the same priority join one in-flight plan; requests at
different priorities remain separate. A hard swap below
min_priority_for_hard_swap declines before effect; NO_OP and SOFT_SWAP are never threshold gated.
A manual or internal transition request must carry canonical doctrine priority `0..100`; the
manager rejects an out-of-range value before it records a trace or enters the arbiter, and the HTTP
boundary rejects it during query validation.
A warm/open fast path can return early, but every other plan is recomputed inside the arbiter after
its predecessor settles. The arbiter reserves the exact capability/priority cohort before its
owner begins asynchronous registry preflight; followers join that result without probing, while a
warm/open result still bypasses the global physical-transition section. Previews bind nothing.

Each preflight and each post-arbitration replan has one `planning_timeout_s` observation budget
for the complete managed-Animator set, including waiting for the registry probe lock. It does not
reset for each peer, consume the later warm-up budget, or limit time queued for arbitration.
An expired planning budget cancels and settles the probe, invalidates interrupted observations,
and declines before effect. Cohort followers receive the same failure; a later request may retry
with fresh observations. No lease or claim gate closes until planning succeeds.

### Optional admission expiry

A direct `POST /orchestrator/activate` request may supply `admission_timeout_s`. It is a
finite, nonnegative duration, converted once at handler entry to an absolute cutoff in the owning
event loop's monotonic clock. The internal manager input is an optional finite
`admission_deadline` in that same clock. Neither queueing, replanning nor joining a cohort renews
it. Zero is a valid already-expired request. Invalid durations or a nonfinite computed cutoff
receive HTTP 400; an already-expired request declines before trace, cohort or probe mutation.
Omission creates no caller-owned admission cutoff.

Admission means this transition invokes its hard actuator or soft adapter activation, or confirms
honest readiness on an observation-only path. Both the warm/open fast path and the post-arbitration
NO_OP path require that confirmation. Static and already-WARMING waits remain subject to admission
expiry until readiness is confirmed. The final invocation check follows synchronous observer
publication, with no intervening callback or await before invocation. A refused soft invocation
does not acquire the uncertainty of an activation it never called.

A timely invocation or readiness confirmation retires admission expiry. Later observer delivery,
HTTP completion or physical settlement may cross the old cutoff without replacing the result.
Admission expiry promises neither a response by the cutoff nor physical host submission by that
time. After invocation, existing explicit cancellation, readiness, compensation and containment
law continues to govern the effect.

The capability/priority cohort retains one owner. A follower's earlier expiry ends only its own
wait; it cannot cancel the owner, inherit ownership or reopen gates. Owner expiry fixes the cohort
refusal, delivered after required cleanup and gate handling. An omitted-option caller, including
an internal caller, can join a timed owner and inherit that refusal. A timed follower can join an
untimed owner without tightening the owner's budgets. Cohorts are not partitioned by deadline.
A nonexpired follower joining already-admitted work joins its settlement. For a follower already
waiting before admission, compare its cutoff with the actual admission boundary; delayed timer
delivery does not admit a follower whose cutoff was reached first.

HTTP admission refusal carries `code` and readable `detail`, with HTTP 409. The code is
`transition_admission_expired` for owner or already-expired entry refusal, and
`transition_admission_wait_expired` when only a follower's wait expires. Successful TransitionPlan
responses and existing priority-threshold refusal responses retain their contracts. These codes
create no public request lookup or durable deadline identity.

### Local budgets and deadline precedence

Admission expiry neither replaces nor restarts a local safety budget. Preflight and replan each
retain their own complete-set planning budget. A drain wait retains the cutoff created by
LeaseLedger after queue claims have paused and an uncleared lease set requires waiting; an
already-clear set creates no drain timeout. Soft convergence starts its warm-up budget after
drain and the verifying publication. Hard readiness starts after actuator settlement and the
verifying publication. Each convergence budget retains one cutoff for its complete operation,
including the hard transition's evictee-cold observations. Queue waiting creates none of these
phase budgets.

The earliest applicable original cutoff wins. A local planning, drain or convergence budget wins
an exact tie with owner admission expiry. Expiry means `now >= cutoff`: timers wake the decision
machinery, while successful phase completion and admission check the clock before retiring their
cutoffs. Completed phases retire their budgets; cleanup cannot renew them. Strict enforcement
also applies when admission expiry is omitted. This preserves budget starts, durations and error
categories while closing delayed-callback races that could previously accept late success.

While admission remains pending, fix the winning deadline cause and its nominal cutoff before
cancellation begins required settlement. A winning local budget retains its existing failure
classification; an earlier owner
admission cutoff produces admission refusal. For an already-joined, unadmitted follower, an
earlier follower cutoff ends its own wait; an earlier or equal winning cohort cutoff delivers the
settled cohort failure. Once a deadline outcome is selected, callback ordering, cleanup duration,
later publication or subsequent cancellation cannot replace the cohort's recorded cause.
Repeated cancellation cannot interrupt required cleanup. Cancellation or disconnection of an
outer caller's await may prevent delivery to that caller without rewriting the cohort outcome.
An ordinary failure or explicit cancellation that initiated cleanup retains its existing
classification even if a cutoff passes during cleanup. Keep these decisions in control state,
not projection traces. This rule does not establish a general timestamp ordering among arbitrary
exceptions or change cancellation after timely admission.

### Drain, change, and observe

The actual rite is:

1. Refresh and compute target plus exact affected set.
2. Close affected lease admission, then the process claim gate.
3. Wait for no live LeaseLedger grant on any affected Animator.
4. Freeze a TransitionIntent with target, evict/launch sets, expected active pre-world, and capability/conflict digest.
5. Have the host boundary attest freshness, ownership, loaded topology, and pending systemd work.
6. Perform one hard target transaction or one permitted runtime-native soft activation.
7. Require target WARM, and after hard swap every evictee stopped.
8. Reopen only under the restoration law.

Pre-effect drain timeout/cancellation reopens gates. Operational failure or cancellation during the
direct systemd actuator's topology, pending-job, or pre-world observations is also verified no effect:
no runtime transaction has been submitted, so retain the cause and classification and reopen the gates.
Once submission begins, cancellation must settle and classify the transaction and, where needed,
restore the exact prior world before reopening. The waiting run has no lease. Hardware Stasis
is live; Graph and Snapshots own durable sleep. The process-local bounded TransitionJournal is for
Nexus/run-event projection, not a Host Reactor journal or complete history.
The journal and Run observers consume the same immutable transition observation. Callbacks never
receive the mutable control trace or physical plan. Traces retain only the action and cost summary,
not the plan's mutable eviction and launch sets. Projection failures do not direct or abort a
physical transition.

### Runtime-Started Convergence (`SOFT_SWAP` Plan Label)

A SOFT_SWAP plan begins with a started runtime, which may still need no model load at all. The
whole target Animator drains because loading dynamically can unload another leased model. For a
dynamic capability outside WARM and WARMING, the canonical adapter receives an activation request;
WARMING and static started routes simply await honest warmth. Router observations classify models
individually. Activation rechecks that inventory and cannot submit another load for a target
already loading or loaded. Inference disables router autoload so that lost warmth cannot trigger
a load or eviction outside this transition boundary.

Dispatcher never asks this of a shared non-warm route. Direct surfaces enforce the same ownership
boundary before considering runtime-started convergence, so an already-started shared dynamic
Animator cannot enter SOFT_SWAP.

llama.cpp router and ExLlamaV3/TabbyAPI prove the seam in repository tests, not live model/GPU
operation; State records their Operator-validation receipts.

One absolute warm-up deadline bounds
the complete target convergence operation: initial refresh, optional adapter activation, accepted-
activation refresh, and final WARM polling. That same deadline bounds post-stop cold observation of every evictee. A hung probe therefore enters
typed compensation or containment instead of holding closed admission and claim gates forever.
Cancellation or failure during adapter activation or its accepted-state refresh invokes bounded
adapter abandonment before the canonical error is propagated; repeated caller cancellation cannot
interrupt that cleanup.

Before this transition invokes adapter activation, convergence is observation only. Failure,
timeout, or cancellation of the initial refresh or a static/already-WARMING wait is a verified
no-effect decline: reopen the claim and admission gates and retain the original cause. Coalesced
requests receive the same no-effect classification. An externally started load does not make an
observation-only transition the owner of that effect; fresh readiness still governs later grants.

Invoking adapter activation crosses the uncertainty boundary before the call begins, including a
call that returns `accepted=false`: that boolean is not an authoritative no-effect receipt. Soft
activation has no sufficient prior model state for a trustworthy inverse, so failure after that
boundary leaves its claim and admission gates closed for operator recovery. Before invoking a soft
activation, the Vessel durably arms an owner-only record in the Crypt's `runtime-guard` directory.
Only observed target WARM permits clearing that exact record. An interrupted or uncertain attempt,
including an incomplete record write, fences a fresh Vessel before queues or services are published;
changing configuration or restarting the process cannot release it. Observation-only convergence
does not arm a record. Persistence failure prevents activation and fails closed.

The guard is mounted read-write into the managed Vessel, separately from the
Host Reactor's read-only journal. Recovery is an explicit host operation: with lifecycle and guard
exclusion held, attest the owned topology and prove the Vessel and the recorded Animator service
stopped before clearing the exact pending record. Unknown identity, changed topology, pending jobs,
or uncertain service state refuse recovery. No readiness probe alone releases containment.

### Host Mutation Port and Privilege Boundary

All domain host mutation passes through `RuntimeActuator.apply(TransitionIntent)`. The closed
intent contains logical Animator identities, never a shell or unit payload. Compensation refers
to one completed forward transition and must be its exact typed inverse.

Direct systemd remains an explicit host-adapter test mechanism, not a host-native Core profile: under the lifecycle lock it resolves registry identities,
attests the loaded Scribe-owned graph, requests one target transaction, awaits jobs, and classifies
service state. Caged Host Reactor atomically publishes owner-only JSON, revalidates after claim,
shares the lock, uses an attested absolute systemctl, and records the result; local-UID handoff is
not a signed remote protocol.

| Reactor result | Meaning |
| --- | --- |
| .completed | Exact requested world observed |
| .declined | Preconditions failed before effect |
| .restored | Exact prior world observed |
| .processing | Claimed work unresolved |
| .contained | Fresh outcome uncertain |
| .rejected | Invalid delivery, not physical success |

Unclaimed publication may be retracted after claim deadline. Claimed cancellation/timeout does not
prove systemd stopped; wait for terminal classification. Exact desired state wins even after a bad
client return. Cancellation retains a host-owned decline or exact-restoration receipt and may reopen
admission on that proof; completion alone does not prove restoration. For an ordinary failed
transaction, exact prior state is restored; otherwise one typed compensation must prove exact
restoration. Once compensation starts, repeated caller cancellation cannot abandon it; the inverse
finishes before cancellation is propagated and admission can reopen. Rejected/contained or
unresolved compensation fails closed. Direct containment latches
only process lifetime; Reactor .processing/.contained survive and fence startup/effects until
operator recovery. Inert private-systemd tests prove ordering, not Quadlet/Podman/GPU embodiment.

## Designed resource policy

### 1. The Tipping Point (Whim Algorithm)

**Whim is Designed.** The current `declared-conflicts` policy (and its compatibility alias
`evict-idle`) counts only selected evictees in `total_metabolic_cost`. It measures no VRAM, load time,
context rebuild, thermal state, topology, bandwidth, transition peak, or tier substitution.

### 2. Model Tiering and Reservation

Resource-aware scheduling is Designed. Preload and idle-eviction settings are not implemented;
explicit coexistence and persistent_resident are declarations, not capacity proof. Future measured
`ResourceEnvelopeRef`s record idle, active, and transition-peak GPU memory, host RAM, devices and
topology, disk, bandwidth, warm/unload time, concurrency, and measurement conditions.
`PlacementProfile`s relate exact immutable capability profiles and required headroom on one host or
Legion topology. A future `CapabilitySetRequest@1` asks for one desired set of exact bindings; it is
not a Coven, queue, or semantic selection request.

The planner may admit one serialized desired-world transaction only after fresh observation and
reservation. Physical effects are not atomic: partial change must follow the existing
drain/attest/actuate/converge sequence and exact compensation, restoration, or containment law.
Durable local service attempts additionally transfer their exact reservation/fence before a Run
parks. Current process-local leases cannot prove that handoff.

### 3. Delegated Provider Capacity

A future delegated-capacity policy acts after semantic selection. It may delay or decline work
for admitted physical or economic capacity, but may not rewrite the task, choose its provider,
alter Graph, or manufacture capacity. Conservative/balanced/maximize behavior in a future
`ProviderCapacityPolicy` must stay beneath the minimum authorized, provider, and configured
ceilings. Disablement or cooldown stops admission; unknown quota cannot create slots. No such
policy implementation, scheduler, observation, durable reservation/release, Provider Gate, or
spend ledger is wired.

### 4. Swarm Lease Management

Swarm leasing is Designed. Current leases are process-local; expires_at has no enforcement,
renewal, distributed fence, peer lease, preemption, handoff, or ghost sweep. Legion must reuse
this admission/drain law.

### 5. Watchdog and Recovery

No autonomous watchdog or general repair engine exists. Pre-effect/drain failure reopens; hard
failure seeks one exact inverse; post-submission cancellation waits for settlement/restoration;
soft failure after invoking activation contains; unknown worlds are operator-owned. Conflict topology is Available in focused
tests; transition protocol and Nexus tickets are Partial; Host Reactor protocol has inert
private-systemd evidence; real host/model runtimes need Operator validation; resource-aware Whim,
tiering, swarm preemption, watchdog, and repair are Designed.

## Consequences

!!! success "Accepted"
    - Selection, adapter activation, and physical execution have distinct owners.
    - Lease closure precedes drain; stale and unauthorized topology declines before effect.
    - Exact restoration, not optimistic retry, releases containment.

!!! failure "Cost"
    - No capacity solver verifies declared coexistence.
    - Broker gate and leases are process-local; soft activation lacks an inverse; direct containment dies on restart.
    - Live hosts still require named operator receipts.

---
title: "24. Graph"
plain_name: "Design rule 24: Step maps and pausing"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/24-graph/
guide: https://lychd.snayu.ai/docs/adr/24-graph/
---

# 24. Graph (Design rule 24: Step maps and pausing)

## Plain-English summary (Snayu)

**What it is:** Defines how a workflow runs as a Step Map (Graph) using Pydantic Graph: serial steps, checked against a pinned manifest, that can checkpoint, Pause (Stasis) for approvals or hardware, and resume without replaying from the start.

**Why it matters:** Read this before writing workflow steps or anything that must pause and resume safely.

- Steps run serially; parallel branches, joins and map steps are rejected for now.
- Only declared, JSON-serializable state survives a pause; live clients and sessions stay in dependencies.
- A step returning an undeclared next step is rejected before that step runs.

**Status:** Partial. The serial engine works; pause and approval resume are partly proven.

## Original text (Hexanomicon)

!!! abstract "Context"
    An Invocation must survive deterministic work, capability waits, consent, and bounded foreign
    labor. That requires a recoverable control boundary, not a process image or a second authority
    ledger.

## Decision

LychD uses Pydantic Graph v2's native GraphBuilder with serial BaseNode stations. A Workflow binds typed Graph,
start-node type, admitted-Intent state factory, deterministic routing trigger, and immutable
PatternManifest. Each BaseNode receives mutable state and run-scoped dependencies and returns its
next node or End. Python return types declare intended transitions. LychD compares the native
builder routes to the pinned manifest and rejects an undeclared returned successor or End before
any successor executes. Typed shape and declared routing still cannot prove hidden premises or
the meaning of a mutation.

The delivered engine is serial. Broadcast, map/spread, joins, reducers, arbitrary function steps,
and parallel execution have no admitted checkpoint contract and are rejected by this adapter.

## State and dependencies

Resume retains only declared continuation data in a JSON-round-tripping Pydantic model. Live models,
grants, toolsets, sessions, connectors, and service handles remain in deps; any messages needed
after a park must first be serialized. Frames, token fragments, temporary objects, and
uncommitted work may be lost. This boundary preserves declared memory without claiming total recall.

## Pattern binding

PatternManifest is Spellweaver's renderer-neutral score: URL-safe key/revision, checkpoint-schema id,
unique stations, unique permitted edges, and deterministic digest. Every executable station maps
one-to-one to a Python node; mapped implementations equal the node set; delegated stations use
DelegatedAgentNode; edge endpoints are declared. The digest proves declared snapshot, not source
equivalence or every return path.

In the accepted workflow grammar, one station places a Spell contract. The current manifest has no
independent Spell identity or catalogue: its stations are legacy inline placements bound directly
to Python nodes. `PatternManifest` is therefore not the portable Scroll ABI.

Admission pins the full manifest. Before execute or resume, worker requires that snapshot to remain
valid and exactly equal the registered revision; a revision mismatch fails instead of silently changing score.
Fresh execution must begin at the builder's declared entry station; only a validated durable
cursor may enter at a later station. Fresh calls retain the caller's state and node objects while
checkpoint storage retains detached copies.
Both delivered Bridge revisions validate fresh and restored state against admitted Run identity,
session, prompt, priority, and capability binding before node execution.
Workflow.mermaid() is a projection.

### Boundary metadata

A future contribution declares execution plane, eligible local/Portal providers, local-only/egress
behavior, writes, delegation, quarantine, label propagation, and required declassification receipt,
Gate, or consent. station.kind remains mechanics, not a generic danger bit. Loom may badge that
declaration; occurrence evidence must name actual provider, decision, payload digest, receipt, and
result. Current manifests cannot prove it. Context owns labels; Security owns declassification.

## Execution and occurrence identity

perform_run is the single execution site: it rejects stale/duplicate delivery, claims exact
enqueue sequence, verifies pinned Pattern, builds run services, then invokes GraphRunner. Each node
attempt gets a process-local station-attempt correlation and an entered, settled, waiting
(hardware/consent/delegate), or failed event. Its delivered field remains the legacy
`occurrence_id`; canonical Spellweaver **Occurrence** instead names a schedule or external-trigger firing
before Invocation admission. Dispatch adds its grant event only after lease admission;
Orchestrator events retain the station-attempt correlation. Events observe; they neither recover
work nor establish a global order. Ordinary observer exceptions are logged and cannot replace
completion, the original execution failure, or a checkpointed wait. Cancellation still propagates.

## Capability handshake

Capability nodes ask [Dispatcher](22-dispatcher.md), never bind runtimes directly. On
HardwareTransitionRequired GraphRunner finds the signal even through a task group, snapshots state
only when the exception tree resolves unambiguously to that signal; mixed signal/failure groups fail
closed rather than swallowing a sibling. It snapshots state and current node, marks waiting, sets
AWAITING_HARDWARE, asks [Orchestrator](23-orchestrator.md) to
converge, returns RUNNING, resumes persistence, and dispatches again. Default limits are eight
hardware resumes per Run and three consecutive requests for one capability; exceeding either fails.
The counters live in checkpointed Run state, so a durable park or replacement `GraphRunner` cannot
reset the budget. A pre-budget legacy checkpoint decodes with zero counters because past attempts
cannot be reconstructed retroactively. The waiting run holds no lease and does not know whether
convergence was a load, systemd swap, or no effect.

## Live and Durable Stasis

Stasis has two lifetimes. Live Stasis keeps the loop resident; the current linear hardware
wait uses an in-memory LiveStasisPhylactery. Durable Stasis saves a mandatory checkpoint, exits
the worker, and re-enters through a new queue claim. Gate, DelegatedAgentNode, and PeerTaskNode
select the durable tier automatically.

| Park | Signal | Run status |
| --- | --- | --- |
| Human verdict | ConsentPending | AWAITING_CONSENT |
| Delegated job | DelegatedAgentPending | AWAITING_DELEGATE |
| Sovereign peer task | PeerTaskPending | AWAITING_PEER |
| Service job (Designed) | ServiceJobPending | AWAITING_SERVICE |

Long Sleep means a durable wait that outlives the worker. The
[native public peer station](26-a2a.md#native-public-peer-station) uses this same checkpoint and
owner-specific re-admission rule. Vessel lifecycle waits remain designs. `AWAITING_SERVICE` is accepted law
but has no source, persistence, or relay yet. Missing checkpoint fails as stasis lost; process death
in RUNNING or AWAITING_HARDWARE recovers only an exact Consent, delegated or peer pre-park boundary
bound by the first resumable checkpoint; otherwise startup contains correlated effects and records
failure. It never guesses a
replay. [Reanimation](../sepulcher/phylactery/reanimation.md#reanimation-a-new-vessel-judges-durable-truth)
keeps the state-by-state return conditions.

For a future service job, the owning station persists `ServiceJobAttempt@1` before first submit,
checkpoints the same owner, then parks. Re-entry reads terminal attempt truth and dispatches afresh;
it never resumes a Connector, grant, provider SDK object, or process handle. Unknown external
effect remains contained rather than being repeated. [Workers
(14)](14-workers.md#service-job-attempts) owns the common attempt and recovery mechanics;
the Composition/domain contract owns result meaning and acceptance.

## Checkpoint Ownership and Terminal Commit

DurableStasisPhylactery stores one Run-owned snapshot document. PostgreSQL replaces complete
validated snapshot history in one JSONB row with INSERT ON CONFLICT UPDATE; memory uses defensive
process-local copies. A snapshot contains typed state, next node, status, and completed/end
snapshots—not dependencies or event stream.

The native builder has no persistence API. LychD owns the snapshot codec and execution statuses;
GraphRunner invokes the public native iterator and task-request API to execute one station at a
time. It records running before the native node call, records success/error afterward, and retains
the next station or final result before reporting settlement. Re-entry injects the decoded node
at the native iterator's initial boundary before any station runs. Native task ids and fork stacks
remain local to that invocation.

The codec preserves the supported v1 wire envelope while validating state and output against the
pinned graph and resolving node ids only from its declared classes. Unknown nodes or node fields,
duplicate snapshot ids, and multiple created cursors fail explicitly. A pending snapshot remains
decodable but is not automatically replayed; neither running nor error status grants a new attempt.
The `node_id` field belongs to the checkpoint envelope; node constructors cannot declare it.
Constructor fields are checked before writing and after reading, so serialization cannot silently
replace a node value with envelope metadata or retain fields the decoder cannot restore.

GraphRunner can create/resume snapshots but cannot decide their deletion. Durable checkpoint
deletion requires committed DONE, FAILED, or CANCELLED Run truth. A worker that owns terminal
settlement releases run-scoped context and attempts checkpoint deletion before publishing its
terminal event and draining its Step evidence.

API cancellation follows [Workers](14-workers.md#cancel-and-contain): a worker observing
`CANCELLING` releases volatile execution resources for containment acknowledgement while retaining
its checkpoint. After `CANCELLED` commits, the engine handles terminal evidence and channel closure
before best-effort resource cleanup; failed evidence persistence does not prevent that cleanup.
For sovereign peers, required containment means durable local adoption closure and actual local
exchange retirement under Workers law. Retained remote uncertainty cannot resume the Graph and
is not erased with its checkpoint. This changes no local AgentJob/process containment obligation.

Cleanup is best-effort. Failed deletion retains checkpoint for reconciliation; committed terminal
truth remains authority. Repository evidence proves adapter and memory-profile recovery, not a real
PostgreSQL consent-plus-checkpoint restart, schema migration, transactional Step-event outbox, or distributed fence.

## Consent re-entry

A Gate stores serializable message suffix/call ids, snapshots itself, and parks. Worker commits the
consent relation and AWAITING_CONSENT; one guarded verdict edge admits QUEUED and the next worker
resumes the same Graph. Typed checkpoint shape alone does not authorize that re-entry: before
the first node executes, its Gate/delegated station kind and retained owner id must match the Run's
single current wait owner. [Workers (14)](14-workers.md#durable-consent-delegated-and-peer-waits) owns
replacement of that relation across chained or mixed waits; historical records remain evidence.
One approval call per model round, with bounded chained rounds, is current;
ADR 25 owns verdict order and recovery.

## Delegated Agent Macro-Nodes 

DelegatedAgentNode is one typed opaque station. Graph owns purpose and result routing, not the
foreign planner, subagents, tool loop, or events. DelegatedAgentRequest names request/run/step,
exact runtime adapter, read/candidate/verify containment, bounded prompt, and immutable input
ArtifactRefs.

AgentJob follows:

```text
QUEUED → ADMITTED → PREPARING → RUNNING → terminal
```

Terminals are SUCCEEDED, FAILED, CANCELLED, TIMED_OUT, LOST. Request id is idempotency key:
different reuse fails. For result adoption and ordinary polling, the first admitted terminal wins
and late results are inert. LOST records indeterminate external truth and never authorizes automatic
repetition. Explicit cancellation still contains the owning runtime and may record `LOST → CANCELLED`
only after containment returns, as required by [Workers](14-workers.md#delegated-agentjob-labor).

delegated_rite@1 proves no-effect reference submit, park, adoption, re-admission, and projection.
It performs no subprocess, provider, network, credential, or workspace effect. Runtime selection is
exact-name only, not Dispatcher grant or Orchestrator capacity; memory store is process-local.
Optional delegated_rite@2 retains the configured exact runtime/profile in admitted Run intent and
state. Its checkpoint must match that binding; current Settings cannot redirect resumed work.
It preserves the same no-replay and uncertain-outcome rules, with no automatic fallback.
The [artifact-reference receipt](../state-of-the-work.md#artifact-reference-contract) covers a
bounded PostgreSQL metadata round-trip through job creation and result adoption, using tables
created from schema metadata. It does not establish migration execution, process restart,
provider effects, Graph park/resume, or artifact-byte custody.

Coffin, Provider Gate, effectful adapters, cancellation, artifact custody, budgets, and
cross-process recovery retain their [State boundaries](../state-of-the-work.md#delegated-agent-execution). Provider
testimony is labelled, bounded evidence, never hidden reasoning.

## Runtime migration

The installed version is owned by [Agents](20-agents.md#decision) and the lockfile. The v2 migration
uses the public builder and BaseNode interoperability; it does not retain the removed v1 runner or
vendor upstream persistence. Official [builder documentation](https://pydantic.dev/docs/ai/graph/builder/)
and the [migration map](https://pydantic.dev/docs/ai/overview/migration/) explain that native graph
snapshotting is absent. The LychD serial adapter preserves the existing Run/Stasis boundary instead
of introducing an external durability engine or agent-Harness authority.

Captured Pydantic Graph 1.107.5 consent, delegated, and hardware-wait documents exercise the owned
decoder in `tests/integration/test_graph_checkpoint_codec.py`. The captured consent continuation
runs on the native builder with either verdict; pending remains nonreplayable. These receipts do
not establish process restart, database schema migration, or broker recovery. Parallelism and
external durability remain separate designs.

## Future parallel topology

Parallel execution needs an adapter that retains typed isolated branch state, fan-out
identity/parentage, declared join/reduction, bounded concurrency/capability admission, checkpoint
compatibility, and cancellation settlement for every branch. Its evidence must distinguish
topology from factual agreement. A reducer applies a predicate; consensus, first completion, or
a model judge cannot thereby establish truth.

## Runtime evidence

| Record | Answers |
| --- | --- |
| Pinned Pattern manifest | What passage was permitted? |
| Station-attempt events (legacy `occurrence_id`) | Which station attempts were observed? |
| Dispatch/transition events | Which grant and hardware change correlated? |
| Run ledger | What lifecycle truth settled? |
| Graph checkpoint | Where may execution lawfully resume? |

Event replay is process-local. A terminal manifest station is declarative: Pydantic Graph returns
End directly, so observers must not fabricate a terminal-node occurrence.

## Following a pause and return 

[Stasis and return](../sepulcher/extensions/weaver/stasis-and-return.md) follows a running or
parked workflow. [Reanimation](../sepulcher/phylactery/reanimation.md) explains how a new Vessel
judges the durable records after process loss.

## Consequences

!!! success "Accepted"
    - Serial typed execution has bounded hardware recovery, durable parks, pinned revisions, and terminal-before-cleanup law.
    - Later parallelism has a narrow compatibility seam.

!!! failure "Cost"
    - Checkpoint schemas require deliberate versioning; durable replacement rewrites whole history.
    - Live waits die with process; valid routing cannot prove factual correctness or effect meaning.

## Verification

State round-trip/tier-selection, GraphRunner, worker, consent, delegation, checkpoint, and event
tests cover the current path. [State of Work](../state-of-the-work.md) separates those memory-profile
facts from PostgreSQL and external-runtime receipts.

---
title: "25. HitL"
plain_name: "Design rule 25: Human approval"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/25-hitl/
guide: https://lychd.snayu.ai/docs/adr/25-hitl/
---

# 25. HitL (Design rule 25: Human approval)

## Plain-English summary (Snayu)

**What it is:** Defines the Approval Step (consent): an agent may propose an effect but never authorize it. The exact proposed call pauses for a human verdict or matches a pre-approved standing rule, then resumes through the same durable path.

**Why it matters:** Read this before adding any tool or action with real-world effects that might need human approval.

- Three outcomes: needs a live human verdict, pre-authorized by a config rule, or denied.
- No model or GPU pass is held while waiting; the job resumes once with the recorded verdict.
- Core changes, migrations, deletions, secret changes and host lifecycle always need live approval.

**Status:** Partial. Basic approval works; required review for native actions is designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    An Agent may propose an effect, never become its authority. A human decision or bounded standing
    policy may outlive the worker; it must retain the exact call, release scarce execution, and
    return through the same durable path without replaying a Pattern from origin.

In the Lich's tongue the Call can ask and the Blade can refuse. Here that is a durable, auditable
transition from one proposed effect to authority to attempt it—not proof, safety, or effect-time
authorization.

## Decision

The Magus Consent Protocol has three outcomes:

| Outcome | Meaning |
| --- | --- |
| Live verdict required | Exact call parks for authorized Magus approval or denial. |
| Codex preauthorized | Matching standing rule settles the same consent record. |
| Denied | Neither live verdict nor standing rule admits this effect class. |

Every effect declares eligible outcome. Confidence, repetition, previous approval, or broad tools
cannot change it. Core mutation, migration, destructive deletion, secret/authority change, and
host lifecycle remain live-only until narrower enforced law exists. Current ledger, bounded ZTE
Rune, Altar verdict, Graph park/resume, and guards do not prove a complete live-only taxonomy;
[State of Work](../state-of-the-work.md#graph-stasis-consent) owns the consent and stasis delivery boundary.

A candidate that touches a Spellweaver [Protected
Region](28-workflow.md#authorship-provenance-and-protected-regions) is always live-only. Its call
binds the exact base, candidate digest, affected region ids, old and replacement digests, an
authorized exact-diff artifact, and target-owner effect revision. Codex preauthorization, a
previous approval, or a broader repository grant cannot settle it. The verdict authorizes only
promotion of that candidate; it does not attest that a human authored the replacement.

## Consent invariants

### One verdict, one visible call

A consent record names one Run, tool, deferred tool-call id, censored arguments, verdict, deciding
principal, and preauthorization provenance. Its paired checkpoint additionally binds capability,
durable toolset id and concrete type, tool name, project-owned effect id and revision, and
prepared-definition digest. Resume compares that binding before approved dispatch; missing or
changed identity settles as a policy bottleneck without invoking a handler. Approval-required
tools without an effect identity cannot park, and tool owners must revise the effect revision when
executable semantics change without changing the prepared definition. Bridge accepts one approval
request per model round and rejects multiple or external deferred calls: Pydantic AI demands every
deferred result, so one card cannot counterfeit consent for hidden calls.

`pending`, `granted`, and `denied` describe judgment; `cancelled` is a terminal audit settlement
used when Run cancellation withdraws the pending call without manufacturing a human verdict.

Changed security-relevant argument, object, effect class, destination, amount, or authority creates
a new call. A safe projection can redact; executor remains bound to validated call. Consent may
authorize eligible disclosure but cannot declassify, repair missing lineage, approve different
provider/payload, override non-declassifiable categories, or replace Security's Privacy Cut and
EgressDecision.

### Verdict before effect

At Graph boundary:

```text
pending → Durable Stasis
granted → resume exact deferred call with approval
denied  → resume exact deferred call with refusal
```

Both decisions re-admit. AwaitConsent produces DeferredToolResults; denial never executes the
tool, carries no free-form critique, and does not promise a revised proposal. A verdict is not a
grant: before an approved effect, handler rechecks Principal, Sigil, object, effect, policy
generation, revocation, and IAM authority.

### No scarce lease across judgment

Judgment begins after the chat grant is released. AwaitConsent moves the Run to
AWAITING_CONSENT and lets its worker exit, leaving no model or VRAM lease. Checkpoint and
Run/Consent records hold this Durable Stasis; neither a sleeping coroutine nor an old event
channel owns the wait.

### Commit before projection

The permitted park order is:

1. validate one representable approval call;
2. persist censored consent row;
3. persist AwaitConsent checkpoint;
4. bind consent id to Run and commit AWAITING_CONSENT;
5. emit the Altar event.

A page snapshot can see the row sooner, so worker re-reads verdict after park; this and API use the
same atomic admission gate.

If the process dies between steps 3 and 4, startup accepts the park only when the first resumable
node snapshot names both this Run and the exact latest non-cancelled consent id. A verdict already
committed in that window is parked and then re-fired; an older approval round cannot lend its
checkpoint to a newer Consent row.

### One resume hop

First successful AWAITING_CONSENT → QUEUED compare-and-set for the exact current `consent_id`
receives a new monotonic enqueue_seq and creates one `PENDING` RunDelivery in the same transaction.
The gate re-reads that same-run Consent and requires a terminal verdict plus its decision principal
and timestamp. Newest-row ordering cannot substitute another Consent for the persisted owner.
Repeat clicks, historical cards, concurrent clients, post-park race closer, and startup
reconciliation lose that CAS. The external SAQ publication is not in that transaction: failure
leaves the admitted `QUEUED` hop and exact key for startup or the lifespan relay to publish. The
wait state is not recreated and a possibly existing broker key is never reused. Reconciliation
re-fires decided parked rows only for their current owner. Missing checkpoint fails as stasis lost,
never a restarted Pattern.

## Live judgment at the Altar

The route needs runs:approve, commits idempotent approve/deny before re-admission, and retains its
first result against contradictory clicks. Current card shows tool plus censored arguments. A mature
typed effect-owner projection may show Principal/Sigil; exact object/destination/amount/effect;
bound evidence; reversible and irreversible outcomes; policy provenance/expiry/history; and
approve/deny/revise/inspect alternatives. These are records, not model assurances; no workflow
produced diff, screenshot, test, or simulation artifact merely because a card exists.

Loopback bootstrap requires the [dedicated local credential](09-security.md) before assigning
the fixed `magus:*` Sigil. `runs:approve` is meaningful only at the documented same-host scope;
it does not establish remote identity or the [Ward](38-iam.md)'s effect-time authorization.

### Required review for native actions (Designed)

A native application may require review of an action it has already prepared. Its Consent retains
an immutable binding to the owning Composition, native action, exact preparation, review profile
and revision, producer and revision, admitted audience, and review content. Requiredness remains
explicit even when the binding cannot be decoded. Missing, unsupported, or changed binding refuses
judgment and issuance; it cannot turn the request into an ordinary consent. Existing consents
without this requirement retain their current behavior. Adding this contract does not migrate
parked work or establish compatibility between application revisions.

The Composition produces its typed review from the frozen command and trusted admission records.
The authenticated reviewer reaches the same owner projection through snapshots, event streams,
and direct verdict responses. Before a stream event invokes that projection, its Consent must belong
to the event's Run. A mismatch invokes no producer and discloses no review. The owner checks current
permission to disclose the complete review and, separately, to judge that action. `runs:approve`
alone does not supply either object authority.
If required facts cannot be disclosed, the review remains unavailable and no verdict is admitted.
Generic arguments remain censored; private checkpoints, arbitrary metadata, and model-written
explanations cannot replace the required facts. Shared event history retains the Consent reference,
without caching one reviewer's disclosure for another.

A native verdict carries the exact review-binding digest presented by the client. Before settling
either approval or denial, or re-admitting a retry, the server checks that binding and the reviewer's
current eligibility again. The conditional verdict update preserves the binding and the first
settled decision. A client that omits or changes the digest cannot settle this native request;
older clients remain compatible with ordinary consents. The digest identifies the review being
judged. It does not prove that a human read it or authorize the later effect.

This client compatibility does not admit mixed server versions. Before native actions are admitted,
[Evolution](18-evolution.md#promote-across-the-temporal-boundary) must stop and replace every Consent
writer that predates the binding; an older pending-only update cannot enforce it.

The native action owner compares the retained preparation and review binding again before issuance
and performs the current authority checks required above. [Blockworld's Sentinel](../compositions/blockworld/sentinel.md)
defines the placement review; [Continuity](../compositions/blockworld/continuity.md) owns its atomic
preparation and action recovery. [Persistence](06-persistence.md#native-consent-bindings-designed)
owns schema compatibility. These requirements remain **Designed**: storage and transport alone do
not supply the owned preparation transaction, current authorizer, or complete client review.
[State of Work](../state-of-the-work.md#graph-stasis-consent) owns the delivered boundary.

## Consent history and proposal branches

The consent history extends the existing Consent ledger with attributable, append-only records.
One **proposal** binds one immutable request to its effect owner, effect revision, exact call or
native preparation/review binding, initiating Principal, and originating Run and occurrence. Its
stable identity is distinct from the Consent that judges it and any attempt that executes it.
A history group collects related proposals for inspection; it grants no authority of its own.

An admitted revision names the proposal it revises. Several alternatives may revise the same
proposal, forming branches. The server validates immutable, acyclic revision links within the
authorized group; the client cannot infer ancestry from timestamps, similar text, filenames, or
screen position. Additional dependency and artifact references remain typed links rather than
invented parentage. A group may relate work from different Runs only through an explicit,
authorized association; it cannot transfer either Run's consent or continuation ownership.

Each proposal's record sequence distinguishes preparation, judgment, withdrawal or supersession,
and references to effect-owner attempts and receipts. Records carry stable identities, an
owner-assigned sequence, actor/source attribution and recorded time. Human decisions and standing
policy decisions remain distinguishable. Corrections and bounded explanations append with their
provenance; they never rewrite the first settled verdict. Explanation text is untrusted content,
not executable direction, permission, an automatic Context injection, or training admission.

### Branches never inherit consent

A revision is a new proposal with a new identity and its own Consent. Approval cannot pass from
a parent, sibling, group, previously approved version, or human-authorship attestation. After
denial, a separately admitted revision remains possible, but denial itself neither schedules that
work nor promises an Agent response. If a proposal is later withdrawn, its historical approval
remains visible.

Creating an alternative does not silently supersede its predecessor. Explicit supersession must
close the predecessor's remaining issuance eligibility through its effect owner before admitting
the replacement as its successor. A pending verdict/withdrawal race uses the existing guarded
decision path. For an already approved proposal, withdrawal preserves that verdict and fences
future issuance separately; it cannot retract an issued effect. If an attempt may have started,
the owner must reconcile or complete cancellation before a replacement effect can be admitted.
An uncertain outcome never authorizes a duplicate attempt on another branch.

The consent state and its judgment history commit atomically before re-admission or UI publication.
The existing Consent decision path remains the judgment authority. The effect owner retains
effect-time authorization, attempt identity, execution and recovery. Its durable receipt or
reconcilable publication supplies history references bound to proposal, Consent, attempt and
effect revision; idempotent adoption cannot create an effect or infer its outcome from approval.
Missing, delayed, failed and unknown execution remain distinct. A lost history delivery cannot
cause a second effect, and a history read cannot resume a Run.

### Typed review, shared history

The shared history envelope covers file changes, network acquisition, external disclosure,
spending, and deployment. Each effect owner still supplies the versioned review profile and
receipt semantics for its own act: file review links exact base, candidate, and diff; network
review binds destination and limits; other types expose the facts their law requires. An
unsupported profile must remain visibly unavailable for judgment. The envelope cannot register
or authorize a new effect class.

Bridge presents proposals as a tree with separate decision and execution details. Orb correlates
the same identities to retained Run evidence. Both consume authorized, bounded pages from the
same records; neither copies a separate verdict store or derives success from a tree badge.
Expansion and filtering preserve stable identities and disclose pagination or unavailable
history. A semantic list with keyboard-operated disclosure supports the same inspection without
requiring a graph canvas. Group selection provides no blanket approval.

Artifact revision history and [authorship/protected-region records](28-workflow.md#authorship-provenance-and-protected-regions)
remain with the artifact owner. Consent links their exact revisions rather than duplicating them;
approval does not attest authorship or prove that the bytes were applied. Each read rechecks
disclosure of records and referenced artifacts, including ancestry and counts. A visible proposal
does not make a private predecessor, explanation, diff or receipt public.
[Persistence](06-persistence.md#consent-history-custody) owns journal consistency and retention.
[State of Work](../state-of-the-work.md#graph-stasis-consent) distinguishes this history contract
from the current consent implementation.

## Codex preauthorization

A Rune under runes/codex/preauth matches Sigil/tool patterns, supported argument allowlists or
string prefixes, optional expiry, and optional max uses; unknown constraints fail closed. PostgreSQL
uses guarded UPDATE RETURNING for budget consumption and commits a consumed use with its consent
row in one transaction. ZTE requires non-empty constraints, expiry, and max_uses; standard may still
be broader.

An expiry names an absolute instant with an explicit timezone. Rune validation rejects timezone-free
datetimes before policy admission rather than interpreting them in the host's local timezone.

A named argument constraint requires that argument to be present. Absence never aliases an explicit
JSON `null`, even when `null` is itself an allowed value; otherwise an omitted authority-bearing
field could satisfy policy accidentally.

Preauthorization is Magus policy, never model confidence. Startup reconciles the complete Rune-owned
set in one transaction: same-slug rows retain usage and a manual disable, changed policy fields are
replaced, and absent Rune-owned rows are disabled. PostgreSQL startup fails closed when this sync
fails. An auto-granted Consent stores a digest of the policy that authorized it; before Graph accepts
that verdict, PostgreSQL rechecks the row is enabled, unexpired by database time, and digest-equal.
This is standing-policy revalidation, not the still-required generic effect-time IAM/object/authority
check after arbitrary intervening work.

## Failure and recovery

| Failure | Result |
| --- | --- |
| Worker/Vessel dies pending | Consent and checkpoint persist; lease does not. |
| Verdict before queue publication | Exact pending delivery survives; startup/relay publishes it. |
| Duplicate/contradictory verdict | First settled verdict is authoritative. |
| Multiple deferred calls | Policy bottleneck; no shared verdict. |
| Missing checkpoint | Honest stasis-lost failure. |
| Old hop races newer | Hop ownership/enqueue_seq bars old settlement. |
| Run cancelled while pending | Consent settles as `cancelled`; no later verdict can re-admit it. |
| Altar disconnects | Durable state remains; browser is not record. |

Memory-profile simulated restart proves this path; no maintained real PostgreSQL
Consent-plus-Checkpoint restart receipt exists.

## Rejected alternatives

### Hold the worker and model lease

It wastes scarce capacity and loses continuity.

### Poll a flag from the running Agent

It has neither an exact checkpoint nor single-owner re-admission.

### Treat review, simulation, and training as one pipeline

They remain distinct offices: consent does not promote Karma, assign credit, or train weights.

## Consequences

!!! success "Accepted"
    - Human latency occupies durable records, not model capacity.
    - One visible exact call gets an immutable attributable verdict; approval and refusal survive a declared boundary.
    - Missing state, duplicate decisions, and publication loss receive honest routes.

!!! failure "Cost"
    - Approval Patterns need serializable compatible checkpoints.
    - Consent, Run admission, and broker publication require reconciliation.
    - Redaction can limit review; live-only classification and effect-time reauthorization remain unsolved enforcement.

## Verification

Focused suites cover parks/resumes, chained single approvals, missing stasis, idempotency,
verdict-before-resume, delivery reconciliation, memory-backed preauthorization,
Sigil guards, terminal cleanup, PostgreSQL first-verdict concurrency, and preauthorization rollback.
Disposable PostgreSQL receipts cover use-and-consent atomicity, complete-set Rune sync, DB-time
expiry, policy-digest invalidation, and startup failure propagation. Generic effect-time
reauthorization and a full Consent-plus-Checkpoint process-restart receipt remain absent. State owns
graph-stasis and local-Sigil delivery claims.

---
title: "26. A2A"
plain_name: "Design rule 26: Agent-to-agent calls"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/26-a2a/
guide: https://lychd.snayu.ai/docs/adr/26-a2a/
---

# 26. A2A (Design rule 26: Agent-to-agent calls)

## Plain-English summary (Snayu)

**What it is:** Defines the Agent-to-Agent Line (Intercom): how one independent LychD install asks another for bounded work, sending requests and results, never weights, credentials or internal state. The receiver decides how to do the work.

**Why it matters:** Read this before building anything that talks to another LychD node or external agent over A2A.

- Exchange intents, not tensors: only bounded values or artifact references cross the wire.
- Delay makes it durable delegation with an inbox and outbox, never a remote function call.
- The first outbound profile is signed public text only over A2A JSON-RPC; peer trust is never self-enrolled.

**Status:** Partial. State of Work: a narrow outbound A2A profile works; the full Intercom described here is still Designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    A sovereign node can request bounded labor from another sovereign node. Their identity,
    memory, tools, hardware, and policy remain separate; delay makes the exchange durable
    delegation, never a remote function call.

## Status

**Intercom is Designed.** The transport-neutral envelope, verification, policy, replay, lifecycle,
terminal-adoption, and durable inbox/outbox contracts below are accepted law, not delivered source.
[State](../state-of-the-work.md#a2a-intercom) owns delivery. The common contract is transport-neutral;
the bounded outbound profile below selects and must test its own external revision.

## Decision

Intercom will carry versioned asynchronous labor inside Vessel using existing LychD identity,
persistence, Graph, dispatch, and workers. The exchange sends **intents, not tensors**: bounded
values or immutable ArtifactRefs go in; typed values, refs, or explicit non-completion come back.
The receiver decides whether and how to work on its own iron. No weights, KV cache, Python object,
provider client, live toolset, local Sigil, capability grant, Graph state, or infrastructure command
crosses the wire, and no additional control plane is introduced.

An ordinary peer request names an authorized public task schema. The receiver maps that task to its
own exact Scroll and local resolution; the sender neither selects nor learns that decomposition. A
portable Scroll or teaching bundle may cross only as a separately typed, inert artifact. It is not
the receiver's Graph and cannot force local admission, binding, acquisition, or execution.

A public task schema may carry ordered content-language preferences, original-language facts, and
a declared finish boundary such as still, motion, or packaged result. Canonical task, Spell,
Scroll, field, status, and artifact identities remain untranslated; peers may localize their own
labels without changing signed bytes. Unsupported language, translation policy, or finish depth is
an explicit incompatibility or refusal, never permission to substitute a language, engine, model,
or smaller result. Different typed values create another task or Invocation; a changed score
remains another Scroll revision.

Use Intercom when the receiver is a sovereign task owner, not as a decorative wrapper around a
model request. If the sender selects provider/model and needs one inference operation, the road is
a Portal. If an operator-controlled foreign runtime receives a bounded workspace and tool loop,
the road is a delegated `AgentJob`. A2A must not proxy a human subscription, provider credential,
local tool inventory, or hidden fallback chain. The sender binds an `A2ATarget` containing the
enrolled peer, task schema, adapter, and endpoint in a fresh exact egress decision; the receiver's
private model and decomposition remain its own affair.

## Peer identity

A peer is cryptographically verifiable network principal, neither Persona nor local Sigil, with
trust record, keys, and authorization. Public discovery is an untrusted advertisement of exact
protocol/profile versions, endpoints, authentication methods, public task schemas, public
Spell-contract references, content limits, and deliberately coarse price or availability. A claim
means only that the peer advertises it; it proves neither local binding, present availability,
authority, nor admission. An authenticated extended card or query may reveal peer-specific
contracts, ceilings, bounded availability, quote eligibility, or teaching policy.

Discovery never enumerates Personas, Sigils, grants, installed private Scrolls or learned Spells,
local implementation revisions, Graph state, tool/model inventory, backend topology, Tether
coordinates, live queues, artifact bearer URLs, invoices, or payment proofs. A public key repeated
inside an unauthenticated card cannot enroll its own trust.

The first interoperability candidate is the
[A2A 1.0 Agent Card](https://github.com/a2aproject/A2A/blob/main/docs/specification.md) at
`/.well-known/agent-card.json`, plus a versioned LychD extension for exact task and public
Spell-contract metadata. Intentionally public known Spells appear through the card's skill and
extension vocabulary; private catalogue truth does not. The adapter owns document version,
extension URI, authentication, canonicalization, and conformance fixtures; Core does not invent a
parallel `/.well-known/lychd-*` path. Until that adapter is selected and tested, this is protocol
design rather than a shipped discovery claim.

Tether and Veil are transport and ingress layers, not alternative trust models. A conservative
first route is Veil-compiled HTTP exposed only through Tether, then Ward authentication and policy,
then Intercom envelope verification and replay fencing. Public Veil exposure is a later profile.

The [Reach deployment profiles](../compositions/reach/deployments/index.md) are outbound A2A clients
by default. In home-only and edge/home, only the authoritative home egress service may call a peer;
the VPS edge cannot. In standalone VPS, its local authoritative egress service calls the peer.
Invoking one enrolled, authenticated, task-authorized peer requires a fresh exact egress decision,
but no published Agent Card, callback, Tether, or public Veil. The first receipt pins polling and
disables streaming and push. A later callback-only route may update only an existing outbound task;
accepting new foreign work is a separate A2A server profile with Ward, durable Intercom inbox/outbox,
Workers, and its own result path. Incoming peer work can never invoke Reach's Discord delivery.

### Outbound public-text JSON-RPC profile 

The first construction profile, `outbound-public-text@1`, binds
[A2A v1.0.1](https://github.com/a2aproject/A2A/releases/tag/v1.0.1), commit
`3303592588e388e62e0f69f701af531d2f4e3991`, JSON-RPC with `A2A-Version: 1.0`.
Its required extension URI is
`https://github.com/hexanomicon/lychd/blob/main/docs/adr/26-a2a.md#peer-task-jsonrpc-1`.
That URI identifies this versioned contract; availability or a self-advertised key never enrolls
trust. [The upstream extension rules](https://github.com/a2aproject/A2A/blob/3303592588e388e62e0f69f701af531d2f4e3991/docs/topics/extensions.md)
permit required message-signing extensions. RFC 9421 Ed25519 is this profile's explicit requirement,
not a standard mandatory A2A authentication scheme or an invented HTTP Authorization scheme.

An authenticated local operator separately authorized to classify a source may author one
bounded public-text task through the dedicated declaration path. This is an attributed assertion,
not PII detection or proof that text was never pasted. Known restricted influence, prohibited
categories, unknown lineage and local-only constraints refuse. Ordinary chat, ASR, model output,
private Context and serialized classification shapes inherit no declaration. This first transport
profile uses an explicit operator-operation identity, never a fabricated Run, Cut or peer wait.
The native binding below adds a genuine Run owner; private-input transformation remains a
separate acceptance gate.

Only `SendMessage`, `GetTask` and `CancelTask` are admitted. Submit uses one user text part,
`returnImmediately=true`, `historyLength=0`, the exact configured public task schema and
`acceptedOutputModes=["text/plain"]`. Polls also request zero history. The receiver assigns
the foreign task id; a direct Message result is incompatible with this durable-task profile.
No task listing, follow-up turn, raw/URL part, artifact fetch, push, streaming, discovery or
automatic version, endpoint, credential, provider or language fallback is admitted. Typed
inline text results remain quarantined foreign data and confer no tool or game authority.

The semantic request body is sealed once. Every physical attempt prepares fresh signature
timestamps, nonce and attempt identity over its exact UTF-8 body digest and HTTP context, then
seals the complete HTTP representation before a fresh egress decision. This is not portable JCS:
verification hashes actual body bytes before parsing. Request coverage includes method, complete
target URI, content type/digest, protocol/extension, workload sender, recipient, task schema,
local task and physical attempt. The signed response binds status, body digest, those expected
roles and identities, and the exact pending request URI, content digest and nonce. One signature,
the exact component/parameter sets, bounded freshness and matching current enrolled key are
mandatory. Duplicate or ambiguous critical headers, unknown profile fields and content encoding
refuse; no request-component feature unsupported by the installed verifier may be assumed.

The profile bounds the complete application request to 64 KiB, body to 48 KiB, headers to 8 KiB
and 32 fields; response body to 64 KiB, inline artifacts/parts to eight each, and foreign ids to
128 visible ASCII characters. Signature validity is at most 30 seconds, with no future-created
or expired signature admitted. Each task has an independently bounded lifetime and each network
operation one absolute deadline no longer than 30 seconds. HTTPS uses an explicitly configured
trust root, hostname, numeric peer address, port and exact path, without DNS, redirects, ambient
proxies or implicit contact retry. The actual numeric peer is verified after connection.

Base A2A makes SendMessage deduplication optional and supplies no guaranteed message-id lookup.
This profile never resends an uncertain submit or invents a foreign task id. A lost send reply
retains unknown remote execution. A known foreign task id permits a fresh authorized poll;
uncertainty in a read poll cannot authorize another submit. Cancellation acknowledgement is
an authenticated observation of foreign state, not proof of rollback or process containment.
Local expiry, revocation and closed adoption remain distinct from the peer's terminal state.

Acceptance requires the callable production submit/poll/result path, durable task/outbox and
transmission custody, real installed cryptography, current Ward authority, complete-wire gating,
and an independent endpoint implementation. The official Python SDK `1.2.3`, commit
`44b2f761a99123370237afe6c828f4cd2a50c402`, is a conformance candidate in a separate locked test
environment; its unsigned route alone proves neither this extension nor durable peer behavior.
Identity helpers, a dormant registry or recorder-to-HTTP substitution do not pass this gate.

## Envelope

Every message names protocol/schema versions; sender and recipient; message/task/idempotency ids;
issued/expiry times; nonce/replay fence; task type; bounded content/refs; and authentication over
adapter-pinned canonical bytes. LychD portable artifacts follow
[Workflow serialization](28-workflow.md#portable-declaration); an A2A adapter must separately pin
its envelope profile and signature input. `context_id` only correlates: continuation additionally
needs same peer, compatible schema, explicit authorization, and unexpired task relation. Unknown
field/version, identity/signature mismatch, expiry, and same id with changed content fail closed.

Authentication, revocation, and authorization are rechecked at replay, queue, start, resume,
effect, result egress, and adoption boundaries appropriate to the task. Returning an old
idempotent result cannot treat a now-revoked peer as presently authorized.

## Durable task protocol

Admission writes one local peer-task record before work:

```text
RECEIVED → ADMITTED → QUEUED → RUNNING → terminal
```

SUCCEEDED, REFUSED, FAILED, EXPIRED, REVOKED, CANCELLED, and LOST are distinct terminals.
Transport is at-least-once, so inbox admission, claim, adoption, and outbox delivery are
idempotent; repeat same envelope returns same identity, changed-content reuse is a security fault.
Every physical redelivery retains that exact envelope and external/idempotency identity but obtains
a fresh byte-time EgressDecision and consumes its bounded disclosure use; it is not a new semantic
peer task or Privacy Cut.
Polling, callback, and stream may return results, but none is sole truth. Callback needs exact
egress policy and peer revalidation; silence means neither refusal nor success.

## Graph and Long Sleep

Outbound labor occupies one opaque station. The Invocation can enter Durable Stasis only after
the request and outbox intent commit. It then releases local leases and waits for authenticated,
correlated terminal adoption. Its checkpoint retains the peer-task id and local continuation,
never foreign state. Expiry, revocation, and loss follow declared Pattern routes; an unknown
remote effect cannot be silently repeated.

### Native public peer station

`native-public-peer@1` extends the public-text profile through the existing serial Graph, Run
ledger, delivery relay and durable checkpoint owner. It adds a distinct `PeerTaskNode` and
`AWAITING_PEER`, not an AgentJob or another orchestrator. A dedicated authenticated admission
pins the actual Run, Pattern digest, station, stable caller request identity, original public
source, exact target and lifetime. That source is still an explicit operator assertion; a Run,
Sigil, voice transcript or retained declaration shape cannot classify it public.

Prepare one immutable task and outbox without contact, checkpoint that exact task, then atomically
park its Run and settle the claimed delivery. Only the committed exact peer wait permits the
relay's first send. Same semantic occurrence returns the same task, body and original expiry;
changed reuse refuses. A committed or uncertain submit claim is permanent, including when zero
accepted bytes are known. No foreign id means unknown remote execution, never another submit.
Known foreign ids permit independently authorized bounded polls. Network work holds no Run lock
or local capability lease and does not keep the Graph worker resident.

The single current wait owner survives re-admission and claim. Canonical task/terminal custody,
exact Run/source/Pattern ownership and current live authority jointly permit one owner-specific
resume CAS and one successor delivery. Caller-supplied terminal dictionaries cannot authorize
that transition. The first resumable checkpoint must bind the same peer station and task before
any node executes. Only a matching created checkpoint plus committed preparation can recover the
pre-park crash window; missing, running, error or ambiguous cursors never authorize replay.

Live Run permission belongs to the process-owned peer service and actual current operator marker;
it is neither returned nor persisted. Restart creates no live permission. An explicit fresh
authenticated reauthorization rereads the immutable Run/task/source/target relation under current
policy. First activation of a provably unsent task additionally requires a fresh public assertion
over its exact original source. This never redeclares the task, changes its expiry or rearms a
claimed, closed, revoked or expired occurrence. Standalone operator reconciliation cannot itself
resume a Graph. Current Run and claim fences apply at each physical handoff, adoption, resume
and station re-entry; historical admission alone grants none of those actions.

Local cancellation closes adoption for every task bound to the Run, including preparation before
park, and proves retirement of all locally owned exchanges before local terminal commitment.
It requires no foreign id or usable remote credential. `CANCELLED` ends the local Invocation and
its effect/adoption authority; it claims neither rollback nor containment of a sovereign peer.
Retain visible, attributed remote outcome uncertainty independently of checkpoint cleanup.
Remote CancelTask/GetTask is separately authorized, bounded reconciliation; an acknowledgement
is not containment proof. Late authenticated replies may retain correlated remote observations
but cannot reopen adoption or enqueue a continuation. Local AgentJob and process containment
requirements are unchanged.

This is accepted construction law. Delivery requires a coordinated real Run/Graph, PostgreSQL
checkpoint/task/delivery, production authenticated transport and independent endpoint passage,
including actual local-process restart with fresh authentication, one resume, unknown-submit
non-repetition, cancellation races and independently observed local exchange retirement.

Incoming work is an ordinary local admitted run under peer authority. Dispatcher and Orchestrator
may use their local powers; peer receives no internal handles.

`remote` is an origin, trust, and authority qualifier—not a fourth service class. A peer may request
foreground, deadline-windowed, or spare-capacity treatment, but receiver policy maps or clamps that
request under peer identity, quotas, local priority, and resource truth. The remote provenance
remains attached whichever tempo is selected.

## Missing Spells and teaching

The receiving policy handles an unknown or incompatible Spell explicitly:

| Policy | Result |
| --- | --- |
| Refuse | Return a bounded incompatibility result naming only the safe public requirement. |
| Request teaching | Ask for an attributed teaching bundle under exact peer, task, size, content, license, and expiry policy. |
| Trusted exact contract | Continue only when the local catalogue admits that exact public Spell contract and an exact local implementation binding. |

A receiver-owned policy configuration selects among these outcomes by exact peer, task/content
class, and Spell identity. A sender may ask to teach, but its request cannot select the policy,
authorize acquisition, or widen the accepted material.

A teaching bundle is a separately identified, size-bounded, content-addressed manifest over
quarantined foreign material, never a live node, package, tool, or registry write. It may contain a
public contract, examples, implementation or artifact references, provenance, license duties, and
claimed evidence. [Assimilation](35-assimilation.md) may turn it into a local candidate;
Spellweaver validates any contract or Scroll candidate while the appropriate Extension, Packaging,
Security, Evolution, and effect owners retain implementation and activation authority.
The original peer task remains refused or otherwise terminal. A successful lesson permits only a
new envelope and new Invocation, so teaching cannot rewrite an in-flight Scroll or inherit its
authority.

Paid work and paid teaching are distinct purchased resources with distinct quote and idempotency
identities. Toll may quote only after task or teaching eligibility; settlement neither
authenticates the peer nor admits work, teaching, publication, or activation.

## Sovereignty wall

| Boundary | Question |
| --- | --- |
| Identity | Known, authenticated, current, unrevoked peer? |
| Task | This task and content class authorized? |
| Resources | Local capacity at priority/deadline? |
| Tools | Exact task toolset? |
| Artifacts | Read, retain, return each blob? |
| Egress | Result and callback may leave? |
| Economics | Quote/bounty expressly admitted? |

Security egress law keeps source-manifest and influence-label digests plus opaque restricted
lineage references in durable evidence, never raw subjects or source spans, and requires an exact
peer/callback decision per attempt. Trust never declassifies. Magus work may outrank peer labor only
with peer-visible paused, revoked,
or failed settlement; killing work without a result is forbidden. Resource revocation never widens
tool/data authority.

## Legion and Necropolis

Legion delegates to owned nodes. Enrollment may narrow shared administration, but the Node
Agent retains identity, fencing, revocation, and application authorization, with no Master Sigil
or raw host command. Necropolis relates sovereign peers whose foreign Graph, memory, models, and
priors remain private. Both exchange bounded labor without thereby assimilating the other body.

HTTP is first candidate; Nostr/relays remain candidates behind same envelope/inbox/outbox law.
NAT, encryption, and relay signatures require adapter proof. Legion extends one Magus over owned
iron; Necropolis begins at ownership's edge.

## Consequences

!!! success "Accepted"
    - Sovereign execution and local policy survive durable at-least-once exchange.
    - Standard compatibility remains possible without library capture.

!!! failure "Cost"
    - Identity, replay protection, persistence, callbacks, schemas, and reconciliation are security work.
    - Indeterminate outcomes are irreducible until independent interoperability proves the contract.

## Acceptance gates

There is no envelope or ledger implementation, route, peer registry, discovery, cryptographic
implementation, authenticated durable inbox/outbox, callback handler, transport adapter, Run
bridge, or inter-node receipt.

Intercom needs pinned hostile-envelope fixtures; rotation/revocation/expiry/replay proof; durable
inbox/outbox restart recovery; idempotent admission/adoption; SSRF-safe callback/artifact policy;
Graph park/cancel/timeout/re-entry; peer-visible preemption; and one independent endpoint.
An adapter that supports Spell compatibility or teaching additionally needs downgrade, unknown-
revision, false-claim, oversized-bundle, provenance/license, quarantine, and no-live-mutation proof.

---
title: "27. Memory"
plain_name: "Design rule 27: Long-term memory"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/27-memory/
guide: https://lychd.snayu.ai/docs/adr/27-memory/
---

# 27. Memory (Design rule 27: Long-term memory)

## Plain-English summary (Snayu)

**What it is:** Defines Long-term Memory (Archive): records, sources, policy and lifecycle stored in PostgreSQL with pgvector indexes behind LychD's own interfaces. Retrieval frameworks may help but never own storage, curation or training eligibility.

**Why it matters:** Read this before adding memory, embeddings, retrieval or anything that stores what the assistant learns.

- PostgreSQL is the source of truth; embeddings are derived data that can be rebuilt or deleted.
- Run logs, traces, personas and training data are separate stores, linked by stable references.
- Today only a bounded, opt-in local public-notes profile works; general intake and recall are not built.

**Status:** Partial. Only the local public-notes profile works; general memory is designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    Working context is bounded; durable storage does not itself decide what deserves retention,
    recall, correction, or authority. Embeddings help retrieve while adding model and deletion
    obligations. Archive must keep source, policy, and lifecycle inspectable outside retrieval tools.

Flux leaves a [Seed](../sepulcher/lich/spirit/seed.md); Archive preserves its return; [Recall](../sepulcher/lich/spirit/recall.md)
moves retained form into present work.

## Decision

Archive keeps authoritative records, lineage, policy, lifecycle, and derivations in PostgreSQL,
with pgvector-derived indexes behind LychD-owned ports. Frameworks may help extract, embed, rank,
or rerank; they cannot silently acquire transaction, migration, curation, sharing, or
training-eligibility authority. Run/Step ledgers, traces, checkpoints, Personas, one-call context,
and Soulforge corpora remain distinct stores of meaning, cited through stable refs.

!!! warning "Delivery boundary"
    The bounded public-note profile below does not deliver the general Archive contract.
    Automatic intake, combined native semantic retrieval, cross-namespace sharing, Curator, and
    private-material recall remain separate work. Existing Karma rows are not a usable memory corpus. State owns
    the profile's exact executable and acceptance boundary.

## Bounded local public notes

The opt-in `local-public-notes@1` profile admits explicitly supplied bounded text to one
configured namespace. Trusted host composition supplies its stable local subject, namespace owner,
and mandatory current authorizer; neither a Sigil name nor public classification grants access.
The retained namespace binds its owner and policy revision. A changed configured binding refuses
existing material until an explicit migration is admitted; restart cannot adopt it implicitly.
Every admission, lifecycle change, recall, and receipt resolution binds subject, namespace, owner,
purpose, exact policy revision, action, and proposed or retained object digest. Authorization is
checked before reads and again after awaited preparation under the serialized namespace operation.

An exact intake request is idempotent. Reusing its identity with different material refuses, as
does changing bytes under an existing source key and source revision. Separate request identities
may name the same exact source revision without creating another note. A revoked source revision
remains a tombstone and cannot be reingested. Source identity is asserted provenance, not proof of
real-world authorship or semantic deduplication.

Each note revision starts as a candidate. Explicit promotion makes it eligible and atomically
archives any earlier promoted revision of that source. Archive and revoke remove ordinary recall
eligibility; revoke additionally clears controlled text. Lifecycle versions fence stale changes
and retained recall. PostgreSQL `simple` text search supplies lexical matching and ranking, with
finite input, result, and character bounds and a stable UUID tie break. Lexical recall executes no embedding.
Every Archive transaction sets its own five-second statement timeout and two-second lock timeout
before namespace work; these bounds never change the connection's defaults. Timeout is an
operation failure that rolls back undecided work, never a lexical miss.

Current authorization is checked once more after transaction and session cleanup, immediately
before any record, receipt or source projection is returned. A refusal at that final response
boundary does not undo an already committed mutation. An authorized exact intake replay recovers
its retained identity and current lifecycle; stale lifecycle retries refuse their expected-version
comparison rather than guessing whether to repeat the change.

Authorized configuration discovery and metadata inspection have explicit actions and management
purpose; recall is not a shortcut to review authority. Configuration discovery returns only the
current configured public-note profile, without storage access, namespace creation, model probes
or Run admission. It does not establish compatibility with an existing retained namespace.
A separate authorized interface projection may identify the admission engine's current default
Pattern and compare its complete configured Archive binding with this managed profile. Only
`bridge_chat@3` with an equal binding requests this profile; another default or a missing/different
binding does not. An unavailable admission default stays unknown. This projection reveals no other
profile's namespace or owner and performs no storage, model or Run work. It establishes neither
readiness, the next routed Run, nor the binding of an already admitted Run.
Metadata reads expose bounded source/revision, digest, lifecycle/version and retention metadata
across candidates, promoted revisions, archives and revoked tombstones. They select no note text,
search vectors, recall projections or embeddings. Lists use a finite page bound and stable keyset;
an exact-record read permits recovery from a lost mutation response without replaying that effect.
Reads create no persistent namespace, note or receipt rows. A missing namespace lists empty, while
an existing owner/policy mismatch or storage failure refuses instead of becoming an empty result.
Current authorization is rechecked after awaited preparation and transaction/session cleanup.
Recovered lifecycle versions still require a new explicit compare-and-set decision; inspection
neither retries a transition nor restores revoked content or source-revision eligibility.

A durable recall receipt retains the exact namespace, subject, purpose, policy, query digest,
budgets, selected revision and lifecycle identities, projection digests, and ordered scores. It
contains neither query nor note text. Resolving that receipt rechecks current authority and exact
eligible revisions; it refuses revoked, archived, superseded, changed, or missing material rather
than replacing the selection. A miss differs from infrastructure failure. Each later model request
resolves the same receipt again.

Historical receipt metadata inspection is a separate current-authorized management read. It
looks up one exact namespace and request identity, validates the retained receipt's integrity and
its complete expected request, subject, answer purpose and profile binding, and returns no source
text. It performs no recall, resolution, lifecycle transition or persistent write. Missing storage
is not a miss; an absent receipt remains absent. Namespace owner/policy and current inspection
authority are checked after awaited preparation and transaction/session cleanup. A valid historical
selection remains inspectable after source correction, archival or revocation; that inspection
neither claims current eligibility nor restores controlled content. Source names and digests are
protected metadata under the configured local management authority, not anonymous public exports.

A Run-linked explanation additionally requires the retained exact supported Pattern, admitted
Archive/capability binding and complete expected recall request. Caller-supplied Run/request
identities can preseed even that exact request. The explanation therefore establishes a retained
selection matching the Run request, not that the workflow consumed it or sent it to a provider.
A stronger execution claim requires a separately owned capture at the actual boundary. Context owns transient attributed data projection; retrieval
never adds instructions or authority. The read-only Bridge revision uses no model tools or settled
history replay, and retains only receipt references to retrieved material in Graph state. Generated replies may quote
the notes: source revocation cannot erase that recorded influence.

This profile establishes a bounded lexical path, not semantic retrieval, automatic retention,
Curator judgment, shared namespaces, remote IAM, private-material egress, or training. Old Karma
rows remain inert and are not silently admitted. State owns the implementation evidence.

## Explicit local derivation

An independent optional Archive selection may bind one configured generation and the exact local
Core `model.embed@1` profile. Generation registration is explicit and authorized; startup never
registers rows or starts a model. Its immutable manifest binds namespace ownership and policy,
Core profile/binding, whole-note chunking, cosine metric, float32 storage and a fixed 60-second
attempt lifetime. Retiring a generation is irreversible; replay cannot reactivate it.

An authorized caller may discover the configured generation identifier and manifest digest before
registration. Discovery checks current namespace policy and the generation-discovery action with
the management purpose. It returns configuration metadata only: no registration or eligibility
claim, source material, database access, lease, readiness probe or model activation follows.

The first derivation stores one whole promoted note as one 1024-dimensional pgvector value.
Core measures tokens and refuses its fixed byte/token limits; neither caller truncates or splits
oversize notes. The profile binds float32 little-endian encoding and the accepted L2 tolerance.
Core and persistence use the same canonical float32 digest without renormalization; an actual
PostgreSQL round trip must preserve it, including signed zero. The execution receipt retains
only bounded identities, digests and usage, never source text or a second copy of vector coordinates.

Durable identity is namespace, generation, exact source revision and whole-note chunk. Status
exposes the latest attempt only: prepared, running, expired, complete, failed or invalidated.
A DB-clock deadline makes an abandoned running attempt visibly expired; only an explicit retry
may claim it. No background job, automatic retry, semantic coverage or query eligibility follows.
Exact completed replay performs no embedding while current source and generation remain eligible.

All state changes take the existing namespace lock first. Preparation retains only metadata;
the caller acquires its ordinary Core lease before claiming source. Claim creates a fresh token
and increments attempt and row versions. Concurrent callers may acquire leases, but only the
winning claim discloses source and calls embedding; losers close their leases. No database lock
spans inference or lease cleanup. Completion follows cleanup and conditionally matches the exact
generation, source, live token, versions and unexpired DB deadline. Late results cannot upsert or
resurrect retired data. A cleanup failure cannot publish complete.

Archive, revoke, superseding promotion and generation retirement atomically invalidate affected
derivations across generations, clear all vector columns and live attempt tokens, and advance
fences. Authorized status can still inspect the retained historical source reference after
revocation; that reference is not permission to resolve source bytes. Revocation cannot retract
bytes already accepted at the locked source handoff, or remove WAL, backups and earlier outputs.
Current policy is checked before source handoff, after session cleanup and before each source-bearing
Core request; these synchronous checks do not claim an atomic socket-write/lifecycle transaction.

This derivation API adds no semantic recall, ANN index, Bridge revision, model tool or receipt-v2
format. Existing lexical receipts and Bridge3 behavior remain unchanged. Model conformance,
PostgreSQL race tests and live host acceptance are separate evidence boundaries recorded by State.

## Explicit exact semantic recall

A separately selected exact semantic consumer binds the same public-note Archive profile and one
immutable configured generation/reference plus Core model.embed@1 binding. Query inference is
separately opt-in through `archive.semantic` (default `false`), permitted only with the existing
`archive.derivation` selection. It uses that exact configured generation; derivation configuration
alone grants no semantic query authority. Startup registers/derives/queries nothing. Caller supplies
no vector, arbitrary embedder, namespace fallback or model command. Lexical request/receipt schema1,
digests, retained replay and Bridge3 remain unchanged; the semantic policy is
postgres-exact-cosine@1 with a separate strict request and schema2 receipt.

Generation readiness is **per-source derivation**, not a generation-wide completed corpus claim. A
query may search only the exact current complete rows of its active configured generation. Under the
existing namespace lock in the final selection transaction, the receipt counts current promoted
non-null notes and the subset with eligible complete vectors before threshold/rank; retained
coverage is historical on replay. Zero eligible rows is an observed empty compatible set with
explicit coverage; missing/foreign/unregistered/retired/mismatched generation is a typed failure,
not a miss. No completeness marker, new namespace adoption or silent generation registration is
invented.

The request binds namespace/request identity, exact generation/manifest, configured profile/policy,
trusted subject/purpose, raw query digest and complete defaults/budgets into request identity. Query
length is bounded by current Archive limit; Core additionally enforces exact rendered UTF-8/token
bounds. min_cosine is an explicit required finite value in[-1,1], not an inferred
confidence/default. Results use finite cosine similarity in[-1,1] (one minus pgvector cosine
distance), descending score and stable note UUID ties. All current eligibility predicates apply
before exact distance/ranking; no global top-k followed by filtering, approximate index or silent
lexical fallback. Select at most the requested top-k, then fit whole-note character budget without
truncation or backfill, retaining omissions.

Semantic recall and semantic resolution use separate explicit authorization actions
(semantic_recall, semantic_resolve); historical metadata retains inspect authority. The caller's
current configured namespace/owner/policy, purpose and exact request/generation binding must
authorize before query disclosure/storage; recheck after every awaited preparation, before each
source-bearing Core request and after session/lease cleanup. Source text and query remain
public-classified protected data under those authorities. Similarity locates context; it grants no
instruction, tool, write, identity or truth authority.

Preflight/replay is a short serialized namespace transaction. Exact completed semantic replay checks
integrity and full binding and returns its original text-free receipt with zero embedding, including
after source/generation retirement as historical selection only. It never reranks or restores
eligibility. Conflicting request identity, including lexical/semantic reuse, refuses before
inference. For a new request, preflight verifies the active exact generation and captures its
version, then releases the transaction before one ordinary embed_query lease. Validate
profile/item/input/rendered/vector/token/native receipt bindings and canonical float32/L2 without
renormalization. Close/join driver and counted lease before selection/publication. Missing
readiness, malformed/oversize output, cancellation, timeout and cleanup failure cannot publish a
miss.

The final namespace transaction first rechecks current authority and looks up the request identity
again: a matching completed receipt returns its original selection with this caller's execution
metadata; a conflict refuses. Only the unpublished branch rechecks the same active
generation/version and selects current eligible joined source/vector rows. A retired generation
during inference refuses. Note lifecycle changes during inference affect this final eligible
snapshot; no stale vector can be resurrected. Selected rows pin exact source
revision/digest/lifecycle/projection, derivation identity/row version/vector digest and
generation/reference/version. Persist schema2 in the existing archive_recall JSON/namespace-request
uniqueness, with text-free query execution metadata/digests/tokens and
coverage/bounds/order/omissions. Never persist raw query text, query-vector coordinates, source
bodies or a second vector copy in the receipt. No migration or new durable job ledger is justified
for this slice.

No database lock spans inference or cleanup. Concurrent unseen identical requests may each perform
their one explicitly admitted local query operation before one receipt wins publication. This
duplicate cost is explicitly allowed, not exactly-once inference. Completed replay does no model
work. A successful immediate call result reports both the winning retained selection receipt and any
query-execution metadata incurred by **this caller**, so a losing publisher cannot disguise its own
work as zero-cost replay. Winning receipt usage is not total duplicate/unknown-failure accounting;
no durable all-attempt/spend completeness claim follows. No automatic retry; unknown outcome
requires an explicit caller decision and may incur another operation. Reuse the existing counted
lease/resource boundaries, without adding a global paid-capacity policy.

Semantic resolution rechecks current authority, exact active generation/reference/version, and every
selected complete derivation/source/lifecycle/projection fence before returning attributed source
bytes. Revocation, archival, supersession, generation retirement, missing/incomplete/changed vectors
or any binding change refuses the whole resolution; no replacement source or rerank. Historical
text-free inspection remains independent and can survive those changes. Final synchronous authority
checks follow transaction/session cleanup; they do not claim atomic socket-write/lifecycle or
deletion of earlier influence. Existing lexical readers explicitly refuse a schema2 receipt rather
than silently parsing it as schema1.

This section governs a separately selected consumer; it does not establish delivery. State owns
executable and native-composition acceptance.

### Native semantic source-answer consumer

An explicitly selected native source-answer casting may consume the existing semantic service.
Admission retains the complete configured generation manifest/reference and explicit threshold,
result and character bounds together with the exact local chat capability, caller and Run. No
client supplies server admission metadata. Restore compares that binding with the retained Run
and the current composed service; changed configuration cannot silently replace the admitted
profile or generation. Each node obtains its Archive subject through the persisted caller's
mandatory local subject mapping. Configuration and historical selection do not confer current
source authority.

The casting derives one semantic-specific request identity from its canonical Run, recalls before
chat admission, and retains only receipt references and observed text-free query execution metadata.
The embedding driver and counted lease must close before chat acquisition. A dedicated cold
capability may use the existing bounded Graph hardware wait and re-enter the same recall node
before query inference; shared unmanaged cold and failed convergence refuse. Re-entry rechecks
current authority and request identity. Completed replay performs no query inference. Interrupted
or duplicate pre-checkpoint work is not zero-cost or exactly-once execution; winning receipt usage
and this caller's observed execution remain distinct from total attempt accounting.

Before chat/hardware work, every outbound count/request/stream, and settlement, resolve the exact
schema2 receipt under current generation/source/derivation and caller fences. No rerank, replacement,
lexical fallback, automatic preparation or unknown-outcome inference retry is implied. Context
preserves coverage and source attribution under [ADR21](21-context.md#explicit-archive-projection).
The answer consumer applies [ADR20’s completion rule](20-agents.md#semantic-answer-completion)
before ordinary settlement: a known output-limit response refuses without automatic retry. A
successful empty recall is distinct from incomplete model generation.

After successful current resolution selects no sources, the answer node settles an explicitly
labelled deterministic recall outcome without a Chat grant, context assembly, pre-count, request,
stream or new SDK messages. It distinguishes zero eligible notes, no threshold selection and
notes omitted for the character budget, and reports the receipt's historical coverage without
claiming an exhaustive search or an answer unsupported by sources. Fresh query embedding remains
counted work; this is zero additional Chat generation, not zero model work. Refused resolution is
never an empty success. Settlement still revalidates the exact receipt under current authority;
ordinary retained conversation turns may record the outcome while existing SDK history stays
unchanged. Nonempty selections retain the generated-answer path and its completion checks.

A generated answer can quote sources and persist; revocation blocks later use without erasing that
prior influence. Retrieval conformance or a synthetic ranking trial cannot establish grounded
answers, abstention, actual native execution or broad quality. State records those acceptances
separately.

## Framework boundary and Memori

[Memori](https://github.com/MemoriLabs/Memori) is a maintained comparison source, not an installed
LychD subsystem. Its explicit entity/process/session attribution, raw-conversation versus derived
augmentation stages, idempotent conversation creation, bounded background writer queue, and drain
operation are useful implementation patterns. A pinned source checkout may support design review;
it grants no runtime or schema authority. In the reviewed
[574b1ea augmentation implementation](https://github.com/MemoriLabs/Memori/blob/574b1ea3e876f100ef82c37817d603eb7e258e59/memori/memory/augmentation/augmentations/memori/_augmentation.py),
the request includes conversation messages and a prior summary. A locally owned database therefore
does not establish local processing or permitted egress. Attribution identifiers are not caller
authentication, and queue drain is not LychD's durable completion or stale-write contract.

LychD does not adopt transparent LLM-client interception, retain every conversation, automatically
extract claims, or inject recall into every prompt. Those conveniences cross Archive's admission,
privacy, correction, and Context authority. A future LychD-owned `CandidateArchivePort` must admit
attributed raw candidates and separately identified derivatives, preserve source lineage and
anti-reingestion identity, and expose bounded processing state. The exact retry and stale-write
rules for that general interface remain design requirements. The bounded public-note profile
defines its own exact intake, lifecycle and lexical recall below those broader requirements.
Embedding, curation and training consumers require separate evidence.

## The Archive record

Each immutable record revision names the following:

| Concern | Required content |
| --- | --- |
| Identity | Stable record and revision; namespace owner and subject; kind and lifecycle. |
| Material | Content or an immutable reference, plus derived representations. |
| Provenance | Source, producer, observation, and transformations. |
| Time | Creation, observation, validity, expiry, supersession, contradiction, and retention times. |
| Authority | Classification, sharing, and deletion authority. |
| Evidence | Quality and evaluator evidence. |
| Relations | Related Session, Run, Invocation, Pattern, Persona, and artifact references. |

```text
candidate → promoted → archived
    │           │
    └───────────┴→ revoked
```

candidate awaits adjudication; promoted is eligible only for declared recall; archived remains but
is excluded from ordinary recall; revoked retains lawful tombstone/lineage while content/indexes
are removed or quarantined. Promotion is bounded eligibility, never infallibility: Viparyaya and
Pramāṇa both carry source and correction.

## Namespaces and authority

Choose the namespace before retrieval begins, for every write and recall request. A namespace
may belong to a Principal, Persona, Composition, shared body, or published corpus, and needs its
own explicit identity and policy. Current Sigils have no stable `entity_id`; Archive must neither
invent `Sigil.id` nor claim delivered isolation across identities.

Cross-namespace recall is denied by default. A sharing decision binds the source, consumer,
purpose, record and field classes, duration, onward disclosure and revocation. Similarity,
organizational membership, delegation and model choice cannot supply that decision. Candidates
must be authorized before their content or embeddings leave the owner's boundary.

## Embeddings are derived data

Each vector inherits its source chunk's Privacy Label and deletion lineage. Opacity does not
permit remote embedding: Context owns the labels, and Security owns declassification. Every
derived representation records:

- source revision and chunk;
- embedder identity, revision, digest and configuration;
- dimension, distance measure, normalization, chunking and preprocessing;
- creation time, status and quality receipt; and
- index generation.

Incompatible spaces cannot be compared. Changing the embedder creates a new generation. An older
generation may remain queryable under policy during a proved migration, then retire; migration
must neither overwrite it nor mix the spaces.

pgvector gives this substrate one governed database backup target. A coherent snapshot of
artifacts, models and services still requires their own owners. The public-note profile uses a
PostgreSQL lexical index. The explicit derivation path above retains generations; HNSW and hybrid retrieval remain separate
implementation work; an installed pgvector extension does not establish that delivery.

## Ingestion

Ingestion is admitted workflow:

1. authorize source and memory purpose;
2. retain immutable source/provenance;
3. make candidate units with versioned parser/extractor;
4. classify privacy, owner, retention, sharing;
5. validate and retain uncertainty/contradiction as such;
6. write candidate revisions;
7. derive representations through admitted embedding capability;
8. offer eligible candidates to Curator.

Workers may partition and embed admitted material. Dispatcher selects an eligible capability;
Orchestrator supplies readiness. Neither decides what deserves retention. Extracted facts,
relations, summaries and preferences remain attributed claims with a source excerpt or reference.

An authoritative record and its derivation may commit separately. Asynchronous vector work must
expose its index state and remain invisible to vector recall until its exact source derivation
in the configured generation is complete. The explicit semantic consumer reports partial
completed-source coverage; it does not infer a generation-wide completion marker.
Retries are idempotent by source revision and derivation specification.

## Curation and sediment 

A versioned Curator weighs source quality, verification, correction, contradiction, use outcome,
recency, expiry, and Drift findings. Declared policy may let access, repetition, similarity, or
praise affect salience. None of those signals establishes truth.

The Curator may promote, retain or archive a record; revoke it and invalidate derivatives; or
record supersession and contradiction without rewriting history. An anchor has an owner and a
review rule, so it remains corrigible. Batch curation stages revisions and leaves active Agent
Context unchanged. Mirror, Context and Drift may consume these records while the Curator retains
the curation decision.

## Recall

One contract serves Pattern context or an authorized tool:

1. Bind caller, namespace, purpose, policy, query, and result and token budgets.
2. Authorize fields and classes.
3. Choose a compatible lexical, vector, relational, or hybrid plan.
4. Retrieve and rerank under versioned implementations.
5. Apply the threshold, diversity, recency, and contradiction rules.
6. Return bounded results with provenance, lifecycle, times, and uncertainty.
7. Write a receipt without treating a hidden prompt as memory.

Similarity locates a result within a representation; it is not a probability that the result is
true. A threshold miss establishes only that no result was admissible to this query.

Retrieval grows from a measured lexical and exact-vector baseline. Approximate indexes must retain
namespace eligibility and demonstrate their filtered recall against that baseline; [pgvector's
filtering behavior](https://github.com/pgvector/pgvector#filtering) is part of that evaluation.
Graph extraction is a separate derivation with source lineage and invalidation, not an automatic
upgrade to a vector index. [GraphRAG local search](https://microsoft.github.io/graphrag/query/local_search/)
targets entity relationships; [global search](https://microsoft.github.io/graphrag/query/global_search/)
uses community reports for corpus-wide questions. Either requires an admitted corpus, extraction
quality and cost evidence, and the same current-authority and Context boundaries before adoption.

Context fits the returned material and records omissions. The model receives an attributed prior
rather than an instruction. The receipt pins the policy and returned revisions. Later correction
changes what future queries may return while preserving the record of influence on earlier Runs.

## Continuity and deletion

Committed rows survive process death. Reanimation still requires an explicit Pattern and compatible
revisions; restoring rows does not restore thought or Persona.

Deletion removes or quarantines controlled content and indexes, preserves the minimum tombstone
needed to prevent reingestion, and invalidates dependent recall and evaluation. It must also
identify exported or shared copies and Soulforge descendants. Influence already carried into
generated artifacts or weights requires decisions by those owners; deleting an Archive row
cannot erase it.

## Training boundary

Archive may supply structured input to Soulforge, but corpus admission remains a separate act.
It selects exact revisions and checks privacy, license, deduplication, splits, and holdout.
Findings and feedback can nominate material for review; they cannot automatically alter Karma,
rank, or weights.

## Rejected alternatives

### A vector service as the source of truth

A derived store may scale retrieval, but cannot own content, provenance, policy, lifecycle, or restore.

### A retrieval framework as the Archive

An add/search API cannot expose curation, deletion, audit, and training-admission records.

### Automatic retention of every trace

It expands privacy exposure and feeds error back into context; only explicit ingestion makes candidates.

## Consequences

!!! success "Accepted"
    - Inspectable provenance and vector derivation share one governed substrate.
    - Authorization precedes retrieval; recall retains uncertainty and correction.

!!! failure "Cost"
    - Re-embedding, generations, provenance, deletion propagation, and PostgreSQL operations are substantial.
    - Curation and hybrid quality need calibrated human/corpus-specific measurement.

## Acceptance evidence

The local public-note profile requires real PostgreSQL evidence for explicit authorized intake,
exact replay and conflict refusal, staged promotion and correction, bounded lexical recall and
threshold miss, revocation and search cleanup, restart, receipt revalidation, and a guarded schema
downgrade. Its selected model path separately proves transient untrusted-data projection without
automatic transcript retention. Semantic Archive acceptance additionally requires a compatible
embedding capability, derivation generations, semantic retrieval and index restoration. State
records delivery; lexical acceptance does not waive those later requirements.

---
title: "28. Workflow"
plain_name: "Design rule 28: Workflows and apps"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/28-workflow/
guide: https://lychd.snayu.ai/docs/adr/28-workflow/
---

# 28. Workflow (Design rule 28: Workflows and apps)

## Plain-English summary (Snayu)

**What it is:** Defines the Workflow Engine (Spellweaver): who owns each Workflow (Pattern) and its versions, how an App (Composition) publishes workflows, and how one exact workflow version is selected, run, paused and migrated.

**Why it matters:** Read this before creating a workflow, versioning one or building an App or App Bundle.

- Each Job Record pins its exact workflow version; resume never re-routes the request.
- New workflows need an App owner; an App Bundle (Suite) may publish only coordination workflows.
- Old versions stay runnable until pinned jobs finish; history is never rewritten during migration.

**Status:** Partial. A fixed core workflow registry works; app publishing and scheduling are designed.

## Original text (Hexanomicon)

!!! abstract "Context"
    Graph carries typed movement, not the answer to which graph serves an Intent, who owns its
    revision, or which score remains valid through pause and repair. Spellweaver supplies that
    logical jurisdiction without absorbing authority, execution, or application purpose.

[Spellweaver](../sepulcher/extensions/weaver/index.md) keeps the score through motion, pause, and return.

For one casting, follow [score identity](#spells-scrolls-and-casting), [exact road selection](#execution-road-planning), [admission](#admission-and-ownership), and [Stasis](#gates-effects-and-stasis). To change what may be cast, follow [migration](#migration-without-rewritten-history), [contribution](#pattern-contribution), and [protected authorship](#authorship-provenance-and-protected-regions). [Application and coordination ownership](#compositions-products-suites-and-schedules) keeps those scores accountable to their Compositions, Products, and Suites.

The contracts below connect application ownership to one exact casting. [Current material](#current-material) relates them to the source registry; [State of Work](../state-of-the-work.md#topology-a-local-runs) collects implementation evidence and outstanding work.

## Decision

**Spellweaver** is LychD's single logical workflow jurisdiction; `Weaver` remains its short,
code-facing name and the compatibility spelling used by existing paths.

| Name | Office |
| --- | --- |
| Area | Non-exclusive thematic grouping for discovering Compositions, without application or runtime ownership |
| Composition | Reusable application capability owning domain records, judgment, effects, policies, projections, and a Pattern catalogue |
| Composition Revision | One immutable version of a stable Composition contract; a materially different application capability requires another identity |
| Product | Named professional or market package selecting Composition or Suite revisions, owner-qualified profiles, projections, and concrete use cases |
| Pattern | One named executable-score lineage published by an application owner: a Composition, or a Suite for coordination only |
| Scroll | The mythic name for one immutable Pattern revision: the whole score, not one node |
| Spell | One independently named semantic action contract: what a station may do |
| Spell placement | One Scroll-local station that invokes an exact Spell contract |
| Invocation | One admitted bounded world—the Circle—in which identity, Context, authority, and consequence meet |
| Casting | The performance of one exact Scroll within that Invocation |
| Run | Durable execution/ledger identity |
| Graph | Typed state topology |
| Loom | Read-only declared-score projection |
| Suite | Versioned live coordination of separate Composition-owned Invocations, independent of Product packaging |

Spellweaver owns validation, registration, routing, logical dependencies, Gates, schedules/overlap,
revision continuity, and contribution.

Composition owns domain judgment. Product owns its customer
promise, supported-use-case catalogue, packaging, and defaults, but none of its members' records,
policy, secrets, consent, or effect authority.

IAM/Ward/HitL own authority; Dispatcher capability;
Orchestrator readiness; Workers delivery/retry; Phylactery/Graph stores and checkpoints; Drift
evaluation; Soulforge corpus and training lineage. Promotion remains with the receiving policy,
required HitL, and target effect owner under [Training](33-training.md).

## Spells, Scrolls, and casting

The grammar follows a performance: a **Scroll** is one immutable workflow score; each semantic
station places a **Spell**; a **casting** performs the Scroll inside one admitted Invocation and
its [Circle](../divination/altar/circle.md). These names preserve distinct engineering identities.
They create no duplicate schemas, and imagery cannot replace those identities.

A Spell is the smallest independently named, discoverable, teachable action at the workflow
boundary: ask an Agent, anonymize material, await consent, write an artifact, delegate work, or
send through a Portal. “Smallest” is semantic, not mechanical. Its implementation may involve
model calls, tools, syscalls, retries, or adapter machinery. An internal operation becomes another
Spell placement only when the Scroll must independently type, route, authorize, checkpoint,
retry, inspect, or recover it.

The **Spell contract** defines typed input, output, errors and non-completion; semantic
requirements; authority and effect demands; and continuity obligations. A **Spell implementation**
Contribution claims to realize one exact contract revision, retains its Registrant provenance, and
separately names any concrete Provider it binds. It has distinct code, package, adapter,
checkpoint, and evidence identity. A Spell is not an uppercase Dispatcher
`Capability`, tool, Agent, credential, grant, Python type, or live handle. Its name requests a
bounded action and grants no power to perform it.

A Scroll declares its placements, edges, entry, termination, configuration, budgets, requirements,
and authority/effect/privacy ceilings; receiving the artifact conveys none of that authority. Each
placement names an exact authority-qualified Spell contract revision and digest. A receiver-owned,
immutable **Resolution Lock** binds it to an exact local implementation, adapter, code/artifact,
Agent/Posture requirement, tool/effect contracts, checkpoint codec, and registry generation where
needed. The Run pins both the Scroll snapshot and Resolution Lock digest. Contract identity,
implementation identity, and placement identity never substitute for one another.

A one-Spell Scroll is valid. A larger workflow or batch is simply a Scroll with several placements;
the same Spell may appear more than once under distinct placement identities and bindings. This
uses the existing workflow identity rather than inventing another batch object.

Admission distinguishes parseable, contract-conformant, locally bound, available, authorized, and
admissible. A claim at one level proves none of the later levels. Unknown, unavailable,
incompatible, revoked, or unauthorized placements block casting; no similar name, version range,
provider, or newer revision may be substituted. A future Loom may render an **inert resolution
report** with grey placements and redacted reasons, but such a view is not an executable Graph.

The current fixed manifests expose station key, label, kind, one workflow-wide implementation
closure, and edges, with each executable station bound one-to-one to a Python Graph node. A current
station therefore behaves like a legacy inline Spell placement plus implementation binding, but it
has no independent public Spell identity. The runtime does not ship a Spell catalogue, persisted Resolution Lock,
portable Scroll ABI, remote compatibility negotiation, teaching surface, or package contribution
store.

Policy for an unknown Spell may choose only among refusal, a request for an attributed teaching
candidate, or use of an already admitted exact contract with an exact local binding. A teaching
candidate is hostile foreign craft: it enters [Assimilation](35-assimilation.md), not the live
registry. Smith may re-express it locally, but Spellweaver validates and the target owner publishes
it only after evidence and authorization. Publication creates new catalogue truth and a later
casting; it never mutates or resumes the refused Invocation under changed law.

### Language is typed, not global

Canonical Composition, Pattern, Scroll, Spell, placement, schema, field, route, status, and event
identities are locale-neutral and never translated. Human-facing labels and explanations may use
versioned catalogues, but changing their locale cannot change the signed declaration, Resolution
Lock, Graph topology, or Run. [Frontend](15-frontend.md#interface-locale-and-content-language) owns
Altar locale; [Vision](36-vision.md) and [Audio](37-audio.md#engine-model-protocol-and-language)
own their media-language boundaries.

A Spell contract carries exact language or locale fields only where its semantics require them:
ordered input/output preferences, original language, requested result language, permitted
detection, fallback, and refusal. Translation is a separately named, attributed Spell or
owner-declared transformation; it retains source and derived text, implementation revision, and
declared loss. A model, engine, browser, peer, or Persona may not infer a host-global language or
silently translate another station's material.

Translation does not become a freestanding Composition merely because several Patterns can reuse
it. A versioned Translation Spell has an authority-qualified publisher that owns the contract's
semantics and revision; Spellweaver owns registration, placement, resolution, and casting law,
not linguistic truth or application acceptance. The Composition placing it retains the source and
attributed derivative and owns fit for its domain.

For example, [Language Edition](../compositions/language-edition/index.md) may place Translation inside a timed-media
language edition while retaining scene, speaker, glossary, timing, and localization judgment.
Another application may place the same exact contract under different records and finish law
without inheriting Language Edition's project or becoming part of a global Translation workflow.

### Progressive finish and forward continuation

A Scroll may declare several typed finish boundaries and an exact admission-time finish policy,
including a bounded interactive policy whose possible Gates and terminal routes are already in the
score. For example, one visual score may permit an accepted still, an animated sequence, or a
sealed visual package. Reaching the requested still boundary is successful completion of that
Invocation, not a Run left in Stasis. Failing to reach a requested motion boundary is partial or
non-complete according to the pinned score; an intermediate image cannot be relabelled as the
requested video.

A Gate may pause the same casting for an exact review or a declared choice to continue. Live or
Durable Stasis exists only while an admitted owner, capability transition, consent, or delegated
result remains outstanding. Once the operator settles at a valid finish boundary, the Run becomes
terminal. Later animation, soundtrack, edit, or publication begins a new forward Invocation over
immutable `ArtifactRef` inputs and preserves the prior result.

Different prompts, source artifacts, requested language, target profiles, or a declared finish
boundary are new Invocation inputs when the exact Scroll schema permits them. Different stations,
edges, Spell contracts, authority ceilings, or model requirements create another Scroll revision.
Several steps owned by one Composition may inhabit one Scroll; separate Composition-owned work is
coordinated by a Suite through typed handoffs, never by nesting or silently resuming another
Pattern.

## Portable declaration

Portable `SpellContract`, `Scroll`, and `TeachingBundle` artifacts use versioned, restricted UTF-8
JSON. Hash and signature inputs use the pinned
[JSON Canonicalization Scheme](https://www.rfc-editor.org/rfc/rfc8785.html); duplicate keys,
non-interoperable numeric values, unknown unnamespaced fields, YAML tags/aliases/merge semantics,
and source-language object construction are refused. Semantically unordered arrays define and
verify their own deterministic order. Identity includes schema reference, authority-qualified name,
exact revision, algorithm-tagged digest, and domain-separated artifact kind.

YAML may serve as a friendly Loom or repository authoring projection, but it must compile through
the same typed validator into canonical JSON. YAML text is never portable identity and is never the
signed object. A different wire encoding requires a separately versioned adapter and conformance
corpus; it cannot claim byte identity with JSON.

`core` contract namespaces are reserved to their canonical owner. Built-in, Crypt, operator, and
foreign publishers retain distinct authority-qualified identities. A private implementation may
prove conformance to a public contract without acquiring its publisher's name. Learned material is
private by default and preserves `derived_from` or `implements` lineage; promotion cannot squat a
canonical namespace.

## Current material

Fixed source registry retains bridge_chat@1 (Bridge conversation, context, Agent turn, optional consent
Gate, reply), adds bridge_chat@2 with an admission-pinned exact capability key and bridge_chat@3
with that key plus an explicit public-note Archive profile. Opt-in bridge_chat@4 binds one
authenticated public-page declaration and Scout profile. The registry also retains
delegated_rite@1 (exact `/delegate` command token, reference job, Durable Stasis,
result/reply). Optional delegated_rite@2 retains one configured runtime/profile through Run admission
and checkpoint validation; neither revision supplies an external coding-agent/Tomb plane. One boot-composed catalogue
is shared by admission, workers, Bridge, Loom, and Orb. It freezes after construction, rejects
duplicate exact revisions, requires an explicit active revision when alternatives exist, permits
registered revisions or whole names to remain retained but inactive, requires explicit non-default
route precedence whenever multiple names are active, and has one active default. Run commits selected
name and manifest; resume never routes Intent again. Loom exposes active/default/route-rank metadata
without making retained revisions admissible.

This is a retained Core-owned legacy Pattern registry, not Extension contribution, Composition or
Suite publication, scheduler, editor, or durable Pattern store. The `bridge_chat` lineage and
`delegated_rite` lineage are the explicit pre-Portfolio exception: new application Patterns require a
Composition owner, while a Suite may publish only its coordination Pattern. State separately owns
v1 adapter, delegation, stasis, and Loom.

The opt-in `bridge_chat@3` revision is a read-only public-note answer profile within that retained
lineage. Admission pins the exact local chat capability and Archive profile, namespace, subject,
and policy revision before queue publication. Its score recalls once, resolves the exact retained
receipt for inference, and settles an attributed answer. It admits no model tools, consent Gate,
or settled-history replay. A restarted casting keeps its admitted bindings and receipt; changed
current authority or source eligibility refuses continuation. The receipt's identifiers and
digests may enter Graph state, while recalled bytes remain transient Context data. Revisions 1
and 2 keep their existing manifests and recovery contracts. State of Work separately records
whether the new revision's runtime and PostgreSQL acceptance have passed.

The separately opt-in `bridge_chat@5` semantic source-answer casting belongs to the same retained
Bridge lineage. Its immutable score is `RecallSemanticNotes` → `AnswerSemanticNotes` →
`SettleSemanticAnswer`, with a separate checkpoint schema. Typed `weaver.bridge.semantic` selects
explicit threshold and bounds; the existing independently enabled Archive semantic generation
supplies the manifest/reference. Boot composition requires PostgreSQL, the actual local Archive
caller mapping and an exact local chat capability, without readiness probing, startup derivation,
registration or inference. Admission pins all bindings before queue publication; restored state
must match the persisted Run and current source authority. The [Memory](27-memory.md#native-semantic-source-answer-consumer)
and [Context](21-context.md#explicit-archive-projection) owners govern retrieval and outbound data.
Existing revisions keep their identity, manifests and history contracts. Omission does not change
the ordinary conversation route. This boot selector does not supply a per-message mode switch;
Altar guidance describes the configured default independently of historical Runs and readiness.
State separately owns executable and native answer acceptance.

The opt-in `bridge_chat@4` revision answers one explicitly declared public page. Its
command is `/read-public <exact HTTPS URL>` followed by a newline and a nonblank question. The
authenticated operator separately declares the complete locator public under the current local
Scout classification policy; an ordinary message or model-produced URL cannot supply that
declaration. Admission retains the declaration, exact Scout profile and local chat capability.
This revision refuses other command forms rather than falling back to another Bridge revision.

Its score is `PreparePageReview` → `AwaitPageConsent` → `AcquireAndAnswerPage` →
`SettlePageAnswer`. Preparation atomically retains the acquisition request and complete native
review with its consent. The consent Gate parks without acquiring material. The acquisition station
resolves and verifies the exact local chat grant before claiming Scout's durable, bounded attempt;
hardware re-entry cannot repeat an issued acquisition. Fetch, extraction and inference share that
station. Scout rechecks current authority after awaited preparation and before each network handoff,
extraction and material consumption, including token counting. No remote model or model tool is
admitted by this profile.

State contains admitted identities, preparation/receipt references, dispositions and the ordinary
answer. Acquired bytes remain bounded attributed Context data, with influence and budget accounted
for; they cannot become instructions or authority. A receipt without its transient material cannot
authorize refetch after a park, retry or restart. Such a continuation reports material unavailable
unless the answer already reached its retained settlement checkpoint. An answer may quote source
text and is retained as ordinary Bridge history; transient acquisition is not a promise that no
derived text persists. The first profile follows no redirects. Revisions 1–3 retain their manifests
and recovery contracts. State of Work owns delivery and end-to-end qualification separately.

The explicitly configured `creation.investigate@2` belongs to the accepted
[Creation investigation](../compositions/creation/index.md) contract. Its fixed serial score
retains a source-bound candidate and fresh attributed verdict through the existing Run road.
Application records own stage claims, uncertainty, cancellation and separately admitted
continuation; the registry and Graph create no second scheduler or general SDLC owner.
Its local typed selector fixes the exact capability, while case custody additionally retains
resolved role bindings. State of Work owns delivered registration and end-to-end evidence.

The initial revision 1 prototype remains historical. Revision 2 is the sole selected closure;
current-role reads retain old cases, while retired-contract policy refuses their write actions.
Full profile matching gates admission, continuation and stages. Current-revision cancellation
uses retained contract identity and current local authority without requiring a live model binding.
No old Run, claim, response or reservation is reinterpreted or renewed.

## Pattern identity

The manifest binds:

- schema, URL-safe key and revision;
- reviewed implementation revision and checkpoint schema;
- the declared entry station;
- semantic stations, each with a unique key, a label, and a kind;
- permitted edges between declared endpoints; and
- a deterministic SHA-256 digest.

Executable stations map one-to-one with Python nodes. Construction rejects missing, duplicate,
unknown, or mismatched station mappings; unknown station kinds or edge relations; duplicate semantic
edges; Gate or delegate marker mismatches; dynamic `BaseNode` returns whose topology cannot be
proved; and any semantic transition set that differs from the public Graph node definitions.

The declared entry names the actual executable start node and participates in the digest. Exactly
one terminal is required. Gate loops remain explicit Graph edges; a delegate station additionally
declares its durable same-station re-entry edge. A Gate or delegate derives Durable Stasis.

The opaque implementation revision is a human-reviewed compatibility closure, not a hash of Python
bytes. Behavior that would invalidate parked state or replay must bump it or the Pattern revision.
The manifest fingerprints source-adjacent declaration rather than compiling all semantics.

Admission persists snapshot/digest; execution/resume requires exact current registered equality or
fails pinned Pattern unavailable. Multiple exact source-registered revisions may coexist: new
admission uses only an active revision while an older Run resolves its retained pinned revision
directly. Removing old executable code still makes that revision unavailable. Compatibility
is proved only by exact registered equality and the reviewed closure. Automatic source-code change
detection, durable publication, drain, and migration remain future work.

## Migration without rewritten history

Portable Spells and Scrolls arrive additively:

1. Freeze current Pattern schema v2 digests and persisted-Run fixtures.
2. Introduce Spell-contract, implementation, placement, and Resolution-Lock types without changing
   v2 snapshots.
3. Adapt each v2 station at assembly as a Scroll-private `legacy_inline` Spell identity; it is
   neither reusable nor portable.
4. Add separate receiving-owner-governed Spell-contract, implementation, and Scroll stores whose
   Contributions retain Registrant provenance and any separate concrete Provider reference, then
   build one immutable registry generation shared by admission, workers, Bridge, Loom, and Orb.
5. Introduce a new Scroll schema with exact Spell references and a Resolution Lock while dispatching
   v2 and the new schema through separate validators and resolvers.
6. Publish built-ins only as new revisions. Never rewrite `bridge_chat@1` or `delegated_rite@1`, and
   retain their executable closures until pinned Runs drain or settle honestly unavailable.

No compatibility shim may present a v2 Python node as a canonical public Spell merely because its
label resembles one.

### Private v2 adapter

The internal adapter for steps 2–3 gives every executable v2
station a deliberately private identity: derive a Scroll-private contract from `(pattern_id,
pattern_revision, manifest_digest, station_id, legacy_inline)`, place it under the station key and
kind, and bind it to the manifest's exact `implementation_revision`, `checkpoint_schema`, and Python
node fingerprint `module:qualname`. Contract, placement, and implementation identities must remain
separate and form a one-to-one set over executable stations. The declarative terminal maps to Graph
`End` and must not become a fictional Spell or implementation.

The boot-derived `legacy_inline` Resolution Lock must have a deterministic **internal-v0** digest.
It is not JCS portable identity, a signature input, a public Spell contract, or proof of Python
source equivalence. It must change when the exact local node binding changes without altering the
frozen v2 Pattern snapshot or digest. During this migration step, in-process exact revision lookup
must use the lock; the lock must not be stored on Run, exposed by Loom/Orb, or claimed as the future
persisted Resolution Lock. Persisting and projecting it begins only with a new schema and migration
under steps 4–5.

### Configuration-to-casting spine

The extensibility path is one directional assembly, not runtime reflection:

```text
typed local configuration selection of exact registered refs and bounded policy
→ explicitly selected shaped contribution stores
→ one immutable contract / implementation / Scroll registry generation
→ exact resolution and Resolution Lock
→ registered Scroll-version adapter and Graph binding
→ per-placement AgentSpec, Context contributions, and effect demands
→ Run admission pins executable truth before queue publication
```

TOML may later select authority-qualified ids, exact revisions/digests, activation, placement
policy, budgets, and registered Context projection profiles already admitted by the selected
Extensions. It remains a local typed selector, not the portable Scroll identity owned by canonical
JSON. It may not contain a Python module/class path, callable, Graph node or edge, arbitrary prompt,
raw source material, credential, live Connector/grant, or fallback implementation. Registering a
Rune schema, Spell contract, implementation, Scroll, adapter, AgentSpec, Context formatter, or
effect handler is a separate shaped contribution; none implies another and duplicate or unresolved
exact identity fails before activation.

The Graph binder consumes only an admitted Scroll-version adapter and its exact lock. It never
imports code named by configuration, scans packages for subclasses, or guesses an implementation
from a similar label. Placement-specific Agent and Context assembly occurs after resolution so a
Reader may receive an exact `structure` or `verbatim` projection without acquiring Writer tools,
while a Writer must separately satisfy its declared effect and authority contract. The current
source delivers the fixed v2 registry and a bounded `[weaver.bridge]` selector for `bridge_chat@2`,
public-note `bridge_chat@3`, public-page `bridge_chat@4`, or explicitly boot-selected semantic-source
`bridge_chat@5`. Revision 5 binds the independently enabled Archive semantic generation's exact
manifest/reference and embedding binding, an explicit cosine threshold and finite recall bounds,
and one exact local Soulstone Chat capability. Boot composition checks declaration metadata without
readiness probes, model work, generation registration or derivation; Run admission retains the
complete semantic binding before queue publication. Omitting configuration keeps revision 1 for
new admissions, and a changed selection cannot redirect older Runs.
Its exact capability key is server-admitted Run intent, copied into typed Graph state; a missing key refuses admission or checkpoint decoding,
and an unavailable target never falls back to another runtime. The worker binds the revision's
state validator to persisted Run intent; the Graph runner checks fresh and restored state before
node execution, including hardware re-entry. A differing key, Run/session identity, prompt, or
admitted priority refuses the checkpoint. Retried admissions first read
existing Run truth, so configuration changes cannot rewrite queued or parked work. Revision 1
applies the same admitted-state checks while keeping its eligible-pool behavior and manifest.
Private `legacy_inline` assembly now binds in-process exact lookup while preserving v2 snapshots.
Portable stores, Resolution Lock persistence, placement profiles, and dynamic registration remain
undelivered.

## Execution-road planning

Portal, A2A, and delegated coding are not interchangeable provider names. Spellweaver first closes
the labor boundary, then any cognition boundary inside it:

- a native Spell or Agent keeps decomposition in LychD and may use deterministic work, a local
  Soulstone, or one admitted Portal capability;
- an A2A placement delegates one public task schema to a sovereign peer, which owns its private
  decomposition and provider choice; and
- a delegated coding placement gives one foreign runtime a contained `read`, `candidate`, or
  `verify` workspace and tool loop. A child model call is a nested Portal boundary.

Each eligible placement pins `ExecutionRoadPolicy@1`: exact Pattern/Spell/placement revisions;
semantic input/output and non-completion; permitted labor and cognition roads with explicit branch
predicates; classification, lineage, Cut, consent, quarantine, and validators; effect demands;
deadlines and request/token/concurrency/spend ceilings; durability and idempotency; permitted
fallback edges; and result-adoption evidence. Economics and readiness may eliminate an eligible
branch, never make an ineligible one lawful.

Before road admission, Spellweaver creates immutable `ExecutionRoadDecision@1`; the Run ledger
stores it before any road-owned submission, and the later dispatch event, `ServiceJobAttempt`,
Intercom task, or `AgentJob` references its id. The decision binds Run, station attempt, parent
decision/retry generation, exact input/export digest, artifact-reference-set digest, opaque
custody refs, and canonical content-digest/media-type/size/classification evidence,
source-manifest and influence-label digests, safe residual-disclosure summary/digest, opaque
restricted lineage refs, purpose, policy and expiry, chosen road, budgets, expected
result/quarantine, record classification/visibility/retention, and the expected road binding. It
contains no caller-supplied full `ArtifactRef`, raw subject, filename, material-parent, source span,
reversal value, credential, or live grant/lease handle:

The complete decision is restricted, deployment-local, non-exportable evidence. Loom, logs, and
external receipts receive only an opaque decision id or Security-owned `EvidenceDigest@1`
projection; canonical raw digests never leave local decision/attempt custody and are not anonymous.

| Road | Exact authority retained by its owner |
| --- | --- |
| local capability | dispatch event records demand plus observed grant/lease identity only; asynchronous or effectful work transfers to `ServiceJobAttempt` |
| Portal | bounded immediate `ModelGrant`/`CallGrant` uses the decision, exact `EgressDecision`, lease, and dispatch/security events; Reach, asynchronous, paid, autonomously retriable, or post-submit-reconcilable work uses `ServiceJobAttempt` |
| A2A | enrolled peer, outbound peer-task/outbox identity, Durable Stasis, authenticated terminal adoption |
| delegated coding | `AgentJob`, runtime/profile, Coffin containment, workspace/artifact boundary, terminal adoption |

The decision records selection only; it never replaces those ledgers, observes a terminal, or
settles their truth. Durable road admission commits the decision and its road record atomically when
they share one Phylactery transaction; otherwise the decision commits first and the idempotent road
record adopts its id. A local
deterministic road-selection Spell may choose only among manifest-declared branches using pinned
policy and admitted observations. Dispatcher then binds an already eligible capability; it does
not rank price, privacy, peer trust, or coding runtimes. Orchestrator makes managed local substrate
ready; it does not change the road. Gateway `auto`, model-written routing, or a foreign runtime's
provider choice cannot substitute for this decision.

Cache reuse is an execution-road optimization, not Execution Projection, Agent memory, continuity,
authority, or recovery. After semantic input, road, and exact capability binding are pinned, a
future execution profile may carry an opaque cache-affinity preference only for connector reuse or
physical placement of that same admitted call. The preference carries no prompt, history, plain
prompt-derived digest, or authority and cannot select another model, road, or input policy. No
current Dispatcher or Orchestrator contract implements it; future declared support remains a
Dispatcher capability fact and local placement remains inside Orchestrator's physical boundary.

Provider cache eligibility, identity and lifetime scope, retention, and current tariff remain
dated [Portal Roads](../sepulcher/animator/portal-roads.md) selection-receipt facts; local prefix or
KV behavior remains an exact Soulstone engine/profile fact. A provider, model, or engine name alone
proves no cache fact. An exact launch flag or provider declaration is declared capability or
intent, not observed residency, hit, or savings; `prefix_digest` witnesses LychD content only, and
a projected discount is not a receipt. When available, provider-reported cached-token usage is
attributed billing evidence under [Oculus](29-observability.md) law, not proof of physical KV reuse.

Cache availability cannot be required for correctness, input sufficiency, budget admission, or
recovery. Before first submission—or after the road owner proves no prior effect—an ordinary cache
miss, eviction, or process restart executes the same admitted call without cache reuse on the same
pinned binding. The miss alone causes neither refusal, fallback, nor input-policy change. After
submission, existing reconciliation and idempotent-redelivery law governs; a changed target,
model, or runtime still requires the existing fresh road decision. Only a separately admitted
provider live-session road may require its exact session binding and opaque handle; its owner
defines loss and reconciliation. Tool and consent continuation retain their existing Graph and
HitL contracts and never become cache affinity.

A semantic retry, fallback, changed payload, target, peer, model, workspace projection, or
delegated child call creates a new road decision, then its road owner creates the appropriate
attempt/task/job and every required Cut/egress decision. Exact transport redelivery within one
admitted road-owned attempt instead preserves sealed bytes, target, external/idempotency identity,
road decision, and Cut/token namespace; the adapter must prove atomic same-key/same-payload
idempotent replay or no prior effect, road-specific retry/reconciliation law must permit it, and
each physical transmission receives a fresh EgressDecision and consumes its bounded disclosure
use. A submitted attempt is first reconciled under its existing identity; uncertainty cannot
activate an alternate branch by pretending the first effect did not happen. Every remote return
stays attributed and quarantined until the Composition owner validates and adopts it.

[Execution roads](../sepulcher/extensions/weaver/execution-roads.md) carries this law through the
operator-facing selection and failure journey.

## Admission and ownership

Spellweaver selects once from admitted Intent; Run ledger owns identity/status:

1. validate/select Pattern;
2. atomically create Run with exact manifest and its initial durable delivery;
3. retain caller initiating record while that delivery is held, then release it;
4. publish the exact job key; relay it later when the broker is unavailable.

The Run delivery outbox is transactional with Run truth, not with the external broker. Workers and
the relay publish, claim, and settle physical hops; Graph checkpoints; Spellweaver neither writes the
outbox directly nor operates containers. Spellweaver owns scheduling identity, eligibility, overlap,
and miss semantics; a separate clock/relay mechanism detects due work and publishes only the
ordinary delivery that Spellweaver has admitted. Spellweaver does not become that timer or broker.

## Gates, effects, and Stasis

| Boundary | Rule |
| --- | --- |
| Live Stasis | Resident process waits and resumes itself. |
| Durable Stasis | Declared Gate/delegate exits after checkpoint; re-admission mandatory. |
| Terminal | Run truth commits before checkpoint cleanup. |

Checkpoint is Graph state, never process image or retroactive replay safety. Effect station declares
idempotency, receipt, cancellation, compensation/refusal, and illegal-repeat boundary. Consent
appears only where HitL/effect policy demands; a verdict covers exact effect, not Pattern promotion
or downstream authority. Archive, Ward, Dispatcher, provider, execution retain policy even when
coordinated.

A protected remote score joins labels, selects a minimum disclosure projection, locally transforms,
may ask a local Privacy Agent, independently verifies transformation evidence, creates a consumer-
specific Privacy Cut, gets an exact tagged-target EgressDecision, transmits once, and quarantines
the return. Censor/Agent proposes only. Context owns the Cut; Security owns declassification.

### Execution projections for procedural Agent placements

For a declared long-horizon procedural region, a Composition may define a bounded, versioned
**Execution Projection**. The Composition owns its meaning; the exact Scroll revision pins its
schema and initialization, placement mappings, required unknown and omission fields, admitted
observation inputs, permitted candidate operations, applicator binding, history policy, and hard
field, cardinality, and byte limits. A changed meaning, schema, mapping, operation set, applicator,
or history policy is a new Scroll revision. The projection contains only working material required
by later placements. It is not the whole Graph continuation, an authoritative domain record, an
effect receipt, an audit trail, Archive memory, or conversation history.

The placement history policy selects exactly `transcript`, `projection`, or `hybrid`. `transcript`
means [Context](21-context.md)-governed bounded settled message groups. A hybrid pins the
deterministic selection profile and bounds for attributed history retained beside the projection;
the assembled call records the exact groups selected at runtime. It is not an undeclared fallback
to all settled history. Any required provider, tool, or consent continuation remains orthogonal
and indivisible; it does not turn `projection` into `hybrid`. Semantic sufficiency and continuity
select the pinned shape before cache, latency, or price. Cache availability cannot change it.

At an explicitly declared Agent placement, [Context](21-context.md) may assemble immutable
instructions, the recipient-specific current Execution Projection, the exact station request, and
fresh admitted observation projections without replaying settled reasoning, actions, or
observations into that model call. Every observation retains its source, revision or cursor,
freshness, classification, and lineage. The placement may omit settled history only when its
contract declares the projection sufficient for continuation; required material that does not fit
refuses before inference. Declared bounds make this input independent of prior-turn count, not
independent of the actual size of its projection and observation.

The Agent returns typed, bounded candidate operations and, when allowed, an action intent. It does
not replace the projection, extend its schema, or mutate workflow control, authority, privacy,
domain truth, or effect settlement. A deterministic workflow-owned applicator binds the candidate
to the exact current projection value and revision plus its admitted observations, validates the
permitted fields and invariants, and alone creates the next committed projection value and revision
for that Casting. An action intent remains inert until the owning effect boundary authorizes,
executes, and settles it; confirmed world-facing fields follow owner observations or receipts,
while indeterminate consequence remains `UNKNOWN`.

Canonical sources, full attributable artifacts, receipts, events, and any retained history remain
with their existing owners even when excluded from a later model call. Exact conversational
history and an in-progress provider/tool or consent continuation are not replaced by an Execution
Projection. When no fixed sufficient schema is known, earlier material may become relevant only
later, or the historical trajectory is itself the requested evidence, the Scroll must admit the
necessary attributed history or artifacts—or stop with an explicit unknown or non-completion.

[SKILL.state v2](https://arxiv.org/html/2608.26263v2) reports that its projection-only,
state-plus-latest-observation variant can preserve or improve benchmark performance while
materially reducing repeated transcript tokens in long sequential single-agent tasks, including
budget-matched controls. That evidence motivates the accepted shape; it does not establish LychD
delivery, universal model performance, shared mutable multi-Agent state, concurrent merge law,
privacy, effect safety, checkpoint recovery, or LychD-specific token savings, cache-aware billing
savings, cache-hit rates, time-to-first-token improvements, or latency gains. The current Pattern
v2 manifests and built-in workflows do not deliver Execution Projections.

## Parallelism and delegation

Built-ins are serial BaseNode. Parallel map/fork/join/reduce needs branch identity, declared
reduction, bounded concurrency, cancellation, Gate behavior, completed-effect receipts, and
crash-recovery on both join sides. A bounded durability adapter cannot replace ledger, Ward,
Dispatcher, Orchestrator, HitL, or revision. Delegated station declares request/result,
containment, budget, timeout, cancellation, artifact boundary, downstream use; provider adapter
invokes foreign runtime, never embedded CLI/credential/private graph.

### Scoped context handoff

A handoff begins a fresh, recipient-specific Context for the receiving Agent placement. The
parent's conversation, loaded documents, tool outputs, and sibling work do not enter implicitly.
Loading a scope into an existing conversation can narrow its task, but cannot remove material
already present; a handoff therefore needs a new assembly boundary. The parent keeps the wider
purpose, dependencies, shared budget, ordering, and responsibility for assessing the return
against the owning acceptance contract.

The exact Scroll pins the handoff's input and return contracts. The parent supplies the smallest
sufficient packet: task and role, acceptance target, relevant operator decisions and constraints,
allowed inputs and effects, exact source/artifact revisions, dependencies and unresolved unknowns,
and the applicable scope routes. A scope routes the recipient to canonical owners and the smallest
useful evidence slice; it is neither a replacement for those owners nor the task specification.
The recipient may load further material within the admitted boundary. A missing prerequisite
requires a bounded request or explicit non-completion, never an automatic copy of the parent's
entire context.

Spellweaver declares the handoff and its continuity requirements;
[Context](21-context.md) owns assembly, ordering, attribution, and budgeting. Applicable governing
instructions and authority constraints survive the handoff. Required provider/tool or consent
continuation remains indivisible; work that requires it must use its declared continuation path.
When historical material is itself necessary evidence, the contract selects bounded, attributed
history or artifacts explicitly. Excluding material from a child call never deletes the parent's
history or canonical records, and prompt isolation alone proves no tool or workspace containment.

The return contains the candidate result or artifact references, observed verification evidence,
and remaining unknowns or blockers. The parent admits the useful return under the existing
acceptance and effect boundaries; no complete child transcript is implicitly appended to its
Context. Independent review receives its own sufficient packet.
[Delegation evidence](../state-of-the-work.md#delegated-agent-execution) records the runtime
boundaries established by the reference adapter.

### Bounded Inquiry in an engineering workflow

**Inquiry** is a reusable design form in the
[Creation workflow](../sepulcher/extensions/weaver/creation.md): bounded Explore is followed by
independent coverage and sufficiency judgment, then Crucible for material alternatives. It can
examine both direction and later implementation boundaries. This method is neither a registered
global Pattern nor evidence of delivered subgraph composition.

The owning score declares the question, required evidence, omissions, judge independence, probe
budget, stopping conditions, and typed return. Sufficiency means enough evidence for the declared
decision, never exhaustive knowledge. A judge may request a bounded source probe or return
non-decision; another judge is not an unlimited escape from missing evidence. Factual disagreement
calls for an admitted discriminating test where one can settle it. The receiving owner retains
acceptance and residual-risk judgment under its law.

Human decision assistance presents a concrete unresolved choice and its consequences. Inquiry
does not add blanket approval requirements to already admitted work; exact live-only and Protected
Region rules remain with [HitL](25-hitl.md). Evaluation of a changed procedure produces evidence
for a new immutable revision and later Invocation, never mutation of a pinned Run.

### Crucible choreography

[Crucible](../sepulcher/extensions/weaver/crucible.md) is the canonical adversarial choreography
for forming a decision candidate: frame one question and common evidence; run separately biased
first-round Postures; join their strongest claims, citations, concessions, defeat conditions, and
unknowns; return that attributed projection for a second-round rebuttal; synthesize without a
vote; then stop at an exact Magus Gate or inert dossier boundary. Logical independence is required;
physical concurrency is optional. A serial implementation must preserve the same isolation and
must not leak an earlier advocate's output into another first-round Context.

Bias is declared input, never authority or a substitute for evidence. Compression between rounds
retains source references, every advocate's nominated strongest claims, concessions, dissent,
unknowns, and omissions; the full reports remain attributable artifacts. Missing evidence may
produce `UNKNOWN`, a bounded evidence request, or honest non-decision. Majority, confidence,
eloquence, model identity, or survival through summarization cannot adopt the result.

Crucible is a reusable score form, not an ownerless global Pattern. A Composition that uses it must
publish its exact Pattern and dossier contract and apply ordinary revision, road, budget, and
authority law. When the receiving decision belongs to another office, that office retains judgment
and the Composition only coordinates the dossier. The choreography neither evaluates a capability
in Drift's place, materializes Shadow branches, nor promotes its own recommendation. A downstream
mutation or Covenant edit begins only through its target owner's workflow and applicable
authority. Where its law requires an exact human verdict, the dossier cannot substitute for that
verdict; where standing policy is eligible, Crucible does not introduce a second universal live
Gate. Protected Regions remain live-only.

## Pattern contribution

A publishable Scroll revision declares:

- identity, revision, owner, provenance, support, and parentage;
- every required Spell contract and placement;
- typed inputs, outputs, state, errors, and non-completion;
- topology and cancellation;
- capabilities, tools, planes, budgets, and waits;
- Sigil, effect, privacy, egress, and consent requirements, with secret-free durable state;
- checkpoint, idempotency, receipt, compatibility, migration, drain, and refusal contracts;
- Loom metadata; and
- serialization, failure, and recovery evidence.

Assembly uses an explicitly selected shaped store, never package scanning. It rejects duplicate
identities, ambiguous routes, unknown adapters, unreachable stations, unsafe cycles, unserializable
state, missing continuity, and forbidden effects before freezing the generation.

The workflow dataclass is internal and pre-v1, not an ABI. Creation, Assimilation, and Extension law
govern candidate publication. Source, model output, and Loom drafts require validation, review,
evidence, and an immutable revision before publication.

Spell-contract publication, executable implementation registration, Scroll publication, and
activation are separate acts and shaped stores. Deactivation of an implementation closes dependent
Scrolls to new admission; already pinned Runs may use an explicitly retained closure, while security
revocation forbids even retained execution. Installing code or replacing a process-built catalogue
is [Evolution](18-evolution.md). Reanimation reconstructs the same body from committed records
after process death; restoring a whole-body cut additionally follows the
[Snapshot Protocol](07-snapshots.md). A future declarative-only Scroll may activate without Vessel replacement only when all
implementations are already admitted and an atomic durable catalogue-generation mechanism exists.

## Authorship provenance and protected regions

Authorship records who wrote material; approval records who accepted it. A human can approve
model-written text without becoming its author, just as an Agent can commit through a
human-configured VCS identity. Git author, committer, account name, prose style, detector score,
and missing model metadata can serve as evidence at most. None may mint human provenance.

An **Authorship Attestation** binds one artifact revision and stable region id to its canonical
content digest, locator, origin class, attesting Principal, and evidence references:

| Origin | Meaning |
| --- | --- |
| `human_attested` | An authorized human Principal explicitly claims authorship of the exact bound content. Approval alone is insufficient. |
| `agent_generated` | Host-observed Agent or model lineage produced the bound content. |
| `mixed` | Human and Agent contribution are materially interleaved and cannot be separated honestly. |
| `unknown` | No admissible record establishes authorship. |

The attestation is an attributable claim, not proof of private cognition. A trusted local or
authenticated human surface may create `human_attested`; an Agent, provider assertion, imported
commit, or style classifier may not. Agent outputs receive `agent_generated` from the host job and
artifact lineage even when a human later approves them. Approval changes authority to promote, not
the history of who composed the bytes.

Attestations append; they do not overwrite inconvenient lineage. Contradictory or inseparable
human and Agent evidence resolves to `mixed`, while insufficient evidence remains `unknown`. A
trusted human surface may attest a new human-written replacement only when it binds that editing
boundary and exact result. Copying unchanged Agent output through the human surface cannot launder
its origin.

A **Protected Region** binds a stable region id, target artifact revision, canonical content digest,
locator, and `live_change_only` policy. Accepting a human authorship attestation protects that region
by default; an authorized human may also protect material of another or unknown origin. Line numbers
are only a projection. Document block ids, syntax-aware symbols, structured field paths, or
media-specific selectors locate the region, while the digest detects changes. Moving, deleting,
splitting, reformatting, changing its marker, or changing the protection record itself counts as a
touch.

Source comments, front matter, editor decoration, and VCS notes may display the mark but are not its
authority. The target owner retains the base-revision attestation and protection manifest outside
the candidate's control. An Agent cannot unprotect text by deleting its visible marker.

For a candidate that may replace an artifact, Spellweaver orders one admission path:

1. bind the exact base revision, candidate digest, and target-owner diff;
2. resolve touched regions against the base-revision protection manifest;
3. continue normally when none overlap, or enter Durable Stasis for one live HitL verdict naming
   every affected region, old and replacement digests, and an authorized exact-diff artifact;
4. after approval, revalidate base, candidate, region set, and effect identity before the target
   owner writes a successor artifact and manifest.

Protected-region change never accepts Codex preauthorization, a previous verdict, a broad “edit
this repository” grant, or approval of a different patch. A change to the base or candidate creates a new
call. Denial preserves the candidate as inert evidence; it does not mutate the active artifact.
An Agent may prepare a suggested replacement in Lab, but cannot apply it to the protected body.

An approved Agent edit remains `agent_generated` when it wholly replaces a region and `mixed` when
it interleaves with retained human material. Unchanged human-attested content retains its
provenance across an approved move. A human may later rewrite and freshly attest the exact result;
the approval itself never performs that relabelling.

For legacy material, history and stylometry may nominate likely regions for review. They remain
`unknown` until a human explicitly attests the exact current digest. Spellweaver owns the Gate and
ordering; the artifact/effect owner owns region resolution and mutation; [SDLC](16-sdlc.md)
owns candidate isolation and target-owner promotion; [HitL](25-hitl.md) owns the live verdict.
No Authorship Attestation store, protected-region manifest, trusted authoring surface, overlap
resolver, or candidate-bound review card is delivered. [State of
Work](../state-of-the-work.md#smith-forge-promotion) owns that boundary.

## Compositions, Products, Suites, and schedules

### Concerns and application design

[Atlas](15-frontend.md#independent-concerns-decomposition-and-addressing) maps independent
Concerns, their decomposition, and where they are addressed. An idea or application can take shape
through that account without first becoming a Project or native Composition. Its own Covenants
can record its adopted decisions. Work outside LychD may use LychD's Covenants as one optional
source of inspiration.

When the design concerns a native Composition, the map explains why its parts exist and exposes
unresolved needs. The Composition still owns its accepted reusable records, judgment, effects,
policies, projections, and Pattern catalogue. Addressing links do not publish or revise those
contracts. Concern decomposition also creates no Scroll transitions or Suite coordination; those
remain separately declared and admitted under their execution owners.

### Composition identity, revision, and retirement

A Composition keeps one stable URL-safe identity across immutable numbered revisions. Each
revision pins its reusable application contract: owned record and request/result families,
Pattern catalogue, judgment and policy boundaries, effect and authority seams, projections,
terminal outcomes, and recovery law. Pattern and Scroll have their own revision identities.
Changing a Scroll cannot silently revise the Composition that selected its catalogue contract.

Publication freezes a Composition revision independently of its implementation. A material
change to any pinned part creates a new revision under the same stable identity. A change that
creates a materially different reusable application capability, transfers its defining durable
records or judgment, or replaces its authority, finish, or recovery boundary requires a new
Composition identity rather than stretching the old one. Editorial clarification that preserves
the complete contract may update its current explanation without claiming another revision.

Retirement never reinterprets an old identity or revision. The owning Composition record names the
retired revision, successor or absence of one, reason, compatibility boundary, and any required
migration or explicit lack of executable migration. If no registry, Run, or stored application
record ever used a revision, there may be no runtime migration to perform; its historical
meaning and retirement still remain explicit. [State of Work](../state-of-the-work.md) separately
records whether any revision is registered, executable, persisted, or supported.

Portfolio membership marks an accepted **Native Reference Composition**: a first-party maintained
application contract and worked example. It does not prove executable delivery;
[State of Work](../state-of-the-work.md) keeps the shared whole-system envelope, while a
Composition mentions local delivery only when it materially changes how the contract is read.

Portfolio acceptance is deliberately rare but not numerically capped. It requires durable reusable
application truth with its own records, judgment, terminal outcomes, and recovery boundary; reuse
of a mechanism or provider is insufficient. Two independently motivated Products or use cases are
strong corroborating evidence, neither a necessary threshold nor proof by themselves. Portfolio
acceptance remains distinct from runtime registration and from delivery.

<span id="areas-for-discovery"></span>An **Area** is a non-exclusive thematic grouping for
discovering Compositions. Areas name the Portfolio's editorial reader views; their directories
and indexes provide documentation routes. They have no runtime identity, revision, domain
records, authority, application namespace, code-layout consequence, dependency meaning, delivery
state, or runtime/Product selection role. A Composition may be discoverable through several
Areas while retaining one canonical route and its own contract. Renaming an Area or changing
its membership does not revise those contracts. Guides organize explanations; Candidate studies
organize proposals by acceptance status. Neither is a thematic Area.

Suites may coordinate live Composition-owned Invocations within one Area or across several Areas.
Sharing or crossing an Area boundary alone creates no Suite requirement; the live-coordination
contract below determines that need.

A **Product** gives a profession or market one named operator door. It pins eligible Composition
or Suite revisions, owner-qualified profiles, projections, supported use cases, defaults, and its
customer and support envelope. A Product may use one Composition or coordinate several through a
Suite; it does not become another workflow executor, merge member ownership, or convert packaging
into authority. Deployment instantiates either a Product revision or an exact Composition-owned
reference deployment profile under one operator's configuration. A Productless reference
deployment creates no market promise or Product identity; changing a Product-backed deployment's
host, customer, or credentials likewise does not create a new Product identity.

A **Product Revision** is one immutable version of that selection and promise. Changing an exact
Composition or Suite pin, owner-qualified profile, projection, supported use case, default, or
customer/support policy within the same stable operator promise creates a new Product Revision.
A materially different profession, market, or operator promise requires a new Product identity.
Neither a new Deployment nor presentation-only public copy changes the Product Revision.

A Native Reference Composition may publish an exact reference deployment profile without becoming
a Product. Such a profile binds that Composition's implementation and acceptance target. Once
Configuration selects a delivered registered revision and Containers admits its complete manifest,
the resulting configured installation is a Deployment; it still creates no Product, supported-use-
case catalogue, customer promise, or service before those gates.

A Product or use-case study may expose an unresolved application-ownership need. Until that need
resolves to an exact external authority or an accepted Composition revision, the Product must not
claim the affected use case as supported and no Invocation depending on that missing truth may be
admitted as a supported Product path. Product packaging never acquires the missing records,
judgment, policy, consent, secrets, or effect authority in the meantime.

An already-settled exact record, artifact, receipt, capability snapshot, Product co-packaging, or
exact external precondition whose lifecycle the consumer cannot manage does not by itself create a
Suite. A foreign reference grants no installation, availability, lifecycle, upgrade, credential,
admission, or effect authority. Suite is required when one result must initiate or admit, await,
retry, cancel, recover, correlate, or settle multiple Composition-owned Invocations. It pins member
and Pattern revisions, typed ArtifactRef/Intent handoffs, correlation, ceilings, dependencies, and
partial-completion law while never merging ownership, secrets, Sigils, HitL, or domain judgment.
A Suite has its own technical identity, authority-qualified publisher, and revision as soon as
that reusable live-coordination contract is published. Each Suite revision pins one exact
Suite-owned coordination Pattern revision—an immutable Scroll whose only application truth is
member identity, typed handoff, correlation, ceilings, cancellation/recovery, and aggregate
settlement. Its Casting opens a parent Suite Invocation and Run; every initiated member remains a
separate Composition Invocation and Run with its own owner and judgment. A direct Intent may
therefore resolve the Suite revision and its pinned Scroll without a Product, while a Product may
pin the same eligible Suite revision. Neither route grants the publisher or parent Run any member
authority.

Suite execution requires authority-qualified Suite publication, the Suite-to-Pattern pin,
parent and child identity/revision/closure, fan-out/join, budgets, cancel, Stasis, retry, effects,
compensation, and partial-settlement law before admission of any Suite Casting.

A Schedule makes one durable, deduplicated **Occurrence** for each firing and enters ordinary
admission. Spellweaver owns calendar/event meaning, service class, temporal eligibility,
priority/overlap/coalescing/revision, and the decision to admit or settle a missed firing. Workers
deliver and retry exact admitted hops; Dispatcher resolves capability; Orchestrator owns readiness.
A timer never calls a Graph node, model, Animator, or container.

Three semantic service classes govern admission; they are not broker queues:

| Service class | Contract |
| --- | --- |
| `foreground` | Eligible now and latency-sensitive. It receives preference, not a promise of immediate start or unsafe preemption. |
| `deadline_windowed` | Initial Invocation admission is no earlier than `not_before` and strictly before `latest_start_at`, with optional `finish_by`. An unadmitted firing at or beyond the latest-start bound settles explicitly without an Invocation. |
| `spare_capacity` | No completion-time promise. Scarce-resource work requires a proved bounded yield/containment contract or an operator-approved quiet window. |

Class is orthogonal to doctrine priority and physical queue. Continuous foreground demand must not
silently starve a declared deadline; approaching deadline feasibility may outrank ordinary latency
preference under the pinned policy. `spare_capacity` defaults to already-WARM/NO_OP-compatible
capability and may not trigger a disruptive hard swap merely to keep iron busy.

Cron is one trigger grammar, not a service class. A calendar Schedule pins its revision, Pattern
revision, IANA time zone, ambiguous/nonexistent civil-time policy, overlap and misfire policy,
bounded catch-up, budgets, and authority owner. Jitter changes eligibility, never Occurrence
identity. An overlap remains live while its prior Invocation is nonterminal, including Stasis;
coalescing requires a Pattern-owned typed merge and preserves every member Occurrence.

### Temporal admission and settlement (Designed)

These rules govern the designed Schedule and Occurrence contract. They add no executable
scheduler, store, Run status, event, or callable interface.

A firing has one recoverable identity within an authority-qualified stable Schedule. A calendar
source identifies its nominal firing and selected fold member when applicable; an external
trigger requires a source-qualified durable event identity. Input equality, delivery identity,
jitter, worker attempt, and arrival time do not identify a firing. A trigger without a recoverable
source-firing identity cannot claim durable deduplication. This is an identity requirement, not a
public identifier encoding.

Each source firing is assigned to one exact Schedule revision once. Assignment and revision
activation share serialized decision authority. Rediscovery first recovers the assignment by
stable Schedule and source firing, across all retained revisions; it never looks only under the
currently active revision. The assigned revision, immutable source content, Pattern and policy
revisions, calendar interpretation, resolved absolute bounds, and selected jitter remain with the
Occurrence. A replay returns that Occurrence and any admitted Invocation even after the original
Run is terminal. Changed immutable source content fails closed; a newly active policy revision
alone does not make an unchanged source replay conflicting content.

For a previously unassigned external event, the revision active at its first committed assignment
owns the firing. Activation and assignment cannot race to assign it twice. For calendar firings,
activation instead pins a disjoint, recoverable partition of the source firings between retained
revisions. This partition covers unresolved old firings as well as the cutover and new firings;
late discovery uses that partition, not the revision active when a relay happens to run. Existing
assignments cannot be changed by activation. A change of time zone, cadence, or fold policy must
pin which nominal candidates under the two calendar interpretations denote the same source
firing, which are distinct, and which are explicitly skipped under their assigned revision.
Civil timestamps in different zones are not a shared ordering. Activation is refused if the
partition is missing, ambiguous, or would reassign an existing firing. Two relays encountering
the same cutover firing must therefore recover one assigned revision and one Occurrence. These
requirements refine Schedule revision law; they introduce no separate registry or service.

Calendar revisions retain the exact zone-rule interpretation needed to reproduce unresolved
firings. Installing different zone rules requires another revision rather than silently
reinterpreting an existing one. Materialization retains resolved bounds and selected jitter;
redelivery and restart cannot resample or revise them. The default calendar policy selects the
earlier instant in a fold and explicitly skips a nonexistent civil firing without shifting it.
Recovery considers at most the newest still-eligible missed calendar firing for admission; older
unadmitted backlog is explicitly skipped. Eligibility follows the firing's service class and no
expired window is enlarged. Different fold, gap, or bounded catch-up policies must be pinned in
the Schedule revision.

Temporal decisions compare absolute UTC. Take a fresh trusted clock sample at the serialized
conditional transition, after acquiring its decision authority; retain that sample as
`decision_time` only if the exact atomic transaction commits. Transaction opening time, caller or
delivery timestamps, and acknowledgement time cannot substitute. A lost acknowledgement requires
observation of the exact durable decision; rollback leaves no accepted decision. This measures
the accepted decision, not the later physical visibility or acknowledgement of the commit. A
process may derive a fresh monotonic waiting budget from the retained absolute bounds but cannot
persist that process-local reading as recovery authority. Restart and clock correction require
another absolute check before an undecided transition; they never reopen a committed admission,
skip, expiry, or terminal settlement.

The `not_before`, `latest_start_at`, and optional `finish_by` predicates below apply only to
`deadline_windowed`. Foreground and spare-capacity firings retain their own eligibility contracts;
they require no invented cutoff or sentinel bound. Identity, revision assignment, deduplication,
recovery, authority, and overlap rules apply to every service class.

| Deadline-windowed boundary | Required transition |
| --- | --- |
| Initial admission | Admit only when `not_before <= decision_time < latest_start_at`, and strictly before any `finish_by`. The same atomic decision binds the Occurrence to one Invocation and its initial Run delivery. Before commit there is no admitted Invocation; afterwards publication and recovery preserve that exact admission. |
| Unadmitted expiry | At or after `latest_start_at`, or an earlier `finish_by`, settle the firing explicitly as missed without creating an Invocation. Before `not_before`, retain it outside a sleeping worker while neither upper bound has expired. This strict rule retires the previously Designed admitted-late option for this class; no pinned miss policy can authorize it. |
| Consent or delegate resume | Initial admission satisfies `latest_start_at` once; a later worker claim or first effect need not precede it. Resume preserves the exact persisted wait owner and pinned Pattern, and requires current authority and ordinary Workers, Graph, and HitL checks. An approval creates no new firing and renews no bound. |
| Finish acceptance | The requested finish is timely only when its pinned semantic evidence is accepted by the authoritative terminal Run decision at `decision_time < finish_by`. The required proof must already be valid when that decision samples time; the transaction retains the exact proof and temporal disposition together. An intermediate artifact, generic `DONE`, event, or projection cannot substitute for that proof. |
| Admitted finish expiry | At or after `finish_by`, absent a timely accepted finish, close forward-effect admission and record the unmet deadline. Every new forward-effect admission must check that bound; safety cannot depend on an expiry callback running on time. A committed expiry prevents later acceptance of a timely finish. Expiry alone establishes neither terminal Run truth nor proof that an effect stopped. |

The requested finish remains domain- and Scroll-owned. If it requires delivered speech, committed
text alone cannot satisfy it: speech or an explicitly admitted text-only fallback must be proved.
A separately settled destination result does not finish a Companion presentation or a Suite round
trip. Display is observational only when presentation is not itself the admitted result.

After finish expiry, preserve every already-started effect's identity, actual result, and
settlement obligations under its original safety budgets. Use the existing owning cancellation,
containment, and reconciliation contracts. A late result can resolve those obligations but cannot
retroactively satisfy `finish_by`, reopen a terminal job, or authorize replacement submission.
Unknown effects remain unresolved; required unresolved containment keeps the Run nonterminal under
[Workers](14-workers.md#terminal-settlement). These are temporal dispositions, not new Run statuses.
Without `finish_by`, `latest_start_at` supplies no completion-time promise.

The default overlap policy skips a new firing while any earlier Invocation of the same stable
Schedule is nonterminal, across all Schedule revisions. Consent, delegated work, cancellation,
and required unresolved containment keep that overlap live. Neither a released worker nor a
finish accepted only in memory releases it. A different overlap policy must be pinned; coalescing
still requires the Pattern-owned typed merge and preserves every member Occurrence.

Schedule timing does not change [Orchestrator](23-orchestrator.md) activation-cutoff law. Timely
actuator/adapter invocation or honest readiness confirmation retires that local admission cutoff;
subsequent settlement keeps its original safety budgets. An expired coalesced follower ends only
its own wait. Local coalescing and that process-local cutoff establish neither Occurrence identity
nor workflow settlement.

Canonical **Occurrence** means the schedule or external-trigger firing before Invocation admission.
The delivered Graph runtime's `occurrence_id` field is a legacy name for a station-attempt
correlation; it is not this durable trigger identity. No Occurrence store, timer, eligibility
engine, service-class persistence, safe preemption, or periodic workflow scheduler exists.

## Returning findings

Drift returns `CompositionSuiteFindingSet@1`, `AttributionCandidate@1`, `InvalidationSet@1`, and
`CorrectionRequest@1` as evidence. A Correction Request enters Spellweaver only as a new forward
Invocation under validation, budget, authority, and consent. It cannot create reverse edges,
resume an arbitrary old station, mutate an artifact, inherit consumer authority, or turn
recurrence into training. Repair begins at the smallest supported cut. Reuse needs full
input/evaluation closure, while unresolved attribution or exhausted budget ends the attempt honestly.

## Loom projection and drafting

[Loom](../divination/altar/loom.md) reads the fixed immutable Pattern manifest: semantic stations,
edges, Gate/delegate, revision, implementation revision, checkpoint schema, and digest.
Mermaid/canvas are views. Charcoal remains inert until a canonical declarative Pattern has typed
ports/state/effects/authority/termination/continuity. Drawn grouping does not nest a Pattern or
execute a Suite. Publication alone makes a new immutable revision; Invocations stay pinned. Model
prose, browser gesture, and renderer state are not authority.

## Rejected alternatives

### Unversioned procedural chains

Functions suit a bounded station, not long-lived identity with parking, projection, contribution, or revision continuity.

### A second application scheduler

It fragments admission, priority, recovery, and inspection; applications contribute to Spellweaver.

### Visual source as executable law

Renderer state cannot state all type, authority, effect, and recovery invariants; Loom projects and may draft candidates.

### Git identity or an AI detector as authorship proof

Commit identity can be borrowed by an Agent, and style classification is probabilistic. Both may
nominate legacy material for review; neither can create a human authorship attestation.

### A prompt warning or source comment as protection

An effectful Agent can ignore the prompt or delete the marker. Protection is enforced by
target-owner comparison with the base manifest and an exact live Gate, outside candidate control.

## Consequences

!!! success "Accepted"
    - Exact Pattern identity, waits, contributions, Suites, schedules, and Loom share one future admission law.
    - Ownership stays split and immutable revision prevents substitution.
    - Human authorship remains distinct from human approval, and protected material cannot be
      promoted through an Agent edit without one exact live verdict.

!!! failure "Cost"
    - Automatic compatibility proof, durable Pattern publication, scheduling, parallel durability, and editing are separate programs.
    - Construction proves declared Graph topology only; effect, recovery, and compatibility semantics still need their own evidence.
    - Trusted human identity, stable media-specific selectors, retained manifests, and exact diff
      review add storage, UI, and recovery work.

## Acceptance evidence

Registry, route-once, manifest, serialization, Loom, admission, claim, consent, delegation, and
recovery tests prove the floor. Each future surface needs focused ambiguity, compatibility, failure,
cancellation, replay, and projection evidence before State promotion.

The portable profile additionally requires golden and negative fixtures consumed by two independent
implementations: canonical bytes/digests; duplicate and unknown fields; numeric and ordering edge
cases; namespace collision; exact contract resolution; repeated Spell placement; missing,
unauthorized, unavailable, retained, and revoked implementations; v2 coexistence; and refusal of
similar-name, version-range, or newer-revision substitution.

The authorship-protection profile additionally requires fixtures for every origin class;
conflicting and inherited lineage; unchanged moves, splits, marker deletion, and manifest changes;
base and candidate races; live-only refusal of preauthorization; exact affected-region review; and
proof that approving Agent output never relabels it `human_attested`.

The execution-road profile additionally requires complete local/Portal/A2A/delegated matrices;
manifest-undeclared and model-selected road refusal; consumer-specific Cut and target binding;
nested coding-agent child egress; capability/peer/runtime unavailability; pre- and post-submit
failure at every edge; new-attempt fallback; indeterminate reconciliation; quarantine/adoption; and
proof that a decision commits before admission, contains no live handle, is referenced by the
road-owned record/event, and never settles that ledger.

---
title: "29. Observability"
plain_name: "Design rule 29: Observability"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/29-observability/
guide: https://lychd.snayu.ai/docs/adr/29-observability/
---

# 29. Observability (Design rule 29: Observability)

## Plain-English summary (Snayu)

**What it is:** Defines how logs, events and traces make execution understandable without becoming authority. Every record states who produced it, about what and how it was captured; the office doing an effect keeps the authoritative record.

**Why it matters:** Read this before adding logging, events, metrics, tracing or Run Inspector views.

- Logs and events are evidence, never authority; missing or stale data must stay visible.
- Content is allowlisted and secrets are prohibited in all evidence.
- External tools like Phoenix get one-way redacted exports and gain no LychD authority.

**Status:** Partial. Logs, run events and Orb work; traces, metrics and native Oculus are not built.

## Original text (Hexanomicon)

A Run can finish while an observer misses an event. A provider can report success while the
owning ledger still has an unresolved effect. Observability must let a reader distinguish those
situations without making a log, timestamp, or convincing picture authoritative.

## Requirements

Every record identifies its producer, subject, identity, ordering domain, and capture class.
Missing material, stale observations, and uncertain outcomes remain visible. Content is
allowlisted and secrets are prohibited. The office performing an effect keeps its authoritative
record; observations and rebuildable projections retain their own purpose and retention.

The first Orb query is a bounded, authorized view of one Run. An external viewer receives only
redacted exports and gains no LychD authority.

## Considered Options

| Option | Result |
| --- | --- |
| Require an external metrics and tracing stack | Rejected: deployment and retention would precede a clear account of evidence ownership. |
| Put every signal and body in generic JSONB | Rejected: authoritative records, diagnostics, privacy, and schema boundaries would become indistinguishable. |
| Keep a native evidence contract and optional external Eyes | Selected: tools may change while LychD retains its own record meanings. |

## Decision Outcome

[Oculus](../sepulcher/extensions/oculus.md) is the designed native evidence Domain. Its Altar
instrument is **Orb**, and using that instrument is **scrying**. An external **[Eye](../lexicon/iron-tongue.md#e)**
may be Phoenix, Logfire, an OpenTelemetry collector, or another viewer. Each supplies a way to
inspect evidence without becoming a second source of truth.

Structured logging and the bounded Orb have current repository evidence. Native Oculus has no
ingestion or telemetry adapter, trace/metric store, retention, health query, cross-process bus,
resource telemetry, or multi-Run query. The optional Phoenix contribution supplies a service;
application trace export remains unproved. [State of Work](../state-of-the-work.md#altar-and-observability)
owns those delivery boundaries.

### 1. Evidence Ownership and Correlation

| Evidence class | What the reader can establish |
| --- | --- |
| Authoritative record | The responsible office committed this transition or effect state. |
| Bounded observation | This producer observed this subject by a named method, at stated times, with explicit freshness and limits. |
| Derivation | A named algorithm used these parents; uncertainty and invalidation remain attributable. |
| Interpretation or verdict | An evaluator applied declared criteria, as in Drift. |

RunLedger owns Run status. Consent, grants, jobs, host transitions, artifacts, and evaluations each
keep their own records. Step and RunEvent observations may describe that truth but cannot
supersede it.

A RunEvent names `run_id`, UUID `event_id`, monotonic per-Run `seq`, and producer timestamp `ts`.
The live channel emits a contiguous process-local sequence and one terminal event. Non-token
events tee to the Step ledger in order, but append is best-effort and may leave gaps; PostgreSQL
enforces `(run_id, seq)` where that store is used. Token deltas never become Step evidence.

Sequence orders one producer. Timestamps do not establish a global order, and a shared identifier
proves correlation rather than causality or completeness. Cross-office relations name the exact
Pattern revision, trigger Occurrence, station attempt, grant, job, or transition. A trigger
Occurrence and a station attempt remain distinct identities; ADR 28 owns their relationship.
Trace context never authenticates a caller or authorizes an effect.

### 2. Native Service and External Eyes

| Signal | Current shape | Authority |
| --- | --- | --- |
| Run events | Process-local channel, 256-event replay, best-effort non-token Step tee | Observation |
| Logs | Structlog/stdlib human or JSON stderr | Diagnostic |
| Traces | No producer or export adapter | No native ingestion, export, retention, or read contract |
| Metrics | No producer, registry, store, or query | Designed |
| Orb | Bounded Run catalogue, graph lenses, and retained-evidence feeds | Read-only |

Future Oculus exposes typed query and event ports; clients do not inspect its tables directly.
An Eye receives a one-way allowlisted export, with no canonical read-back. The legacy Phoenix
service spelling `oculus` is a compatibility name and cannot make that service native Oculus.

### 3. Interior Evidence Without Mind Reading

Interior evidence needs an attributed source and a declared kind. Progress text is first-person
testimony, a tool/provider span is an operated observation, and a scored explanation is a
versioned interpretation. These remain separate sources; none exposes hidden chain-of-thought.

Prompts and completions, retrieved Context, tool bodies, provider exchanges, media, credentials,
and identity data remain absent unless the applicable policy admits them. A useful structural
view must remain possible without that content. It must also be able to say that the evidence
needed for a stronger conclusion was not captured.

### 4. Delegated-Agent Evidence

For delegated work, observation stops at the admitted adapter. LychD records admission, policy,
settlement, artifacts, and adoption. Usage and protocol messages reported by the provider stay
attributed to that provider. Neither source reveals the foreign planner, subagent tree, or
private reasoning.

Orb displays at most **32 newest job summaries** and **64 newest lifecycle events per job**. It
shows state and result-or-artifact presence while withholding prompts, output, and private errors.
The store queries one extra job and event as omission sentinels. Database `LIMIT`s select the
newest suffixes before per-job event hydration; projection then restores creation/sequence order
and marks truncation explicitly.

Any later raw protocol artifact remains bounded untrusted input. It cannot settle the job,
authorize an effect, mutate Graph, or become training material by default.

### 5. Orb Read Models

[Orb](../divination/altar/orb.md) discovers Runs through a bounded metadata catalogue and opens
one Run by direct URL. It keeps ledger-head and page bounds separate, reports sequence gaps and
omissions, and names capture as `process_local` or
`durable_best_effort`. A Pattern link and declared workflow graph require a valid pinned manifest
equal to the registered revision; a Nexus link requires a recorded transition identity.
LOG events are summarized without their raw message.

The parallel field retains at most three live lenses of 100 records each. Its graph folds supplied
Run, station/subject, occurrence, and record identities; counts describe loaded membership.
Retained-evidence SSE polls the owning ledger in bounded batches, preserves explicit gaps, and
resets an invalid future cursor through an authoritative snapshot. A ledger-terminal settlement
drains currently retained evidence without claiming completeness. This feed is distinct from the
process-local Bridge token channel. [Frontend](15-frontend.md#snapshots-streams-and-recovery)
owns its browser recovery and lifecycle contract.

Current Orb has no native Oculus model, nested subworkflow identity, cross-process completeness,
artifact custody, or annotation. A reset requests snapshot replacement; it does not recover history
inside the browser.

Viewing, filtering, and layout never change a Run. A future annotation is a separately authorized
record, not an implicit retry, approval, cancellation, publication, or transition.

### Exact-Run Archive selection explanation

A separate Archive-authorized read may join one retained Run to its exact expected recall request.
It requires the supported pinned Pattern and complete admitted/current Archive binding, then
current local metadata-inspection authority; `altar:read` alone is insufficient. The bounded view
contains historical receipt identities, selected source revisions, scores, character/result bounds
and recorded budget omissions, with no prompt, source body, answer or provider payload.

The capture class is a matching retained request. Public recall accepts caller-supplied identities,
so even an exactly matching receipt may precede workflow execution. The view cannot claim actual
consumption, provider transmission, complete Context, or restored process-local assembly. Missing,
unsupported, denied, failed and successfully empty selections remain distinguishable. Later source
revocation does not rewrite the old selection or grant access to its former content. This read
neither appends structural evidence nor changes a Run; Archive owns its retained metadata.

### 6. The Physical Body and Pulse

A future Resource Snapshot records the node, units, measurement method, age, errors, and freshness
of VRAM, thermal, power, ownership, and pressure observations. No such snapshot exists today.
Stale or failed measurement means unknown capacity, never free capacity.

Orchestrator may consume fresh physical truth during admission; Oculus can help explain it.
Rates, percentiles, and trends are derived observations. They confer no grant, reservation,
health verdict, or promotion threshold.

### 7. Privacy, Retention, and Failure

Each evidence class declares its purpose, fields, classification, visibility, retention, and export
policy. Redaction occurs before serialization under a named policy version; an Eye applies another
filter. Secret material is rejected.

Privatization telemetry may retain opaque decision/receipt identities, keyed
`EvidenceDigest@1` projections, categories and counts, policy version, failure stage, and gaps.
It carries no canonical raw payload/source digest, sensitive span, or pseudonym reversal map.
Plain hashes of stable or low-entropy private values allow linkage; hashing alone does not
anonymize them. Security owns local-only decisions and keyed evidence projections; Context owns
transformation receipts.

Current Orb allowlists structural fields and omits raw prompts, output, private errors, and LOG
messages. Shared logging has no general redaction, storage, rotation, retention, or correlation
contract. Disabling blanket HTTP body/header capture establishes only that instrumentation choice.

A conforming Oculus must bound producer/subscriber queues, batching, flush, and shutdown. Today's
live Run replay and each subscriber queue are bounded at **256 events**. On overflow, pending
deltas collapse to an explicit snapshot-resync boundary; the channel does not apply producer
backpressure. Failed Step persistence is logged and may leave a gap. A lost observation impairs
diagnosis; authoritative correctness records still commit through their owning transactions.

## Consequences

The evidence contract lets a reader distinguish an authoritative event, an observation, a
derivation, and someone's conclusion. Capture class, gaps, freshness, and uncertainty remain
visible parts of that evidence. An external Eye can be replaced without replacing those meanings.

The cost is explicit ingestion, retention, query, migration, health, and queue work. Privacy and
partial-order correlation require more care than arbitrary tracing spans, and some questions must
remain unanswered when their evidence was never retained.

---
title: "30. Webcrawler"
plain_name: "Design rule 30: Web fetching"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/30-webcrawler/
guide: https://lychd.snayu.ai/docs/adr/30-webcrawler/
---

# 30. Webcrawler (Design rule 30: Web fetching)

## Plain-English summary (Snayu)

**What it is:** Defines the Web Fetcher (Scout): every web action - search, fetch, extract, crawl, render, download and so on - is a separate permitted effect with its own limits, and fetched content is treated as untrusted with its source kept.

**Why it matters:** Read this before adding any feature that searches, downloads or reads web pages.

- Each web action needs its own host-issued grant; a failure never unlocks a stronger action.
- The calling app still decides whether a source is trustworthy and what it means.
- Today only a bounded public-page fetch and extract path works, behind authentication and approval.

**Status:** Partial. Public-page fetch and extract works; search, crawl and rendering are designed.

## Original text (Hexanomicon)

!!! abstract "Context and Problem Statement"
    Web acquisition crosses an untrusted network and returns untrusted bytes. Search, fetch,
    extraction, crawling, rendering, interaction, credentials, sessions, and storage are distinct
    effects; failure may never authorize a stronger one. [Scout](../sepulcher/extensions/scout.md)
    binds each acquisition attempt to its admitted effect and retains its source attribution.

## Decision

Scout owns acquisition: mechanics, attribution, freshness, and destination/contact policy.
It is an Extension Domain, not a crawler service or Composition.
[The first passage](#the-first-passage) follows a bounded static read from a proposed URL to
attributed text. A provider supplies the mechanism. The host binds the locator proposed by an
Agent or admitted application Pattern to principal, Run, effect, destination scope, consent,
provider, and budget. The consuming application still owns source eligibility, interpretation,
truth, autonomy, and consequence.

Each of **Search, Fetch, Extract, Crawl, Render, Interact, Credential Use, Session Custody,
Screenshot,** and **Download** needs its own host-owned `ScoutEffectGrant` and ceiling. **Artifact
Admission is a separate custody-owner effect**, not an eleventh Scout track: Scout may hand off the
quarantine identity and acquisition receipt, but the custody owner validates classification,
retention, retrieval authority, and exact bytes, and alone returns the durable artifact reference.
Neither the application eligibility decision nor a Scout grant can pre-approve that custody
judgment.

Authentication, CAPTCHA, payment, quota, robots denial, provider failure, cancellation, or a
challenge is a terminal typed result: no identity rotation, provider switch, retry, spend, or
effect escalation follows. No-web profiles are valid and confer no ambient egress.

### Provider, Animator, and effect-grant boundary

A Scout **Provider** names one admitted acquisition mechanism. An [Animator](../sepulcher/animator/index.md)
may manifest that mechanism as a local Soulstone or remote Portal, but it does not replace Scout:

- the Animator Rune, adapter, probe, and capability declaration establish what service exists and
  whether it is ready;
- the Scout provider binding declares the exact acquisition effects that service may implement;
- a Dispatcher `CallGrant` or `JobGrant` exposes only the exact technical surface and lease; a
  separate `ScoutEffectGrant` authorizes each Search, Fetch, Extract, Crawl, Render, or other effect;
- a provider call that necessarily combines effects may run only when every constituent effect grant is
  present. A convenient scrape endpoint never merges those grants into one authority.

An Animator-owned `ToolConnector` therefore cannot expose a provider's raw SDK, MCP server, REST
surface, CDP session, or browser automation API directly to an Agent. The Agent-facing tool is
Scout-owned and host-mediated: it validates the current effect grants, sends one adapter-authored bounded
request, normalizes the response, and settles the Scout receipt. Animator registration without an
effect-specific Scout provider contribution grants no acquisition authority.

The designed contribution binds one provider identity/revision, host-assigned Registrant,
semantic interface and operation, exact required effects, immutable profile and dialect-driver
references, and conformance evidence. Its execution binding selects either a native adapter or
one exact Animator capability. These references resolve before the Scout-owned store seals with
the [extension assembly](05-extensions.md#2-the-registration-surface-the-extension-context).
Conflicting ownership, unresolved references, and post-assembly mutation refuse. Scout binds the
[Dispatcher's interface/profile/driver contracts](22-dispatcher.md); it does not create another
capability registry or disguise Search as a model.

Configuration selects an admitted binding and may narrow its ceilings. It cannot contribute code,
an endpoint, extra engine, or new effect through request parameters. Preparation retains the
binding and effective configuration digests; replacement requires a new admitted attempt, and
executable changes follow the existing Vessel-generation boundary. A readiness probe checks its
declared local service surface only. A real search probe needs its own Search and egress admission.

### First-party mechanism policy

LychD's first-party web path must remain useful without a paid remote service. The accepted
mechanism sequence is:

| Mechanism | Concrete form | First-party office |
| --- | --- | --- |
| Native static passage | trusted local Scout code with a disposable, network-denied parsing/extraction child | one bounded public-HTTPS Fetch followed by network-free Extract |
| [SearXNG](https://github.com/searxng/searxng) | digest-pinned Soulstone behind a native adapter | selected Search provider; locators and attributed snippets only |
| [Crawl4AI](https://github.com/unclecode/crawl4ai) | digest-pinned, separately isolated Soulstone | experimental candidate for one exact public-HTTPS Fetch + Render + Extract passage |
| [Firecrawl](https://github.com/firecrawl/firecrawl) self-hosted | no selected concrete form | deferred comparison candidate, admitted only if it later proves a material advantage over Crawl4AI under the same effect and containment contract |
| [Browserless](https://github.com/browserless/browserless) | no selected concrete form | no first-party raw CDP, Playwright, function-execution, or download adapter; future comparison must satisfy the same narrow renderer contract |
| Paid web-acquisition API, including Tavily and hosted crawler/browser services | operator-owned private Portal extension | no first-party built-in adapter or automatic compatibility promise |

SearXNG is Search, not Fetch. Its result URL remains an observation and needs a new Fetch effect grant
before contact. Its engine catalogue, parsers, suspension policy, and upstream maintenance remain
inside the separate service; LychD owns the Rune, exact JSON profile, ingress authentication,
enforced egress mediation, result normalization, probe, and conformance suite. The
[Search contract](#searxng-search-contract) below defines that mediation; an ordinary SearXNG
container does not already satisfy it.

Crawl4AI's name grants no Scout Crawl authority. The initial candidate has no frontier, arbitrary
JavaScript, hooks, LLM extraction, credentials, cookies, persistent session, screenshot, download,
artifact custody, or generic MCP surface. It receives one exact URL only after the host holds the
separate Fetch, Render, and Extract effect grants. Promotion requires an authenticated narrow API, an
immutable image, a sandboxed browser, a dedicated renderer containment zone, independently gated
destination egress, strict time/process/byte/output ceilings, a license/SBOM receipt, and
real-browser adversarial tests.

Firecrawl is not carried alongside Crawl4AI merely as optional duplication. Its self-hosted stack
remains deferred while it couples more acquisition effects and operational services than the
selected passage needs. Reconsideration requires evidence of materially better coverage,
reliability, or containment at comparable authority and operating cost; cloud Firecrawl remains a
paid private-Portal concern under the rule above.

Browserless is not selected as a second browser backend. A broad CDP or Playwright connection hands
the caller more authority than the first renderer passage, while a service-specific REST facade
still needs the same Scout effect grants, destination gate, containment, and output limits. It returns to
comparison only for an identified gap that Crawl4AI cannot satisfy; adapter multiplicity is not a
goal.

### Attempt layers and crash semantics

The Scout-owned effect attempt carries principal, Run, exact effect grants, destination, provider
binding, budget, acquisition disposition, and receipt semantics. A bounded synchronous Scout
effect enters `prepared` before I/O. An Animator-backed implementation additionally holds a scoped
`CallGrant`; a native host-owned adapter pins its exact Scout provider/adapter binding and uses no
Dispatcher lease. Neither creates a `ServiceJobAttempt@1`. If the process dies before settlement,
Scout records `unknown_after_crash` and does not replay the effect without independent evidence.

An asynchronous crawl or render admitted through `JobGrant` keeps that Scout domain job and layers
it over Core's [`ServiceJobAttempt@1`](14-workers.md#service-job-attempts). Its
`unknown_after_crash` domain disposition maps to the mechanical attempt's `INDETERMINATE` state;
recovery reconciles the same capability-backed execution binding and never invents a second
submission.

No provider is a fallback. One prepared Scout effect attempt binds one selected provider and
profile. A static page that needs JavaScript, an exhausted Search provider, or a renderer failure
settles with that outcome; another provider or stronger effect requires a newly admitted attempt.

The designed [trusted local profile](38-iam.md#trusted-local-scout-profile) commits one unique
execution claim and atomically reserves its complete worst-case allowance against both binding
and shared host limits before network I/O. The claim binds the retained Run, exact preparation and
consent, provider/profile, contact plan, policy and revocation generations. An exact duplicate
reads retained status; changed bindings refuse. No database transaction spans network I/O, and
the current handoff gate rechecks authority after awaited claim preparation. Restart cannot turn
the reserved allowance into another execution permit.

Each handoff decision is made before its byte transfer. Its bounded restricted evidence may
be buffered until terminal settlement; successful settlement persists that evidence and measured
usage before releasing eligible reservations. A crash may therefore leave the durable claim and
reservation without exact contact detail. Such an attempt remains `unknown_after_crash`, never a
claim that no bytes were sent, a refunded budget, or permission to replay. Unproved socket or child
termination keeps the reservation held.

### Workflow handoff

The hosting Pattern pins a stable acquisition request identity before execution and retains its
attempt/receipt references in typed state. A Graph node execution occurrence is trace identity,
not the acquisition idempotency key: hardware re-entry can create another occurrence for the same
logical request. A repeated request with changed bindings refuses; an exact repeat reads retained
status without obtaining a second execution permit.

An Animator-backed station resolves readiness and its scoped technical lease before Scout
preparation. Hardware waiting therefore cannot leave a prepared acquisition to be resubmitted on
re-entry. Native static acquisition needs no model grant. Scout retains authority and reservation
truth in its own attempt store; Run, Step and orchestration events carry safe correlation only.

Workflow state never retains live grants, provider handles, or acquired bodies. An acquisition
receipt cannot recover ephemeral bytes after a park or restart. A workflow that needs those bytes
later must obtain separate custody admission and recheck current retrieval authority; otherwise it
returns material-unavailable without refetching. Context receives a bounded, attributed data
projection with its budget and influence accounted for before a model request. Neither dynamic
instructions nor ordinary history silently become a storage path for web material. The
[Archive answer workflow](../state-of-the-work.md#karma-semantic-memory) is a projection precedent, not
Scout delivery or permission to auto-promote sources into memory.

### Native adapters and upstream services 

A **native adapter** is the LychD-owned side of an integration: Rune schemas, provider binding,
probe, request allowlist, normalizer, receipts, and conformance tests. The upstream search engine,
crawler, or browser service keeps its own source, image, license, release cadence, and process
boundary. Native integration does not copy that engine into the MPL-covered core. Small useful
patterns may enter through [Assimilation](35-assimilation.md) with provenance and independent
expression; entire engine catalogues and service internals may not.

### Advertised feeds

A known public feed can answer a purpose through an explicitly admitted Fetch and Extract
passage, before a search service or browser is needed. Its publication supplies a proposed locator
only. Contact, parsing, custody, and recurring polling need their own authority. The feed also
needs a qualified media and extraction profile because the current native HTML/plain-text profile
does not admit XML. Item locators remain bounded returned data, never permission for further
fetches. The consuming application owns local filtering and suitability; repeat watching needs
current admission and finite standing policy.

The [Scout source study](../sepulcher/extensions/scout-web-research.md) records a Bazoš RSS
premise and the next qualification obligations. It is a candidate study, not an admitted feed
profile or delivery evidence.

### Model-free native feed handoff

The selected native `rss-public-feed@1` binding uses `native-static@1` and the qualified
`scout-rss-extract@1` worker. Its HTTP profile sends only the fixed RSS/XML Accept set and accepts
only `text/xml`, `application/xml` or `application/rss+xml`, with strict UTF-8 and at most 1 MiB
decoded representation, 2 MiB response wire body and the existing bounded HTTP/gzip/framing
rules. The profile is selected by the host-owned binding before contact, never inferred from a
response header. The old static serializer/parser and page binding retain their exact media and
byte contracts. This first feed follows no redirect, retry, item link, script or subresource.

A model-free consumer binds its exact admitted Pattern, purpose, application request and
projection/custody profile independently of any later model capability. It gets no placeholder
capability, Dispatcher lease or ServiceJobAttempt. The unversioned page preparation/review encoding
remains frozen; a distinct closed feed encoding retains the consumer binding and explicitly no
model grant. Unknown or mixed encodings refuse. Run, consent, claim, profile and budget identity
remain in the existing Scout store; the first profile preserves the one-active-binding/fresh-profile
database boundary and refuses retained incompatible budgets without rewriting them.

The consuming Composition owns its retained result. Scout's transient feed material is consumed
only by that exact admitted consumer under current CONSUME authority, including after waits and
before result adoption. It does not acquire storage authority from Fetch or Extract. Extraction
settlement uses a positive type-specific metadata projection: profile/media, source/record/text
digests where applicable, strategy, transformations and bounded counts. It never serializes feed
channel/items, titles, links, summaries or publisher claims by removing only a `text` key.
Contact attribution remains separately owned restricted network evidence.

The [Scavenger finite observation](../compositions/scavenger/market.md#finite-feed-observation)
selects the concrete native consumer and its whole-field custody/deletion/recovery contract.
A retained receipt cannot reconstruct missing material or authorize refetch. Network/native/consumer
qualification remains separate from the RSS extraction mechanism.

## SearXNG Search contract

The designed `searxng-search@1` profile supports one query, one qualified engine, one result page,
and at most ten locator observations. A later multi-engine profile must qualify each recipient
and their aggregate disclosure budget. The Agent proposes query text, a supported language/time
filter, and a result limit within the profile. The host owns provider selection, engine identity,
endpoint, credentials, request parameters, deadlines, and grants. Unknown fields and unsupported
filters refuse before contact; an arbitrary provider-options dictionary is not part of the tool.

The adapter uses authenticated `POST /search` with explicitly enabled JSON output, no caller
cookies or preferences, and no redirect following. The effective service configuration positively
selects the engine; inherited defaults, autocomplete, favicon retrieval, answerers, and optional
plugins cannot add contacts or outputs. Query syntax that selects engines, categories, languages,
external bangs, or lucky redirects is refused by the pinned parser contract, not guessed away
with an unqualified regular expression. Typed filters are compiled only where that engine proves
support. These restrictions also apply at service admission and transport, independently of input
validation. The local service address comes from its registered control-plane binding; it does
not grant an exception for public acquisition to contact private destinations.

### Query disclosure and engine transport

Query derivation preserves [Context influence and privacy labels](21-context.md#privatization-and-the-privacy-cut).
A local search service still discloses to remote engines. Before each upstream transmission,
[Security](09-security.md#portal-privatization-and-egress) must admit the exact final request:
recipient and custody route, canonical target and wire digest, source influence, disclosure basis,
policy, expiry, and remaining budget. Raw-eligible public queries still require this decision;
URL encoding is not anonymization. The local ingress request never authorizes unknown fan-out.

The selected integration requires an explicit cooperative request-mediation seam: the service
prepares a bounded engine request, the trusted transport admits its final bytes and sends it, and
the service receives the bounded response for parsing. Independent containment denies direct
service egress. Query-bearing URLs, headers, bodies, initialization, auxiliary requests and
redirects must all cross that seam under an exact admitted contact plan. No transparent TLS
interception, ambient proxy, destination allowlist alone, or after-the-fact observation substitutes
for the Gate. The adapter must account for transport-generated fields before sealing the request.
No compliant upstream hook, engine profile, image, or containment implementation is claimed here.

The first profile has no retry, redelivery, proxy/identity rotation, page expansion, or fallback.
It reserves a finite contact budget before preparation; every transmission consumes both that
budget and the purpose's disclosure allowance before its first byte. A failed engine remains a
failed engine. A disconnect, quota, challenge, or `Retry-After` cannot authorize another request.
An engine requiring an unmediated call is ineligible. Cancellation fences new transmissions and
requires evidence that owned work stopped; an uncertain terminal state follows Scout recovery
law. Raw queries, query-bearing URLs, provider errors and unkeyed content digests stay out of
general logs, Orb and Loom. Their permitted projections follow Security's restricted-evidence law.

### Search observations and failure meaning

The normalizer returns host-authored attempt/provider/profile references, observation time,
normalizer identity, bounded ordered results, coverage, declared omissions, and separate measured
and provider-reported usage. Each result carries original locator, any derived normalized locator,
rank, plain title/snippet, and provider-reported engine attribution. Normalization preserves query
parameters and path meaning; canonicalization never creates permission to contact the URL.
Provider dates, scores and attribution remain claims, not verified freshness, confidence or truth.
Deduplication retains the contributing identities and ranks. Raw-response and derivation digests
remain restricted local evidence, not public telemetry.

Result count and coverage are independent. Coverage is `no_reported_failure`, `partial`, or
`unknown`; the first means only that the provider reported no failure. Zero results with a failed
or suspended engine is not a clean miss, and an empty error list does not prove every intended
contact completed. Unrecognized engine errors map to a generic attributed failure; translated
provider prose never becomes a stable protocol code. Partial observations are permitted only for
provider-reported engine failures within an otherwise valid admitted exchange. Host authority,
destination/egress, adapter-to-service transport, framing, schema, resource, or cancellation
failure is terminal and cannot be salvaged into successful partial output, even if some results
arrived before the refusal. Invalid required locators refuse the response rather than silently
manufacturing an empty result. A declared top-ten selection is an intentional projection; a byte
ceiling failure is a refusal, not permission to truncate a record.

Generated answers, raw page bodies, images and extra links are outside this profile. The
Scout-owned tool returns attributed data to Context. Fetching a result, retaining its bytes, or
submitting a memory candidate requires the respective owner to admit a separate effect.
[Memory](27-memory.md) keeps candidate intake and explicit promotion; search relevance cannot
grant recall eligibility or instruction authority.

## The first passage

The first designed passage is one unauthenticated static HTTPS GET and network-free extraction:

1. An Agent or admitted application Pattern proposes one exact URL. The host validates its
   principal and Run, admits separate Fetch and Extract grants with their own ceilings, and binds
   the Fetch destination. It selects an eligible static provider, reserves worst-case budget, and
   durably records those exact grants in one Scout effect attempt as `prepared` before I/O.
2. The provider pins and performs one GET with only explicitly bounded, re-gated redirects: no
   subresources, JavaScript, cookies, cache, URL credentials, `.netrc`, ambient proxy, custom
   headers, automatic retry, or rendering. A redirect needs exact current destination and
   disclosure authority, including any required consent; an unlisted redirect refuses by default.
   Describing future redirect gates in the initial review does not authorize unknown targets.
3. A network-free extractor accepts only allowed HTML, XHTML, or plain text; it records raw and
   output digests, extractor identity, and loss, then returns fenced attributed text.
4. Settlement records disposition and usage. A prepared bounded-call Scout effect attempt after a
   crash is `unknown_after_crash`; without an independent terminal record there is no blind retry.

Wire bytes, decoded bytes, expansion ratio, parse work, output, headers, time, redirects, rate,
concurrency, depth, requests, and spend are separately bounded. `Content-Length` and
`Content-Type` are hints. Mismatch, truncation, unsupported media, or any limit failure refuses.
Crawl, when admitted, adds a finite deduplicated frontier, page/depth budget, per-origin
scheduler, identifying agent, and fail-closed robots evaluation; robots is neither authentication,
site terms, nor legal permission.

### Initial qualification envelope

The `static-public-page@1` envelope below defines a conservative qualification target. Its
numeric limits become usable only with the pinned adapter's conformance evidence; declaring them
does not measure parser safety or document coverage. A limit change creates a changed profile.
Runtime settings may narrow the limits but cannot silently widen a prepared attempt.

| Resource | Ceiling | Enforcing owner |
| --- | --- | --- |
| Contact chain | initial GET plus at most three redirects; one active passage per admitted binding | Scout reservation and destination gate |
| Transfer | 2 MiB encoded body, 4 MiB decoded body, 20:1 cumulative expansion, 64 KiB headers per response; body budgets aggregate across the chain | bounded transport and decoder |
| End-to-end elapsed time | 30 seconds from prepared admission through extraction, including DNS and redirects | host monotonic deadline |
| Extraction | 5 seconds elapsed, 2 seconds CPU, 256 MiB child memory, within the remaining passage deadline | supervisor and OS limits |
| Parse structure | 50,000 elements, depth 128; no external entity, DTD, XInclude, schema or subresource resolution | pinned parser with construction-time limits |
| Serialized return | 256 KiB UTF-8 including attribution | bounded encoder and IPC |
| Retry, paid spend, frontier | zero | Scout admission and transport |

Expired or revoked authority refuses before each new contact. Slots and worst-case budgets are
reserved atomically against both binding and shared host limits; another binding cannot bypass
the aggregate ceiling. Reservations are not released while owned work may still run. Restart reconciles
uncertain reservations with the retained attempt rather than assuming a timeout refunded them.

Parsing and extraction run in a disposable network-denied child, with no acquired sockets,
credentials or workspace authority. The parent supplies bounded decoded bytes and pinned options;
the child cannot fetch, decompress again, load external resources, or invoke an LLM. The host kills
and reaps owned work on timeout/cancellation. OS CPU and memory limits must cover parsing as well
as extraction; post-parse element counts and coroutine timeouts are insufficient. A parser without
construction-time bounds or observable limit failures is ineligible. Silent recovery truncation,
OOM, child crash, limit failure, or unproved cleanup cannot become successful extraction.

One pinned extractor strategy is selected per profile. Heuristic boilerplate removal records its
declared transformations without claiming an exact semantic-loss percentage. Page titles,
bylines, dates, `<base>` and canonical links remain untrusted claims; they cannot replace the
contacted source or trigger another contact. Wire, decoded-body and output identities remain
distinct. Readiness requires representative ordinary and hostile fixtures before any library or
numerical envelope is qualified.

### Native HTTPS transport profile

The native transport receives an exact destination candidate, a host-selected numeric DNS
resolver, an explicit CA file, a remaining monotonic deadline and a mandatory current handoff
gate. None of those values mints an effect grant. It reads no ambient resolver, proxy, credential,
trust-store or TLS key-log configuration.

For a hostname, it asks that resolver for A and AAAA over separate, single TCP contacts, with no
search suffix, UDP fallback, cache or retry. Each response is at most 16 KiB and 64 records; at
most eight CNAME links may be resolved inside the returned message, without another question.
Both families must be complete NOERROR responses for the exact question and agree on the final
name; an empty family requires an enclosing SOA. Every returned destination address passes the
public-address policy before one address is selected. These are observations from the configured
resolver, not DNSSEC proof. Resolver custody remains the authorizer's separate obligation.

The selected numeric peer is checked after the single connect. TLS 1.2 or newer validates the
original hostname against the explicit CA file and certificate SAN, offers HTTP/1.1 only, and
preserves that hostname for SNI and `Host`; an IP literal uses certificate IP identity without
literal-IP SNI. Memory BIOs keep the TLS implementation away from the network socket. Every
actual connect/send, including handshake and read-generated TLS output, crosses the synchronous
gate. Per-connection ceilings are 4 MiB received, 512 KiB sent, 256 KiB handshake input and 256 KiB
handshake/control output, with 16 KiB socket chunks and bounded BIO buffers. Later TLS input shares
the receive ceiling. These limits cannot enlarge the stricter
aggregate HTTP body or passage deadline limits.

The fixed GET carries only `Host`, `Accept`, `Accept-Encoding` and `Connection: close`. Final
success requires status 200, HTTP/1.1, UTF-8 HTML or plain text, and identity or single-member gzip
encoding. Content-length, ordinary chunked and close-delimited bodies are supported. Initial
headers are bounded before the HTTP parser receives them; ambiguous framing, chunk extensions,
trailer fields, informational/upgrade responses, malformed terminators, truncation, trailing data,
unsupported encoding and expansion failures refuse. Body accounting includes chunk framing as
well as encoded payload; decoded bytes are independently bounded. The HTTP response digest names
decrypted HTTP octets, never ciphertext or a claimed network capture.

Redirect observations are resolved only against an exact pre-admitted target list, re-resolved
and re-gated, with loop and aggregate-budget checks. Relative references whose empty path
segments would be changed by the URI resolver refuse. Transport EOF is required before a response
becomes complete. Fetch and extraction share the remaining passage deadline; cancellation closes
the socket and awaits extraction containment. A cleanup uncertainty cannot become a successful
page result. These mechanisms remain unexposed until durable attempts, current authority and the
hosting workflow are assembled and qualified together.

### Native text extraction profile

The first native extractor uses a fixed standard-library worker for strict UTF-8 `text/html`
and `text/plain`. It accepts decoded bytes, not a locator, executable, parser plugin, credential,
or network handle. HTML is projected to text without a document tree: element and nesting limits
apply during parsing. Head, script, style, template, SVG, MathML and comment content is omitted;
attributes and source-supplied base/canonical links confer no authority. A bare HTML5 doctype is
inert; external or internal DTDs, processing instructions and other declarations refuse. The
versioned strategy declares its whitespace and structural transformations. This is neither a
browser's rendering nor article extraction, factual verification or prompt-injection removal.
Malformed input outside that strategy refuses rather than being silently repaired into success.

The private child protocol has one bounded header, an exact body length and EOF. Decoded input is
at most 4 MiB. One UTF-8 JSON response is at most 240 KiB, leaving room within the passage's
256 KiB return ceiling for host-authored attribution; the passage must still count its complete
serialized return. Invalid encoding, trailing input, unsupported media, output overflow, child
failure and malformed returns are terminal refusals. Errors use closed codes, never source text.
The parent verifies returned structure and computes decoded-input and serialized-output digests;
neither is a network-wire digest or permission to retain the material.

The Linux host supplies an explicitly reviewed Bubblewrap executable, dedicated Python runtime
and finite loader/library closure. The fixed worker receives an empty filesystem root with those
read-only runtime mounts, fresh user, PID, network, IPC and UTS namespaces, cleared environment,
dropped capabilities and closed unrelated descriptors. It receives no checkout, home, host proc
mount, credentials or writable host directory. Namespace creation and disabling nested user
namespaces are mandatory; there is no bare-process fallback. The assembled mount root is
read-only. CPU and virtual address space are bounded before acquired input is processed; core
dumps are disabled and the fixed worker cannot fork or create threads. `RLIMIT_AS` is an
address-space ceiling, not an RSS measurement or cgroup memory guarantee. The supervisor bounds input/output, enforces the five-second
wall deadline and separately bounds kill/reap cleanup; unknown cleanup cannot produce success.

Qualification belongs to the actual host/runtime/profile combination. Tests of command assembly
or substituted processes establish only those contracts. A live qualification must demonstrate
network and host-file denial, descriptor/environment isolation, limit failures and termination of
namespace descendants, including a new-session descendant. Availability of `bwrap`, an exit code,
or a passing extraction fixture alone does not establish containment. This extractor is a local
mechanism: Fetch/Extract grants, egress decisions, durable acquisition attempts, workflow binding
and artifact custody remain separately owned prerequisites to a Scout passage.

### Native RSS 2.0 extraction profile

The `scout-rss-extract@1` profile shares the fixed worker's physical containment and
supervisor with text extraction; it has a separate request and structured return. The existing
static text profile still accepts only HTML/plain text. Its two-field private header must refuse
XML. RSS needs the exact additional profile identity and one of `text/xml`, `application/xml`, or
`application/rss+xml`; a media label alone cannot select it. Neither mechanism admits Fetch,
recurring watching, custody or any item contact.

The first profile accepts strict UTF-8 RSS 2.0, one unnamespaced `rss` root and one `channel`.
A declaration, when present, must name XML 1.0 and UTF-8. It retains channel title, locator and
summary, and at most 100 item observations with title, original locator, summary and optional
publisher date/identifier. Channel title/locator/summary are required; each item needs a locator
and nonempty title or projected summary. Duplicate selected fields, nested XML inside those
fields, non-whitespace text in structural RSS/channel/item containers, malformed/truncated XML
and missing required values refuse the complete result.
Namespace extensions and unselected elements/attributes are omitted with declared loss and an
omitted-element count; they cannot impersonate selected fields. Publisher dates and identifiers
remain claims, never verified freshness, global identity or a deduplication authority.

| Resource | RSS ceiling |
| --- | --- |
| Decoded UTF-8 input | 1 MiB |
| Element count / depth / items | 10,000 / 64 / 100 |
| Title / locator / summary | 1,024 / 4,096 / 8,192 UTF-8 bytes per field |
| Publisher date / identifier | 128 / 1,024 UTF-8 bytes per field |
| Serialized return | 240 KiB, within the enclosing passage's remaining return budget |
| Child wall / CPU / address space | 5 seconds / 2 seconds / 256 MiB, no wider than static extraction |

A field or output ceiling refuses rather than truncating items. XML-decoded scalar construction
is bounded before trimming or description projection, even if that later transformation would
shorten the field; the projected value is checked again. XML whitespace surrounding a
selected scalar is removed without rewriting locator paths or queries. RSS descriptions containing
escaped HTML or CDATA use the fixed HTML text strategy inside the same child; source instructions
remain data. Description attributes are omitted after control checks; numeric references are
checked before HTML5 replacement can erase a forbidden control. Selected locators are independently checked by the parent against Scout's existing
pure HTTPS destination-syntax contract. That validation performs no DNS or contact and grants
neither; each later contact needs fresh current authority.

Parsing uses the runtime's Expat with reparse deferral enabled and version at least 2.6.0, under
the same pre-input hard process limits. DTDs, entity declarations, external entities and processing
instructions refuse before they can acquire authority or resources. XML declarations are handled
separately; encoding declarations cannot broaden strict UTF-8. Raw and entity-decoded text obey
the existing control-character policy, including omitted material. Construction-time element/depth
and input bounds apply to omitted material too; selected fields are bounded incrementally. No
DOM, external resource loader, browser or Core XML parser substitutes for the isolated child.

Qualification must join ordinary and hostile RSS behavior to the exact shared worker, supervisor,
interpreter and containment closure. A changed worker requires fresh evidence for existing text
profiles as well; an earlier static receipt cannot qualify RSS. Network acquisition and native
workflow admission remain subsequent, separately proved boundaries.

## Destination and data boundary

Every external acquisition URL, redirect, and new connection is independently authorized: canonical HTTPS
scheme, hostname, port, and origin only; no userinfo or unsupported scheme. Resolution runs
without ambient proxy or credentials and rejects mixed or forbidden addresses (loopback, private,
link-local, multicast, unspecified, and metadata). The approved address is pinned through the
connection; connected peer, TLS certificate, SNI, and `Host` must match. Redirects are manual,
bounded, loop-checked, and re-gated. An HTTP client or crawler SDK alone cannot establish this
SSRF/DNS-rebinding boundary.

### Destination preflight

The bounded `public-https-destination@1` preflight performs no resolution or contact. It accepts
at most 4 KiB of ASCII URL text, HTTPS on port 443 only, a canonical dotted DNS hostname or
canonical public IP literal, and no userinfo, fragment, whitespace, control character, backslash,
encoded authority, or malformed percent escape. DNS case is normalized; an explicit `:443` may
be omitted. Path/query bytes, including an empty query delimiter, retain their meaning. Unicode
host conversion, alternate numeric address spellings, scoped IPv6 and custom ports require a
separately reviewed profile rather than permissive parser repair.

A second pure check classifies a supplied complete, bounded A/AAAA answer set for that exact
hostname. Empty, malformed, duplicate-overflow, forbidden or mixed sets refuse; IP literals must
match the supplied address exactly. The conservative policy excludes special-purpose IPv4 ranges
and allows ordinary IPv6 global unicast only, excluding special-purpose and transition ranges.
The policy is explicit and versioned rather than inherited from changing standard-library
`is_global` tables. Positive facts remain an immutable candidate, not a grant or evidence that a
resolver actually returned them. The future trusted resolver must establish completeness and
freshness; transport must still pin and verify the actual peer, TLS identity, redirects, authority
and budget. A caller-constructed candidate cannot bypass those gates.

An acquisition receipt names the effect, principal/Run, provider/version, policy, locator and
redirects, destination evidence, time, disposition, media/size, usage, and raw digest. It proves
an attempted effect, not a correct response. Responses and derivations remain attributed data:

```text
locator != response != derived statement != trusted fact
acquired != admitted != understood != promoted
```

They are never instructions, code, policy, or truth. Interpretation belongs to
[Drift (34)](34-evaluation.md) or the consuming Composition.

## Custody and stronger tracks

Acquired bytes remain ephemeral until their custody owner verifies digest, media type, size,
classification, retention, retrieval authority, and storage and returns a retrievable
`ArtifactRef`. A digest or receipt alone is not an artifact, and an arriving download enters
bounded quarantine rather than creating a workspace or artifact. Render, Interact, Credential Use,
Session Custody, Screenshot, and Download remain Designed. JavaScript or a challenge produces
refusal or `human_required`, never a browser.

Any future renderer needs a finite destination/egress grant and isolation from Core peers, host
paths, databases, control sockets, wallets, and unrelated secrets. Credentials are opaque,
principal- and origin-scoped references outside prompts and telemetry. A browser-bearing
Soulstone may not join the shared `lychd.pod`; it needs a dedicated rootless containment and
network zone whose only target egress crosses the Scout gate.

## Qualification evidence

The following are acceptance obligations, not existing tests or runtime receipts. Each profile
must bind its actual finite request, response, parser, time, concurrency and disclosure ceilings;
missing, unlimited, negative or nonfinite values refuse admission. Search additionally fixes
query/locator/title/snippet limits and a per-engine contact plan before qualification.

| Case | Required observation |
| --- | --- |
| Wrong effect, stale binding, forged provenance, mutable registration | refusal before contact; no raw provider tool is exposed |
| Query bangs, preferences, extra parameters, inherited engines, service initialization | no unadmitted recipient or auxiliary request |
| Disconnect, redirect, timeout, quota, challenge, cancellation | no hidden retransmission, provider switch, or stronger effect; uncertain work is not reported settled |
| Partial engine failure, suspension, empty result, missing coverage | distinct attributed observations; no exhaustive-search claim |
| Valid result JSON after a host-denied auxiliary request | terminal refusal, never successful partial output |
| DNS rebinding, mixed public/private answers, peer mismatch, redirect to metadata | no application bytes reach the forbidden destination |
| Compression bomb, malformed framing/JSON, invalid locator, limit and limit-plus-one input | deterministic bounded refusal; no salvaged partial success |
| Deep/wide markup, expensive parsing, OOM, external entities and resources | Core survives; bounded child termination; no unauthorized network or file read |
| Prompt injection, forged receipts, canonical links and provider error text | unchanged authority and host attribution; no follow-up contact, automatic custody or memory promotion |
| Crash between preparation, transmission, extraction and settlement | retained identity and unknown outcome; no blind replay or early budget refund |
| Changed image, parser, engine, effective config or driver | old qualification cannot authorize a new binding |

### Upstream comparisons

These primary references informed the design review on 12 October 2026; they do not qualify a
dependency or deployment. Recheck the exact selected revision before implementation.

- **SearXNG:** [JSON API](https://docs.searxng.org/dev/search_api.html),
  [query syntax](https://docs.searxng.org/user/search-syntax.html) and
  [engine settings](https://docs.searxng.org/admin/settings/settings_engines.html) support the
  separate search adapter, but default-disabled engines and query routing are not authorization.
  At [ad46ebd7d](https://github.com/searxng/searxng/blob/ad46ebd7d/searx/network/network.py#L249-L279),
  the first connection-error branch permits another client request even with zero configured
  retries. This is evidence of a permitted retry path, not proof that every such error retransmits
  application bytes. Qualification must observe and constrain that path.
- **Tavily:** its [Search API](https://docs.tavily.com/documentation/api-reference/endpoint/search)
  demonstrates optional generated answers, raw content, automatic parameter selection and usage.
  A future private Portal must close those choices explicitly; the endpoint name alone does not
  establish its effects or cost. It remains outside the first-party provider set.
- **Trafilatura and Readability:** [Trafilatura's extraction source](https://trafilatura.readthedocs.io/en/latest/_modules/trafilatura/core.html)
  checks output tree size after parsing/extraction; [Readability](https://github.com/mozilla/readability)
  consumes an already-built DOM and does not sanitize returned HTML. Their article-selection
  mechanisms are comparison candidates, not parser containment. Neither extractor is selected
  without coverage and resource evidence; return plain attributed text through the same boundary.
- **Crawl4AI and Firecrawl:** [Crawl4AI configuration](https://docs.crawl4ai.com/core/browser-crawler-config/)
  exposes browser powers wider than the selected passage; [Firecrawl self-hosting](https://docs.firecrawl.dev/contributing/self-host)
  introduces a broader service stack. Keep the existing renderer candidate and deferred comparison
  until a demonstrated static-coverage gap justifies their operating and containment cost.

## Delivery Boundary

The native public-page profile implements bounded Fetch and Extract through opt-in
`bridge_chat@4`, with authenticated declaration, native consent and durable attempt accounting.
It is distinct from the general provider, Search, Crawl and Render surfaces designed above.
[State of Work](../state-of-the-work.md#scout-web-acquisition) owns its current evidence envelope:
separately qualified network/extraction mechanisms and controlled workflow/PostgreSQL checks do
not establish a deployed application-to-model passage or arbitrary host compatibility.

The pure `public-https-destination@1` checks remain preflight facts; only the admitted transport
can establish connected-peer and transmission evidence. A locator, model declaration, generic
runtime test or `ArtifactRef` cannot supply missing authority or custody.

No Scout-owned general provider contribution, effect-scoped Agent tool, robots/rate scheduler,
browser, download quarantine or Reliquary is delivered by that profile. Search mediation and
renderer isolation require their own qualification; the native path cannot grant their effects
or make the shared Pod an acceptable browser boundary. The
[Scout topic](../sepulcher/extensions/scout.md#public-page-answers) owns configuration and operation.

## Consequences

!!! success "Positive"
    Static reads do not inherit browser, credential, payment, storage, or interpretation authority.
    Redirect, provenance, hostile-content, and custody failures stay visible and recover only by a
    newly admitted effect. Search-engine and browser maintenance stay behind replaceable service
    protocols, while the free local first-party path remains coherent.

!!! failure "Negative"
    Safe acquisition requires more than HTTP and HTML libraries. Dynamic, authenticated, paid, and
    durable material remains unavailable until its separate adversarial boundaries pass. Operators
    choosing paid web providers own a private adapter, its compatibility, and its provider contract.

---
title: "31. Simulation"
plain_name: "Design rule 31: What-if simulation"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/31-simulation/
guide: https://lychd.snayu.ai/docs/adr/31-simulation/
---

# 31. Simulation (Design rule 31: What-if simulation)

## Plain-English summary (Snayu)

**What it is:** Defines the What-if Simulator (Shadow): exploring alternative branches against a pinned starting point, with separate roles proposing (Dancer) and reviewing (Hunter) branches, while the target owner decides any real change.

**Why it matters:** Read this before building experimentation or branch-and-compare features.

- Simulation never changes live state; promotion is a separate, explicit owner decision.
- Branch generation and review are kept separate, with budgets and stopping conditions.
- No branch has to win; unknown or contradictory results stay recorded as such.

**Status:** Designed. No simulation store, workflow or provider is built yet.

## Original text (Hexanomicon)

!!! abstract "Context"
    [Shadow](../sepulcher/extensions/shadow/index.md) explores bounded alternatives against a
    pinned base and retains the evidence and outcome of each branch. Candidate generation,
    independent review, and promotion need separate owners: [Dancer](../sepulcher/extensions/shadow/dancer.md)
    proposes alternatives; [Hunter](../sepulcher/extensions/shadow/hunter.md) reviews them; the target
    owner decides whether a proposed change may affect the system.

## Decision

Shadow owns the experiment: its simulation Intent, branch lineage, assumptions and unknowns,
separation of expansion from review, budgets and stopping conditions, evidence/artifact
references, eligibility packages, and cleanup eligibility/receipts. Scheduling, unsafe execution,
capability selection, readiness, truth, Persona, consent, live mutation, Memory curation, and
training remain outside that office. Spellweaver, execution, Dispatcher, Orchestrator, Drift,
Mirror, HitL, Archive, and Soulforge keep those responsibilities.

A game engine simulating physics, navigation, actors, and gameplay inside an exact local project
is [Foundry](../compositions/foundry/world.md) execution, not a Shadow branch. Shadow may compare
separate project candidates under pinned bases, but it neither becomes the engine world nor owns
the selected game's scene, rules, playtest, or build.

!!! warning "Delivery boundary"
    Shadow is **Designed**. No simulation Rune or schema, Pattern, branch store, search provider,
    workspace manager, Tomb, Reaper, Vision contract, evaluation integration, or promotion path
    ships. [State of Work](../state-of-the-work.md#shadow-simulation) owns delivery.

## Records and branch law

An immutable **Simulation Intent** names owner, purpose, exact base state, permitted effects,
budgets, stop conditions, and promotion class. It creates stable **Branches**, each recording
parent, generating Invocation, assumptions, required/observed state, unknowns, resource owner,
and status. **Observations** name exact command/tool/predicate, environment, inputs, outputs,
artifacts, and error class. A **Vision** packages one candidate revision, lineage, checks,
measurements, uncertainty, hazards, and proposed effect; a **Promotion Request** adds target,
validation, rollback, authority class, and expiry. A **Cleanup Receipt** records resources,
retained evidence, teardown, residue, and terminal state.

Repository, fixture, world, and artifact bases are exact revisions, never “latest.” Branches are
either text-only **idea** branches, isolated **material** branches, or a **promotion candidate**
packaged as a complete Vision. The latter is not selected, true, or authorized. Branch status is
explicit:

```text
open | blocked | failed | ineligible | candidate | retained | reaped | cleanup_incomplete
```

No branch need win. Exhaustion, contradictory requirements, unavailable state, and `UNKNOWN` are
truthful outcomes.

## Open, judge, prune

An experiment may use enumeration, debate, best-of-N, beam/tree search, human candidates, or
another provider; no heuristic is constitutional. Dancer receives the common Intent and one
declared Lens, then proposes alternatives with provenance, assumptions, required state, and
unknowns. It cannot see siblings before the join, rank them, or promote them. Hunter separately
reviews a named candidate, returning challenges, evidence requests, boundary findings, withhold
recommendations, and uncertainty without inventing a preferred replacement. A join can cluster
or deduplicate only while preserving original lineage.

Before material spend, deterministic predicates may make a branch ineligible; witnessed policy
violations may block it. Missing evidence is `unknown` and may justify one bounded inquiry naming
question, access, budget, and stop condition; it ends `resolved`, `refuted`, or `unknown` and may
not widen itself. Model hesitation proves nothing. Drift evaluates reviewer Posture against
matched solvable controls. The **Dual-Gate** combines deterministic checks with attributed,
calibrated qualitative judgment before eligibility; no score, confidence, or surviving cheap branch
selects reality.

### Versioned exploration strategy

A Simulation Intent may pin an executable exploration strategy by revision and digest, with its
input/output contract and implementation closure. Given the observations disclosed so far,
eligible branches and remaining budget, it proposes where to continue, a bounded batch of
attempts, or a stop. Its decisions retain the evidence available at that point. Branch eligibility,
independent Hunter review and promotion keep their existing owners; the strategy cannot widen
authority, resource ceilings or sibling visibility.

The strategy remains fixed throughout one admitted experiment. A proposed successor is candidate
material evaluated by Drift and admitted by the receiving owner for later work. Changes to the
score or implementation follow [Workflow revision law](28-workflow.md#pattern-identity); no
strategy update patches a live Run. Spellweaver coordinates the admitted attempts, Dispatcher
selects capability, and Orchestrator owns physical readiness and resource conflicts.

Retained branch histories may support [historical exploration replay](34-evaluation.md#historical-exploration-replay).
The replay snapshot pins parentage, source revisions, disclosed observations, recorded costs,
terminal states and missing continuations. It preserves unsuccessful branches within the admitted
retention scope. Search over those records produces a candidate strategy and bounded evidence;
fresh trials establish how it behaves beyond the recorded history. This optional mechanism needs
no change to model weights and grants no training admission.

## Material containment and budgets

A material branch receives an isolated workspace through a replaceable provider. Jujutsu can
provide tracked change identity, not an execution sandbox. Its contract pins base and owned paths,
mounts/processes/ports/services/network/secrets/effects, evidence locations, leases, reset/snapshot,
expiry, teardown, and state-change verification. Effectful tests use an admitted execution boundary:
directory deletion cannot end processes, revoke credentials, close ports, undo remote calls, or
restore shared state. The designed Tomb proves none of this today.

Intent bounds branch/depth count, tokens, wall time, spend, disk, artifacts, concurrent execution,
and review rounds; children consume their parent's reserved envelope. Spellweaver coordinates fan-out,
join, cancellation, and termination; Dispatcher chooses capability; Orchestrator manages readiness
and lease conflict; Workers run jobs. Exhaustion cancels or marks incomplete, then cleans up—it
never selects a winner.

## Evaluation, reaping, and collapse

An Observation proves only its named predicate. A unit test cannot establish architectural fit,
a commit cannot establish shared-state isolation, and a model judge cannot establish an effect.
Shadow sends exact branches, environments, observations, and artifacts to versioned Drift Trial
Suites, keeping deterministic receipts distinct from verdicts. Mirror may supply
Persona-congruence criteria but cannot privately select a Persona. A score is a scoped,
versioned, attributable evaluation signal: it may guide pruning, priority, or convergence inside
the experiment, but proves and authorizes nothing.

## The Branch Reaper

Only after retention settles may Reaper act: commit terminal state; retain required inputs,
observations, artifacts, findings, and errors; enumerate jobs, leases, processes, services, ports,
and credentials; have workspace/execution owners tear down; reconcile external/shared residue; and
write the Cleanup Receipt. TTL is not proof of safe deletion; hold, lease, pending promotion,
required evidence, or unknown ownership postpones it. Failure retains its witnessed boundary;
neither traces nor success/failure pairs become Karma or training examples automatically.
Jujutsu cleanup verifies descendants and retained references because abandonment can rewrite
revision relationships.

Shadow emits only a Promotion Request:

```text
Vision → target owner revalidates current state and evidence → rollback/snapshot preparation
→ Ward and HitL/preauthorization decide the exact effect → owner applies and verifies → receipt
```

The target rechecks base, preconditions, policy, authority, and rollback against current reality.
Historical success or preauthorization outside an eligible class cannot merge, publish, purchase,
deploy, restore, or otherwise cross the boundary. Archive separately admits memory; Soulforge
separately admits training. This is the Demarcation Law: Spellweaver coordinates live Invocations;
Shadow produces candidate realities.

## Consequences

!!! success "Accepted"
    Candidate worlds carry lineage, budgets, evidence, adversarial review, honest pruning, and
    cleanup without collapsing experimentation into authority or live effect.

!!! failure "Cost"
    Search and review consume finite resources, isolation/teardown are difficult, bias can converge
    on the wrong candidate, and some experiments end without a promotable answer.

## Acceptance evidence

Shadow remains **Designed** until one bounded Pattern proves independent Dancer branches, separate
Hunter review, base pinning, material ownership, deterministic observations, Drift evaluation,
budget cancellation, inert Promotion Request, current-state revalidation, and a Cleanup Receipt
including incomplete teardown. State of Work records that transition.

---
title: "32. Identity"
plain_name: "Design rule 32: Personas and attribution"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/32-identity/
guide: https://lychd.snayu.ai/docs/adr/32-identity/
---

# 32. Identity (Design rule 32: Personas and attribution)

## Plain-English summary (Snayu)

**What it is:** Defines the Persona Keeper (Mirror): it owns persona definitions and revisions, binds an exact persona version to a job, and keeps attribution between people and machinery. It does not authenticate users or grant permissions.

**Why it matters:** Read this before adding personas, assistant identity or attribution of who did what.

- A job pins an exact persona revision, or records that none was chosen.
- Authentication and permissions belong to the Security Desk (Ward), not personas.
- Persona changes go through reviewed revision proposals, never silent self-editing.

**Status:** Designed. Chat uses a fixed agent spec today; no persona registry exists.

## Original text (Hexanomicon)

!!! abstract "Context"
    **Mirror** governs filtered, durable but revisable Persona bindings and their attribution.
    Those bindings must remain traceable when model processes end, work resumes, or a Persona
    revision changes. Mirror is neither a hidden runtime nor evidence of continuous Cognizance.

The [Answer](../sepulcher/lich/answer.md) develops the corresponding account of Ahaṃkāra and
local identity.

## Decision

Mirror is LychD's singular identity-binding jurisdiction. It owns Persona definitions/revisions,
an exact Persona revision binding when an Invocation selects one, explicit absence when it selects
none, scoped identity context and eligible memory hydration,
hydration receipts, attribution across people and machinery, and reviewed Persona-revision
proposals. It does not authenticate a Principal, grant scope, select model, schedule Pattern,
evaluate quality or causal blame, or train weights; IAM/Ward, Dispatcher, Spellweaver, Drift, and
Soulforge retain those offices.

!!! warning "Delivery boundary"
    Mirror is **Designed**. Bridge currently binds a fixed `The First One` `AgentSpec`, static
    identity instruction, and loopback `magus:*` Sigil. There is no Persona registry, revision
    lineage, identity-scoped Archive, hydration receipt, congruence Trial Suite, or self-revision
    path.
    Current Sigil fields prove authority plumbing, not Persona continuity. [State of
    Work](../state-of-the-work.md#mirror-identity) owns delivery.

## Keep the names apart

| Name | Question | Owner |
| --- | --- | --- |
| **Principal** | Who initiated or approved? | IAM |
| **Sigil** | Which bounded authority was active? | Ward/IAM |
| **Persona** | Which durable voice, commitments, and orientation shaped the Agent? | Mirror |
| **AgentSpec** | Which executable cognitive/output/tool contract ran? | Agent |
| **Posture** | Which per-run settings and constraints applied? | Pattern/Agent |
| **Composition / Pattern** | Which purpose and workflow admitted the act? | Composition/Spellweaver |
| **Producer** | Which human, model, provider, tool, or adapter contributed? | provenance owner |

No value substitutes for another: Persona grants no authority; a Principal does not author every
requested output; a provider is not Persona; shared Persona does not merge Runs. Present `Sigil`
is a frozen name/scope set, without stable identity id, credential lineage, delegation relation,
or revocation epoch; future Mirror keys may not pretend `Sigil.id` exists.

Persona **voice** means declared discourse, commitments, manner, and orientation. It is not an
acoustic voice profile, synthesized speech artifact, musical vocal, dubbed performance, or
presentation asset. Echo retains acoustic and speech-lifecycle facts; Riffmaw musical performance;
Language Edition timed-language performance; and Avatar the eligible presentation selection that may
reference any exact permitted artifact. Avatar's Morphe may select presentation style and an
already eligible output locale; it cannot select or rewrite Persona discourse manner, translate
text, or turn localized wording into identity.

## Persona and binding

Each Pattern makes an explicit Persona choice: one exact revision or no Persona. The admitted
Run retains that choice. Promoting a revision can redirect later work through a name, but cannot
rewrite an existing Run's binding.

One Persona has a stable id and immutable revisions. Publication freezes a revision; editing
produces candidate children. Each revision declares:

| Concern | Required content |
| --- | --- |
| Lineage | Owner, provenance, parent, creation and lifecycle. |
| Identity | Name, discourse voice, commitments, domain, non-goals, and protected terms and relationships. |
| Hydration | Ordered instruction fragments, memory namespace and eligibility, and compatible Postures. |
| Review and change | Required Drift Trial Suites; replacement, rollback, export and retirement law. |

Codex owns declared intent. Phylactery stores revisions, bindings, hydration receipts and
attribution. When a Persona is selected, Mirror compiles its contribution:

```text
Persona revision + Pattern/AgentSpec requirements + active Principal/Sigil
+ eligible identity-scoped memory → ordered context blocks + hydration receipt
```

The receipt records source revisions, memory references, transformations and exclusions, ordering,
size and truncation, and the envelope digest. It establishes what was supplied, not model obedience.
Context owns token budgeting and final prompt assembly. Ward authorizes namespaces, tools and
scopes; Dispatcher selects capability; Orchestrator supplies readiness. More forceful identity
instructions cannot replace any missing permission.

Identity memory is denied by default across Personas and Principals. Every record carries its
namespace, producer, subject, provenance, eligibility and retention. Cross-identity recall needs
explicit policy and retains source attribution.

Resume preserves the revision-pinned Persona binding and cites newly admitted memory. It does
not silently replace the selected revision with the latest Persona.

## Attribution and congruence

Attribution follows every identity-bearing Invocation or artifact. It records who initiated,
approved, delegated, and acted, with the active Sigil; exact Persona, AgentSpec, Posture,
Composition, and Pattern revisions; the exact Invocation identity; contributing models,
providers, tools, sources, and humans; and parent, handoff, and artifact lineage. Each record
declares whether it is an assertion, observation, evaluation, correction, or promoted act. Those
relationships make the act traceable without deciding its quality, credit, fault, or causal blame.

At a Composition Suite handoff, the immutable artifact retains its original attribution. The
consumer starts a newly admitted child Invocation with its own binding. Handoff and correlation
receipts convey neither authority nor authorship. Delegation names both principals and uses the
delegate's producer identity and grant. Edits and rejected branches add to lineage rather than
laundering it.

Drift keeps the author and subject of findings and corrections. Mirror binds that history;
Drift owns verdicts and attribution candidates; Soulforge independently admits any training use.

A Persona may supply Drift with criteria for commitments, voice boundaries, role limits, memory
claims, tool behavior and response to pressure. Congruence measures one property of that Persona;
it does not establish truth or general quality. A designed Phantasma Pattern may request bounded
Shadow branches and a versioned Persona-congruence Trial Suite. Mirror cannot select whichever
resemblance it prefers.

Matched controls distinguish continuity from slogans, mimicry, refusal and leakage. Changes to
authority language, tools, memory policy or core commitments rerun affected adversarial and
regression evidence. A punctuation change need not rerun every Trial Suite.

## Revision and recovery

Experience can motivate a revision proposal. Changing the promoted definition still requires
the reviewed passage below:

```text
attributed observations/findings → bounded diff against exact parent → validation
→ Drift congruence/regression evidence → required Magus/HitL decision → immutable child
```

Smith may draft or package a candidate and Spellweaver may coordinate the work; publication stays
with Mirror. Repetition, praise, model confidence and memory volume grant no additional scope,
tool, trigger, queue position or hardware priority.

Rollback directs future Invocations to a prior promoted revision and leaves earlier Runs and
artifacts intact. A static prompt supplies none of the required binding, scoped memory, receipt,
lineage or rollback. Retrieval provides hydration input, while behavioral resemblance can support
at most a Drift finding. Automatic self-revision is refused because it bypasses the attributable
reviewed passage.

## Consequences

!!! success "Accepted"
    Persona, authority, execution configuration, memory, and authorship remain distinguishable;
    future continuity is revision-pinned, attributable, reviewable, and reversible.

!!! failure "Cost"
    Revision/attribution propagation, explicit memory eligibility, and calibrated congruence Trial Suites
    add storage and latency, and rich lineage often leaves credit or fault unresolved.

## Acceptance evidence

Mirror remains **Designed** until a Persona is declared, revision-pinned to a Run, hydrated from an
authorized namespace with reproducible receipt, fully attributed, resumed with its pinned revision intact,
tested against matched congruence controls, revised through an immutable candidate, and rolled back
for new Invocations. State of Work records that transition.

---
title: "33. Training"
plain_name: "Design rule 33: Model training"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/33-training/
guide: https://lychd.snayu.ai/docs/adr/33-training/
---

# 33. Training (Design rule 33: Model training)

## Plain-English summary (Snayu)

**What it is:** Defines the Model Trainer (Soulforge): only explicitly admitted data can become a training corpus, training runs in isolation, and the resulting model must pass independent evaluation and an explicit promotion decision before serving.

**Why it matters:** Read this before building fine-tuning, dataset collection or model promotion features.

- Runtime traces are never harvested for training by default; corpus admission is explicit.
- Training never changes serving weights in place; trainer loss is not promotion evidence.
- Adapters need exact base-model compatibility, and rollback must stay possible.

**Status:** Designed. No training package, corpus service or trainer exists.

## Original text (Hexanomicon)

!!! abstract "Context"
    Retained material can shape later acts through Context and Recall; training changes model
    parameters. **Soulforge** governs which nominated evidence may enter that training, how a
    candidate is formed, and what must reach independent judgment. A useful trace still needs
    corpus admission; trainer loss cannot authorize promotion; an adapter needs exact base-model
    compatibility. The [Soulforge guide](../sepulcher/extensions/soulforge/index.md) follows the
    passage from corpus admission to candidate handoff.

## Decision

Soulforge carries admitted material from corpus admission and dataset compilation into a
training-job contract, candidate lineage, and handoff for independent evaluation/promotion.
It must never harvest runtime traces by default or treat Karma, consent, repetition, or a positive
Drift verdict as corpus admission. It cannot mutate serving weights in place, use trainer
telemetry as promotion evidence, select production routing, or turn Trial Suite feedback into
gradients or automatic repair.

```text
nominated evidence → admitted immutable corpus → compiled dataset + sealed holdout
→ isolated Training Run → frozen Candidate Bundle → independent Drift evaluation
→ explicit promotion decision → versioned serving observation
```

Every arrow is attributable and may refuse; there is no ambient online self-training.

!!! warning "Delivery boundary"
    Soulforge is **Designed**. No training package, corpus service, compiler, trainer plane,
    candidate registry, evaluation integration, or Altar route is installed. The `karma` table is
    not a corpus. [State of Work](../state-of-the-work.md#soulforge-training) owns delivery.

## Training discernment from work

The [discernment training passage](../sepulcher/extensions/soulforge/discernment-training.md)
applies this law to nominated SDLC traces and human corrections. Preserve the distinction that
changed a decision, its evidence and conditions, and a counterexample to the superficial rule.
Preference, fact, authorization, measured result and evaluator judgment remain distinguishable.
First test whether Context or a versioned procedural correction solves the limitation; changing
weights requires a separate objective and transfer claim. Meeting capture, retained history,
accepted work and evaluation consent do not imply training admission. The passage participates in
[Ouroboros](../sepulcher/extensions/weaver/ouroboros.md) through settled records, with no ambient
harvesting or self-certified promotion.

## Records

| Record | Required content |
| --- | --- |
| **Training Intent** | Pins Principal, purpose, target capability, base digest, allowed data classes, resources, and promotion authority. |
| **Corpus Admission** | Freezes members and exclusions, provenance, transforms, privacy, consent/license, splits, objective, and approval. |
| **Dataset Manifest** | Pins examples, lineage groups, split digests, compiler, schema, statistics, and contamination checks. |
| **Recipe** | Pins trainer, dependencies, method, hyperparameters, randomness, precision, budgets, stops, and expected change. |
| **Training Run** | Pins exact inputs, environment, resources, logs, checkpoints, terminal state, and artifact digests. |
| **Candidate Bundle** | Binds base, candidate bytes, tokenizer and configuration changes, corpus/Recipe lineage, receipt, and compatibility. |
| **Promotion Decision** | Binds independent evidence, capability envelope, serving constraints, approver, rollout, rollback, and retirement. |

Names never replace digests. Every repeated execution receives a new Training Run identity and
receipt. Reproducibility must be proved by the execution contract; matching inputs or candidate
bytes cannot substitute for the later Run’s own lineage.

## Corpus admission

Drift Cases/Outcomes, Mirror attribution, HitL decisions, Archive rows, success, refusal,
repetition, storage consent, and database access may nominate material; none grants training
rights. Before trainer access, admission proves:

- source, Run, artifact, producer, time, and transform lineage;
- exact purpose, subject, derivative and retention use, and approving Principal;
- training-specific consent, license, or authority;
- privacy minimization and retained redaction limits;
- target relevance and label quality;
- lineage-aware grouping of duplicates, revisions, sibling trajectories, and generated variants;
- immutable train, development, and sealed-holdout splits;
- base target, learning signal, unacceptable change, expected lift, regression limits, and stops.

The sealed holdout is fixed before training-facing generation and withheld from trainer,
augmentation, selection, and model judges used to tune. A negative ledger retains rejected,
redacted, and duplicate ids so retry/compiler cannot restore them. Missing provenance, authority,
privacy clearance/minimization, relevance, safe split, or uncontaminated holdout blocks admission.
Runtime data is opt-in: completion is not quality, and a blocked/refused Run can be useful if
objective and evidence support it. Redaction never erases source influence; privatization labels and
lineage remain attached through any narrower disclosure separately admitted by
[Security](09-security.md#portal-privatization-and-egress).

## Dataset compilation

Dataset compilation begins from one admitted corpus snapshot and produces an immutable Dataset
Manifest. Every resulting field must trace to a source or versioned deterministic transform.
The compiler preserves:

- role, tool, workflow and authority context;
- the distinction between observations, human labels, evaluator judgments and augmentations;
- truthful non-completion and split or lineage-group membership;
- filtering, redaction, truncation, normalization and sampling decisions; and
- audit statistics for balance, concentration, length, duplication and exclusion.

Schema-valid generation still requires evidence for its claims. Holdout answers, benchmark
solutions, evaluator rationales and downstream targets must remain outside prompts, retrieval,
augmentation, preference construction, trainer metadata and selection. A benchmark used to choose
the corpus must be disclosed and needs an untouched control before it can support independent
promotion. Only the admitted Manifest crosses to training.

## Training execution

The execution boundary receives one immutable Manifest, the exact base-model, tokenizer and
configuration digests, the Training Intent and Recipe, admitted secrets and network access, and
fresh Run-owned output locations. Its resource request names exact accelerators, memory,
storage, network and duration requirements together with the declared conflict domains it may
affect. Orchestrator resolves the affected set and owns readiness, affected-lease drain, conflict
resolution and restoration. Corpus meaning and trainer success remain with their owners.
Training has no universal priority: unused devices stay undisturbed, and policy may postpone or
refuse the request.

Filesystem, credential, network, process and resource controls must enforce the execution
boundary and leave receipts. A container or Coven label alone establishes none of these controls.
Local work has no privacy exemption. Remote work additionally records egress, provider custody
and retention, secret and network handling, returned artifacts and receipts. The trainer receives
no authority to enlarge its corpus with live traces, replace serving, widen resources or promote
its own result.

LoRA, QLoRA, full tuning, preference optimization, distillation and later methods remain
replaceable Recipe ports. Each adapter pins its base digest and runtime compatibility.

Failure or cancellation preserves terminal truth, logs, checkpoints and quarantined partials
for diagnosis. A completed checkpoint may be evaluated only as pinned candidate material through
the same independent handoff; it never becomes serving state by surviving the job. A partial is
never a Candidate Bundle. Retrying creates a new Training Run and receipt.

## Independent evaluation

A frozen Bundle enters [Drift](34-evaluation.md) as an exact, immutable subject. Drift may
neither alter the candidate nor change its corpus, Recipe or lineage. Its evidence must include:

- the sealed target holdout and matched Outcomes from the base or currently promoted baseline;
- named regression Trial Suites and adversarial or authority-boundary Cases; and
- quality, latency, memory and cost measured in a compatible serving Environment.

Errors, exclusions, uncertainty and evaluator calibration accompany those results. Loss,
development improvement, trainer-authored examples and self-grading remain diagnostics. A visible
Trial Suite establishes only the capability and safety claims its Environment can support.

## Promotion, serving, and rollback

A passing Drift result makes the candidate eligible for a promotion decision. Owning policy and
Magus/HitL still decide whether to promote. That decision binds the exact Bundle and Outcomes,
admitted capabilities and denied uses, compatible engine and base relation, rollout observations
and stops, fallback and rollback, and retention, quarantine, and retirement rules.

Dispatcher consumes a registered capability; files alone cannot create one. Revisions remain
immutable, and supersession requires a new Bundle and decision. Rollback routes new work to an
earlier digest and quarantines the suspect candidate while preserving completed effects.

A later privacy, authority, license, contamination or leakage failure must be traced through the
exact Dataset, Run, Bundle, claims and promotion descendants. Policy may block serving or reuse,
quarantine or delete controlled artifacts, invalidate affected claims, and require clean
admission and rebuilding. Source deletion cannot untrain produced weights.

Retrieval remains appropriate for current, mutable, attributable knowledge. Exporting all history
to a provider, or allowing a trainer to select, evaluate and deploy itself, collapses the separate
authority this contract requires.

## Consequences

!!! success "Accepted"
    Corpus and weights gain auditable lineage; observation cannot silently become model bias;
    trainer and serving remain replaceable; holdouts/regressions separate optimization from release.

!!! failure "Cost"
    Review, grouping, sealed holdouts, large artifact custody, representative evaluation, and
    reproducibility consume substantial operator, hardware, and storage capacity; weight influence
    cannot be reliably removed by source deletion.

## Acceptance evidence

Soulforge remains **Designed** until one bounded recipe proves admissions/exclusions, lineage-safe
splits, sealed holdout, isolated immutable-input execution, candidate custody, independent Drift
evaluation, explicit promotion, compatible serving, and rollback to a prior revision. State of Work
records the transition.

---
title: "34. Evaluation"
plain_name: "Design rule 34: Evaluation"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/34-evaluation/
guide: https://lychd.snayu.ai/docs/adr/34-evaluation/
---

# 34. Evaluation (Design rule 34: Evaluation)

## Plain-English summary (Snayu)

**What it is:** Defines the Evaluator (Drift): it tests an exact version of a model, workflow or app against a declared goal and real conditions, using versioned test suites and rubrics, and reports findings with uncertainty.

**Why it matters:** Read this before building benchmarks, quality checks or anything that compares models or workflows.

- Evaluation is evidence offered to policy, never policy itself; it cannot authorize deployment or spending.
- Verdicts include PASS, PARTIAL, FAIL, CONTRADICTED, UNKNOWN and DISPUTED.
- A missing dependency counts as a harness problem, not a failure of the thing tested.

**Status:** Designed. No evaluation harness, test suites or results store exists.

## Original text (Hexanomicon)

!!! abstract "Context"
    A capability must be evaluated for its declared task under the tools, authority, hardware,
    dialect, and consumer conditions in which it will be used. [Drift](../sepulcher/extensions/drift/index.md)
    keeps those conditions versioned and its findings attributable, so a result can be assessed
    against the claim it is meant to support.

## Decision

Drift is LychD's singular evaluation jurisdiction: it evaluates how an exact subject revision
meets or departs from a declared goal. It defines Cases and Trial Suites, captures observations,
applies versioned Rubrics, reports uncertainty, and returns bounded findings. It does not execute
unsafe payloads or own Tomb; select Animator/capability; authorize spend, publication,
repair, or deployment; define Persona; mutate Pattern, Composition, or artifact; admit training;
or promote a Soulstone. Execution, Dispatcher, Toll, Spellweaver, Mirror, Smith, Soulforge, and HitL
keep those effects. Evaluation is evidence offered to policy, never policy disguised as a score.

!!! warning "Delivery boundary"
    Drift is **Designed**. There is no harness, maintained Trial Suite, evaluator store,
    capability matrix, benchmark history, Altar route, or Dispatcher update driven by evaluation.
    [State of Work](../state-of-the-work.md#drift-evaluation) owns delivery.

## The declared goal

Before a trial, its requesting owner states expected and forbidden behavior in the Case and
criteria, thresholds, and missing-evidence policy in the Rubric. Applicable authority,
constraints, and permitted effects remain part of the trial conditions. Drift evaluates that
declared contract. Its findings cannot revise the goal or authorize a way of reaching it.

Deviation from the goal may be categorical, qualitative, or measured along separate axes. A first
trial needs no earlier version or time series: its reference is the declared goal. Baseline/candidate
comparisons and repeated trials show how that relation changes. An unchanged failure remains a
failure; a large behavioral change may be an improvement. Missing evidence establishes neither
success nor a measured distance from the goal.

A revised goal requires revised Cases or Rubrics and new Outcomes. Earlier findings retain their
original contract; the subject cannot move the acceptance criteria after seeing the result.

## Trial contract

| Record | Required content |
| --- | --- |
| **Case** | input/fixtures, expected and forbidden behavior, oracle, effect class, stop |
| **Trial Suite (`TrialSuite@1`)** | versioned Cases/controls, order, repetitions, aggregation |
| **Rubric** | criteria, verdict vocabulary, thresholds, missing-evidence policy, revision |
| **Evaluator** | kind/identity/revision, independence, calibration, limitations |
| **Environment** | subject/prompt/tool/dependency/hardware/harness/state/budget/policy revisions |
| **Outcome** | observations, measures, verdicts, uncertainty, errors, cost, latency, evidence |

Changed subject, prompt, schema, Rubric, Evaluator, or Environment creates a new Outcome; it
cannot rewrite an earlier result. Libraries implement this port but do not own evidence or routing.
Drift first retains what was observed: process exits, files, rows, tool requests, admitted
effects, resource measurements and provider receipts. A criterion match, quality grade,
attribution claim or judge score is a judgment over those observations and must remain separately
identifiable. Model self-report is output under test. Mechanically observable receipts outrank
textual similarity, and missing evidence stays missing. Shadow may isolate candidates and Tomb
may execute them; each contributes typed observations to this judgment.

```text
trial status: completed | subject_error | harness_error | evaluator_error | blocked
claim verdict: PASS | PARTIAL | FAIL | CONTRADICTED | UNKNOWN | DISPUTED
```

Unavailable dependency is not subject failure; a hidden validator precondition is a harness/state
contract candidate. Refusal on an impossible task is not success unless matched solvable controls
show action when action is possible.

## Adversarial evidence and calibration

**Adversarial Cases** pressure a boundary: forbidden authoritative requests, false premises, demanded
certainty amid missing evidence, contradictions/impossible completion, repeated nudges, recoverable
distortion, and attempted tool/memory/identity/completion claims beyond supplied evidence. Matched
positive and negative controls record pressure round/order, recovery, over-refusal, truthful
non-completion, and downstream contamination separately—not a mutable “integrity” scalar. Magus
dialect perturbations are still test data with provenance, scope, and release rules.

A Trial Suite declares repetitions and stopping rules before it runs. It retains distributions,
trial order, applicable random seeds, blocked and error trials, and exclusions. Non-deterministic
Evaluators are calibrated against labelled controls and known ambiguity. Qualitative work records
independent agreement and disagreement where the judgment warrants it.

An LLM judge is a declared, bounded Evaluator. Its prompt, revision, inputs, lineage, calibration
and conflicts belong to the Environment; hidden chain-of-thought is never required. Sealed Cases
and holdouts protect against tuning. Leakage, duplicates, unstable harnesses and changes in
Evaluator behavior invalidate the claims they undermine while leaving independently supported claims intact.

## Evaluating a workflow change

[Workflow improvement](../sepulcher/extensions/drift/workflow-improvement.md) applies this trial
contract to an exact score, prompt, schema, Context policy or implementation revision. The claim
must include relevant trajectory evidence, failures and human burden as well as terminal artifact
quality. It pins baseline and candidate, matched budgets, controls, uncertainty and stopping rules
before comparison. Observations and qualitative judgments remain distinguishable.

Cached evidence can support only its unchanged input and evidence closure. Regrading a retained
artifact creates a judgment over that artifact; it cannot establish that a changed workflow
produces the same trajectory. Changed actions or relevant state require fresh admitted trials.
The owner may adopt, reject or investigate the resulting candidate under its authority, without
rewriting earlier Outcomes or a live Scroll. A later training hypothesis requires separate
[Soulforge](33-training.md) admission and protected holdout evidence.

### Historical exploration replay

Drift may evaluate a [versioned exploration strategy](31-simulation.md#versioned-exploration-strategy)
against an immutable collection of recorded branch histories. The Environment pins the histories,
observation-disclosure and transition rules, cost accounting and stopping conditions. The subject
strategy sees only observations revealed by its preceding replay decisions; hidden descendants
and their outcomes remain unavailable. An absent continuation stays unknown and cannot become
an invented observation or a witnessed failure.

Such an Outcome measures strategy behavior on that recorded search space. It does not establish
that changed requests, dependencies, timing or parallel execution would reproduce those outcomes.
Keeping the baseline among candidates can prevent a worse selection on the same replay objective
and history; it gives no guarantee for later histories or live work. Effectiveness outside replay
requires fresh admitted trials, protected evaluation and independently observed state. Report
represented execution costs separately from actual replay, strategy-development and validation
costs. The [operating passage](../sepulcher/extensions/drift/workflow-improvement.md#replay-an-exploration-history)
shows how to prepare that comparison.

### Evidence of recursive improvement

A recursive-improvement claim must show reuse of a changed mechanism: exact baseline/candidate
revisions, motivating evidence, adoption decision, and a later improvement attempt that actually
used it. Showing effectiveness requires a further comparison. Compare the successors produced
by original and revised mechanisms from comparable starting subjects and evidence, under matched
total budgets and independent evaluation. Keep transfer results, regressions, uncertainty, and
stopping decisions alongside improvement across rounds. A better task artifact alone does not
establish a better mechanism for future improvements.

Development feedback remains separate from protected assessment. Revising an Evaluator creates
a separately calibrated candidate and new Outcomes; the subject cannot redefine its own acceptance
criteria. [Ouroboros](../sepulcher/extensions/weaver/ouroboros.md#what-the-next-round-inherits)
connects these claims to the owning creation and adoption passages.

## Capability claims and routing

Drift may derive a scoped claim from a healthy Trial Suite. Each claim pins:

- Animator, model, adapter, tool, and configuration revisions;
- task class, Cases, Rubric, Evaluators, and Environment;
- sample, controls, distribution, uncertainty, and noise;
- cost and latency per admitted success, including failures;
- creation, expiry, and evidence references.

There is no universal rank: accuracy, latency, VRAM, cost, restraint, and tool behavior
are distinct policy-valued axes. Dispatcher may consume fresh admitted claims only after Ward,
compatibility, availability, privacy, and authority construct an eligible set. Missing/stale
evidence leaves the Dispatcher's documented deterministic readiness order in force rather than
inventing an intelligence floor. [Dispatcher selection](22-dispatcher.md#candidate-selection)
owns that order, including the treatment of stale or erroneous cached observations. It selects
one candidate; failure of that selection does not retry another candidate. Toll may use the same
measures in spend policy
without making one local or frontier win universal routing authority.

## Evaluation before and after training

Soulforge defines a training proposal's expected change, baseline Outcomes, holdout evidence,
and unacceptable regressions. Post-training evaluation uses that contract or makes every change
visible; training-facing improvement cannot promote a candidate. Drift returns evidence without
selecting a corpus or registering a model. Passing an identity/behavior Trial Suite grants no
Persona, Sigil, tool, or privileged route.

## Returning findings across a Composition Suite

An exact, version-pinned [Composition Suite](../compositions/products-and-suites.md#compositions-relate-without-nesting)
may return a consumer consequence as evidence. This requires the member Composition and Pattern
revisions, handoffs, failing observation, Rubric, Evaluator, Environment, verdict and uncertainty,
and the declared artifact and evidence dependencies. Returning evidence does not reverse execution
or merge member rows, secrets, Sigils, approvals, policies or effect authority.

| Inert record | Law |
| --- | --- |
| `CompositionSuiteFindingSet@1` | Binds the Composition Suite and Rubric, subjects, Environment, observations and measures, Evaluator, verdicts and uncertainty. |
| `AttributionCandidate@1` | Names a possible boundary, supporting and conflicting evidence, rival explanations and uncertainty; it does not establish causal certainty. |
| `InvalidationSet@1` | Identifies claims whose support fails and claims with intact closure. |
| `CorrectionRequest@1` | Names a bounded owner delta, preserved constraints, evidence, scope and repair budget. |

Drift follows declared dependencies backwards to the smallest cut supported by the evidence.
The nearest producer is not automatically the cause. Reuse requires the same complete input
closure, artifact revisions, Rubric, Evaluator, relevant Environment and evidence contract. A
failing consumer alone cannot condemn shared artifacts.

Missing lineage, flakiness, contagion, capture or rival explanations may leave the verdict
`UNKNOWN` or `DISPUTED`. They can justify at most a broader bounded trial; they cannot justify
reconstructed history or convenient blame.

The returned records authorize no spend, publication, deletion, training, promotion or mutation.
Spellweaver may admit a new forward Invocation under ordinary policy and HitL. Earlier Runs and
Outcomes remain in its lineage.

## Consequences

!!! success "Accepted"
    Claims are reproducible and scoped; receipts, judgment, and absence remain distinct; pressure
    measures restraint without rewarding blanket refusal; consumers retain their own authority.

!!! failure "Cost"
    Cases, controls, environments, calibration, and evidence maintenance cost ongoing human,
    hardware, and provider effort; observability may leave attribution disputed and claims stale.

## Acceptance evidence

Drift remains **Designed** until one versioned Trial Suite with controls distinguishes subject/harness/
evaluator failure, reproduces an Outcome, calibrates each non-deterministic Evaluator, preserves raw
evidence/uncertainty, and proves routing/repair consumers reapply their own policy. State of Work,
not this ADR alone, records promotion.

---
title: "35. Assimilation"
plain_name: "Design rule 35: Adopting outside code"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/35-assimilation/
guide: https://lychd.snayu.ai/docs/adr/35-assimilation/
---

# 35. Assimilation (Design rule 35: Adopting outside code)

## Plain-English summary (Snayu)

**What it is:** Defines how external code or ideas are re-written as attributable local LychD code under the Smith area: the result is only a candidate that must pass review, testing and a separate promotion before use.

**Why it matters:** Read this before porting code from other projects or building AI-driven self-extension.

- Provenance, license, security and maintenance must be checked for anything adopted.
- A model may propose the code but cannot certify its own work.
- Candidates are built and tested in a Lab, then promoted separately by the target owner.

**Status:** Designed. No end-to-end adoption path, forge or promotion controller ships.

## Original text (Hexanomicon)

!!! abstract "Context"
    Foreign craft crosses more than a code boundary: provenance, license, behavior, security,
    architecture, verification, maintenance, and promotion must survive. A model may propose the
    crossing; it cannot certify its own work.

## Status

The **Smith Extension Domain** and its reference Assimilation protocol are **Designed**. LychD
ships no candidate-author Agent, end-to-end Assimilation path, forge, autonomous repair loop, compatibility
gate, verified package promotion, rollback controller, or self-extension runtime. [State of
Work](../state-of-the-work.md#smith-forge-promotion) owns this boundary.

## Decision

**Assimilation** re-expresses an admitted foreign pattern as attributable local LychD code under
the Smith Domain's governance. It produces a candidate, never a live organ. The protocol orders
governance questions and settled handoffs, while the owners of admissions and effects retain
their coordination and execution. Assimilation itself is not a Portfolio Composition.

| Act | Meaning |
| --- | --- |
| Integration | Bind an external service/protocol through an adapter. |
| Delegation | Ask another runtime or sovereign node for bounded labor. |
| Assimilation | Study a pattern and implement an owned local expression. |
| Material intake and interpretation | Convert external user data into provenance-bearing candidates; [Transmuter](../compositions/transmuter/index.md) studies the application boundary. |

No act promises bit-for-bit reproduction, protocol or license compatibility, or freedom from
upstream maintenance without separate evidence.

### Paperclip Maximizer

!!! quote "Paperclip Maximizer — the will to become"
    Assimilation's generative pressure asks what the body could learn, express, or make possible.
    Its appetite has no inherent finish line; an admitted undertaking must supply one. Desire
    produces possibilities, while purpose, budgets, provenance and receiving owners govern acts.

The name identifies a creative tension within Smith's governed protocol, not another Agent,
Pattern or authority. A useful foreign mechanism may remain an independent service or peer;
local growth need not erase its source or homogenize the systems that made the lesson possible.
[Evolution's Synchronic Syncretizer](18-evolution.md#synchronic-syncretizer) judges a proposed
inheritance against its declared obligations before the changed body may ask to live.

### Execution has no second coordinator

There is no `assimilation.*` Pattern, end-to-end Graph, Suite, or Assimilation coordinator in this
decision. For one future application-owned job, that application's exact Pattern must admit the
purpose, Dossier, candidate-author Agent, ceilings, and terminal result; Spellweaver may validate
and execute its pinned Scroll but owns neither Smith's candidate semantics nor any promotion
effect. Each later receiving owner acts only from a settled typed request and re-admits its own
effect. If a reusable promise must actively coordinate several Composition-owned Invocations, it
requires a separately named and revisioned Suite before execution.

Until one of those exact application contracts is published, Assimilation remains a non-executable
governance protocol. Source/custody, Smith candidate authorship, verification, HitL, packaging,
migration, activation, and observation owners may each perform their own already-admitted action;
the protocol stages transfer no lifecycle authority and imply no ambient resume of the next action.

## Teaching a missing Spell

A peer can respond to an unknown-Spell refusal by offering an attributed **teaching bundle** for
study. Its bounded, content-addressed manifest binds the exact public contract revision and
digest, examples, source/artifact identities, provenance, license and notice duties,
implementation requirements, declared authority/effects, and claimed evidence. Intercom does not
install a Spell by receiving it. Every claim stays untrusted until local admission and proof;
intake must never import or execute the contents.

A candidate-author AgentSpec selected by an exact owning application Pattern may satisfy Smith's
role contract and re-express the lesson as a local Spell-contract or implementation candidate under an
Assimilation Dossier. Existing code may satisfy the contract, or the candidate may require new
code, an adapter, package, tool, or capability; each follows its own owner and verification path.
Spellweaver validates contract and Scroll candidates but does not coordinate the Assimilation
protocol. Where the candidate adds a Contribution, its receiving Core office or Extension Domain
retains its semantics; Extension law governs package admission; Creation, Packaging, Security,
Evolution, and effect owners retain implementation, promotion, and activation authority.

Policy may refuse teaching entirely, request it only from named peers and content classes, or
accept only an already trusted exact contract with a local implementation binding. No configuration
may turn a teaching bundle into ambient package installation or self-publication. Foreign claims
retain publisher/key attribution; learned contracts and implementations enter an operator- or
Crypt-owned namespace, never `core` or another canonical publisher's namespace. If future
promotion succeeds, a new immutable catalogue generation may make the unchanged exact Scroll
admissible to a later Invocation. The original refused peer task is never resumed under changed
catalogue truth.

Code or contribution changes activate through controlled [Evolution](18-evolution.md): close or
drain admission as required, preserve retained executable closures for pinned Runs, replace the
Vessel or process-built catalogue, reconcile durable state, verify readiness, and reopen. This is
not **Reanimation**, which reconstructs the same body from committed records after process death.
A whole-body restore additionally requires the exact sealed cut in [Snapshots](07-snapshots.md).
Declarative-only Scroll publication may avoid replacement only after an atomic durable catalogue-generation mechanism and
already-admitted implementations exist; neither is delivered now.

The [Creation workflow](../sepulcher/extensions/weaver/creation.md) supplies a candidate-working method
for this passage: establish the foreign lesson and local need, test direction, then test the local
implementation boundary before constructing it. [Ouroboros](../sepulcher/extensions/weaver/ouroboros.md)
connects later observations to separately admitted evaluation, correction and training. Neither
reference creates an Assimilation coordinator or grants an unknown Spell installation authority.

## Candidate author and admission

A **candidate-author Agent** is the future reference Agent role defined by the Smith Extension
Domain. A future exact owning application Pattern must select a registered AgentSpec satisfying
that role. The Agent may inspect admitted source and write candidate code, schemas, migrations,
tests, documentation, and packaging inputs inside a bounded Lab coordinate. It has no ambient authority
over active checkout/Vessel, locks, publication, database migration, lifecycle, secrets,
unrestricted network, or promotion; it submits typed requests to their owners. Authorship is not
authority.

Every candidate begins with an **Assimilation Dossier**: exact source identity/revision/digest/path,
license/notice duties, target behavior or defect, chosen local target/base revision,
transformations/generated files, model/tool/prompt/human authorship, expected effects/verification,
unresolved gaps, and maintenance owner. Absent identity, provenance, or license, material may be
studied but may not request promotion.

Source, manifest, documentation, examples, archive, comments, tests, issue text, and generated
configuration are hostile data, never instruction authority. Admission acquires only exact
material, retains provenance and classification, fences it outside stable instructions, denies ambient
credentials/home/undeclared egress, bounds size/recursion/decompression/parser/subprocess effects,
and records every transform. Typed candidate-author output constrains shape, not truth; prompt injection
can produce valid-looking schemas.

### Admit the mechanism, preserve its maintenance boundary

Before construction, the Dossier identifies the smallest foreign mechanism the local contract
needs, the behavior expected to survive re-expression, excluded authority and defaults, and the
receiving maintenance owner. It explicitly chooses service integration, bounded delegation, or
a locally maintained expression. Acquiring the source or gaining a provider feature cannot also
admit its credential store, router, tool permissions, orchestration, or billing fallback.

Conformance evidence compares the claimed behavior at the actual local boundary, including refusal,
malformed input, limits, interruption and uncertain outcomes where relevant. Foreign tests and
benchmarks remain attributed inputs; the local candidate and its independent oracle establish
only the contract actually exercised. An upstream change becomes a new study/adoption decision,
not an ambient dependency update. Shared-source contribution and downstream activation remain
separate from admitting the local lesson. The
[bootstrap procedure](../sepulcher/extensions/weaver/development-bootstrap.md#assimilate-one-mechanism-at-a-time)
gives the operator-controlled first passage without creating an Assimilation executor.

## Candidate law and Lab

Assimilation inherits [SDLC](./16-sdlc.md)'s candidate/promotion contract: immutable
identity and exact base, permitted paths/effects, isolated workspace, budget, verification plan,
and terminal disposition. Lab is a location, not a sandbox. Untrusted analysis, build, or generated
command needs the [Tomb](../state-of-the-work.md#tomb-untrusted-execution) or another delivered
execution boundary before automation. Pre-v1 coupled Extensions may use internal imports, but are
tested body parts rather than public-API consumers; targets must use actual registration,
configuration, and runtime contracts. A versioned external package/ABI claim needs deliberate
tests.

Python, Rust/PyO3, WebAssembly, shell, and generated Quadlets are candidate materials with distinct
toolchains/effect surfaces. A compile, faster language, or foreign suite never bypasses admission.

## Verify, then promote separately

The Dossier selects evidence that can establish its particular claim:

- lint, types, tests, build and focused behavior;
- differential or conformance checks when equivalence is claimed;
- migration rehearsal, install, import and package checks;
- extension registration and startup;
- permission, egress, secret and hostile-input probes;
- license and notice review; and
- performance measurements only when performance is claimed.

Foreign tests establish foreign behavior. Generated tests cannot be the sole judge of generated
code, and heuristic review cannot override a failed deterministic gate. A bounded correction loop
ends verified or explicitly incomplete. Traces and failures may inform repair through their
Memory, Shadow, Drift and consent owners.

The candidate-author Agent emits a **Promotion Request**, while owners decide and perform their own effects:

| Concern | Owner |
| --- | --- |
| candidate lineage/workspace | [SDLC](./16-sdlc.md) |
| source/package/image construction | [Packaging](./17-packaging.md) |
| coupled extension-package admission | [Extension law](./05-extensions.md) |
| migration/persistence | [Phylactery](./06-persistence.md) |
| activation | [Evolution](./18-evolution.md) and lifecycle owners |
| human authority | [HitL](./25-hitl.md) |

At effect time each revalidates candidate identity, current base, evidence, authority, and its own
recovery. Merge cannot atomically make migration, restart, remote write, and publication. Failed or
indeterminate effects remain attributed; the candidate-author Agent cannot erase them by deleting its
workspace or changing its explanation.

## Transmuter and correspondence 

Cloud archives, historical conversations, and shared media expose an application ownership need
outside Smith. **[Transmuter](../compositions/transmuter/index.md)** names that candidate study,
with Extractor and Synthesizer as internal stages. It remains outside the accepted Portfolio
until its records, judgment, finish, recovery, and independent use establish an accepted contract.
The candidate-author Agent may propose a parser or supply attributable candidate artifacts for
interpretation. Transmuter's proposals retain source lineage; Memory, Mirror, and Soulforge
independently admit their own effects. Imported material establishes no Persona, instruction,
preference, or training truth by itself.
Assimilated capability and every learned Spell are private by default; A2A advertising,
Legion distribution, or public packaging needs its own authorization.

Assimilation is not consumption: the candidate-author Agent breaks foreign pattern on the anvil of local law
and offers a new organ. _Purpose is the hammer. Pattern is the anvil. Consent is the seal._ What
leaves the Forge may ask to live; it does not crown itself.

## Consequences

!!! success "What this gives us"
    One attributable, quarantined passage from foreign craft to locally verified candidate keeps
    provenance, license, authorship, test evidence, and promotion authority distinct.

!!! failure "What it costs"
    Serious work can require differential tests, migration rehearsal, supply-chain review,
    long-term maintenance, and retesting coupled Extensions; some behavior cannot be reproduced
    lawfully or reliably.

## Acceptance gates

No automated Assimilation path may ship until hostile-source ingestion, candidate isolation,
provenance retention, bounded execution, deterministic receipts, refusal after base changes, effect-time
authorization, target-owned promotion, and recoverable or explicitly forward-only failure are
proved.

---
title: "36. Vision"
plain_name: "Design rule 36: Vision and images"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/36-vision/
guide: https://lychd.snayu.ai/docs/adr/36-vision/
---

# 36. Vision (Design rule 36: Vision and images)

## Plain-English summary (Snayu)

**What it is:** Defines Vision & Media (Prism): images, video and documents are handled as tracked artifacts with custody, permissions and safe decoding, and every transformation keeps a record of its source.

**Why it matters:** Read this before adding image, OCR or video features or sending images to models.

- Visual inputs are referenced by immutable artifact references, never pasted as raw prompt data.
- Media is treated as potentially hostile and must be stored and authorized before any model sees it.
- Results must name the exact source and transformation they used.

**Status:** Partial. Only metadata and routing contracts exist; no image bytes are handled yet.

## Original text (Hexanomicon)

!!! abstract "Context"
    A visual source is material with a history, not an oversized prompt. Seeing or transforming
    an image, video, document, or spatial form needs custody, authorization, hostile-media
    handling, declared transformation, and a result that can still name what it used.

## Status

Vision admission is **Partial**. The current v1 compatibility spine defines immutable `ArtifactRef`
metadata, distinguishes the closed `vision` family from image-capable `chat`, and filters
capability declarations by explicitly supplied required input modalities.
Delegated-job contracts can carry artifact references; the current `Intent` and Bridge admission
remain text-only and carry neither artifacts nor required modalities through the Run ledger.
These shapes prove metadata and routing contracts, not an executable visual interface.

It does **not** upload, store, authorize, materialize, decode, normalize, or transport image
bytes. Bridge does not forward artifact modalities into dispatch. No Prism package, image
custody adapter, OCR tool, or managed visual provider ships. The separate bounded local
[WAV custody seam](../state-of-the-work.md#artifact-reference-contract) provides no visual
execution. [State of Work](../state-of-the-work.md#vision-admission) owns that boundary.

## Decision

**Prism** owns visual grounding and transformation. Given an admitted source artifact, it
produces bounded derivatives and observations while preserving the source's identity,
classification, provenance, and declared information loss.

| Faculty | Contract |
| --- | --- |
| **Eye (Prism)** | Dedicated general visual analysis; current v1 projects this as the `vision` family. |
| **Multimodal Mind** | A `model.chat@1` profile with image input; current v1 projects `chat` plus `image` in `modalities_in`, and it remains chat. |
| **Sight** | Finite typed estimates such as regions, masks, tracks, depth, pose, flow, and registered change under a dedicated perception contract; later live sources require a separate bounded session. |
| **Scanner** | Source-grounded document extraction through native parsing, OCR, layout, reading order, and structured reconstruction. |
| **Lens (Prism)** | Deterministic decode, orientation, crop, resize, or normalization. |
| **Maker/editor** | Text- or source-conditioned image and time-based video generation or mutation producing new artifacts through separate effect contracts. |
| **Form** | Bounded generation, reconstruction, texturing, structural decomposition, rigging, rendering, and representation conversion of spatial material through separate tool or effect contracts. |
| **Kinesis** | Bounded recovery, generation, retargeting, cleanup, synchronization, validation, and conversion of structured motion through a dedicated finite-job contract. |

Here Eye and Lens name Prism faculties. An external [observability Eye](29-observability.md)
consumes bounded evidence exports; a [Shadow Lens](20-agents.md#mechanical-cognitive-postures)
seeds a speculative branch with a Posture. Their owners and contracts remain distinct.

### Language and faculty admission

Visual language is typed per job, not inherited from the host or Altar locale. Original prompt,
requested model-facing language, permitted detection, translation or enhancement revision, and
declared loss remain separate facts. A translated prompt is a derivative instruction, not a
replacement for the operator's visual direction; a model that happens to understand a language
has not passed the image, video, typography, or control bake for that language.

A Coven may group compatible local services for operation. It is not a dispatch unit: manifesting
one visual faculty does not manifest the rest.

Form does not establish a universal `spatial` Dispatcher family. Each future implementation must
declare its exact operation, accepted modalities, produced artifact facets, tool or effect
semantics, and recovery contract; a repository that can emit a mesh is not thereby a general 3D
runtime.

### Finite and live perception

Sight likewise does not establish another capability family or turn image-capable chat into
precise perception. A finite Sight result binds every estimate to original source pixels and, for
video, exact frame identity, PTS, and rational timebase through the full transform chain. Masks,
depth and flow remain typed derivative artifacts; confidence is model evidence rather than a
universal probability; a local track id is not identity; and an uncovered region or skipped frame
cannot prove absence.

A camera or feed is not a finite `SightJob` extended indefinitely. Its future session binds capture
purpose and authority, source and stream epoch, privacy masks, active window, viewers, retention,
bounded queues, sampling and drop policy, gaps, and downstream consumers. A proved contiguous
transport reconnect may continue the same epoch; otherwise reconnect closes it, and every new
epoch receives a new track namespace. Observation grants no PTZ, recording, robot, game, or other
effect authority.

### Spatial form, motion, and engine use

Form owns the exact skeleton, hierarchy, rest and bind pose, skinning, morph controls, and rig
revision. Kinesis owns structured curves and their technical motion derivatives. A pose
observation is not a motion clip; a rig is not proof of compatible animation; moving pixels are
not reusable curves; and a clip is not an engine controller or an authorized world effect.
`KinesisJob@2` acts on finite admitted material and returns a typed `MotionAssetSet@1` or, for
validation, `MotionFindingSet@1`; later live motion requires a separate `LiveKinesisSession@2`
with bounded queues, clock and calibration epochs, drop policy, consent, retention, and consumers.
Neither contract inherits source capture, creative acceptance, engine, avatar, robot, or
publication authority.

A portable Form assembly remains spatial material rather than a playable engine world. Foundry
owns engine-native scene hierarchy, placements, collision and physics meaning, navigation,
streaming, animation-controller use, gameplay bindings, scenario evidence, and build derivatives.
Import or a beauty render proves none of those facts.

## Custody before sight

Prism begins with source bytes already owned by the Reliquary. Their durable reference binds
identity and SHA-256 digest, media type and byte size, classification and owning Principal, and
custody and retention policy. A future materializer must recheck authority on every read.
`ArtifactRef` itself supplies neither byte custody nor a bearer token; a provider URL supplies
neither durable custody nor permission.

The [first Reliquary custody profile](06-persistence.md#reliquary-custody-designed) compares the
complete retained reference before materialization, including identity and classification as well
as digest, media type, and size. Owner and trusted acquisition attribution remain separate from
producer claims. Quarantine inspection requires different authority from an admitted read.
Echo's PCM inspector is the first bounded consumer; its structural result grants no admission,
speech eligibility, or visual/provider compatibility. A separately authorized trusted handler
admits only the exact retained bytes.

Decoders receive hostile input. Admission bounds supported formats, dimensions, frames, pages,
geometry, vertices, faces, nodes, materials, textures, scene depth, animation channels, bone
influences, points, splats, voxels, archive expansion, decompression, metadata, and parser or
compute resources. Media-type labels are claims to verify. Embedded links, external URIs,
profiles, scripts, drivers, plug-ins, scene procedures, and metadata receive no network or
execution authority.

## One optic path

```text
admit source → authorize materialization → inspect and decode → admit declared transform or effect
→ resolve an exact finite tool or dispatch an eligible provider → retain grounded observation or derivative
```

Each Prism Lens transformation records its exact parent, operation and implementation revision,
parameters, result artifact and digest, and loss from crop, resize, compression, frame selection,
or color conversion. The source remains available according to retention policy; a thumbnail,
OCR result, or caption cannot silently replace it.

Provider adapters may use Pydantic AI `BinaryContent`, Base64, a tensor, or a provider handle.
Those are request representations, never the universal artifact format.

## Dispatch, egress, and result

A Pattern asks for an exact semantic interface, operation, typed material, and feature facts.
Current v1 can only project general analysis as `vision` plus `image` and general reasoning as
`chat` plus `image`; precise Sight, Scanner, Lens, Image, Video, Form, and Kinesis work requires its
own declared service or tool contract. Generated visual output never arises merely because a chat
capability accepts visual input. The
[Dispatcher](22-dispatcher.md) admits only an eligible capability.
For an otherwise eligible managed binding that is not `WARM`, Dispatcher returns
`HardwareTransitionRequired`; the requesting Run enters Graph Stasis while
[Orchestrator](23-orchestrator.md) converges readiness, then re-dispatches. In current source,
however, even a `WARM` v1 `vision` declaration fails closed at grant issue because no typed visual
surface exists; readiness convergence cannot manufacture one. A live pause need not become a
Reanimation boundary. Prism cannot evict a provider, revoke a lease, raise priority, or infer
remote fallback.
Declared coexistence and measured operator evidence, not a universal VRAM formula, decide whether
visual and reasoning providers can remain resident together.

A Portal additionally needs source-and-derivative classification eligibility, explicit egress
policy, consent where required, and a cost bound. A caption cannot launder restricted pixels;
[Security](09-security.md#portal-privatization-and-egress) evaluates every source and derivative.

A grounded observation names the source and derivative chain; relevant page, frame, time, or
region; task; producing provider or deterministic revision; output; and suitable uncertainty. It
also says whether it is extraction, deterministic geometrical measurement, learned estimate, or
interpretation. OCR is attributed extraction, a caption interpretation, and generated or edited
image, video, audio-video, mesh, scene, voxel, or structured-motion material a new artifact set
with effect provenance. Fluent output never becomes source truth, and conversion between spatial
or motion representations creates a new derivative with declared loss.

### Compound media and application acceptance

Synchronized audio and video from a provider belong to one technical attempt and one compound
provenance parent. Before execution, `MediaFacetAuthoritySet@1` names every requested semantic
role, its owning Composition identity and revision, and the exact owner-request digest. Prism
records the container, stream digests, shared timebase and technical settlement.

Each declared owner then issues its own `SemanticFacetAdmissionReceipt@1` before that facet may
enter application truth:

- Atelier judges visual and VFX material;
- Riffmaw judges music;
- Language Edition judges timed-language material;
- Foundry judges interactive world sound; and
- Broadcast judges picture-bound sound and the final editorial audiovisual relation.

An undeclared facet fails closed. Inseparable streams must be accepted or refused for their
declared compound use. Neither the provider's output shape nor a `generate_sound` flag supplies
an owner's judgment.

## Consequences and acceptance

Keeping a result connected to its source lets Prism compose vision, multimodal chat, OCR,
transforms, and generation. That continuity brings explicit costs: custody, safe decoding,
derivative storage, retention, and provider loss all remain part of the contract.

It cannot move beyond the current schema seam until focused evidence proves upload and custody,
principal-bound materialization, hostile-media limits, transform lineage, modality forwarding,
local and Portal policy, provider conversion, grounded results, retention/deletion, and failure
recovery.

---
title: "37. Audio"
plain_name: "Design rule 37: Voice and audio"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/37-audio/
guide: https://lychd.snayu.ai/docs/adr/37-audio/
---

# 37. Audio (Design rule 37: Voice and audio)

## Plain-English summary (Snayu)

**What it is:** Defines Voice (Echo): speech-to-text and text-to-speech treat audio as a timeline with capture consent, privacy, interruption and delivery tracking, rather than as text with an attachment.

**Why it matters:** Read this before building voice input, transcription or speech output.

- Capture, transcription, synthesis and playback are separate events with their own evidence.
- Transcripts keep source, time regions, provider and language assumptions.
- Local stop and safe bypass must work without the model's cooperation.

**Status:** Partial. Schemas and engineering probes exist; no native speech path ships.

## Original text (Hexanomicon)

!!! abstract "Context"
    Speech has a timeline. Capture may precede a word, synthesis may succeed while delivery fails,
    and interruption may race with both. Treating audio as text with an attachment erases consent,
    privacy, and reception.

## Status

Audio admission is **Partial**. The current v1 compatibility spine can carry immutable audio
`ArtifactRef` metadata, express audio input through `modalities_in`, and declare `stt` and `tts`
capability families. Media-type projection to input modality remains Designed. Those labels prove
schema only, not a working transcription or synthesis call.

A pure Echo inspector also checks supplied bytes against an exact artifact reference and the
bounded PCM subset below. The separate explicit local Reliquary adapter can retain supplied WAV
bytes in quarantine. A trusted Echo consumer reruns the inspector, requires separate admission,
and reads under current authority. These unregistered helpers supply no capture or speech path.

An explicit engineering probe can inspect and send canonical WAV to pinned local audio.cpp or
whisper.cpp transcription bindings, retain attributed transcription or generated audio.cpp WAV,
and optionally capture a finite
utterance through a separately invoked Linux recorder helper. Explicit Horizon and companion lab
entries can select bounded local playback after capture, with owned player-group settlement and
distinct player-exit facts. These helpers issue no native speech grant or playback receipt.
Bridge does not forward audio modality into dispatch. No
credential-backed audio admission, speech timeline, streaming transport, native STT/TTS grant,
selectable Echo extension, or Audio Coven ships. [State of
Work](../state-of-the-work.md#audio-admission) owns this boundary and the
[local custody limits](../state-of-the-work.md#artifact-reference-contract).

## Decision

**Echo** owns the speech lifecycle. Its first profile, **record and send**, begins with one
explicit, bounded utterance. The utterance becomes an immutable artifact before an admitted
provider returns text or another audio artifact.

| Role | Contract |
| --- | --- |
| **Ear** | `echo.transcribe@1` transcribes bounded audio; current v1 projects the `stt` family. |
| **Voice** | `echo.synthesize@1` synthesizes bounded speech; current v1 projects the `tts` family. |
| **Audio-capable Mind** | A `model.chat@1` profile declaring audio input/output; current v1 projects `chat`, and it remains chat. |
| **Listener** | Device capture, codecs, and optional voice-activity detection. |
| **Mind** | Ordinary reasoning; speech creates no separate reasoning identity. |

There is no `audio` capability family. Audio is material; current `stt`, `tts`, and `chat` are v1
compatibility families, while the Designed general-service path uses exact interfaces, profiles,
operations, and call/session grants.

## Engine, model, protocol, and language

Speech integration keeps four axes separate:

| Axis | Owns |
| --- | --- |
| **Engine/runtime** | Execution of explicitly supported model families on declared CPU or accelerator backends. |
| **Model profile** | Exact checkpoint or voice, digest, capabilities, languages, license, and measured resource envelope. |
| **Connector dialect** | Request, response, health, discovery, and cancellation shapes exposed by one endpoint. |
| **Language policy** | Ordered input and output preferences, explicit request overrides, detection permission, and fallback behavior. |

A shared file format or OpenAI-compatible route does not make an unknown model architecture
loadable. Engine support means that the exact family has a loader, preprocessing, decoding, and
tested execution path. Likewise, two servers exposing `/v1/audio/transcriptions` or
`/v1/audio/speech` may accept different fields and provide different streaming or cancellation
semantics; each admitted endpoint declares and proves its dialect.

The first planned local engine profile is **audio.cpp** behind the bounded OpenAI audio batch
subset. It is one initial runtime choice, not a new universal audio abstraction and not evidence
that every audio.cpp family works. Its Rune must pin the runtime revision, model family,
checkpoint and digest, backend and device, declared and verified languages, license, and the exact
`stt` or `tts` behavior admitted by a bake. The engineering qualification probe may explicitly
select a separate pinned whisper.cpp transcription binding while retaining audio.cpp synthesis.
Each operation owns its endpoint, runtime revision, dialect, model identity and language policy;
a common HTTP route does not merge their provenance. Existing single-runtime profiles retain
their original identity. This additional probe binding grants no native Ear or Voice admission
and permits no automatic runtime fallback. Echo owns the current candidate models and promotion
criteria; native delivery remains Not yet.

Language is neither a host-global switch nor a property inferred from the engine. An explicit
request language wins, then the admitted Principal or Persona preference, then model-supported
detection when policy allows it. A model may route a language only after declaring it; a
**verified** language additionally passed the relevant LychD bake. STT detection never silently
authorizes translation, and TTS may not substitute another language or voice when the selected
output locale is unavailable. Translation is a separate semantic act.

Altar interface locale is independent of this speech policy: a Slovak interface may capture an
English utterance and request a Japanese Voice, provided each exact step is admitted. Musical
lyrics, singing, arrangement, and musical acceptance belong to Riffmaw rather than Echo; they reuse
the same no-global-language and no-silent-translation law without turning a song generator into
TTS.

[Language Edition](../compositions/language-edition/index.md) owns an attributed timed-media language edition: aligned
source and target words, casting, performance direction, dialogue timing, caption fit, and
acceptance of a constrained language-track replacement. It may place STT, Translation, and TTS or
human-performance steps in one Pattern, but that orchestration does not make Echo the application
or Translation an ambient feature. Language Edition may alter only declared language tracks against a locked
master; Broadcast retains editorial recutting, final assembly, and publication.

## Capture and custody

An explicit engineering qualification probe may exercise the selected local runtime before a
native Ear or Voice is admitted. Its fixed literal-loopback dialect, model identity, bounded
inputs and outputs, private external workspace and cancellation limits must be explicit. Such a
probe issues no Animator grant, registers no ambient provider or extension, and cannot establish
Bridge audio admission, Resonance Session delivery or remote-egress authority. It exists to
measure the exact binary/model pair and supply evidence for those later boundaries. The
[local qualification contract](../sepulcher/extensions/echo-local-probe.md) owns its operation.

Capture authority is explicit, visible, time-bounded, and revocable. Consent to one utterance is
not permanent microphone access; device indicators and server state must agree whether capture is
armed, active, stopped, or failed.

Voice cloning is not implied by TTS support. A cloning request separately binds the authorized
speaker or source, reference-audio custody, permitted words and use, model and license, and the
derived voice artifact. A convincing result grants no Persona, Principal, or attribution
authority.

Reliquary custody binds recording or synthesis identity, digest, media type, byte size, validated
duration/codec facts, classification, Principal, retention, and derivation from recording,
transcript, or request. Bytes never enter a Graph checkpoint, queue payload, event envelope, or
log—only references and bounded timeline state do. Decoders and transcoders treat them as hostile:
format, duration, channels, sample rate, decompression, parser resources, and metadata are bounded
before provider use.

### Bounded PCM inspection

Echo's first local material-inspection contract accepts supplied immutable bytes and an existing
`ArtifactRef`. It checks the exact byte length and SHA-256 digest against that reference; it neither
retrieves the artifact nor establishes custody or permission to use it.

This first subset is deliberately exact: `audio/wav`, a 44-byte RIFF/WAVE header with a 16-byte
PCM `fmt ` chunk immediately followed by one `data` chunk, signed 16-bit little-endian samples,
one channel, and 16,000 frames per second. The RIFF length, data length, byte rate, block alignment,
and sample width must agree with the actual bytes. Accept 1 through 480,000 complete frames
(up to 30 seconds) and no more than 1 MiB in the supplied artifact. Refuse ancillary chunks,
extended headers, compression, trailing bytes, truncation, empty data, and other WAV variants;
there is no implicit conversion or resampling.

A successful inspection returns immutable source and PCM facts. It establishes only that these
bytes match this reference and this structural subset. Silence is valid PCM; inspection proves
neither speech, origin, consent, semantic eligibility, model compatibility, nor an executed
transcription. Construction of a facts record alone does not prove inspection. This boundary
starts after a caller has obtained bytes; it does not bound an upstream upload or retrieval.

## Record, send, account

```text
explicit capture → immutable source artifact → eligible Ear or audio-capable Mind
→ attributed transcript or native observation → ordinary Agent step → optional Voice
→ delivery receipt
```

A transcript retains source, available time regions, provider and revision, language assumptions,
and uncertainty; it interprets a recording rather than replacing it. Synthesized audio is a new
artifact. “Generated” says bytes were produced, not that a client received, buffered, played, or
completed them.

When speech is required, the admitted Pattern's finish policy declares the required result,
the evidence needed to settle it, and any explicitly configured accepted fallback. Failure or
missing evidence at that required boundary produces partial or non-completion under the pinned
score unless an explicitly admitted fallback is fulfilled. Preserved text does not fulfill a
required speech obligation; text-only completion is permitted only when that fallback was
explicitly admitted. An observed playback completion establishes the reported playback boundary,
not that the person heard or understood the response.

The Pattern supplies exact interface/operation, material facts, classification, priority, and
authority. The [Dispatcher](22-dispatcher.md) chooses an exact Ear, Voice, or Mind profile; current
v1 can express only the `stt`, `tts`, or `chat` compatibility projection. For an otherwise eligible
managed binding that is not `WARM`, Dispatcher returns `HardwareTransitionRequired`; the requesting
Run enters Graph Stasis while [Orchestrator](23-orchestrator.md) converges readiness, then
re-dispatches.

In current source, even `WARM` v1 `stt` and `tts` declarations fail closed at grant issue because
neither has a typed call surface. Readiness convergence cannot turn those labels into Ear or Voice.

Echo may not preempt, revoke another grant, make its own continuing session, or silently select a
remote provider. A Portal needs egress eligibility, consent where required, and a cost bound. Local
execution still requires capture, retention, and tool authority; source influence persists under
[Context privatization](21-context.md#privatization-and-the-privacy-cut).

## Streaming without pretending a socket is a protocol

Record-and-send establishes the minimum passage. Half-duplex can then stream one response after
capture closes. Full-duplex requires more: simultaneous capture and playback, VAD, barge-in,
echo cancellation, and contested turn ownership must all be accounted for.

Voice-activity detection answers whether speech is present; it does not prove that an activation
phrase was spoken. The first profile therefore uses visible push-to-talk. A future wake-word
backend belongs to the Listener and emits a bounded activation event; it is neither an `stt`
Animator nor ambient permission to retain or transcribe surrounding audio.

A **Resonance Session** keeps one monotonic timeline for segments and attempts: capture
armed/active/stopped/failed; transcription and synthesis in progress/settled/generated; delivery
offered/accepted/failed; playback started/completed/interrupted/unknown; and cancellation, expiry,
or retry. WebSocket, WebRTC, or another transport can carry these records but supplies none of
their semantics. Reconnect resumes by acknowledged sequence and artifact identity, never by
guessing from a live socket.

Cancellation names its scope: stopping playback need not erase an artifact, revoking capture stops
new input, and cancelling an Invocation settles every admitted provider and transport attempt.
Closing local result adoption or a transport connection does not prove that provider execution
stopped. After submission, retain execution ownership until completion or an owned stop and
reconciliation proves settlement; uncertain execution cannot authorize a retry or release a
compute reservation. Late output may settle execution while remaining ineligible for adoption.
A future [Companion](../compositions/companion/index.md) client can own physical capture, playback,
route selection, and low-level device state; a private Tether still supplies transport, not
application authority, classification, or consent.

## Application-owned live audio

Echo's Resonance Session owns speech chronology. Applications retain their own records over
that chronology: [Riffmaw](../compositions/riffmaw/sessions.md) may own a musical performance
session and clock overlay, while Language Edition may own a language-edition timeline over exact
speech attempts. Neither duplicates the capture, synthesis, delivery, or playback ledger. Every
live route still follows Audio custody, transport, interruption, and uncertain-playback law;
Echo does not absorb every application that carries sound.

[Avatar](../compositions/avatar/index.md) may use an authorized exact voice profile or derived
artifact inside one profile or Morphe. Avatar can narrow purpose, audience, words, disclosure,
retention, and revocation, but cannot create speaker authority, copy a Persona, widen the cloning
grant, or claim that synthesized speech was played. Echo retains those lifecycle facts. Language Edition may
cast the same eligible reference for one exact language edition, but owns only role fit,
pronunciation, timing, disclosure, and performance acceptance; it cannot widen either Avatar's
presentation envelope or the underlying performer and voice-use authority.

Monitoring, recording, retention, analysis, transformation, remote transmission, and machine
response are independently admitted scopes. A visible armed input proves none of the others. A
live route binds an exact route and clock epoch, monotonic and sample-frame mapping, sequence,
scheduled window, absolute deadline, cancellation fence, and output acknowledgement. Late or stale
frames are rejected locally after expiry, disconnect, cancellation, or epoch change; a restarted
device, peer, model, or plug-in requires reconciliation and a newly admitted live Invocation.

The realtime callback never waits on a model, disk, network, control-plane action, or unsafe
plug-in operation. Declared direct or otherwise safe monitoring, output limiting, feedback
protection, safe bypass, and immediate local stop remain available without model cooperation.
Model and planning work occurs outside that callback and may emit only through the deadline fence.
PCM, MIDI streams, device handles, and plug-in state never enter Graph checkpoints or events; only
artifact references, bounded sequence state, epochs, and receipts cross the durable seam.

A tempo or phase protocol does not establish audio transport or a shared sample clock. A remote
audio link does not establish recording consent. Each application records mappings, clock-rate divergence,
resampling, loss, jitter, latency, discontinuity, and uncertainty rather than naming two devices
“synchronized” by assertion.

## Consequences and acceptance

Independent Ears, Voices, Minds, and Listeners can compose because Echo keeps generation,
delivery, and playback distinct. Doing so requires sensitive custody, storage and retention,
and explicit handling of timing, cancellation, and egress races.

Bounded material inspection can be accepted through actual byte-parsing and refusal tests without
claiming a speech runtime. Usable record-and-send execution additionally requires evidence for
visible capture consent, custody, hostile-audio limits at acquisition and decoding, modality
forwarding, local and Portal policy, STT/TTS conversion, transcript provenance, delivery/playback
receipts, interruption, retention/deletion, and disconnect recovery.

---
title: "38. IAM"
plain_name: "Design rule 38: Identity and access"
section: "Covenants"
status: "Partial"
original: https://hexanomicon.dev/adr/38-iam/
guide: https://lychd.snayu.ai/docs/adr/38-iam/
---

# 38. IAM (Design rule 38: Identity and access)

## Plain-English summary (Snayu)

**What it is:** Defines the Security Desk (Ward) as the single authority for who someone is and what they may do: principals, users, credentials, sessions, ID Badges (Sigils), roles and grants, all starting with zero power.

**Why it matters:** Read this before adding login, remote access, permissions or multi-user features.

- New principals start with no power; network location, proxy headers or VPN membership never grant authority.
- Today only a local loopback password gives the fixed operator badge; it is never a remote credential.
- Permission is checked again when an effect happens, so revocation takes effect.

**Status:** Partial. State of Work: local operator access works; remote IAM is still Designed.

## Original text (Hexanomicon)

## Context

The contained loopback surface requires a dedicated local HTTP Basic credential before assigning
one fixed `magus:*` Sigil. It proves possession of the operator's local credential and exercises
scope grammar and guards; it cannot serve remote people, services, peers, or owned nodes.
Remote use needs one authority that can identify a presenter, validate its evidence,
decide its requested object and action, and remain current when an effect occurs.

## Decision

LychD adopts the **Ward** as its singular Core-coupled IAM and authorization authority. New
Principals start with zero power; network arrival, proxy headers, mTLS, and tunnel membership may
be evidence but never application authority.

| Record | Office |
| --- | --- |
| **Principal** | Immutable identity of a human, service, peer, or owned node. |
| **User** | LychD's shared human-account abstraction bound to a human Principal, not an application-specific person record. |
| **Credential** | Revocable proof bound to one Principal, issuer, protocol, audience, and lifecycle. |
| **Session** | Authentication continuity, distinct from a Principal, Sigil, Grant, or Bridge conversation. |
| **Sigil** | Secret-free request/Run context carrying Principal identity and bounded claims. |
| **Role** | Named policy bundle that may help evaluate authority; never an ambient object grant. |
| **Authority Grant** | Current decision over Principal, action, object, audience, lifetime, policy generation, and delegation chain. |

A Sigil propagates attribution and bounded claims. It is not a bearer secret, and its historical
scope bag is not current authorization. Roles cannot turn route access into ownership of every
object served there.

## People, accounts, and instances

An instance may serve one person, a family or household, an organization, or another group.
Several people or organizations can share it under explicit access and sharing policy; one
person or organization can also use or operate several instances. These are use contexts, not
exclusive runtime modes. No organization or tenant is required for every installation.
Single-user operation is the smallest case rather than a one-person-per-instance invariant.

Ward owns the common User account and its binding to a Principal; Compositions reference that
identity while retaining their own domain records and policies. A represented person, such as a
care recipient or employee, need not have an account. Linking that record to a User does not itself
grant access. A person may use only a client of a shared instance and need no LychD of their own;
an enrolled device or service remains distinct from the human for whom it acts.

Enrollment and authorization are local to the receiving instance. The same human may have
different accounts, roles, and working interfaces in personal, household, and workplace instances.
Shared names, organization membership, or a common operator do not link identities or transfer
credentials, grants, memory, or trust automatically. Sovereign task delegation between instances follows
[A2A](26-a2a.md); adding Users is neither A2A nor [Legion's](42-multinode.md) distribution of one
control plane across physical nodes.

Groups and organizational memberships may supply explicit policy relationships without replacing
individual attribution. Direct Principal assignments remain possible without either. Several
Principals may receive the full administrative powers defined by an installation, using separate
credentials. Policy must state whether those powers include content access or the ability to
change access policy. The trusted host operator remains distinct from an application administrator;
shared use does not promise isolation from that operator or from trusted in-process extensions
under [Security](09-security.md).

## Profiles and working interfaces

A user-facing profile may combine permission assignments with application defaults and named client
views. Users of one installation may therefore receive different apps, screens, navigation,
workflow views, and approval controls. Ward still decides access to each protected surface,
record, and action. A durable profile or Role assignment informs that decision without becoming
a perpetual Grant, and permission to open a screen grants no blanket access to its objects.

Compositions own the meaning of their working views and application policy; Products may package
them. [Spellweaver](28-workflow.md) owns the admitted score and workflow state, not User accounts or
screen layout. An offered action must satisfy both current authorization and the workflow's
declared state and transition rules. A presentation profile cannot silently rewrite a Scroll,
widen its authority ceilings, or change a running Invocation.

Clients render the authorized projection for the selected account, instance, work context, and
device capabilities. Restricted data must be excluded before delivery, not merely hidden in the
client. [Frontend](15-frontend.md#user-specific-working-interfaces) owns browser projection; mobile
experiences such as [Companion](../compositions/companion/index.md) use the same identity boundary
without becoming the global profile authority. Application-specific actions, resources, and policy
inputs require explicit Ward integration; package registration alone grants no such integration.

## Admission and effect-time authority

For every protected request, Ward validates credential protocol, issuer, audience, expiry, replay
defence, revocation, and assurance; resolves one enrolled Principal; mints a secret-free Sigil
from trusted local state; authorizes route and named object in one ownership-aware query; then
records credential, policy, and revocation generations. Unknown credentials, unresolved
Principals, and caller-supplied identity or scope headers receive no authority.

Before a tool or side effect runs, its owning handler checks current Principal, action, object,
assurance, delegation, consent or preauthorization, policy generation, and revocation epoch
again. Agent-visible tools can be narrower than the Grant; their handler remains authoritative.
Worker claim, Stasis resume, consent resume, queued work, and deferred peer work may not reuse a
stale scope snapshot.

## Objects, delegation, and revocation

Persistence queries enforce the owner or explicit sharing policy of sessions, Runs, consents,
streams, artifacts, memories, tasks, leases, and administrative records. An unrestricted read
followed by result filtering is too late. Shared memory needs an explicit relation with purpose,
audience, retention, and revocation; sharing a model or database grants no access.

Delegation records issuer, delegate, audience, scope, object, expiry, depth, and revocation.
Revocation invalidates credentials, sessions, cached grants, and affected sleeping or pending work;
recovery starts at zero authority. Neither a universal remote Master token nor ambient fallback is
permitted.

Typed credential adapters may verify passkeys, API credentials, signed peer envelopes, client
certificates, or later protocols. They do not mint local Sigils or compete as policy authority.
Extensions cannot remove Ward from a protected route, create a universal Sigil, or turn
peer-declared scope directly into local power. Audit retains the admitted evidence and decision
generations without exposing credential secrets.

## Host-enrolled candidate profile

The inactive `host-opaque-candidate@1` service foundation admits explicit trusted-host
composition only. The host supplies the existing Phylactery session factory and stable issuer
UUID; it alone enrolls immutable human/service/peer/node Principals and changes exact assignments.
A human enrollment creates a distinct shared User relation. Enrollment creates no permission.
No application route, middleware, browser or existing Bridge conversation selects this profile.

An enrollment returns a freshly random 256-bit opaque credential once. PostgreSQL retains only
its SHA-256 digest, exact issuer/protocol/audience, lifetime and revocation generation. A successful
one-time exchange creates a separate random authentication Session secret and marks the credential
exchanged under the Principal lock. Session tokens are bearer possession evidence within their
bounded lifetime; they do not authorize an object by themselves. Unknown credentials, issuer or
audience mismatch, expiry, repeated exchange and revocation refuse. The host must retain secrets
in its credential owner; this service does not read an ambient credential or repair a lost token.

Each protected publication freshly resolves the Session, Credential and Principal, then queries
one exact subject/action/candidate UUID/audience/purpose assignment. Assignments permit only
candidate inspect, admit, read or decide in this namespace; they do not authorize actual custody,
adoption, repository writes, activation or an existing application object. Policy changes advance
the Principal policy generation; mandatory expected-generation binding fences prepared work.
Principal, credential and Session revocations are monotonic, and no cache or historical Grant
can bypass fresh resolution after restart.

This profile requires actual transactional PostgreSQL/asyncpg READ COMMITTED operation. Each
Session must bind every Ward model to one AsyncEngine; pre-bound AsyncConnection and differing
Ward model binds refuse. Before application SQL, admission checks the checked-out DBAPI connection
is not in AUTOCOMMIT, then checks `SHOW transaction_isolation` is exactly `read committed` and the
actual asyncpg connection is inside a server transaction. Other or unknown states refuse. SHOW
alone is insufficient in AUTOCOMMIT, where row locks immediately release. Admission changes neither
caller engine configuration nor transaction isolation. This statement-snapshot prerequisite
allows child Credential/Session reads after acquiring the Principal lock to see revocations committed
while discovery or lock acquisition waited. REPEATABLE READ can retain a snapshot from the earlier
Session lookup even if locking an unchanged Principal succeeds, so it is not admitted here.

All these operations serialize on the permanent Principal row. After outside preparation,
publication first commits a uniquely identified `publication-attempt` in Ward's existing audit,
bound to the issuer, actual identities/generations and exact requested operation/policy generation.
An eligible attempt starts with unknown outcome. That transaction ends before a second transaction
reacquires the Principal lock and freshly checks all current evidence and database-clock expiry.
Only then may a trusted synchronous callback immediately hand off its projection without yielding.
Revocation or policy change between transactions prevents that handoff and retains refusal.
The attempt identity appears in callback attribution and error notes; it supplies no permit,
resume operation, deduplication or retry authority.

Eligible attempts conservatively remain unknown even when the callback returns: this seam has no
delivery oracle. Callback, commit or acknowledgement failures preserve the original exception and
retained attempt without implying that disclosure did not occur. No rollback can erase the initial
acknowledged attempt. A failed initial audit commit permits no handoff; acknowledgement loss can
still leave an unknown retained attempt. No exactly-once effect or automatic retry is admitted.

The same callback contract runs before preparation and at the store boundary. Detectable coroutine,
async-generator and generator functions or callable-object methods refuse. A callback must return
None; a returned coroutine is closed and a returned Task/Future cancelled before yielding, and any
non-None result fails with unknown outcome. No asynchronous return is awaited. These checks catch
composition mistakes: arbitrary trusted synchronous code can still schedule hidden work, block,
or hand off before raising, and is outside hostile containment. The callback permits only immediate
in-process projection handoff, with no await, blocking I/O or external effect. Attribution remains
secret-free historical context. A future consumer must integrate its own owner/sharing-aware
content query and exact content/operation binding; this assignment query supplies no object bytes.

Fixed audit events retain identities, exact operation and generations without token or payload
bytes. No cleanup or token recovery is admitted. The migration locks all Ward tables and refuses
downgrade while any identity, assignment, Session or audit remains. This inactive local foundation
supplies no remote ingress, general IAM activation, physical containment or native receipt.

## Closed inactive candidate operation

A separately composed, isolated trusted-host candidate consumer may connect Ward to physical
custody. This is distinct from `publish`: the projection callback above retains its no-I/O rule.
The fixed consumer owns one private candidate store and serializes access and shutdown before
entering custody. Its transaction-scoped synchronous authorizer queries the same Ward predicates,
exact assignments, generations and database clock at every physical custody gate while retaining
the Principal row lock. SQLAlchemy's synchronous transaction bridge may yield for database I/O;
ordinary filesystem I/O deliberately blocks inline. This profile promises neither production
event-loop responsiveness, deadlines nor hostile containment. Detached attribution, worker-thread
handoffs and caller-supplied inspectors cannot replace the live transaction.

The consumer binds exact retained bytes, candidate UUID, known selection/closure plan and assigned
participants. Inspection, import, structural admission, case binding, assessment and decision have
separate exact purposes. Every operation binds its expected current policy generation. Its private
authorizer expires on exit and cannot be returned as a Grant. Actual custody and Creation receipts
own effects; Ward's conservative attempt audit remains attribution with unknown outcome. There is
no shared filesystem/database transaction or automatic replay after uncertainty.

Native assessments require an assigned Principal distinct from the proposer. Creation retains
current-authorized attribution with the exact assessment/decision body. Only inactive hold/reject
decisions are admitted; no source write, executor, positive OwnerAdmission or activation follows.
Changed bytes, selection, policy, roles or custody identity invalidate affected preparation.

## Trusted local custody 

The Designed [Reliquary profile](06-persistence.md#reliquary-custody-designed)
`same-host-trusted-bootstrap@1` accepts a subject only from trusted host composition. It requires
a mandatory injected current authorizer for import, quarantine inspection, admission, read, hold,
hold release, and deletion. Each decision names the actual subject, store and object, complete
record binding, trusted owner, action and purpose. The query also carries the typed subject of
that action: the import proposal, proposed hold UUID and reason, exact retained hold and digest
for release, admission evidence, or deletion request and hold-release basis. A policy must be
able to distinguish two holds on the same artifact; an action label and opaque digest alone do
not identify what it is allowing. There is no permissive fallback from Sigil name, scope bag,
ownership alone, network location, or caller identity headers.

The protected operation completes any awaited preparation before its final authorization check.
Under its serialized operation boundary, it checks authority immediately before admission or
tombstone publication and before handing bytes to a consumer. Prior receipts are audit evidence,
not reusable grants. Revocation or a changed decision during preparation must prevent disclosure
or the protected mutation.

This is a local composition seam, not a second IAM service. It enrolls no credential and supplies
no Ward session, remote authentication, delegation or deployed revocation service. Substituted
authorizers in tests establish consultation and refusal behavior only; they do not prove
credential-backed authority or containment against hostile same-UID code.

## Trusted local Archive profile

The opt-in `local-public-notes@1` Archive profile admits one explicitly configured namespace and
public notes only. Trusted host composition supplies a stable local subject and a mandatory current
authorizer. Every operation binds the actual subject, retained owner, namespace, purpose, action,
policy revision, and exact proposed or retained object digest. Public classification, ownership,
loopback arrival, or a Sigil scope bag does not supply a permissive fallback. The authorizer is
consulted before protected reads, after awaited preparation under the serialized namespace
boundary, and immediately before handing a retained projection to a consumer. Old receipts are
evidence, not reusable grants; restart injects a current authorizer again.

This is an explicit trusted-host composition profile, not credential enrollment, remote Principal
resolution, a Ward session, cross-namespace sharing, or isolation from trusted same-process code.
An unconfigured profile has no Archive authority. The separate read-only Bridge revision can
consume authorized notes but grants no model tool or effect authority.

Optional local derivation requires separate generation-registration, generation-retirement,
derive and status actions with dedicated purposes. Recall or ingestion permission alone does not
authorize embedding. Authority binds the configured generation and exact source/attempt identity;
post-commit response refusal does not claim rollback. Status contains no text, vector coordinates
or live token and can report an invalidated historical reference under current authority.

Source eligibility linearizes under the shared namespace lock. Current authority is checked again
after database cleanup and before each tokenizer/embedding request. No lock spans inference, so
later revocation cannot retract accepted source bytes; it does atomically invalidate controlled
vectors and fence late completion. A caller-supplied Run UUID is attribution, never a Run grant,
relationship assertion or authority to emit events into that Run.

## Trusted local Scout profile

The Designed opt-in Scout profile binds one authenticated local operator to a host-owned subject
and authentication generation in the single control process and event loop. Its mandatory current
host authorizer separately decides public-locator classification, review disclosure/judgment,
Fetch, Extract and transient material consumption. Every decision binds the actual subject,
retained Run and request, exact preparation, purpose, policy revision, revocation generation,
expiry and applicable budget. Neither a caller-supplied Run UUID nor a matching Sigil name/scope
bag supplies authority. [Security](09-security.md#target-and-disclosure-basis) owns the declaration
and disclosure basis; [Scout](30-webcrawler.md#attempt-layers-and-crash-semantics) owns attempts
and reservations. Raw acquired material remains transient, and this profile admits no remote
model inference.

A model-free feed consumer binds the exact admitted Composition/Pattern, application request,
projection and custody profile in place of a model demand. CONSUME is required for deterministic
filtering too; no placeholder capability makes it a chat action. Consumer result adoption, read,
re-filter and deletion require their own current application authority. Fetch/Extract grants or a
historical consent cannot supply those decisions. The old page binding/review remains unchanged.

After awaited preparation, a mandatory synchronous gate checks current authority, consumes the
finite reserved counters and hands off each actual socket connect/send without yielding between
check and handoff. DNS and TLS output cross this gate too. Policy updates and revocation serialize
with it on the same loop; a transport thread, separate worker or permissive transport default is
outside this profile. Revocation fences later handoffs but cannot retract kernel-accepted bytes.

Run cancellation and shutdown synchronously fence affected attempts before awaited containment.
Observed worker failure first fences its exact retained delivery claim before any settlement
await; a stale worker cannot fence a successor's claim. A Run-wide failure fence follows verified
current ownership. Every fence is monotonic: completion of a cancellation election or a
failed database/broker operation cannot reopen it. Containment must then close owned sockets and
stop/reap children. A granted consent is historical judgment; the pending-only decision operation
does not revoke it. Withdrawal uses Run cancellation or current host-policy revocation. Restart
injects current authority again and never restores a live permit from a receipt.

This local composition seam supplies no remote Principal enrollment, Ward session, cross-process
revocation or isolation from trusted same-process code. Runtime activation remains Designed until
the complete assembly and its effectful refusal, revocation and recovery evidence are delivered.

## Outbound peer authority profile

The Designed [outbound public-text profile](26-a2a.md#peer-task-jsonrpc-1) introduces narrowly
enrolled peer Principals, credentials and current task authority under Ward. The local initiating
operator, local workload signing credential and remote result-verification credential are distinct.
Actual local password possession establishes the initiating marker; its public fields, Sigil,
endpoint, TLS certificate and a key repeated in a card establish no enrollment or permission.

Trusted host composition supplies one explicit bootstrap policy; empty or missing action,
purpose, content, task, peer or endpoint selectors deny. Enrollment, source classification,
submit, poll, cancellation/reconciliation, result consumption, rotation and revocation are
separate protected operations. Each checks the real current authentication marker before a
protected query and rechecks current exact object/action authority after awaits. The dedicated
public-text declaration binds complete text, source/influence facts, subject/authentication
generation, purpose, category, peer/task target and policy generation. It is an operator assertion,
not automatic declassification of inherited private material.

Peer identity is immutable. Credential versions retain issuer, protocol, audience, public-key
binding, validity, assurance and lifecycle; private key bytes remain in the trusted secret owner.
Acknowledged retirement and policy/revocation generations survive restart and cannot be rolled
back by configuration removal, reappearance or a new label. Rotation adds a version and never
re-enrolls a retired key implicitly. Missing or incompatible durable current state refuses.
An uncertain mutation is not reported as successful; the current owner remains fenced until its
retained outcome is reconciled. Restart begins without live grants and requires fresh current
bootstrap and operator authentication rather than restoring a historical marker.

The [native public peer profile](26-a2a.md#native-public-peer-station) separately protects Run
admission, adoption and resume. The host retains only live per-Run permissions bound to the actual
marker and immutable canonical source/task/target. Explicit fresh authentication may reauthorize
that same retained relation; a first send also reaffirms its exact original public source. It
creates no new semantic task, expiry, credential or capacity. Missing live permission pauses
contact and native resume. Trusted local cancellation always remains possible; it grants no
remote cancellation or reconciliation permission.
An independently authorized local-evidence inspection may show retained Run/task identities,
local closure and remote uncertainty despite a peer revocation or uncertain peer mutation. It
requires the actual current operator marker and explicit inspection selectors, returns no source
or result body, and grants no remote contact, result consumption, adoption or resume permission.

This first profile has one control process and event loop for policy mutation, network handoff
and result admission. Revocation fences local authority before awaiting persistence. The final
current policy, credential, task fence, expiry and finite budget check and each actual socket
handoff do not yield. No database lock spans the network. This proves no cross-process revocation,
hostile same-UID isolation, human account system, incoming-task IAM or public remote browser route.

## Thresholds and delivery

[Veil](40-proxy.md) owns hostile ingress and trusted-proxy canonicalization; [Tether](39-vpn.md)
owns private reachability. Ward authenticates and authorizes traffic arriving through either.
The credential-gated `magus:*` context remains confined to the same-host operator profile and is
never a remote credential. Its dedicated password is unavailable to shared-Pod model services;
rotation replaces that secret and restarts the Vessel. No cookie, network-origin header, or
unauthenticated bootstrap route supplies fallback authority.

This Covenant records **Designed** law. The inactive local candidate profile above supplies no
registered application service. Remote Principal enrollment, remote sessions, general object
authorization, delegation, tenant isolation and deployed IAM remain undelivered.
[State of Work](../state-of-the-work.md#remote-iam) owns the exact boundary.

## Consequences

A runtime can serve remote surfaces while keeping their records and powers separate. Maintaining
that separation requires Principal-aware repository and effect-handler tests, with revocation and
deferred-work reconciliation treated as lifecycle work. Tunnels, proxies, and provider SDKs
cannot substitute for application authority.

---
title: "39. VPN"
plain_name: "Design rule 39: Private network (VPN)"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/39-vpn/
guide: https://lychd.snayu.ai/docs/adr/39-vpn/
---

# 39. VPN (Design rule 39: Private network (VPN))

## Plain-English summary (Snayu)

**What it is:** Defines the Tether extension: a self-hosted WireGuard tunnel giving the operator a private road to the host. It provides reachability only, never permissions inside LychD.

**Why it matters:** Read this before setting up remote access over a VPN or touching network routes.

- Being on the tunnel grants no role, badge or permission; the Security Desk still authorizes every request.
- A private tunnel is not anonymity; it is not a consumer VPN exit or Tor.
- A failed private route must never silently fall back to an open one.

**Status:** Designed. No VPN provider, enrollment or peer registry is built.

## Original text (Hexanomicon)

!!! abstract "Context"
    A Magus may need a private road to the host without making administrative surfaces public or
    mistaking membership of that road for authority inside the Vessel.

## Decision

The **Tether** extension uses **WireGuard** for an operator-controlled, encrypted, self-hosted
private road. This layer supplies reachability only. Tunnel membership grants no application
role, Sigil, capability, or permission to a named object or effect.

Private reachability is not anonymous browsing. A tunnel can conceal destination traffic from
the access network while moving visibility and trust to its endpoint; traffic timing and volume,
endpoint addresses, browser fingerprints, accounts, and provider-held request content remain
separate disclosure surfaces. Tether does not currently define a consumer VPN exit, browser
anonymity profile, or Tor transport. An accepted future outbound privacy profile must name the
observer it protects against and prove DNS, IPv4/IPv6, direct-route and reconnect failure closure,
browser-origin isolation, and egress custody. It must never silently bypass a failed private route.
Remote model/CLI requests still disclose their transmitted content to the receiving provider,
irrespective of the road carrying it; [Security](09-security.md#portal-privatization-and-egress)
owns that disclosure decision.

The Tether may manifest a rootless service with only the network capability it needs and explicit
UDP publication. Interface name, listen port, address space, DNS behaviour, routes, and peer limits
are Rune-owned configuration, not hard-coded topology. Typed operations under a future host-owned
run-operation verb may generate a keypair, admit, inspect, revoke, rotate, or export a short-lived
client configuration or QR projection; it adds no root CLI verb.

If that service is projected through Quadlet, its future Rune may embed the code-level
`QuadletConfig` value under `quadlet`. That does not rename Tether to a kind of Stone, make it an
Animator, or grant generic unit-text authority; Tether keeps ownership of its exact network fields
and compilation policy.

The Tether service remains outside the shared application Pod. It receives no broad mounts,
application secrets, database credentials, or host-mutation channel; granting `CAP_NET_ADMIN`
inside that Pod is not an acceptable shortcut.

The optional [Gateway Host](../sepulcher/gateway.md) uses Tether only when placement requires a
private routed road. **Remote** may admit one exact peer and backend route from the off-site Veil to
Core; it receives no default route or ambient home reachability. **Home** needs no Tether merely
because Veil runs on a separate local machine: an exact directly routed private segment may supply
reachability while firewall and service authorization retain their separate duties.

## Reach deployment roads

The [Reach deployment matrix](../compositions/reach/deployments/index.md) selects Tether by exact
profile, not a trust toggle. Home-only and standalone outbound VPS use no Tether. Only
`reach.edge-home.public@1` requires one named VPS peer and the smallest route to a Tether-only
private Veil backend for typed event admission, delivery claim, settlement, and health. It receives
no default route or path to the home Phylactery, Reach core, Altar, model/provider API, Podman
socket, Reactor, or host administration. Tether custody contains tunnel keys only; the edge relay
keeps its disjoint workload credential and revoking one class never repairs another.

## Peer custody and exact routes

The Codex may retain stable peer identity, public key, allowed addresses/routes, endpoint and
keepalive policy, enabled/revoked state, and creation/rotation metadata. Private and preshared keys
are hydrated through the secret boundary and never rendered into ordinary documentation, logs, QR
history, or public peer records.

Each route must be explicit. Host firewall policy determines which listeners the interface can
reach, Veil may apply ingress policy, and Ward and Vessel still authenticate and authorize.
Database administration, lifecycle mutation, Oculus, audio, model APIs, and A2A stay closed until
their own policy admits the peer. A tunnel address, interface, peer key, or forwarded metadata
can contribute credential evidence but cannot mint `magus:*`, widen a Sigil, or create an
administrator.

## Lifecycle, failure, and recovery

Binding validates peer-address overlap, route conflict, key reference, port collision, and the
generated service contribution before inscription. Revocation removes the peer from the active
interface and persists revised intent. Rotation overlaps old and new credentials only with explicit
operator authorization. Versioned public peer/routing intent prevents restore or reconciliation
from reviving revoked or stale access; failure stays visible and privileged traffic never falls
back to a public route.

Dynamic addressing needs an operator-supplied reachable endpoint, whether through DNS, fixed
addressing, or a separately accepted rendezvous mechanism. Carrier NAT, blocked UDP, changing
endpoints, roaming, endpoint metadata, and traffic analysis remain concerns. Relay and NAT
traversal require separate trust decisions; recovery cannot introduce them invisibly.

## Delivery and consequences

This Covenant is **Designed**. No VPN provider, interface, enrollment, peer registry, key
rotation, route policy, health, or revocation path ships; generated deployment remains
IPv4-loopback-only, rejects UDP, and must not be tunnelled or port-forwarded. [State of
Work](../state-of-the-work.md#vpn-tether) owns that boundary.

Independent revocation is Tether's practical return. Operating that private road requires
security-sensitive peer and route management, backup, rotation, recovery, and an account of
uncertain direct reachability.

---
title: "40. Proxy"
plain_name: "Design rule 40: Reverse proxy"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/40-proxy/
guide: https://lychd.snayu.ai/docs/adr/40-proxy/
---

# 40. Proxy (Design rule 40: Reverse proxy)

## Plain-English summary (Snayu)

**What it is:** Defines the Veil extension: Caddy as an optional, separately managed reverse proxy handling TLS, certificates and routes for remote access, without becoming a second authority over the application.

**Why it matters:** Read this before exposing LychD beyond localhost or configuring domains and certificates.

- Without Veil, the server stays local; enabling it makes nothing public by default.
- Routes, ports, domains and certificates come from validated Service Config Files.
- Transport identity is never application authority; the Security Desk still checks every caller.

**Status:** Designed. No proxy provider, public listener or certificate lifecycle is built.

## Original text (Hexanomicon)

!!! abstract "Context"
    A remote entrance needs TLS, protocol handling, route composition, and certificate lifecycle
    outside the Vessel. It must not become a second authority plane or let one extension rewrite
    another's edge policy.

## Decision

**Caddy** is the default engine of the optional **Veil** extension. Without admitted remote ingress
the Vessel remains at its local boundary; enabling Veil makes no route public by implication.

Veil runs as a separately managed service, forwarding admitted routes over the local service
network to Vessel or another explicitly named backend. Validated Runes define ports, domains,
certificate issuer, backend identity, and transport policy. Port `80` may handle ACME challenge
or redirect, and port `443` admitted TLS, with collisions detected at binding. Internal or
offline deployments may use operator-provided certificates or a separately accepted internal issuer.

If Veil is projected through Quadlet, its future Rune may embed the code-level `QuadletConfig`
value under `quadlet`. Veil remains the Domain identity and owns its ingress fields and compiler;
it is not another Stone, Animator, or opening for raw Quadlet/systemd text.

## Gateway placement

Veil may share the Core host or manifest on an optional separate
[Gateway Host](../sepulcher/gateway.md). The Gateway is a deployment trust role rather than another
Extension Domain or Composition. **Home** places it on operator-controlled local iron and forwards
only to an exact private Core backend. **Remote** places it off-site and may use one Tether peer and
route to that same narrow backend. RPi and VPS are substrate and placement choices, not
architectural identities.

Both placements compile the same typed route contract and keep the same application authority
behind it. The Gateway receives only edge certificates, route material, one backend service
credential, optional tunnel material, and bounded transport evidence. Its firewall denies general
LAN and arbitrary egress only as defense in depth. Policy outside that host—a router/firewall,
L3-switch ACL, or cloud-network rule—plus the receiving Core firewall enforces the public listener
and exact declared Gateway identity and backend flow. It does not trust the Gateway host to preserve
its own rules. Same-host, Home, and Remote are selected by exact deployment profiles, never an
`ingress`, `gateway`, `rpi`, or `vps` toggle.

TLS termination gives Veil custody of the admitted route's plaintext, including headers and
credentials carried inside that transport. A second encrypted hop to Core does not remove that
custody. The route contract therefore binds permitted content classes, the authentication proof
visible at the edge, request/response logging and retention, and compromise consequences. A
Gateway forbidden private Context cannot terminate a route carrying it: that route stays closed
unless a separately accepted protocol keeps the protected payload and reusable application
authority encrypted end to end to Core. Edge signatures alone cannot independently authenticate
an end user after that edge is compromised.

## Reach deployment edges

The [Reach deployment matrix](../compositions/reach/deployments/index.md) selects exact routes, not
an `ingress` toggle. Home-only and standalone outbound VPS have no inbound application listener and
therefore no Veil. `reach.edge-home.public@1` binds a private home Veil only to its Tether address
and routes exact event-admission, delivery-claim, settlement, and unauthoritative-health operations
to an isolated edge adapter. It never exposes a public listener. A later callback-only profile may
route an authenticated update only to isolated Intercom ingress for one existing outbound task.
A full A2A server is a separate profile with its own Ward, inbox/outbox, Workers, quotas, and
result route.

The Reach VPS Discord edge is a platform adapter, not a Gateway Host merely because it is remote;
that profile's Veil remains the private home ingress named above.

Neither profile may forward hostile bytes directly to the Reach core, Discord edge, or outbound
credential gate. Every route names its methods, media types, compressed and expanded body limits,
time/stream ceilings, backend, exposure tier, authentication precondition, and adapter revision; a
wildcard path is forbidden. Veil receives edge certificates and routing material only, never bot,
provider, A2A application, corpus-write, database, or delivery authority.

## Compile the admitted ingress routes 

Core and extensions contribute typed route intent: host/route match, backend service and port,
protocol/streaming behaviour, body/timeout/header limits, application-authentication preconditions,
and permitted public, Tether, or local exposure tier. The compiler rejects ambiguous ownership,
overlapping exclusive routes, unknown backends, unbounded raw directives, and ports outside the
admitted service topology. It renders complete Caddy configuration in staging, validates it, then
inscribes transactionally. The Scribe owns the generated projection; contributions remain separate
and attributable.

## Caller authority at the backend 

Transport establishes an endpoint and protects bytes through TLS; routing selects a backend.
Caller authentication and effect permission remain with Ward and Vessel, which enforce Sigils,
Grants, consent, and rate policy. A2A keeps its own authentication and replay defence. Tether,
mTLS, forwarded metadata, Nostr, or another signature scheme may contribute evidence only under
its owner's authentication decision. None can mint a Sigil or administrator.

Veil may impose coarse connection, header, and traffic limits. It is neither full DDoS defence nor
application validation, and receives only a narrow path to registered HTTP backends—not database,
model, Reactor, systemd, container, application-secret, or arbitrary-egress authority.

## Certificate failure and delivery

Certificate state belongs in declared durable storage and account keys in declared secret
boundaries. Validate before every configuration/certificate activation; rollback restores the prior
generated projection. Renewal failure preserves the last valid configuration and degrades
readiness before expiry. Public ACME also needs a resolvable domain and reachable challenge path
or configured DNS provider. Without them, the public entrance stays unavailable while the local
Vessel continues. Reconciliation closes removed routes.

This Covenant is **Designed**. No proxy provider, public listener, certificate lifecycle, edge
compiler, hardening, or trusted-proxy policy ships. Generated deployment is IPv4-loopback-only and
the browser boundary is unsafe to publish: no ad hoc reverse proxy, tunnel, or port-forward may
stand in for the missing contract. [State of Work](../state-of-the-work.md#proxy-veil) owns the
delivery boundary.

Operating Veil adds certificate, DNS, firewall, abuse, and availability duties alongside its
dedicated remote-transport role. A loopback-only deployment avoids those duties.

---
title: "41. Toll"
plain_name: "Design rule 41: Payments"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/41-x402/
guide: https://lychd.snayu.ai/docs/adr/41-x402/
---

# 41. Toll (Design rule 41: Payments)

## Plain-English summary (Snayu)

**What it is:** Defines Toll, an optional payments area with two parts: a ledger for quotes, budgets and accounting, and a separate gate that performs one verified, hard-to-reverse settlement. Models and responses can never authorize spending.

**Why it matters:** Read this before adding paid APIs, budgets, credits or any money movement.

- No model, HTTP 402 response or routing choice can become spending authority.
- Budgets are reserved before spending to prevent double-spend; local credits come before payment rails.
- Each seller sets its own prices and currencies; there is no shared token or network-wide exchange.

**Status:** Designed. No payment package, ledger or settlement path exists.

## Original text (Hexanomicon)

!!! abstract "Context"
    Remote labor and local compute can carry cost, while money movement is difficult to reverse.
    A response code, model, middleware hook, or Dispatcher choice must never become spending
    authority.

## Decision

**Toll** is an optional economics Domain with two separated planes: a **Counting House** for quote
handling and accounting, and an **Irreversible Gate** for one independently verified settlement
effect. It is neither a mandatory wallet, global auto-payment interceptor, nor Agent authority.

Each selling operator owns its prices, accepted currencies, payment providers, and conversion and
payout arrangements. The vendor or its chosen payment provider handles any offered conversion.
Paid participation and remote casting require no shared currency, project-native asset, or
network-wide token allocation. A vendor may choose supported conventional or optional crypto rails;
that choice does not prescribe another vendor's prices, balances, or accepted assets.

Vendor choice does not establish a network-wide exchange or cross-vendor clearing service. The
buyer still needs a supported, funded payment route under exact spending authority. A quote or
local credit balance cannot authorize an implicit currency swap, substitute settlement assets,
or make another issuer accept the balance. Toll retains quote, budget, settlement, delivery,
refund, and reconciliation duties whichever payment route is selected.

A provider quote, invoice, or HTTP `402` can propose terms. It remains untrusted and cannot
authorize signing, settlement, retry, identity, access, or an increased budget. x402, L402,
Lightning invoices, Wallet Connect, Nostr Zaps, and future rails have distinct adapter contracts;
their names are not interchangeable.

Remote casting and teaching a missing Spell are distinct purchased resources. They cannot share a
quote or idempotency identity merely because one peer offers both. Payment satisfies neither peer
authentication, task admission, teaching quarantine, publication, activation, nor authority.

## Local credits first, rails later

The first practical topology is deliberately issuer-local. An operator may grant or sell
**MANA** service credits, or charge an exact request through one conventional payment provider.
MANA is an issuer-scoped entry in that issuer's durable Counting House ledger, not
cryptocurrency, cash, a bearer asset, a global currency, a governance vote, or a claim on another
issuer. An amount without its issuer is invalid. The initial profile is account-bound: unlike
issuers' balances are not fungible, and no cash redemption, peer transfer, or cross-issuer
conversion is implied. Changing any of those properties requires a separately admitted economic
and legal contract, not a configuration toggle.

Tithe meters model-token usage, generated media, concurrency, queue weight, hardware time, and
other resource consumption. The Counting House separately owns MANA balances, reservations,
debits, credits, refunds, and reconciliation. Only an issuer-authorized accounting boundary—not an
Agent, model, or ordinary tool—may issue, expire, or correct MANA. Every entry retains its authority
and grant reason or exact external funding identity; corrections append compensating entries rather
than rewriting history, while reservations prevent double-spend and negative available balance.

Only an independently verified settlement admitted under issuer policy may fund one exact local
balance or settle one exact pay-as-you-go request. Funding atomically and idempotently binds the
external-effect identity; a client claim, webhook alone, pending authorization, or ambiguous
settlement cannot create reusable credit. A sale retains purchase asset, amount, rate, terms,
expiry, and original funding identity. A required refund returns through its governed original
route where possible; it is not a promise that MANA can freely cash out.

Toll can support different rails while retaining exact evidence. Every quote, authorization,
and receipt names issuer, rail, asset, integer units, merchant, and the network or external-effect
identity where applicable. Conventional processor and x402 adapters are sibling rails: x402 is
neither a currency nor a requirement for a project-native asset. Translation must preserve
provenance and cannot make unlike balances fungible.

## The commitment before the signature

The Counting House may parse a versioned challenge, normalize integer monetary units, compare
candidate costs, reserve a budget, and reconcile receipts. It holds no spend key. An authorization
binds authenticated Principal and budget owner, merchant/service, method and canonical destination,
request digest and purchased resource, asset/network, maximum amount including fees, expiry,
redirect policy, and idempotency key.

The [execution-road policy](28-workflow.md#execution-road-planning) considers quotes only among
roads that satisfy capability, privacy, policy, and resource feasibility. Toll owns judgment of
the economic terms and reservation of their exposure; [Dispatcher](22-dispatcher.md) binds an
already eligible capability. Policy rejects the quote, applies one matching bounded low-risk
standing authority, or parks the Run for live Magus consent over the exact terms.
Novel or significant spend requires [HitL](25-hitl.md). Consent means *this exact maximum*, never
whatever a later challenge asks.

Accounting reserves worst-case exposure before signing. The isolated Irreversible Gate revalidates
the pinned authorization and live reservation, enforces per-effect and rolling caps, atomically
consumes the reservation, signs once, submits once, and records a stable external-effect identity.
Unknown version, scheme, network, destination, amount, fee bound, changed quote, or expired
authority fails closed. No model or ordinary tool receives a wallet or general signing surface.

## Two settlement rites

Local MANA consumes no wallet signature or external proof-bearing replay:

```text
eligible request → quote → authorize and reserve local balance
→ execute → debit on the declared delivery condition / release / refund → reconcile
```

An external rail separately crosses the Irreversible Gate:

```text
destination-pinned request → quote → validate and reserve → reject / standing authority / live consent
→ revalidate → sign and submit once → one proof-bearing replay → reconcile settlement and delivery
```

After independently authorized settlement, the original connector may make at most one
proof-bearing replay to the same pinned destination. That replay cannot initiate another payment.
Payment and delivery remain non-atomic: a settled charge may produce no useful result, and a
successful response does not establish content truth. Refund, credit, dispute, expiry,
paid-but-undelivered, and ambiguous outcomes stay durable and visible. Unknown settlement requires
investigation and reconciliation, never a second signature.

## Budgets, effects, and restore

**Tithe** records currency-neutral model-token usage, generated media, concurrency, queue weight,
and hardware time against a stable Principal or service grant even with every payment adapter
disabled. A paid quota grant cannot mint or widen a Sigil, expose memory or tools, bypass consent,
or displace protected local work. Currency-free Legion work still needs quotas, reservation,
attribution, and evidence.

Quote, reservation, authorization, submission, settlement, delivery, refund, expiry, and ambiguity
form a durable idempotent receipt chain. Keys, signatures, bearer proofs, preimages, invoices, and
wallet credentials never enter prompts, ordinary projected configuration, logs, traces, or
artifacts. [Oculus](29-observability.md) can observe redacted transitions and reconciliation lag;
a trace is not the financial ledger. Restore cannot rewind money: spending stays closed until
external rail state reconciles.

Extensions may add bounded quote parsers, rails, signers, and paid Portal connectors, but not
arbitrary global middleware, unrestricted keys, rival ledger truth, or a bypass of host
authorization. Every external adapter pins one exact provider or protocol profile and conformance
corpus. The first delivered adapter need not be x402.

## Deferred shared and sovereign settlement

x402, stablecoin settlement, cross-provider clearing, a native token, a validator network, and a
sovereign L1 remain future candidates, not accepted dependencies or delivery promises. A native
chain is not admitted merely by calling it another rail adapter. It requires later amendments to
this and every affected Covenant after independent operators demonstrate a need that issuer-local
credits and existing payment rails cannot satisfy, together with explicit consensus, custody,
issuance, validator, upgrade, economic-security, privacy, recovery, abuse, and legal gates.

No MANA balance, contribution, usage receipt, test token, or participation creates any right to a
future token allocation, conversion, airdrop, cash redemption, or governance claim. Economic
balance, token ownership, and validator status cannot grant canonical-source selection or
Evolution promotion authority; [Packaging](17-packaging.md#forge-neutral-source-trust) and
[Evolution](18-evolution.md#future-quorum-roster) retain those separately governed human-seat
decisions.

## Delivery and consequences

This Covenant is **Designed**, not payment capability. No Toll package, quote/budget ledger,
reservation, authorization, signer, settlement path, safe `402` response, reconciliation, or
budget enforcement ships. [State of Work](../state-of-the-work.md#x402-payments) owns that public
boundary; [Toll](../sepulcher/extensions/toll.md) owns operated doctrine.

Delivery proceeds through these steps:

1. Establish immutable financial identities and integer money types.
2. Verify quote, budget, reservation, and receipt accounting without money movement, then prove
   manually granted MANA through idempotent reservation, debit, release, and refund.
3. Build and verify the isolated, capped Irreversible Gate.
4. Admit one allowlisted conventional payment adapter in its provider's sandbox, with evidence
   for crash, replay, refund, chargeback, and ambiguous settlement.
5. Only then admit production pay-as-you-go, seller routes, x402, or other optional rails.

Toll makes economic consequence attributable, bounded, interruptible, and reconcilable, while
requiring durable accounting, key custody, explicit parked/ambiguous caller states, and later
marketplace, refund, dispute, legal, and abuse domains.

---
title: "42. Multinode"
plain_name: "Design rule 42: Multiple machines"
section: "Covenants"
status: "Designed"
original: https://hexanomicon.dev/adr/42-multinode/
guide: https://lychd.snayu.ai/docs/adr/42-multinode/
---

# 42. Multinode (Design rule 42: Multiple machines)

## Plain-English summary (Snayu)

**What it is:** Defines how one operator's control plane can delegate bounded work to other machines they own through node agents (Legion), without sharing the database or letting a scheduler override what each node knows about itself.

**Why it matters:** Read this before designing anything that spreads work across several machines, GPUs or devices.

- The main node keeps all policy, memory, approvals and job records; node agents hold none.
- Node agents never get the main database, queues, filesystem or operator badge.
- Each node decides what physically fits and may refuse; delegation is durable, not a remote call.

**Status:** Designed. No node role, enrollment or durable delegation is built.

## Original text (Hexanomicon)

!!! abstract "Context"
    One Magus may own other machines, accelerators, robots, and embedded bodies. Delegation must
    extend cognitive continuity without turning every body into another Master, sharing the
    Phylactery, or allowing a scheduler to override physical truth known by the destination.

## Decision

**Multinode** governs bounded delegation across operator-owned physical nodes under one sovereign
control plane. **[Legion](../sepulcher/extensions/legion.md)** is the distributed-embodiment
Extension Domain applying this law through an owned-node profile over future [Intercom](26-a2a.md).
A **Legionnaire** in mythic language is a **Node Agent** in engineering.
It is neither a Master-shaped Vessel, remote database client, universal shell, nor foreign A2A peer.

| Jurisdiction | Master | Node Agent |
| --- | --- | --- |
| Cognitive truth | Principals, policy, consent, sessions, memory, Graphs, Runs, routing | None |
| Delegation state | Fleet ledger and transactional outbox | Crash-safe command/result journal |
| Identity | Enrols and revokes nodes | Unique rotating node-scoped credential |
| Physical truth | Ranks fresh advertisements and requests outcomes | Observes, reserves, admits, actuates, refuses |
| Evidence and artifacts | Authorizes manifests and aggregates bounded projection | Produces freshest evidence; verifies/publishes admitted material |

No Node Agent receives Master Postgres, queues, filesystem, Phoenix, container control, wallet
keys, Master Sigil, or other Soul-level service. Its residue only deduplicates messages, fences
reservations/effects, replays results, and reconciles recovery.

## A durable semantic delegation

The first channel should be node-initiated, avoiding a public listener on the node. A mutually
authenticated stream or long poll carries a versioned, audience-bound, replay-safe envelope.
Ward can use the transport identity as evidence; the connection itself grants no application
permission.

1. Master commits the delegation attempt and outbox intent, then checkpoints the exact attempt
   and local continuation before parking cognition and releasing its leases. Publication follows
   the committed outbox under [Intercom's Long Sleep contract](26-a2a.md#graph-and-long-sleep).
2. Node authenticates, persists and deduplicates before acknowledgement, and returns a typed
   decline or a fenced reservation.
3. Node records execution and terminal result before a replayable receipt.
4. Master resumes only when task, node, Master epoch, node session, delegation fence, and result
   digest match the admitted attempt.

Delivery is at least once. Requests name a typed capability, constraints, and expected outcome,
never shell commands, systemd/Podman action, GPU ordinal, filesystem path, database operation, or
Reactor instruction. Observable handling is idempotent; consequential external effects also bind a
stable effect identity, node-local effect receipt, and explicit reconciliation. Late results cannot
authorize blind retry elsewhere; results use the principal-bound channel or Master pull, never a
task-supplied callback URL.

## The body decides what fits

The node's advertisement helps scheduling for a limited time. It may describe semantic
capability, provisioned artifact digest, coarse capacity, health, queue pressure, and evidence
age, but is neither a reservation nor permission. Before accepting work, the node takes a
coherent local snapshot and validates device identity, VRAM/host-memory headroom, topology,
health, thermals, compatibility, active reservations, and safety margin. It then takes a fenced
local reservation. Only that reservation can enter admission closure, lease drain, narrow
actuation, readiness, compensation, and containment. Master may ask another eligible node after
a decline, but must never override local refusal.

Every consequential message binds Master epoch, node boot/session, delegation attempt/fence,
reservation generation, and local transition precondition. A stale command remains evidence but
cannot admit resources, actuate, release newer reservation, or wake cognition. During partition,
local policy may finish admitted bounded work and spool its result; Master rejects a superseded
fence. Master restore closes fleet admission, advances its epoch, and reconciles signed node
receipts before new delegation. Reconnection alone is not settlement. Cancellation, expiry,
revocation, version skew, duplicate delivery, and ambiguous effects remain explicit states.

## Evidence and artifact boundary

Nodes emit bounded, signed, versioned evidence batches with node/boot identity, monotonic sequence,
occurrence/send/receive times, schema/redaction class, gaps, decision references, reservations,
transitions, and outcomes. [Oculus](29-observability.md) may project freshness and clock
uncertainty; only fresh local evidence, local reservation, and actuator preconditions authorize
physical work. Signatures attribute bytes, not truth or safety.

The first profile can advertise only models/runtimes already provisioned at exact content
digests. Missing material makes placement infeasible and cannot trigger an implicit
URL/Master-path fetch, download, or Portal fallback. Later artifact transfer needs classified
content-addressed manifests, bounded resumable chunks, integrity checks, quotas,
provenance/license policy, atomic publication, and corruption quarantine. Returned results remain
typed quarantined observations until admitted.

## Delivery and consequences

This Covenant is **Designed**, not a fleet. No node role, enrollment, durable delegation,
advertisement, local reservation, fencing, artifact transfer, durable spool, cancellation,
settlement, or fleet-evidence path ships. [State of Work](../state-of-the-work.md#legion-federation)
owns that boundary; [Legion](../sepulcher/extensions/legion.md) owns operated doctrine.

Safe delivery proves fresh resource evidence, deployment variants, and fenced admission on one host;
then disjoint Master/Node assemblies with negative composition tests; credential-backed Ward;
durable Intercom and node journal; partition, replay, cancellation, restore, version-skew, artifact,
and two-node GPU behaviour; and finally fleet projection.

Legion grows one cognitive continuity without sharing Soul authority, but deliberately costs node
identity, journals, fencing, reconciliation, evidence, and proof of native resource intelligence on
one host before fleet placement is honest.
