# Capture Live Adapter Conformance Evidence

This playbook is the operator procedure for refreshing the
**sanitized live capture fixtures** under `tests/fixtures/live/`.
Those fixtures back the v1 freeze gate 1 ("Adapter evidence") in
`docs/release-gates.md` — they are the reference observations that
`lifeloop::claude_manifest()` and `lifeloop::codex_manifest()` claims
must remain consistent with.

This playbook covers Claude Code (#30). Codex CLI (#31) reuses the
same rig with a sister orchestrator script.

> **Read first:** `tests/fixtures/live/README.md` describes the
> fixture layout, sanitization rules, and the deny-by-default
> contract every captured field must satisfy.

## When to recapture

- **Adapter manifest claims change** in `lifeloop::claude_manifest()`
  (`src/cli/manifest.rs`) — recapture confirms the new claims still
  match real harness behavior.
- **Claude Code or CCD ships a hook-protocol change** — the
  sanitizer's deny-by-default rules will fail loudly the next time
  someone tries to recapture, and that is the cue that a manifest
  correction or sanitizer rule update is needed.
- **Pre-v1 freeze**, as part of cutting the v1 release.

If none of the above is true, a stale-but-passing capture is
acceptable. The fixtures are reference observations, not a continuous
contract.

## Prerequisites

- Local clone of this repo with main checked out.
- A **real** CCD binary installed (not the capture wrapper). Note
  the absolute path; you will export it as `LIFELOOP_LIVE_REAL_CCD`
  below. See dusk-network/ccd for build and install instructions.
- Claude Code CLI installed and authenticated.
- Per refinement #4 in #30: **smoke-test the legacy CCD→Claude
  host-asset chain on the current Claude/CCD versions before
  capturing**. The chain is what produces the evidence; if it has
  drifted on this Claude/CCD pair, the capture will record the
  drift, not the lifeloop manifest claims. The smoke test is:
  ```bash
  cd "$(mktemp -d)"
  git init -q
  ccd start --activate --path . | jq -r '.disposition'
  # Should print: resume_active_continuity OR resume_blocked_continuity
  # Anything else (panic, error, transport-failure) is a failed smoke
  # test — fix CCD/Claude versions before continuing.
  ```

## Step-by-step recapture

```bash
# From the lifeloop repo root, with main checked out.
export LIFELOOP_LIVE_REAL_CCD="$(command -v ccd)"   # adjust if installed elsewhere
./scripts/regenerate-live-claude-evidence.sh setup
```

The `setup` subcommand:

1. Creates a scratch git repo under `$LIFELOOP_LIVE_SCRATCH_DIR`
   (default `$TMPDIR/lifeloop-live-claude`).
2. Builds the in-tree `lifeloop` binary if needed.
3. Renders the CCD-compat Claude `settings.json` via
   `lifeloop asset preview --host claude --mode native_hook` and
   writes it into the scratch repo's `.claude/`. The rendered
   command line refers to `${CCD_BIN:-ccd}`, so pointing `CCD_BIN`
   at the capture wrapper transparently intercepts every hook
   without modifying the Lifeloop renderer or CCD itself.
4. Prints the operator commands for steps 2 and 3 below.

Then drive Claude:

```bash
# In a NEW shell — the envs scope to the capture session.
export LIFELOOP_LIVE_CAPTURE_DIR="$LIFELOOP_LIVE_SCRATCH_DIR/captures"
export LIFELOOP_LIVE_REAL_CCD="$(command -v ccd)"
export CCD_BIN="<lifeloop-repo>/scripts/capture-live-hook.sh"

cd "$LIFELOOP_LIVE_SCRATCH_DIR"
claude
```

Inside the Claude session, exercise every lifecycle path #30
captures. The recommended minimal walk:

| Lifecycle event   | How to fire it                                          |
| ----------------- | ------------------------------------------------------- |
| `SessionStart`    | Launching Claude (step above) fires this.               |
| `UserPromptSubmit`| Send any short prompt, e.g. `echo hello`.               |
| `PreCompact`      | Run `/compact` if the Claude version exposes it.        |
| `Stop`            | Let Claude reach end-of-turn (return to prompt).        |
| `SessionEnd`      | `/exit` or close the session cleanly.                   |

If `/compact` is unavailable in the Claude version under test, note
the version in the recapture commit message; #30's body covers how
that maps to a manifest correction or pre-v1 degradation.

After the session ends, sanitize:

```bash
./scripts/regenerate-live-claude-evidence.sh sanitize
```

The sanitizer applies the rules in
`tests/fixtures/live/README.md` and writes
`tests/fixtures/live/claude/<event>/<n>.json`. Any unexpected field
in the raw captures fails the sanitizer with an explicit message —
add a rule to `scripts/sanitize-live-evidence.py` (and document it
in the README) before retrying.

Verify:

```bash
make verify
```

The forthcoming `tests/live_evidence*.rs` (landed in #30's evidence
MR, not in the rig MR) runs the captured fixtures against
`lifeloop::claude_manifest()` and surfaces any mismatch as a
manifest claim that has lost its grounding in real harness
behavior.

If the captures look clean and `make verify` passes, commit the
fixtures and the per-harness `tests/fixtures/live/claude/README.md`
(harness version, CCD version, capture date, operator).

Finally:

```bash
./scripts/regenerate-live-claude-evidence.sh teardown
```

Tears down the scratch repo. Fixtures under
`tests/fixtures/live/claude/` are **not** touched.

## Sanitization safety contract

The capture wrapper (`scripts/capture-live-hook.sh`) writes raw
hook stdin and stdout into `$LIFELOOP_LIVE_CAPTURE_DIR`. **Those
files contain unredacted operator data** — paths, session ids,
prompt text. They live under your scratch dir and are deleted by
`teardown`; they must NEVER be committed to the repo.

The sanitizer is the only path from raw captures to committed
fixtures, and it is deny-by-default. If you find yourself wanting
to commit something the sanitizer rejects, either:

- add a rule to redact the new field (and document it in the
  README), or
- conclude that the field is fine to keep and add a `_keep` rule.

Do **not** edit fixtures by hand.

## Recapture cadence

Recapture is on-demand, not scheduled. The expected triggers are
listed in "When to recapture" above. The rig itself is stable —
the `tests/fixtures/live/README.md` and the scripts under
`scripts/` should not change without a deliberate sanitizer-version
bump and a fresh recapture.
