On branch master
Your branch is ahead of 'origin/master' by 5 commits.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   docs/claude-memory/README.md
	modified:   docs/claude-memory/blog-series.md
	modified:   docs/claude-memory/p7-started.md
	modified:   docs/claude-memory/p8-started.md
	modified:   docs/claude-memory/project-name-leveva-p10.md

no changes added to commit (use "git add" and/or "git commit -a")
=== DIFF ===
diff --git a/docs/claude-memory/README.md b/docs/claude-memory/README.md
index 0486ca53..e6c32e8a 100644
--- a/docs/claude-memory/README.md
+++ b/docs/claude-memory/README.md
@@ -21,6 +21,7 @@
 - [PLAN.md rows stay thin](plan-md-rows-stay-thin.md) — never accumulate per-sub-phase detail in PLAN.md table rows; put it in PLAN-P<N>-progress.md + docs/progress-log/
 - [L1 cref static-symbol limit](l1-cref-static-symbol-limit.md) — static C fns have no cref_ oracle symbol → can't be L1-diffed; also every L1 test needs link_reference_archives()
 - [P-IAUTH state](piauth-state.md) — P5+P6 done; iauth-rs all 5 modules + handshake differential done; what's left; the relink/fd-0-socketpair differential-gate mechanism + C iauth.conf gotchas
-- [P7 started](p7-started.md) — P7 (I/O core) in progress; bsd.c/packet.c dropped, ircd.c + s_bsd.c leaves (P7d-s) + s_auth.c (P7u-v) partial-ported; what's left = the event-loop/auth core
+- [P7 complete](p7-started.md) — P7 (I/O core + event loop + glue) DONE 2026-06-07 (P7oo ported c_ircd_main, the last C logic); all C logic now Rust, only data globals + ~25 variadic trampolines remain; next = P8 (delete C + retire oracle)
+- [P8 started](p8-started.md) — P8 rips out the ~25 variadic sender trampolines (non-variadic Rust core + wire!-raw-byte-builder; PORT_*_P8x mechanism); P8a–P8i DONE (sendto_iauth / serv_butone+ops_butone / serv_v / match_servs+_v / prefix_one / match_butone / channel_butone+anon-machinery / common_channels / sendto_flog+logfiles_open-close); easy/clean leaves now exhausted — what's left is the keystone sendto_flag (247) + sendto_one (~437, blocked on leveva typed-numerics: reply(i) is a runtime fmt) + channel_butserv BLOCKED on sendto_flag; sender-call-graph caveat
 - [P7 L1 shared-global race](p7-l1-shared-global-race.md) — P7 L1 tests touching me/cref_me/local[]/highest_fd must serialize on a mutex (cargo runs #[test]s in parallel)
 - [SUMMON/utmp not required](summon-utmp-not-required.md) — summon + utmp_open/read/close in s_bsd.c are config-gated off (ENABLE_SUMMON/USERS_SHOWS_UTMP undef) → not compiled, nothing to port
diff --git a/docs/claude-memory/blog-series.md b/docs/claude-memory/blog-series.md
index 6377c818..27f19184 100644
--- a/docs/claude-memory/blog-series.md
+++ b/docs/claude-memory/blog-series.md
@@ -43,4 +43,6 @@ Each post = one topic, written for peers:
 
 - 015-the-loop-that-runs-every-test — P7ff `read_message` (s_bsd.c:2091/2088), the select() event loop, body of `io_loop` (ircd.c:1264, called up to ~6×/pass over fdas/fdall), LAST logic in s_bsd.c. THE post on the function the L1 oracle can barely touch: its real input is the kernel (select/accept/recvfrom/exit_client), so there's exactly ONE differentially-safe path — the EMPTY LOOP (`FdAry.highest=-1`, udpfd/resfd/adfd=-1, delay=0 → empty fd_set → `select(0,…,200ms)`=0 → no dispatch → return 0; read_message_diff.rs:73, two cases incl ro=1). Two near-empty asserts for the busiest fn in the program; the test file's own doc says "Why L1 here is one case by design." CENTERPIECE INVERSION (vs 010's coverage-by-ubiquity TRAP): here ubiquity is AIRTIGHT — read_message IS io_loop, so every byte the daemon moves flows through it → the whole golden_*/golden_s2s_* suite (~190 #[test]s, 2 real daemons, real bytes diffed) is its real test end-to-end. "You don't write a test for the event loop; the event loop runs every other test." Mara caveat: L2 is a great gate, lousy DEBUGGER (red = 1-of-50 suspects); the empty-loop L1 catches one thing but localizes. Secondary beats: (1) the DEAD `USE_POLL` half — C read_message is two event loops in a trenchcoat (#if/#else, SET_READ_EVENT/SET_WRITE_EVENT macros serve both backends), USE_POLL off → poll side never compiles → Rust ports select-only, macros evaporate to direct `libc::FD_SET`; ~430-line C fn → one Rust loop. Faithful-dead-code, CLEANER than 011 (compile-time `#if` vs 011's runtime-macro-constant-false). (2) the 8 statics (completed_connection/read_listener/read_packet/client_packet/ircd_no_fakelag/do_dns_async/polludp/check_ping) — all `static`, no cref_ oracle ([[l1-cref-static-symbol-limit]]/012), ported as module-private twins w/ read_message → 8 of 9 fns in the I/O-engine heart have ZERO L1 oracle, the 9th has the empty-loop case; biggest P7 port, thinnest L1 footprint. OPENS on the honest miscount in 014's closing (it said "two little static helpers"; it was EIGHT). Honest ledger: skeleton proven, all dispatch (accept/read/write/exit_client/do_dns_async/polludp/check_ping) untested-by-design → L2/soak. Closing mirrors 014's "So that's daemonize" cadence ("So that's read_message"). Footer-links 010/012/003/008/009/001. Topic was flagged in 014's closing as "the next one I'm nervous about"; user didn't name it. Verified vs s_bsd.rs:3201/3216/2500 + read_message_diff.rs + ircd.c:1264 + s_bsd.c:2091/2094/2110.
 
-Pick an unused topic for the next one. Most recent = 015 (read_message, P7ff — the event-loop spine; ONE empty-loop L1 case for the busiest fn + the L2-ubiquity-is-airtight-here inversion vs 010's trap; dead-USE_POLL-half + 8-statics-no-oracle beats; opened on 014's eight-not-two miscount). 009→010→011 was the I/O trilogy; 012 = coverage-limits at symbol granularity; 013 closed the 005 iauth loop (the launcher); 014 = the boot detach that CALLS start_iauth; 015 = the loop those boot fns hand control to. **s_bsd.c now has NO logic left** — only data globals (local[]/highest_fd/timeofday/fd arrays), a later-phase/P9 problem. P7 itself continues past read_message: P7gg try_connections, P7hh check_pings, P7ii delayed_kills, P7jj setup_me (all io_loop/timer/boot fns in ircd.c, landed by 2026-06-06) — candidate cluster for a future "the timer sweeps around the loop" post if one wants an io_loop-companion to 015. Still open beyond that: the variadic-trampoline family (flagged for 004, may have been folded in — check); the 56-cluster connected-component finding from P5 (touched in 006/008, runner-up for 012 — "the unit of migration isn't the function"); "faithful to the bugs" bug-for-bug reproduction (offered for 009, NOT picked — best examples spent in 005/006; the faithful-DEAD-CODE sibling is spent in 011/015, so a future bug-for-bug post must stick to REACHABLE-behavior bugs). The full process is in the project skill `create-blogpost` (`.claude/skills/create-blogpost/SKILL.md`).
+- 016-the-trampoline-with-no-riders — the INVERSE of 004 + the OPENING of P8 (delete the C). 004 explained why ~25 variadic `sendto_*` trampolines had to stay C and promised they die in P8 by deletion-not-translation; this is the first one out: **P8a `sendto_iauth`** (s_auth.c:120-170). THESIS = deleting a variadic isn't about the variadic — by P8 every caller is already Rust, so you move the `va_start` work to the call sites (where `format!` already lives) and the fn loses its `...` → becomes `pub unsafe fn sendto_iauth(line:&[u8])` (s_auth.rs:38). CLEANEST-FIRST insight (title metaphor): `nm` showed ZERO live C callers (all remaining C callers in `#ifdef`'d-out bodies) = "no riders"; all 24 callers already Rust → deleting touches only Rust sites I control → picked it first ON PURPOSE as the safe one to learn the mechanics on. Mechanics shown: the before/after `sendto_iauth(c"%d U %s",fd,user)`→`sendto_iauth(format!("{} U {}",fd,ia_str(user)).as_bytes())`; `ia_str` (s_auth.rs:77) = lossy C-string read, byte-faithful bc iauth pipe protocol is ASCII. FAITHFUL-BUG beat (REACHABLE-behavior-adjacent but actually unreachable): the C write loop sets `p=abuf` then `write(adfd,abuf,len)` from the BASE while advancing `p+=i` never used → dead cursor, would double-send on a partial write, but tiny lines on a local pipe = one write so it never fires; replicated bug-for-bug anyway (re-issue from base). ORACLE-IS-ALLOWED-TO-BE-VARIADIC beat (the funny one): I can't DEFINE an extern"C" variadic in stable Rust but the cref_ oracle is STILL C (unguarded s_auth.o) so `cref_sendto_iauth(fmt,...)` stays variadic — drive same line both ways (oracle vsprintf vs Rust pre-formatted bytes), 2 socketpairs, byte-diff the pipe (sendto_iauth_diff.rs). Honest holes: debug `-1 E last=%u start=%x` pointer line (nondeterministic→not diffed) + lost-slave hard-error branch (can't force fatal write→by-inspection). leveva-deferred note: format!-now not leveva typed Message bc this carries the iauth PIPE protocol `<id> <cat> <info>` not IRC msgs ([[p8-started]] decision). Ledger: 1 of ~25; keystones `sendto_one`(~478)/`sendto_flag`(~255) still per-recipient-hard per 004's vsendpreprep. Guard `PORT_S_AUTH_SENDTO_IAUTH_P8a` (build.rs:292). Footer-links 004/003/005. Topic auto-picked (freshest commit, opens P8); user didn't name it. Verified vs s_auth.rs:38/77 + s_auth.c:120 + sendto_iauth_diff.rs + build.rs:292 + 2026-06-07-p8a plan.
+
+Pick an unused topic for the next one. Most recent = 016 (sendto_iauth, P8a — the FIRST variadic trampoline deleted; inverse of 004, opens P8; "no riders" = nm-zero-C-callers cleanest-first; move-the-va_start-to-the-callsite mechanic + ia_str; faithful dead-p-cursor bug; oracle-stays-variadic-because-it's-still-C test; leveva-deferred for the iauth pipe protocol). The P8 keystones (`sendto_one`/`sendto_flag`, per-recipient `va_arg` in vsendpreprep — the hard ones 004+016 both flag) are the obvious next blog beats AS THEY LAND (not yet ported as of 2026-06-07). Earlier: 015 (read_message, P7ff — the event-loop spine; ONE empty-loop L1 case for the busiest fn + the L2-ubiquity-is-airtight-here inversion vs 010's trap; dead-USE_POLL-half + 8-statics-no-oracle beats; opened on 014's eight-not-two miscount). 009→010→011 was the I/O trilogy; 012 = coverage-limits at symbol granularity; 013 closed the 005 iauth loop (the launcher); 014 = the boot detach that CALLS start_iauth; 015 = the loop those boot fns hand control to. **s_bsd.c now has NO logic left** — only data globals (local[]/highest_fd/timeofday/fd arrays), a later-phase/P9 problem. P7 itself continues past read_message: P7gg try_connections, P7hh check_pings, P7ii delayed_kills, P7jj setup_me (all io_loop/timer/boot fns in ircd.c, landed by 2026-06-06) — candidate cluster for a future "the timer sweeps around the loop" post if one wants an io_loop-companion to 015. Still open beyond that: the variadic-trampoline family (flagged for 004, may have been folded in — check); the 56-cluster connected-component finding from P5 (touched in 006/008, runner-up for 012 — "the unit of migration isn't the function"); "faithful to the bugs" bug-for-bug reproduction (offered for 009, NOT picked — best examples spent in 005/006; the faithful-DEAD-CODE sibling is spent in 011/015, so a future bug-for-bug post must stick to REACHABLE-behavior bugs). The full process is in the project skill `create-blogpost` (`.claude/skills/create-blogpost/SKILL.md`).
diff --git a/docs/claude-memory/p7-started.md b/docs/claude-memory/p7-started.md
index af27b3db..13628afe 100644
--- a/docs/claude-memory/p7-started.md
+++ b/docs/claude-memory/p7-started.md
@@ -1,94 +1,65 @@
 ---
 name: p7-started
-description: P7 (I/O core + event loop + glue) progress; bsd.c (P7a) + packet.c (P7b) dropped, s_bsd.c FULLY drained of logic incl. the read_message event loop (P7ff) + daemonize/start_iauth (P7dd/ee) — only data globals remain, s_auth.c (P7u-P7y) all non-variadic logic done, ircd.c partial via ircd_link.o (P7c/P7t/P7gg/P7hh/P7ii/P7jj/P7kk: tune pair, calculate_preference, try_connections, check_pings, delayed_kills, setup_me, signal-handler+restart+server_reboot cluster); what's left = ircd.c c_ircd_main/io_loop + setup_signals/bad_command/open_debugfile helpers + variadic trampolines (P8)
+description: P7 (I/O core + event loop + glue) is COMPLETE as of 2026-06-07 (P7oo ported c_ircd_main, the last C function with logic). All C *logic* is now Rust; only data globals + the ~25 variadic sender trampolines remain. Next phase is P8 (delete the C + retire the oracle harness). Per-cluster detail in PLAN-P7-progress.md + docs/progress-log/p7.md.
 metadata: 
   node_type: memory
   type: project
   originSessionId: 4f57516a-af1b-4de7-ae4d-ab62168da772
 ---
 
-As of 2026-06-05, **P7 (I/O core + event loop + glue) has started** — the last
-faithful-port phase (P1–P6 + P-IAUTH modules all done). Ported bottom-up / leaf-first,
-same mechanism as P6, recorded per-cluster in `PLAN-P7-progress.md` +
-`docs/progress-log/p7.md`. Use the `command-cluster-port` skill's procedure (it
-generalizes to any TU port: RED L1 → force-RED via PORTED → GREEN port → L1/L2).
+**P7 (I/O core + event loop + glue) is COMPLETE as of 2026-06-07.** This was the last
+faithful-port phase (P1–P6 + P-IAUTH all done before it). Ported bottom-up / leaf-first,
+same mechanism as P6, recorded per-cluster in `PLAN-P7-progress.md` (one-line summaries) +
+`docs/progress-log/p7.md` (full entries) — **read those for any cluster detail, not this**.
+The `command-cluster-port` skill's procedure generalizes to any TU port (RED L1 → force-RED
+via PORTED → GREEN port → L1/L2).
 
-**Done (full per-cluster detail in `PLAN-P7-progress.md` + `docs/progress-log/p7.md` — read those, not this):**
-- P7a `common/bsd.c` (`deliver_it`+`dummy`) → **`bsd.o` dropped**; P7b `common/packet.c`
-  (`dopacket`) → **`packet.o` dropped**.
-- `ircd.c` partial via `ircd_link.o`: P7c tune-pair (`ircd_writetune`/`ircd_readtune`,
-  `-DPORT_IRCD_TUNE_P7c`), P7t `calculate_preference` (`-DPORT_IRCD_CALC_PREF_P7t`).
-  `c_ircd_main`/`me`/signals/`server_reboot` stay C → drop near-last (removing
-  `c_ircd_main` is the Rust-entry keystone).
-- `s_bsd.c` partial via `s_bsd_link.o`: **P7d–P7s** ported nearly every s_bsd leaf —
-  socket/file utils (P7d), `add_local_domain` (P7e), the teardown chain
-  `delay_close`/`close_client_fd`/`close_connection`/`close_listeners` (P7f–i),
-  `activate_delayed_listeners`/`add_connection_refuse` (P7j–k), the UDP CPING pair
-  `setup_ping`/`send_ping` (P7l–m), the listener (re)construction
-  `open_listener`/`reopen_listeners`/`add_listener`/`inetport` (P7n–p), `report_error`
-  (P7q), `init_sys` (P7r), `get_my_name` (P7s, de-static'd `mysk`). One `-D…_P7x` guard
-  per leaf, all on the `s_bsd_link.o` recipe.
-- `s_auth.c` partial via `s_auth_link.o`: P7u iauth `/STATS` reporters
-  (`report_iauth_conf`/`report_iauth_stats`, de-static'd `iauth_conf`/`iauth_stats`
-  list heads), P7v `set_clean_username` (de-static'd, the last pure-logic leaf), P7w
-  the ident (RFC1413) protocol I/O pair `send_authports`/`read_authports`
-  (`-DPORT_S_AUTH_AUTHPORTS_P7w`; both already global in s_auth_ext.h → no de-static;
-  L1 fd I/O over socketpairs + a real IPv6-loopback socket so getsockname populates
-  sin6_port), P7x the ident *initiator* `start_auth` (`-DPORT_S_AUTH_START_AUTH_P7x`;
-  opens the non-blocking `authfd`, builds the iauth `"<fd> C <themip> <themport> <usip>
-  <usport>"` query when `adfd>=0` else `bind`/`connect`s `[peer]:113`; L1 over a shared
-  real IPv6-loopback `cptr->fd` so the query bytes are byte-identical), P7y the
-  iauth-pipe line parser `read_iauth` (`-DPORT_S_AUTH_READ_IAUTH_P7y`; the LAST
-  non-variadic logic in s_auth.c — drains `adfd`, persistent `obuf`/`olen` partial-line
-  carry + per-opcode dispatch `O`/`V`/`A`/`a`/`s`/`S`/`U`/`u`/`o`/`D`/`K`/`k`/garbage;
-  **P7z (back in s_bsd.c) ports `check_client`** (`-DPORT_S_BSD_CHECK_CLIENT_P7z`; the
-  ordinary-client access check called from the Rust `register_user` — getpeername
-  peer addr → `ip`/`port`, DNS host↔ip verify (IP# Mismatch→clear `hostp`),
-  `attach_Iline`; `NO_OPER_REMOTE`/`UNIXPORT` undef → no `FLAGS_LOCAL`/unix branch /
-  no `mysk`; the static `check_init` it shared with the still-C `check_server_init`
-  becomes a private Rust twin (GCC inlines the surviving C static into its sole
-  remaining caller) — the P7p `set_sock_opts` precedent; L1 4-case zero-diff over a
-  shared IPv6-loopback fd + empty conf, L2 = `golden_registration` success path);
-  file-scope `iauth_version`/`iauth_conf`/`iauth_stats`/`iauth_options`/`iauth_spawn`
-  stay C-owned, variadic `sendto_iauth`/`sendto_flag` *called*; L1 10-case zero-diff over
-  per-world socketpair `adfd`, incl. obuf/olen partial-carry + istat-decrement via
-  per-world `MyMalloc`/`cref_MyMalloc`; finding: per-client prefix uses the ported
-  `inetntop` that expands `::1`→`0:0:0:0:0:0:0:1`). **s_auth.c now has only the variadic
-  `sendto_iauth`/`vsendto_iauth` left (→ P8 trampolines).**
+**Outcome:** every C translation unit is now drained of *logic*:
+- `bsd.c` (P7a) + `packet.c` (P7b) dropped outright.
+- `s_bsd.c` fully drained (P7d–P7ff: socket/file leaves → teardown → listeners →
+  `add_connection`/`connect_server` → `start_iauth`/`daemonize` → the `read_message`
+  select/poll event loop). Only its data globals (`local[]`/`highest_fd`/`timeofday`/`FdAry`)
+  remain C-owned (the mio-ownership rewrite is **P12**, not P7).
+- `s_auth.c` ident/iauth-pipe I/O ported (P7u–P7y, + P7z `check_client` back in s_bsd.c).
+  Only the variadic `sendto_iauth`/`vsendto_iauth` remain.
+- `ircd.c` fully drained: P7c/P7t tune-pair + `calculate_preference`; P7gg–P7ii the io_loop
+  timers (`try_connections`/`check_pings`/`delayed_kills`); P7jj `setup_me`; P7kk the
+  signal-handler + `restart`/`server_reboot` cluster; P7ll `setup_signals`; P7mm `io_loop`;
+  P7nn `bad_command`/`open_debugfile`; **P7oo `c_ircd_main` (the boot spine — the LAST C
+  function with logic)**. Guarded out via `ircd_link.o` (`-DPORT_IRCD_*`). `ircd-rs/src/main.rs`
+  still calls `ircd_sys::c_ircd_main`, which resolves to the Rust `#[no_mangle]` def; `nm`
+  confirms `T c_ircd_main` from Rust and `ircd_link.o` defines only data globals.
 
-**`s_bsd.c` is now FULLY drained of logic.** The `read_message` select/poll event loop
-+ its 8 statics (`read_listener`/`client_packet`/`read_packet`/`check_ping`/`polludp`/
-`do_dns_async`/`ircd_no_fakelag`) ported P7ff; `daemonize`/`start_iauth` P7ee/P7dd. Only
-`s_bsd.c`'s data globals (`local[]`/`highest_fd`/`timeofday`/`FdAry`) remain C-owned (the
-mio-ownership rewrite is P12, not P7). These were all **L2-gated** (fork/loop/network-I/O,
-not L1-differentiable) → covered by the full `ircd-golden` suite, which IS `io_loop`'s body.
+The boot-spine / event-loop / signal / setup_me ports are all **L2-gated, no L1** (fork/
+loop/network-I/O/global-table mutation → not L1-differentiable) — covered by the full
+`ircd-golden` suite (86 tests byte-identical). The one persistent failure is
+`golden_s2s_s_serv_stats` = the documented [[p5-s2s-stats-flake]] (uninitialized-sendq
+"sq" garbage, non-deterministic, present on clean HEAD too — NOT a regression).
 
-**Remaining C *logic* = `ircd.c`'s process-lifecycle core (the genuine spine):**
-- `ircd.c` — `c_ircd_main`/`main`, `io_loop`, `setup_signals`, and the helpers
-  `bad_command`/`open_debugfile`. The `me` by-value global lives
-  here too. Already ported via `ircd_link.o`: P7c tune pair, P7t `calculate_preference`,
-  P7gg `try_connections`, P7hh `check_pings`, P7ii `delayed_kills` (both io_loop timer
-  helpers), **P7jj `setup_me`** (ircd.c:723, the boot `me`-singleton initializer —
-  de-static'd; **L2-gated, no L1** because it mutates 4 shared global tables [client/sid
-  hash, server_name interning, channel hash] + the `me` singleton + `istat`, the
-  P7dd/ee/ff precedent; golden boot suite is the gate), **P7kk the signal-handler +
-  reboot cluster** (`s_die`/`s_slave`/`s_rehash`/`s_restart`/`restart`/`server_reboot`,
-  ircd.c:73-215, `-DPORT_IRCD_SIGNALS_P7kk`; de-static'd the `dorehash`/`dorestart`/
-  `restart_iauth` flags [shared w/ still-C io_loop] + `s_rehash`/`s_slave`; `IRCD_PATH`
-  → `ircd_sys::SERVER_PATH` for `server_reboot`'s execv; L1 = `ircd_signals_diff.rs`
-  flag transitions, terminating exit/execv arms faithful-by-inspection; L2 = boot gate +
-  golden_s_serv_shutdown/_maint). **Next leaves:** `setup_signals` (now UNBLOCKED — the
-  handlers are Rust; it just needs `dummy` [already Rust, P7a] + the line-34 forward-proto
-  split with the still-C io_loop/open_debugfile), `bad_command` (printf+exit, untestable),
-  `open_debugfile` (empty body under DEBUGMODE-off — a near-free guard+drop). Then
-  `io_loop`, then the keystone `c_ircd_main` (removing it makes Rust the real entry).
-- `s_auth.c` I/O — only the variadic `sendto_iauth`/`vsendto_iauth` (va_list → P8
-  trampolines) remain. **All non-variadic logic in s_auth.c is now Rust.**
-- `support.c`/`send.c` variadic remnants (`irc_sprintf`/the `sendto_*` family) → **P8
-  trampolines by design, not P7**.
+**Remaining C (verified 2026-06-07 by `nm` on a freshly-rebuilt `libircd_c.a` — the on-disk
+archive goes stale after `-D`-flag-only changes since `make` keys off the unchanged `.c` mtime;
+`rm cbuild/*_link.o` + rebuild for true symbols):**
+- **Variadic senders + their `va_list` formatters** (NOT pure trampolines — they carry
+  per-recipient formatting logic, e.g. `vsendpreprep`/`build_suffix` consume `va_arg` per
+  recipient): `send.c` `sendto_one/flag/serv_butone/ops_butone/prefix_one/common_channels/
+  channel_butone/channel_butserv/match_butone/match_servs(+_v)/serv_v` + `vsendto_one`/
+  `vsendprep`/`vsendpreprep`/`sendto_flog`/`dead_link`; `s_send.c` `esendto_*` + statics
+  `build_suffix`/`build_new_prefix`/`esend_message`; `s_auth.c` `sendto_iauth`/`vsendto_iauth`;
+  `support.c` `snprintf_append`.
+- **Non-variadic helpers entangled with those senders' file-static buffers, NOT yet Rust:**
+  `initanonymous`/`setup_svchans`/`logfiles_open`/`logfiles_close` (send.c),
+  `make_isupport`/`dgets` (support.c). So "all C *logic* is Rust" is an OVERSTATEMENT — these
+  ~6 are real unported logic riding in the partially-ported send.c/support.c TUs.
+- **Pure data globals** (`me`/`client`/`local[]`/`highest_fd`/`msgtab`/timers/`configfile`…);
+  `ircd_link.o` + `s_bsd_link.o` now have ZERO code symbols, only these.
+Stable Rust can't define `extern "C"` variadics → all the above is P8 by design.
 
-The remaining ircd.c fns are mostly L2-gated (signals/exit/fork) or de-static-then-L1
-like check_pings/try_connections (the non-destructive paths). See
-[[p7-l1-shared-global-race]] for the L1 gotcha
-(shared C globals like `me`/`local[]`/`highest_fd` need a serializing mutex in tests).
-Related: [[rust-migration-plan]], [[work-on-master-directly]], [[plan-md-rows-stay-thin]].
+**Next phase: P8 — delete the C + retire the oracle harness.** Replace the variadic sender
+trampolines with a non-variadic Rust sender API at every call site, then drop all C
+compilation from `ircd-sys` (no more `cc::Build`), run the full L1/L2/L4 suite byte-identical
+vs reference-C one last time, then mothball the oracle and migrate the load-bearing tests into
+`ircd-common` as self-contained Rust tests. After P8: 100% Rust workspace, zero C TUs.
+
+See [[p7-l1-shared-global-race]] for the L1 gotcha (shared C globals like `me`/`local[]`/
+`highest_fd` need a serializing mutex in tests). Related: [[rust-migration-plan]],
+[[work-on-master-directly]], [[plan-md-rows-stay-thin]], [[project-name-leveva-p10]].
diff --git a/docs/claude-memory/p8-started.md b/docs/claude-memory/p8-started.md
index 443a4194..80753258 100644
--- a/docs/claude-memory/p8-started.md
+++ b/docs/claude-memory/p8-started.md
@@ -70,15 +70,109 @@ discipline still applies (replicate even C bugs; byte-identical wire output).
   `sendto_match_servs_diff.rs` (5 cases incl. the mask-filter inverse); L2-S2S covered by
   existing `golden_s2s_{topic,kick,membership,mode,njoin,join}`.
 
-**Left (still C variadic trampolines, Rust call-site counts):** `sendto_one` ~450,
-`sendto_flag` ~219, `sendto_prefix_one` (9), `sendto_channel_butone`
-(8)/`_butserv` (15), `sendto_match_butone` (1),
-`sendto_common_channels` (5), `sendto_flog`, + `irc_sprintf`/`snprintf_append` (P1-deferred
-format engine, deleted not ported per P11). Live in `send_link.o` (+ `s_send.c` esendto_*).
-`sendto_one`/`sendto_flag` are the keystone, BUT most `sendto_one` sites use a **runtime**
-`reply(i)` format string (from `replies[]`) — `format!`/`wire!` can't bind a runtime fmt, so
-`sendto_one` is blocked on the **leveva typed-numeric layer** (P10), not a mechanical pass.
-Senders with **static** formats (DONE: serv_butone/serv_v/match_servs+_v; LEFT:
-channel_butone/butserv, prefix_one, common_channels, match_butone) are convertible now via
-`wire!`. Guard byte-identity vs C `irc_vsprintf` 512-truncation when adopting leveva
-`to_wire()`.
+- **P8e — `sendto_prefix_one`** (send.c:1017-1027, the first `vsendpreprep`-based prefix
+  sender). Clean leaf: NO in-send.c caller (internal paths use the `static
+  vsendto_prefix_one`; only external now-Rust callers reach the public variadic).
+  Introduces the **`prep_preprep` Rust core** = faithful `vsendpreprep` (send.c:388-419,
+  IRCII_KLUDGE off): special path (`to && from && MyClient(to) && IsPerson(from)`)
+  collapses the `:%s` prefix arg `par` to `:from->name!user@host` when `mycmp(par,
+  from->name)==0`, else `:par`; non-special emits `:par`+rest verbatim; reuses `prep_line`.
+  Two faithfulness reductions: every caller leads with `:%s` so the C `!strncmp(...,":%s",3)`
+  guard reduces to the to/from test (caller supplies `par`+pre-formatted `rest`); the
+  `from == &anon` disjunct is unreachable from Rust (only still-C channel senders pass
+  `&anon`, they keep using C `vsendpreprep`) → encoded only the `mycmp` arm, anon lands
+  with those senders. `pub unsafe fn sendto_prefix_one(to, from, par: *const c_char, rest:
+  &[u8])`; 10 call sites (s_numeric numeric relay; channel INVITE×2; s_user
+  PRIVMSG/NOTICE×4 + KILL) build `rest` with `wire!`. The static `vsendto_prefix_one` +
+  `vsendpreprep` STAY C. `-DPORT_SEND_PREFIX_ONE_P8e`. L1 `sendto_prefix_one_diff.rs`
+  (collapse / no-collapse / non-special verbatim / >510 trunc; **gotcha:** NUL-terminate
+  fixtures before `strcpy` or you overrun `namebuf` → heap corruption — use a bounded
+  `set_cstr`); L2 = existing `golden_channel_invite` / `golden_s_user_message` /
+  `golden_s2s_message` / `golden_s_user_kill` / `golden_s2s_kill`.
+
+- **P8f — `sendto_match_butone`** (send.c:935-987, the `$$`/`$#`-mask broadcast prefix
+  sender). Clean leaf: NO in-send.c caller, ONE call site (`m_message` in s_user.rs).
+  REUSES the P8e `prep_preprep`/`sendto_prefix_one` core verbatim — delivery is
+  `vsendto_prefix_one(cptr, from, …)` with the **real** `from` (NEVER `&anon`), so no anon
+  machinery needed (that's the channel senders' problem). `pub unsafe fn
+  sendto_match_butone(one, from, mask, what, par, rest: &[u8])` walks `i=0..=highest_fd`
+  over `local[i]`, skip NULL + origin `one`; server recipient → walk `cptr->prev` for first
+  `is_registered_user(srch) && srch->from==cptr && match_it(srch,mask,what)`; non-server →
+  require client itself match; each survivor → `sendto_prefix_one`. Added `match_it`
+  (MATCH_HOST=2→`user->host` array, MATCH_SERVER=1→`user->server` ptr; `match_`==0 on match)
+  + `is_registered_user` (= `is_person`). `-DPORT_SEND_MATCH_BUTONE_P8f`. L1
+  `sendto_match_butone_diff.rs` (4 cases incl. inverses; **gotcha:** NUL-terminate `mask`/
+  `par` fixtures — bare `b"*.ok"` overran → `match_` missed); L2 = existing
+  `golden_s_user_message`/`golden_s2s_message`.
+
+- **P8g — `sendto_channel_butone` + the `anon` machinery** (send.c:459-510). The channel
+  broadcaster + the FIRST anon-needing sender. Ported `anon`/`ausr`/`initanonymous` from C
+  to Rust as `#[no_mangle] pub static mut` globals (`MaybeUninit::zeroed`) + an extern-C
+  `initanonymous`; the still-C `vsendpreprep`/`sendto_channel_butserv` reference them via
+  `extern` decls (guarded by `-DPORT_SEND_ANON_P8g`, replacing the `static` defs with
+  `extern`). `prep_preprep` grew the `from == anon_ptr()` collapse arm. The non-variadic
+  core routes BOTH the C raw-server (`vsendprep`) and prefixed-MyClient (`vsendpreprep`)
+  paths through the P8e `sendto_prefix_one` core — byte-identical because `prep_preprep`
+  already branches on `my_client(to)` (server → else-path `:par`, MyClient → collapse; a
+  local STAT_CLIENT always has `user` so the MyConnect-non-eligible case is never MyClient).
+  7 call sites (s_numeric/channel×5/s_user) build `rest` with `wire!`.
+  `-DPORT_SEND_CHANNEL_BUTONE_P8g`. L1 `sendto_channel_butone_diff.rs` (parallel
+  Rust/cref channels — channel passed by arg, no global; 4 cases: broadcast
+  collapse/verbatim/IsMe-skip, `one` exclusion+inverse, self-send-not-doubled, anon-channel
+  collapse; **gotchas:** cref's global `sendbuf`/`psendbuf` + `anon` globals → `GLOBALS_LOCK`
+  serialize; `STAT_ME == -1` not -2); L2 = channel join/part/kick/topic/mode_set/invite +
+  s_user_message + s2s message/join/kick/topic/mode.
+
+- **P8h — `sendto_common_channels`** (send.c:620-729, the local-channel-peers broadcaster
+  for NICK/QUIT). Clean leaf, NO C caller, **no anon** (skips anonymous channels → `from`
+  always the real `user`). Key faithfulness call: C preps the line ONCE (`if (!len)`,
+  DEBUGMODE off) into `psendbuf` + reuses it for all recipients → ported as a local
+  `[u8;520]` + `len`, calling `prep_preprep` only when `len==0`, NOT `sendto_prefix_one` per
+  recipient (which re-preps against each `to`) — matters in the big-client branch where a
+  remote (`fd==-1`, not MyClient) `clist` member still receives the cached FIRST-recipient
+  line. Both Comstud branches ported (`highest_fd<50` HUB `IsMember`-over-`user->channel` +
+  the `>=50` `clist`/`sentalong` walk). `sentalong` is a per-call `vec![0;MAXCONNECTIONS]`
+  indexed via raw `.offset((*cptr).fd as isize)` (matches C's `fd==-1` OOB pointer arith, no
+  Vec panic). New private `is_member`/`is_quiet` (via P2 `find_channel_link`). `pub unsafe fn
+  sendto_common_channels(user, par: *const c_char, rest: &[u8])`; 3 call sites (s_misc
+  exit_client QUIT; s_user nick-save + m_nick NICK) → par + `wire!` rest.
+  `-DPORT_SEND_COMMON_CHANNELS_P8h` (the now-unused `sentalong` static guarded too). L1
+  `sendto_common_channels_diff.rs` (parallel rust/cref `local[]`+`highest_fd` worlds w/
+  per-client `user->channel` Link lists, 4 cases: shared-channel broadcast+self-send+inverse,
+  quiet-skip, anon-skip, remote-user no-self-send; `GLOBALS_LOCK` serializes); L2 =
+  `golden_s_user_nick`/`golden_s_user_quit` + S2S `golden_s2s_nick`/`golden_s2s_quit`.
+
+- **P8i — `sendto_flog` + `logfiles_open`/`logfiles_close` + the `userlog`/`connlog` fd
+  statics** (send.c:1202-1440). The FIRST **non-variadic** leaf — `void sendto_flog(cptr,
+  char msg, username, hostname)`. Ported the whole connected component over the shared
+  file-private fds (the logger + its open/close pair + the two statics) to
+  `ircd-common/src/send.rs`; `setup_svchans`/`svchans` (a *separate* component shared with
+  the still-C variadic `sendto_flag`) stay C. **Formatting = byte-identical by
+  construction:** `libc::sprintf` with the exact C format string `"%c %d %d %s %s %s %s %d
+  %s %lu %llu %lu %llu "` + args cast to C's varargs promotions (`%c`/`%d`→`c_int`,
+  `%lu`→`c_ulong`, `%llu`→`c_ulonglong`, `(u_int)firsttime`/`(u_int)timeofday` via `as u_int
+  as c_int`) — same libc engine + same fmt ⇒ no logic to drift. Config: `LOG_OLDFORMAT`/
+  `USE_SYSLOG`/`USE_SERVICES`/`LOG_SERVER_CHANNELS`/`LOGFILES_ALWAYS_CREATE` all OFF (only the
+  new-format `#else` + the `logfile==-1` early-return + a no-`O_CREAT` open compile).
+  `FNAME_USERLOG`/`FNAME_CONNLOG` reach Rust via new `IRCD_USERLOG_PATH`/`IRCD_CONNLOG_PATH`
+  rustc-envs (the `PID_PATH` make-expand trick) → `ircd_sys::{USERLOG_PATH,CONNLOG_PATH}`
+  consts. `-DPORT_SEND_FLOG_P8i`. L1 `sendto_flog_diff.rs` = the **write_pidfile pattern**:
+  both worlds open the same hardcoded log path so drive open→flog→close in rust+cref, read
+  back, assert identical bytes; sandbox `/usr/local/var/log` is unwritable → both no-op
+  (`None==None`), bytes pinned only where writable. **No L2/S2S** — file-only, `USE_SERVICES`
+  off → never on the wire; boot smoke via any golden (`logfiles_open` runs at every boot).
+  1 live `sendto_flog` caller (s_bsd `add_connection` clone-reject).
+
+**Left (still C variadic trampolines, Rust call-site counts):** `sendto_one` ~437,
+`sendto_flag` (247), `sendto_channel_butserv` (2 files), + `irc_sprintf`/`snprintf_append`
+(P1-deferred format engine, deleted not ported per P11). Live in `send_link.o` (+ `s_send.c`
+esendto_*). **The easy/clean leaves are now exhausted (P8a–P8i).** No trivial next leaf —
+what remains is the keystone work. **Blocked:**
+`sendto_channel_butserv` (send.c:737) — the still-C variadic `sendto_flag`
+(send.c:1147) calls it, so it can't go non-variadic until `sendto_flag` (247 Rust call
+sites — a big step) is ported. The C `anon`/`vsendpreprep`/`static vsendto_prefix_one` stay
+C until butserv goes (butserv references all three). `sendto_flag` + `sendto_one` are the
+keystone last: most `sendto_one` sites use a **runtime** `reply(i)` format string (from
+`replies[]`) → `wire!`/`format!` can't bind a runtime fmt, so it's blocked on the **leveva
+typed-numeric layer** (P10). Senders with **static** formats are convertible now via `wire!`.
+Guard byte-identity vs C `irc_vsprintf` 512-truncation when adopting leveva `to_wire()`.
diff --git a/docs/claude-memory/project-name-leveva-p10.md b/docs/claude-memory/project-name-leveva-p10.md
index cd32741d..44e11fb8 100644
--- a/docs/claude-memory/project-name-leveva-p10.md
+++ b/docs/claude-memory/project-name-leveva-p10.md
@@ -12,3 +12,5 @@ The all-Rust product of this ircd port is to be named **leveva**. Per PLAN.md, *
 **Why:** user's chosen name for the final all-Rust product; not derivable from the code (the workspace crates are `ircd-rs`/`ircd-common`/`iauth-rs`/etc. through P0–P9). User explicitly set the rename to begin at Phase 10 (2026-06-06), superseding an earlier note that put it at P8.
 
 **How to apply:** the faithful-port + cleanup phases (P0–P9) keep the `ircd-*` names; at P10, rename to `leveva` (Cargo.toml package names, binary artifact, README/docs). See [[rust-migration-plan]].
+
+**Update 2026-06-07 — leveva crate STARTED EARLY (string layer):** the user pulled P10's typed-string foundation forward (right after P7 completed, before P8/P9). A new greenfield `leveva/` workspace member now exists — std-only, NO `ircd-sys`/`ircd-common` dep, no `cref_` oracle, ordinary Rust unit/doc tests. Modules: `casemap` (textbook RFC 1459 fold — `A-Z↔a-z` PLUS Scandinavian `[↔{ \↔| ]↔} ~↔^`; deliberately differs from this daemon's ASCII-only `tolowertab` in `common/match.c`), `string` (`IrcStr`/`IrcString` casemapping `Eq/Ord/Hash`, `Borrow<IrcStr>`, NUL/CR/LF reject, `IrcStringBuilder`), `ident` (validating newtypes via `ident_newtype!` macro: `Nick`/`ChanName`/`Sid`/`Uid`/`Cid`/`ServerName`/`UserName`/`HostName`, grounded in struct_def.h lengths + char_atribs NVALID + do_nick_name + s_id.c), `message` (`Message`/`MessageBuilder` → 512-safe CRLF wire). The crate/binary **rename of the `ircd-*` crates is still deferred** to the real P10 slot. Progress: `docs/progress-log/p10.md`; plan: `docs/superpowers/plans/2026-06-07-leveva-rfc1459-string.md`.
