# P8 — Delete the C + retire the oracle harness (per-cluster progress) One-line summary per cluster. Detailed entries: [`docs/progress-log/p8.md`](docs/progress-log/p8.md). P8 rips out the ~25 variadic sender trampolines (replacing each with a non-variadic Rust sender API + `format!` at the call sites), then drops all C compilation and mothballs the L1/L2 oracle. "100% Rust" lands here. - **P8a DONE: `sendto_iauth` trampoline ripped out** — the C `sendto_iauth`/`vsendto_iauth` variadic pair (s_auth.c:120-170) → a non-variadic `pub unsafe fn sendto_iauth(&[u8])` in `ircd-common/src/s_auth.rs`; all 24 Rust call sites (s_auth/s_user/s_bsd/ircd/res) now `format!` the iauth line and pass its bytes. Guarded out of `s_auth_link.o` (`-DPORT_S_AUTH_SENDTO_IAUTH_P8a`); only s_auth.c data globals remain C. Gate: new L1 `sendto_iauth_diff.rs` (socketpair byte-diff vs `cref_sendto_iauth`, 2 tests) + the iauth L1 suite + `golden_registration` all green; `cargo build` 0 warnings. - **P8b DONE: `sendto_serv_butone` + `sendto_ops_butone` trampolines ripped out** — the two coupled server-broadcast senders (send.c:517/989). `ops_butone` was `serv_butone`'s only in-send.c caller, so porting `serv_butone` forced porting `ops_butone` to close the C→C edge. Non-variadic Rust cores in `ircd-common/src/send.rs` + a `wire!`/`WirePart` raw-byte line builder (faithful: quit/kill comments pass through verbatim, no UTF-8 lossy step); 18 call sites (parse/s_misc/s_user/channel/s_serv) now build the body with `wire!`. Guarded out of `send_link.o` (`-DPORT_SEND_SERV_BUTONE_P8b`/`-DPORT_SEND_OPS_BUTONE_P8b`). Gate: new L1 `sendto_serv_butone_diff.rs` (4 cases: QUIT broadcast, >510 truncation, one-uplink exclusion, ops WALLOPS) + the existing `golden_s2s_{away,quit,nick,kill,wallops, membership,join,save,s_serv_connect,s_serv_squit}` all byte-identical; `cargo build` 0 warns. - **P8c DONE: `sendto_serv_v` trampoline ripped out** — the third variadic server-broadcast sender (send.c:541-572) and near-identical sibling of P8b's `sendto_serv_butone`: same `fdas.highest`→0 loop over `local[fdas.fd[i]]` (skip `one`'s uplink + `me`, build the line once via `vsendprep`, `send_message` each). Its `ver` parameter gates on `cptr->serv->version & ver` but that gate is `#if 0`'d out, so `ver` is dead and it always returns rc = 0. No live C caller (every caller — ircd.c/s_serv.c/ s_user.c/channel.c — already ported + dropped), so ripped out alone. Non-variadic `pub unsafe fn sendto_serv_v(one, _ver, body: &[u8]) -> c_int` in `ircd-common/src/send.rs` (reuses `prep_line`); 10 call sites (ircd `s_die`; channel NJOIN tail; s_user KILL+SAVE; s_serv 4× EOB + SDIE relay + m_sdie) now build the body with `wire!`. Guarded out of `send_link.o` (`-DPORT_SEND_SERV_V_P8c`). Gate: new L1 `sendto_serv_v_diff.rs` (3 cases: EOB broadcast + rc==0, >510 truncation, one-uplink exclusion) + the existing `golden_s2s_{save,join,membership,kill,s_serv_connect,s_serv_squit}` all byte-identical; `cargo build` 0 warnings. - **P8d DONE: `sendto_match_servs` + `sendto_match_servs_v` trampolines ripped out** — the channel-mask server-broadcast pair (send.c:790-876). Both walk `fdas.highest`→0 over `local[]`, skip `cptr == from` + `me`, and — when the channel name carries a trailing `:server-mask` (`get_channelmask` = `rindex(name,':')`, JAPANESE off) — also skip servers whose `name` doesn't `match` the mask; a leading-`&` channel returns at once. `sendto_match_servs_v`'s `ver` gate is `#if 0`'d out (dead → always rc = 0), the same serv_butone/serv_v shape as P8b/c. Clean leaves (no in-send.c callers), so ripped out as a pair; all 12 call sites are in channel.rs (TOPIC/PART/JOIN/MODE+o + KICK/NJOIN/MODE), now built with `wire!`. Non-variadic Rust cores reuse `prep_line`. Guarded out of `send_link.o` (`-DPORT_SEND_MATCH_SERVS_P8d`). Gate: new L1 `sendto_match_servs_diff.rs` (5 cases: broadcast, `&`-early-return, mask filtering + inverse, `from`-exclusion, `_v` >510 trunc + rc==0) + the existing `golden_s2s_{topic,kick,membership,mode,njoin,join}` all byte-identical; `cargo build` 0 warnings. - **P8e DONE: `sendto_prefix_one` trampoline ripped out** — the first of the `vsendpreprep`-based prefix senders (send.c:1017-1027), a clean leaf with no in-send.c caller (internal paths use the `static vsendto_prefix_one`; only external — now-Rust — callers reach the public one). Introduces the `prep_preprep` Rust core: a faithful port of `vsendpreprep` (send.c:388-419) reproducing the special path — when `to` is MyClient and `from` is a Person, the `:%s` prefix arg `par` collapses to `:from->name!user@host` (if `par == from->name`) else stays `:par`; otherwise the line is emitted verbatim — then hands the body to the shared `prep_line` (≤510 + CRLF). The C `from == &anon` disjunct is unreachable from Rust callers (only the still-C channel senders substitute `&anon`), so it lands when those are ported. Every caller leads with `:%s`, so the C `!strncmp(pattern, ":%s", 3)` guard reduces to the to/from test. The static `vsendto_prefix_one` + `vsendpreprep` stay C (the channel senders still use them). Non-variadic `pub unsafe fn sendto_prefix_one(to, from, par, rest: &[u8])`; 10 call sites (s_numeric numeric relay; channel INVITE ×2; s_user PRIVMSG/NOTICE ×4 + KILL) build the post-`:%s` `rest` with `wire!`. Guarded out of `send_link.o` (`-DPORT_SEND_PREFIX_ONE_P8e`). Gate: new L1 `sendto_prefix_one_diff.rs` (4 cases: special-collapse, special-no-collapse, non-special server-`to` verbatim, collapse >510 truncation) + the existing `golden_channel_invite`, `golden_s_user_message`, `golden_s2s_message`, `golden_s_user_kill`, `golden_s2s_kill` all byte-identical; `cargo build` 0 warnings. - **P8f DONE: `sendto_match_butone` trampoline ripped out** — the `$$`/`$#`-mask broadcast prefix sender (send.c:935-987, "enhanced PRIVMSG"). A clean leaf: no in-send.c caller, one live call site (`m_message` in s_user.rs). Reuses the P8e `prep_preprep`/`sendto_prefix_one` core verbatim — its delivery is `vsendto_prefix_one(cptr, from, …)` with the *real* `from` (NEVER `&anon`), so no new anon machinery is needed (that lands with the channel senders). Non-variadic `pub unsafe fn sendto_match_butone(one, from, mask, what, par, rest: &[u8])` in `ircd-common/src/send.rs`: walks `i = 0..=highest_fd` over `local[i]`, skips NULL + the origin `one`; for a server recipient walks `cptr->prev` for the first registered dependent whose `from == cptr` and whose host/server `match`es the mask (the new `match_it` + `is_registered_user` helpers; MATCH_HOST=2 / MATCH_SERVER=1), for a non-server requires the client itself match; each survivor gets the P8e `sendto_prefix_one`. The single call site (`:%s %s %s :%s` → par = parv0, rest = ` :` built with `wire!`) converted. Guarded out of `send_link.o` (`-DPORT_SEND_MATCH_BUTONE_P8f`). Gate: new L1 `sendto_match_butone_diff.rs` (4 cases: my-client MATCH_HOST match + inverse, server `prev`-walk MATCH_SERVER match + inverse, origin exclusion, unregistered-client skip) + the existing `golden_s_user_message` (7) / `golden_s2s_message` byte-identical; `cargo build` 0 warnings. - **P8g DONE: `sendto_channel_butone` ripped out + the `anon` machinery ported to Rust** — the channel broadcaster (send.c:459-510; JOIN/PART/KICK/MODE/TOPIC, the s_numeric channel-numeric relay, and channel PRIVMSG/NOTICE). It is the first **anon-needing** channel prefix sender, so this step also moves the anonymous-identity placeholder (`anon`/`ausr`/`initanonymous`, send.c:344-365) from C to Rust: `anon`/`ausr` become `#[no_mangle] pub static mut` globals and the still-C `vsendpreprep` / `sendto_channel_butserv` (send_link.o) reference them via `extern` decls that resolve to the Rust symbols. `prep_preprep` gains the C `from == &anon` disjunct (collapse to `:anonymous!anonymous@anonymous.`). The non-variadic Rust core routes BOTH the C raw (`vsendprep` → server recipients) and prefixed (`vsendpreprep` → MyClient recipients) paths through the P8e `sendto_prefix_one`/`prep_preprep` core (byte-identical: a server recipient lands in the else-path `:par`, a MyClient recipient collapses). 7 call sites (s_numeric ×1, channel ×5, s_user ×1) build the post-`:%s` `rest` with `wire!`. Guarded out of `send_link.o` (`-DPORT_SEND_CHANNEL_BUTONE_P8g -DPORT_SEND_ANON_P8g`). **Deferred:** `sendto_channel_butserv` (still-C variadic `sendto_flag` at send.c:1147 calls it — needs `sendto_flag`'s 247 Rust call sites ported first) and `sendto_common_channels` (a clean leaf, no anon, its own step). Gate: new L1 `sendto_channel_butone_diff.rs` (4 cases: broadcast collapse/verbatim/IsMe-skip, `one` exclusion + inverse, self-send-not-doubled, anonymous-channel collapses to anon) + the existing channel goldens (join/part/kick/topic/mode_set/invite ×21) + s_user_message (7) + the S2S goldens (message/join/kick/topic/mode ×8) all byte-identical; 0 warnings. - **P8h DONE: `sendto_common_channels` trampoline ripped out** — the local-channel-peers broadcaster (send.c:620-729) used by NICK changes + QUIT so a client's peers see the event once. A clean leaf: no in-send.c caller; live callers are the now-Rust `exit_client` (s_misc) + the two NICK-change paths (s_user). **No anon machinery** — it explicitly skips anonymous channels (`if IsAnonymous(...) continue`), so `from` is always the real `user`. Non-variadic `pub unsafe fn sendto_common_channels(user, par, rest: &[u8])` in `ircd-common/src/send.rs`. The faithful subtlety: C preps the line **once** (`if (!len)`, DEBUGMODE off) into `psendbuf` and reuses it for every recipient, so the Rust port holds a local `[u8;520]` + `len` and calls `prep_preprep` only when `len==0` — NOT `sendto_prefix_one` per recipient (which re-preps against each `to`); in the big-client branch a remote `clist` member (not MyClient) still receives the cached, FIRST-recipient-shaped line, which per-recipient prep would diverge on. Both size-gated branches ported (`highest_fd<50` HUB + the big-client `clist`/`sentalong` path); `sentalong` becomes a per-call `vec![0; MAXCONNECTIONS]` indexed via raw `.offset((*cptr).fd as isize)` to match C's `fd==-1` (remote) pointer arithmetic without a Vec bounds panic. New private `is_member`/`is_quiet` helpers (via the ported `find_channel_link`). 3 call sites converted (`:%s QUIT :%s` / `:%s NICK :%s` → par + `wire!` rest). Guarded out of `send_link.o` (`-DPORT_SEND_COMMON_CHANNELS_P8h` — the now-unused `sentalong` static guarded too). Gate: new L1 `sendto_common_channels_diff.rs` (4 cases: shared-channel broadcast + self-send + different-channel/server inverse, quiet-channel skip, anonymous-channel skip, remote-user no-self-send) + `golden_s_user_nick` (5) / `golden_s_user_quit` (4) / `golden_s2s_nick` / `golden_s2s_quit` (2) byte-identical; 0 warnings. - **P8i DONE: `sendto_flog` logfile cluster** (the first non-variadic leaf) — ripped the `sendto_flog` logger + its companion `logfiles_open`/`logfiles_close` + the file-private `userlog`/`connlog` fd statics out of `send_link.o` into `ircd-common/src/send.rs`; formatting via `libc::sprintf` with the exact C format string (byte-identical by construction); `setup_svchans`/`svchans` stay C (svchans shared with the still-C variadic `sendto_flag`); FNAME paths via new `IRCD_USERLOG_PATH`/`IRCD_CONNLOG_PATH` rustc-envs; `-DPORT_SEND_FLOG_P8i`. Gate: new L1 `sendto_flog_diff.rs` (write_pidfile pattern — diff rust-vs-cref logfile bytes, no-op identical in sandbox / byte-pinned where writable; 2 cases REG→userlog, non-REG→connlog) + golden boot smoke; no L2/S2S (file-only, USE_SERVICES off). - **P8j DONE: `sendto_flag` (the keystone) + `dead_link` ripped out** — the server-notice broadcaster (send.c:1141, ~220 call sites across 16 ircd-common files) → a non-variadic Rust core `sendto_flag(chan, body: &[u8])` in `ircd-common/src/send.rs` that clamps `chan`, looks up the server-owned channel in the now-Rust `svchans[]` (its connected component — `svchans` + `setup_svchans` — ported too), and wraps `:me NOTICE :` via the still-C variadic `sendto_channel_butserv` (called through the bindgen decl; channel_butserv's only C caller was sendto_flag, so it's now the next step). `dead_link` (send.c:50, the last C caller of sendto_flag) ported alongside (non-variadic; SetDead + DBufClear + the SCH_ERROR notice). Call sites pre-render the notice text with `wire!`; WirePart grew `%u`/`%08x`/`%x`/`%X`/`%#x`/`%02d`/ `%2d`/`%c`/`%p` helpers (integers via `format!` = byte-identical; `%#x`/`%p` via libc). All 203 literal-format call sites machine-verified byte-faithful vs the original C format strings (the one NULL `%s` renders the literal `(null)` glibc emits). Guarded out of `send_link.o` (`-DPORT_SEND_FLAG_P8j -DPORT_SEND_DEAD_LINK_P8j`). Gate: new L1 `sendto_flag_diff.rs` (4 cases: basic wrap, mixed `%d/%s/%u`, chan clamp, NULL-svc_ptr no-op — drives `cref_sendto_flag` via `cref_setup_svchans` + a hashed `&NOTICES`) + 16 golden binaries (registration, s_user nick/quit, channel join/part/kick/topic, s2s nick/quit/kill/join/eob/server/squit/njoin/ s_serv_connect) byte-identical; `cargo build` 0 warnings. - **P8k DONE: `sendto_channel_butserv` ripped out** — the channel local-members broadcaster (send.c:746-780; TOPIC/PART/KICK/JOIN/MODE relays to MyClient members + the anonymous PART + the now-Rust `sendto_flag`). Unblocked by P8j (its only in-send.c caller, `sendto_flag`, went Rust). A clean leaf like P8g minus the server broadcast: it only ever sends to MyClient recipients, so per-recipient `sendto_prefix_one` (P8e core) is byte-identical to the C `psendbuf`/`if (!len)` cache. Non-variadic `pub unsafe fn sendto_channel_butserv(chptr, from, par, rest: &[u8])` in `ircd-common/src/send.rs`: `MyClient(from)` self-send (real prefix) then `IsQuiet`→return; `IsAnonymous && IsClient(from)`→`lfrm=&anon`; loop `chptr->clist` delivering to each `MyClient(acptr) && acptr != from` via `lfrm`. 14 call sites converted to `par`+`wire!` rest (12 channel.rs, 1 s_misc anon-PART, the sendto_flag wrapper in send.rs); the local variadic `extern` decls in channel.rs/s_misc.rs replaced with `use crate::send::sendto_channel_butserv`. Its now-orphaned static helpers `vsendpreprep` + `vsendto_prefix_one` + the `psendbuf` buffer (last unguarded caller was channel_butserv) go with it under the same guard; `vsendprep`/`sendbuf` stay (live: `vsendto_one`). Guarded out of `send_link.o` (`-DPORT_SEND_CHANNEL_BUTSERV_P8k`). Gate: new L1 `sendto_channel_butserv_diff.rs` (4 cases: local members + server/remote inverse, quiet early-return, anonymous `&anon` prefix with real-prefix self-send, remote-from no-self-send — both worlds' anon initialized via initanonymous/cref_initanonymous) + `sendto_flag_diff` (4) still green + 14 golden binaries byte-identical (channel join/part/kick/topic/mode_set/modes + s2s join/topic/kick/mode/njoin); `cargo build` 0 warnings. - **P8l DONE: `sendto_one` (the keystone single-client sender) ripped out** — the C variadic `sendto_one`/`vsendto_one`/`vsendprep` (send.c:450-468) → a non-variadic Rust core `send::sendto_one(to, body: &[u8])` (preps ≤510+CRLF via `prep_line`, delivers via `send_message`). All 435 call sites across 15 ircd-common files convert the line body: 58 literal-pattern sites via `wire!`, 377 `replies[]`/runtime-pattern sites via a new `reply_one!` macro (libc `snprintf` — the same printf engine the C trampoline used via `vsprintf`, so byte-identical, and the only faithful path for the ~6 runtime `reply(var)` sites — `reply(num)`/`reply(cj)`/`reply(REPORT_ARRAY[idx][1])` — that `wire!` cannot bind). The 2 `rlen += sendto_one(...)` accumulator sites (channel.rs) call the core directly for its `c_int` return. `vsendprep`/`vsendto_one`/`sendto_one` + the orphaned `sendbuf` guarded out (`-DPORT_SEND_ONE_P8l`). **Key finding:** the plan's "blocked on leveva typed-numerics" note overstated it — only ~6 sites are genuinely-runtime `reply(var)`; the ~430 `reply(ERR_CONST)`/literal sites have a compile-time-known format, and since `vsendprep` uses **libc `vsprintf`** (not the custom `irc_vsprintf`), `reply_one!`/snprintf is byte-identical for ALL sites. Gate: new L1 `sendto_one_diff.rs` (5 cases: wire! literal, reply_one! `%s` template, `%d`/`%02d` numerics, NULL `%s`→`(null)`, >510 trunc) + the full 111-test golden suite byte-identical (the only 2 failures are the pre-existing STATS garbage flakes — uninitialized per-process `sq`/`Sq/Yg/Fl` counters, not sendto_one output); `cargo build` 0 warnings. **All variadic sender trampolines are now Rust** — only the P1-deferred `irc_sprintf` format engine (deleted, not ported, in P11) remains C in send. - **P8m DONE: the `esendto_*` cluster ripped out** — the last variadic SENDER trampolines (ircd/s_send.c: the UID-aware service-routing esendto_one/serv_butone/channel_butone/ match_servs). USE_SERVICES off → ZERO callers, so no call-site conversion and no L2 path; ported faithfully to a non-variadic ircd-common/src/s_send.rs (the variadic fmt/... collapses to suffix: &[u8]) with all quirks (the maxplen+slen>512 suffix truncation, the UID-selection + newplen=-1 bail, the hardcoded :anonymous!anonymous@anonymous. local prefix, the &-channel return + match() mask filter). The :%s %s %s prefixes defer to libc::sprintf (byte-identical incl. glibc's (null) for a NULL oname). s_send.o dropped outright (PORTED, no s_send_link.o, no -DPORT_* guard; cref keeps the unguarded .o for L1). Gate: new L1 s_send_diff.rs (9 cases, branches + inverses) zero-diff + golden_registration byte-identical. - **P8n DONE: the `s_auth.c` iauth data globals ripped out → `s_auth.o` dropped outright** — the five file-scope iauth globals (`iauth_options`/`iauth_spawn`/`iauth_version`/`iauth_conf`/ `iauth_stats`, s_auth.c:102-112) were the LAST C symbols `s_auth_link.o` defined (all of s_auth.c's *logic* went Rust over P7u..P8a). Moved them to Rust-owned `#[no_mangle] pub static mut` statics in `ircd-common/src/s_auth.rs` (zero/NULL-init exactly as the C BSS defs); the iauth-timeout readers in ircd.rs/s_user.rs/s_bsd.rs reach `iauth_options`/`iauth_spawn` through their bindgen `extern` decls, which resolve to these defs at link (the data-symbol case of the function-symbol seam). `s_auth.o` added to `PORTED` (dropped outright — no more `s_auth_link.o`, the P7u..P8a `-DPORT_S_AUTH_*` chain gone); cref keeps the unguarded `s_auth.o` for `cref_iauth_*`/`cref_report_iauth_*`/`cref_sendto_iauth`. Gate: the existing iauth L1 suite (`read_iauth_diff` 10 — writes all 5 globals — + `iauth_reporters_diff` 6 + `sendto_iauth_diff` 2 + `start_iauth_diff` 3, all zero-diff vs cref) + `golden_registration` 2 byte-identical; `nm` confirms the 5 resolve as Rust BSS defs (none undefined); `cargo build` 0 warnings. - **P8o DONE: `send.o` dropped outright** — the second P8 data-global drop. Over P3d + P8b..P8l every `send.c` sender (plus `dead_link`, the logfile cluster, the `svchans` component, the `anon` machinery) was `#ifdef`'d out of `send_link.o` and reimplemented in `ircd-common/src/send.rs`, leaving `send_link.o` defining ONLY the module-private `rcsid` version string (an unreferenced `static`, internal linkage). `nm --defined-only cbuild/send_link.o` = `rcsid` and nothing else, so `send.o` is added to `PORTED` and dropped outright: the entire `send_link.o` second-compile step + the `-DPORT_SEND_P3 .. -DPORT_SEND_ONE_P8l` guard chain + the `"send.o" => "send_link.o"` link-map arm are deleted from `ircd-sys/build.rs`. The Rust `logfiles_open` still reads `FNAME_USERLOG`/`FNAME_CONNLOG` via the `IRCD_USERLOG_PATH`/`IRCD_CONNLOG_PATH` rustc-envs; cref keeps the unguarded `send.o` (native Makefile recipe, FNAME_* expanded) for the L1 send diffs. Gate: all 14 send L1 differentials (`send_diff`/`sendto_one`/`sendto_flag`/`sendto_channel_butone`/ `sendto_channel_butserv`/`sendto_serv_butone`/`sendto_serv_v`/`sendto_match_servs`/ `sendto_match_butone`/`sendto_prefix_one`/`sendto_common_channels`/`sendto_flog`/`sendto_iauth`/ `s_send`, 57 tests) zero-diff + `golden_registration` 2 byte-identical; `nm target/debug/ircd` shows `logfiles_open`/`svchans` resolving as Rust defs and no undefined send symbols; `cargo build` 0 warnings. - **P8p DONE: `s_bsd.o` dropped outright** — the third P8 data-global drop. Over P7d..P7ff every `s_bsd.c` *function* went Rust, leaving `s_bsd_link.o` defining ONLY its data globals (`local[]`/`fdas`/`fdall`/`highest_fd`/`readcalls`/`udpfd`/`resfd`/`adfd`/`timeofday`/`mysk` + the module-private `rcsid`). Those globals now live in `ircd-common/src/s_bsd.rs` as Rust-owned `#[no_mangle] pub static mut` statics with byte-exact C inits (`udpfd`/`resfd`/ `adfd = -1` → `.data`; `local`=all-NULL, `fdas`/`fdall`=`FdAry{fd:[0;50],highest:0}`, `highest_fd`/`readcalls`=0, `timeofday`=0, `mysk`=`MaybeUninit::zeroed` → BSS). The data-symbol seam carries the rest: the other modules (send/parse/s_user/s_auth/s_service/ s_send + s_bsd.rs itself) reach them through their bindgen `extern static mut` decls, which resolve to these defs at link (proven for `anon`/`ausr` P8g, `svchans` P8j, the iauth globals P8n). `s_bsd.o` added to `PORTED`; the whole `s_bsd_link.o` second-compile (the long `-DPORT_S_BSD_*` chain) + the `s_bsd.o`→`s_bsd_link.o` link-map arm deleted from build.rs; cref keeps the unguarded `s_bsd.o` so `cref_local`/`cref_highest_fd`/`cref_mysk`/… survive for the L1 differentials. Two in-module clears: dropped the old local `extern "C" { static mut mysk }` decl, and renamed the `read_message` local var `local` → `local_p` (it shadowed the new static). Gate (pure-data drop, per P8n/P8o): the existing s_bsd L1 differentials that exercise the globals end-to-end — `read_message_diff`/`add_connection_diff`/`close_connection_diff`/ `close_listeners_diff`/`list_diff` (add_fd/del_fd on fdas/fdall)/`s_bsd_leaves_diff`/ `connect_server_diff`/`check_client_diff`/`setup_ping_diff`/`send_ping_diff`/`check_pings_diff`/ `get_my_name_diff` (mysk)/`init_sys_diff`/`daemonize_diff`/`start_iauth_diff`/`delayed_kills_diff`/ `calculate_preference_diff` — all zero-diff + the cross-module wire seam (`sendto_one`/`sendto_flag`/ `sendto_common_channels` read `local` via the seam) + `golden_registration` byte-identical; `nm target/debug/ircd` shows all 10 resolving as Rust defs (B/D, none `U`); `cargo build` 0 warnings. - **P8q DONE: `ircd.o` dropped outright** — the fourth P8 data-global drop. Over P7c..P7oo every `ircd.c` *function* went Rust, leaving `ircd_link.o` defining ONLY its data globals (`nm --defined-only ircd_link.o` = no `T` symbols): `me`/`client`/`istat`/`iconf`/`myargv`/ `rehashed`/`portnum`/`configfile`/`debuglevel`/`bootopt`/`serverbooting`/`firstrejoindone`/ `sbrk0`/`tunefile`/`dorehash`/`dorestart`/`restart_iauth`/the `next*` timers/`ListenerLL` (+ the module-private `rcsid`). Those now live in `ircd-common/src/ircd.rs` as Rust-owned `#[no_mangle] pub static mut` statics with byte-exact C inits (`me`/`istat`/`iconf` zeroed via `MaybeUninit::zeroed`; `client = addr_of_mut!(me)`; `portnum`/`debuglevel = -1`; `serverbooting = 1`; `bootopt = BOOT_PROT|BOOT_STRICTPROT`; the six `=1` timers in `.data`, the rest BSS). The `me` self-pointer hazard is a non-issue at definition — the interior `me.name → me.serv->namebuf` pointers are set at *runtime* by the already-ported `make_server`/`setup_me`, so the static is just a zeroed `aClient` (the C BSS def). DATA-symbol seam carries the rest: the other modules reach the bindgen-surfaced globals through their `ircd_sys::bindings::{me,client,…}` `extern static mut` decls, which resolve to these defs at link (proven `local`/`anon`/`svchans`/iauth). The 5 non-bindgen flags/timers (`dorehash`/`dorestart`/`restart_iauth`/`nextpreference`/`nextiarestart`), formerly reached via two local `extern "C"` blocks in ircd.rs, are now module statics (the blocks removed, bare refs resolve directly); the three bindgen import-lists trimmed of the now-defined names to clear the clash. `configfile`/`tunefile` default to `IRCDCONF_PATH`/`IRCDTUNE_PATH` via new `IRCD_CONF_PATH`/`IRCD_TUNE_PATH` rustc-envs (re-exported `ircd_sys::CONF_PATH_Z`/`TUNE_PATH_Z`, NUL-terminated). `ircd.o` added to `PORTED`; the `ircd_link.o` second-compile (the long `-DPORT_IRCD_*` chain) + the `ircd.o`→`ircd_link.o` link-map arm deleted from build.rs; cref keeps the unguarded `ircd.o` so `cref_me`/`cref_try_connections`/`cref_dorehash`/… survive for the L1 differentials. Gate (pure-data drop, per P8n/o/p): the ircd L1 differentials that exercise the globals end-to-end — `try_connections_diff`/`check_pings_diff`/ `calculate_preference_diff`/`delayed_kills_diff`/`ircd_signals_diff` (writes `dorehash`/ `dorestart`/`restart_iauth`)/`ircd_tune_diff`/`ircd_cli_helpers_diff`/`setup_signals_diff`/ `activate_delayed_listeners_diff` — all zero-diff + `golden_registration` 2 byte-identical (boots the Rust ircd, which now owns `me`/the timers/`configfile`/`tunefile`); `nm target/debug/ircd` shows all ~26 resolving as Rust defs (B/D, none `U`) with the correct `.data`/`.bss` split; `cargo build --workspace` 0 warnings. Now only `support_link.o` (the format remnants `dgets`/`make_isupport`/`snprintf_append`/`ipv6string`/`minus_one`) keeps C *logic*; every other TU is Rust-or-data-only. - **P8r DONE: `support.o` dropped outright — the LAST C-logic TU** — `dgets` + `make_isupport` ported to `ircd-common/src/support.rs`, the `ipv6string` (`[c_char;46]` BSS) + `minus_one` (`[c_uchar;17]` = 16×0xff+0, `.data`) data globals defined as `#[no_mangle] pub static mut` statics. The variadic `snprintf_append` is NOT ported: it has no live Rust caller (WHOX is built field-by-field in `s_user.rs`) so it died with the `.o`. `support.o` added to `PORTED`; the `support_link.o` second-compile (`-DPORT_SUPPORT_P1 -DPORT_SUPPORT_P2`) + the `"support.o" => "support_link.o"` link-map arm deleted from build.rs (`link_objs()` is now a plain set difference — no more `*_link.o` variants). cref keeps the unguarded `support.o` (13 syms) so `cref_dgets`/`cref_make_isupport`/… survive for L1. **Every ircd C TU is now Rust** — the product link set holds only the generated `version.o` + the L1 harness `ctruth.o`. Gate: new L1 differentials `dgets_matches_reference` (pipe-driven: `\n`/`\r` lines, odd-backslash continuation splice, even-backslash run, EOF tail, `dgets(_,_,0)` reset) + `make_isupport_matches_reference` (walk the `char**`) both zero-diff; full `support_diff` (7) zero-diff; `golden_registration` (2) byte-identical (005 ISUPPORT flows through `make_isupport`); `s_conf_match_ipmask_diff`/`res_gethost_diff` (read `ipv6string`/`minus_one` via the seam) zero-diff; `nm target/debug/ircd` shows `dgets`/`make_isupport` as `T`, `ipv6string` `B`, `minus_one` `D` (none `U`), `snprintf_append` absent; `cargo build --workspace` 0 warnings. - **P8s DONE: all 115 L1 `cref_` differentials migrated to self-contained `ircd-common` insta snapshots** — the oracle-retirement test step. Each `ircd-testkit/tests/_diff.rs` now has an `ircd-common/tests/_snap.rs` that drives ONLY the Rust port (`#[no_mangle]` syms via `link_anchor()`; no `cref_`, no `ircd_testkit`). Dual-World diffs collapse to a single Rust world; raw pointers/timestamps/fd-numbers/ephemeral-ports become derived invariants (bools/offsets/byte-seqs); clock interposition + global `Mutex`es preserved. Sound via the capture chain: the matching differential is green at capture (Rust==cref), so `snapshot==cref` golden. `insta` added as a dev-dep. Built hand-proven (s_err/s_id) + 6-tier pilot + a throttled multi-agent workflow (guide: `docs/superpowers/plans/2026-06-08-p8-test-migration-guide.md`). Gate: 115 tests / 707 snapshots, 1:1 coverage, `ircd-common` suite stably green over repeated runs (determinism), `cargo build --workspace` 0 warnings. `ircd-testkit`/`cref_` oracle left intact (still the proof oracle); mothballing it + dropping `cc::Build` is the remaining P8 work. - **P8t DONE: `version.c` ported to Rust — the last *generated* C TU** — its five data globals (`generation`/`creation`/`pass_version`/`infotext`/`isupport`) are now `#[no_mangle]` statics in `ircd-common/src/version.rs` via the data-symbol seam (the bindgen `extern` decls in `s_serv`/`s_user`/`s_debug`/`ircd`/`s_bsd` resolve to them at link). `generation`=`CARGO_PKG_VERSION`, `creation`=a UTC build-stamp captured in a new `ircd-common/build.rs` (user-directed: sourced from crate metadata at build time); `pass_version`=`PATCHLEVEL` + the `infotext[]` credits array copied verbatim. The `version.c.SH` generation step + the `version.o` compile/archive deleted from `ircd-sys/build.rs` → `libircd_c.a` now holds only the L1 harness `ctruth.o`. `creation` is now build-time volatile so the L2 canonicalizer masks RPL_CREATED (003), matching the existing 371 Birth-Date rule. Gate: `cargo build --workspace` 0 warnings; `nm` shows all five syms as Rust defs (D/B, none U), `version.o` absent from the archive; `ircd-common` snapshot suite green (117 results); golden suite 58 pass + the one known pre-existing `golden_s2s_s_serv_stats` flake (reference-C uninitialized-sendq garbage, unrelated). - **P8u DONE (FINAL — oracle retired, workspace 100% Rust): dropped all C compilation + mothballed the L1/L2 oracle** — ran the differential suite a last time green (L1 `ircd-testkit` all pass; L2 `ircd-golden` 86 pass + only the documented `s_serv_stats` reference-C-garbage flake, Rust the correct side), then deleted from `ircd-sys/build.rs` the `make` object build / the `cref_*`/`ctruth.o`/`res.o` recompiles / the `libircd_c.a` archive / the whole-archive link + `-lz`/`-lm`/`-lcrypt` (none needed by Rust). `build.rs` now only runs `configure` + bindgen over the C *headers* + expands the install-path Makefile vars. `ircd-testkit`/`ircd-golden` `exclude`d from the workspace (mothballed, git-recoverable); `ctruth.c`/`layout.rs` drift-net deleted. Gate: `cargo build --workspace` 0 warnings links pure Rust (binary boots, 0 `cref_`/`ctruth` syms, `c_ircd_main` a Rust `T`); `cargo test --workspace` 698 pass / 0 fail across 125 binaries. **Every ircd C TU is gone from the build — P8 COMPLETE.** - **P8v DONE (C source tree DELETED, `ircd-sys` retired — workspace now has zero C *files* at all):** P8u stopped one step short of literal C removal — it dropped all C *compilation* but kept `ircd-sys`, whose `build.rs` still ran `configure` + bindgen over the C *headers* to produce the struct/type view `ircd-common` builds against. P8v finishes the job: **froze the generated `bindings.rs`** (4953 lines, bindgen 0.72.1 over the locked-config headers) into a committed `ircd-common/src/bindings.rs` (`pub mod bindings;` + a self-alias `extern crate self as ircd_sys;` so the 28 ported modules' `ircd_sys::bindings::*` / `ircd_sys::MOTD_PATH` paths resolve unchanged to the in-crate module + frozen install-path consts — zero src churn). Then **deleted** the `ircd-sys` crate, the mothballed `ircd-testkit`/`ircd-golden` oracle crates, the `iauth-rs/tests/differential_c.rs` C-iauth differential (per-module unit tests remain the iauth gate), and the **entire C source tree** (`common/ ircd/ iauth/ support/ contrib/ cbuild/ configure .clang-format* .github/workflows/clangformat.yml`). `ircd-rs` now calls `ircd_common::ircd::c_ircd_main` directly (dropped its `ircd-sys` dep). Four `clashing_extern_declarations` surfaced once bindings + the modules' local forward-decls shared a crate (`unregister_server`/`del_from_hostname_hash_table`/`del_from_ip_hash_table` missing `-> c_int`; `mystrdup` decl'd `*const` vs the real `*mut`) — aligned the 4 decls to the real signatures (one `line.as_ptr() as *mut c_char` cast at the s_misc MOTD call site). Gate: `cargo build --workspace` 0 warnings links pure Rust; `cargo test --workspace` 695 pass / 0 fail. **The repo now contains no C whatsoever.** Next: P9 (std-library cleanup).