Files
openrig/docker/testbed/runbooks/L2-tmux-server-lifecycle.md
v-openrig-buildandClaude Opus 4.8 49a8e6b588 docs(testbed): 51-04 step-2 L0-L5 verification runbooks (host-side, evidence-defined)
Step-2 (plan §2): the L1-L4 live legs authored as host-executed, evidence-defined
runbooks (the 51-09 live-legs pattern; the VM seat has no runtime per the locus ruling).
Each leg = exact commands + real-byte capture + PASS/FAIL verdict-on-bytes (never from
memory) + hashed evidence dir (census-receipt discipline):
- L0 resolve inputs (base-image digest + stub-assets.list census — the two host-resolved slots)
- L1 PTY allocation (docker run -t + tmux capture real bytes + resize propagation)
- L2 tmux server lifecycle (detach-survive, multi-pane, exact send-keys/capture round-trip)
- L3 daemon-in-container (container-local sqlite, healthz on published port, rig up stub
  topology settles — where stub-assets.list is grounded/finalized; zero tokens)
- L4 hermetic fail-closed (foreign OPENRIG_URL hard-refused INSIDE the container; grounding
  note flags the packaged-vs-runner-mode form honestly)
- L5 multi-host (N named self-hosts on one docker network via the host registry, plan §3)
  + the 51-09 live-leg RIDER: executes the shipped collision/alignment RUNBOOK.md (LEG A
  cross-host triple, LEG B founder-collision) against the testbed containers in one session.
Fences carried on every leg: no real-HOME mounts, network-only shared surface, scenarios
byte-unchanged, docker-gap-watch routes to PM.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-06 05:23:49 +00:00

2.1 KiB

L2 — tmux server lifecycle (detach-survive, multi-pane, send-keys + capture round-trip)

Runs host-side, after L1. Proves the tmux server — the substrate the whole product rides — behaves in-container: sessions survive client detach, multiple panes coexist, and a send-keys → capture round-trip returns the exact bytes.

Setup

GIT_SHA="$(git rev-parse HEAD)"; IMAGE="openrig-testbed:${GIT_SHA}"; EVID="dist/testbed-image/evidence/${GIT_SHA}"; mkdir -p "${EVID}"
NAME="orig-l2-${GIT_SHA:0:8}"; docker run -d -t --name "${NAME}" "${IMAGE}"

L2.1 — server survives detach

docker exec "${NAME}" tmux new-session -d -s l2 -x 80 -y 24
docker exec "${NAME}" tmux send-keys -t l2 'echo persist-marker-$$ > /tmp/l2.marker' Enter
sleep 1
# A detached session is the default with -d; confirm the server + session still list after a beat.
docker exec "${NAME}" tmux ls | tee "${EVID}/L2-sessions.txt"
docker exec "${NAME}" cat /tmp/l2.marker | tee "${EVID}/L2-marker.txt"

PASS: tmux ls shows l2 still alive; the marker file exists. FAIL: "no server running" / no l2.

L2.2 — multiple panes

docker exec "${NAME}" tmux split-window -t l2 -h
docker exec "${NAME}" tmux list-panes -t l2 -F '#{pane_index}' | tee "${EVID}/L2-panes.txt"

PASS: at least two pane indices (0,1). FAIL: one pane / error.

L2.3 — send-keys + capture round-trip (exact bytes)

TOKEN="roundtrip-$(date +%s 2>/dev/null || echo fixed)-marker"
docker exec "${NAME}" tmux send-keys -t l2.0 "printf '%s\n' '${TOKEN}'" Enter
sleep 1
docker exec "${NAME}" tmux capture-pane -p -t l2.0 | tee "${EVID}/L2-roundtrip.txt"

PASS: the capture contains ${TOKEN} verbatim (the exact bytes round-tripped through the server). FAIL: token absent / garbled.

Teardown + evidence

docker rm -f "${NAME}" >/dev/null
{ grep -q 'l2' "${EVID}/L2-sessions.txt" && [ "$(wc -l < "${EVID}/L2-panes.txt")" -ge 2 ] && grep -q "${TOKEN}" "${EVID}/L2-roundtrip.txt" \
  && echo "VERDICT: PASS — server survives detach, multi-pane, exact round-trip" \
  || echo "VERDICT: FAIL — see L2-*.txt"; } | tee "${EVID}/L2-verdict.txt"