P10 — Rename to leveva + typed identifier string types#
P10 is the idiomatic-Rust end state: the workspace is renamed to leveva and gains
validating newtype strings for every IRC identifier class. Greenfield Rust — no cref_
oracle, no extern "C" seam, no ircd-sys dependency. Tests are ordinary Rust unit /
doc tests.
Note: P10 is being started early, before P8/P9, at the user's request — the string foundation is useful to have in place. The crate/binary rename of the
ircd-*crates is still deferred to the real P10 slot (after P8 deletes the C and P9 does the std-lib cleanup).
Entries#
-
2026-06-07 —
levevacrate bootstrapped: RFC 1459 string layer. New workspace memberleveva/(std-only, no deps). Foundation modules:casemap— textbook RFC 1459 case folding:A-Z↔a-zplus the Scandinavian set[↔{ \↔| ]↔} ~↔^(to_lower/to_upperconst fns +eq_ignore_case/cmp/hashbyte-slice helpers). Deliberately differs from the faithful-porttolowertabincommon/match.c, which is ASCII-only — confirmed by reading the C table;levevaimplements the rule the RFC actually specifies (user decision).string—IrcStr(#[repr(transparent)]overstr, one localizedunsafecast like stdPath) andIrcString(String), whoseEq/Ord/Hashare RFC 1459 case-insensitive whileDisplaypreserves original casing.IrcString: Borrow<IrcStr>so it keys aHashMaplooked up by&IrcStr. Construction rejects the framing bytes NUL/CR/LF (IrcError::Forbidden). PlusIrcStringBuilder.ident— validating newtypes aroundIrcString, generated by anident_newtype!macro:Nick(do_nick_name rule: no leading-/digit, notanonymous, NVALID char class, NICKLEN 15),ChanName(#&+!prefix + chanstring, CHANNELLEN 50),Sid/Uid/Cid(exact-length base-36A-Z0-9: 4/9/5),ServerName,UserName(USERLEN 10),HostName(HOSTLEN 63).IdentErrorenum. Grammars grounded incommon/struct_def.h,common/match.c char_atribs,ircd/s_user.c do_nick_name,ircd/s_id.c.message—Message/MessageBuilder:prefix/param(s)/trailing(eachimpl Display, so typed idents pass through) →to_line()and 512-byte-safe CRLFto_wire()(truncation respects UTF-8 char boundaries).- Gate:
cargo test -p leveva— 27 unit + 4 doc tests green;cargo clippy -p levevaclean; 0 warnings. Each identifier type round-trips its legal inputs and rejects every illegal class (the inverse-invariant discipline). Plan:docs/superpowers/plans/2026-06-07-leveva-rfc1459-string.md.
-
2026-06-07 —
leveva::patricia: generic longest-prefix-match trie. Idiomatic, 100% safe Rust descendant ofircd/patricia.c(which was a CIDR-only,void*-valued, raw-pointer/MyMalloctrie). User decisions: generic core + IP helpers, idiomatic Rust API.- Generic over the value
V(novoid*) and over the key — aPrefixis just bytes + a bit length, so the trie serves IP CIDRs, MAC ranges, routing labels, any hierarchical bit key.Prefixmasks insignificant trailing bits on construction, so10.5.0.0/8 == 10.0.0.0/8(correct network identity forEq/Hash). - No
unsafe, no raw pointers. Nodes live in aVec<Option<Node>>arena with a free list; children/parent areOption<usize>indices. The Cnode->bit < maxbitsOOB guard is subsumed bybit_testreading past-end bits as0, which also makes mixed-width keys safe. Removed slots are recycled. - API:
new/insert(→oldOption<V>)/get/get_mut/contains/remove/longest_match/iter(+Default/FromIterator/Extend/IntoIterator/Debug). IP layer:Prefix::{from_ipv4,from_ipv6,from_ip,host},IpCidr(FromStr:"10.0.0.0/8"or bare host;CidrParseError),insert_cidr/get_cidr/remove_cidr/longest_match_ip(impl Into<IpAddr>). - Faithfulness:
insert/search_exact/search_best(inclusive)/removeported from the C algorithms incl. glue-node creation and the three-case removal (two-children → demote to glue; leaf → unlink + fold glue parent; one-child → splice up). Iteration is deterministic left-first pre-order (not claimed byte-identical to the CPATRICIA_WALK). - Gate:
cargo test -p leveva— 17 patricia unit tests + 1 doc test green (full crate 41 unit + 5 doc);cargo clippy -p leveva --all-targetsclean; 0 warnings. Tests pair every positive with its inverse (insert→remove→gone, glue fold + slot reuse, remove-all → empty, longest-match fallback after removal, 256-prefix stress with odd-removal).
- Generic over the value
-
2026-06-07 —
leveva::numeric: theNumericreply/error enum. Pure-data port of the complete numeric table incommon/numeric_def.h(184 codes, 001–759) into a single#[repr(u16)] #[non_exhaustive]enum whose discriminant is the three-digit code, son as u16/Numeric::code()is the wire value directly.- Naming: variants keep the
Rpl/Errprefix with the remainder title-cased (RplWelcome,ErrNosuchnick). The prefix is load-bearing — dropping it would collideRPL_STATSKLINE(216) withERR_STATSKLINE(499), the only such clash in the table. The canonical C symbol is always recoverable viaNumeric::name()("RPL_WELCOME"). - API:
code(),name(),is_error()(the400–599convention),From<Numeric> for u16,TryFrom<u16>(→UnknownNumeric(u16)), and aDisplaythat renders the zero-padded three-digit wire token (001).RPL_WHOISTLSis exposed as an associatedconstaliasingRplWhoisextra(320), mirroring the C#define(a repr enum can't carry a duplicate discriminant). - Gate:
cargo test -p leveva— 8 numeric unit + 1 doc test green; clippy clean; 0 warnings. Tests cover code==discriminant, three-digit padding, name round-trip, known/unknownTryFrom, the STATSKLINE 216-vs-499 distinction, and the WHOISTLS alias.
- Naming: variants keep the
-
2026-06-07 —
leveva::mode: theUserModeandChanModeenums. Pure-data port of the mode tables, grounded inircd/s_user.c,ircd/channel.c, andcommon/struct_def.h.UserMode— the six modes inuser_modes[](o O i w r a), bits from theFLAGS_*constants.as_char/TryFrom<char>,bit/from_bit,flag_name()("FLAGS_OPER"),ALLin table order, andrender(bits)(set letters, table order).ChanMode— all 17 channel mode letters, categorised byChanModeKindintoFlag(p s m n t i a r),Membership(o v O),List(b e I R), andParam(k l).bit()returns theMODE_*value (membership bits double as the lowCHFL_*bits);mode_name()recovers the C symbol;kind()/takes_parameter();render(bits)emits only flag-kind letters inflags[]order (membership/list/param can't be reconstructed from a channel bitmask alone).MODE_QUIET(0x02000) is omitted — it has no mode letter and never appears on the wire.- Grounding caveats:
+I(MODE_INVITE, invite-exception list) is kept distinct from+i(MODE_INVITEONLY);takes_parameter()documents that the oracle still omits the parameter specifically when removing+l(parse behaviour, left to the handler port). - Gate:
cargo test -p leveva— 8 mode unit + 1 doc test green (full crate 56 unit + 7 doc); clippy clean; 0 warnings. Tests cover char/bit round-trips against the oracle values, the fourChanModeKindcategories, and table-orderedrender.
-
2026-06-07 —
leveva::config: KDL-based, typed ircd configuration. The first leveva module with dependencies (kdlv6+v1-fallbackandthiserrorv2 — the exact versionsiauth-rspins, so the lockfile is shared). Replaces the C daemon's pipe-delimited single-letter config (theM/A/Y/P/I/O/C/N/H/L/Klines parsed inircd/config_read.c+ircd/s_conf.c) with a KDL document parsed into a typedConfig. Plan:docs/superpowers/plans/2026-06-07-leveva-config-kdl.md. User decisions: lives inleveva(deps are fine), idiomatic redesign (not a faithful line-mirror), pragmatic core scope.- Idiomatic schema, not a line-mirror:
C+Nmerge into oneconnectblock (send-password/accept-password) withH/Lfolded into arole "hub" "*"/role "leaf"property;I/O-line flag letters become named booleans; theO-lineACL_*flag string becomes anOperPrivilegeenum (20 granular variants, grounded instruct_def.h:1043-1070+ the letter table ins_conf.c:306-383). Tokens"kill"/"squit"/"connect"expand to local+remote;"all"matches the CAletter (everything bar clients/no-penalty/can-flood);ACL_LOCOPis thelocalfield, not a privilege. - Typed by construction: identifier fields (
server.name,server.sid,connectname) parse through leveva'sServerName/Sidnewtypes, so a malformed value is aConfigError::BadFieldat parse time. Glob/CIDR patterns (user@host,*.x) stayString. - Passwords classified, not carried verbatim:
operator/connect/allowpasswords are aPasswordenum (Hashed|Plain). You can't reliably distinguish a hash from plaintext (a 13-char alnum plaintext == a DEScrypt(3)hash), so classification is conservative: a(hash)/(plain)KDL type annotation (read viaentry.ty()) forces the choice — and a declared(hash)is structurally validated, so a typo'd hash is aBadFieldat load, not a failed login; with no annotation, a well-formed Modular Crypt Format value ($id$…) is auto-detected as a hash and everything else (incl. bare DES-13) isPlain.warnings()flags plaintext operator/link passwords. (The C makes this a compile-time choice —CRYPT_OPER_PASSWORD, off in this build — and uses the config password as thecrypt()salt; per-password classification is a deliberate leveva improvement.) - Parsing mirrors
iauth-rs/src/config.rs:src.parse::<KdlDocument>(), walkdoc.nodes()by name, read each leaf as a child node's single positional arg; typed helpers (req_string/opt_string/flag/req_u32/…). Note kdl v6as_integer()returnsi128(range-checked intou16/u32/u64). Scope:server,admin,options,class,listen,allow,operator,connect,ban. Cross-reference validation (everyclassnamed by allow/operator/connect is defined; singletonserver/admin; unique class names) + non-fatalwarnings(). - KDL v2 gotcha: bare
true/falseis illegal in KDL v2 — it only parses via the fragile v1-fallback (which requires the whole document be valid v1, so it works intermittently). Canonical form is#true/#false; a bare node name also means true. Theflag()helper + the example doc this. - Deferred (out of this cut): the rare line types (bounce
B/ versionV/ quarantineQ/ denyD/ gecos-X/ serviceS/ zip-connectc), a KDL writer for rehash round-trip, aMasknewtype, and wiring into the daemon boot path (belongs with the connection/rehash port — this module just parses → typedConfig). - Gate:
cargo test -p leveva— 26 config unit + 1 doc test green (full crate 82 unit- 8 doc);
cargo clippy -p leveva --all-targetsclean; 0 warnings. Worked example atleveva/examples/ircd.kdl(also the happy-path test fixture viainclude_str!); each error variant has a negative test, plus password classification (MCF auto-detect,(plain)override, malformed declared hash, unknown annotation).
- 8 doc);
- Idiomatic schema, not a line-mirror:
-
2026-06-07 —
leveva::messagegains a parser +leveva::matchingglob/hostmask. The two halves of the protocol-text layer that were missing.Message::parse/FromStr— the inverse of the existing builder: a raw line → optional:-prefix, command, space-separated middle params, optional:-trailing. Strips a trailing CRLF, tolerates runs of spaces, keeps a bare:asSome("")(distinct from no trailing), preserves the command verbatim (case left to a futureCommandenum), and round-trips withto_line().ParseError::{Empty, MissingCommand}.leveva::matching— descendant ofmatch()/collapse()(common/match.c).matches(mask, name)supports*,?,#(the IRCnet digit wildcard — so a literal#in a mask matches a digit; use\#), and\-escaping, case-insensitive under leveva's RFC 1459 casemapping (deliberate divergence frommatch.c's ASCII-onlytolowertab, the same call the rest of leveva makes). Greedy*backtracking is linear-time, so the CMAX_ITERATIONScap is unnecessary.collapse()minimizes redundant wildcards (*?*?→*??).HostMask— thenick!user@hostpattern whose three components are matched independently (faithful toBanMatch,ircd/channel.c:49).parse()mirrorsparseNUH(channel.c:1815): split on the first!, then the last@; with no!, the text before@is the nick (a real gotcha —foo@bar⇒ nick=foo, host=bar), and empty components default to*.matches_parts(nick,user,host)is the primary API (the server already has the three components);matches_target("n!u@h")is the convenience.- Gate:
cargo test -p leveva— 8 message + 13 matching unit tests + their doc tests green (full crate 101 unit + 10 doc); clippy--all-targetsclean; 0 warnings. Covers the parse round-trip, empty/extra-space/error cases, each wildcard + escape, the no-catastrophic-backtracking shapes,collapseminimization, and theparseNUHsplit edge cases.
-
2026-06-07 —
leveva::matchingglob parsing moved tonom+ a compiledPattern. Replaced the hand-rolled byte-walker tokenizer with anomparser (nom7, the versionircd-commonalready pins) that compiles a mask into aVec<Tok>. The tokenalt's final any-byte arm makes the parser total, somany0consumes the whole mask without looping. New publicPatterntype (compileonce,is_matchmany) so a ban/host mask checked against many users isn't re-parsed per call;matches()is now the compile-once-match-once convenience over it. Matching semantics are unchanged (*/?/#/\, RFC 1459 case-insensitive, linear greedy-*backtracking);collapse()andHostMaskuntouched. Gate: full crate 103 unit + 11 doc green; clippy clean.