# P6 — Config & DNS: per-cluster summary

One-line top-level summary per P6 cluster (detailed entries live in
[`docs/progress-log/p6.md`](docs/progress-log/p6.md)).

- **P6a DONE: `s_conf.c` TKLINE cluster** (`m_tkline`/`m_untkline`/`prep_kline`/`do_kline`/`wdhms2sec`/`tkline_expire` + the `tkconf` list) — the oper temporary-kill family ported to `ircd-common/s_conf.rs` via an `s_conf_link.o` partial port (`-DPORT_TKLINE_P6`; the rest of `s_conf.c`'s config grammar stays C). Handler cluster, not server-reachable (msgtab col 2/3; do_kline emits only local `SCH_NOTICE`→`&NOTICES` notices + reaps local clients). Gates: L1 (`s_conf_tkline_diff`: wdhms2sec corpus + tkconf add/dedup/expire lifecycle with inverses, highest_fd pinned -1) + L2 (`golden_s_conf_tkline`: oper TKLINE notice/UNTKLINE/bad-format, the two-client reap → 465+disconnect, non-oper 481 inverse). No S2S (no IsServer/remote-field/propagation path).
- **P6b DONE: `res.c` `m_dns`** (the resolver/cache debug command — the *last* command handler still in C) — ported to `ircd-common/res.rs` via a `res_link.o` partial port (`-DPORT_DNS_M_DNS`, de-static'ing `cachetop`/`cainfo`/`reinfo`); the resolver proper stays C. **Every `msgtab` handler is now Rust.** Handler cluster, msgtab col 2 (STAT_OPER) only + the `is_allowed(ACL_DNS)` O-line `d` gate. L2 (`golden_s_dns`, `dns_oper.conf`): oper `DNS` stats + `DNS l` empty cache dump, non-oper 481 inverse. No S2S.
- **P6c DONE: `s_conf.c` flags cluster** (the six pure config-flag converters `{iline,pline,oline}_flags_parse`/`_to_string`) — same `s_conf_link.o` partial port (`-DPORT_SCONF_FLAGS_P6`); first bite into the config *grammar*. Utility/callee (none in msgtab). L1 (`s_conf_flags_diff`: all six vs `cref_`) + L2 (`golden_s_conf_flags`, `flags_oper.conf`). No S2S.
- **P6d DONE: `s_conf.c` `match_ipmask`** (the CIDR/#IP-bitmask matcher — a pure leaf predicate over `cptr->ip`/`username`, used by Rust channel ban-matching + the TKLINE/conf-lookup paths) — same `s_conf_link.o` partial port (`-DPORT_SCONF_IPMASK_P6`). Utility/callee. L1 (`s_conf_match_ipmask_diff`: v4-mapped /32//24//0, j-boundary, user@host/cidr, badmask, native v6, each with its inverse) + L2 (`golden_s_conf_match_ipmask`: channel CIDR `+b`). No S2S.
- **P6e DONE: `s_conf.c` `find_admin`/`find_me`** (two leaf read-only walks of the global `conf` list for the `CONF_ADMIN`/`CONF_ME` entry) — same `s_conf_link.o` partial port (`-DPORT_SCONF_FINDADMIN_P6`). Utility/callee. L1 (`s_conf_find_admin_me_diff`: head/non-head/absent/combined-bits incl. inverses, both globals pointed at one list) + L2 (`golden_s_conf_find_admin`: the `ADMIN` command via Rust `m_admin`). No S2S.
- **P6f DONE: `s_conf.c` config-file parser** (`openconf` + `initconf` — the whole `ircd.conf` grammar) — same `s_conf_link.o` partial port (`-DPORT_INITCONF_P6`, un-static'ing `lookup_confhost`); the line lexer is a new **`nom`-based** module (`config_parse.rs` — faithful `process_escapes`→`split_fields` port of the escape/comment pass + `getfield`), the semantic switch builds byte-identical `aConfItem` lists/classes + side effects. Not in msgtab. L1 (`config_parse_diff`: nom `split_fields` vs `cref_getfield`; `s_conf_initconf_diff`: full conf-list build vs `cref_initconf` over A/I/i/O/o/Y/C/c/N/D/H/L/V/Q/B/K/k) + L2 (`golden_s_conf_initconf`: STATS y/i/o over the parsed config). No S2S.
- **P6g DONE: `s_conf.c` `find_Oline`** (the read-only `conf`-list scan `m_oper` uses to resolve `OPER <name> <pass>`: best `CONF_OPS` entry by name `mycmp` + host `match`/`match_ipmask`, honouring `clients < MaxLinks(Class)` with the over-limit `tmp2` fallback) — same `s_conf_link.o` partial port (`-DPORT_SCONF_FINDOLINE_P6`). Utility/callee (`m_oper` calls it). L1 (`s_conf_find_oline_diff`: name/host-glob/CIDR-in-out/over-limit-fallback/wrong-status/empty incl. inverses) + L2 (`golden_s_conf_find_oline`, `find_oline.conf`: a `10.0.0.0/8` O-line that misses the 127.0.0.1 client → 491, vs a `*@*` O-line → 381 — the host/CIDR-miss branch the existing OPER golden can't reach). No S2S (no IsServer/remote-field path).
- **P6h DONE: `s_conf.c` `find_conf*` family** (the seven read-only conf lookups `find_conf_exact`/`find_conf_name`/`find_conf`/`find_conf_host`/`find_conf_host_sid`/`find_conf_ip`/`find_conf_entry`) — same `s_conf_link.o` partial port (`-DPORT_SCONF_FINDCONF_P6`). Utility/callee (none in msgtab; the still-C `s_serv.c`/`s_bsd.c`/`s_misc.c` server-link + registration paths call them). L1 (`s_conf_find_conf_diff`: all seven vs `cref_` over positive + inverse — name/host/status/port/passwd-asymmetry misses, the CONF_OPERATOR over-limit skip, the server-mask `mycmp`-exact-vs-`match`-glob split, the NUL HOSTLEN early-outs, the `find_conf_ip` in-place `@`-split restore; **the differential caught an inverted `!match(passwd,sid)` sid gate in the first draft**) + S2S (`golden_s2s_s_conf_find_conf`: a peer link drives the C/N-line `find_conf` accept + `find_conf_host`/`find_conf_host_sid` leaf/hub checks → byte-identical burst + post-link routing; the 37-test `golden_s2s_*` suite + registration goldens are the broader regression). No client-only L2 numeric.
- **P6i DONE: `s_conf.c` K-line lookup family** (`find_kill`/`find_two_masks`/`find_conf_flags`/`find_denied`) — the read-only K-line / version-mask / deny lookups named in the PLAN P6 row, ported to `ircd-common/s_conf.rs` via the `s_conf_link.o` partial port (`-DPORT_SCONF_FINDKILL_P6`, three guard regions; `find_bounce` stays C). Config-resolved: TKLINE on (find_kill's tkconf→kconf two-pass loop compiles), KLINE off, TIMEDKLINES off (the reply/check_time_interval block not compiled; `timedklines` arg inert). Utility/callees (none in msgtab); the still-C `s_serv.c` `check_version`, Rust `s_user.c` `register_user`, and `ircd.c` resolve to the Rust defs at link. L1 (`s_conf_find_kill_diff`: all four vs `cref_` over positive + inverse — find_kill tkconf/kconf hit, expired-TK fallthrough, OTHERKILL→ident vs KILL→username `check`, port gate, CIDR in/out, '='-numeric-only skip, resolved-hostname match, IsKlineExempt short-circuit, no-user guard; find_two_masks/find_conf_flags status/host/name/no-slash/prefix/strpbrk inverses; find_denied host-scan/reversed/digit-passwd/no-D-line) + L2 (`golden_s_conf_find_kill`, `kline.conf`: a 127.0.0.1 client hits `K|127.0.0.1|…|*|0|` mid-registration → 465 + `K-lined:` Closing Link) + S2S (`golden_s2s_s_conf_find_two_masks`, `vline_reject.conf` = s2s.conf + `V|*||peer.test|`: m_server_estab check_version → find_two_masks → "Bad version" exit). The no-match version-check path is exercised by every other `golden_s2s_*` test; find_denied is reachable only from `try_connections` server auto-connect (not in the golden harness) → L1 only.
- **P6j DONE: `s_conf.c` `find_bounce`** (the RPL_BOUNCE sender — the read-only conf-list scan that emits `010 :Please use this Server/Port instead` to a rejected connection) — ported to `ircd-common/s_conf.rs` via the `s_conf_link.o` partial port (`-DPORT_SCONF_FINDBOUNCE_P6`, one guard region; the mutating `attach`/`detach`/`rehash` family + `lookup_confhost`/`ipv6_convert` stay C). Three dispatch modes by `fd`: `fd>=0` early-reject (cptr NULL → `sprintf`+raw `sendto`), `fd==-1` class-number host match, `fd==-2` host-match-only. Config: `CONF_BOUNCE`=262144, `RPL_BOUNCE`=10. Utility/callee (not in msgtab); callers s_bsd.c (all-conns-in-use), C `count_cnlines`, and Rust `m_nick`/`m_user` (server-only P-line) resolve to the Rust def at link. L1 (`s_conf_find_bounce_diff`: 9 tests diffing **sent bytes** — sendQ via sendto_one for fd<0, socketpair recv for fd>=0 — over host-glob hit/miss, CIDR in/out, class-number host on fd==-1 vs the fd==-2 skip, non-bounce-skip + first-match-wins, the cptr-NULL guard, empty list, and the fd>=0 empty-host write vs non-empty-host no-op) + L2 (`golden_s_conf_find_bounce`, `bounce.conf`: a server-only P-line `P||||16667|0|S|` + `B|127.0.0.1||bounce.elsewhere|7000|` → client NICK on the server-only port → `010` bounce + `Server only port` exit, byte-identical). No S2S (no IsServer/remote-field path; the fd>=0 raw-sendto branch needs MAXCLIENTS conns → L1 only).
- **P6k DONE: `s_conf.c` attach/detach mutating cluster** (`attach_conf`/`detach_conf`/`det_confs_butmask`/`attach_confs`/`attach_confs_host` + the private `is_attached`/`add_cidr_limit`/`remove_cidr_limit`) — the connected component of conf-attachment mutators (grow/shrink `cptr->confs` + the global `conf` list, mutate class refcounts `aconf->clients`/`ConfLinks` and the per-class CIDR-limit patricia trees), ported to `ircd-common/s_conf.rs` via the `s_conf_link.o` partial port (`-DPORT_SCONF_ATTACH_P6`, three guard regions). Config-resolved: ENABLE_CIDR_LIMITS on (add/remove_cidr_limit compile; `pnode->data` void* counter), YLINE_LIMITS_IPHASH on (per-host limit loop walks the IP hash), YLINE_LIMITS_OLD_BEHAVIOUR off (max-links gate `ConfLinks >= ConfMaxLinks`). Utility/callees (none in msgtab); callers — C `attach_Iline`/`count_cnlines`/`s_bsd.c`/`s_serv.c`/`s_service.c` + Rust `register_user`/`m_oper`/`m_umode` — resolve to the Rust defs at link. Gates: L1 (`s_conf_attach_diff`: two fully-isolated worlds via an `Api` of fn-pointers; round-trip/inverse invariants — attach→detach unlink, is_attached idempotency, -3 Y-line-max + -4 CIDR gates, CIDR freed-slot reuse, free-class on maxLinks==-1, illegal-conf removal from global list, det_confs_butmask, attach_confs/host glob-vs-mycmp; zero diff) + L2 (`golden_s_conf_attach`, `ylinemax.conf`: 2 clients in a maxlinks-1 class → bob rejected via attach_conf -3 → "Too many connections", byte-identical; success+detach paths covered pervasively by the registration + golden_s2s_* suite). No S2S (no IsServer/remote-field path; attach_confs C/N + det_confs_butmask SQUIT covered by the 37-test golden_s2s_* establishment/teardown suite). What stays C in s_conf.c is now only `rehash`, `attach_Iline`/`count_cnlines` (callers of this core), and the initconf-private `lookup_confhost`/`ipv6_convert`.
- **P6l DONE: `s_conf.c` `attach_Iline` + `count_cnlines`** (the two callers of the P6k attach/detach core) — the local-client I-line lookup used during registration (`attach_Iline`: scan `conf` for the best `CONF_CLIENT` line matching the client's port/name/host/password, set the +r/kline-exempt conf flags onto `cptr->user->flags`, copy the resolved host into `sockhost`, then `attach_conf`; emits `464 ERR_PASSWDMISMATCH`/`find_bounce` on rejection) and the read-only single-N-line counter used during inbound server-link establishment (`count_cnlines`), ported to `ircd-common/s_conf.rs` via the `s_conf_link.o` partial port (`-DPORT_SCONF_ILINE_P6`, one guard region s_conf.c:483–664). Config-resolved: UNIXPORT off (no unix-socket host branch), XLINE off (no XlineExempt clear), NO_DNS_LOOKUP on (hp usually NULL). Utility/callees (none in msgtab); callers — C `check_client`/`check_server` (s_bsd.c) — resolve to the Rust defs at link. **What stays C in `s_conf.c` is now only `rehash` + the initconf-private `lookup_confhost`/`ipv6_convert`.** Gates: L1 (`s_conf_iline_diff`: two fully-isolated worlds via an `Api` of fn-pointers — happy glob/CIDR/empty-mask attach + the no-I-line `-2` inverse, port gate, password fall-through vs `-8`+`464`, +r/kline-exempt flag-set, hp!=NULL name-match + `get_sockhost`; `count_cnlines` single-N/zero/two/non-server-skip/empty; zero diff over 8 tests) + L2 (`golden_s_conf_iline`, `iline_pass.conf`: a password I-line with no `F` flag → a client sending no `PASS` → `464` + "Bad password" Closing Link, byte-identical). No S2S (neither has an `IsServer` branch / remote-field formatting; `count_cnlines`'s server-link path is covered by the 37-test `golden_s2s_*` link suite).
- **P6m DONE: `s_conf.c` finalize — `rehash` + `ipv6_convert` + `lookup_confhost` + the `conf`/`kconf`/`networkname` data globals** (the last three functions + the last three data globals s_conf.c owned) — ported to `ircd-common/s_conf.rs`, so **`s_conf.c` is now FULLY Rust → `s_conf.o` dropped outright** (added to `PORTED`; the `s_conf_link.o` partial-compile + the `"s_conf.o" => "s_conf_link.o"` link map removed; the cref oracle keeps the unguarded `s_conf.o`). `rehash` = the faithful config reload (free conf/kconf, mark classes `MaxLinks=-1`, `initconf(0)`, close/reopen listeners, re-read MOTD, the sig `1`/`'a'`/`'d'`/`'t'` branches; ULTRIX/USE_SYSLOG off, TKLINE on); `ipv6_convert` = the pure `[user@]addr[/cidr]` canonicaliser (in-place `@`/`/` poke + restore); `lookup_confhost` = numeric host via `inetpton` (the NO_DNS path) / alpha host via the still-C `gethost_byname`, `badlookup` AND16==255 reset. The conf/kconf/networkname globals flip from bindgen externs to `#[no_mangle] pub static mut` defs (list.rs/s_serv.rs importers resolve to them at link, same as `tkconf`/`classes`). `build.rs` expands `IRCDMOTD_PATH` via make → the `IRCD_MOTD_PATH` rustc-env → `ircd_sys::MOTD_PATH`, so the Rust `rehash`'s `read_motd` reads the identical file reference-C does. Utility/callees (none in msgtab); `rehash` reached from Rust `m_rehash` (oper REHASH) + still-C `ircd.c` SIGHUP. Gates: L1 (`s_conf_rehash_diff`: `ipv6_convert` vs `cref_` over bare-v6/user@/cidr/v4-mapped/passthrough + the input-restore invariant) + L2 (`golden_s_serv_maint` REHASH 382 success/481 reject now drives the Rust `rehash`; `golden_s_conf_initconf` boot exercises `lookup_confhost`/`ipv6_convert`). No S2S (no `IsServer`/remote-field path). `lookup_confhost` is `static` in the unguarded oracle → no `cref_` symbol → covered by the boot golden, not L1.
- **P6n DONE: `res.c`'s pure wire-format leaf `res_comp.c`** (the BIND DNS name compression/expansion `ircd_dn_expand`/`ircd_dn_comp`/`__ircd_dn_skipname` + the big-endian integer marshalers `ircd_getshort`/`ircd_getlong`/`ircd__putshort`/`ircd__putlong`) — ported outright to `ircd-common/res_comp.rs` → **`res_comp.o` dropped** (added to `PORTED`; no `_link.o`). Self-contained leaf: `nm --undefined-only` shows zero ircd-internal deps (only libc `memcpy`/`strchr`/`errno`); the 7 BIND `static` helpers (`ns_name_*`/`special`/`printable`/`mklower`/`dn_find`) ported as private Rust fns. Faithful raw-pointer port; `errno` set (`EMSGSIZE`/`ENOENT`) on every error path as the C does. Utility/leaf (none in `msgtab`); callers — still-C `res.c`/`res_mkquery.c` — resolve to the Rust defs at link. Gate: **L1 only** (`res_comp_diff`: get/put match + put→get round-trip; `dn_comp`→`dn_expand` pack/expand round-trip; the compression-pointer reuse diffed as buffer-relative `dnptrs` offsets + emitted wire bytes; a hand-built compressed-pointer message; `dn_skipname` plain/compressed/truncated; the dstsiz-too-small, malformed-pointer, overlength `-1` inverses with `errno` compared). No L2/S2S — pure wire-format leaf with no client/server-reachable command path under the locked config; end-to-end DNS coverage arrives when the resolver proper is ported under a fixture nameserver.
- **P6o DONE: `res.c`'s DNS query-packet builder `res_mkquery.c`** (`ircd_res_mkquery` — forms QUERY/NS_NOTIFY_OP/IQUERY messages into a caller buffer, returns the packet length or `-1`) — ported outright to `ircd-common/res_mkquery.rs` → **`res_mkquery.o` dropped** (added to `PORTED`; no `_link.o`). Deps resolve at link: `ircd_dn_comp`/`ircd__putshort`/`ircd__putlong` are the P6n Rust defs, the resolver-state global `ircd_res` + `ircd_res_init` stay C (res_init.o). **Layout hazard neutralized:** the 12-byte DNS header is written through the **bindgen `HEADER`** bitfield type (size 12, `set_id`/`set_opcode`/`set_rd`/`set_rcode`/`set_qdcount`/`set_ancount`/`set_arcount` byte-identical to the gcc little-endian `nameser_def.h` layout) instead of hand-packing bitfields; `h_errno` set via `__h_errno_location` exactly as the C. Config-resolved: `DEBUG` off → the `RES_DEBUG` printf block not compiled. Utility/leaf (none in `msgtab`); callers — still-C `res.c` (`query_name`/`do_query_*`) — resolve to the Rust def at link. Gate: **L1 only** (`res_mkquery_diff`: Rust vs `cref_` byte-identical packets over QUERY±recurse, NS_NOTIFY_OP with/without the additional-record branch, IQUERY answer section with/without rdata, plus the `-1` inverses — bad op, NULL buf, `buflen<HFIXEDSZ`, and the question-section `buflen`/`dn_comp` overflow — and the shared `++ircd_res.id` side effect diffed identically; both `ircd_res`/`cref_ircd_res` pinned with RES_INIT to skip the nondeterministic `res_init`/`res_randomid` path, a process-global `RES_LOCK` serializing the parallel `#[test]` threads). No L2/S2S — pure wire-format leaf with no client/server-reachable command path under NO_DNS_LOOKUP; end-to-end DNS coverage arrives when the resolver proper (`res.c`+`res_init.c`) is ported under a fixture nameserver.
- **P6p DONE: `res.c`'s resolver-state bootstrap `res_init.c`** (`ircd_res_init` — reads `/etc/resolv.conf` + `LOCALDOMAIN`/`RES_OPTIONS` env into the global `ircd_res`; the static `res_setoptions` it drives; the random message-id `ircd_res_randomid`) — ported outright to `ircd-common/res_init.rs` → **`res_init.o` dropped** (added to `PORTED`; no `_link.o`). The `ircd_res` global moves from C to a Rust `#[no_mangle] static mut` (`MaybeUninit::zeroed`); `res_mkquery.rs`/`res.c`/`s_bsd.c` resolve their `ircd_res`/`ircd_res_init` references to the Rust defs at link. Self-contained leaf — the only non-libc dep is `inetpton` (P1 `support.rs`). Config-resolved: `DEBUG`/`NEXT`/`RESOLVSORT`/`RFC1535`/`HAVE_GETIPNODEBYNAME`/`USELOOPBACK`/`__BIND_RES_TEXT` all OFF → only the simple path compiles (no NetInfo, no sortlist, no debug printfs, default-`dnsrch` derivation active, `inet6`→`RES_USE_INET6`; `AFINET=AF_INET6` so nameservers parse as IPv6). Utility/leaf (none in `msgtab`). Gate: **L1 only** (`res_init_diff`: the `ircd_res` struct produced by `ircd_res_init` diffed vs `cref_` field-by-field — scalars, ndots/nsort bitfields, the 3 `nsaddr_list` `sockaddr_in6` byte-for-byte, `defdname` bytes, `dnsrch[]` as offsets into `defdname` — over the default-`dnsrch`/`LOCALDOMAIN`-search-tokenizer/`RES_OPTIONS` `ndots:`+`inet6`+`RES_MAXNDOTS`-clamp paths, both globals zeroed + `.id` pinned nonzero to skip the nondeterministic `res_randomid`, env-set/init/restore under a process-global `RES_LOCK`; `res_randomid` is nondeterministic → only its `& 0xffff` mask smoke-tested). Boot/registration + `golden_s_dns` goldens confirm the Rust `ircd_res_init`/`ircd_res` boot byte-identical. No L2/S2S (pure leaf, no client/server command path under `NO_DNS_LOOKUP`; end-to-end DNS coverage arrives when the resolver proper `res.c` is ported under a fixture nameserver). **`res.c` is the only DNS file still in C.**
- **P6q DONE: `res.c` cache-hash leaves `hash_number`/`hash_name`** (the two pure DNS-cache bucket hashes — first bite of the `res.c` cache cluster, ported bottom-up from the resolver's dependency floor) — ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_CACHE_P6q`, dropping their bodies + declaring them extern so the still-C cache walkers `find_cache_name`/`add_to_cache`/`rem_cache`/`find_cache_number` call the Rust defs). Both are upstream file-`static`, so a new three-way `RES_CACHE_LINKAGE` macro de-statics them to GLOBAL in the cref oracle's `res.o` (`-DRES_CACHE_EXPOSE`, behavior-neutral; res.o is consumed only by `libcref.a`) so `cref_hash_*` exists for the L1 differential — neutralizing the `l1-cref-static-symbol-limit`. Faithful: `hash_number` is the unrolled `hashv=ip[0]; for i in 1..16 { hashv=2*hashv+ip[i] }` over a **wrapping u32** (`% 1009`=ARES_CACSIZE only at the end; reads exactly 16 bytes = sizeof in6_addr, AFINET=AF_INET6); `hash_name` sums bytes to the first `.`/NUL with **signed-char** promotion (`i8 as i32 as u32`). Utility/leaf (not in `msgtab`). Gate: **L1 only** (`res_hash_diff`: Rust vs `cref_` over 16-byte v6 addrs incl. all-0xff u32-overflow/v4-mapped/high-bit, names incl. empty/dot-first/embedded-dot/8-bit/long; range-checked `[0,1009)`). No L2/S2S (no client/server command path; resolver inert under `NO_DNS_LOOKUP`, cache never populates at runtime — end-to-end DNS coverage arrives when the resolver proper is ported under a fixture nameserver). `golden_s_dns` + boot goldens confirm the still-C cache walkers call the Rust hashes without regression.
- **P6r DONE: `res.c` cache removal/expiry core `rem_list`/`rem_cache`/`expire_cache`/`flush_cache`** (the second bite of the `res.c` cache cluster, building on the P6q hashes) — the connected component that *deletes* cache entries, ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_CACHE_REM_P6r`, generalizing the P6q three-way `RES_CACHE_LINKAGE` to `rem_cache`/`rem_list`). `rem_list` unlinks one entry from `cachetop` **only** (leaves the hash buckets + `incache` untouched — the faithful quirk); `rem_cache` does the full delete (NULL any `local[]->hostp` at this `he`, unlink from `cachetop` + both `hashtable` buckets via the Rust `hash_name`/`hash_number`, free name/aliases/addrs/entry, `incache--` + `ca_dels++`); `expire_cache` reaps the past-due + returns the next poll time; `flush_cache` reaps everything. The cache data globals `hashtable`/`incache` join `cachetop`/`cainfo` on `RES_DNS_STATIC`, now also exposed under `-DRES_CACHE_EXPOSE` so the cref oracle gets `cref_cachetop`/`cref_hashtable`/`cref_incache`/`cref_cainfo` for the L1 isolated worlds. Utility/leaf (not in `msgtab`). Gate: **L1 only** (`res_cache_rem_diff`: two fully-isolated `World`s of fn-pointers + global base pointers, entries hand-built à la `add_to_cache`; flush/expire/rem_cache-hostp/rem_list each with its inverse — flush empties + re-inserts clean, expire keeps survivors in order + returns min-future/`now+AR_TTL`, rem_cache clears a per-world dangling `hostp`, rem_list returns the successor + leaks `incache` by design; zero diff). No L2/S2S (resolver inert under `NO_DNS_LOOKUP`; `golden_s_dns` + registration goldens confirm the still-C cache walkers call the Rust removal core without regression). **Still C in `res.c`:** the resolver proper + the cache build/insert/lookup half (`add_to_cache`/`update_list`/`find_cache_*`/`make_cache`).
- **P6s DONE: `res.c` cache lookup/reorder half `update_list`/`find_cache_name`/`find_cache_number`** (the third bite of the `res.c` port — the half of the hostent cache that *looks up* and *reorders/merges* entries, built on the P6q hashes + P6r removal core) — the connected component ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_CACHE_LOOKUP_P6s`, extending the three-way `RES_CACHE_LINKAGE` to the three upstream file-statics so the still-C `gethost_byname_type`/`gethost_byaddr`/`proc_answer`/`make_cache` callers resolve to the Rust defs at link, and the cref oracle de-statics them to `cref_*` for L1). `update_list` reorders a hit to the `cachetop` head and (if `rptr != NULL`) merges new aliases (T_PTR) / addresses (T_A/T_AAAA) from the ResRQ reply into the cached `hostent` — the gnarly double-`MyRealloc` of the contiguous IP block + the pointer array, then the `FLG_PTR_*` flag update by `addrcount`; `find_cache_name`/`find_cache_number` do the hashed-bucket lookup + the full-list fallback (the fallback's fixed-`s`=alias[0] quirk + the `find_cache_number` `rem_list` degenerate-entry reap preserved), `update_list` on hit, `ca_na_hits`/`ca_nu_hits` counters. Faithful raw-pointer port preserving the C post-increment index walks (`s = h_aliases[i++]`) and the for-loop `continue`→increment semantics. Utility/leaf (not in `msgtab`). Gate: **L1 only** (`res_cache_lookup_diff`: two isolated `World`s of fn-pointers + global base pointers — `cachetop`/`hashtable`/`cainfo`; find_cache_name hashed hit+reorder+counter / name-miss / flags-gate-miss / alias full-list fallback; find_cache_number hashed hit / absent-addr miss / FLG_PTR_VALID gate / multi-addr fallback; update_list rptr=NULL reorder-only + T_PTR alias-merge & T_A addr-merge each with the already-present no-growth inverse; zero diff over 6 tests). No L2/S2S (resolver inert under `NO_DNS_LOOKUP`; `golden_s_dns` + `golden_registration` confirm the still-C build/insert half calls the Rust lookup/reorder core without regression). **Still C in `res.c`:** the resolver proper + the cache **build/insert** half (`add_to_cache`/`make_cache`).
- **P6t DONE: `res.c` cache build/insert half `add_to_cache`/`make_cache`** (the fourth and final bite of the `res.c` cache cluster — the two functions that *create* and *link in* hostent-cache entries, built on the P6q hashes + P6r removal core + P6s lookup/reorder) → **`res.c`'s hostent cache is now FULLY Rust**; only the resolver proper remains C. Ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_CACHE_BUILD_P6t`, extending the three-way `RES_CACHE_LINKAGE` to both upstream file-statics so the still-C `proc_answer` caller of `make_cache` resolves to the Rust def at link, and the cref oracle de-statics them to `cref_*` for L1). `add_to_cache` = list-head push + both hash-bucket links (`hash_name`/`hash_number`) + `++incache > MAXCACHED` LRU tail-evict via `rem_cache` + `ca_adds++`; `make_cache` = dedup-or-build (T_PTR→`find_cache_number` per reply addr / T_A·T_AAAA→`find_cache_name` by name — a hit returns the already-reordered+merged entry; a miss `MyMalloc`s a fresh entry, builds the contiguous IP block + pointer array, **steals** the ResRQ aliases + `h_name` (source nulled), clamps `ttl<600`→600 + `re_shortttl++`, `expireat = timeofday + ttl`, sets the `FLG_A_VALID`/`FLG_AAAA_VALID` flag, then `add_to_cache`). Config: DEBUG off (no Debug blocks), AFINET=AF_INET6 (16-byte IN_ADDR), MAXCACHED 512. Utility/leaf (not in `msgtab`). Gate: **L1 only** (`res_cache_build_diff`: two fully-isolated `World`s of fn-pointers + base pointers incl. `incache`/`reinfo`/`timeofday` — build-by-name A/AAAA with the steal inverse, short-ttl clamp + the ≥600 inverse, dedup-by-name + dedup-by-addr-PTR no-add, multi-addr contiguous-block build, `add_to_cache` LRU boundary at MAXCACHED (evict via ca_dels delta) + the under-cap inverse, both-bucket linkage via the two finders; `timeofday` pinned so `expireat` is deterministic; zero diff over 8 tests). No L2/S2S (resolver inert under `NO_DNS_LOOKUP`, cache never populates at runtime; `golden_s_dns` + `golden_registration` confirm the still-C resolver calls the Rust build/insert core without regression). **Still C in `res.c`:** only the resolver proper (request queue + answer parser + socket I/O).
- **P6u DONE: `res.c` request-queue core `add_request`/`rem_request`/`make_request`/`find_id`** (the first bite of the `res.c` resolver proper — the queue-management primitives the rest of the resolver builds on, ported bottom-up from the outstanding-DNS-request floor after the P6q–P6t cache cluster) — ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_REQ_P6u`: a parallel three-way `RES_REQ_LINKAGE` de-statics the four fns — `extern` in res_link.o so the still-C walkers `del_queries`/`timeout_query_list`/`get_res` resolve to the Rust defs, GLOBAL in the cref oracle for `cref_*` L1, static otherwise — and the `first`/`last` queue heads flip from `static` to `RES_DNS_STATIC` so the Rust core + the still-C walkers share one storage, same as the cache globals). `add_request` tail-appends + `reinfo.re_requests++` (NULL → -1 no-op); `rem_request` unlinks (repointing `last` on tail removal) + frees `he.h_name`/`he.h_aliases[]`/`name`/the node; `make_request` `MyMalloc`+`bzero` + seeds `sentat=timeofday`/`retries=3`/`resend=1`/`srch=-1`/`timeout=4`/`he.h_addrtype=AFINET` + copies the `Link` into `cinfo` + `add_request`; `find_id` linear-scans `first`. Config: AFINET=AF_INET6, DEBUG off (Debug() traces gone), MyFree→`libc::free`. Utility/callees (not in `msgtab`). Gate: **L1 only** (`res_request_diff`: two isolated `World`s of fn-pointers + `first`/`last`/`reinfo` base pointers — make_request seeds+appends (NULL-lp zeroes cinfo), add_request order+counter + the NULL no-op, find_id hit/miss + misses-after-rem, rem_request head/middle/tail unlink+`last`-repoint+free, drained queue `first==last==NULL`+reusable; `timeofday` pinned, a process-global LOCK serializes the parallel threads; zero diff over 8 tests). No L2/S2S (resolver inert under `NO_DNS_LOOKUP`, the queue never populates at runtime; `golden_s_dns` + `golden_registration` confirm the still-C walkers call the Rust queue core without regression). **Still C in `res.c`:** `del_queries`/`timeout_query_list` + the resolver socket/answer half (`send_res_msg`/`do_query_*`/`query_name`/`resend_query`/`proc_answer`/`get_res`/`gethost_*`/`init_resolver`/`cres_mem`).
- **P6v DONE: `res.c` queue walkers `del_queries`/`timeout_query_list`** (the second bite of the `res.c` resolver proper — the reaper/timeout layer that walks the outstanding-DNS request queue, built on the P6u queue core) — ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_WALK_P6v`). `del_queries(cp)` reaps every node whose `cinfo.value.cp` matches; `timeout_query_list(now)` walks `first`, reaping past-due requests whose `--retries` is exhausted (`reinfo.re_timeouts++` + the per-`cinfo.flags` notify — ASYNC_CLIENT `sendto_iauth`+`ClearDNS`, ASYNC_CONNECT `sendto_flag` SCH_ERROR — then `rem_request`) or backing off the rest (`sentat=now`, `timeout` doubled, `resend_query`, `tout=now+timeout`), returning `(next>now)?next:now+AR_TTL`. A new `RES_RESEND_LINKAGE` seam de-statics the still-C `resend_query` (extern in res_link.o so the Rust `timeout_query_list` resolves to it; the cref oracle keeps it static — `cref_timeout_query_list` resolves to the objcopy-renamed local, self-contained since `resend_query` has no out-of-TU caller). Config-resolved: DEBUG off (`Debug`/`myctime` traces gone), USE_IAUTH on; `retries` is unsigned `char` on this platform → faithful `wrapping_sub`. Utility/callees (not in `msgtab`); still-C callers `s_bsd.c`/`ircd.c` + Rust `list.rs` resolve to the Rust defs at link. Gate: **L1 only** (`res_walk_diff`: two fully-isolated `World`s of fn-pointers + `first`/`last`/`reinfo` base pointers — del_queries head/middle/tail match + absent-cp no-op + all-match drain; timeout future-survive (min `tout`) / exhausted ASYNC_CONF·ASYNC_CLIENT (ClearDNS clears the DNS bit only)·ASYNC_CONNECT / retry back-off (resend=0 → `resend_query` no-op) / a mixed survivor+reaped+retried walk — return value, queue shape, `re_timeouts` all diffed; `timeofday` pinned, `adfd=-1` + BSS-zero `svchans` neutralize the variadic notifies, process LOCK serializes; zero diff over 9 tests). No L2/S2S (resolver inert under `NO_DNS_LOOKUP`, the queue never populates at runtime; `golden_s_dns` + `golden_registration` confirm the still-C resolver calls the Rust walkers without regression). **Still C in `res.c`:** only the answer parser + socket I/O half (`send_res_msg`/`do_query_*`/`query_name`/`resend_query`/`proc_answer`/`get_res`/`gethost_*`/`init_resolver`/`cres_mem`).
- **P6w DONE: `res.c` `bad_hostname`** (the pure RESTRICT_HOSTNAMES character validator used by the still-C answer parser `proc_answer`) — the next bottom-up leaf of the resolver proper, ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_HOSTNAME_P6w`; a new three-way `RES_HOSTNAME_LINKAGE` seam: `extern` in res_link.o so still-C `proc_answer` resolves to the Rust def, GLOBAL in the cref oracle under `-DRES_CACHE_EXPOSE` for `cref_bad_hostname`, static otherwise). Utility/callee (not in msgtab — called only from `proc_answer`). Faithful to the compiled body (`HOSTNAMES_UNDERSCORE` off): the for-increment-on-`continue` semantics + the `isalnum`/`s[1]` short-circuit ordering. Gate: L1 (`res_bad_hostname_diff`: a hostname corpus × every prefix length 0..=len+1, asserting identical return; valid names, hyphen/dot edge cases incl. the `len==1` trailing-hyphen guard, illegal chars space/`_`/`/`/`*`/`:`/control/high-bit, and the `len` boundary). No L2/S2S path (unreachable without the still-C answer parser).
- **P6x DONE: `res.c` `cres_mem`** (the DNS-cache memory-usage reporter, called from `s_debug.c`'s `count_memory` via `STATS z`) — the next bottom-up leaf of the resolver proper, ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_CRES_MEM_P6x`). Unlike the file-static cache/queue leaves, `cres_mem` is **exported** (res_ext.h) → the cref oracle already carries `cref_cres_mem`, so **no `RES_*_LINKAGE`/`*_EXPOSE` seam was needed** — the guard just drops the C body and the Rust def resolves it for `count_memory` at link. Utility/callee (not in `msgtab`). Faithful to the `nm += i - 1` **unsigned modular** arithmetic (0 aliases → `i==0` wraps −1, cancelled by the following `+= sizeof(char*)`; reproduced with `wrapping_add`) and the `%d`-on-`u_long` format quirk. Gates: L1 (`res_cres_mem_diff`: two-world return-value + RPL_STATSDEBUG sendQ byte diff over empty/0-alias-wrap/multi-alias/null-name/multi-entry caches — the per-entry summation the empty boot cache never exercises) + L2 (`golden_debug::stats_memory_match_reference`, STATS z, stays green). No S2S (oper STATS only, no `IsServer`/remote-field path).
- **P6y DONE: `res.c` `send_res_msg`** (the resolver UDP datagram-send leaf — the bottom of the send tree `do_query_*`/`resend_query`→`query_name`→`send_res_msg`) — ported to `ircd-common/res.rs` via `res_link.o` (`-DPORT_RES_SEND_P6y`; a new three-way `RES_SEND_LINKAGE` seam de-statics it: extern in res_link.o so the still-C `query_name` resolves the Rust def at link, GLOBAL in the cref oracle for `cref_send_res_msg`). Reads the Rust `ircd_res` (P6p) + the s_bsd.c `resfd` global; fans `msg[0..len]` to `max=MIN(nscount,rcount)` nameservers (clamped to 1 on `RES_PRIMARY`, floored to 1), bumping `reinfo.re_sent` only on a full-length `sendto`. Utility/callee (not in msgtab; only `query_name` calls it). Gate: L1 (`res_send_msg_diff`: two isolated `World`s each with own loopback `::1` UDP recv+send sockets; single-send / NULL-msg / rcount=0 floor / RES_PRIMARY override / two-nameserver / bad-resfd cases diffed on `{ret, datagram bytes, re_sent delta, family}`). No L2 (DNS path disabled project-wide via `NO_DNS_LOOKUP`; boot goldens stay byte-identical), no S2S.
- **P6z DONE: `res.c` `query_name`** (the DNS query builder/sender — the leaf above the P6y `send_res_msg`: `do_query_name`/`do_query_number`/`resend_query`/`get_res` call it) — ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_QUERY_P6z`; a new three-way `RES_QUERY_LINKAGE` seam de-statics it: extern in res_link.o so the still-C callers resolve the Rust def at link, GLOBAL in the cref oracle for `cref_query_name`). Builds the query into a `MAXPACKET` buffer via the Rust `ircd_res_mkquery` (P6o), picks a DNS id that doesn't collide with the outstanding-request queue (`do { nstmp = ntohs(hptr->id)+k + (tv.tv_usec & 0xffff); … } while (find_id(...))` — LRAND48 off → `gettimeofday`-seeded), records `id`/`sends++`/`sent` on the `ResRQ`, and fans the packet via `send_res_msg` (P6y); `r<=0` → `h_errno=NO_RECOVERY` return `r`, send `-1` → `h_errno=TRY_AGAIN` (with `sends` already bumped). Utility/callee (not in `msgtab`). Gate: L1 (`res_query_name_diff`: two isolated `World`s each with own loopback `::1` UDP recv+send sockets + `ircd_res`/`reinfo`/`resfd`/`first` base pointers; a **strong interposed `gettimeofday`** pins the id randomization so packets are byte-identical between worlds + the `find_id` collision loop is deterministic — A-record/PTR queries, a forced one-collision id advance vs the no-collision inverse, mkquery-failure NO_RECOVERY no-send, send-failure TRY_AGAIN with `sends` still bumped; diffed on `{ret, datagram bytes, rptr.{id,sends,sent}, re_sent delta, h_errno}`). No L2 (DNS path disabled project-wide via `NO_DNS_LOOKUP`; boot goldens `golden_registration`/`golden_s_dns` stay byte-identical — the still-C resolver calls the Rust `query_name`), no S2S. **Still C in `res.c`:** the answer parser + socket I/O (`do_query_name`/`do_query_number`/`resend_query`/`proc_answer`/`get_res`/`gethost_*`/`init_resolver`).
- **P6aa DONE: `res.c` `do_query_name`/`do_query_number` (the query-dispatch layer)** — the next bottom-up cluster of the resolver proper, above the Rust `query_name` (P6z) and below the still-C `gethost_*`/`get_res`/`resend_query` callers. `do_query_name` builds the forward-lookup hostname (truncate to `HOSTLEN`, append `ircd_res.defdname` on the dotless+`RES_DEFNAMES` resend path), `do_query_number` builds the reverse-lookup name (IPv4-mapped → `d.d.d.d.in-addr.arpa.`, else the 32-nibble `…ip6.arpa.` form); both allocate the `ResRQ` via `make_request` (P6u) when none was passed, then call the Rust `query_name` (P6z). Ported to `ircd-common/res.rs` via `res_link.o` (`-DPORT_RES_DOQUERY_P6aa`) + a new three-way `RES_DOQUERY_LINKAGE` (extern in res_link.o / GLOBAL in the cref oracle / static otherwise). Utility/callee leaf (not in `msgtab`), inert under `NO_DNS_LOOKUP` → **L1 is the gate** (`res_do_query_diff`, 7 tests, zero diff over a loopback UDP harness with `gettimeofday` interposed; fresh-vs-resend, domain-append vs already-dotted, overlong-defdname `-1`, all three reverse-name arms, resend no-alloc). No L2/S2S (no `IsServer`/remote-field path; `golden_s_dns`+`golden_registration` stay green).
- **P6bb DONE: `res.c` `gethost_byname_type`/`gethost_byname`/`gethost_byaddr`** (the public host-lookup entry points, the layer above the cache lookup + query dispatch) — ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_GETHOST_P6bb`). **No linkage seam** — they are exported `res_ext.h` symbols, so the `cref_*` oracle already exists (like P6x `cres_mem`). Each bumps a lookup counter (`re_na_look`/`re_nu_look`), consults the Rust cache (`find_cache_name`/`find_cache_number`), and on a miss fires the Rust `do_query_name`/`do_query_number` when `lp != NULL` (else returns NULL). `gethost_byaddr`'s only caller (`s_bsd.c`) is gated behind `NO_DNS_LOOKUP`'s `#else` → compiled out of the locked binary (ported + L1-verified regardless). Utility/leaf — none in `msgtab` → **L1 only**. L1 (`res_gethost_diff`, 8 cases): two isolated cache+query worlds (live vs cref) over the cache globals + resolver-query globals, each with a loopback `::1` UDP recv socket + pinned `gettimeofday`; branch matrix + inverses (bad-type early-out, cache HIT vs MISS, `lp==NULL` short-circuit vs `lp!=NULL` AAAA/PTR query issue, byname→T_AAAA delegation, `re_na_look` vs `re_nu_look` split). No S2S (resolver is inert under `NO_DNS_LOOKUP`; no IsServer/remote-field path).
- **P6cc DONE: `res.c` `resend_query`** (the DNS request-retry dispatcher) — ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_RESEND_P6cc`); the next bottom-up unit above the P6aa query-dispatch layer (`do_query_name`/`do_query_number`) and below the still-C `get_res`. Upstream file-static → the P6v `RES_RESEND_LINKAGE` seam promoted to the standard three-way shape (`extern` in res_link.o, GLOBAL in the cref oracle → `cref_resend_query` for L1, else static). A no-op when `resend==0`, else bumps `reinfo.re_resends` and re-dispatches by record type (`T_PTR`→`do_query_number`, `T_A`/`T_AAAA`→`do_query_name`, default→no-op). Utility/callee (file-static, not in msgtab; callers = Rust `timeout_query_list` + still-C `get_res`). L1 gate (`res_resend_query_diff`: two isolated cache+query worlds over a loopback UDP harness with `gettimeofday` pinned; matrix = `resend==0` no-op / `T_A` dispatch / `T_PTR` dispatch / default-arm counter-only). No L2 (resolver is dead code under `NO_DNS_LOOKUP`). No S2S. **Still C in res.c:** only `proc_answer`/`get_res`/`init_resolver`.
=====P6 LOG TAIL=====
  - **Cluster choice** — `bad_hostname` (res.c:1832), the pure hostname-character validator used by the answer parser `proc_answer` (res.c:802,851) to reject malformed PTR/A results. No socket, no globals, no allocation — the cleanest remaining `res.c` leaf to extract before the socket/answer-parser core. Single function → atomic cluster.
  - **Config-resolved body** — `RESTRICT_HOSTNAMES` is defined (cbuild/config.h:608), `HOSTNAMES_UNDERSCORE` is not. So the compiled body is the restrictive branch *without* the underscore escape hatch: `isalnum` ok; interior hyphen ok unless leading / after-dot / trailing (`len==1`) / before-dot; `.` ok unless leading or doubled; else `-1`.
  - **Guard / seam** — upstream file-static, so a new three-way `RES_HOSTNAME_LINKAGE` (mirroring P6q/P6r/P6s `RES_CACHE_LINKAGE`): `extern` when building res_link.o (`-DPORT_RES_HOSTNAME_P6w`, body `#ifndef`'d out → Rust def wins, still-C `proc_answer` resolves at link), GLOBAL in the cref oracle (`-DRES_CACHE_EXPOSE` → `cref_bad_hostname` for L1), `static` in the plain build. Applied to the forward decl (res.c:132) + the definition. `build.rs` appends `-DPORT_RES_HOSTNAME_P6w` to the res_link.o compile line.
  - **Faithfulness notes** — the C `for (s=name; (c=*s) && len; s++, len--)` runs the `s++, len--` increment on every `continue` (C `continue` jumps to the increment) and never falls through to it (each path `continue`s or `return -1`s); the Rust port advances `s`/`len` *before* each `continue` and skips it on the `-1` exit. `isalnum(c)` is called as `libc::isalnum(c as c_int)` with the same (signed-char-promoted) value → byte-identical shared-libc table lookup. `s[1]` is read only when `len != 1` — the Rust `&&` short-circuits identically, so `*s.add(1)` is never evaluated at the cap.
  - **Classification** — utility/callee TU (not in `msgtab`; called only from the still-C `proc_answer`). **L1 is the gate.** No client command reaches it under the locked config without the still-C answer parser running.
  - **L1** — `ircd-testkit/tests/res_bad_hostname_diff.rs`: declare `c_bad_hostname` (`#[link_name="bad_hostname"]` → Rust def via res_link.o) + `cref_bad_hostname` (oracle), drive both over a corpus × every prefix length `0..=len+1` (the `len` cap is load-bearing — only the first `len` bytes are scanned) and assert identical return. Covers valid names (incl. punycode interior double hyphen), hyphen edge cases (leading/trailing/after-dot/before-dot + the `len==1` trailing-hyphen guard), dot edge cases (leading/trailing/doubled), illegal chars (space, underscore, `/`, `*`, `:`, control `\x07`, high-bit), and the `len` boundary (illegal char at `len` vs `len-1`, `len==0`, empty string). 6 tests, zero diff.
  - **S2S** — no path (the function is unreachable without the still-C answer parser; no `IsServer`/remote-field/propagation path exists).

- **2026-06-05 — P6x (`res.c` `cres_mem`) merged.** The DNS-cache memory-usage reporter — the next bottom-up leaf of the `res.c` resolver proper, ported to `ircd-common/src/res.rs`.
  - **Cluster choice** — `cres_mem(aClient *sptr, char *nick)` (res.c:1810): walks the hostent cache list (`cachetop`, via `list_next`) summing each `aCache`/`hostent`'s struct bytes (`sm`), IP storage (`im` — `sizeof(char*)+sizeof(struct IN_ADDR)` per addr, +1 for the NULL terminator) and name storage (`nm` — `sizeof(char*)+strlen` per alias, then the `i-1`/`+sizeof(char*)` tail, then `strlen(h_name)`); `ts = ARES_CACSIZE(1009) * sizeof(CacheTable)(16) = 16144`; sends two RPL_STATSDEBUG (249) lines and returns `ts+sm+im+nm`.
  - **Seam / Guard** — `cres_mem` is **non-static**, exported in `res_ext.h`, so the cref oracle already carries `cref_cres_mem` → **no new `RES_*_LINKAGE`/`*_EXPOSE` seam** (contrast the file-static cache/queue leaves P6q–P6w). `#ifndef PORT_RES_CRES_MEM_P6x` wraps the C body; `ircd-sys/build.rs` adds `-DPORT_RES_CRES_MEM_P6x` to the `res_link.o` compile so the body is dropped and the Rust `#[no_mangle] cres_mem` resolves it for `s_debug.c`'s `count_memory` at link. The cref oracle `res.o` is untouched.
  - **Config-resolved body** — DEBUG off; the whole body compiles unconditionally. `me` (bindgen `static mut me`) read for the server name; `sendto_one` via the existing res.rs variadic extern.
  - **Faithfulness notes** — the `nm += i - 1` step is **unsigned modular** arithmetic: with 0 aliases `i == 0`, so it adds `(int)-1` widened to `u_long` (= `u_long::MAX`, i.e. `nm -= 1`), and the following `nm += sizeof(char*)` nets `+7`. Reproduced with `wrapping_add` throughout the `nm` accumulation so it may transit `u_long::MAX` without a debug-mode overflow panic. The `%d` format applied to the `u_long` args (`ts`/`sm`/`im`/`nm`) is preserved verbatim (reads the low 32 bits) — the values pass as `u_long` so the live trampoline and `cref_sendto_one` push identical bytes.
  - **Classification** — utility/callee (not in `msgtab`); reached from `count_memory` via `STATS z`. Read-only on the cache.
  - **L1** (`ircd-testkit/tests/res_cres_mem_diff.rs`) — two-world (LIVE over `cachetop`/`me`/the Rust `cres_mem`; CREF over `cref_cachetop`/`cref_me`/`cref_cres_mem`) build of identical caches + a buffering local client (`make_client`, P2) per world with a pinned `me.name`. Diffs **both** the return value and the **sendQ bytes** (the two RPL lines). Cases: empty cache (return == `ts` = 16144, `Structs 0 IP storage 0 Name storage 0`); single entry / **0 aliases** (the `nm += i-1` wrap → `+7`); single entry / 3 aliases / 2 addrs; NULL `h_name` (trailing `strlen` skipped); 3 entries (`sm` scales per node). Hand-computed totals match the cref oracle. Zero diff.
  - **L2** — already covered by `golden_debug::stats_memory_match_reference` (STATS z → `count_memory` → `cres_mem`); stays green (empty boot cache under NO_DNS_LOOKUP → `ts`-only walk).
  - **S2S** — none. No `IsServer`/remote-field path (oper STATS only).
  - **Still C in res.c** — the socket/answer-parser core only: `send_res_msg`/`do_query_*`/`query_name`/`resend_query`/`proc_answer`/`get_res`/`gethost_*`/`init_resolver`.

- **2026-06-05 — P6y (`res.c` send_res_msg) merged.** The resolver UDP datagram-send leaf — the literal bottom of the send tree (`do_query_name`/`do_query_number`/`resend_query` → `query_name` → `send_res_msg`). Continues the bottom-up `res.c` resolver-proper port; after this only the answer-parser + socket-I/O core remains C (`query_name`/`do_query_*`/`resend_query`/`proc_answer`/`get_res`/`gethost_*`/`init_resolver`).
  - **Seam.** `send_res_msg` is upstream file-static → new three-way `RES_SEND_LINKAGE` (same shape as `RES_RESEND_LINKAGE`/`RES_HOSTNAME_LINKAGE`): `extern` in res_link.o (`-DPORT_RES_SEND_P6y`; body `#ifndef`-dropped, Rust defines it, the still-C `query_name` resolves at link), GLOBAL in the cref oracle (`-DRES_CACHE_EXPOSE` → `cref_send_res_msg` for L1), else `static`. The resolver socket fd `resfd` it sends on is a real exported global (`s_bsd_ext.h`) — declared extern in res.rs, no extra seam; `ircd_res` is the Rust res_init.rs global (P6p).
  - **Config-resolved body / faithfulness.** `max = MIN(nscount, rcount)`, overridden to 1 on `RES_PRIMARY` (=16), then floored to 1 — the clamp order is load-bearing (`rcount=0` → 1 send; `RES_PRIMARY` with nscount=3 → 1 send). Each iteration force-sets `nsaddr_list[i].sin6_family = AF_INET6` (=AFINET) then `sendto(resfd, msg, len, 0, &nsaddr_list[i], sizeof(sockaddr_in6))`; `reinfo.re_sent`/`sent` bump **only** on a full-length send (`== len`); the DEBUGMODE-off failure branch is a no-op. Returns `sent`, or -1 on NULL msg / all-failed.
  - **Classification.** Utility/callee — not in `msgtab`; only caller is `query_name` (res.c). No client command reaches it under the locked config (`NO_DNS_LOOKUP` disables the DNS path).
  - **L1.** `ircd-testkit/tests/res_send_msg_diff.rs`: two fully isolated `World`s (LIVE via `#[link_name]` → Rust over res_link.o/res_init globals; CREF via `cref_*`). Each world+scenario binds its own loopback (`::1`) UDP recv socket(s) with a 300ms `SO_RCVTIMEO` + its own send socket, points `ircd_res.nsaddr_list[]` at the recv port(s), zeroes `reinfo.re_sent`, drives `send_res_msg`, then `recvfrom`s and snapshots `{return value, datagram bytes received, re_sent delta, nsaddr_list[0].sin6_family}`. Six cases diff byte-identical: single-nameserver one-send; NULL msg → -1/no send; `rcount=0` floor-to-1; `RES_PRIMARY` (nscount=2) override-to-1 (only ns[0] receives); two-nameserver both-receive; bad `resfd` (-1) → all sends fail → -1, counter untouched.
  - **L2/S2S.** None. No DNS command path under `NO_DNS_LOOKUP`; boot/registration (`golden_registration`) and oper-DNS (`golden_s_dns`) goldens stay byte-identical, confirming the dropped C body doesn't perturb the binary. No `IsServer`/remote-field path.

- **2026-06-05 — P6z (`res.c` `query_name` — the DNS query builder/sender) merged.** The next bottom-up leaf of the resolver proper, sitting directly above the P6y `send_res_msg` leaf in the send tree. Ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_QUERY_P6z`).
  - **Cluster choice** — `static int query_name(char *name, int class, int type, ResRQ *rptr)` (res.c:618). Its only callees are already Rust: `ircd_res_mkquery` (P6o), `find_id` (P6u), `send_res_msg` (P6y). Its callers are still C: `do_query_name`/`do_query_number`/`resend_query`/`get_res`. So it is the next clean leaf up the tree.
  - **Linkage / seam** — upstream file-static → new three-way `RES_QUERY_LINKAGE` (mirrors `RES_SEND_LINKAGE`): `extern` under `-DPORT_RES_QUERY_P6z` (res_link.o body `#ifdef`'d out → Rust def; still-C `do_query_*`/`get_res` resolve at link), GLOBAL under `-DRES_CACHE_EXPOSE` (cref oracle → `cref_query_name` for L1), static otherwise. No new data-global seam — it touches only `ircd_res`/`resfd`/`first`/`reinfo`, all already exposed (P6p/P6u/P6y). (Gotcha hit while writing the C comment: `do_query_*/` contains a literal `*/` that closes the block comment early → reworded to `do_query_name/do_query_number`.)
  - **Config-resolved body** — `LRAND48` absent from `cbuild/setup.h`/`config.h` → the id source is `gettimeofday(&tv,NULL)` + `tv.tv_usec & 0xffff` (the `lrand48()` branch is dead); `DEBUG` off → no `Debug()` trace. `MAXPACKET=1024`, `QUERY=0`, `NO_RECOVERY=3`, `TRY_AGAIN=2`. `reslist.sends` is a signed `char` → `sends++` is an `i8` `wrapping_add`, sign-extended to `int` as `send_res_msg`'s `rcount`. `hptr->id` is the HEADER 16-bit bitfield → `(*hp).id()`/`set_id` (stored big-endian; `ntohs`=`u16::from_be`), the res_mkquery.rs:84 pattern. The do/while collision loop is a faithful `loop { …; k += 1; if find_id(...).is_null() { break } }`.
  - **Classification** — utility/callee leaf, **not in `msgtab`**; reachable only through the still-C resolver entry points, inert project-wide under `NO_DNS_LOOKUP`. **L1 is the gate.**
  - **L1** — `ircd-testkit/tests/res_query_name_diff.rs`: two fully-isolated `World`s (LIVE = Rust port over res_link.o/res_init globals; CREF = `cref_*` oracle), each with its own loopback `::1` UDP recv+send sockets + `ircd_res`/`reinfo`/`resfd`/`first` base pointers (the `res_send_msg_diff.rs` shape). **Determinism via a strong interposed `#[no_mangle] gettimeofday`** returning a fixed `tv` — both worlds (the Rust `libc::gettimeofday` call and the cref-archive call) resolve to it at link, so packets are byte-identical **including the id field** and the `find_id` collision loop is reproducible (`ircd_res.id` pinned to 0 → mkquery writes `htons(1)`, first computed id = `1 + (tv_usec & 0xffff)`). Diff on `{ret, datagram bytes, rptr.{id,sends,sent}, re_sent delta, h_errno}` over: A-record query (1 send, id == header id, sends 0→1), PTR query (qtype trailer == T_PTR), a forced one-collision id advance (seed the queue with a node whose id == the first computed id) vs the no-collision inverse (k stays 0 → id == first computed) with the exact second-iteration id checked against the C formula, mkquery-failure (300-char single label → dn_comp fails → `r<=0`, NO_RECOVERY, no send, `sends`/`sent`/`re_sent` untouched), and send-failure (`resfd=-1` → `send_res_msg` -1 → TRY_AGAIN, but `sends` **still** bumped before the send, `sent`/`re_sent` untouched). Zero diff over 5 tests.
  - **L2 / S2S** — none. The DNS path is disabled project-wide via `NO_DNS_LOOKUP`; the boot goldens `golden_registration` + `golden_s_dns` stay byte-identical, confirming the still-C resolver calls the Rust `query_name` without regression. End-to-end DNS coverage arrives when the resolver proper (answer parser + socket I/O) is ported under a fixture nameserver.

- **2026-06-05 — P6aa (`res.c` query-dispatch layer `do_query_name`/`do_query_number`) merged.** The next bottom-up cluster of the still-C `res.c` resolver proper, sitting directly above the P6z `query_name` leaf and below the still-C `gethost_*`/`get_res`/`resend_query` callers.
  - **Cluster choice.** `do_query_name` (res.c:541) builds the forward-lookup hostname and `do_query_number` (res.c:580) builds the reverse-lookup name; both allocate the `ResRQ` via `make_request` (P6u) when none was passed and then call `query_name` (P6z) — all three callees are already Rust, so this is the clean next leaf up the send tree. `resend_query` (which dispatches to both) is the next unit *above* and stays C this bite (now calling the Rust do_query_*).
  - **Guard / seam.** `res_link.o` gains `-DPORT_RES_DOQUERY_P6aa`. Both functions are upstream file-static → a new three-way `RES_DOQUERY_LINKAGE` (mirrors `RES_QUERY_LINKAGE`): `extern` under `PORT_RES_DOQUERY_P6aa` (res_link.o — the two bodies `#ifndef`'d out, Rust defines them, the still-C callers `gethost_byname_type`/`gethost_byaddr`/`get_res`/`resend_query` resolve at link), GLOBAL under `RES_CACHE_EXPOSE` (cref oracle — `cref_do_query_name`/`cref_do_query_number` for L1), else `static`. No new data-global seam — they touch only `ircd_res`/`first`/`last`/`reinfo`/`resfd`, all already exposed (P6p/P6u/P6y). (Gotcha re-hit from P6z: a `gethost_*/` in the macro comment closes the block comment early via the literal `*/` — reworded to spell out the caller names.)
  - **Config-resolved body.** `AFINET=AF_INET6` → `rptr->addr`/`he.h_addr` are `in6_addr` (16 bytes); `IN6ADDRSZ` = `sizeof(struct IN_ADDR)` = 16. `RES_DEFNAMES = 0x80` (resolv_def.h). DEBUG off → the `Debug((…))` trace drops out. `strncpyzt(x,y,N)` = `strncpy(x,y,N); x[N-1]=0` (struct_def.h:871); `HOSTLEN=63` → `hname[HOSTLEN+1]` = `[c_char; 64]`. `index`=`strchr`; `MyMalloc` returns `*mut c_char`.
  - **Faithfulness notes.** The domain-append branch is gated on `rptr != NULL` (the resend path) in the C — faithful: a *fresh* `do_query_name` (rptr==NULL) never appends `defdname`, and stores the **original** (un-truncated/un-appended) `name`, not `hname`. `do_query_number`'s two `sprintf` branches are reproduced by building the exact byte string in Rust (`{}` decimal for the IPv4 form, single-nibble lowercase `{:x}` for the ip6.arpa form, byte-reversed low-then-high nibble) and `copy_nonoverlapping` into the C `ipbuf`; `bcopy` → `copy_nonoverlapping`; `&rptr->he.h_addr` = `&he.h_addr_list[0]`.
  - **Classification.** Utility/callee leaf — neither in `msgtab`; reachable only through the still-C resolver entry points, inert project-wide under `NO_DNS_LOOKUP`. → **L1 only, NO L2, NO S2S** (no `IsServer`/remote-field path).
  - **L1.** `ircd-testkit/tests/res_do_query_diff.rs` — two fully-isolated `World`s (LIVE `#[link_name]` → the Rust port over the res_link.o/res_init globals; CREF `cref_*` over the renamed oracle), each with its own loopback `::1` UDP recv+send sockets + `ircd_res`/`reinfo`/`resfd`/`first`/`last` base pointers (the `res_query_name_diff.rs` shape). A strong interposed `gettimeofday` pins `query_name`'s id randomization so packets are byte-identical including the id. Diffs `{ret, datagram bytes, the resulting ResRQ (type/name/id/sends/sent), he.h_addr bytes, he.h_length, addr bytes, re_sent delta, h_errno}` over 7 tests: do_query_name fresh (original name stored verbatim, no append, 1 send); do_query_name resend + RES_DEFNAMES (`.example.org` appended → longer packet) vs the already-dotted inverse (no append); the overlong-defdname overflow → -1/no send; do_query_number IPv4-mapped (`::ffff:127.0.0.1` → `in-addr.arpa`, `he.h_addr`/`addr`/`he.h_length=16` seeded) + the all-zero-prefix arm + the full-IPv6 `ip6.arpa` nibble form; and do_query_number resend (no make_request, he/addr untouched, queue stays empty). Zero diff. `do_query_name`/`do_query_number` confirmed `T` (Rust-defined) in `target/debug/ircd`.
  - **L2/S2S.** None (see Classification). `cargo test -p ircd-golden` `golden_s_dns` (2) + `golden_registration` (2) stay byte-identical — the still-C `gethost_*`/`get_res`/`resend_query` call the Rust do_query_* without boot regression. 0 warnings.
  - **Still C in `res.c`.** Only the answer parser + remaining socket I/O: `resend_query`/`proc_answer`/`get_res`/`gethost_byname`/`gethost_byname_type`/`gethost_byaddr`/`init_resolver`.

- **2026-06-05 — P6bb (`res.c` `gethost_byname_type`/`gethost_byname`/`gethost_byaddr`) merged.** The public host-lookup entry points — the next bottom-up cluster of the resolver proper, sitting directly above the Rust `find_cache_*` (P6s) + `do_query_*` (P6aa) and below the still-C `get_res`/`s_bsd` callers.
  - **Cluster choice.** The three exported lookup fns are thin dispatchers: bump a counter → try the cache → on a miss issue an async query (when a client `lp` is present) or give up. They depend only on already-ported Rust (`find_cache_name`/`find_cache_number`, `do_query_name`/`do_query_number`), so they are the clean next leaf above the do_query layer.
  - **Mechanism / no seam.** Ported into `ircd-common/res.rs`; `res_link.o` drops the C bodies via `-DPORT_RES_GETHOST_P6bb`. Because all three are exported `res_ext.h` symbols (not file-statics), **no linkage seam is needed** — the cref oracle's unguarded `res.o` already exports `cref_gethost_*` for L1 (same pattern as P6x `cres_mem`).
  - **Config-resolved body.** `DEBUG` off → the `Debug(...)` trace in the miss path vanishes. `gethost_byname` delegates with `T_AAAA` (AFINET=AF_INET6 → IPv6-first; `get_res` falls back to `T_A`). `gethost_byname_type` rejects any non-`T_A`/`T_AAAA` type with NULL **after** bumping `re_na_look`; the cache flag is `FLG_AAAA_VALID`/`FLG_A_VALID` by type. `gethost_byaddr` gates the number cache on `FLG_PTR_VALID` (via `find_cache_number`). `(struct hostent *)&(cp->he)` → `addr_of_mut!((*cp).he)` (already `*mut hostent`, no cast).
  - **Faithfulness.** Counter bump precedes the type guard; cache consulted before any query; `lp == NULL` short-circuits to NULL before `do_query_*`; the async query path always returns NULL (the result arrives later via `get_res`).
  - **Compiled-out caller.** `gethost_byaddr`'s sole C caller (`s_bsd.c:1681`) lives in the `#else` of `#ifdef NO_DNS_LOOKUP`; the project builds with `NO_DNS_LOOKUP`, so the call is compiled out and the linker omits the (unreferenced) Rust fn from the `ircd` binary. It is still ported faithfully and L1-verified — `nm` confirms `gethost_byname`/`gethost_byname_type` resolve to Rust (`T`) in the binary; `gethost_byaddr` simply has no caller to pull it in.
  - **Classification.** Utility/leaf — none in `msgtab` → **L1 only**. No `IsServer`/remote-field path; the resolver is inert under `NO_DNS_LOOKUP`, so no client/server command reaches these at runtime.
  - **L1.** `ircd-testkit/tests/res_gethost_diff.rs` (8 cases, zero diff). Two fully isolated worlds (live `#[link_name]` Rust port vs `cref_*` oracle) spanning **both** the DNS cache globals (`cachetop`/`hashtable`/`cainfo`) and the resolver query globals (`ircd_res`/`reinfo`/`resfd`/`first`/`last`), each binding its own loopback `::1` UDP recv socket + a pinned `gettimeofday` (deterministic query id, matching res_do_query_diff). Branch matrix + inverses: bad-type early-out (re_na_look bumped, cache untouched, no query), cache HIT (returns `&he`, `ca_na_hits`/`ca_nu_hits` bumped, no datagram) vs MISS, `lp==NULL` short-circuit vs `lp!=NULL` async query (AAAA datagram + queued `T_AAAA` node for byname; PTR/`ip6.arpa` datagram + queued `T_PTR` node for byaddr), the byname→byname_type(T_AAAA) delegation, and the `re_na_look` (byname) vs `re_nu_look` (byaddr) split.
  - **S2S.** None — no server-reachable path (see Classification).

- **2026-06-05 — P6cc (`res.c` `resend_query`) merged.** The DNS request-retry dispatcher — the next bottom-up unit of the still-C resolver proper, sitting directly above the P6aa query-dispatch layer (`do_query_name`/`do_query_number`) and below the still-C `get_res`. Ported to `ircd-common/res.rs` via the `res_link.o` partial port (`-DPORT_RES_RESEND_P6cc`); after this only the answer parser + socket I/O remain C (`proc_answer`/`get_res`/`init_resolver`).
  - **Cluster choice.** `RES_RESEND_LINKAGE void resend_query(ResRQ *rptr)` (res.c:703). Its callees are all already Rust — `do_query_number`/`do_query_name` (P6aa) → `query_name` (P6z) → `send_res_msg` (P6y) — so it is the clean next leaf up the tree. Its callers are the Rust `timeout_query_list` (P6v, the retry branch) and the still-C `get_res` (res.c:1149, on a truncated/failed reply).
  - **Seam.** `resend_query` is upstream file-static. The `RES_RESEND_LINKAGE` macro already existed (P6v, where it was 2-way: `extern` under `PORT_RES_WALK_P6v` to satisfy the Rust `timeout_query_list`, else `static`). P6cc promotes it to the standard three-way shape (mirrors `RES_QUERY_LINKAGE`/`RES_DOQUERY_LINKAGE`): `extern` under `PORT_RES_RESEND_P6cc` (res_link.o — the body `#ifndef`'d out, Rust defines it, the still-C `get_res` + the Rust `timeout_query_list` resolve at link), GLOBAL under `RES_CACHE_EXPOSE` (cref oracle → `cref_resend_query` for L1), else `static`. res_link.o sets both `PORT_RES_WALK_P6v` and `PORT_RES_RESEND_P6cc`; the P6cc arm is ordered first so it wins (the legacy P6v arm is kept for clarity but superseded). No new data-global seam — it touches only `reinfo`/`first`/`last`/`ircd_res`/`resfd`, all already exposed (P6p/P6u/P6y).
  - **Config-resolved body.** Faithful 1:1 with the C: early-return on `resend == 0`; bump `reinfo.re_resends`; `match (*rptr).type_` on `T_PTR` → `do_query_number(NULL, &rptr->addr, rptr)`, `T_AAAA | T_A` → `do_query_name(NULL, rptr->name, rptr, type)`, `_` → no-op (the counter still bumped before the switch, matching the C ordering). The Rust extern decl for `resend_query` (added in P6v so `timeout_query_list` could call the still-C fn) was removed — the module now *defines* it.
  - **Classification.** Utility/callee (file-static, not in `res_ext.h` → not in `msgtab`). **L1 is the gate.** No L2 path — the resolver is dead code under the locked `NO_DNS_LOOKUP` config (the golden binary never drives a live lookup), same as every P6q–P6bb resolver bite. No S2S (no `IsServer`/remote-field/propagation path).
  - **L1.** `ircd-testkit/tests/res_resend_query_diff.rs` (modeled on `res_do_query_diff.rs`): two fully isolated `World`s (LIVE `#[link_name]` → the Rust port over the res_link.o/res_init globals; CREF `cref_*` → the renamed reference-C oracle), each binding its own loopback `::1` UDP recv+send sockets so the two never cross-talk. `gettimeofday` interposed (fixed `tv`) to pin `query_name`'s id randomization → byte-identical datagrams. Snapshots `{datagram bytes, node.{type,name,id,sends,sent}, re_resends delta, re_sent delta, h_errno}`. Branch matrix + inverses: `resend==0` → no-op (no datagram, zero counter deltas, `sends` untouched); `T_A` → `do_query_name` dispatch (datagram, `re_resends`+1, `re_sent`+1, `sends`+1); `T_PTR` → `do_query_number` dispatch (in-addr.arpa reverse datagram, `re_resends`+1); default (`type=99`) → counter bumps but nothing dispatched (no datagram, `re_sent` delta 0). Zero-diff. The P6v `res_walk_diff` (which calls `resend_query` via `timeout_query_list`, now resolving to the Rust def) + `res_do_query_diff` re-run green.
