26:- **2026‑06‑02 — P5d (s_user.c WHO/WHOIS cluster) merged.** The contiguous WHO/WHOIS display cluster (s_user.c:1685‑2315 — `who_one`/`who_channel`/`who_find` [statics], `parse_who_arg` [file‑global], `send_whois` [static], `m_who`/`m_whois` [exported, msgtab]) ported to `ircd-common/src/s_user.rs`. **First in‑TU partial port of P5:** `s_user.o`→`s_user_link.o` (`‑DPORT_USER_P5` `#ifndef`‑guards the cluster out of the link set; the cref oracle keeps the full unguarded `s_user.o`). The rest of s_user.c (register_user/m_nick/m_kill/m_umode/m_oper/m_message/… + the shared statics `buf`/`buf2`/`user_modes`) stays C. `s_user_link.o` built via `make --eval` so the per‑object `FNAME_USERLOG/CONNLOG/OPERLOG` path defines (used by the surviving C register_user/m_oper) expand identically (the send_link.o pattern).
39:  - **Keystone finding — a lone server is *permanently* split‑mode, which blocks `#`‑channel creation.** The fixture M‑line's split thresholds are **floored to SPLIT_SERVERS(10)/SPLIT_USERS(5000)** (s_conf.c:1950), so `check_split()` never leaves split (needs 10 eob‑servers + 5000 users). During split, channel.c:2537 (`IsSplit() && UseModes(name) && !(&||!)`) rejects creating global `#` channels with ERR_UNAVAILRESOURCE — but allows `+` (not `UseModes`) and `&` (excluded). So `#` golden tests must boot **`-p standalone`** (`iconf.split = -1` → `IsSplit()` false), which lets all three prefixes be created uniformly. (This is exactly why `+`/`&` passed but `#` failed on the first run.)
49:- **2026‑06‑02 — P5h (s_user.c UMODE cluster) merged.** `m_umode` (s_user.c:3164), `send_umode` (:3358), `send_umode_out` (:3409) + the `user_modes[]` table (:38) ported into `ircd-common/src/s_user.rs`, extending the existing `s_user_link.o` partial port (one new `#ifndef PORT_USER_P5` region spans the three fns; the `user_modes[]` static is guarded separately since only this cluster uses it). **Handler cluster** (`UMODE`→`m_umode` is a msgtab row; `MODE <nick>` routes through still‑C `m_mode` (channel.c) → Rust `m_umode` once the target isn't a channel) — L2 golden is the gate. RED confirmed via undefined `m_umode`/`send_umode`/`send_umode_out`; no parse.rs edit. Plan: `docs/superpowers/plans/2026-06-02-p5h-s_user-umode.md`.
50:  - **`send_umode` is called from three still‑C TUs** (`register_user` in s_user.c, `s_service.c`, `s_serv.c` — all via `send_umode(NULL, …, buf)`); porting it means **those C callers now resolve to the Rust def at link**, so byte‑faithfulness is load‑bearing beyond just `m_umode`. This is why `send_umode` gets its own L1 differential (`s_user_umode_diff`): the +/- mode‑diff string builder with `cptr=NULL` is socket‑free, so it's L1‑testable directly (10 cases over old/current‑flags/sendmask/MyClient combos — pure/grouped/mixed add‑del/`SEND_UMODES` vs `ALL_UMODES` filtering).
54:  - **Verification:** L1 `s_user_umode_diff` zero‑diff vs `cref_send_umode` (10 cases). L2 `golden_s_user_umode` 2/2 byte‑identical: **MODE alice +i ; MODE alice** (echo `:alice MODE alice :+i` via the ALL_UMODES local echo + `221 alice +i`), **MODE alice +iw-i ; MODE alice** (parse nets to +w / ‑i → echo `:alice MODE alice :+w` + `221 alice +w`, exercising the +/- grouping). `m_umode`/`send_umode`/`send_umode_out` defined `T` from ircd‑common in the Rust `ircd`; full `cargo test` green (all `*_diff` L1 + layout + all 9 golden suites); 0 warnings. No new canonicalizer masks. **Deferred to S2S L2:** the `send_umode_out` server‑broadcast loop (`fdas`/`local[]` → `:uid MODE name :modes`) and the oper/restricted (`det_confs_butmask`, ERR_RESTRICTED) paths — need a server link / oper; ported faithfully, covered by review + the L1 differential.
65:  - **Verification:** L2 `golden_s_user_oper` 1/1 byte‑identical over three OPER attempts on one registered client: **`OPER nope wrong`** → `491 ERR_NOOPERHOST` (find_Oline miss), **`OPER alice wrong`** → `464 ERR_PASSWDMISMATCH` (StrEq fails → detach path), **`OPER alice secret`** → success: `:alice MODE alice :+o` (send_umode_out ALL_UMODES local echo) + `381 RPL_YOUREOPER`. `m_oper` defined `T` from ircd‑common in the Rust `ircd`; full `cargo test` green (67 passed, 0 failed: all `*_diff` L1 + layout + all 11 golden suites); 0 warnings. No new canonicalizer masks (no time tokens). **Deferred to S2S L2:** the `send_umode_out` server‑broadcast loop, the LocOp (`o`) path, and the SCH_NOTICE to server‑notice subscribers — need a server link / a subscribed oper; ported faithfully, covered by review.
77:- **2026‑06‑03 — P5m (s_user.c canonize utility) merged.** `canonize` (s_user.c:283 — the O(n²) comma‑list deduplicator) ported into `ircd-common/src/s_user.rs`, extending the existing `s_user_link.o` partial port (one new `#ifndef PORT_USER_P5` guard region around s_user.c:277‑319; the cref oracle keeps the full unguarded `s_user.o`). **Utility / callee fragment** (no `msgtab` row) — it is called *from* `m_mode`/`m_part`/`m_topic` (channel.c), `m_whowas` (whowas.c), and the already‑Rust WHO cluster (s_user.rs:521/797/960). RED confirmed via the three Rust call sites failing to find `canonize` once it was removed from the `bindings` import; **defining it locally resolves those Rust callers + all the still‑C callers to the Rust def at link** (the `send_away`/`send_umode` pattern from P5g/P5h). Plan: `docs/superpowers/plans/2026-06-03-p5m-s_user-canonize.md`.
80:  - **`format!` per user request — N/A, documented in‑module.** `canonize` copies arbitrary client‑supplied token bytes (channel names / nicks) verbatim via `strcpy` and mutates the buffers in place — there is nothing to format, and a UTF‑8 `String`/`format!` could neither reproduce `strcpy` of non‑ASCII bytes nor the in‑place `strtoken`/comma‑restore surgery. `format!` stays reserved for the ASCII/numeric reply cases (cf. `m_umode` query reply, `who_one` numeric fields).
119:- **2026‑06‑03 — P5t (channel.c leaf‑predicate foundation cluster) merged.** `is_chan_op` (channel.c:577), `has_voice` (:593), `find_channel` (:716), `clean_channelname` (:2062) ported to `ircd-common/src/channel.rs`. **First channel.c sub‑phase — establishes the `channel_link.o` partial‑port mechanism** (`‑DPORT_CHANNEL_P5` `#ifndef`‑guards the four C defs out of the link set; the cref oracle keeps the full unguarded `channel.o`). These are the only **truly‑leaf** channel.c exports (no file‑static, no shared `buf`/`modebuf`/`parabuf`/`uparabuf` use). Plan: `docs/superpowers/plans/2026-06-03-p5t-channel-leaf-predicates.md`.
121:  - **Classification & seam:** `is_chan_op`/`has_voice` are callee predicates, `find_channel`/`clean_channelname` callee utilities (none a msgtab row). All four are already imported by still‑C channel.c callers *and* the already‑Rust `s_user.rs` (`clean_channelname`/`find_channel`) + `s_misc.rs` (`is_chan_op`); defining them `#[no_mangle]` resolves every caller (C and Rust) to the Rust def at link (the `canonize`/`send_away` pattern). No parse.rs edit. `find_user_link`/`hash_find_channel` are the P2 Rust ports; `my_connect`/`is_person`/`is_restricted` inline helpers mirror s_user.rs. **`can_send` deferred** to the mode‑manipulation cluster (it calls the file‑static `match_modeid`). **JAPANESE off** → `clean_channelname`'s comma‑`flag` block isn't compiled (`flag` always 0); `jp_*`/`get_channelmask` absent.
123:  - **Verification:** L1 `channel_leaf_diff` zero‑diff vs `cref_` (4 tests: is_chan_op over op/uniqop/voiced/non‑member/restricted‑on‑`#`‑vs‑`&`/remote + null‑chan; has_voice; find_channel empty‑name→arg + hash‑miss→NULL after `inithashtables`; clean_channelname over 10 strings comparing return + mutated bytes). L2 `golden_channel` 1/1 byte‑identical (registered alice `JOIN #chan` under `‑p standalone` → JOIN echo + `353` with `@alice` [is_chan_op marks the creator chanop] + `366`). Full `cargo test` green (0 failed); `cargo build` 0 warnings. No new canonicalizer masks. **Deferred:** `has_voice` has no JOIN/NAMES path under `‑s` (L1‑only); the rest of channel.c (mode/join/display clusters, 5 components over the shared mode buffers) stays C in `channel_link.o`.
124:- **2026‑06‑03 — P5 S2S golden coverage (the deferred server‑path harness) merged.** Every P5 cluster above deferred its `IsServer(cptr)`/server‑reachable paths to "an S2S scenario" because the standalone (`‑s`) client harness can never present a linked peer. This adds that peer. New `ircd-golden` primitives (committed first, then a 12‑agent `ultracode` workflow authored one test per cluster, each probing both binaries before writing): `boot_s2s` + a `Peer` fake‑server that completes the IRCnet 2.11 server handshake (`PASS linkpass 0211030000 IRC|aHmM` / `SERVER peer.test 1 001B …` → drains the burst through `EOB`) and then speaks the SID/UID‑prefixed server protocol; the `s2s.conf` fixture (M/A/P/Y/I **+ C/N/H lines** authorizing an inbound link from `127.0.0.1`, name `peer.test`, pass `linkpass`). **13 `golden_s2s_*` scenarios, all byte‑identical ref‑C == Rust after `canonicalize()`** (full golden suite 51/51, 0 warnings).
139:  - **Verification:** full `cargo test -p ircd-golden` = 51 passed / 0 failed (the 13 S2S scenarios + all prior golden + L1/layout suites); `cargo build` 0 warnings. The S2S harness lives entirely in `ircd-golden/src/lib.rs` (`Peer`, `boot_s2s`) + `ircd-golden/fixtures/s2s.conf` — no change to any ported `ircd-common` source (these tests *characterize* the already‑merged ports, they don't re‑port). **Still S2S‑deferred (no test yet):** multi‑hop server‑burst diffing through a TS‑aware peer, channel NJOIN/MODE burst (channel.c still mostly C), and `m_ping`/`m_pong` server‑col paths (P5i) — left for the channel mode‑cluster + a future burst harness.
141:  - **Cluster = a closed connected component over static‑function call edges.** Coupling in channel.c is *only* via static functions called across the C/Rust boundary (static *variables* like `buf`/`modebuf` used transiently can be duplicated — established P5 practice). Verified edges: `list_length`→only `add_invite`; `add_invite`→only `m_invite`; `del_invite` non‑static (no linkage issue); `check_channelmask`→**10 C callers** (m_join/m_part/m_kick/m_topic/m_njoin/set_mode/send_channel_modes/send_channel_members + m_invite; the JAPANESE site is `#if 0`). So the cluster is `{m_invite, add_invite, list_length, del_invite, check_channelmask}` — every static is called only by cluster members **except** `check_channelmask`, handled by the extern‑prototype switch below.
147:  - **Verification:** L1 `channel_invite_diff` 2/2 zero‑diff vs `cref_del_invite`. L2 `golden_channel_invite` 4/4 byte‑identical: **success** (alice chanop of #chan `INVITE bob #chan` → `341 RPL_INVITING` to alice + `:alice!~alice@127.0.0.1 INVITE bob :#chan` to bob — the only path that fires the private `add_invite`/`list_length` live), **`401`** (INVITE ghost → find_person miss), **`442`** (alice not a member of bob's #other), **`476`** (`check_channelmask` reject on `#chan:nomatch.zzz` + the MyClient ERR_BADCHANMASK send). `m_invite`/`del_invite`/`check_channelmask` defined `T` from ircd‑common in the Rust `ircd`; full `cargo test` green; `cargo build` 0 warnings. No new canonicalizer masks (no time tokens). **Deferred to S2S L2:** the `!chptr` remote‑INVITE forward (`sendto_prefix_one` to a remote acptr), the `&`‑channel + `!MyClient(acptr)` reject, and `check_channelmask`'s server/`chan:mask` propagation branches (need a server link; ported faithfully, covered by review). **Remaining channel.c (C):** the mode (`m_mode`/`set_mode`/`match_modeid`/…), join (`m_join`/`m_njoin`/`can_join`/`get_channel`/`add_user_to_channel`), part/kick/topic, and display (`m_names`/`m_list`/`names_channel`/`find_chasing`) clusters stay in `channel_link.o`.
148:- **2026‑06‑03 — P5v (channel.c can_send + match_modeid cluster) merged.** `can_send` (channel.c:615 — the channel send‑permission predicate, +m/+n/+b/+e) and `match_modeid` (channel.c:314 — the ban/exception `mlist` matcher) ported to `ircd-common/src/channel.rs`, extending the existing `channel_link.o` partial port (three new `#ifndef PORT_CHANNEL_P5` regions: the `match_modeid` forward proto switch at :75, the `match_modeid` body, the `can_send` body; the cref oracle keeps the full unguarded `channel.o`). **Third channel.c sub‑phase.** Completes the P5t deferral ("`can_send` deferred to the mode cluster — it calls the static `match_modeid`"). Plan: `docs/superpowers/plans/2026-06-03-p5v-channel-can_send.md`.
149:  - **Cluster = a closed connected component over static call edges.** `can_send` (exported, channel_ext.h) calls only `IsMember`/`find_user_link`/`match_modeid`; `match_modeid` (static) calls only `match`/`match_ipmask`/macros — no other channel.c static. `match_modeid`'s *other* callers (`can_join`, `reop_channel`) stay C → handled by the **P5u extern‑prototype switch** (the forward `static`→`extern` at channel.c:75 under the guard, so the C remnant resolves to the Rust `#[no_mangle]` def at link; linkage‑only, faithful). `can_send` is already imported by the Rust `m_message` (P5f, s_user.rs:1155) + the WHO path (s_user.rs:3439) from `ircd_sys::bindings` → those bindgen decls resolve to the Rust def once the C def drops (the `is_chan_op`/`has_voice` P5t seam — **no s_user.rs edit needed**, unlike the plan's tentative Step 6 which would have diverged from established practice). No parse.rs edit (neither is a `msgtab` row).
152:  - **Config (verified `cbuild/config.h`):** `JAPANESE` **off** → `can_send` has no JP branch. `MODE_MODERATED`=32/`MODE_NOPRIVMSGS`=256/`MODE_BAN`=1024/`CHFL_BAN`=8/`CHFL_EXCEPTION`=16 (bindgen consts); `(*chptr).mode.mode` is `u_int`; `aConfItem.flags` is `c_long` (cast `CFLAG_NORESOLVEMATCH as c_long`). New helpers `is_an_oper`/`is_conf_no_res_match` mirror s_user.rs; `match_ipmask`/`find_channel_link`/`aConfItem`/`Link` + the mode/flag consts added to the bindings import; `strchr` added to the local extern block.
155:  - **Verification:** L1 `channel_can_send_diff` zero‑diff vs `cref_can_send` over 8 cases (+m non‑voiced/voiced/chanop member + non‑member, +n member/non‑member, plain‑member empty‑mlist ban path, remote `!MyConnect` bypass). L2 `golden_channel_can_send` 2/2 byte‑identical: **+m moderated** (alice chanop sets +m, bob joins as a plain member → bob PRIVMSG → `404 ERR_CANNOTSENDTOCHAN` via the Rust `m_message`→Rust `can_send` MODE_MODERATED branch) and **+n no‑external** (bob non‑member → MODE_NOPRIVMSGS branch); read‑barriers (`366`/`MODE` echoes) serialize the cross‑connection ordering so +m/+n is in effect before bob sends. `can_send`/`match_modeid` defined `T` from ircd‑common in the Rust `ircd`; full `cargo test` green (0 failed); `cargo build` 0 warnings. No new canonicalizer masks (no time tokens). **Deferred to S2S L2 / review:** `match_modeid`'s populated‑`mlist` `+b`/`+e` match (incl. the UID‑ban and CIDR `match_ipmask` paths) and the remote‑client `can_send` bypass under a server link (ported faithfully). **Remaining channel.c (C):** the mode (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`change_chan_flag`/`make_bei`/`free_bei`/`channel_modes`/`send_channel_*`), join (`m_join`/`m_njoin`/`can_join`/`get_channel`/`add_user_to_channel`/`reop_channel`/`free_channel`), part/kick/topic, and display (`m_names`/`m_list`/`names_channel`/`find_chasing`/`check_string`) clusters stay in `channel_link.o`.
156:- **2026‑06‑03 — P5w (channel.c channel_modes leaf) merged.** `channel_modes` (channel.c:831 — the "simple" channel mode‑string serializer: writes the `+`‑flags into the caller's `mbuf` and the `+l`/`+k` parameters into `pbuf`) ported to `ircd-common/src/channel.rs`, extending the existing `channel_link.o` partial port (one new `#ifndef PORT_CHANNEL_P5` region around the body; the cref oracle keeps the full unguarded `channel.o`). **Fourth channel.c sub‑phase.** Plan: `docs/superpowers/plans/2026-06-03-p5w-channel-channel_modes.md`.
157:  - **Classification: exported true‑leaf callee (no `msgtab` row).** `channel_modes` touches **no file‑static** — it writes into the caller‑provided `mbuf`/`pbuf` — and calls only the `IsMember`/`IsServer` macros + libc `sprintf`/`strcat`. So a plain `#ifndef` guard drops the exported def and the still‑C callers resolve to the Rust def at link: the **`m_mode` query path** (channel.c:1112, `MODE #chan` with `parc < 3` → `channel_modes` then `replies[RPL_CHANNELMODEIS]`), **`set_mode`** (mode‑change echo), and **`send_channel_modes`** (the S2S burst — the symbol that referenced `channel_modes` at link, confirming RED). The `#ifdef USE_SERVICES` m_join call (channel.c:1987) is not compiled. No parse.rs / build.rs edit.
158:  - **Config findings (verified):** the body (831‑866) has **no `#ifdef`** inside it — the full bit cascade compiles verbatim. `nm cbuild/channel.o` shows `T channel_modes` (exported). `JAPANESE`/`USE_SERVICES` off — neither affects this fn. `SMode { mode: u_int, limit: c_int, key: [c_char;24] }`; mode consts present in bindings (`MODE_SECRET`=16/`MODE_PRIVATE`=8/`MODE_MODERATED`=32/`MODE_TOPICLIMIT`=64/`MODE_INVITEONLY`=128/`MODE_NOPRIVMSGS`=256/`MODE_ANONYMOUS`=4096/`MODE_QUIET`=8192/`MODE_REOP`=65536) — added the six missing ones + `strcat`/variadic `sprintf` externs to channel.rs.
160:  - **Verification:** L1 `channel_modes_diff` zero‑diff vs `cref_channel_modes` over 17 cases (empty `+`, every single bit, secret‑wins‑over‑private precedence, `+ntl`/`+nk`/`+tlk` params for a server cptr, the same `+tlk` for a **non‑member** [params suppressed → empty `pbuf`], and the all‑bits+l+k full house) — both the `mbuf` and `pbuf` byte buffers asserted identical. L2 `golden_channel_modes` 1/1 byte‑identical: alice (chanop → member) sets `+tnl 5` then `+k secret`, then the `MODE #chan` query → `324 RPL_CHANNELMODEIS` carrying the mode string + the `+l 5` (`sprintf`) and `+k secret` (`strcat`) params. `channel_modes` defined `T` from ircd‑common in the Rust `ircd`; `cargo build` 0 warnings; no new canonicalizer masks (no time tokens). **Remaining channel.c (C):** the rest of the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`change_chan_flag`/`make_bei`/`free_bei`/`send_channel_*`), join, part/kick/topic, and display clusters stay in `channel_link.o`.
163:  - **Cluster shape & the linkage moves.** The three touch **no** shared `buf`/`modebuf`/`parabuf`/`uparabuf` static (unlike the mode/display clusters) — their only remaining‑C edge is the static `free_channel`, which `remove_user_from_channel` calls when the last user leaves. Two `static`s (`add_user_to_channel`, `change_chan_flag`) have **no forward decl** in C (defined before their callers), so guarding their bodies out would leave the C remnant (`setup_server_channels`/`m_join`/`m_njoin`; `set_mode`/`reop_channel`) calling an undeclared symbol → added `extern` forward decls under the guard. `free_channel` is **kept C** but switched `static`→`extern` under `#ifdef PORT_CHANNEL_P5` (forward decl :71 + definition storage class) — a **new variant** of the P5u mechanism (P5u/P5v switched a C static so the *Rust* def wins; here the body stays C and only its linkage opens so the *Rust* caller can reach it). `remove_user_from_channel` is exported and already called from the Rust `s_misc.rs` exit cascade (P5c, extern decl s_misc.rs:65) → resolves to the Rust def once the C def drops. No parse.rs / build.rs edit.
165:  - **Faithfulness notes:** `add_user_to_channel` — `chptr->users++ == 0` is the unconditional post‑increment (`was_zero` capture then `+= 1`); the locked‑channel history reset `bzero(&chptr->mode, sizeof(Mode))` → `ptr::write_bytes(addr_of_mut!((*chptr).mode) as *mut u8, 0, size_of::<Mode>())` gated on `*chname != '!'`; the per‑uplink `clist` link found/created on `who->from` then `flags++`. `remove_user_from_channel` — a leaving `CHFL_CHANOP` arms `chptr->reop = timeofday + LDELAYCHASETIMELIMIT + myrand()%300` (the L1 fixture uses non‑chanop members so this non‑deterministic `myrand()` path is **not** exercised — it would diverge Rust's live `myrand` from the oracle's `cref_myrand`); `if (tmp2 && !--tmp2->flags)` predecrement drops the clist link at 0; `--chptr->users <= 0` → the `is_chan`/`is_chanmem`/`is_hchan`/`is_hchanmem` swap + `free_channel`. `change_chan_flag` — mirrors the flag into both the member link and the client link, `~lp->flags & MODE_FLAGS` = `(!lpflags) & MODE_FLAGS` (unary‑not binds tighter, same as C). **`format!` per user request — N/A, documented in‑module:** the cluster builds no reply string (pure list/counter mutation).
166:  - **Verification.** L1 `channel_membership_diff` zero‑diff vs `cref_remove_user_from_channel`: a 2‑member channel with both members linked into `chptr->members` + each `who->user->channel` + a per‑uplink `clist` entry; removing one member asserts identical surviving `members`/`clist`/`user->channel` chains, `chptr->users`, `joined--`, and the `is_userc`/`is_chanusers` deltas — deliberately keeping `users >= 1` so the last‑user `free_channel` teardown (needs the channel hash + global) is **not** L1‑reached (L2/review‑covered). **Inverse/round‑trip invariant** (`add_remove_readd_roundtrip_is_clean`, the skill's required inverse test): drives the now‑Rust `add_user_to_channel` directly (a C static → no `cref_` oracle) to add two members, remove one and assert it is *actually gone* from `members`/`clist`/`user->channel` with the counters decremented, then re‑add and assert no duplicate node + the `is_userc`/`is_chanusers` counters return **exactly** to the two‑member values (a botched removal passes the positive‑only differential but leaks/double‑counts here). `change_chan_flag` is a C static → no `cref_` oracle → covered by L2. L2 (all byte‑identical ref‑C == Rust, 0 new canonicalizer masks): `golden_channel_part` — (1) **PART** with a *second member* (bob) staying on #chan to observe alice's relayed PART, then a follow‑up NAMES + WHO confirming alice is gone from both membership lists (`remove_user_from_channel`); (2) **MODE +o → NAMES** showing `@bob` (`change_chan_flag` set the flag, `is_chan_op` reads it). `golden_channel` (JOIN) still covers `add_user_to_channel`. **S2S `golden_s2s_membership`** — a remote NJOIN (`m_njoin` C → Rust `add_user_to_channel`; the server‑side `get_channel(&me, CREATE)` creates the federated `#chan` a split lone link won't let a local client create) then a local observer JOINs and sees `@bob`, then a remote PART (`m_part` C → Rust `remove_user_from_channel`) the observer sees + a NAMES no longer listing bob. `cargo build` 0 warnings; full `cargo test` green (41 test binaries incl. the new `channel_membership_diff` L1 + `golden_channel_part`/`golden_s2s_membership` L2). **Split‑mode finding:** in `boot_s2s` a single configured uplink keeps the server permanently split (`IsSplit()`), so a local client **cannot create** a federated `#` channel (m_join:2591 `ERR_UNAVAILRESOURCE`) — but **can JOIN an existing one** (the split guard is inside `if(!chptr)`); the NJOIN server path creates it. **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), join/access (`can_join`/`get_channel`/`free_channel`/`reop_channel`), part/kick/topic, and display (`names_channel`/`find_chasing`/`check_string`/`m_names`/`m_list`) clusters stay in `channel_link.o`.
170:  - **Config (verified `cbuild/config.h`):** `TOPIC_WHO_TIME` **defined** (config.h:522) → the `topic_t`/`topic_nuh` blocks (the 333 RPL_TOPIC_WHO_TIME reply on query, the `topic_nuh = "%s!%s@%s"` build + `topic_t = timeofday` on set) **are compiled and ported**. `USE_SERVICES` **off** → the `check_services_butone(SERVICE_WANT_TOPIC, …)` block not compiled/not ported. `JAPANESE` off (no effect). Numerics: RPL_NOTOPIC=331, RPL_TOPIC=332, RPL_TOPIC_WHO_TIME=333, ERR_NOSUCHCHANNEL=403, ERR_NOTONCHANNEL=442, ERR_NOCHANMODES=477, ERR_CHANOPRIVSNEEDED=482. Fields (bindgen): `topic[256]`, `topic_nuh[92]`, `topic_t` (time_t). New helpers: `is_channel_name` (cid_ok, CHIDLEN=5), `use_modes`, `is_anonymous`, `strncpyzt`; new bindings imports `canonize`/`strtoken`/`cid_ok`/`RPL_NOTOPIC`/`RPL_TOPIC`/`RPL_TOPIC_WHO_TIME`/`ERR_NOCHANMODES`/`ERR_NOSUCHCHANNEL`; new externs `sendto_match_servs`/`sendto_channel_butserv`/`strncpy`.
172:  - **Faithfulness notes:** the `strtoken(&p, parv[1], ",")` per‑target loop with `parv[1]=NULL` advance; the `find_channel` miss does `return penalty` (**not** `continue`); `IsChannelName` reject → 442, `!UseModes` → 477, `!IsMember` → 442, `check_channelmask` → continue; query (`topic==NULL`) → empty topic → 331, else 332 + (if `topic_t > 0`) 333 with `IsAnonymous(chptr) ? "anonymous!anonymous@anonymous." : topic_nuh`; set (`parc > 2`) only if `!(mode & MODE_TOPICLIMIT) || is_chan_op` → strncpyzt topic, build topic_nuh, `topic_t = timeofday`, propagate (`sendto_match_servs` UID‑sourced + `sendto_channel_butserv` name‑sourced), `penalty += 2`; else → 482.
173:  - **L2 is the gate (no clean L1 data op — m_topic sends wire output via a live channel).** L2 `golden_channel_topic` 2/2 byte‑identical (`-p standalone` so `#chan` can be created): **lifecycle** (query empty → 331; set → echo; query → 332 + 333; **change** → re‑query 332 reflects the *new* value — the round‑trip/inverse invariant a botched set/strncpyzt would break) + **rejects** (442 non‑member, 403 no‑such‑channel, 482 non‑op on +t). **S2S `golden_s2s_topic`** 1/1 byte‑identical (the user‑requested server path): a remote chanop bob (NJOIN'd onto a federated `#chan`) sets the topic → `m_topic` (cptr = peer server, sptr = bob) relays `:bob TOPIC #chan :…` to local member alice via `sendto_channel_butserv` and her query returns 333 carrying **bob's `topic_nuh`** (the remote‑user fields only an S2S link produces); then local alice sets the topic → `sendto_match_servs` propagates `:000AAAAAA TOPIC #chan :…` (UID‑sourced) to the peer. **New canonicalizer mask:** 333 RPL_TOPIC_WHO_TIME's trailing `topic_t` (= `timeofday`) is wall‑clock volatile between the separately‑booted ref‑C/Rust → masked to `<T>`. `m_topic` defined `T` from ircd‑common in the Rust `ircd`; `cargo build` 0 warnings. **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), join/access (`m_join`/`m_njoin`/`can_join`/`get_channel`/`free_channel`/`reop_channel`), part/kick (`m_part`/`m_kick`/`find_chasing`), and display (`m_names`/`m_list`/`names_channel`/`check_string`) clusters stay in `channel_link.o`.
180:  - **Faithfulness notes:** `parc > 2 && hunt_server(…, 2, …) != 0` → `return 10` (the forwarding short‑circuit; `HUNTED_ISME`=0 falls through, `PASS`=1/`NOSUCH`=‑1 forward). Bare arg (`BadPtr(parv[1])`): `!sptr->user` → RPL_LISTEND + `return 2`; else opening notice, then loop 1 over `sptr->user->channel` listing only `Secret||Hidden` channels, then loop 2 over the global `channel` list skipping `!users || Secret || Hidden` — each with the `DBufLength > maxsendq` → ERR_TOOMANYMATCHES throttle (loop 1's `goto end_of_list` modelled as `break 'lists`, loop 2's `break` falls through), then the trailing notice. Named arg (`else`): `canonize` then per‑token `strtoken(&p, parv[1], ",")` with `parv[1]=NULL` advance; `find_channel && ShowChannel && sptr->user` → RPL_LIST; `*name=='!'` → `hash_find_channels(name+1, …)` mask loop with the `scr = SecretChannel && !IsMember` users‑`-1`/topic‑`""` masking; both with the `!MyConnect && rlen > CHREPLLEN` break. Tail: `!MyConnect && rlen > CHREPLLEN` → ERR_TOOMANYMATCHES; always RPL_LISTEND; `return 2`.
181:  - **L2 + L2‑S2S are the gates (no clean L1 data op — `m_list` only reads channel state and sends wire output).** L2 `golden_channel_list` 1/1 byte‑identical (`-p standalone`): bare `LIST` shows two public channels (322) + the ALIS notice + 323, and a `+s` secret channel a non‑member (alice) is not on does **not** appear (the inverse); named `LIST #pub` → just that channel; `LIST #nonexistent` → only 323 (the `find_channel` miss). **S2S `golden_s2s_list`** 1/1 byte‑identical: the `hunt_server` forwarding path the standalone harness can't reach — a local client issues `LIST #chan peer.test` (`parc > 2`, parv[2] = the linked peer) and the peer receives the forwarded `LIST` command byte‑for‑byte under ref‑C and Rust, confirming the Rust `parc > 2` branch invokes `hunt_server` and short‑circuits (`return 10`) exactly as C. `m_list` defined `T` from ircd‑common in the Rust `ircd`; `cargo build` 0 warnings; the six channel goldens (channel/topic/part/modes/can_send/invite) stay green after the `sendto_one` sig unification; no new canonicalizer masks. **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), join/access (`m_join`/`m_njoin`/`can_join`/`get_channel`/`free_channel`/`reop_channel`/`collect_channel_garbage`/`setup_server_channels`), part/kick (`m_part`/`m_kick`/`find_chasing`/`check_string`), and display (`m_names`/`names_channel`) clusters stay in `channel_link.o`.
189:  - **L2 + L2‑S2S are the gates (no clean L1 — m_part is a socket‑driven handler with no extractable data‑op core, consistent with m_topic/m_list).** L2 `golden_channel_part` (now driving the Rust m_part) stays byte‑identical on the local success path (PART observed by a second member + the NAMES/WHO inverse confirming the parter is gone — `remove_user_from_channel`), **extended** with `part_errors_match_reference`: m_part's own 403 (PART a nonexistent channel) and 442 (PART a channel you're not on) numerics, previously unexercised. **S2S `golden_s2s_membership`** already covers the `IsServer(cptr)`/`MyPerson` remote‑PART branch — a remote user behind the peer PARTs (`:001BAAAAA PART #chan`), routed through the now‑Rust m_part's `sptr->user->uid`‑sourced propagation + the member relay a local observer sees, then NAMES no longer lists the remote user. All byte‑identical ref‑C == Rust; `cargo build` 0 warnings; no new canonicalizer masks. **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), join/access (`m_join`/`m_njoin`/`can_join`/`get_channel`/`free_channel`/`reop_channel`/`setup_server_channels`), `m_kick`/`find_chasing`/`check_string`, and display (`m_names`/`names_channel`) clusters stay in `channel_link.o`.
192:  - **`find_chasing` is the cluster's shared static — the P5u/P5x extern‑switch case.** `m_kick` is its caller, but `find_chasing` is also called by the still‑C `set_mode`/`m_mode` (channel.c:~1301), so the C body is guarded out under `#ifndef PORT_CHANNEL_P5` and the `#else` branch adds an `extern aClient *find_chasing(…)` forward decl (it had none — it was defined before both use sites) so the C remnant resolves to the Rust `#[no_mangle]` def at link (linkage‑only, faithful). `check_string` — the other display‑cluster static — is **not** touched: `m_kick` doesn't call it (only `make_bei`/`m_mode` do). RED confirmed via the two undefined symbols `find_chasing`+`m_kick` (every other callee already Rust or a C extern).
194:  - **Faithfulness notes.** `nbuf[BUFSIZE+1]` is a **local auto** array in C (not a file‑static) → a Rust stack `[c_char; BUFSIZE+1]`; no shared `buf`/`modebuf` touched. The C size_t arithmetic is mirrored exactly: `maxlen = BUFSIZE - MAX(strlen(sender),strlen(name)) - strlen(comment) - 10` via `wrapping_sub … as c_int`, and `clen = maxlen - strlen(name) - 1` via `(maxlen as usize).wrapping_sub(…)` (the C int→size_t promotion), with the flush test comparing `… >= clen as usize`. The `!(IsServer(cptr) && (who=find_uid(...))) && !(who=find_chasing(...))` short‑circuit assignment is preserved branch‑for‑branch (find_uid only attempted for a server `cptr`, find_chasing only when that misses). `sender` = SID (server) / UID (person) / name; the relay echoes `sptr->name`/`who->name` to members but the comma‑batched `sendto_match_servs_v(SV_UID,…)` carries UIDs (`who->user->uid`). Returns `penalty`.
196:  - **L2 + L2‑S2S are the gates (no L1 — `find_chasing` is file‑static so no `cref_` oracle symbol, cf. P5u/P5x statics; `m_kick` is a socket‑driven handler with no extractable data‑op core, cf. m_topic/m_list/m_part).** New `golden_channel_kick` (L2): chanop alice KICKs member bob → bob sees `:alice KICK #chan bob :…` + the NAMES inverse (bob gone — `remove_user_from_channel`); plus m_kick's own error numerics 441 (find_chasing resolves a non‑member → `!IsMember`), 403, 442, 482 (461 min‑params is the parser's, not asserted). New `golden_s2s_kick` (L2‑S2S): (a) **UID propagation** — a local chanop KICKs a remote member (peer‑NJOINed) → the peer receives `:000AAAAAA KICK #chan 001BAAAAA :…` (`sendto_match_servs_v(SV_UID)`, kicker‑UID source + victim‑UID target); (b) **server‑sourced KICK** — the peer server KICKs a local user by UID (`:001B KICK #chan 000AAAAAA :…`) → the `IsServer(cptr)`+`find_uid` victim resolution + `IsServer(sptr)` SID‑sender/SCH_NOTICE branches relay `:peer.test KICK #chan alice :…` and remove her (NAMES member‑list inverse). All byte‑identical ref‑C == Rust; `cargo build` 0 warnings; no new canonicalizer masks. **Also fixed a pre‑existing timing flake** in `golden_s2s_membership` (`s2s_deop_and_clean_readd`): the re‑NJOIN `:bob JOIN` relay raced the 300 ms drain window — now consumed deterministically via `read_until(" JOIN ")` (mirroring the MODE‑relay barrier already in that test). **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), join/access (`m_join`/`m_njoin`/`can_join`/`get_channel`/`free_channel`/`reop_channel`/`setup_server_channels`), `check_string`, and display (`m_names`/`names_channel`) stay in `channel_link.o`.
203:  - **L2 + L2‑S2S are the gates (no L1 — read‑only + wire, no extractable socket‑free data‑op core, cf. m_topic/m_list/m_part).** New `golden_channel_names` (L2): `NAMES #pub` from a member → `= #pub :@alice bob` 353 + 366 (the `=` public marker, `@` op prefix); a `+s` secret channel's member view → the `@ #secret` 353 marker; the **inverse** — a non‑member's `NAMES #secret` yields only 366 (`showusers=0`, members hidden); bare `NAMES` → all‑visible‑channels + the `* * :` remaining‑users third section ending `366 … *`. JOIN‑echo regression covered by the existing `golden_channel` (its 353/366 now come from the Rust `names_channel` via the still‑C `m_join`). New `golden_s2s_names` (L2‑S2S): the `parc>2` `hunt_server` forwarding short‑circuit (`NAMES #chan peer.test` → the peer receives the byte‑identical forwarded `NAMES` line). All byte‑identical ref‑C == Rust; `cargo build` 0 warnings; no new canonicalizer masks. **Test note:** the L2 test uses **2** concurrent clients (alice op of #pub, bob member + #secret owner) — a 3‑client variant tripped the per‑host clone limit (BrokenPipe), so the inverse is driven by alice (non‑member of #secret) rather than a third nick. **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), join/access (`m_join`/`m_njoin`/`can_join`/`get_channel`/`free_channel`/`reop_channel`/`setup_server_channels`), and `check_string` stay in `channel_link.o`.
207:  - **Callees, all already resolved:** Rust — `strtoken` (P1), `check_channelmask` (P5u), `clean_channelname`/`find_channel`/`is_chan_op` (P5t), `hash_find_channels` (P2), `check_chid`/`get_chid` (P3 s_id), `del_invite` (P5u), `add_user_to_channel`/`remove_user_from_channel` (P5x), `names_channel` (P5cc), `exit_client` (P5c), `match_modeid` (P5v), `mycmp` (P1 match_); C extern — `get_channel` (channel.c file‑static, extern‑switched by P5aa; called both `0`=!CREATE and `CREATE`), the variadic senders (`sendto_serv_v` + `sendto_channel_butone` added to the local extern block; `sendto_one`/`sendto_channel_butserv`/`sendto_match_servs`/`sendto_match_servs_v`/`sendto_flag` already there). New helper `is_split` (`iconf.split > 0`, struct_def.h:805). New consts/imports: `bootopt`/`iconf`/`CREATE`/`BOOT_PROT`/`CHFL_INVITE`/`CHFL_REOPLIST`/`EXITC_VIRUS`/`CHIDLEN`(local)/the JOIN ERR_* numerics. `CLIENTS_CHANNEL` off (no `&CLIENTS` branch), `USE_IAUTH` on (`&AUTH` in can_join's oper‑channel set), `JAPANESE` off (no `jp_valid`), `TOPIC_WHO_TIME` defined (the topic‑on‑join 333 block ported).
210:  - **Faithfulness notes.** `IsServer(cptr)` head (the only JOIN over a link): `parv[1]=="0"` → walk `sptr->user->channel`, PART each (the `PartFmt` `:%s PART %s :%s` literal + the now‑Rust `remove_user_from_channel`), then `sendto_match_servs(NULL,cptr,":%s JOIN 0 :%s",uid,parv[0])`; a non‑zero server JOIN is silently ignored. First pass: per‑token `check_channelmask`/`"0"`‑literal/`clean_channelname`/the `!`‑channel block (`!!`/`!#` new‑id build + `hash_find_channels`/`check_chid` duplicate rejects; short `!chan` resolves via find_channel→hash_find_channels with the `&&`‑short‑circuit preserved)/`IsChannelName` gate/jbuf‑overflow `break`. Second pass: parallel `key` strtoken on parv[2]; `JOIN 0` part‑all; `get_channel(!CREATE)`; `IsMember` skip; `MyConnect && joined>=MAXCHANNELSPERUSER` → 405; the 10‑byte virus‑string `strncmp` → `exit_client`; the split‑mode create gate → 437; `get_channel(CREATE)`; `can_join` → `replies[i]`; the chanop‑on‑create flag decision; `add_user_to_channel`; the JOIN echo; `del_invite`; topic 332/333; `names_channel`; anonymous NOTICEs; the NJOIN propagation (`get_channelmask(name)||*chname=='!'` → `sendto_match_servs_v(SV_UID)` else `*chname!='&'` → `sendto_serv_v(SV_UID)`, both `me.serv->sid`‑sourced with the `@@`/`@`/`""` flag prefix). Returns 2.
211:  - **L2 + L2‑S2S are the gates (no L1 — `m_join` only manipulates membership via the already‑L1'd `add_user_to_channel`/`remove_user_from_channel` and emits wire; `can_join` is a file‑static, cf. m_names/m_list/m_topic).** New `golden_channel_join` (L2, `boot_standalone`, 5 scenarios incl. inverses): `+k` wrong‑key 475 then the keyed JOIN succeeds (the key round‑trip); `+i` 473 then alice's INVITE overrides can_join's invite gate; `+l 1` full 471; a duplicate JOIN is a silent no‑op (the `IsMember` skip — assert no second echo); `JOIN 0` PARTs every channel then the NAMES inverse (she is gone, the channel destructed). The existing `golden_channel` (basic JOIN + JOIN→PART→re‑JOIN round‑trip) now drives the Rust m_join as a regression. New `golden_s2s_join` (L2‑S2S, `boot_s2s`, 2 scenarios): (a) a local client's JOIN of a federated `#chan` (peer‑created via NJOIN) propagates `:000A NJOIN #chan :000AAAAAA` to the peer — the `sendto_serv_v` SV_UID tail formatting the LOCAL SID + the joiner's UID, fields the client‑facing echo never carries; (b) the `IsServer(cptr)` head — a peer‑sourced `:001BAAAAA JOIN 0` relays bob's `:bob!~bob@remote.host PART #chan` to a local co‑member. All byte‑identical ref‑C == Rust; the 10 channel goldens + 20 s2s goldens + the channel L1 diffs stay green; `cargo build` 0 warnings; no new canonicalizer masks. **Remaining channel.c (C):** the mode cluster (`m_mode`/`set_mode`/`add_modeid`/`del_modeid`/`send_mode_list`/`make_bei`/`free_bei`/`send_channel_*`), `m_njoin`, `reop_channel`/`collect_channel_garbage`/`setup_server_channels`, `free_channel`, and `check_string` stay in `channel_link.o`.
218:  - **Faithfulness notes.** The mode‑prefix parse (`@`/`@@`/`@@+`/`@+`/`+` → `mbuf` `o`/`ov`/`v` + `chop` CHFL bits, `name` advanced past the prefix, `target` left at the prefix for the verbatim uidbuf copy) is branch‑for‑branch. The MODE‑burst accumulator (the `cnt` switch): case 0 falls through to case 1 (`strcat modebuf/parabuf`, the `mbuf[1]` double‑name for a `+ov` user), case 2 flushes `:%s MODE %s +%s%c %s %s` (the `mbuf[0]` `%c` promoted `as c_int`), `cnt == MAXMODEPARAMS` flushes `:%s MODE %s +%s %s` and resets — modelled as `if cnt==0||cnt==1 {…} else if cnt==2 {…}` (the C fall‑through). The size_t/ptrdiff math (`maxlen = BUFSIZE - 17 - strlen(parv0) - strlen(parv1) - NICKLEN`; the `u.offset_from(u_base) >= maxlen` flush test) mirrored as signed `isize`. Empty‑channel lock (`parv[2]=="."` → `history = timeofday + (L)DELAYCHASETIMELIMIT`, `istat.is_hchan*` bumps, return 0) ported (no observable wire → review‑covered). JOIN relay `:%s JOIN %s%s` with the `:`‑prefix‑unless‑bursting netjoin‑discriminator trick. Already‑on‑channel error class (`IsBursting` → SCH_ERROR notice + `ERROR` line to cptr; else SCH_CHAN "Fake:" notice). Source SID = `sptr->serv->sid` (the NJOIN origin server). Returns 0.
