feat(leveva): caller-id (+g user mode + ACCEPT) — P11 slice 216
Add charybdis-style caller-id ("server-side ignore"): a user sets +g to
receive private PRIVMSG/NOTICE only from clients on their ACCEPT list. A
blocked PRIVMSG bounces 716 to the sender and notifies the target once
(717 to sender + 718 to target); a NOTICE is silently dropped.
The pure CallerId store (accept set + once-per-pair notify gate) lives
inside Registry — the metadata precedent — so it costs no ServerContext
churn; accept entries are stable UIDs (survive nick changes, quit-filtered
on read), capped at 30. +g is purely local (not in SEND_UMODES): the gate
runs on the target's home server, so a transit/origin server needs no copy.
ACCEPT supports add / -remove (mixed) / list (281+282), with 401/456/457/458;
self-accept is a no-op. CALLERID=g advertised in 005; 8 new numerics.
Picked after confirming no clean documented deferral remained open — the
STS-REHASH / S2S-KILL-notice / throttle-knob / MODE+VERSION-proptest /
UTF8ONLY "deferred" doc comments were all stale, closed by later slices.
Remote-sender gating (S2S) and +G soft caller-id are documented follow-ons.
Tests: callerid unit (6), accept (8), message gate (5), numeric round-trip,
isupport token, s2s/umode excludes +g; golden_callerid (2); callerid_proptest
(2, accept-list + notify model lockstep). Boot snapshots regenerated for the
new 004 'g' umode letter and the 005 CALLERID=g token.
Assisted-by: Claude Opus 4.8 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>
feat(channel)!: drop the IRCnet channel types (&, !, +); # only (P11 slice 144)
Leveva inherited four channel prefixes from IRCnet 2.11 — # (global), &
(server-local), + (modeless), and ! (timestamped "safe"). The latter three
are IRCnet-specific and unwanted; this removes them so only # is a valid
channel prefix. CHANTYPES is now "#".
With +/! gone, the *modeless* machinery they were the only users of is dead
and is deleted: use_modes() removed, a channel creator is always a chanop,
and the unreachable KickGate::NoChanModes / ApplyOutcome::NoChanModes variants
(and their 477 handler arms) are gone. ERR_NOCHANMODES stays in the numeric
table (a wire-code registry, not a feature list).
The three S2S channel-target sigil helpers narrow from #&+! to #, and
relay::local_join drops its dead &-channel non-propagation skip.
Fuzzing: new tests/chantypes_proptest.rs (512 cases) pins that any legal
#-body parses and round-trips, and — the inverse — any &/!/+ -prefixed name
is BadPrefix regardless of body, no name resurrects a dropped type, and
arbitrary bytes never panic the validator.
Docs: CHANNEL_TYPES/KICK/REOP_LIST help pages + 8 ISUPPORT golden snapshots.
Gate: cargo test -p leveva green; clippy -p leveva --tests clean;
cargo build --workspace 0 warnings.
Plan: docs/superpowers/plans/2026-06-13-p11-slice144-drop-irc-net-channel-types.md
feat(leveva): CHANTRACE channel-scoped extended trace (P11 slice 287)
The channel-scoped sibling of TRACE/ETRACE/MASKTRACE, completing the trace
quartet: CHANTRACE <#channel> reports every member of a named channel in
ETRACE's extended 708 column format (folded-nick order), closing 262.
Gate (charybdis-faithful ordering): 461 (missing channel) -> 403 (no such
channel, existence before membership) -> 442 unless the requester is a member
or holds OperPrivilege::Trace (the operspy-equivalent bypass). Reuses
etrace::etrace_line, no new numeric.
Divergences (leveva-native, no oracle): emits 708 not charybdis 709; reports
the full roster incl. remote members (unlike local-only ETRACE/MASKTRACE) but
no S2S propagation; no IP-hiding (host==host, no separate IP column).
Tests (TDD, inverse invariants + fuzzing): 11 unit (403-before-442, PART
removes match, non-member admitted once joined, outsider never appears),
golden_chantrace (real binary), chantrace_proptest (4 properties, 512 cases).
feat(leveva): CYCLE — self-only channel refresh (P11 slice 295)
charybdis-style `CYCLE <channel>` (extensions/m_cycle.c): part and rejoin a
channel *without races*. Faithful to the real m_cycle, the effect is entirely
client-side for the issuer — `:source PART <chan> :Cycling`, `:source JOIN
<chan>`, then a fresh 353/366 — and nothing changes server-side, so the user
keeps op/voice and place and cannot be locked out by +i/+k/+l or lose a glare.
No new Channels seam (CYCLE never mutates): it composes the read-only
display_name/is_member/names_query accessors. Per-channel gate ladder:
461 no param → 403 nonexistent → 442 not-a-member → success, existence before
membership; the re-sent NAMES honours the issuer's multi-prefix/userhost-in-names.
Divergences (leveva-native, no oracle): self-only/observationally-pure (NOT
member-visible — that would drop ops, destroy a sole-member channel, and desync
peers), fixed :Cycling reason, local-only.
7 command units + cycle_proptest (observational-purity + arbitrary-args) +
golden_cycle; CYCLE.md help + COMMANDS allowlist + index.md.
feat(leveva): D-lines (DLINE/UNDLINE) — IP-level operator bans (P11 slice 284)
charybdis-style D-lines, the IP/CIDR sibling of the temporary K-line family
(slices 281–283): `DLINE <duration> <ip/cidr> [:reason]` bans a raw IP or CIDR
block, `UNDLINE <ip/cidr>` lifts it. Built as a near-clone of the K-line plane
keyed on a single IP/CIDR `mask` (matched with the CIDR-aware
`matching::host_component_matches`) instead of `user@host`.
- `dline.rs`: `DlineStore` mirrors `KlineStore` (Vec+Mutex, NOCASE dedup,
`find_active`, same `database {}` SQLite write-through + boot reload as slice
282); `Dline::covers` = `host_component_matches`. Reuses the kline duration
grammar/clock/clamp.
- `command/dline.rs`: `dline`/`undline` mirror `tkline`/`untkline` (461→481 gate,
empty/`*` mask → Incorrect format, no success reply); `reap_matching_ip` ejects
local matching clients by `orighost` (real connect IP), skipping remote +
`kline-exempt`. New `OperPrivilege::Dline` (bit 0x400000).
- `session.rs`: registration gate checked before the K-line gate, matching the
pre-cloak connect IP → 465+ERROR+REJ snomask, never counted/claimed.
- `s2s/dline.rs`+`forward.rs`+`burst.rs`: `ENCAP * DLINE`/`UNDLINE` propagation
(server-prefixed, remaining-seconds, slice-281 KLINE shape) + burst
re-assertion.
- `stats.rs`: `STATS d` → `250 RPL_STATSDLINE` via `dline_report`.
- `server.rs`: `ctx.dlines` opens against the same `database {}` file (persists
across restart); boot test + inverse extended.
- help `DLINE.md`/`UNDLINE.md` + COMMANDS allowlist.
Tests (TDD, inverse invariants, mandated fuzzing): unit+proptest per module;
`tests/golden_dline.rs` (real binary, `dline.kdl` fixture) and
`tests/dline_proptest.rs` (6 properties incl. model-lockstep registration gate
over `Session::feed`). leveva-native, no oracle differential.
`cargo test -p leveva` green (2530 lib); clippy clean; workspace 0 warnings.
feat(leveva): combination extbans $& (AND) / $| (OR) (P11 slice 307)
Port of charybdis extensions/extb_combi.c: two extban operator types whose
data is a comma-separated list of child extbans ([~]<type>[:<data>], no leading
$), optionally paren-wrapped, with paren-aware comma splitting and backslash
escaping. $& matches iff all children match; $| iff any does. Children may
nest (depth cap 5, <=10 children/node, data <= BANLEN 195).
A faithful byte-walk of eb_combi in extban/combi.rs dispatching to the existing
eval_type handlers — the C global recursion_depth is threaded as a depth param
(leveva runs many connections). Preserves the two charybdis subtleties: a child
type is validated for existence always (even when short-circuited, via the new
is_known_type), but child data only up to the short-circuit point, so combiban
validity is subject-dependent.
extban_chars() -> "&acjmorsxz|" so 005 advertises EXTBAN=$,&acjmorsxz|.
Divergence: leveva's $m is usermode (not charybdis's hostmask), so host
matching inside a combiban uses $x:<nick!user@host>#*.
Tests: 11 combi units (AND/OR/negated/nested/paren+escaped-comma + inverses for
every malformed shape, short-circuit type validation, the caps), extban_combi_
proptest (6 props: totality, AND==all/OR==any model vs an independent fold,
single-child==bare, De Morgan), golden_extban_combi (JOIN gates biting only
after OPER + the 005 token). isupport/elemental_extban/mod.rs asserts updated;
9 EXTBAN-token snapshots regenerated. EXTBANS.md documents the operators.
feat(channel)!: drop the IRCnet channel types (&, !, +); # only (P11 slice 144)
Leveva inherited four channel prefixes from IRCnet 2.11 — # (global), &
(server-local), + (modeless), and ! (timestamped "safe"). The latter three
are IRCnet-specific and unwanted; this removes them so only # is a valid
channel prefix. CHANTYPES is now "#".
With +/! gone, the *modeless* machinery they were the only users of is dead
and is deleted: use_modes() removed, a channel creator is always a chanop,
and the unreachable KickGate::NoChanModes / ApplyOutcome::NoChanModes variants
(and their 477 handler arms) are gone. ERR_NOCHANMODES stays in the numeric
table (a wire-code registry, not a feature list).
The three S2S channel-target sigil helpers narrow from #&+! to #, and
relay::local_join drops its dead &-channel non-propagation skip.
Fuzzing: new tests/chantypes_proptest.rs (512 cases) pins that any legal
#-body parses and round-trips, and — the inverse — any &/!/+ -prefixed name
is BadPrefix regardless of body, no name resurrects a dropped type, and
arbitrary bytes never panic the validator.
Docs: CHANNEL_TYPES/KICK/REOP_LIST help pages + 8 ISUPPORT golden snapshots.
Gate: cargo test -p leveva green; clippy -p leveva --tests clean;
cargo build --workspace 0 warnings.
Plan: docs/superpowers/plans/2026-06-13-p11-slice144-drop-irc-net-channel-types.md
feat(leveva): +l locops + LOCOPS command, and make all user modes global — P11 slice 254
Part A — +l locops user mode + LOCOPS command (charybdis UMODE_LOCOPS), the
local-server sibling of +z/OPERWALL: an oper broadcasts to +l users on the
originating server only; the command never crosses a link. Oper-gated to set,
letter 'l' (bit 0x40000). New command/locops.rs + golden_locops.rs +
locops_proptest.rs. The last named standard charybdis umode — surface complete.
Part B — leveva has NO local-only user modes (product decision). SEND_UMODES is
now every UserMode::ALL bit (self-maintaining const loop), so +O/+x/+s/+g/+G/+D/
+R/+Q/+z/+l all propagate and a remote WHOIS shows them. Verified safe: the burst
already rendered the full unmasked set, and a user's host is always carried
explicitly (UNICK field / ENCAP CHGHOST), never recomputed from the +x bit, so
+x cannot double-apply the cloak (+x now emits both UMODE +x and ENCAP CHGHOST).
Enforcement unchanged: caller-id (+g/+G) and +R stay gated on the target's home
server — the ACCEPT list lives only there and is not propagated, so those S2S
gates are the actual enforcement, not redundant re-checks, and are kept.
- mode.rs: UserMode::LocOps + is_locops(); doc sweep (bit propagates, enforcement
is server-local)
- command/mode.rs: 'l' in the oper-gated arm + umode_diff; +x test asserts both frames
- s2s/umode.rs: SEND_UMODES = every umode; exclusion test -> carries-every-mode
- snotice.rs / s2s/relay.rs: stale 'not in SEND_UMODES' comments corrected
- help/LOCOPS.md + USER_MODES +l row; 004 umode list -> ...zSl (6 snapshots)
- golden_s2s_umode rewritten (demonstrates +D now propagating)
feat(leveva): IRCv3 draft/read-marker + the MARKREAD command (P11 slice 300)
The read-state companion to draft/chathistory (slice 274). MARKREAD
<target> [timestamp=<iso8601>] records or queries how far a client has
read a target; a set stores max(existing, new) (monotonic — never
regresses), echoes the effective value, and on a genuine advance fans
the MARKREAD to the user's other capable connections (cross-device
read-state sync). A bare MARKREAD <target> queries the stored marker.
Markers are owned by the services account (synced across connections,
survives a reconnect) when logged in, else by the connection UID
(per-connection, dropped on Session::release). The cap is statically
advertised and valueless; the command is processed regardless of the
issuer's own cap — the cap gates only the cross-connection fan, per spec.
leveva-native: the C 2.11 oracle predates IRCv3, so the gate is unit +
golden + proptest (no differential).
- readmarker.rs: pure parse/format seam (parse_set_timestamp /
format_value) + the monotonic ReadMarkers store (account|UID owner key)
- command/markread.rs: the handler (NEED_MORE_PARAMS / query / set /
INVALID_PARAMS / advance + fan)
- cap.rs: DRAFT_READ_MARKER const + SUPPORTED entry + read_marker
ClientCaps bit; CAP LS snapshots refreshed (a long SASL mechlist now
tips the 302 LS into a spec-legal multiline split)
- server.rs: read_markers field; session.rs: forget_connection release hook
- help/MARKREAD.md + COMMANDS allowlist + index.md Queries line
- tests: readmarker/markread units (inverse invariants), golden_markread
(single-conn round-trip + cross-device push vs uncapped sibling),
readmarker_proptest (total parse + round-trip; advance keeps-max,
order-independent + idempotent)
feat(leveva): MASKTRACE mask-filtered extended trace (P11 slice 286)
Charybdis-style `MASKTRACE <nick!user@host mask> [<gecos mask>]` — the
mask-filtered sibling of TRACE (26) and ETRACE: reports every local client whose
nick!user@host glob-matches (and optionally whose realname matches a 2nd gecos
glob) in ETRACE's extended column format. 461 param gate before the
OperPrivilege::Trace oper gate (481); one reused 708 RPL_ETRACEFULL line per
match in folded-nick order via matching::HostMask + the promoted
etrace::etrace_line/class_name, closing with 262 RPL_TRACEEND (no new numeric).
Leveva-native (IRCnet 2.11 has no MASKTRACE), local-only (no S2S, mirroring the
charybdis model). Emits 708 not charybdis's 709 (same divergence ETRACE
documents); class/ip/XLINE columns identical to ETRACE.
Tests (TDD, inverse invariants + fuzzing): 11 unit tests (gates, folded-order
sweep, full columns, and the inverses — non-matching host excluded, QUIT removes
the match, gecos filter excludes/re-includes, no-match is just the 262);
golden_masktrace.rs (real binary snapshot); masktrace_proptest.rs (4 properties
x 512 cases). Help page + COMMANDS allowlist entry.
Gate: cargo test -p leveva green; clippy clean; cargo build --workspace 0
warnings.
feat(leveva): IRCv3 MONITOR / the online-offline watch list (P11 slice 70)
Adds the MONITOR extension: a per-connection nick watch list with server-pushed
730/731 online/offline notifications, replacing ISON polling. Advertised via the
MONITOR=100 ISUPPORT token (not a CAP). New leveva::monitor shared index (keyed by
watcher UID, off the Registered struct), command/monitor.rs handler (+/-/C/L/S,
734 overflow, comma-chunked replies), live-notify hooks at the registration /
disconnect / nick-change seams, numerics 730-734, and help/MONITOR.md.
Single-server-local: live pushes fire on local lifecycle events only (remote S2S
transitions deferred). Gate: monitor module + command + seam units, golden_monitor
(two clients), monitor_proptest; full leveva suite 1222 pass, clippy clean, 0 warnings.
feat(leveva): OLIST — operator LIST revealing +s/+p channels (P11 slice 293)
charybdis extensions/m_olist.c: the operator variant of LIST that bypasses the
secret (+s) / private (+p) channel-hiding so an oper enumerates every channel,
including the hidden ones a normal LIST skips. The read-only sibling of LIST and
the latest member of the charybdis operator diagnostic family
(TESTLINE/TESTMASK/MASKTRACE/CHANTRACE/FINDFORWARDS/OPME).
- Channels::list_all() (full folded sweep) + list_one_any(name) (named incl.
hidden) — the visibility-bypass seams, no filter; also the fuzz seam.
- command/olist.rs: plain oper-bit gate (non-oper 481 before any sweep), same
321/322/323 numerics as LIST; no-arg → all incl. +s/+p, named → that channel
revealed-or-skipped, no ELIST conditions (faithful to mo_olist).
- Wired "OLIST" + mod olist; help/OLIST.md + COMMANDS allowlist + index.md.
Divergences (leveva-native, no oracle): plain oper-bit gate (not a per-command
privilege), no +s audit snomask (read-only diagnostic family precedent),
local-only.
Tests: list_all/list_one_any units; 6 command units; olist_proptest (full-set
+ superset-of-list model equality, arbitrary_args_never_panic); golden_olist
(LIST hides #secret, OLIST reveals it, non-oper 481). Regenerating
golden_help_users also picks up the pre-existing stale operator-index line
(OPME/FINDFORWARDS from slices 291/292).
cargo test -p leveva green; clippy clean; build --workspace 0 warnings.
feat(leveva): +z operwall user mode + OPERWALL command (charybdis UMODE_OPERWALL) — P11 slice 252
The oper-only sibling of +w/WALLOPS: an operator broadcasts OPERWALL to every
+z operator network-wide. Closes one of the named remaining charybdis umodes.
A near-exact mirror of the slice-178 WALLOPS machinery (command/operwall.rs +
s2s/operwall.rs).
- +z (letter "z", bit 0x10000, FLAGS_OPERWALL): oper-gated to set like +s
(non-oper +z silently ignored, -z always allowed); purely local, NOT in
SEND_UMODES (the OPERWALL command propagates and each server fans to its own
local +z — diverges from +w, which is in SEND_UMODES only for oracle
faithfulness).
- OPERWALL <text>: oper-only (481), 461 on empty, fans :mask OPERWALL :text to
local +z, propagates :<uid> OPERWALL :text; inbound fans is_local_uid-gated +
split-horizon relay.
- mode.rs UserMode::Operwall (+ is_operwall predicate); umode_diff/RENDERED;
004 umode literal +z; help/OPERWALL.md + USER_MODES.md row.
- The mode.rs round-trip test also moved off "z" as its unknown example to ">".
Tests: command/operwall.rs + s2s/operwall.rs units (mirror wallops), +z oper-gate
units, golden_operwall.rs (+z oper receives, -z oper and -z sender do not),
operwall_proptest.rs (delivery decided by +z alone). 5 welcome-burst snapshots
gain the z letter.
cargo test -p leveva green; clippy clean; build --workspace 0 warnings.
feat(channel)!: drop the IRCnet channel types (&, !, +); # only (P11 slice 144)
Leveva inherited four channel prefixes from IRCnet 2.11 — # (global), &
(server-local), + (modeless), and ! (timestamped "safe"). The latter three
are IRCnet-specific and unwanted; this removes them so only # is a valid
channel prefix. CHANTYPES is now "#".
With +/! gone, the *modeless* machinery they were the only users of is dead
and is deleted: use_modes() removed, a channel creator is always a chanop,
and the unreachable KickGate::NoChanModes / ApplyOutcome::NoChanModes variants
(and their 477 handler arms) are gone. ERR_NOCHANMODES stays in the numeric
table (a wire-code registry, not a feature list).
The three S2S channel-target sigil helpers narrow from #&+! to #, and
relay::local_join drops its dead &-channel non-propagation skip.
Fuzzing: new tests/chantypes_proptest.rs (512 cases) pins that any legal
#-body parses and round-trips, and — the inverse — any &/!/+ -prefixed name
is BadPrefix regardless of body, no name resurrects a dropped type, and
arbitrary bytes never panic the validator.
Docs: CHANNEL_TYPES/KICK/REOP_LIST help pages + 8 ISUPPORT golden snapshots.
Gate: cargo test -p leveva green; clippy -p leveva --tests clean;
cargo build --workspace 0 warnings.
Plan: docs/superpowers/plans/2026-06-13-p11-slice144-drop-irc-net-channel-types.md
feat(leveva): add SAPART oper force-part override (P11 slice 153)
Complete the SA* oper-override family (SAMODE 151, SANICK+SAJOIN 152) with
SAPART <nick> <channel>{,...} [:reason] — forcibly part a local user from one
or more channels. Oper-only (481), leveva-native, local-target-only (a remote
target gets a NOTICE).
Built like SAJOIN: extract PART's side-effect core into a shared part::part_one
(returning the parter-facing echo or a structured PartError so the 403/442 can
be addressed to either the parter or the operator) plus part::force_part, so
SAPART is the real PART handler differing only in who is gated and where the
echo lands (the target's mailbox vs the caller's socket). The existing part
suite guards the pure refactor.
Tests: 6 sapart units (gate+inverse, success, reason, errors-to-oper+inverse,
remote NOTICE, last-member delete) + a sapart_equals_the_targets_own_part
proptest (256 cases) fuzzing the override outcome+state against the target's
own PART over arbitrary join/part subsequences.
feat(leveva): server-to-server link protocol (P11 slice 31)
Add the UID-based IRCnet 2.11 S2S burst on server-only listeners: leveva goes
from single-server to linking a peer, exchanging state, and tearing down on
split. New leveva/src/s2s/ modtree (network/handshake/unick/njoin/mode/save/eob/
squit + PeerLink + MemberPrefix codec), a Network mirror in ServerContext
(BTreeMap<Uid,RemoteUser>; netsplit = SID-prefix range drain), and a serve_server
loop in main.rs replacing the old drop.
- Handshake: PASS/SERVER authenticated against connect{} blocks.
- Inbound burst: UNICK/NJOIN/MODE/SAVE/EOB/EOBACK.
- Outbound burst: our servers/users/channels then EOB to a new peer.
- Teardown: SQUIT + abrupt-drop via one squit_subtree (relays QUITs to local
co-members, frees nicks); oper-facing SQUIT command gated on SquitLocal.
Faithful to the oracle wire format; clean-modern implementation. Built by an
ultracode multi-agent workflow, then 3 adversarial-review bugs fixed with
regression tests: NJOIN-only ghost member surviving SQUIT (new
Channels::members_behind_sids sweep), UNICK-collision stale mirror nick, and the
NJOIN '.' empty-channel placeholder wire/parse mismatch.
Verified: unit (s2s 55 + command::squit) + golden_s2s boot golden + 7-property
s2s_proptest. cargo test -p leveva 702 passed/0 failed; clippy + fmt clean;
cargo build --workspace 0 warnings. No pure-oracle entry point, so no
leveva-integration differential (consistent with recent slices).
feat(leveva): TESTLINE ban-match diagnostic (P11 slice 285)
TESTLINE <[nick!]user@host | ip/cidr | nick | #channel> — a charybdis-style
read-only operator command, the capstone of the ban family (RESV 272, TKLINE
281, DLINE 284). It reports which active ban (K/D-line or RESV) would match a
mask, laying/lifting nothing.
- Param gate (461) then a plain oper-bit gate (any oper, no per-ban privilege
→ 481), matching charybdis (TESTLINE needs IsOper with no specific flag).
- A pure probe() classifier strips an optional nick! then routes by mask shape:
user@host → D-line(host)-then-K-line; #channel → channel RESV; bare token →
D-line(as IP)-then-nick RESV. Reports the first hit, priority D > K > R.
- New numerics RplTestline=725 (<type> <minutes-left> <ban-mask> :<reason>; 0
minutes for a permanent RESV) and RplNotestline=726 (<mask> :No matches).
Expiry honoured for free via find_active.
- TESTLINE.md help + COMMANDS allowlist (bijection test).
leveva-native, no oracle (2.11 has no TESTLINE): single best match, no
I-line/auth-block arm, local-only (no S2S propagation, mirroring charybdis).
Tests (TDD, failing first + fuzzing): command/testline.rs units + inline
probe_is_total proptest; testline_proptest.rs (reply-well-formed, non-oper-481,
laid-ban-always-reported inverse); golden_testline.rs (real binary, minutes
field masked). cargo test -p leveva green (2543 lib), clippy clean, workspace
0 warnings.
feat(leveva): TESTMASK mask-population diagnostic (P11 slice 288)
TESTMASK <[nick!]user@host> [<gecos>] counts how many connected clients match
a hostmask (and optional realname glob), split into local vs remote — the
read-only population sibling of TESTLINE (slice 285, which reports bans),
together completing charybdis's test* diagnostic family.
461 param gate before the plain oper-bit gate (481); a malformed mask (no @, or
empty user/host) yields a NOTICE :Invalid parameters (faithful to charybdis's
sendto_one_notice, not a numeric); a registry sweep glob-matches
nick/user/host(+orighost)/gecos (nick & gecos default *) and tallies
is_local_uid into one 727 RPL_TESTMASKGECOS reply. New numeric 727 (charybdis's
724 is dead — no format string, no caller). Pure parse_mask fuzz seam.
Confirmed against cloned charybdis m_testmask.c / messages.h / numeric.h.
leveva-native, local-only (no S2S, mirroring charybdis).
Tests: 13 units (inverse filters + quit-drops-count), golden_testmask (real
binary), testmask_proptest (4 properties incl. l+g <= population, never panics).
feat(leveva): D-lines (DLINE/UNDLINE) — IP-level operator bans (P11 slice 284)
charybdis-style D-lines, the IP/CIDR sibling of the temporary K-line family
(slices 281–283): `DLINE <duration> <ip/cidr> [:reason]` bans a raw IP or CIDR
block, `UNDLINE <ip/cidr>` lifts it. Built as a near-clone of the K-line plane
keyed on a single IP/CIDR `mask` (matched with the CIDR-aware
`matching::host_component_matches`) instead of `user@host`.
- `dline.rs`: `DlineStore` mirrors `KlineStore` (Vec+Mutex, NOCASE dedup,
`find_active`, same `database {}` SQLite write-through + boot reload as slice
282); `Dline::covers` = `host_component_matches`. Reuses the kline duration
grammar/clock/clamp.
- `command/dline.rs`: `dline`/`undline` mirror `tkline`/`untkline` (461→481 gate,
empty/`*` mask → Incorrect format, no success reply); `reap_matching_ip` ejects
local matching clients by `orighost` (real connect IP), skipping remote +
`kline-exempt`. New `OperPrivilege::Dline` (bit 0x400000).
- `session.rs`: registration gate checked before the K-line gate, matching the
pre-cloak connect IP → 465+ERROR+REJ snomask, never counted/claimed.
- `s2s/dline.rs`+`forward.rs`+`burst.rs`: `ENCAP * DLINE`/`UNDLINE` propagation
(server-prefixed, remaining-seconds, slice-281 KLINE shape) + burst
re-assertion.
- `stats.rs`: `STATS d` → `250 RPL_STATSDLINE` via `dline_report`.
- `server.rs`: `ctx.dlines` opens against the same `database {}` file (persists
across restart); boot test + inverse extended.
- help `DLINE.md`/`UNDLINE.md` + COMMANDS allowlist.
Tests (TDD, inverse invariants, mandated fuzzing): unit+proptest per module;
`tests/golden_dline.rs` (real binary, `dline.kdl` fixture) and
`tests/dline_proptest.rs` (6 properties incl. model-lockstep registration gate
over `Session::feed`). leveva-native, no oracle differential.
`cargo test -p leveva` green (2530 lib); clippy clean; workspace 0 warnings.
feat(leveva): user mode +C no-CTCP (P11 slice 306)
Port charybdis extensions/umode_noctcp.c to a leveva user mode +C: a
self-settable umode that refuses CTCP queries (other than ACTION) sent to the
user as a PRIVMSG, replying 531 ERR_CANNOTSENDTOUSER :+C set. NOTICE, CTCP
replies, and ACTION always pass. The recipient-side private-message counterpart
of the channel +C (slice 220), reusing the fuzzed channel::is_blocked_ctcp.
Pure seams mode::is_noctcp + mode::noctcp_user_blocks (the composite gate
decision), enforced home-server-local on both the local command/message.rs path
and the inbound-S2S s2s/relay::inbound_message path (new noctcp_reject_remote
routes 531 to the sender's uplink, the +R 248->249 split precedent). The bit
still propagates (slice-254 "no local-only umodes"), so WHOIS shows +C. Bit
0x80000, numeric 531; umode_diff/RENDERED/004-literal/snapshot wiring per the
user-mode checklist.
Tests: mode seam units, command self-settable + inverse, message gate +
inverses, s2s inbound + inverses, golden_noctcp_umode, noctcp_umode_proptest
(5 props). 5 welcome snapshots regenerated (004 gains C).
feat(leveva): WEBIRC webchat-gateway client IP/host spoofing (P11 slice 301)
Port charybdis extensions/m_webirc.c: a trusted webchat gateway sends a
pre-registration WEBIRC <password> <gateway> <hostname> <ip> so the proxied
connection is recorded under the real client's host/IP, not the gateway's.
Every later admission gate (D/K/X-line, config-ban, per-class conn caps, +x
cloak) and WHOIS key off the spoofed self.host.
- new pure fuzz seam leveva::webirc {parse_request, spoof_host, authorize}
- webirc {} config block (host mask + password) -> StatsConf (boot-read)
- Session::handle_webirc dispatched phase-independently (CAP/AUTHENTICATE seam),
one-spoof-per-connection, +s audit snotice; registered -> 462, bad-pw /
untrusted host / malformed -> NOTICE, no spoof
- HELP WEBIRC topic + commented example/dist config block
Divergences (leveva-native, no oracle): single-host/no-DNS collapse of
charybdis host/sockhost; trust via webirc {} not auth{}; boot-read.
Tests: webirc/config/session units (inverses), golden_webirc end-to-end,
webirc_proptest (parse total + round-trip, spoof_host range, authorize
contract).
feat(leveva): IRCv3 draft/read-marker + the MARKREAD command (P11 slice 300)
The read-state companion to draft/chathistory (slice 274). MARKREAD
<target> [timestamp=<iso8601>] records or queries how far a client has
read a target; a set stores max(existing, new) (monotonic — never
regresses), echoes the effective value, and on a genuine advance fans
the MARKREAD to the user's other capable connections (cross-device
read-state sync). A bare MARKREAD <target> queries the stored marker.
Markers are owned by the services account (synced across connections,
survives a reconnect) when logged in, else by the connection UID
(per-connection, dropped on Session::release). The cap is statically
advertised and valueless; the command is processed regardless of the
issuer's own cap — the cap gates only the cross-connection fan, per spec.
leveva-native: the C 2.11 oracle predates IRCv3, so the gate is unit +
golden + proptest (no differential).
- readmarker.rs: pure parse/format seam (parse_set_timestamp /
format_value) + the monotonic ReadMarkers store (account|UID owner key)
- command/markread.rs: the handler (NEED_MORE_PARAMS / query / set /
INVALID_PARAMS / advance + fan)
- cap.rs: DRAFT_READ_MARKER const + SUPPORTED entry + read_marker
ClientCaps bit; CAP LS snapshots refreshed (a long SASL mechlist now
tips the 302 LS into a spec-legal multiline split)
- server.rs: read_markers field; session.rs: forget_connection release hook
- help/MARKREAD.md + COMMANDS allowlist + index.md Queries line
- tests: readmarker/markread units (inverse invariants), golden_markread
(single-conn round-trip + cross-device push vs uncapped sibling),
readmarker_proptest (total parse + round-trip; advance keeps-max,
order-independent + idempotent)