refactor: extract leveva-matching leaf crate (+ proptest fuzzing)
Continue the leaf-crate carve-out (after leveva-casemap / leveva-string /
leveva-message / leveva-patricia / leveva-cidr / leveva-cloak) by moving the IRC
glob matcher + nick!user@host hostmasks out of the monolith into its own
workspace crate:
- leveva-matching: the C match.c cluster (matches / Pattern / collapse / HostMask
/ host_component_matches / allow_host_matches, 498 LoC). The survey-flagged
"natural next pick": once leveva-cidr split, its only intra-crate edges were
casemap::to_lower and cidr::cidr_match — both already crates — plus nom. Deps =
leveva-casemap + leveva-cidr + nom.
Body moved verbatim via git mv; five repoints only: `use crate::casemap;` ->
`use leveva_casemap as casemap;`, `crate::cidr::cidr_match` ->
`leveva_cidr::cidr_match`, the module-header intra-doc link (crate::casemap) ->
(leveva_casemap), and two doctests `use leveva::matching::…` ->
`use leveva_matching::…`. leveva re-exports it as leveva::matching
(`pub use leveva_matching as matching;`), so the flat
`pub use matching::{collapse, matches, HostMask, Pattern};` and all ~13 consumers
(xline / kline / resv / webirc / metadata / registration +
command/{oper,map,mask,hunt,dline,tkline}) keep their crate::matching::* paths.
No dependency cycle — the code edges all run into matching.
Fuzzing: stable toolchain only (no nightly / no cargo-fuzz), so proptest is the
runnable fuzz tier, matching the other leaves. leveva's matcher deliberately
diverges from match.c (RFC 1459 case-fold, not ASCII tolowertab; #=any-digit), so
there is NO byte-faithful differential oracle — the 13 proptest invariants ARE the
gate. Fed arbitrary (incl. non-ASCII) strings + glob masks: totality/no-panic over
every entry point, `*` is universal, `?`^k iff exact byte-length, case-insensitivity
under leveva_casemap::fold of the name, compile == matches, collapse is
matching-preserving + idempotent + non-growing, HostMask re-parses its own Display,
matches_target == matches_parts, allow_host_matches decomposes into user-glob &&
host-component, and a glob host component falls back to matches.
Gate: cargo build --workspace (0 warnings) · cargo clippy --workspace --tests
(clean) · cargo test -p leveva-matching (28 unit/collapse/escaping + 13 fuzz, + 2
doctests) green · leveva matching-consumer tests (xline/kline/resv/webirc, 181) green.
What else can move out: uid (only crate::ident, blocked on extracting ident — ident
itself blocked by a single crate::command reference worth auditing, the next unlock);
msgid pulls cap/clock/ident; clock is a small candidate leaf. Recorded in the plan +
progress log.
feat(p7oo): port c_ircd_main boot spine from ircd.c to Rust — P7 COMPLETE
Port `main` (renamed `c_ircd_main` via `-Dmain=c_ircd_main`, ircd.c:837) to
ircd-common/src/ircd.rs as `#[no_mangle] c_ircd_main`, config-resolved to the
locked build (CHROOTDIR/ZIP_LINKS/CMDLINE_CONFIG/USE_SYSLOG/DEBUGMODE/IRC_UID/
IRC_GID OFF; USE_IAUTH/TKLINE ON; IRCDCONF_DELIMITER='|'): sbrk0/uid setup, the
argv flag-parse loop, the setuid-root guard, the vfork/execl iauth-presence
check, the init*/initconf/listener-scan/M-line/SID/split checks + make_isupport,
setup_me/check_class/ircd_writetune, the BOOT_INETD block, the startup banner,
mysrand/daemonize/logfiles_open/write_pidfile/dbuf_init, and `loop { io_loop() }`.
Guarded out of ircd_link.o by -DPORT_IRCD_MAIN_P7oo; ircd-rs/src/main.rs is
unchanged (still calls ircd_sys::c_ircd_main, which now resolves to the Rust def).
nm confirms `T c_ircd_main` from Rust; ircd_link.o now defines no main/c_ircd_main,
only data globals.
This is the LAST C function with logic. P7 is COMPLETE: all C *logic* is now
Rust; only data globals + the ~25 variadic sender trampolines remain (deleted in
P8 when call sites adopt a non-variadic Rust sender API).
Faithfulness: me.serv->sid is [c_char;5] (an array) so C's `!me.serv->sid` is
always-false dead code — reproduced as a never-taken branch. configfile/tunefile
keep their C static-initializers. vfork kept to match C. flags is c_long,
aConfItem::status is u32.
L2-gated, no L1 (the boot spine forks iauth, daemonizes, never returns — the
P7mm/P7jj precedent): the full ircd-golden suite (86 tests) boots through it
byte-identical vs reference-C. The lone failure (golden_s2s_s_serv_stats "sq"
field) is the documented pre-existing p5-s2s-stats-flake (uninitialized-sendq
garbage), proven not a regression by re-running on clean HEAD.