Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
P5 — Command handlers (bulk): sub‑phase progress log#
This is the detailed, per‑cluster progress log for Phase P5 of the
strangler‑fig C→Rust migration. It was split out of PLAN.md
(whose P5 table row had grown to ~45 Ki on a single line). See the P5 row
in PLAN.md for the module list, approach, and test gate.
Each entry is one ported command cluster, in order. "Drop" = the .c was
removed from build.rs; partial ports keep the rest of the TU as C behind a
*_link.o seam.
- P5a DONE:
s_service.c(first cluster — established the handler‑porting mechanism). - P5b DONE:
s_debug.c(first utility/callee TU — STATS sub‑reports) +s_zip.cdropped for free (ZIP_LINKS off → onlyrcsid). - P5c DONE:
s_misc.c(theexit_client/exit_one_client/exit_serverexit cascade + client‑name/date/stats utilities;s_misc.odropped). - P5d DONE:
s_user.cWHO/WHOIS cluster (m_who/m_whois/who_one/who_channel/who_find/send_whois/parse_who_arg) vias_user_link.opartial port; rest ofs_user.cstays C. - P5e DONE:
s_user.cUSERHOST/ISON cluster (m_userhost/m_ison) — sames_user_link.opartial port (guard extended). - P5f DONE:
s_user.cmessage‑routing cluster (m_message/m_private/m_notice— PRIVMSG/NOTICE delivery core) — sames_user_link.opartial port; golden harness gained multi‑clientClient+boot_standaloneto cover#/+/&channel relay. - P5g DONE:
s_user.cAWAY cluster (m_away+send_away) — sames_user_link.opartial port;send_awaynow resolves to Rust for the already‑portedm_message/m_whoiscallers. - P5h DONE:
s_user.cUMODE cluster (m_umode+send_umode+send_umode_out+ theuser_modes[]table) — sames_user_link.opartial port;send_umodenow resolves to Rust for the still‑Cregister_user/s_service.c/s_serv.ccallers. - P5i DONE:
s_user.cPING/PONG cluster (m_ping+m_pong) — sames_user_link.opartial port; pure routing handlers (no statics). - P5j DONE:
s_user.cOPER cluster (m_oper) — sames_user_link.opartial port; reuses the Rustsend_umode_out; new dedicatedoper.conffixture +boot_confharness fn to L2‑test the auth paths (491/464/success). - P5k DONE:
s_user.cQUIT/POST exit cluster (m_quit+m_post) — sames_user_link.opartial port; both terminate in the already‑Rustexit_client(P5c); L2 covers QUIT (registered) + POST (unregistered http‑proxy alias). - P5l DONE:
s_user.cPASS cluster (m_pass) — sames_user_link.opartial port; registration‑time password/version‑staging handler (no wire output); L1 differential oncptr->passwd/cptr->info+ L2 PASS‑then‑register banner byte‑identical. - P5m DONE:
s_user.ccanonize utility (canonize— the comma‑list deduplicator) — sames_user_link.opartial port; a pure callee (no msgtab row) reached from m_mode/m_part/m_topic (channel.c) + m_whowas (whowas.c) + the WHO cluster; L1 differential is the gate, WHOWAS gives an L2 dedup regression gate. - P5n DONE:
s_user.cdo_nick_name utility (do_nick_name— the nickname validator/canonicalizer) — sames_user_link.opartial port; a pure string callee (no msgtab row) reached from still‑C m_nick/m_user/register_user; L1 differential is the gate, the registration banner is the L2 regression gate (the nick is echoed in every reply). - P5o DONE:
s_user.cis_allowed ACL gate (is_allowed— the per‑client O‑line/service privilege check) — sames_user_link.opartial port; a pure callee (no msgtab row, no globals/hash — a pure function ofcptr) reached from portedparse.rs(penalty) + still‑C m_kill/s_serv/s_conf/channel/res/hash/s_bsd; L1 differential (conf‑walk) is the gate, oper‑KILL grant(K→401)/deny(T→481) is the L2 branch‑selection gate. - P5p DONE:
s_user.cKILL handler (m_kill— the oper/server KILL command; gates on the Rustis_allowed(P5o), resolves the victim via Rustfind_uid/find_client/get_history, terminates in the Rustexit_client(P5c)) — sames_user_link.opartial port; new multi‑clientgolden_s_user_killL2 (oper alice KILLs registered bob → victim KILL notice +exit_clientclose byte‑identical). - P5q DONE:
s_user.cregister_user (the central client‑registration routine — ident‑prefix username canonicalization,check_client/find_killgating, the welcome banner [001…RPL_YOURID + LUSERS + MOTD],send_umode, the leaf‑server UNICK feed) — sames_user_link.opartial port; a utility/callee (no msgtab row) reached from still‑Cm_nick/m_user/m_unick; the registration banner (the P0‑L2 anchor scenario) is the L2 gate. - P5r DONE:
s_user.cm_user (the USER registration handler —make_user/numericsip, the+/-/RFC‑bit umode‑in‑USER parse, real‑nameinfocapping, then theregister_user(P5q) tail‑call) — sames_user_link.opartial port; a handler (msgtabUSER=[m_nop,m_reg,m_reg,m_nop,m_user]→ unregistered col only) reached on the registration path; the registration banner is the L2 gate (drivesmake_user+ the "no flags" umode path). - P5s DONE:
s_user.cNICK cluster (m_nick+m_unick+save_user[static SAVE emitter] +m_save— the connected component sharingsave_user) — sames_user_link.opartial port;m_nick'sgoto badparamcountkills/goto nickkilldonecontrol flow refactored into two faithful helper fns; L2 golden (golden_s_user_nick: local nick change echo,432erroneous nick,433nick‑in‑use) byte‑identical;m_unick/m_save/save_user's SAVE emit are S2S‑only (no L2 path under‑s, covered by review). Onlynext_client/hunt_server(hash‑dependent → S2S/L2) now remain ins_user_link.o.s_auth.cdeferred to P7/P‑IAUTH (nom_*; pure socket/ident/iauth‑pipe I/O, no L2 path under‑sboot).** - P5t DONE:
channel.cleaf‑predicate foundation cluster (is_chan_op/has_voice/find_channel/clean_channelname— the only truly‑leaf exports, no file‑static/shared‑buffer dep) via the newchannel_link.opartial port (‑DPORT_CHANNEL_P5); establishes the channel.c port mechanism. L1 differential (4 fns) + L2golden_channel(JOIN #chan → 353@alice/366).can_senddeferred to the mode cluster (calls the staticmatch_modeid). P5‑S2S DONE: server‑link golden coverage — the newircd-goldenPeerfake‑server (completes the IRCnet 2.11PASS/SERVER→burst handshake) +s2s.conffixture (C/N/H lines) close theIsServer(cptr)paths every cluster above deferred to "S2S/L2": 13golden_s2s_*scenarios byte‑identical (ref‑C == Rust) — link+remote‑WHOIS, PRIVMSG routing (P5f), AWAY (P5g), umode propagation (P5h), QUIT propagation (P5k), server‑KILL (P5p), SQUIT/exit_serverreap (P5c), remote NICK + SAVE (P5s), USERHOST/ISON (P5e), remote WHO (P5d),register_userleaf‑UNICK feed (P5q), SERVICE intro+SQUERY (P5a). - P5u DONE:
channel.cinvite cluster (m_invite+ the file‑staticsadd_invite/list_length+check_channelmask+del_invite) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Second channel.c sub‑phase; first to hit the static‑function‑with‑remaining‑C‑callers case:check_channelmask(called by m_join/m_part/m_kick/m_topic/m_njoin/set_mode/send_channel_*) has its forwardstaticprototype switched toexternunder the guard so the C remnant resolves to the Rust def (linkage‑only, faithful).del_invite(exported) now resolves for s_misc.rs + free_channel/m_kick/m_njoin too. L1channel_invite_diff(del_invite chain relink + istat deltas; the staticsadd_invite/list_length/check_channelmaskhave no oracle symbol → L2‑covered); L2golden_channel_invite(4 scenarios: success 341 + relayed INVITE [fires add_invite live], 401, 442, 476check_channelmask). - P5v DONE:
channel.ccan_send + match_modeid cluster (can_send[exported send‑permission predicate] +match_modeid[file‑static ban/exception matcher, via the P5u extern‑prototype switch sincecan_join/reop_channelstay C]); resolves the already‑Rustm_message/who callers; also fixed a latent P5uis_memberbug (the activeIsMembermacro walks the client's channel list viafind_channel_link, notchptr->members). L1channel_can_send_diff(8 cases vscref_can_send) + L2golden_channel_can_send(+m moderated / +n no‑external 404 rejects). - P5w DONE:
channel.cchannel_modesleaf (the "simple" channel mode‑string serializer, channel.c:831 — writes+‑flags intombufand the+l/+kparams intopbuf) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Fourth channel.c sub‑phase; a true leaf (no file‑static — writes caller buffers; onlyIsMember/IsServer+ libcsprintf/strcat), so a plain#ifndefguard drops the exported def and resolves the still‑C callers (m_modequery,set_mode,send_channel_modes) to the Rust def. L1channel_modes_diff(17 cases vscref_channel_modes: every bit + secret/private precedence ++l/+kparams member/server vs suppressed) + L2golden_channel_modes(MODE #chanquery →324 RPL_CHANNELMODEISbyte‑identical, exercising both+lsprintfand+kstrcat). - P5x DONE:
channel.cmembership cluster (add_user_to_channel+remove_user_from_channel+change_chan_flag— themembers/clist/user->channellist manipulators +istatcounters) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Fifth channel.c sub‑phase; touches no sharedbuf/modebufstatic. The two file‑statics (add_user_to_channel/change_chan_flag) getexternforward decls under the guard (no existing forward decl); the still‑Cfree_channelis kept C via a linkage‑onlystatic→externswitch (the Rustremove_user_from_channelcalls it on the last‑user teardown).remove_user_from_channelalready resolves for the Rusts_misc.rsexit cascade (P5c). L1channel_membership_diff(the exportedremove_user_from_channelvscref_: members/clist relink +user->channel+is_userc/is_chanusersdeltas; the statics are L2‑covered). L2golden_channel_part(PART with a second member observing the relay + NAMES/WHO omitting the parted user →remove_user_from_channel;MODE +o→NAMES@bob→change_chan_flag) + the JOINgolden_channelregression coversadd_user_to_channel; S2Sgolden_s2s_membership(remote NJOIN →add_user_to_channel, remote PART →remove_user_from_channel, observed by a local member). - P5y DONE:
channel.cm_topichandler (the TOPIC command — per‑channel query [331/332/333] or set [propagate + 482 reject]) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). The cleanest channel.c handler: every callee is already Rust (canonize/strtoken/find_channel/check_channelmask/is_chan_op) or a C variadic sender, andm_topichas no file‑static of its own → a plain#ifndefguard drops the C def and them_topicdecl parse.rs imports resolves to the Rust def (no extern‑prototype switch, no parse.rs/build.rs edit).TOPIC_WHO_TIMEdefined → thetopic_t/topic_nuhblocks ported (topic_nuh= byte‑builder, notformat!; 333'stopic_tmasked as wall‑clock volatile). L2golden_channel_topic(lifecycle: query‑empty 331 → set → query 332/333 → change → re‑query reflects the new value; rejects 442/403/482) + S2Sgolden_s2s_topic(remote bob TOPIC → relay to local member + 333 with bob'stopic_nuh; local alice TOPIC →sendto_match_servsUID‑sourced propagation to the peer). - P5z DONE:
channel.cm_listhandler (the LIST command — channel listing: bare lists all visible channels [322 + LIST_ALIS_NOTE notice + 323], named/!‑mask forms) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Likem_topica true leaf (no file‑static of its own) → a plain#ifndefguard drops the C def; every callee is already Rust (canonize/strtoken/find_channel/hash_find_channels/get_sendq) or a C extern (hunt_server, the variadicsendto_one— whose ircd‑common extern decls were unified to-> c_intsom_list'srlen += sendto_one(…)reply‑length throttle ports faithfully). L2golden_channel_list(bare LIST shows two public channels + 323, a+schannel a non‑member can't see is absent [the inverse], namedLIST #pub,LIST #nonexistent→ only 323) + S2Sgolden_s2s_list(thehunt_serverforwarding short‑circuit:LIST #chan peer.test→ the peer receives the forwarded command, byte‑identical). - P5aa DONE:
channel.cm_parthandler (the PART command — leave one/more channels: per‑channelget_channel/check_channelmask/IsMembergating, the comma‑batched server broadcast via the private scratchbuf, member relay, then the now‑Rustremove_user_from_channel) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Its only still‑C callee is the file‑staticget_channel(extern‑prototype switch on both forward decl + definition, P5u/P5x mechanism — flag 0, no CREATE); every other callee is already Rust (canonize/strtoken/check_channelmask/remove_user_from_channel) or a C variadic sender (sendto_serv_butone/sendto_match_servs/sendto_channel_butserv);get_channelmaskis the JAPANESE‑off macrorindex(name,':')=strrchr. The sharedstatic buf[BUFSIZE]is pure scratch (init+flush in‑call) → a module‑privatestatic mut BUFis faithful. L2: the existinggolden_channel_part(local success + NAMES/WHO inverse) now drives the Rust m_part, extended with its own error numerics (403 NOSUCHCHANNEL / 442 NOTONCHANNEL); S2Sgolden_s2s_membershipalready covers the remote‑PARTIsServer(cptr)/sptr->user->uidpropagation branch. - P5bb DONE:
channel.cm_kickhandler + the file‑staticfind_chasing(the KICK command — kick one/more users from one/more channels:get_channel/check_channelmask/is_chan_opgating,find_chasing/find_uidvictim resolution, the comma‑batchedsendto_match_servs_v(SV_UID)UID propagation, member relay viasendto_channel_butserv, then the now‑Rustremove_user_from_channel) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5).find_chasingis the cluster's shared file‑static — also called by the still‑Cm_mode/set_mode, so it gets the P5u/P5x extern‑prototype switch (its C body is guarded out and anexternforward decl added so the C remnant resolves to the Rust def);check_string(the other display static) is untouched (m_kick doesn't call it). Every other callee is already Rust (get_channel[C static, extern‑switched by P5aa]/check_channelmask/is_chan_op/remove_user_from_channel/find_uid/find_client/get_history/mystrdup) or a C variadic sender (sendto_flag/sendto_match_servs_vadded to the extern block). L2golden_channel_kick(chanop KICKs member → relay + NAMES inverse; error numerics 441 [find_chasing resolves a non‑member]/403/442/482) + S2Sgolden_s2s_kick(UID propagation:<kicker‑uid> KICK #chan <victim‑uid>to the peer; server‑sourced:001B KICKexercising theIsServer(cptr)+find_uid/IsServer(sptr)SID‑sender branches). - P5cc DONE:
channel.cdisplay cluster —m_nameshandler + the file‑staticnames_channel(the NAMES command + the per‑channel353 RPL_NAMREPLY/366 RPL_ENDOFNAMESemitter) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5).names_channelis still called by the Cm_join(the JOIN echo) → P5u/P5x extern‑prototype switch (itsstaticforward decl + body guarded out, anexternforward decl added so the C remnant resolves to the Rust def);m_namesis a plain#ifndefguard (msgtabNAMES=[m_nop,m_names,m_names,m_nop,m_unreg]→ its decl parse.rs imports resolves to Rust). Every callee is already Rust (find_channel_link/find_channel/clean_channelname/strtoken) or a C extern (hunt_server, the variadicsendto_one). Both share the moduleBUF(the Cbuf[BUFSIZE]):names_channelfills+flushes it in‑call andm_namesonly writesbufitself after all itsnames_channelcalls → oneBUFis faithful (the still‑Cm_joinkeeps its own Cbuf; its!‑autocreatename=bufcross‑call aliasing is a documented residual that vanishes when m_join ports). No socket‑free data op (read‑only + wire) → L2/L2‑S2S are the gates, no L1 (cf. m_list/m_topic). L2golden_channel_names(NAMES #pub= #pub :@alice bob353+366; secret‑channel member@ #secretmarker; inverse — a non‑member'sNAMES #secretyields only 366; bareNAMESall‑channels +* * :remaining‑users section) + JOIN‑echo regression viagolden_channel; S2Sgolden_s2s_names(theparc>2hunt_serverforwarding short‑circuit:NAMES #chan peer.test→ the peer receives the forwarded command, byte‑identical). - P5dd DONE:
channel.cJOIN cluster —m_joinhandler + the file‑staticcan_join(the JOIN command + its access‑control predicate) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5).can_joinis file‑static and its only caller (m_join) ports here too → no C caller remains, so it is a private Rustunsafe fn(nocref_can_joinoracle → L2‑tested via m_join's reject numerics); both its forward decl + body are plainly guarded out.m_joinis a plain#ifndefguard (msgtabJOIN=[m_nop,m_join,m_join,m_nop,m_unreg]→ client+server cols; its decl parse.rs imports resolves to Rust). Every callee is already Rust (strtoken/check_channelmask/clean_channelname/find_channel/hash_find_channels/check_chid/get_chid/del_invite/add_user_to_channel/remove_user_from_channel/names_channel/exit_client/match_modeid/mycmp) or a C extern (get_channel[extern‑switched by P5aa], the variadic senderssendto_serv_v/sendto_channel_butoneadded to the block). m_join's function‑static jbuf[BUFSIZE]→ a module‑privateJBUF(distinct from the sharedBUFit uses as the!‑channel‑idsprintfscratch — resolving the P5cc‑documentedm_join/bufresidual). No socket‑free data op (membership via the already‑L1'dadd_user_to_channel, then wire) → L2/L2‑S2S are the gates, no L1 (cf. m_names/m_list). L2golden_channel_join(+kwrong‑key 475 then keyed join,+i473 then INVITE override,+l 1full 471, duplicate‑JOIN no‑op,JOIN 0part‑all + NAMES inverse) + thegolden_channelJOIN/part/rejoin regression; S2Sgolden_s2s_join((a) a local client's JOIN of a federated#chanpropagates:000A NJOIN #chan :000AAAAAAto the peer [sendto_serv_vSV_UID, local SID + joiner UID]; (b) theIsServer(cptr)head — a peer‑sourced:<uid> JOIN 0relays the remote user's PART to a local co‑member).m_njoin/reop_channel/the mode cluster stay C. - P5ee DONE:
channel.cm_njoinhandler (the server‑only NJOIN channel‑membership burst command) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Twelfth channel.c sub‑phase; a handler with no standalone client path (msgtabNJOIN=[m_njoin,m_nop,m_nop,m_nop,m_unreg]→ col 0 only, server‑reachable) → L2‑S2S is its only gate (no L2, no L1). Plain#ifndefguard (its decl parse.rs imports resolves to Rust; not anyone's static callee). Every callee already Rust (check_channelmask/find_person/find_uid/add_user_to_channel/get_client_name) or a C extern (get_channel[extern‑switched by P5aa, CREATE], the variadic senders). The sharedmodebuf/parabuffile‑statics (the synthetic‑MODE scratch) → module‑privateMODEBUF/PARABUF(pure in‑call scratch — faithful, cf. P5aa'sBUF);uidbuf/mbufare C autos → Rust stack arrays. Newis_burstinghelper (!(flags & FLAGS_EOB)). L2‑S2Sgolden_s2s_njoin(the@+op+voice MODE‑burst the membership test doesn't cover: a peer NJOINs carol@+onto a #chan a local member is on → the relayed JOIN + the synthetic:peer.test MODE #chan +ov carol carolburst, exercising thembuf[1]double‑param path) + the existinggolden_s2s_membership(plain add/remove) now drives the Rust m_njoin as a regression; the other NJOIN‑driving goldens (join/kick/topic) stay byte‑identical. - P5ff DONE:
channel.cmode‑id list layer (check_string+make_bei/free_bei+add_modeid/del_modeid— the ban/exception/invite+b/+e/+Ilist‑item alloc +mlistadd/del, the connected component over the file‑staticasterixvar) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Thirteenth channel.c sub‑phase; all five are file‑staticin C → the P5u/P5x extern‑prototype switch on each (the still‑Cset_modecallscheck_string/make_bei/add_modeid/del_modeid;set_mode+free_channelcallfree_bei— so eachstaticforward decl flips toexternunder the guard;check_stringhad none → a newexterndecl added).asterixis module‑private in Rust (static mut ASTERIX): C never references it outside the now‑portedcheck_string/make_bei/free_bei, so the pointer identity stays self‑consistent (make_bei stores it, free_bei compares it, C only ever passes the resultingaListItem). Every callee already Rust (collapse/mycmpP1,make_link/free_linkP2,istatP2 withwrapping_add/sub— cf. P5u add_invite) or libc (MyMalloc/free/strncpy/isspace). No L1 — all five file‑statics → nocref_oracle (cf. P5vmatch_modeid/P5ddcan_join); L2 byte‑identity through the still‑Cset_modeis the faithfulness gate. L2golden_channel_ban(local chanop+b/+e/+Iadd → make_bei split + add_modeid store, ban‑list query367/348/346reads the Rust‑builtmlist, duplicate+bBanExact dedup, then-b→ del_modeid + free_bei + inverse re‑query the ban is gone) + S2Sgolden_s2s_ban(a peer server sets+b→ the non‑MyClient add_modeid arm — the pure list‑add that skips everysendto_one, reachable only over a link — then server-b→ del_modeid; alice's query confirms the round‑trip). - P5gg DONE:
channel.cmode core (m_mode+set_mode+send_mode_list+send_channel_modes+send_channel_members— the MODE handler + the ~860‑line mode parser/applier + the server‑burst emitters; the connected component over the sharedmodebuf/parabuf/uparabufstatics, now module‑private sincem_njoin[the only other user] is already Rust) via the existingchannel_link.opartial port (‑DPORT_CHANNEL_P5). Fourteenth (final large) channel.c sub‑phase. All five take a plain#ifndefguard (no extern‑switch):set_mode/send_mode_listare file‑static with no remaining C caller (m_mode/send_channel_modes port here) → private Rustunsafe fns;send_channel_modes/send_channel_membersare exported and still called by the Csend_server_burst→#[no_mangle]resolves s_serv's calls at link;m_mode's decl resolves via the parse.rs imports. Faithful port of the full mode grammar (+/-witho/v/O/k/b/e/I/R/l+ the simple‑flag table, theopcntchopsreconstruction, parseNUH via the Rustmake_bei, thekkey sanitizer, thereopscheduling). Bug caught by the burst S2S test:aListItem.nick/user/hostare*mut c_charpointers, not arrays — the first port tookaddr_of!and printed pointer bytes; fixed to pass the pointers directly. L2golden_channel_mode_set(chanop+v/-vmember‑voice relay seen by a second member + NAMES+bob→bobinverse) + the regression suite already driving set_mode (golden_channel_modessimple/limit/key,golden_channel_ban+b/+e/+I,golden_channel_part+o→NAMES). S2Sgolden_s2s_mode(outbound: a local chanop's+m/+l 5→sendto_match_servs_v(SV_UID)UID‑sourced propagation to the peer; link burst: a peer relink replays #chan viasend_channel_membersNJOIN +send_channel_modes+tnl/+b— the only way to burst a populated#channel in the single‑peer harness, since a split local server can't pre‑create one) +golden_s2s_ban/golden_s2s_membershipthe inbound‑server‑MODE regression. - P5hh DONE:
channel.clifecycle group (get_channel/free_channel/reop_channel/setup_server_channels/collect_channel_garbage+ thechannelglobal list head) — the 15th and final channel.c sub‑phase, sochannel.ois now dropped outright (added toPORTED; the P5t…P5ggchannel_link.osecond‑compile + its-DPORT_CHANNEL_P5substitution removed entirely; the cref oracle keeps the unguardedchannel.o).get_channel/free_channelwere file‑static (extern‑switched P5aa/P5x) andreop_channelpurely file‑static (collect_channel_garbage's only caller → private Rustunsafe fn);setup_server_channels/collect_channel_garbageare channel_ext.h exports called fromircd.c(boot / io_loop timer). Classification: utility/callee TU (nomsgtabhandler). L1 (channel_lifecycle_diff.rs, the two exported entries havecref_oracles; the three statics are transitively covered):setup_server_channelscreate‑cluster (14 server channels under USE_IAUTH‑on/CLIENTS_CHANNEL‑off — chname/topic/mode/lone‑chanop walk identical) + the inverse (oracle'dremove_user_from_channelon&ERRORS→free_channelunlinks it from list+hash, the other 13 survive) +collect_channel_garbage(hand‑built&deadempty+expired vs&live→ identical returnnow+CHECKFREQ+ free/keep; pinnedtimeofdayso free_channel's clock re‑check fires). No new L2‑S2S — none of the six has anIsServer(cptr)dispatch branch or formats remote‑user fields;get_channel/free_channelare already L2/S2S‑covered transitively by every JOIN/PART golden (golden_channel*,golden_s2s_membership), andcollect_channel_garbage/reop_channelare timer‑driven (300 s, unreachable in a short golden — themyrandreop arm is review‑covered). channel.c is now FULLY ported to Rust. - P5ii DONE:
s_serv.cinformational query foundation cluster (m_version+m_time+m_admin— the three leaf informational query handlers: each ahunt_serverforward + a fewsendto_one(replies[…])replies, with no file‑static of its own) — the firsts_serv.csub‑phase, establishing thes_serv_link.opartial port (‑DPORT_SERV_P5, carrying the per‑object‑DIRCDMOTD_PATHfor the still‑Cm_motd; mirrorss_user_link.o) for the last/largest P5 TU. Plain#ifndefguards (none is a file‑static or anyone's static callee). Every callee already resolves:hunt_server/find_admin/sendto_one(C externs),replies(P3),date(P5c),serveropts(P5b),me/me.serv->sid/IRC_VERSION. Classification: handler cluster (msgtab col 1, min‑params 0 → client‑reachable) with a server‑reachablehunt_serverforward branch → L2 + L2‑S2S, no L1 (pure wire handlers, no socket‑free data op — cf.m_list/m_topic/m_names). L2golden_s_serv_info(local VERSION→351 / TIME→391 [localtime masked] / ADMIN→256‑259 via minimal.conf'sAline) + S2Sgolden_s2s_s_serv_info(thehunt_serverforwarding short‑circuit:VERSION/TIME/ADMIN peer.test→ the peer receives the forwarded command, byte‑identical). - P5jj DONE:
s_serv.cnetwork‑info query cluster (m_info+m_links+ the file‑staticcheck_link) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Second s_serv.c sub‑phase; first s_serv.c extern‑prototype switch:check_link(file‑static, still called by the Cm_stats/m_motd) flips its forward declstatic→externunder the guard so the C remnant resolves to the Rust def (P5u/P5x mechanism);m_info/m_linkstake plain#ifndefguards. Every callee already resolves (hunt_server/sendto_oneC externs;infotext/creation/generationversion.c externs;myctime/collapse/match_/svrtop/ircstpRust;CHREPLLEN=8192 baked). Classification: handler cluster, no L1 (pure wire handlers;check_link's counter‑mutating load branches are file‑static → nocref_oracle + non‑deterministic over a loaded link → review‑covered, the return‑0 local path is L2‑covered). Two new canonicalizer masks for m_info's volatile371trailers (:Birth Date:build stamp +:On‑line sinceboot clock). L2golden_s_serv_info_links(INFO371/374+ bare LINKS364/365) + S2Sgolden_s2s_s_serv_info_links(INFO/LINKShunt_serverforwards to the peer + the bare‑LINKS tree walk before/after the link — the positive/inverse pair exercisingm_links's remoteup->name/sid/infoformatting). - P5kk DONE:
s_serv.cinformational stub cluster (m_users+ the file‑staticsend_users+m_summon+m_help) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Third s_serv.c sub‑phase; three leaf handlers with no file‑static of their own. Config‑resolved:USERS_RFC1459off →m_usersforwards (parc>1) then callssend_users(265/266);ENABLE_SUMMONoff →m_summon→445;m_helplistsmsgtab[].cmdas NOTICEs.send_usersisstaticin C but has a remaining C caller (the still‑Cm_lusers, s_serv.c:2386) → the P5u/P5x extern‑prototype switch on its forward decl (s_serv.c:52) so that caller resolves to the#[no_mangle]Rust def. No L1 (pure wire handlers;send_usershas nocref_oracle — GCC inlined it as.isra.0). L2golden_s_serv_stubs(USERS265/266+ SUMMON445+ HELP NOTICE list anchored on the final:ETRACE) + S2Sgolden_s2s_s_serv_stubs(thehunt_serverforwarding short‑circuit:USERS peer.test/SUMMON nobody peer.test→ the peer receives the forwarded command;m_helphas no forward path → not in the S2S scenario). - P5ll DONE:
s_serv.cLUSERS handler (m_lusers) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Fourth s_serv.c sub‑phase; a single leaf handler with no file‑static of its own (plain#ifndefguard) that closes the P5kksend_usersloop — itsall‑path tailif (all) send_users(...)already resolves to the Rustsend_users. Config‑resolved (USERS_RFC1459off): bare/*LUSERSreadsistat(theallpath → 251/254/255 then 265/266 viasend_users);LUSERS <server>resolves a remotefind_client→IsServer→usercnt[];LUSERS <mask>walkssvrtop/svctopsumming remoteusercnt[];parc>2forwards viahunt_server. Newis_server/is_meone‑line status helpers. Faithfulness:intlocals stayc_int(C'su_long→inttruncation =as c_int),istat.is_chanpassed straight to the%dvariadic asu_long(byte‑identical, cf.send_users), and the 253 RPL_LUSERUNKNOWN usesparv0notBadTo(parv0)quirk ported literally. Classification: handler cluster, no L1 (pure wire handler, the lookups are read‑only counting terminating insendto_one). L2golden_s_serv_lusers(bare LUSERS → 251/254/255 + thesend_users265/266) + S2Sgolden_s2s_s_serv_lusers(two server‑reachable facets: thesvrtopmask walkLUSERS *.testafter a peer links — the 251 server count reflects the link + theIsMe253 arm — diffed client‑side; and theparc>2hunt_serverforwardLUSERS * peer.test→ the peer receives the forwarded command). - P5mm DONE:
s_serv.cmap‑display cluster (m_map+ the two recursive file‑staticsdump_map[plain names] /dump_map_sid[names + usercount + SID + version]) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Fifth s_serv.c sub‑phase; a handler + its two tree‑renderer statics, all under one plain#ifndefguard (the statics have no remaining C caller → private Rustunsafe fns, nocref_oracle;m_map's decl resolves via the parse.rsmsgtabimports). The sharedbuf[BUFSIZE]→ a module‑privateBUF(filled+flushed in‑call → faithful, cf. P5aa/P5cc); the recursive tree walk overserv->down/->rightaccumulates the output line via raw pointer arithmetic (pbuf + 4per nesting, backward tree‑char cleanup), each leaf flushing the wholebufwith015 RPL_MAP.meisSetEOB'd at boot →dump_map_sid(&me)always takes the deterministic non‑bursting branch. Classification: handler cluster, no L1 (pure wire handlers;m_maphas nohunt_serverforward butdump_map/dump_map_sidformat remote‑server fields → L2 + L2‑S2S). L2golden_s_serv_map(MAP→ 018/015/017 single‑server +MAP s→ local usercount/SID/version) + S2Sgolden_s2s_s_serv_map(the multi‑server tree walk: bareMAPbefore/after the peer links —: \- peer.testappears — thenMAP sadds: `- peer.test 0 001B 0211030000, the peer sent anEOB` first so the non‑bursting branch is deterministic). - P5nn DONE:
s_serv.cTRACE cluster (m_trace+m_etrace+ the file‑statictrace_one+ the internal‑linkagecount_servers_users) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Sixth s_serv.c sub‑phase; a handler pair + their shared per‑client renderer.trace_one(file‑static, only callersm_trace×2 port here) → private Rustunsafe fn;count_servers_users(thestaticforward decl gives it internal linkage despite the non‑staticdef → GCC inlined it, no symbol) is still called by the Creport_myservers→ extern‑prototype switch (its forward decl flipsstatic→externunder the guard so the C remnant resolves to the#[no_mangle]Rust def). HUB off →count_servers_usersuses theistat‑only branch (is_serv‑1,is_user[0]+is_user[1]‑is_myclnt); XLINE off →m_etrace's user2/user3 are the"-","-"literals; ENABLE_SIDTRACE off →m_sidtracenot compiled, not ported. The volatile200 RPL_TRACELINKuptime/sendQ ported faithfully but only diffed peer‑side (the forwarded command) in S2S. Classification: handler cluster, no L1 — pure wire handlers terminating insendto_one;count_servers_usersis a data op but has nocref_oracle (internal linkage in the oracle archive too), so it is L2‑S2S‑covered via the206servers/users it feeds (cf. P5jjcheck_link). L2golden_s_serv_trace(bare TRACE → 205/262 plain client; OPER+ETRACE → 709/759 via newtrace_oper.conft/ACL_TRACE oper) + S2Sgolden_s2s_s_serv_trace(bare TRACE after a peer links →206 RPL_TRACESERVERfromtrace_one+count_servers_userswith the remoteserv->version/by/userfields;TRACE peer.test→ theIsServerpassthru forwards the command, diffed peer‑side). - P5oo DONE:
s_serv.cSTATS / reporting cluster (m_stats+ the five file‑static reportersreport_myservers/report_configured_links/report_ping/report_fd/report_listeners+ thereport_array[18][3]table) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Seventh s_serv.c sub‑phase; completes the cluster‑map "Stats / reporting" component (its siblingstrace_one/check_link/count_servers_usersalready ported P5jj/P5nn). All five reporters are file‑staticwithm_statsas their only caller → private Rustunsafe fns (no extern‑switch, nocref_oracle);report_arrayis a module‑private static reproduced resolved to TKLINE‑on (the twoCONF_T*KILLrows present, the*p/p+=3row walk preserved);m_statsis a plain#ifndefguard (its decl resolves via the parse.rsmsgtabimports). XLINE off →report_x_linesnot compiled. Faithful: the full selectorswitch, theIsServer(cptr)check_link rate‑limit head, bothhunt_serverparc==3/parc>=3forms, thereport_configured_linksK/V/H/Q‑passwd‑shown + TKLINEhold‑timeofday+ CLIENT/OPERATORiline/oline_flagsbranches, theSTATS mmsgtab command‑frequency loop;report_ping/report_fduse the moduleBUF/ipv6stringas in‑call scratch (cf. dump_map P5mm). Classification: handler cluster, no L1 (pure wire reporters terminating insendto_one;report_arrayis config‑gated data with no oracle). L2golden_s_serv_stats(STATS i215/o243viareport_configured_linksover oper.conf's I/O lines, y218viareport_classes, m212the msgtab loop — each closing219; volatile selectors l/L/P/f/F/?/u review/mask‑covered) + S2Sgolden_s2s_s_serv_stats(report_myservers—STATS ?after a peer links →249 RPL_STATSDEBUGwith the peer name/1S 0C/byte counts/BURST/%Xversion, diffed in full bar the masked(timeconnected)real‑clock token; thehunt_serverforwardSTATS m peer.test→ the peer receives the forwarded command). - P5pp DONE:
s_serv.cm_motdhandler (the MOTD command —check_linkrate‑limit +hunt_serverforward, then themotd‑list reply: 375/372 + thelocaltime(&motd_mtime)date line/376, or 422 whenmotd==NULL) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Eighth s_serv.c sub‑phase; a leaf handler with no file‑static of its own → a plain#ifndefguard (its decl resolves via the parse.rsmsgtabimports). Every callee already resolves:check_link(Rust P5jj),hunt_server/sendto_one(C externs),reply()(P3), themotd/motd_mtimeglobals (bindgen statics),localtime/tm(libc). Classification: handler cluster, no L1 (pure wire handler terminating insendto_one). L2golden_s_serv_motd(MOTD →422 ERR_NOMOTDunder the no‑MOTD‑file test config — the realistic local path; the listing + date line are review‑covered, wall‑clock data from the file mtime) + S2Sgolden_s2s_s_serv_motd(thehunt_serverforwarding short‑circuit:MOTD peer.test→ the peer receives the forwarded command, byte‑identical). - P5qq DONE:
s_serv.cserver‑registration data‑structure cluster (find_server_string/find_server_num[theserver_name[]string‑interning pair],add_server_to_tree/remove_server_from_tree[theaServer‑tree pointer rewiring],check_servername) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Ninths_serv.csub‑phase — the first s_serv.c utility/callee cluster (nomsgtabrow; pure data ops, no socket/wire). Theserver_name/server_max/server_numfile‑statics → module‑private Ruststatic mut;check_servername_errors[3][2]stays C (the s_serv_ext.h decl is a tentative definition underEXTERN‑empty → a Rust#[no_mangle]strong def would collide with the C BSS symbol, andcheck_servernamenever reads the table — only its callers index it; ported whens_serv.ois dropped). All five take a plain#ifndef PORT_SERV_P5guard (every caller stays C —m_server/m_server_estabs_serv.c,exit_servers_misc.c, boot ircd.c,register_users_user.c — and resolves to the Rust defs at link). Classification: utility/callee TU → L1 is the gate (s_serv_servtree_diff:server_name[]interning round‑trip incl. theMyRealloc/server_max+=50growth boundary + the no‑duplicate‑slot re‑intern inverse; theaServer‑tree add/remove/re‑add with the leaf and head unlink inverses + theserverscount;check_servernamerc corpus + the exported error table — all zero‑diff vscref_). No new L2/S2S — none has anIsServer(cptr)dispatch branch of its own (they are unconditional callees of the still‑C link handler); every symbol runs on the existing 13golden_s2s_*peer‑link/SQUIT scenarios (link →find_server_num+add_server_to_tree+check_servername; remote users →find_server_string; SQUIT →remove_server_from_tree), which stay byte‑identical as the regression gate. - P5rr DONE:
s_serv.coper‑maintenance cluster (m_close+m_rehash) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Tenths_serv.csub‑phase — two leaf oper handlers with no file‑static of their own (plain#ifndefguards; theirmsgtabdecls resolve to the Rust defs at link). Config‑resolved: DELAY_CLOSE on →m_close’s trailingis_delayclosewait/delay_close(-2)block ported; USE_SYSLOG off →m_rehash’ssyslog()line not compiled/ported. Faithful: thefor(i=highest_fd;i;i--)walk never toucheslocal[0],RPL_CLOSINGcarriesacptr->statusas the%darg,exit_client(..,&me,..)(P5c) closes each UNKNOWN/CONNECTING/HANDSHAKE fd,m_rehashreturnsrehash(cptr,sptr, parc>1?parv[1][0]:0)(C extern). Classification: handler cluster (dispatch col 2/STAT_OPER only — a non‑oper client hits the col‑1m_nopriv/481 at the parse table), no L1 (pure wire handlers terminating insendto_one/sendto_flag, no socket‑free data op), no S2S (neither has anIsServer(cptr)dispatch branch nor formats remote‑user fields). L1: none. L2golden_s_serv_maint(success via the newmaint_oper.confO‑line flagslr: REHASH → 382 RPL_REHASHING, CLOSE → 363 RPL_CLOSEEND; inverse viaoper.confno‑flags: the handler‑internalis_allowedreject → 481). - P5ss DONE:
s_serv.cend‑of‑burst cluster (m_eob+m_eoback) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Elevenths_serv.csub‑phase — the thematic end‑of‑burst pair: a linked server'sEOB(burst complete) + theEOBACKack. Both server‑only (msgtabcol 0 — a local client/oper hitsm_nop;m_eob's first guard isIsServer(sptr)) with no file‑static of their own (m_eob'seobbuf[BUFSIZE]is a function‑local stack scratch → a Rustlet mutarray, not a module static) → plain#ifndefguards; theirmsgtabdecls resolve to the Rust defs at link. Every callee already resolves:strtoken(P1),find_sid(P4),exit_client/check_split(P5c),istat(P2), the C variadicsendto_one/sendto_flag/sendto_serv_v(SV_UID);SetEOBis a new inline flag helper. Faithful: theIsBursting(sptr)branch (MyConnect → wall‑clock "after %d seconds" SCH_NOTICE / remote → un‑masked "End of burst" notice),SetEOB+is_eobservers++, the hopcount‑1:000A EOBACKreply, theparc<2bare‑EOBsendto_serv_vpropagation, theparc≥2mass‑SIDstrtoken/find_sidloop (unknown‑SID/wrong‑direction →exit_clientlink drop; theeobbufcomma‑SID builder +eobmaxlenflush via raw‑pointer walk +memcpy), thencheck_split;m_eobackclearsFLAGS_CBURST+byuid[0]. Classification: handler cluster, server‑reachable → L2‑S2S is the only gate (no L1 — pure server‑protocol handlers with no socket‑freecref_oracle; no plain L2 — a local client can't present a STAT_SERVER prefix; cf. m_njoin P5ee). L2‑S2Sgolden_s2s_eob(a bursting peer'sEOB→:000A EOBACKreply on the peer socket; inverse — a second EOB now finds!IsBursting→ no reply, proving SetEOB changed state;m_eoback→ link survives a follow‑up remote introduce+WHOIS) +golden_s2s_s_serv_map(which drives a peer EOB) the regression. The mass‑SID multi‑server loop is review‑covered (the single‑peer harness reaches only the directly‑linked bare‑EOB path). - P5tt DONE:
s_serv.cm_sethandler (the SET oper command — read/change the runtime tunables POOLSIZE/ACONNECT/CACCEPT, echoing each value back as a NOTICE) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Twelfths_serv.csub‑phase — a single leaf oper handler with no file‑static of its own (plain#ifndefguard; itsmsgtabdecl resolves to the Rust def at link). Config‑resolved:set_table[]is unconditional (POOLSIZE/ACONNECT/CACCEPT);TSET_SHOWALL=(int)~0= ‑1 (bindgen drops the cast macro → baked asconst TSET_SHOWALL: c_int = -1, all bits set so the no‑arg form's threeacmd & TSET_*echoes all fire). Faithful: the Cswitch/break‑to‑bottom‑echo control flow refactored into aset_finishhelper (the two "Illegal value" armsbreakout of the switch straight to the trailingif(acmd)echo block → ported as an earlyreturn set_finish(...), acmd unchanged so the echo still fires);poolsize > tmpkeeps the C signed→unsigned promotion (tmp as c_uint);poolsize/tmppassed to%dwidth‑matched (as c_int). Classification: handler cluster (dispatch col 2/STAT_OPER — a non‑oper client hits the col‑1m_nopriv/481 at the parse table; the body re‑gates onis_allowed(ACL_SET)), no L1 (pure wire handler terminating insendto_one/sendto_flag, no socket‑free data op), no S2S (noIsServer(cptr)dispatch branch, no remote‑user fields — reads/writes local tunables only). L2golden_s_serv_set(newset_oper.confO‑line flage= ACL_SET → no‑arg SET showall POOLSIZE/ACONNECT/CACCEPT echoes,SET ACONNECT OFFapply+echo,SET BOGUS→ "Invalid option BOGUS" with no trailing echo [acmd stays 0, the inverse of a hit]; theoper.confno‑flags inverse → handler‑internal is_allowed reject → 481). - P5uu DONE:
s_serv.cm_wallopshandler (the WALLOPS broadcast — relay an operwall to every other server [origin link excluded] + emit the!from!framing to local&WALLOPSwatchers viasendto_flag(SCH_WALLOP)) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Thirteenths_serv.csub‑phase — a leaf server‑only handler (msgtabWALLOPS=[m_wallops, m_nop, m_nop, m_nop, m_unreg]→ col 0/STAT_SERVER only; a local client/oper hitsm_nop) with no file‑static of its own → a plain#ifndefguard; itsmsgtabdecl resolves to the Rust def at link. The whole body issendto_ops_butone(IsServer(cptr)?cptr:NULL, parv[0], "%s", parv[1])(the C variadic imported from bindings, P8); USE_SERVICES off → thecheck_services_butoneblock not compiled (sptr/parc unused). Classification: handler cluster, server‑reachable → L2‑S2S the only gate (no L1 — pure wire handler terminating in the variadic; no plain L2 — a local client can't present a STAT_SERVER prefix). L2‑S2Sgolden_s2s_wallops(a peer:001B WALLOPS→ a local&WALLOPSmember receives:irc.test NOTICE &WALLOPS :!peer.test! …; inverse 1 a non‑member gets nothing [PING‑fenced]; inverse 2 the originating peer does not get its own WALLOPS echoed back [PRIVMSG‑to‑remote fenced] — proving theIsServer(cptr)?cptr:NULLorigin‑link exclusion). - P5vv DONE:
s_serv.cm_errorhandler (the server‑protocol ERROR message — pass an error received over a server link on to local&ERRORSwatchers viasendto_flag(SCH_ERROR)) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Fourteenths_serv.csub‑phase — a leaf server‑only handler (msgtabERROR=[m_error, m_nop, m_nop, m_nop, m_unreg]→ col 0/STAT_SERVER only; a registered client hitsm_nop, an unregistered connectionm_unreg) with no file‑static of its own → a plain#ifndefguard; itsmsgtabdecl resolves to the Rust def at link. Faithful:para = (parc>1 && *parv[1]) ? parv[1] : "<>"; the reachable server branch emits:irc.test NOTICE &ERRORS :from %s -- %s(cptr==sptr,get_client_name(cptr,FALSE)) /from %s via %s -- %s(the "via" form) via the C variadicsendto_flag(P8); returns 2 (not FLUSH_BUFFER → link survives). DEBUGMODE off → theDebug()line not compiled; theIsPerson||IsUnknown||IsService → return 2ignore guard ported for faithfulness but unreachable via the col‑0‑only dispatch. New privateis_servicehelper. Classification: handler cluster, server‑reachable → L2‑S2S the only gate (no L1 — pure wire handler terminating in the variadic; no plain L2 — a local client can't present a STAT_SERVER prefix). L2‑S2Sgolden_s2s_error(a peer:001B ERROR :the disk is full→ a local oper&ERRORSmember receives:irc.test NOTICE &ERRORS :from peer.test -- the disk is full; inverse a non‑member gets nothing [PING‑fenced]). The boot‑created&ERRORSchannel is +i (can_joinadmits only opers, channel.c:2091) → news2s_oper.conffixture (s2s.conf + an O‑line) and alice OPERs before subscribing; thecptr != sptr"via" form (needs a server introduced behind the peer) review‑covered. - P5ww DONE:
s_serv.cserver network‑registration cluster (register_server+unregister_server— head‑insert / unlink a server'saServeron the globalsvrtopdoubly‑linked list, called whenever a server (re)associates or loses its client struct) via the sames_serv_link.opartial port (‑DPORT_SERV_P5). Fifteenths_serv.csub‑phase — the first pure utility/callee s_serv.c cluster since P5qq (nomsgtabrow, no socket, no wire); twoEXTERNintrusive‑list ops under one plain#ifndefguard (no extern‑prototype switch — every caller stays C and resolves to the Rust def: bootircd.c, link estabm_server/m_server_estab,exit_one_client). Faithful raw‑pointer rewiring (head‑insert viasvrtop->prevs/cptr->serv->nexts; splice‑out relink +svrtopadvance, then clearprevs/nexts/bcptr). Classification: utility/callee → L1 the gate, no new L2/S2S (noIsServer(cptr)branch — unconditional callee of the still‑C link handler / exit cascade). L1s_serv_register_diff(register A/B/C head‑insert →[C,B,A]+ fullnexts/prevscross‑links; inverses unregister middle/head/sole node → relink +nexts/prevs/bcptrcleared,svrtopadvance/empty; re‑register → clean[C,A]round‑trip — zero‑diff vscref_). Regression:golden_s2s_link(register_server) /golden_s2s_squit(unregister_server) stay byte‑identical. - P5xx DONE:
s_serv.coperator CONNECT cluster (m_connect— the oper command to force a server link) via the sames_serv_link.opartial port (-DPORT_SERV_P5). Sixteenths_serv.csub-phase. Amsgtabhandler rowCONNECT { m_nop, m_nopriv, m_connect, m_nop, m_unreg }— col 2 (STAT_OPER) only: a plain client hitsm_nopriv(481) at the parse table. Self-contained handler (no file-statics shared with other clusters; only a local port var), so dropped via a fresh#ifndef PORT_SERV_P5guard with no extern-prototype switch (every caller already resolves to the Rust def at link). Faithful port:is_allowed(sptr, parc>3 ? ACL_CONNECTREMOTE : ACL_CONNECTLOCAL)gate →m_nopriv;BOOT_STANDALONEshort-circuit;hunt_serverHUNTED_ISME routing;find_name/find_mask"already exists"; the two-passconfwalk (server names, thenuser@hosthostnames viaindex(host,'@')+1— replicated withstrchr(...).wrapping_add(1)to mirror C's NULL+1 when there is no@); port resolution (atoi/abs); the!IsAnOper(cptr)"Remote CONNECT … from …" ops notice; and theconnect_serverretval switch (0/-1/-2/default withstrerror).USE_SYSLOG/SYSLOG_CONNECToff → the syslog line not compiled. New libc externsabs/strerror; the localme_name()binding renamedmyname(can't shadow the staticme). Classification: handler cluster with a server-reachable path → L1 N/A (needs a live server/socket; no pure data op), L2 + L2-S2S the gates. L2golden_s_serv_connect(local opered client): newconnect_oper.conffixture (O-line flagsC= ACL_CONNECT) →CONNECT nosuch.invalid→NOTICE alice :Connect: Host nosuch.invalid not listed in ircd.conf(noconnect_servercall); inverse via plainoper.conf(no flags) → handler-internalis_allowedreject → 481 — both byte-identical vs reference-C. L2-S2Sgolden_s2s_s_serv_connect(boot_s2s+Peer): a remote oper (+o→ STAT_OPER) behind the peer issues a remote-formCONNECT nosuch.invalid 0 irc.test→ reachesm_connectover the server link (IsServer(cptr)true) → the "not listed" reply routes back out the peer; inverse a plain remote client (col 1 →m_noprivat parse) produces no such notice — both byte-identical. The!IsAnOper(cptr)ops notice +connect_servertail run only once a real C-line matches (a live outbound socket) → no deterministic golden form; faithful C-call passthroughs covered by review. Regression:golden_s2s_link/golden_s2s_squit/golden_s_serv_maintstay byte-identical; workspace builds 0 warnings. - P5yy DONE:
s_serv.cm_squithandler (the SQUIT command — remove a server from the network) via thes_serv_link.opartial port (-DPORT_SERV_P5). A self-contained cluster: its only module-local state is the function-localstatic char comment2[TOPICLEN+1](private scratch → a module-privatestatic mut COMMENT2, not ABI); it touches none of the server-introduction file-statics (introduce_server/send_server/get_version), so it ports cleanly without dragging in the big server cluster. Every callee is already Rust (is_allowedP5o,exit_clientP5c,find_sid/find_server/next_clientP2,m_noprivP4,replies[]P3) or a C extern (get_client_name/my_name_for_link/mycmp, the variadicsendto_one/sendto_ops_butone/sendto_flagtrampolines). Config-resolved: the#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)line is out (USE_SYSLOG#undef); a local oper reachesm_squit(col 2) only becauseOPER_SQUIT+OPER_SQUIT_REMOTEare defined and the O-line carries flag letterS(→ ACL_SQUIT). L2golden_s_serv_squit(local oper:SQUIT irc.test→ "you cannot SQUIT me" notice +SQUIT nosuch.invalid→ 402; inverse no-flag oper → handler-internal 481, no 402) + S2Sgolden_s2s_s_serv_squit(remote oper'sSQUIT nosuch.invalid→ 402 routed back out the peer link; inverse plain remote client → no 402, proving col-2 prefix-is-oper gating). Theexit_clientlink-teardown tail stays faithful passthrough, covered by the existinggolden_s2s_squitpeer-EOF netsplit net. - P5zz DONE:
s_serv.coper-shutdown cluster (m_die+m_restart) — the leaf oper shutdown/restart pair (analogue of P5rr's m_close/m_rehash) via thes_serv_link.opartial port (-DPORT_SERV_P5); plain#ifndefguards, no extern-switch.m_dieuses a localkiller[];m_restart's file-staticbufwas in-call scratch → a module-privateRESTARTBUF(the still-Ccheck_version/m_server_estabkeep the Cbuf). Both re-gateis_allowed(ACL_DIE/ACL_RESTART)→m_nopriv/481. L2 gate = the non-destructive reject (golden_s_serv_shutdown: flag-less oper DIE/RESTART → 481 byte-identical); the notice-loop + terminals_die(0)/restart(buf)are destructive → review-covered; no S2S (noIsServer(cptr)branch, no remote-user fields). - P5aaa DONE:
s_serv.cENCAP/SDIE server-broadcast stub cluster (m_encap+m_sdie) via thes_serv_link.opartial port (-DPORT_SERV_P5) — two server-only leaf handlers (msgtab col 0) that rebuild +sendto_serv_v(cptr, SV_UID, …)-propagate a line to every other server (origin link excluded); plain#ifndefguards, no file-static. No L1 (pure wire/broadcast, no socket-free data op), L2-S2S the only gate (golden_s2s_encap: a peer's:001B ENCAP …/:001B SDIEis NOT echoed back to its origin link + the link survives a follow-up routed PRIVMSG fence — byte-identical ref-C vs Rust). The forward-to-an-additional-server arm needs a 2nd direct peer link the harness lacks → review-covered. - P5bbb DONE:
s_serv.cserver‑introduction / link‑establishment / burst cluster (m_server+m_server_estab+m_smask+check_version/get_version+send_server/introduce_server/send_server_burst+ thecheck_servername_errors[3][2]table) — the finals_serv.csub‑phase, sos_serv.ois now dropped outright (added toPORTED; the P5ii…P5aaas_serv_link.osecond‑compile +‑DPORT_SERV_P5removed; the cref oracle keeps the unguardeds_serv.o).s_serv.cis now FULLY ported to Rust. Config‑resolved (all OFF): USE_SERVICES (nocheck_services_butone), ZIP_LINKS (nozip_init/FLAGS_ZIP arms —encr = cptr->passwd), JAPANESE, CRYPT_LINK_PASSWORD, HUB (the#ifndef HUBleaf‑check IS compiled), USE_SYSLOG.check_servername_errors(kept C through P5qq to avoid a BSS‑symbol collision) is now a#[no_mangle] pub static mut(raw‑pointer table → thereplies[]‑in‑s_err.rs pattern) since the C def is gone andircd.c:1056reads it. Classification: handler cluster, server‑reachable. L1 (s_serv_version_diff):check_version(transitivelyget_version) vscref_on parallelmake_client'd clients with empty conf — the0210‑beta991199/991200boundary, the021xfast‑path, else→SV_OLD, the in‑placeinfosplit, theZ→FLAGS_ZIPRQflag (with aPflag so the faithfulBOOT_STRICTPROT"Unsafe mode" exit isn't taken —bootoptdefaults toBOOT_PROT|BOOT_STRICTPROT, ircd.c:47), and theDefInfoearly‑return — the only gate on the version branches the fixed‑PEER_VERSIONS2S harness can't reach. L2‑S2S: the entire existing 37‑testgolden_s2s_*suite is the regression gate — every test'sPeer::link()PASS/SERVER handshake drivesm_server(local)→check_version→m_server_estab→send_server_burst→EOB, andgolden_s2s_rejectdrivesm_server's reject path; all byte‑identical (the lonegolden_s2s_s_serv_statsred is the documented pre‑existing reference‑C uninitialized‑sendq flake, not a regression). Newgolden_s2s_servercovers the gap —m_server'sIsServer(cptr)remote‑server‑introduction branch (a peer:001B SERVER sub.test 1 002C …→ remoteaServercreation +introduce_server, observed viaLINKS). The server‑removal inverse +m_smask+ multi‑serversend_server/introduce_serverare review/golden_s2s_squit‑covered (the single‑peer harness can't host a fully‑formed sub‑server — SQUITting one segfaults even reference‑C). - P5ccc DONE:
s_user.chunt_server/next_clientcluster (final s_user.c) — the two network-routing callees (resolve a command's target-server arg → forward/handle-locally/402; find the next list client matching a wild mask) ported →s_user.odropped outright (removeds_user_link.osecond-compile +-DPORT_USER_P5;s_user.cnow fully Rust, onlys_auth.cleft in C among P5 TUs). L1s_user_hunt_diff(next_client exact/wildcard/continuation/inverse-NULL walk on parallel client lists+hash; hunt_server ISME/PASS/NOSUCH verdicts + parv[server] rewrite + forwarded-line/error sendQ bytes vscref_) + S2Sgolden_s2s_hunt(VERSION → ISME 351 local / PASS:src VERSION :peer.testat peer / next_clientpeer.*wildcard forward / NOSUCH 402; the wholegolden_s2s_*suite is the de-facto regression gate since it routes via hunt_server). - P5whowas DONE:
whowas.cm_whowashandler (P2‑deferred → now ported, whowas.o dropped) — the WHOWAS command handler (the last C remnant kept behindwhowas_link.o/-DPORT_WHOWAS_P2since the P2 ring port) is ported intoircd-common/whowas.rsalongside the ring machinery →whowas.oadded to PORTED and dropped outright (the P2cwhowas_link.osecond‑compile removed; the cref oracle keeps the full unguardedwhowas.ofor the L1whowas_diff). Every callee already resolves:canonize(P5m),hunt_server(P5ccc),strtoken/mycmp/myctime(P1),replies[](P3),was/ww_index/ww_size(P2, Rust‑owned), the C variadicsendto_one+ libcatoi. Faithful: the do‑while ring walk from(ww_index?ww_index:ww_size)-1, the per‑tokenupreset, thej>=maxearly break, the!MyConnect(sptr)cap of 20, the NICKLEN truncation on the not‑found path. Classification: handler cluster, server‑reachable (formatsup->serverremote‑user field +hunt_serverforward) → no L1 (pure wire handler; the ring is already L1'd bywhowas_diff), L2 + L2‑S2S the gates. L2golden_whowas(alice QUIT → bob WHOWAS alice → 314/312/369 found path +max 1early break + unknown‑nick 406 inverse; 312 ctime masked locally) + S2Sgolden_s2s_whowas(remote rmuser QUIT → local WHOWAS renders 312 withpeer.test;WHOWAS ghost 1 peer.test→hunt_serverforwards peer‑side).golden_s_user_canonize(the 406/369 dedup path) now drives the Rustm_whowasas a regression. - P5hash DONE:
hash.cm_hash(HAZH) handler — ports the last C remnant of hash.c (P2 leftm_hashinhash_link.o) intoircd-common/hash.rs→hash.odropped outright (added toPORTED; the P2dhash_link.osecond-compile deleted). A handler cluster reachable only from a local oper (msgtabHAZHcol 2 =STAT_OPER, re-gated onis_allowed(ACL_HAZH)); DEBUGMODE off →show/list/show_hash_bucketnot compiled. Faithful%fstat lines via(expr as f32) as f64(C(float)(double)+ varargs promotion). L2golden_s_hash(operHAZH/HAZH cusage+statistics; non-operHAZH c→ 481 m_nopriv, the dispatch-column inverse) byte-identical. No S2S (noIsServerbranch / remote-user fields).