# KERNEL — five members (v1, frozen definitions)
Durable definitions only. Each is backed by an evidence report named at its foot; the
reports carry the version-specific numbers, this file carries the invariants.
A note on shape: **Delegation, Observation, and Channel are mechanisms** (things a
runtime/server does); **Cursor is a construct**; **Interaction Persistence is not a
mechanism — it is a substrate contract** that Delegation and Cursor each depend on.
The five are not five symmetric operations. Do not read Interaction Persistence as
something you "invoke."
---
## 1. Delegation (mechanism)
The server emits declarative markup that transfers ownership of a browser-native
interaction machine to the browser.
**Invariants:**
- Browser owns the native interaction state when delegation is **patch-safe**.
- **Delegated browser-owned state must not be stored in a server-reconciled
attribute.** (State reflected into an attribute the server template does not carry
is stripped by reconciliation.)
- **Structural attributes a browser machine requires must be server-rendered
constants.** (A client-added structural attribute — e.g. `popover` — is stripped by
reconciliation just like reflected state. The attribute must be static in the
server template so the machine keeps its shell.)
- **popover is green.** **dialog and details are red** (see `RED_FIXTURES.md`).
*Evidence: `reports/CONFORMANCE_REPORT.md`, `reports/COMBOBOX_SPIKE_REPORT.md` (test 7).*
## 2. Observation (mechanism)
A declarative relay forwards browser-machine events to the server as ordinary
LiveView events.
**Invariants:**
- Observation is **lossy browser-to-server telemetry**.
- It is **never authoritative**.
- The server **may react** to observed events (lazy cleanup, logging, non-gating
assigns) but **must not derive canonical state or authorization** from observed
browser state.
The dialog-close-relay evidence shows the signal is lossy in three independent ways
(a reconciliation-stripped close fires no event; a disconnected close is dropped;
`<dialog>` has no open event at all), so the non-authoritative rule is not hygiene —
it is the only safe reading.
*Evidence: `../archive/observation-spike/OBSERVATION_SPIKE_REPORT.md`.*
## 3. Interaction Persistence (substrate contract — NOT a peer mechanism)
The condition under which owned interaction state survives a patch. It splits by
owner and must **not** be collapsed into a single "Identity" concept.
**Browser-owned tier:**
`DOM node continuity + state-surface non-interference.`
The same DOM node object must persist **and** the machine's state surface (attribute
or top-layer) must not be overwritten. Node continuity alone is insufficient (dialog
keeps its node and still loses `open`).
**Client-owned tier:**
`stable logical identity + explicit userland rebind/re-projection machinery.`
Not provided by LiveView. The two required mechanisms, both evidenced:
- **child-node replacement** → the container hook re-projects presentation by logical
id in `updated()`;
- **hook-node (container) replacement** → recover state from **external storage keyed
by the logical container id** on remount.
**Standing caveat (durable):** LiveView node continuity is **observed implementation
behavior, not a documented framework guarantee**. The harness exists to detect when it
changes.
*Evidence: `reports/CONFORMANCE_REPORT.md`, `reports/CURSOR_REBIND_SPIKE_REPORT.md`.*
## 4. Cursor (construct)
Client-owned coordination state over server-rendered, identity-bearing children.
**Invariants:**
- Primary strategy is **`aria-activedescendant`** (focus stays on a persistent
input/container; the active item is a logical-id reference).
- **Roving tabindex is not patch-safe** as the default strategy — a focused non-form
element is blurred when a patch touches its subtree (LiveView preserves focus for
form inputs only).
- The active descendant **must always target a live node, or collapse
deterministically** (clear/first/nearest, chosen and documented) — it must never
point at a removed or stale node.
- Cursor is a specialization of the Interaction Persistence client tier; it inherits
the "stable logical id + explicit rebind" requirement.
*Evidence: `reports/CURSOR_REBIND_SPIKE_REPORT.md`, `reports/COMBOBOX_SPIKE_REPORT.md` (tests 3–5).*
## 5. Channel (mechanism — a server obligation)
A versioned async query/result exchange between a client-owned input atom and
server-owned result content.
**Invariants:**
- **version-through-render**: the client stamps each query with a monotonically
increasing version; the server stamps each result render with the version it answers.
- **server-enforced monotonicity is required for construction-grade correctness**:
the server render path must **refuse to render superseded versions**. The package
ships `LiveInteractionContracts.Channel` as the reference guard; an application must
route result rendering through that guard to inherit the construction-grade claim.
- **client-side stale detection is a secondary guard, not the primary one.** The
version stamp alone, without `Channel.accept/2` on the server render path, is
**convention** — stale results still enter the DOM and are only flagged after the
fact.
- Channel stays in the kernel because Combobox correctness is impossible without it,
and the version must round-trip *through the server render* (coupling it to the
pipeline in a way generic app-level versioning is not).
*Evidence: `reports/COMBOBOX_SPIKE_REPORT.md` (test 2 — guard on vs off).*
---
## Derivations (not kernel; for orientation only)
- **Dialog** = Delegation (red) + Observation. Red fixture.
- **Popover** = Delegation (green). Reference machine.
- **Dropdown menu** = Popover + Cursor.
- **Combobox** = Popover + Cursor + Channel. Proven to compose on one subtree.