# Lifeloop Release Gates
## Status
Strategic orientation note
## Date
2026-05-08
## Purpose
The extraction backlog is closed. CCD-side mechanics that needed to be lifted
into a neutral lifecycle substrate now live in this crate; the host lifecycle
surface is cut over to the `lifeloop` CLI; and the eight-issue product track
that follows extraction is open. This doc names the v0.2 hardening milestone
and the v1 freeze gates in operational terms so that future work attaches to
a release boundary instead of drifting back into local hardening tasks.
It also records which work blocks the CCD slimdown
(dusk-network/ccd#723) and which work can proceed in parallel, so the
sequencing decisions in issue #27 stay legible after the issue closes.
## Surface taxonomy
Lifeloop ships four distinguishable surfaces. Each one has a different
stability story; conflating them is how product boundaries collapse.
### Library API
The Rust crate's public types and traits: lifecycle event vocabulary, the
callback request and response envelopes, payload envelope (`placement`,
`requirement`, `outcome`), adapter manifest, lifecycle receipts, the 13-class
`FailureClass`, the 5-class `RetryClass`, and the failure-to-retry default
mapping. The `lifeloop.v0.2` slice of the lifecycle contract is implemented
and pinned by `tests/wire_contract.rs` and `tests/spec_alignment.rs`.
What v1 freezes: the wire shape of all of the above and the failure-to-retry
mapping. Additions ride a schema bump; removals require a tombstone with a
removal criterion.
### CLI / operator UX
The `lifeloop` binary subcommands: `events`, `envelope validate request|response`,
`envelope echo`, `manifest`, `asset preview` (read-only render, per the #23
boundary decision in `docs/decisions/asset-apply-boundary.md`), and
`event invoke`. The CLI is an inspection and operator surface, not a separate
contract: every subcommand is a thin shim over the library.
What v1 freezes: subcommand names, argument shapes, and exit-code semantics
for already-shipped commands. New subcommands are additive and do not
require a schema bump unless they expose new wire data.
### Fixture corpus
Committed conformance fixtures used by tests and downstream consumers:
adapter manifests for Codex and Claude, the rendered protocol fixtures, and
sanitized live-evidence fixtures captured from real Codex 0.122/0.129 (#31)
and Claude (#30) runs. The fixture corpus is the contract a non-CCD client
compares against when it asks "does Lifeloop describe this harness the way I
see it?"
What v1 freezes: the existence and shape of the v1-conformance adapter
fixtures, plus the operator procedure for regenerating live evidence. The
exact byte-for-byte contents may evolve under the schema-bump discipline.
### Client profile contract
How a non-CCD client attaches to Lifeloop without importing CCD: the
callback request and response schemas, the payload delivery plane on
`event invoke` and subprocess callbacks, and the integration asset profile
abstraction that renders host assets for something other than CCD. Today
the host asset renderer carries CCD
compatibility command prefixes directly; #26 isolates those behind a named
compat profile and proves a second profile renders.
What v1 freezes: the callback envelope schemas, the subprocess transport
contract for payload delivery (#22), and the profile abstraction shape
(#26). The CCD-flavored profile becomes one client profile, not the
shape of the renderer.
## v0.2 hardening (current milestone)
v0.2 hardens what already exists without freezing the shape. Each bullet ties
to a tracking issue.
- Payload opacity in protocol renderers (#21, landed).
`render_additional_context` no longer parses payload bodies as JSON or
merges keys. Each eligible payload carries through a Lifeloop transport
envelope `{"payloads":[…]}` with `body` passed through verbatim;
overlapping JSON keys across payloads remain distinguishable, and
`body_ref` stays a reference. Pinned by `tests/protocol.rs` opacity
tests.
- First-class payload delivery on event invoke and subprocess callbacks
(#22, landed). `DispatchEnvelope` is the new transport-boundary wire
shape carrying both the `CallbackRequest` and the opaque
`PayloadEnvelope` bodies a dispatch is delivering with. `event invoke`
reads it from stdin and threads payloads through negotiation and the
subprocess invoker; subprocess clients reach payload bodies through the
documented stdio contract. `payload_receipts` records the delivered
placement.
- Lifecycle asset and source-file apply boundary decision (#23, landed).
The decision is recorded in `docs/decisions/asset-apply-boundary.md`:
Lifeloop does not own filesystem writes for lifecycle integration assets.
The misleading `lifeloop asset apply` CLI surface is tombstoned
(`docs/tombstones/asset-apply-cli.md`) and rejected with a redirect to
`asset preview`; `host_assets` remains a pure renderer. The stricter
source-file ownership decision in
`docs/decisions/source-files-are-user-owned.md` retracts the managed-section
renderer entirely because pure replacement-body rendering still points
callers at user-owned instruction files.
- Docs/status refresh and kernel-purity gate (#24, landed). README,
lifecycle-contract implementation status, RLM development-contract
note, and the lifeloop.v0 tombstone agree with the code that landed.
`tests/kernel_purity.rs` is wired into `cargo test` and `make verify`,
scanning every `.rs` file under `src/` for client-owned product
vocabulary outside a documented allowlist of compat zones.
- Profile abstraction scaffolding (#26) lands in v0.2 *only* if it stays a
pure render refactor; otherwise it slides into v1 work because it carries
the second-client-class evidence.
v0.2 closes when payload opacity, payload delivery, the host-asset boundary,
the source-file ownership decision, and docs parity gates are all green and
the kernel-purity gate is wired in. Those gates are landed; only #26 (profile
abstraction) remains for v0.2 hardening if it stays a pure render refactor.
## v1 freeze gates
v1 freezes the four surfaces above. Six gates govern that freeze. Each gate
has a short name, an operational definition, and the issues that close it.
1. **Adapter evidence** (#25, split into #30 and #31). Built-in adapter
manifests for Codex and Claude are backed by captured live runs covering
session start, frame opening, frame end, context pressure where available,
and receipt emission. Manifest claims that disagree with observation are
either fixed in code, corrected in the manifest, or recorded as documented
pre-v1 degradations. A documented operator procedure recaptures the
evidence.
2. **Two client classes** (#28, with #22 and #26 as prerequisites). At
least two clients consume real Lifeloop event-invoke surfaces with
payload delivery: the existing CCD client and one non-CCD client. The
current product pilot is the Fixity client in `crates/fixity-pilot/`,
a Reforge-inspired repeated-signal consumer that runs over
`lifeloop event invoke`, returns valid `CallbackResponse` values,
observes payload refs or bodies through the chosen delivery plane, and
produces conformance fixtures usable by this gate.
3. **Payload delivery** (#22, with #21 as prerequisite). `event invoke`
carries payload envelopes end-to-end through negotiation and subprocess
callbacks. Negotiation receives the actual `PayloadEnvelope` values, not
an empty slice. Subprocess clients can access payload bodies or
`body_ref` without Lifeloop parsing payload contents. Receipt synthesis
includes correct `payload_receipts` for delivered payloads.
4. **Asset application and profile story** (#23 and #26). Lifeloop has a
clear, documented boundary on filesystem writes for lifecycle integration
assets, and a stricter boundary that user-owned instruction source files
are read/suggest-only. The profile abstraction supports at least one
non-CCD host-asset profile rendering plausibly without editing CCD
constants. CCD command strings live behind a named compat profile, not
in the renderer's defaults.
5. **Docs parity** (#24). README, lifecycle contract spec, the RLM
development-contract note, and the tombstones agree with the code. The
kernel-purity gate is wired and CI-enforced. No stale issue-number
TODOs reference already-landed work.
6. **CCD cutover readiness** (#28 plus dusk-network/ccd#723 on the CCD
side). Lifeloop owns enough lifecycle reach that CCD can slim down to a
callback consumer. The replacement contract is documented and the Fixity
pilot confirms a non-CCD client works against real Lifeloop surfaces, not
only fixtures.
v1 freezes when all six gates are green. Subsequent work is governed by the
schema-bump discipline (`docs/playbooks/schema-bump.md`).
## Dependency map (execution graph)
The issue bodies record a partial order. The DAG below collects it; the
recommended execution order matches issue #27.
```text
#27 (this doc)
|
+-----------------+-----------------+
| | |
#21 -----+ #24 (docs/ #23 (asset
(opacity) | purity gate) boundary)
| | | |
v v v v
#22 (payload delivery) <-- (parallel) -->
|
+------+------+
| |
v v
#25 #26 (profiles)
(live evidence) |
| v
| #28 (non-CCD pilot)
| |
+------+------+
v
dusk-network/ccd#723 (CCD slimdown)
```
Recommended execution order (from issue #27):
1. #21 payload opacity and #27 release gates in parallel.
2. #22 payload delivery after #21.
3. #24 docs/purity gate early, in parallel with #22 and #23.
4. #23 host-asset apply boundary and source-file ownership boundary after
the #27 framing lands.
5. #26 client integration profiles after the #23 boundary is clear.
6. #25 live Codex and Claude evidence after #21 and #22, preferably after
#23.
7. #28 non-CCD product pilot after #22 and #26.
8. dusk-network/ccd#723 CCD slimdown after Lifeloop release gates say the
replacement is ready.
Work that blocks the CCD slimdown directly: #21, #22, #25, and #28. The
slimdown also depends on #23, #24, and #26 transitively, but the four
explicit blockers are the ones whose acceptance criteria name CCD slimdown.
Work that can proceed in parallel:
- #21 runs in parallel with #27 (this doc); both are P0 and they have no
shared files.
- #22 runs in parallel with #24 once #21 lands; they touch different
module boundaries.
- #23 runs in parallel with #21, #22, and #24 once the boundary decision
is documented.
- #25 can start in read-only exploratory mode at any point after #21 and
#22 land, even before #23 fully closes; only its v1 evidence claim is
gated on the full prerequisites.
## CCD slimdown reference
The CCD slimdown (dusk-network/ccd#723) is gated by Lifeloop's v1 freeze
gates. Before that work opens, gates 1 through 6 must be green: adapter
evidence captured, two client classes proven, payload delivery end-to-end,
asset application and profile story documented, docs parity enforced, and
the cutover readiness confirmed by a non-CCD client running against real
Lifeloop surfaces.
No work in this repo modifies the CCD repository. The slimdown is a
downstream consequence of Lifeloop reaching v1, not a parallel track.
## Issue references
- Lifeloop #21 — Preserve payload opacity in protocol renderers
https://code.nanto.org/nanto/lifeloop/-/work_items/21
- Lifeloop #22 — First-class payload delivery on event invoke and
subprocess callbacks
https://code.nanto.org/nanto/lifeloop/-/work_items/22
- Lifeloop #23 — Resolve lifecycle asset and source-file apply boundary
https://code.nanto.org/nanto/lifeloop/-/work_items/23
- Lifeloop #24 — Refresh docs/status and add a kernel-purity boundary gate
https://code.nanto.org/nanto/lifeloop/-/work_items/24
- Lifeloop #25 — Capture live Codex and Claude adapter conformance evidence
https://code.nanto.org/nanto/lifeloop/-/work_items/25
- Lifeloop #26 — Generalize lifecycle integration asset profiles beyond
CCD compatibility
https://code.nanto.org/nanto/lifeloop/-/work_items/26
- Lifeloop #27 — Shape Lifeloop v0.2/v1 product surface and release gates
https://code.nanto.org/nanto/lifeloop/-/work_items/27
- Lifeloop #28 — Graduate a non-CCD client from shape proof to product
pilot
https://code.nanto.org/nanto/lifeloop/-/work_items/28
- CCD #723 — CCD slimdown (downstream)
https://code.nanto.org/dusk-network/ccd/-/work_items/723