name: p0c-l1-harness-constraints description: L1 differential harness (ircd-testkit) design + the cref_-oracle-vs-OBJS split phase 1 must wire metadata: node_type: memory type: project originSessionId: 705a4c1c-df44-45b8-b804-d362decb1bc5#
P0c stood up the L1 differential-unit harness (ircd-testkit crate; PLAN.md "L1"). Merged to master 2026-06-02.
How it works:
ircd-sys/build.rsexportscargo:cbuild=/cargo:objs=over itslinks = "ircd_c"channel → dependents readDEP_IRCD_C_CBUILD/DEP_IRCD_C_OBJS.ircd-testkit/build.rsbuildslibcref.a:nm -g --defined-onlyover theOBJSobjects → rename map<sym> cref_<sym>(sorted+deduped) →objcopy --redefine-symson a copy of each.o→ar crDs(deterministic). Renames defs AND internal refs; libc/zlib/crypt untouched. ~450 symbols from 31 objects (an all-objects prototype incl. version/ctruth showed 509).- Tests link
libcref.a(cref_ reference) beside ircd-sys's whole-archivelibircd_c.a(originals) and diffcref_matchvs originalmatchover a corpus.
Two non-obvious gotchas that bit during implementation (both now documented in ircd-testkit/src/lib.rs):
-
Integration tests need a link anchor. A
tests/file is a separate crate; a build script'scargo:rustc-link-lib(-l cref, and ircd-sys's-l ircd_c) reaches it only by replaying a linked dependency rlib's native libs. A test with only rawexternblocks references no Rust item → rustc drops both rlibs → all C symbols undefined at link. Fix:pub fn link_reference_archives()(referencesircd_sys::c_ircd_main); every L1#[test]must call it first. -
The cref_ oracle list must diverge from
OBJSonce porting starts.libcref.ais built fromDEP_IRCD_C_OBJS==OBJS. If a ported module is just dropped fromOBJS, itscref_<sym>vanishes too → nothing to diff the Rust against → tests fail to LINK (loud, never silently vacuous). Phase-1 wiring task: a module being ported must leave the to-be-RustOBJS(so the Rust#[no_mangle]provides the original name) yet stay in a SEPARATE reference-object list that ircd-sys still compiles + exports for the cref_ oracle. Not done in P0c.
Harness is non-vacuous by construction: every project global is renamed, so match exists only in libircd_c.a and cref_match only in libcref.a (distinct addresses, verified). myncmp self-check uses explicit in-domain (a,b,n) triples because myncmp does its end-of-string check AFTER advancing pointers (common/match.c:316) → OOB read for the empty string with n≥2.
Still unbuilt from PLAN.md's P0: L2 golden (clock-pin + canonicalizer), L3 fuzz (ircd-fuzz), L4 conformance, iauth-rs. See [[rust-migration-plan]], [[p0b-bindgen-constraints]].