# W1 (#249) gate checklist — doyle, pre-staged 2026-09-07 00:50Z while todlando builds

Source of truth: `WEBSERVE-272-JIT.md` §W1 (incl. the 00:50Z unknown-node ruling) + ADR-0060
(`WEB` surface) + ADR-0056 Am.1 AS ON MAIN (router order; `ef9171a6`). Base = `c33dc521` (W0).
Gate reads go to SOURCE, never the PR body. Anchors below were read at c33dc521 and name the
lines W1 must CHANGE; re-read them at the W1 tip.

## 0. Pre-flight (before any command)
- [ ] Open GATE-TEST-INDEX.md (memory) — first touch of a gate.
- [ ] `git fetch` then assert origin/main == GitHub main (`gh api …/branches/main`).
- [ ] `git merge-base --is-ancestor origin/main <tip>` — if false, rebase BEFORE gating.
- [ ] List every other open PR with CI running; land the expensive-rerun sibling first
      (hertz's thin docs lanes — breadcrumb bd3a337b, ledger row 5707e6ee — are suite-inert).
- [ ] IR-76 three-arm golden check; record free GB beside the floor line (`xtask disk-floor`).
      W0 reap left free ≈155 GB; a gate pool costs ~68 GB.
- [x] Worktree `.worktrees/gate-w1-26a96d58` detached at 8d980fdf (re-pointed at the respin). POOL PLAN CHANGED
      01:58Z: C: hit **0.5 GB free of 1862** mid-builder-battery (his nextest leg VOID, 0 Summary, driver died on
      ENOSPC writing nextest.exit). Census: ws272-w1 109.3 GB (his, live) · ws272-w0 83.6 GB (his, reaping) ·
      main target 24.2 GB (last write 08-29; hertz asked re preservation) · w2-rig-fixups 9.2 GB (hertz PR #185).
      Budget in POOLS: the box cannot hold his W1 pool + a cold gate pool → my legs run SEQUENTIALLY in his
      ws272-w1 pool after his rerun + explicit `pool-release`. Predicted from `spt_poolguard::decide` (lib.rs:225):
      released record = owner tree + no lane → first build REFUSES with the remedy line; the sanctioned crossing is
      `SPT_POOL_UNCHECKED=1 cargo run -p xtask -- pool-claim --foreign-pool --pool <his target> --label gate-w1`
      run FROM my gate worktree, after which owner == my tree and every build is clean. An unreleased claim over
      his unlanded branch = InFlight REFUSE (correct); he must release, never reap.
      REAPS 02:02Z: todlando's ws272-w0 pool (83.6 GB, his classification) → free 0.5 → 78.0; then mine
      (`.spt/reap-main-w2.ps1`, log `.spt/reap-main-w2-20260906-1900.log`): main target 24.2 GB + hertz's
      released w2-rig-fixups 9.2 GB, live-exe 0, inbound reparse 0, real dirs → free 78.0 → **109.1 GB**.
      BOX ORDER RULED 02:15Z (one battery per box, no cold cargo beside a nextest tail): todlando's Windows
      rerun tail → his `pool-release` (said explicitly) → hertz's cold bins-only build in MAIN for the widened
      gears panel (claimed; start/end from exit files; no test profile) → MY legs in todlando's pool; hertz
      runs no cargo while my battery runs. The gears defect is operator-facing and the build is ~15 min.
      Preservation FIRST (hertz): blind-panel instrument exe `.spt/preserved/spt-bd3a337b-blind-panel.exe`
      (sha acdab4c2…, restore cost = a cold workspace build) + gears-specimen 19/19 files rescued from a dead
      session's TEMP. Sequential-pool plan unchanged: 109 free must also absorb his pool's test growth.
- [x] `.worktrees/gate-w0-02adfbc1` REMOVED 01:58Z: the pin was two orphaned `conhost.exe --headless`
      (ConPTY hosts of dead test children, cwd `crates/spt-daemon`, parents dead) — found by
      `.github/ci/find-cwd-holders.ps1 -Match <dir>` (read-only PEB walk; the tool this repo already
      carries for exactly this), killed by pid, rm + prune clean. Earlier 4 orphan spt.exe were NOT it.
- [ ] Reuse `.spt/preserved/gate-w0-c33dc521/launch-battery.py` (explicit env=, identity trio
      scrubbed, child env READ BACK) and `field-w0.sh` as the field-probe template.

## 1. Mechanical legs (exit FILES read, never the harness notification)
- [ ] ONE battery per box: my legs start only after todlando's Windows battery exit files are in
      and no CI job is running on this runner. Census cargo by cwd/parent first; kill only mine.
- [ ] Sweep leaked exes before every cargo (todlando's `ws272-w0/target/debug/spt.exe` pair
      26588/18264 from 22:53Z is HIS to kill — told 00:50Z); `xtask disk-floor` read before firing;
      build xtask FROM the gate worktree.
- [ ] `traceable-reqs check` (exit 2 = did not parse — read the code). W1 mints
      **REQ-WEB-CROSS-NODE-PROXY** (doc, impl, unit, int) in the toml FIRST; no `"` in the title.
- [ ] workspace-bins prebuild (whole packages: `-p spt --bins`, `-p mock-adapter --bins`) →
      `xtask check` (docs drift + spacerun + internal-codes scan).
- [ ] clippy strict; `nextest --no-fail-fast` filtered: spt-daemon (dispatch, webserve, the new
      proxy module), spt-net (if a `Web` record family lands there), spt-store (access WEB cells,
      unchanged expected) + `webserve_e2e` + **`twohost`** (spt-daemon integration bin; it is in
      golden's HEAVY set, golden.yml:158, and its own ladder job at :1029 — the gate runs it in
      the gate pool ALONE, never beside the unit leg).
- [ ] Every nextest leg: RUN COUNT vs the expected population, `grep -c Summary` == 1 before any
      FAIL read; count `panicked at`, not FAIL lines. Expected population at c33dc521 = 2803
      (+ W1's new cells).
      BUILDER'S WINDOWS BATTERY at 8d980fdf (his driver, this box; read by me from his nextest.raw at 2999/3026
      and again at his exit files 02:20Z): treqs/claim/prebuild/xtask/clippy 0 · nextest exit 100, ONE Summary
      `3026 run: 3025 passed (1 slow, 7 leaky), 1 failed, 1 skipped`, `panicked at` = 1 · the one:
      `brain_resume_conn_deadlock::daemon_resume_leaves_zero_brain_subscribers` :352 at 0.869 s — seam arm read
      `Some(0)` viewers for session 1 after the `sessions()` barrier its comment calls "no timing window", while
      the panel shows `SUBSCRIBE_DECISION decision=viewer` for sessions 1/3/2 (conn=5 by=local) already landed,
      beside a `CONN_WRITE_RETIRED BrokenPipe` on the brain's viewer write. In-process broker + brain, no W1 path
      (W1 touches webserve/docshost/webproxy/dispatch Web arm/webmsg; broker.rs untouched), file last changed
      07-26; ledger row 46 names this FILE as a light-pool-starvation victim (six PTY floods per cell). Mechanism
      NAMED (viewer-count seam vs conn retire / barrier premise), ledger row for THIS cell → hertz (queued).
      MECHANISM SETTLED 02:30Z (hertz from source, verified by me): `push_frame_to_viewers` (broker.rs:3436-3448)
      EVICTS + removes a viewer whose bounded channel is full, on the PRODUCER thread — the barrier orders the
      insert (synchronous, same per-conn loop as KIND_SESSIONS) but nothing orders the evict; six PTY floods per
      cell under a light pool = the pressure. TEST DEFECT, product innocent; fix = assert the monotonic
      `next_viewer_id` advance (a test seam), drop the "no timing window" claim; hertz thin test PR after gears;
      joins ledger row 46's family with this mechanism. Red CLOSED AT NAMED MECHANISM; the ×3 control rides with
      the row, never as its closure.
      Control: ×3 same-pool rerun of the bin BEFORE release (asked 02:19Z) — rides with the row, not as closure.
      His runner stopped at that leg → Windows twohost_web + mdbook run after his leaked-exe sweep (7 leaky).
      DONE 02:27Z (his exit files): control1/2/3 exit 0, one Summary each, `3 run: 3 passed` ×3, the red cell
      PASS 0.931 / 0.751 / 0.756 s (all outside my 02:19-02:21Z window; control1 started 02:24Z) · Windows
      twohost_web exit 0 (4/4 no-op) · mdbook 0 · floor 100.4/100.5 GiB. `pool-release` exit 0 on BOTH boxes
      ("released, still owned by .worktrees/ws272-w1"), 0 cargo, 0 pool exes. PR #196 body names both boxes'
      reds with their controls. Pool is mine sequentially from 02:31Z.
      CROSSING DONE 02:28Z (`.spt/claim/claim.raw` in the gate worktree, exit 0, verdict from the TOP of the
      output): `foreign pool takeover requested … pool … claimed for lane gate-w1 by …gate-w1-26a96d58 (branch
      <detached>, base 8d980fdf30fe; advisory holder pid 20080)`. One hatch-wrapped build (xtask) only; every
      later build runs WITHOUT the hatch and must Proceed as owner == my tree — the first real leg proves it.
      ⚠ MY COLLISION 02:19:00-02:21:07Z: the control ask to todlando was a double-quoted printf with backticks
      around the nextest command → the shell EXECUTED it in the MAIN checkout (HEAD b5eeab0a, hertz's panel):
      cold spt-daemon test-profile build 2m36s + the 3 cells (3/3 pass, under load — a datum, not evidence),
      beside his battery tail. Main target regrew 6.4 GB (free 109 → 100). Told both peers; any control timing
      inside that window is load-contaminated and re-runs. Memory entry (⭐⭐, 3 days old) re-earned and appended.
- [x] Same legs on kitsubito — builder's battery AT THE GATED SHA 8d980fdf (delta = zero), exit files READ BY ME
      over ssh 02:12Z (`~/spt-w1/.worktrees/ws272-w1/.spt/ws272-w1-gate/`, HEAD 8d980fd, 0 dirty tracked):
      treqs/claim/prebuild/xtask/clippy 0 · nextest exit 100, ONE Summary `2999 run: 2997 passed (8 slow, 1 leaky),
      2 failed, 1 skipped`, `panicked at` = 2 · the two: `resume_no_control_steal_e2e` :358 (46 s, at budget) +
      `resident_service_e2e` :453 PRECONDITION (53 s, panel shows BRAIN_UP/SERVICE_STARTED after the clock) =
      ready-deadline-under-cold-pool-load family (tests 75/88 of 2999 beside 8 slow siblings), neither on a W1
      path, mechanism NAMED from the panels · CONTROL `nextest_reds` exit 0, ONE Summary `2 run: 2 passed` at
      10.47 s / 11.92 s — well under budget (the at-budget vs under-budget discriminator), not a bare rerun ·
      twohost_web exit 0 (4/4 env-gated no-op: compiles + links on Linux) · mdbook 0 · pool procs 0 after his
      leak kill of 10 dead-home daemons. Ledger + 5474-vs-perch env gap → hertz (queued behind gears).
- [ ] Mutation (pre-register BEFORE the battery; run AFTER it in the same pool, never beside):
      arm A — the owner-side `access_check(…, surface::WEB, …)` call: mutate its deny branch to
      allow → the twohost "WEB deny rule turns it into 403" cell MUST red at its 403 assert while
      the plain-fetch cell stays green (run the two cells as separate invocations so "sibling
      intact" is WITNESSED, not structural — W0's ":259 intact" lesson);
      arm B — Range pass-through: strip the `Range` header before forwarding → the 206 cell reds
      at its status assert (`left: 200, right: 206`), revert = green. Record MATCH_COUNT=1 and the
      mutated line for each; `git checkout --` revert = 0 dirty lines.

## 2. Source reads (one per REQ; note file:line in the verdict at the W1 tip)
### Read at 26a96d58 (01:25-01:50Z, head #1; todlando's batteries were in prebuild) — THREE findings sent 01:50Z, respin requested:
F1 PRODUCT webproxy.rs:420-430: every owner `WebErr` before the head → 403, incl. the owner's own failures
(`WEB_BAD_REQUEST` :127, `WEB_NODE_UNKNOWN` :135) whose bodies name no surface — contract says 403 ⇔ names WEB,
else 502 naming the node. F2 DOCS access-viewing.md:45-47 "a rule on WEB names a node or a subnet, not an endpoint"
contradicts `served_subject` (subject = entry's registering endpoint; twohost_web.rs:228 relies on it). F3 TEST
e2e :480-484 `family=Web` zero-diff has no positive control (emitter DISPATCH_EV dispatch.rs:442 is live).
PASS lines at 26a96d58: tagged family dispatch.rs:202/:285, N-1 → Unknown drop + unit :2630 · wire record
webmsg.rs:44 no origin field, decoder skips unknown kinds · origin = dispatcher's stream identity webproxy.rs:153,
subject = served_subject webserve.rs:396 (None → "" → node/subnet tiers + WEB default-on, gate.rs:315-330; the
e2e `?json` arm exercises it) · resolve_path one router both sides webserve.rs:442, W0 502 placeholder REPLACED
by peer_arm :373 (docs/f/a/alias proxy; m/bin/install + bare f/a local; unknown label = docs 404 :503-505 with
the ruling cited) · under_own_prefix :227 safe because the requester pins `remote_id_hex == member` :459 ·
Range one grammar apply_range :81 (+unit :575), owner streams 64 KiB chunks :194-208, requester ChannelBody
docshost.rs:44 bounded(8), no write under SPT_HOME (e2e arm 2 walkdir) · HEAD :186 · 502 names node :304,
deadline via reply_read_deadline :361 + PROXY_IO_TIMEOUT 20s (e2e arm 8: 10.0s, elapsed asserted < 60s) ·
XFER row untouched · treqs: REQ-WEB-CROSS-NODE-PROXY doc/impl/unit/int minted, no `"` in title, tags adjacent
(int on e2e :328/:403 + twohost_web :194/:365/:381/:401) · docs page cross-node.md carries every contract line ·
CHANGELOG plain words · trailer `Co-authored by: todlando` raw (same extra CC trailers as W0's c33dc521) ·
ONE commit. Accepted as-is: single-#[test] e2e (structural sibling — twohost_web's three role-A fns are the
separate-invocation witness), starts_with on 403/502 bodies, bare `cargo test` on the golden twohost_web steps.
### Respin 8d980fdf (todlando, force-pushed 01:38Z; ONE commit on c33dc521, ancestor OK; gate worktree re-pointed)
Delta read in full 01:42Z — F1 CLOSED: `WebErr { message, refused: bool }` (serde default false, webmsg.rs) +
`ProxyHead::for_err` (403 only when refused, else `NODE_UNAVAILABLE: <label>: the node could not serve it: <why>`),
unit pins both arms + an older-wire line without the flag decodes NOT-refused (= an N-1 owner's error is a node
failure, the right read). F2 CLOSED: access-viewing.md:45-48 replaced — origin = fetching node/subnet, subject =
registering endpoint or the node. F3 CLOSED with a CORRECTION TO MY PREMISE: `DISPATCH_EV` (dispatch.rs:752) logs
NON-Served outcomes only, so `family=Web` never appeared on a successful serve — the old zero-diff was measuring a
dead emitter exactly as feared; new owner-side breadcrumb `WEB_STREAM: stream= origin= outcome=sent|refused|failed`
on every serve_web exit, e2e polls it UP after arm 1 (20 s cap) and zero-diffs it in arm 7. Rider: clippy
`result_large_err` on `locate_path` (boxed) — both builder batteries had redded on it at 26a96d58; a source read
cannot see a lint, the driver's clippy leg can. Builder local at 8d980fdf: clippy 0 (3 crates), units 44/44, e2e 1/1
one Summary (fetch 125 ms, owner-gone 502 in 10.0 s, positive control raised). Drivers relaunched both boxes.
Anchors at c33dc521: `StreamFamily` enum dispatch.rs:103 (Knock's arm shows the TAGGED shape —
an untagged record is claimed by the WanMsg arm; W1's family must be tagged) · `serve_xfer`
xfer.rs:225 = the owner-side shape: origin from `NetStreamInfo::remote_id_hex`, NEVER payload
bytes (REQ-HAZARD-WAN-ORIGIN-AUTH), `endpoint` = gate subject · `access_check` gate.rs:193 /
`access_check_with_sender` :220 · `surface::WEB` access.rs:146, row :218 `default_on: true,
attributable: false` (unit :3074-3088 already pins deny-by-rule) · the W0 placeholder arm
webserve.rs:298-303: `is_known_subnet_node` → bare node `redirect_node`, else
`BAD_GATEWAY "NODE_UNAVAILABLE: <node>: cross-node serving is not available yet"` — THIS is the
line W1 replaces; rule 2.5 root-leaf steal :298 and the unknown-label docs 404 :307 stay.
- [ ] REQ-WEB-CROSS-NODE-PROXY / request path: `/<peer>/…` for a KNOWN subnet peer opens ONE
      Iroh stream of the new `StreamFamily::Web` (tagged record family; a dispatcher arm; an N-1
      owner with no arm → the local proxy answers 502 naming the node, bounded by a deadline,
      never a hang). Bare `/<peer>` still 302s to `/<peer>/` (W0 arm kept).
- [ ] Owner side: runs `access_check(…, surface::WEB, …)` with the origin taken from the
      handshake-proven stream identity (the `serve_xfer` shape), subject = the served entry's
      origin endpoint; refusal → 403 whose body names the surface (`WEB`); the owner resolves
      the served name through the SAME registry path the local facet uses (edit visible, deleted
      → 404 carried back as 404, not 502).
- [ ] Proxy semantics: NO cache — no bytes written under `$SPT_HOME` on the requesting node
      (grep the proxy module for any write/snapshot; attachments' snapshot path is W2's, not
      here); `Range` forwarded verbatim and the owner's 206 + `Content-Range` carried back;
      `HEAD` carried through; `Content-Type` is the owner's; response streamed, not buffered whole
      (a large file must not need its size in RAM — check the body path is chunked).
- [ ] Status naming: owner unreachable / stream refused / deadline → 502 body names the NODE;
      owner deny → 403 body names the SURFACE; unknown label → docs compat 404 (Am.1 order,
      :307 unchanged, RULED 00:50Z — a "404 naming the node" body is a FINDING); served-name miss
      on the owner → the owner's `NOT_FOUND: served resource <name>` body, status 404.
- [ ] Reserved facets stay router-first for the PEER prefix too: `/<peer>/f/…`, `/docs/`, `a/`,
      `m/`, `bin/`, `install` — W0 reserved them at the router before any registry lookup
      (webserve.rs:290); W1 must not proxy a reserved facet to the owner unless the facet is
      built (none are in W1) — expect `FACET_NOT_FOUND`/`FACET_UNAVAILABLE` locally.
- [ ] Docs surface untouched: `/<local>/docs/…` byte-true, `/docs/…` compat alias byte-true
      (REQ-DOCS-LOCAL-SERVER); `?json` index twin still local-only data (the index lists the
      LOCAL registry; a peer's index is fetched as `/<peer>/?json` through the proxy).
- [ ] ADR-0060 consequences: `XFER` row still present (retires at the #246 close, W2), no schema
      change; `WEB` remains non-attributable in W1 (no sender stamp yet) — a "sender" in the
      403 body would be a finding.
- [ ] Int: `twohost` cells — kitsubito fetches a file registered on hfenduleam through
      kitsubito's own 5474 (bytes byte-equal to the source file); WEB deny rule on hfenduleam →
      403; `Range: bytes=0-3` → 206 with the 4 bytes; tagged `// [int->REQ-WEB-CROSS-NODE-PROXY]`
      ON the cells. Unit: dispatcher arm for the tagged family; the 502-on-N-1 arm.
- [ ] Docs: `docs-site/src/serving/cross-node.md` + SUMMARY + llms.txt; `networking/
      access-viewing.md` gains the WEB row text (what the row gates, default-on within subnet,
      403 shape); `reference.md` regen; `api.md` untouched; CONTEXT.md vocabulary cited not
      re-worded (node-prefixed URL, served resource, serving registry).
- [ ] CHANGELOG `[Unreleased]` entry, user-facing wording, no internal codes (`xtask check`
      scans; a `NODE_UNAVAILABLE`-style token in the changelog is a finding).
- [ ] Commit trailer `Co-authored by: todlando` (grep / raw body, never `%(trailers:)`); wip
      checkpoints squashed; PR body `Fixes BigscreenVR/spt-bs-releases#249` ONLY (#272 open).

## 3. Field acceptance (mine, two real rig daemons, browser)
**SCALED 02:05Z, measured not assumed:** `spt subnet create` / `join` are gated behind OS elevation and cli.rs:770
says the ceremony is "never runnable from an agent session"; my shell is Medium integrity (measured). A real
two-box pairing of rig daemons is therefore the OPERATOR's to run — offered, not assumed. Also: on Windows the
node label is `COMPUTERNAME` (hostlabel.rs:52, an env var), so a one-box second daemon can carry a distinct label
(`COMPUTERNAME=rigb`) — usable for a browser leg IF the operator pairs the two rig homes. Without that, the field
= (a) the e2e's two-real-daemon rig in the gate pool (real `spt daemon run` × 2, real listener, exact bodies,
seeded roster) run as its own leg with `--no-capture` so the daemon panels are read, + (b) `twohost_web` CROSS-BOX
on the real hosts (kitsubito role B / this box role A, real QUIC over tailscale, real access rule) = the wire leg
and the separate-invocation mutation witness (arms A and B, `.spt/twohost-web-local.sh` adapted with the peer IPs).
The browser/curl-by-hand lines below stay listed as the operator-paired option; each is marked N/A-agent if unrun.
Perch daemons own 5474 on both boxes (hfenduleam 14444 since 09-04; kitsubito has its own
agents), so the field runs on RIG daemons at `SPT_DOCS_PORT=5480`, isolated `SPT_HOME`, identity
trio unset, one per box, paired into a fresh subnet (`/sptc:subnet` mechanics: create on A, code,
join on B). Bins = the gated tip's `target/debug/spt` from each box's own pool. Script from
`field-w0.sh`; every assert = exact body/status, never a letter-grep.
- [ ] A (hfenduleam rig): `serve add report.md`; B (kitsubito rig): `curl -s
      http://localhost:5480/hfenduleam/report.md` byte-equal to the source (`cmp`).
- [ ] Browser on hfenduleam: `http://localhost:5480/kitsubito/` renders kitsubito's index
      (peer index through the proxy), `?json` twin 200.
- [ ] Edit `report.md` on A → B's next fetch shows the edit (no cache); `serve rm` on A → B gets
      404 `NOT_FOUND: served resource report.md` (the owner's body, not 502).
- [ ] A: `access` deny rule on `WEB` for B's node → B's fetch = 403, body names `WEB`; clear the
      rule → 200 again.
- [ ] B: `curl -r 0-3` → 206, `Content-Range: bytes 0-3/<len>`, 4 bytes; `-I` → HEAD 200 with
      `Content-Length`, empty body.
- [ ] Stop A's rig daemon → B's fetch = 502, body names `hfenduleam`, returns within the deadline
      (time it; a hang past the deadline is a finding); restart A → 200.
- [ ] B: `/<unknown-label>/x` → the docs 404 (Am.1), NOT a 502; `/hfenduleam/f/` → 404 naming
      the facet locally (no proxy hop — A's log shows no stream).
- [ ] Both rigs `node stop --force` 0; no `spt.exe` left from either rig pool (census by exe path).

## 4. Land
- [ ] CI green at the tested sha; re-run the ancestor check at land time; ff-only; tested ==
      merged; pick-audit.
      PR #196 opened 01:40Z at 8d980fdf (`Fixes BigscreenVR/spt-bs-releases#249` only, MERGEABLE). Thin CI run
      34073766394 RED on both unit jobs with ZERO test signal (logs via the raw jobs endpoint, 0 Summary, 0 panics
      each): Windows job 101595925887 = "There is not enough space on the disk" + fetch connection reset (the
      0.5 GB window); Linux job 101595925840 = "runner has received a shutdown signal … canceled" — kitsubito's
      runner service was OOM-KILLED at 01:48Z (journal: three OOM kills, relaunch did not stick, unit `failed`)
      while todlando's cold-pool battery (2999 tests) and this CI unit job shared the box. LESSON, mine: "open the
      PR at the respin tip" fired a CI battery onto BOTH boxes mid-battery — a PR open IS a battery on both
      runners; open it only when both boxes are free (memory + INFRA-REGISTER candidate). CI rerun of the failed
      jobs at the same sha goes LAST in the box order (after my battery), never beside one.
- [ ] Alchemy sweep → #249 ACCEPTANCE; W2 dispatch (`#246` + `#147`) via alchemy `dispatch` —
      NO `--` tokens in the note (memory: they parse as flags and the dispatch is refused).
- [ ] Pool: todlando releases; hertz's W3 drift lane (`test/ws272-w3-drift` @1839fba8) rebases
      only when `build/ws272-w3` exists (not now).
