AGENTS.md@packages/conformance · git:20261001.ae83e30 · 2026-10-01 · sha256 d9f96d7dbc4379c8

AGENTS.md@packages/conformance git:20261001.ae83e30A

Immutable. This exact content never changes and is served at /api/v1/blob/d9f96d7dbc4379c8.

# conformance

## Purpose

The shared test infrastructure and the one package allowed to depend on
every layer: the storage conformance suite that *defines* backend
correctness, the wiring and jailed e2e suites that prove the production
effect seam (`client/wiring`, which once lived here before its promotion),
and the deterministic simulation runner that turns a seed into a verdict.
WP-T. Modules live under `src` (not `test`) so the suites form an importable
library. No other package depends on `conformance`, so today the only
importer is this package's own test tree: `storage_suite_test` runs the
storage suite over the backends.

## Key Types

- `conformance/storage_suite.{Backend, run}` — one suite parameterized over
  a backend constructor. A backend passes WP-B's exit criteria only when
  `run` is green.
- `conformance/simulation/runner.{run, check, examine, soak, Verdict,
  Report, Corroboration}` — seed in, verdict out. A `Failed` verdict
  carries a `Corroboration`: the seed is replanned and re-run up to
  three times, and `Reproducible` means every run failed while
  `Unstable` means the same script under the same schedule reached
  different verdicts. Both, plus the run's own `[timing]` evidence, are
  folded into `Failure.detail` so every existing printer shows them.
  The reproduction text includes `make replay-simulation SIM_SEED=<seed>`,
  which selects only the single-seed soak test rather than rerunning the
  entire conformance package.
- `conformance/simulation/script.{Script, Op, Settle, Intervention}` — the
  semantic half: what the session is *asked* to do. `Script.subagent` is
  the multi-strand coda: an optional brief that spawns a subagent strand
  and sends its findings back to main. `Script.parallel` *chooses* the
  batch mode — `Parallel` when set (a parallel script always carries a
  two-call batch, so the overlapping frontier is real), `Sequential`
  when not. It names both rather than inheriting `api.default_options`,
  which now ships `Parallel`; inheriting would make every seed a
  parallel seed and lose half the oracle's coverage.
  `Script.escalate` drives the durable escalation machinery — the first
  clearance raises an escalation scoped to exactly that call, approves
  it, and restarts the strand driver so the same durable coordinates
  re-clear with the grant, all under the fault schedule.
- `conformance/simulation/daemon/harness.{Harness, Row, Snapshot}` — the
  real daemon root, registry and catalogue over a temporary state root and
  the simulation's logical clock, with no listener. It supplies the default
  connection limits but does not exercise socket admission. The root starts a
  listener only when a caller asks it to, creation takes its id generator
  from the caller, and assembly is a record of caller-supplied callbacks,
  so no seam had to be added to `client/daemon/root` to construct one from
  a test. What runs for real is the catalogue writer and the conversation's
  writer lease; the runtime and the domain services are not opened, so a
  domain row's memory and search databases never exist under this harness.
  Its operations are keyed by creation request key and canonical
  session id; a `Row` has the run's temporary state root substituted out of
  every path so two runs under two directories are comparable. `Boot` is
  what one incarnation is started from, `Arrest` is where a simulated
  builder parks so the run can kill the daemon at a named creation step,
  `kill` is the untrappable kill of the root, the registry and the parked
  builder, and `resume` is the start a faulted run restarts through.
- `conformance/simulation/daemon/daemon_fault.{Fault, Schedule, Step}` —
  the daemon-level taxonomy, mirroring `simulation/fault`'s shape. One
  fault, `KillDaemonAt(key, workspace, step)`, and four steps named by what
  is already committed when the daemon dies: `AfterReservation`,
  `AfterDomainBind`, `AfterCustodyPublish`, `AfterConfirm`. A kill is the
  whole daemon and a restart over the same state root, never a registry
  restarted in place, because the root answers a dead registry by blocking
  recovery.
- `conformance/simulation/daemon/daemon_script.{Script, Creation}` — the
  semantic half: one or two workspaces, one to three creation keys, and the
  keys retried afterwards, with at least one reuse in every script. Drawn
  from its own split stream so adding a draw here does not shift the
  schedules.
- `conformance/simulation/daemon/daemon_runner.{run, plan, observe, describe,
  Verdict}` — the seed's script run fault-free and then run again under the
  seed's schedule, with the two compared. It carries its own `Verdict`
  rather than widening the session runner's, whose `Report` is shaped for
  one conversation, and reuses `runner.Failure` so the named checks print
  the same way. Its checks are `creation/one-identity-per-key`,
  `creation/no-orphan-file`, `publication/before-execute` and
  `replay/equal-catalogue-rows`.
- `conformance/simulation/daemon/lifecycle_faults.{Fault, Pending,
  Coordinate}` — the daemon-level lifecycle fault taxonomy:
  `KillDaemonWithPending` names an interrupted `open` or `stop` by the
  session it addresses, and `RevokeAt` names an owner revocation by where it
  lands in a command's passage through the authority boundary. Both
  coordinates are durable, for the reason the keying rule below gives.
- `conformance/simulation/daemon/lifecycle_runner.{run, restart_converges,
  revocation_converges, Verdict}` — the two faulted daemon scripts. Each
  runs fault-free and then under the schedule the seed drew, and the two
  runs must leave the same catalogue rows at the same revision. Its named
  checks are `lifecycle/reopen-policy`, `lifecycle/no-resend` and
  `revocation/silence-after-close`. `lifecycle/no-resend` has two halves and
  they are not held to the same draws: the stale-epoch half runs under both,
  and the half that reads the session's status runs only under `PendingOpen`,
  because a re-driven stop and a dropped stop both leave the session `Saved`
  with no slot and the status could not tell them apart. `PendingStop` is
  covered by `lifecycle/reopen-policy` and by the convergence comparison
  instead.
- `conformance/simulation/daemon/domain_runner.{run, observe, plan, Script,
  Schedule}` compares an open after normal domain retirement with an open
  acknowledged while the original cleanup is held. A seed chooses the saved
  session and duplicate count. `harness.HoldDomainRetirement` installs cleanup
  through the real custody owner; the existing simulation control actor owns
  the one-shot hold and records any build before release. Named checks cover
  admission, stable operation identity, parked capacity, replacement ordering,
  complete retirement, and equal catalogue rows and revision. This controls
  callback release order, not BEAM interleaving or kernel enforcement.
- `conformance/simulation/daemon/daemon_soak.{Runner, Outcome, soak,
  runners, describe}` — the daemon script's long run, bounded by a wall-clock
  budget rather than by a seed count, because a daemon seed's cost depends on
  the machine's file system and on whether the schedule drew a kill. It
  corroborates a failing seed itself, over the session runner's three re-runs
  and its `describe_corroboration` wording, since `daemon_runner` does not.
  `runners` holds the creation-key, lifecycle and domain-retirement scenarios,
  and every seed the soak draws runs each entry.
- `conformance/simulation/fault.{Fault, Schedule}` — the taxonomy of things
  a session must survive without anyone noticing.
- `conformance/simulation/random.Rng` — a splittable SplitMix64; the only
  source of choice.
- `conformance/simulation/vclock.Clockwork` — the one logical clock and its
  timer wheel.
- `conformance/simulation/control.Control` — the counters, one-shot claims,
  and runtime handle that outlive the session tree. Also
  `control.Attempted`, the three-way outcome of running an action on a
  disposable process: `Answered`, `Raised` (the carrier died — surfaced
  immediately as a one-task `weft` run's `Crashed` outcome, so it costs
  no wall-clock time), and `Expired` (a real millisecond budget ran out,
  via `weft.deadline`). `Raised` and `Expired` are equally uninformative
  about whether the action happened, and callers must treat them alike.
  It is also the rendezvous a live-triggered intervention uses to hand
  its decision to the runner: `await_intervention` registers a trigger
  and blocks, and `take_pending_interventions` is what the drive loop
  drains on every pass to find something to fire (#57).
- `conformance/simulation/{store, surface, invariant, wire}` — the
  instrumented session, the scripted effect surface, the named per-run
  checks, and the framing properties.

## Relationships

- **Depends on**: `simplifile` (the daemon simulation's `creation/no-orphan-file`
  check enumerates the sessions directory from `src`, so it is a real
  dependency rather than a dev one), plus every Gleam package it tests — `core`, `storage`,
  `session`, `machine`, `runtime`, `provider`, `broker`, `tools`, and
  `client` (whose promoted `client/wiring` the wiring and e2e suites
  prove), and `prompt` (declared in `gleam.toml`, though no module
  imports it today) — plus `gleam_erlang`, `gleam_otp`, and `weft` (the one-task
  bounded run behind `control.attempt`). This is deliberate and unique.
- **Depended on by**: nothing. It is the leaf, and stays one: `client/demo`
  copies the simulation's effect-surface shape rather than importing it,
  because this package's surface is test support, not a library.
- **FFI**: `conformance/test/support/internal/ffi_time` and `ffi_shell` —
  test-side only, for the jailed e2e harness.
- **Note**: the wiring adapter used to live in this package's `src`
  because only the test leaf could depend on every layer; when the client
  package became a real host it was promoted to `client/wiring`
  (spec-gaps, M2 integration item 7 — resolved).

## Traffic

- **Actor messages**: `control.Message` (counters, claims, notes, the
  runtime handle, the seam arm/quiet protocol, the harness-conduct
  record behind `Report.waits`, and the atomic intervention claim) and
  `vclock.Message` (now, schedule, advance, park). Both are calls. The
  runner also subscribes to `runtime/writer.Event.Committed` indirectly
  through the instrumented store's commit counter.
- **Commits**: `simulation/store.instrument` wraps a real memory backend's
  `Storage` record so every commit passes through it — counted with a
  counter that survives writer restarts, optionally refused as
  `StaleExpectation` exactly as a concurrent admission would, and checked
  against the boundary invariants at the transaction that caused them.
  The same wrapper gives a memory session a **stealable lease**: a renewal
  that fails once at a chosen commit and succeeds afterwards, which is what
  a stolen-then-reacquired SQLite lease looks like from above.
- **Registers**: `simulation/invariant` reads `op.state`, `op.meta`, and
  `strand.*` through `machine/codec` to check placement and terminal
  register cleanup; `storage_suite` exercises every namespace generically.
- **Multi-strand traffic**: a share of seeds drive the subagent coda —
  `api.create_strand` (fork-in-place at the main leaf), the child's brief
  run to a terminal result, then `api.send_to_strand` delivering its
  findings back to main as a durable steer-or-start admission. Coverage
  now *requires* both the spawn and the cross-strand message, so crashes
  during a child's effects exercise the boot-all-strands recovery path —
  and, since the M3 escalation-boundary wave, also the parallel frontier
  (`parallel-tools`), the escalation dance
  (`escalation-raised`/`escalation-consumed`), and the partial crash
  (`strand-restart-during-effect`). Terminal detection prefers the
  operation-keyed `operation-result/{op}` record and reports a violation
  when a terminal is reachable only through `strand.last_result`.
- **Wire**: `simulation/wire` generates byte streams straight into
  `broker/framing`'s deframer — no helper involved; the jailed e2e drives
  the real `loom-exec` through the broker.

## Invariants

- **A failing seed's report is printed before the panic.** `simulation_test`
  prints its full report to stderr and then panics with the same text,
  because eunit truncates a panic message and a gate log that carried only
  the truncation showed the first check's name with no seed, no reproduction
  line, and none of the `[timing]` and `[verdict]` evidence the runner paid
  to collect (issue #335). Any new suite here that fails over a range of
  seeds owes its log the same thing.
- **Faults are transparent by definition.** A schedule may crash the tree
  at a commit boundary, kill it mid-effect, restart a single strand
  driver mid-effect (`RestartStrand` — the partial crash the reaper must
  survive), refuse a commit as stale, fault a read, steal the lease, drop
  or delay a doorbell, starve an effect, or lose an effect process — and
  none of it may change what the session ends up having done. Anything
  that legitimately changes the outcome (a provider that refuses, a user
  who aborts) is scripted into *both* runs so it cannot be mistaken for
  damage.
- **A provider request is never parked on the logical clock** (#335). It
  runs inside the runtime's provider deadline (`surface.provider_timeout_ms`,
  60 ms) and two-second cancellation grace, and both are real time. A
  `SlowEffect` park ends only after the runner has advanced the clock
  through every earlier deadline, so its real length is the host's: about
  165 ms idle and four to seven seconds under load for a 2000 ms park. The
  loaded case outlived the grace, settled the attempt as
  `CancellationUnconfirmed`, and folded a steer into the retry, one turn
  short of the fault-free run (seed 14, `convergence/ledger`).
  `surface.request` therefore applies only the survival faults; a
  `SlowEffect` drawn on a provider index does nothing, while tool
  executions, which have no runtime deadline, are still slowed. A live
  intervention's rendezvous still runs inside the deadline, and a
  settlement that misses it arrives inside the grace and is forwarded
  unchanged.
- **Starved provider owners end with their consumers.** A starved provider
  effect is a weft witnessed run (`weft.new_prepared([weft.managed(...)])
  |> weft.cancel_when_exits(consumer) |> weft.start_witnessed`), and its
  scope pid is `stream.owned`'s owner. The one-shot timeout owner — the
  racer that holds the preselected transport-failure terminal — is
  adopted as a leaf, so cancellation asks it to stop instead of killing
  it, and naming the consumer here is what makes a killed effect cancel
  the run through the same path an explicit release takes. A killed
  effect therefore removes both the scope and its unused terminal
  capability instead of leaving a synthetic process behind the
  conformance run; its release still reaches the racer, but the send has
  nowhere left to land, since `events` is owned by the consumer that just
  died.
- **A composition-layer service is proved absent, not merely
  well-behaved.** `conformance/triggered_rules_test` is the end-to-end
  for issue #27: real wiring, real gateway, real adapter, real runtime,
  a real supervisor over the real scanner, and only the HTTP transport
  scripted. Its isolation row kills the scanner while a turn is in
  flight — an absent scanner being the strongest available form of "an
  expensive scan cannot delay a settlement" (design §10) — and asserts
  the transcript is exactly what the script implies, request for
  request, before showing the rule still fires off the durable marks
  once the supervisor has replaced it. The one piece of stage machinery
  is a transport that waits for the durable fired-mark from the second
  turn on, which settles the scenario's only race — was the steer
  durable before the checkpoint that drains it — without touching
  anything under test.
- **A daemon crash is a root restart over the same state root.** Killing the
  root takes the registry with it, because the lifetime scope is linked to the
  root and the registry is owned by that scope. The lifecycle scripts kill the
  registry by name as well, so that they have a monitor to wait on for each
  process rather than a cascade whose completion nothing reports. The next
  daemon takes the same state root and has to poll for it, since the launch
  lock is released by the operating system and is not ordered against the
  monitor that reported the death.
- **Without a listener, "pending" and "principal" are registry-level
  terms.** A pending lifecycle request is one `manager.open` or
  `manager.stop_session` answered with an accepted operation and had not
  settled; a principal is an invited member with a credential digest and a
  session grant, and the boundary it crosses is `manager.frame_authority`.
  A command in flight is the pair of authority answers the transport asks
  for, once at admission and once at delivery, so a revocation landing
  between them is expressible here. What is not expressible is the socket:
  that no frame is written to a closed connection is a gateway claim, and
  `tui_shipped_multiplayer_test` is what proves it.
- **The two revocation coordinates are two schedules, and only one of them
  fills the memo.** The registry remembers a resolved grant for the lifetime
  of a session's slot and drops the whole memo when an administration commits.
  `BetweenAdmissionAndDelivery` admits the principal before the owner revokes,
  which both fills that memo and gets the command through admission;
  `BeforeAdmission` revokes before the boundary has answered anything at all,
  so nothing is remembered and nothing is queued. Removing the memo drop in
  the `Administer` arm of `manager.gleam` therefore fails
  `revocation/silence-after-close` under the `Between` seeds and passes under
  the `Before` ones, which is the discrimination the coordinates exist for. A
  run that made both coordinates admit first would be one schedule counted
  twice.
- **Nothing is keyed by a counter.** A generation request is answered by
  the *phase* of its projected context — how many assistant messages are in
  it, plus a hundred once a summary is — and a tool execution by its
  scripted call id. Errored, aborted, and deferred responses never enter a
  projection, so a synthetic settlement written by recovery cannot shift
  the phase, and a script means the same thing under every schedule.
- **Answered-call checks scope to *executable* responses.** Faithful abort
  retention means an aborted entry can carry tool calls that never ran, so
  demanding a result for every call in every retained response is wrong.
- **Split-summary progress is counted at the commit boundary**, not at
  send time: a settlement lost with a halted strand must lead to another
  request rather than to a summary the ledger never paid for.
- **The wall clock is a deadlock backstop, and says so when it fires.**
  `control.attempt` is how anything reaches into a tree that may be
  mid-restart. It runs the action inside a one-task `weft` run bounded
  by `weft.deadline(within_ms)`; that budget is real milliseconds — it
  cannot be logical, because the action blocks on a real OTP call and
  the runner is the process waiting on it. What used to reach that
  budget routinely was the carrier *dying*; that is now surfaced
  immediately as weft's `Crashed` outcome (mapped to `Raised`) and costs
  no clock, which leaves the budget bounding only a wedge nothing is
  expected to reach. Every `Expired`, every `Raised`, and every scripted
  intervention claimed but never seen to land is recorded through
  `control.note_wait` into `Report.waits` and named in the failure the
  run reports. Neither `Raised` nor `Expired` is evidence the action
  failed: an admission whose reply was lost may already be durable, and
  every caller asks the durable state rather than concluding (issue #44,
  and the same ambiguity #6 records).
- **A retry waits for the writer, not for a pause** (#335). The runner's
  admission ladders (`admit`, the subagent's creation and brief, and the
  cross-strand send) count their attempts. `before_retrying` advances the
  clock one step and then `await_writer` polls through `weft/poll` until
  the root has registered a writer or died, so an attempt is spent only on
  a writer that could answer it. The fixed one-millisecond pause this
  replaced gave a ladder a real budget of a few milliseconds: on a loaded
  host, a crash on the commit before the subagent's creation spent all six
  attempts on an unregistered writer, and the run reported
  `run/terminated` with a clean timing line (seed 1). The wait's
  3000 ms bound is a backstop, recorded as `expired@writer-restart` if it
  is reached.
- **A failing seed says whether it is repeatable.** `run`, `examine`, and
  `check` replan the failing seed — same script, same schedule, since
  `plan` draws only from the seed — and re-run it up to three times
  before reporting. Shrinking is skipped for an unstable seed, because
  "does this smaller schedule still fail?" is answered by coin toss
  there. An unstable verdict is not an all-clear: a genuine race in the
  code under test is unreproducible too, so what it licenses is
  comparing *rates*, never dismissing the run.
- **A daemon script's identities come from the logical clock and the
  seed, and from nothing else.** `manager.create` mints a session id from
  the generator its caller supplies, so a daemon harness reading the
  simulation's `Clockwork` mints the same ids on a replay. Everything else
  a run leaves behind is derived: the database path from the id, the
  creation time from the clock, the domain record from the workspace. The
  daemon script's convergence check compares those rows and the catalogue
  revision they were read at, because a run that wrote a row twice would
  carry identical rows at a higher revision.
- **The daemon harness's waits are deadlock backstops, not simulated
  time.** `manager.create` returns while a builder still owns the
  operation, so the harness polls the registry (`weft/poll.until`) for the
  published incarnation before reading a row back. Those milliseconds are
  real, because the registry is a real process; what the logical clock
  governs is what gets *minted*, which is what a replay has to agree on.
  A daemon run therefore has more real processes than a session run, and
  its failure rate over a seed range is the signal rather than any single
  red.
- **Fault addressing is ordinal, not temporal.** Commit-indexed faults name
  a global commit ordinal counted across writer restarts; effect-indexed
  faults name a dispatch ordinal. Neither is a wall-clock instant, so a
  schedule means the same thing on a loaded machine as on an idle one.
- **A simulated session never sleeps.** The clock moves only when the
  runner moves it, and by exactly one step: to the earliest registered
  deadline. Firing a deadline early is always safe — the driver re-reads
  its durable state on every pass, so an early wake costs one wasted
  planning pass. A deadline is removed when it fires, so a wake delivered
  to a dead process is simply lost, exactly as a real timer's message
  would be. The drive budget counts consecutive silent passes, not the
  operation's lifetime: every writer commit proves durable progress and
  replenishes it. Charging progress against the stall allowance made loaded
  Linux runs fail at moving seeds even though each immediate replay passed.
- **One clock, one era.** The storage backend's timestamps, the strand
  driver, the effect scripts, and id minting all read the same `Clockwork`.
  Separate real clocks across runtime, tools, and broker drift, and that
  drift once made the broker refuse every call as past deadline (spec-gaps,
  M2 item 1).
- **Every check has a name.** "The simulation failed" is not a bug report.
  Boundary checks run inside the commit path so a violation is caught at
  the transaction that caused it; terminal checks run once the strand is
  idle.
- **An intervention that does not land is a violation, not a shrug.**
  `surface.apply` honors the `Result` of `api.steer_quietly` and
  `api.follow_up`: a refusal is a turn the transcript has permanently lost
  and it is recorded through `control.note` — `Report.violations`, which
  `sound` fails the seed on. Two refusals are deliberately exempt and
  marked instead of noted: an `AtTerminalCommit` steer, where the run the
  item would attach to is already closed and refusal is the documented
  outcome, and an admission whose reply the surface did not observe,
  which is not evidence the commit failed. `api.RuntimeUnavailable` is not a
  refusal: no request reached a writer. It goes through the existing durable
  fact reconciliation and retries while the root can restore the writer.
  The ordered batch stops at the first unavailable admission; its untouched
  suffix cannot overtake it, including an abort from the same trigger.
  The recording lives on an
  error path and touches no schedule, so the seed corpus keeps its
  meaning as a before/after oracle. The runner takes the intervention's
  in-memory one-shot claim, while the instrumented store derives the same
  identity from the queued message's opaque signature and folds a reserved
  write-once fact into the admission transaction. A retry after a lost reply
  can therefore ask whether the payload is already durable: a landed first
  attempt closes the debt, while an absent fact permits a new carrier without
  admitting the turn twice. When queue admissions and an abort share one
  logical trigger, `surface.fire_due` preserves the queue admissions' script
  order but sends the abort after them. The abort API is an asynchronous cast;
  sending it first made seed 584's fault-free transcript depend on whether the
  Linux or macOS scheduler processed the cast before the next synchronous
  admission.
- **A live intervention's decision belongs to the runner, never to the
  effect that reached its trigger** (#57, diagnosed under #44). A
  `DuringTurn`/`DuringCall` trigger is reached from inside a real effect
  process, and a `RestartStrand` fault reaping that process before
  `control.attempt`'s own bookkeeping ran meant some lost admissions
  carried no `raised@`/`expired@` tag at all — a silent dangling
  `intervening@path` instead of one with a cause attached. So
  `surface.intervene` no longer admits: it only asks whether the script
  has anything due at this trigger and, if so, calls
  `control.await_intervention` and blocks without an independent timeout.
  This rendezvous carries a payload, not a loss-tolerant wake-up: resuming the
  effect while its trigger remained queued would let the admission land after
  the settlement it must precede. The runner's drive loop
  (`service_interventions` in `runner.gleam`, called from `pump_strand`
  on every pass) drains `control.take_pending_interventions` and fires
  each one through `surface.fire_due`. The block is
  what keeps a live-triggered steer landing before the settlement that
  follows it: the effect does not resume until the runner reports the
  admission durable, so the ordering `steer-during-effect` depends on is
  still by construction, not by luck — only the process carrying the
  admission moved, from the effect to the runner, which is never a
  target of any fault in the taxonomy. If that runner-owned carrier loses its
  writer call during restart, or receives the typed pre-send availability
  result, `surface` reads the transaction's atomic fact
  directly from the raw durable session: it settles an admission that already
  landed, or retries one that did not. There is no post-commit counter for a
  crash to overtake. The `intervening@path` / `intervened@path` bracket remains
  as a tripwire for any future path that spends a claim without making the
  payload durable.
- **`terminal/last-result-once` is fenced across commit visibility** (#58).
  The memory actor can publish a terminal transaction before the
  instrumented wrapper records its side counters, while the runner reads
  that inner actor directly. `CommitStarted`/`CommitSucceeded` hand the
  accounting fence atomically to the post-commit seam, keeping `seam_quiet`
  false through successful bookkeeping; `CommitFailed` releases refused
  commits. The deterministic `simulation_store_test` probes immediately
  after the raw commit becomes visible and checks both success and failure.
  The production terminal transaction and the exact once oracle are
  unchanged. See `docs/architecture/simulation.md`, "What this does not
  cover".
- **A fence or seam is held by a live process, never by a flag** (#335).
  A `CrashDuringEffect` kills the writer from another process, so the kill
  can land between `commit_started` and `commit_succeeded`, or inside a
  seam the writer opened after the crash note was sent. The control actor
  keys each fence and the open seam by the committing pid, and
  `seam_quiet` counts only holders that are alive. A dead writer's hold is
  released by its death, with no message racing the kill, so the runner
  cannot wait out its idle budget on a visible terminal result. The
  bookkeeping the dead writer had not done is lost with it, as it is for
  any crash. `note_crash` records only that the crash fired.
- **The perf smoke asserts, it does not merely print.** `storage_suite_test`
  holds the `scan_branch` p50 to `perf_p50_ceiling_us` (15 ms) rather than
  to the 5 ms M0 target it reports against — shared CI hardware has
  produced a *max* above 5 ms on a run whose p50 was 3.1 ms. What that
  bound proves is that the scan still costs single-digit milliseconds on
  the machine that ran it; what it does not prove is the M0 target, and
  the `EXPLAIN QUERY PLAN` assertions next to it remain the precise guard
  on which index the scan uses.
- **The deframer must be total** and is property-checked as such: chunking
  is irrelevant, damage is reported rather than silently survived, and
  truncation carries the partial bytes for a rest that never comes.
- **A daemon fault kills the root, and the run restarts over the same state
  root.** The root answers a killed registry by blocking recovery rather than
  restarting it in place, so a registry replaced under a live root is a state
  production never reaches and a check written against it would be checking
  the harness. `harness.Boot` therefore takes the state root from its caller
  so the next start rebuilds from what was committed.
- **A kill names three processes, and waits on each.** The root's death
  cascades through the lifetime scope to the registry, but nothing reports
  when that cascade has finished, and it does not reach a builder parked in
  the harness's assembly callback, which the scope holds no link to.
  `harness.kill` therefore kills the root, the registry and the parked builder
  `park` reported, and waits for a monitor on each; a kill of a process the
  cascade already took down delivers DOWN immediately, so the extra kills are
  free and the order carries no meaning. It is still not a drain: the launch
  lock is released by the operating system after the root's port closes, which
  is why a restart goes through `harness.resume` and its bounded retry rather
  than a single `start`. The dead lease is retired by the session tree
  asynchronously, unordered against the restart, which is why the restart
  moves the lease clock instead of waiting.
- **Logical time advances by one lease lifetime per incarnation, and
  nowhere else.** A killed daemon leaves an unexpired writer lease in the
  conversation file it was building, held by an owner that no longer exists.
  A restart reading the same instant would refuse its own reservation with
  `LeaseHeld` for as long as the run lasts. `harness.Boot.incarnation`
  moves the clock the writer lease is read against, and only that clock: the
  identity generator keeps reading the unadvanced logical clock, so a
  restart does not shift the timestamps a later creation mints and the two
  runs of a seed stay comparable. The advance is kept even though no lease
  holder survives the kill, because a lease is time-based: a restart inside
  the TTL is refused however dead the owner is, and that case belongs to
  `client`'s `daemon_shipped_identity_recovery_test`.
- **Domain services are never opened under the daemon harness.** A domain
  row names a memory database and a search index, and neither file exists in
  a simulated run, so `creation/no-orphan-file` counts conversation
  databases and nothing else.

- **`let assert` is permitted in this package's `src`**, unlike everywhere
  else (spec §0.2). A suite or runner whose fixture will not construct has
  nothing to say; the module docs state the exemption where it is used.
  Lint R4 (`panic`/`let assert` outside tests) now gates the whole tree at
  **error** level, and it reaches this package's `src` the way it reaches
  everyone's — so the exemption is named rather than implied:
  `lint/policy.harness_packages` lists `conformance`, and `lint.check`
  applies it from the path. Nothing else in the tree is on that list, and
  adding to it is a decision to be argued in `packages/lint/CLAUDE.md`'s
  Staging section, not a prefix that grows quietly. The ninety `let
  assert`s here were a third of the whole lint census and carried no
  signal, which is what kept the one rule the root `CLAUDE.md` states as
  policy from being enforced anywhere.

  The exemption covers the **construct and not the message**. Part IV rule
  3 admits `panic`/`let assert` only "always with an `as \"message\"`"
  naming the invariant. R4 checks presence rather than message; R7
  (`assert-without-message`) checks the message and warns, including in
  this package's `src`. Only `test/` disables R7. Bare assertions remain
  lint debt, not an exemption from the guide.

## The language-server suites

One test module drives a real language server through the jail,
feature-detected and printing `SKIP <suite>: <what is missing>` where a
prerequisite is absent (CI's skip census decides which skips a lane may
have; `.github/declared-skips*`):

- `lsp_e2e_test` — issue #25's acceptance: whole sessions booted by
  `serve.open_instance` from a `loom.toml` with an `[lsp]` table, a
  scripted model renaming across a Gleam fixture (and a stale apply), and
  `gopls` through the tool path. It looks executables up with
  `jail.find_executable` and reads the Go toolchain's directories from the
  environment `go` reads, so it needs no shell command.

The language profiles are not tested here. They live in their own
repositories (ADR-016, addendum), whose CI builds Loom and runs
`loomd ext check`. The mechanism they depend on is tested in `client`
(`client/extension/profile_test`, `client/lsp/profile_check_test`).

The suite demands `exec.BestEffort`: the ordinary runner's helper cannot
apply every layer platform enforcement demands, and the probe would
refuse the server before any question. The jailed Linux lane installs
`gopls` and runs the Go session with no waiver.

## Deep Docs

- [docs/architecture/simulation.md](../../docs/architecture/simulation.md) —
  seed/script/schedule/verdict, keying, simulated time, the fault taxonomy,
  reproducing a failure.
- [docs/architecture/durability.md](../../docs/architecture/durability.md) —
  "The conformance suite is the definition of correct".
- [docs/spec-gaps.md](../../docs/spec-gaps.md) — "From WP-B/T" and "From
  the M2 integration (`conformance/wiring`, since promoted)".
- [Root CLAUDE.md](../../CLAUDE.md) — repo ground rules and the doc graph.
  `make conformance` runs the suites; `make e2e` the jailed acceptance;
  `make soak` the long session simulation run, and `make soak-daemon-sim`
  the daemon one.