P8 — Delete the C + retire the oracle harness (per-cluster progress)#
One-line summary per cluster. Detailed entries: 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_iauthtrampoline ripped out — the Csendto_iauth/vsendto_iauthvariadic pair (s_auth.c:120-170) → a non-variadicpub unsafe fn sendto_iauth(&[u8])inircd-common/src/s_auth.rs; all 24 Rust call sites (s_auth/s_user/s_bsd/ircd/res) nowformat!the iauth line and pass its bytes. Guarded out ofs_auth_link.o(-DPORT_S_AUTH_SENDTO_IAUTH_P8a); only s_auth.c data globals remain C. Gate: new L1sendto_iauth_diff.rs(socketpair byte-diff vscref_sendto_iauth, 2 tests) + the iauth L1 suite +golden_registrationall green;cargo build0 warnings. -
P8b DONE:
sendto_serv_butone+sendto_ops_butonetrampolines ripped out — the two coupled server-broadcast senders (send.c:517/989).ops_butonewasserv_butone's only in-send.c caller, so portingserv_butoneforced portingops_butoneto close the C→C edge. Non-variadic Rust cores inircd-common/src/send.rs+ awire!/WirePartraw-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 withwire!. Guarded out ofsend_link.o(-DPORT_SEND_SERV_BUTONE_P8b/-DPORT_SEND_OPS_BUTONE_P8b). Gate: new L1sendto_serv_butone_diff.rs(4 cases: QUIT broadcast, >510 truncation, one-uplink exclusion, ops WALLOPS) + the existinggolden_s2s_{away,quit,nick,kill,wallops, membership,join,save,s_serv_connect,s_serv_squit}all byte-identical;cargo build0 warns. -
P8c DONE:
sendto_serv_vtrampoline ripped out — the third variadic server-broadcast sender (send.c:541-572) and near-identical sibling of P8b'ssendto_serv_butone: samefdas.highest→0 loop overlocal[fdas.fd[i]](skipone's uplink +me, build the line once viavsendprep,send_messageeach). Itsverparameter gates oncptr->serv->version & verbut that gate is#if 0'd out, soveris 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-variadicpub unsafe fn sendto_serv_v(one, _ver, body: &[u8]) -> c_intinircd-common/src/send.rs(reusesprep_line); 10 call sites (ircds_die; channel NJOIN tail; s_user KILL+SAVE; s_serv 4× EOB + SDIE relay + m_sdie) now build the body withwire!. Guarded out ofsend_link.o(-DPORT_SEND_SERV_V_P8c). Gate: new L1sendto_serv_v_diff.rs(3 cases: EOB broadcast + rc==0, >510 truncation, one-uplink exclusion) + the existinggolden_s2s_{save,join,membership,kill,s_serv_connect,s_serv_squit}all byte-identical;cargo build0 warnings. -
P8d DONE:
sendto_match_servs+sendto_match_servs_vtrampolines ripped out — the channel-mask server-broadcast pair (send.c:790-876). Both walkfdas.highest→0 overlocal[], skipcptr == from+me, and — when the channel name carries a trailing:server-mask(get_channelmask=rindex(name,':'), JAPANESE off) — also skip servers whosenamedoesn'tmatchthe mask; a leading-&channel returns at once.sendto_match_servs_v'svergate 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 withwire!. Non-variadic Rust cores reuseprep_line. Guarded out ofsend_link.o(-DPORT_SEND_MATCH_SERVS_P8d). Gate: new L1sendto_match_servs_diff.rs(5 cases: broadcast,&-early-return, mask filtering + inverse,from-exclusion,_v>510 trunc + rc==0) + the existinggolden_s2s_{topic,kick,membership,mode,njoin,join}all byte-identical;cargo build0 warnings. -
P8e DONE:
sendto_prefix_onetrampoline ripped out — the first of thevsendpreprep-based prefix senders (send.c:1017-1027), a clean leaf with no in-send.c caller (internal paths use thestatic vsendto_prefix_one; only external — now-Rust — callers reach the public one). Introduces theprep_preprepRust core: a faithful port ofvsendpreprep(send.c:388-419) reproducing the special path — whentois MyClient andfromis a Person, the:%sprefix argparcollapses to:from->name!user@host(ifpar == from->name) else stays:par; otherwise the line is emitted verbatim — then hands the body to the sharedprep_line(≤510 + CRLF). The Cfrom == &anondisjunct 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 staticvsendto_prefix_one+vsendpreprepstay C (the channel senders still use them). Non-variadicpub 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-:%srestwithwire!. Guarded out ofsend_link.o(-DPORT_SEND_PREFIX_ONE_P8e). Gate: new L1sendto_prefix_one_diff.rs(4 cases: special-collapse, special-no-collapse, non-special server-toverbatim, collapse >510 truncation) + the existinggolden_channel_invite,golden_s_user_message,golden_s2s_message,golden_s_user_kill,golden_s2s_killall byte-identical;cargo build0 warnings. -
P8f DONE:
sendto_match_butonetrampoline 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_messagein s_user.rs). Reuses the P8eprep_preprep/sendto_prefix_onecore verbatim — its delivery isvsendto_prefix_one(cptr, from, …)with the realfrom(NEVER&anon), so no new anon machinery is needed (that lands with the channel senders). Non-variadicpub unsafe fn sendto_match_butone(one, from, mask, what, par, rest: &[u8])inircd-common/src/send.rs: walksi = 0..=highest_fdoverlocal[i], skips NULL + the originone; for a server recipient walkscptr->prevfor the first registered dependent whosefrom == cptrand whose host/servermatches the mask (the newmatch_it+is_registered_userhelpers; MATCH_HOST=2 / MATCH_SERVER=1), for a non-server requires the client itself match; each survivor gets the P8esendto_prefix_one. The single call site (:%s %s %s :%s→ par = parv0, rest =<cmd> <nick> :<parv2>built withwire!) converted. Guarded out ofsend_link.o(-DPORT_SEND_MATCH_BUTONE_P8f). Gate: new L1sendto_match_butone_diff.rs(4 cases: my-client MATCH_HOST match + inverse, serverprev-walk MATCH_SERVER match + inverse, origin exclusion, unregistered-client skip) + the existinggolden_s_user_message(7) /golden_s2s_messagebyte-identical;cargo build0 warnings. -
P8g DONE:
sendto_channel_butoneripped out + theanonmachinery 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/ausrbecome#[no_mangle] pub static mutglobals and the still-Cvsendpreprep/sendto_channel_butserv(send_link.o) reference them viaexterndecls that resolve to the Rust symbols.prep_preprepgains the Cfrom == &anondisjunct (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 P8esendto_prefix_one/prep_preprepcore (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-:%srestwithwire!. Guarded out ofsend_link.o(-DPORT_SEND_CHANNEL_BUTONE_P8g -DPORT_SEND_ANON_P8g). Deferred:sendto_channel_butserv(still-C variadicsendto_flagat send.c:1147 calls it — needssendto_flag's 247 Rust call sites ported first) andsendto_common_channels(a clean leaf, no anon, its own step). Gate: new L1sendto_channel_butone_diff.rs(4 cases: broadcast collapse/verbatim/IsMe-skip,oneexclusion + 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_channelstrampoline 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-Rustexit_client(s_misc) + the two NICK-change paths (s_user). No anon machinery — it explicitly skips anonymous channels (if IsAnonymous(...) continue), sofromis always the realuser. Non-variadicpub unsafe fn sendto_common_channels(user, par, rest: &[u8])inircd-common/src/send.rs. The faithful subtlety: C preps the line once (if (!len), DEBUGMODE off) intopsendbufand reuses it for every recipient, so the Rust port holds a local[u8;520]+lenand callsprep_prepreponly whenlen==0— NOTsendto_prefix_oneper recipient (which re-preps against eachto); in the big-client branch a remoteclistmember (not MyClient) still receives the cached, FIRST-recipient-shaped line, which per-recipient prep would diverge on. Both size-gated branches ported (highest_fd<50HUB + the big-clientclist/sentalongpath);sentalongbecomes a per-callvec![0; MAXCONNECTIONS]indexed via raw.offset((*cptr).fd as isize)to match C'sfd==-1(remote) pointer arithmetic without a Vec bounds panic. New privateis_member/is_quiethelpers (via the portedfind_channel_link). 3 call sites converted (:%s QUIT :%s/:%s NICK :%s→ par +wire!rest). Guarded out ofsend_link.o(-DPORT_SEND_COMMON_CHANNELS_P8h— the now-unusedsentalongstatic guarded too). Gate: new L1sendto_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_floglogfile cluster (the first non-variadic leaf) — ripped thesendto_floglogger + its companionlogfiles_open/logfiles_close+ the file-privateuserlog/connlogfd statics out ofsend_link.ointoircd-common/src/send.rs; formatting vialibc::sprintfwith the exact C format string (byte-identical by construction);setup_svchans/svchansstay C (svchans shared with the still-C variadicsendto_flag); FNAME paths via newIRCD_USERLOG_PATH/IRCD_CONNLOG_PATHrustc-envs;-DPORT_SEND_FLOG_P8i. Gate: new L1sendto_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_linkripped out — the server-notice broadcaster (send.c:1141, ~220 call sites across 16 ircd-common files) → a non-variadic Rust coresendto_flag(chan, body: &[u8])inircd-common/src/send.rsthat clampschan, looks up the server-owned channel in the now-Rustsvchans[](its connected component —svchans+setup_svchans— ported too), and wraps:me NOTICE <chname> :<body>via the still-C variadicsendto_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 withwire!; WirePart grew%u/%08x/%x/%X/%#x/%02d/%2d/%c/%phelpers (integers viaformat!= byte-identical;%#x/%pvia libc). All 203 literal-format call sites machine-verified byte-faithful vs the original C format strings (the one NULL%srenders the literal(null)glibc emits). Guarded out ofsend_link.o(-DPORT_SEND_FLAG_P8j -DPORT_SEND_DEAD_LINK_P8j). Gate: new L1sendto_flag_diff.rs(4 cases: basic wrap, mixed%d/%s/%u, chan clamp, NULL-svc_ptr no-op — drivescref_sendto_flagviacref_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 build0 warnings. -
P8k DONE:
sendto_channel_butservripped out — the channel local-members broadcaster (send.c:746-780; TOPIC/PART/KICK/JOIN/MODE relays to MyClient members + the anonymous PART + the now-Rustsendto_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-recipientsendto_prefix_one(P8e core) is byte-identical to the Cpsendbuf/if (!len)cache. Non-variadicpub unsafe fn sendto_channel_butserv(chptr, from, par, rest: &[u8])inircd-common/src/send.rs:MyClient(from)self-send (real prefix) thenIsQuiet→return;IsAnonymous && IsClient(from)→lfrm=&anon; loopchptr->clistdelivering to eachMyClient(acptr) && acptr != fromvialfrm. 14 call sites converted topar+wire!rest (12 channel.rs, 1 s_misc anon-PART, the sendto_flag wrapper in send.rs); the local variadicexterndecls in channel.rs/s_misc.rs replaced withuse crate::send::sendto_channel_butserv. Its now-orphaned static helpersvsendpreprep+vsendto_prefix_one+ thepsendbufbuffer (last unguarded caller was channel_butserv) go with it under the same guard;vsendprep/sendbufstay (live:vsendto_one). Guarded out ofsend_link.o(-DPORT_SEND_CHANNEL_BUTSERV_P8k). Gate: new L1sendto_channel_butserv_diff.rs(4 cases: local members + server/remote inverse, quiet early-return, anonymous&anonprefix 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 build0 warnings. -
P8l DONE:
sendto_one(the keystone single-client sender) ripped out — the C variadicsendto_one/vsendto_one/vsendprep(send.c:450-468) → a non-variadic Rust coresend::sendto_one(to, body: &[u8])(preps ≤510+CRLF viaprep_line, delivers viasend_message). All 435 call sites across 15 ircd-common files convert the line body: 58 literal-pattern sites viawire!, 377replies[]/runtime-pattern sites via a newreply_one!macro (libcsnprintf— the same printf engine the C trampoline used viavsprintf, so byte-identical, and the only faithful path for the ~6 runtimereply(var)sites —reply(num)/reply(cj)/reply(REPORT_ARRAY[idx][1])— thatwire!cannot bind). The 2rlen += sendto_one(...)accumulator sites (channel.rs) call the core directly for itsc_intreturn.vsendprep/vsendto_one/sendto_one+ the orphanedsendbufguarded out (-DPORT_SEND_ONE_P8l). Key finding: the plan's "blocked on leveva typed-numerics" note overstated it — only ~6 sites are genuinely-runtimereply(var); the ~430reply(ERR_CONST)/literal sites have a compile-time-known format, and sincevsendprepuses libcvsprintf(not the customirc_vsprintf),reply_one!/snprintf is byte-identical for ALL sites. Gate: new L1sendto_one_diff.rs(5 cases: wire! literal, reply_one!%stemplate,%d/%02dnumerics, 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-processsq/Sq/Yg/Flcounters, not sendto_one output);cargo build0 warnings. All variadic sender trampolines are now Rust — only the P1-deferredirc_sprintfformat 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.ciauth data globals ripped out →s_auth.odropped 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 symbolss_auth_link.odefined (all of s_auth.c's logic went Rust over P7u..P8a). Moved them to Rust-owned#[no_mangle] pub static mutstatics inircd-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 reachiauth_options/iauth_spawnthrough their bindgenexterndecls, which resolve to these defs at link (the data-symbol case of the function-symbol seam).s_auth.oadded toPORTED(dropped outright — no mores_auth_link.o, the P7u..P8a-DPORT_S_AUTH_*chain gone); cref keeps the unguardeds_auth.oforcref_iauth_*/cref_report_iauth_*/cref_sendto_iauth. Gate: the existing iauth L1 suite (read_iauth_diff10 — writes all 5 globals — +iauth_reporters_diff6 +sendto_iauth_diff2 +start_iauth_diff3, all zero-diff vs cref) +golden_registration2 byte-identical;nmconfirms the 5 resolve as Rust BSS defs (none undefined);cargo build0 warnings. -
P8o DONE:
send.odropped outright — the second P8 data-global drop. Over P3d + P8b..P8l everysend.csender (plusdead_link, the logfile cluster, thesvchanscomponent, theanonmachinery) was#ifdef'd out ofsend_link.oand reimplemented inircd-common/src/send.rs, leavingsend_link.odefining ONLY the module-privatercsidversion string (an unreferencedstatic, internal linkage).nm --defined-only cbuild/send_link.o=rcsidand nothing else, sosend.ois added toPORTEDand dropped outright: the entiresend_link.osecond-compile step + the-DPORT_SEND_P3 .. -DPORT_SEND_ONE_P8lguard chain + the"send.o" => "send_link.o"link-map arm are deleted fromircd-sys/build.rs. The Rustlogfiles_openstill readsFNAME_USERLOG/FNAME_CONNLOGvia theIRCD_USERLOG_PATH/IRCD_CONNLOG_PATHrustc-envs; cref keeps the unguardedsend.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_registration2 byte-identical;nm target/debug/ircdshowslogfiles_open/svchansresolving as Rust defs and no undefined send symbols;cargo build0 warnings. -
P8p DONE:
s_bsd.odropped outright — the third P8 data-global drop. Over P7d..P7ff everys_bsd.cfunction went Rust, leavings_bsd_link.odefining ONLY its data globals (local[]/fdas/fdall/highest_fd/readcalls/udpfd/resfd/adfd/timeofday/mysk- the module-private
rcsid). Those globals now live inircd-common/src/s_bsd.rsas Rust-owned#[no_mangle] pub static mutstatics 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 bindgenextern static mutdecls, which resolve to these defs at link (proven foranon/ausrP8g,svchansP8j, the iauth globals P8n).s_bsd.oadded toPORTED; the wholes_bsd_link.osecond-compile (the long-DPORT_S_BSD_*chain) + thes_bsd.o→s_bsd_link.olink-map arm deleted from build.rs; cref keeps the unguardeds_bsd.osocref_local/cref_highest_fd/cref_mysk/… survive for the L1 differentials. Two in-module clears: dropped the old localextern "C" { static mut mysk }decl, and renamed theread_messagelocal varlocal→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_channelsreadlocalvia the seam) +golden_registrationbyte-identical;nm target/debug/ircdshows all 10 resolving as Rust defs (B/D, noneU);cargo build0 warnings.
- the module-private
-
P8q DONE:
ircd.odropped outright — the fourth P8 data-global drop. Over P7c..P7oo everyircd.cfunction went Rust, leavingircd_link.odefining ONLY its data globals (nm --defined-only ircd_link.o= noTsymbols):me/client/istat/iconf/myargv/rehashed/portnum/configfile/debuglevel/bootopt/serverbooting/firstrejoindone/sbrk0/tunefile/dorehash/dorestart/restart_iauth/thenext*timers/ListenerLL(+ the module-privatercsid). Those now live inircd-common/src/ircd.rsas Rust-owned#[no_mangle] pub static mutstatics with byte-exact C inits (me/istat/iconfzeroed viaMaybeUninit::zeroed;client = addr_of_mut!(me);portnum/debuglevel = -1;serverbooting = 1;bootopt = BOOT_PROT|BOOT_STRICTPROT; the six=1timers in.data, the rest BSS). Themeself-pointer hazard is a non-issue at definition — the interiorme.name → me.serv->namebufpointers are set at runtime by the already-portedmake_server/setup_me, so the static is just a zeroedaClient(the C BSS def). DATA-symbol seam carries the rest: the other modules reach the bindgen-surfaced globals through theirircd_sys::bindings::{me,client,…}extern static mutdecls, which resolve to these defs at link (provenlocal/anon/svchans/iauth). The 5 non-bindgen flags/timers (dorehash/dorestart/restart_iauth/nextpreference/nextiarestart), formerly reached via two localextern "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/tunefiledefault toIRCDCONF_PATH/IRCDTUNE_PATHvia newIRCD_CONF_PATH/IRCD_TUNE_PATHrustc-envs (re-exportedircd_sys::CONF_PATH_Z/TUNE_PATH_Z, NUL-terminated).ircd.oadded toPORTED; theircd_link.osecond-compile (the long-DPORT_IRCD_*chain) + theircd.o→ircd_link.olink-map arm deleted from build.rs; cref keeps the unguardedircd.osocref_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(writesdorehash/dorestart/restart_iauth)/ircd_tune_diff/ircd_cli_helpers_diff/setup_signals_diff/activate_delayed_listeners_diff— all zero-diff +golden_registration2 byte-identical (boots the Rust ircd, which now ownsme/the timers/configfile/tunefile);nm target/debug/ircdshows all ~26 resolving as Rust defs (B/D, noneU) with the correct.data/.bsssplit;cargo build --workspace0 warnings. Now onlysupport_link.o(the format remnantsdgets/make_isupport/snprintf_append/ipv6string/minus_one) keeps C logic; every other TU is Rust-or-data-only. -
P8r DONE:
support.odropped outright — the LAST C-logic TU —dgets+make_isupportported toircd-common/src/support.rs, theipv6string([c_char;46]BSS) +minus_one([c_uchar;17]= 16×0xff+0,.data) data globals defined as#[no_mangle] pub static mutstatics. The variadicsnprintf_appendis NOT ported: it has no live Rust caller (WHOX is built field-by-field ins_user.rs) so it died with the.o.support.oadded toPORTED; thesupport_link.osecond-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.ovariants). cref keeps the unguardedsupport.o(13 syms) socref_dgets/cref_make_isupport/… survive for L1. Every ircd C TU is now Rust — the product link set holds only the generatedversion.o+ the L1 harnessctruth.o. Gate: new L1 differentialsdgets_matches_reference(pipe-driven:\n/\rlines, odd-backslash continuation splice, even-backslash run, EOF tail,dgets(_,_,0)reset) +make_isupport_matches_reference(walk thechar**) both zero-diff; fullsupport_diff(7) zero-diff;golden_registration(2) byte-identical (005 ISUPPORT flows throughmake_isupport);s_conf_match_ipmask_diff/res_gethost_diff(readipv6string/minus_onevia the seam) zero-diff;nm target/debug/ircdshowsdgets/make_isupportasT,ipv6stringB,minus_oneD(noneU),snprintf_appendabsent;cargo build --workspace0 warnings. -
P8s DONE: all 115 L1
cref_differentials migrated to self-containedircd-commoninsta snapshots — the oracle-retirement test step. Eachircd-testkit/tests/<n>_diff.rsnow has anircd-common/tests/<n>_snap.rsthat drives ONLY the Rust port (#[no_mangle]syms vialink_anchor(); nocref_, noircd_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 + globalMutexes preserved. Sound via the capture chain: the matching differential is green at capture (Rust==cref), sosnapshot==crefgolden.instaadded 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-commonsuite stably green over repeated runs (determinism),cargo build --workspace0 warnings.ircd-testkit/cref_oracle left intact (still the proof oracle); mothballing it + droppingcc::Buildis the remaining P8 work. -
P8t DONE:
version.cported to Rust — the last generated C TU — its five data globals (generation/creation/pass_version/infotext/isupport) are now#[no_mangle]statics inircd-common/src/version.rsvia the data-symbol seam (the bindgenexterndecls ins_serv/s_user/s_debug/ircd/s_bsdresolve to them at link).generation=CARGO_PKG_VERSION,creation=a UTC build-stamp captured in a newircd-common/build.rs(user-directed: sourced from crate metadata at build time);pass_version=PATCHLEVEL+ theinfotext[]credits array copied verbatim. Theversion.c.SHgeneration step + theversion.ocompile/archive deleted fromircd-sys/build.rs→libircd_c.anow holds only the L1 harnessctruth.o.creationis now build-time volatile so the L2 canonicalizer masks RPL_CREATED (003), matching the existing 371 Birth-Date rule. Gate:cargo build --workspace0 warnings;nmshows all five syms as Rust defs (D/B, none U),version.oabsent from the archive;ircd-commonsnapshot suite green (117 results); golden suite 58 pass + the one known pre-existinggolden_s2s_s_serv_statsflake (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-testkitall pass; L2ircd-golden86 pass + only the documenteds_serv_statsreference-C-garbage flake, Rust the correct side), then deleted fromircd-sys/build.rsthemakeobject build / thecref_*/ctruth.o/res.orecompiles / thelibircd_c.aarchive / the whole-archive link +-lz/-lm/-lcrypt(none needed by Rust).build.rsnow only runsconfigure+ bindgen over the C headers + expands the install-path Makefile vars.ircd-testkit/ircd-goldenexcluded from the workspace (mothballed, git-recoverable);ctruth.c/layout.rsdrift-net deleted. Gate:cargo build --workspace0 warnings links pure Rust (binary boots, 0cref_/ctruthsyms,c_ircd_maina RustT);cargo test --workspace698 pass / 0 fail across 125 binaries. Every ircd C TU is gone from the build — P8 COMPLETE. -
P8v DONE (C source tree DELETED,
ircd-sysretired — workspace now has zero C files at all): P8u stopped one step short of literal C removal — it dropped all C compilation but keptircd-sys, whosebuild.rsstill ranconfigure+ bindgen over the C headers to produce the struct/type viewircd-commonbuilds against. P8v finishes the job: froze the generatedbindings.rs(4953 lines, bindgen 0.72.1 over the locked-config headers) into a committedircd-common/src/bindings.rs(pub mod bindings;+ a self-aliasextern crate self as ircd_sys;so the 28 ported modules'ircd_sys::bindings::*/ircd_sys::MOTD_PATHpaths resolve unchanged to the in-crate module + frozen install-path consts — zero src churn). Then deleted theircd-syscrate, the mothballedircd-testkit/ircd-goldenoracle crates, theiauth-rs/tests/differential_c.rsC-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-rsnow callsircd_common::ircd::c_ircd_maindirectly (dropped itsircd-sysdep). Fourclashing_extern_declarationssurfaced once bindings + the modules' local forward-decls shared a crate (unregister_server/del_from_hostname_hash_table/del_from_ip_hash_tablemissing-> c_int;mystrdupdecl'd*constvs the real*mut) — aligned the 4 decls to the real signatures (oneline.as_ptr() as *mut c_charcast at the s_misc MOTD call site). Gate:cargo build --workspace0 warnings links pure Rust;cargo test --workspace695 pass / 0 fail. The repo now contains no C whatsoever. Next: P9 (std-library cleanup).