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): 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): 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): 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): 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): +s/+b BOTS snomask producer — Excess-Flood flooder spy + HELP SNOMASK — P11 slice 265
Wire the eighth producer for a slice-257 reserved-but-empty snomask category
(charybdis SNO_BOTS, `b`). A registered client disconnected for Excess Flood
(the command-rate fakelag kill, slices 201-208) now fans a
`Flooder <nick>!<user>@<host> (Excess Flood)` spy notice to local `+s +b`
watchers at the registered flood-kill chokepoint. The pre-registration flood
guard (slice 203) deliberately does not fire it (no nick/identity, no charybdis
analogue). Local-only like every snomask producer; charybdis BOTS is mainly
message-target flood while leveva fans on the live command-rate kill it has —
faithful intent, not a byte copy. Only `d` DEBUG now lacks a producer.
Also ship a `HELP SNOMASK` reference page cataloguing every snomask category
and trim the `HELP USER_MODES` snomask paragraph to allude to it.
- snomask.rs: SnoMask::bots() accessor (BOTS bit, reserved since 257); doc-table
`b` row + producer_accessors test.
- snotice.rs: pure flood_notice(nick, user, host) builder (the fuzz seam).
- session.rs: server_notice_cat(ctx, bots(), flood_notice(...)) at the registered
Excess-Flood kill site; unit tests (fan to +s+b and ALL watchers, inverses for
+s+k-only / -s / modest burst).
- help/SNOMASK.md (new) + help/USER_MODES.md (trimmed) + SNOMASK in the help
TOPICS allowlist.
- tests/bots_snomask_proptest.rs: builder never panics, carries the scaffold,
embeds each field over arbitrary input.
Gate: cargo test -p leveva green (golden_privmsg failure was a load flake under
two contending suites — passes isolated in 0.5s); clippy clean; workspace build
0 warnings.
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(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): 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): 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): 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(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): 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): 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): +D deaf user mode (charybdis UMODE_DEAF) — P11 slice 247
A +D ("deaf") user receives no channel-addressed messages — PRIVMSG,
NOTICE, TAGMSG, and the +z op-moderation redirect — while private
(nick-target) messages still reach them. Client-settable by any user
(MODE <nick> +D / -D), like +i/+w/+B; no oper gate.
The channel fan-out delivers to local members only on each server, so
the deaf filter runs on the deaf user's home server local fan-out: a
remote server never delivers to a deaf user directly and so never needs
to know. +D is therefore purely local and NOT in SEND_UMODES — the same
precedent as +g/+G/+s.
- mode.rs: UserMode::Deaf (letter D, bit 0x2000, FLAGS_DEAF), threaded
through ALL/as_char/bit/flag_name/from_char/from_bit/Display; new pure
predicate mode::is_deaf (the fuzz seam).
- command/mode.rs: D added to the self-settable umode group + umode_diff.
- command/message.rs + command/tagmsg.rs: skip deaf local members at the
channel fan-out and the +z op-redirect loops.
- isupport: user_modes_string() -> oOiwraWBxsgGZD (004 RPL_MYINFO).
Tests: unit (mode predicate/round-trip, self-settable + clear inverse,
channel-blocked-but-private-delivered + un-deaf round-trip for
PRIVMSG/NOTICE/TAGMSG), boot-golden golden_deaf.rs (sentinel-ordering
proves the channel line is dropped while a direct marker arrives), fuzz
deaf_proptest.rs (is_deaf vs independent model + unique letter/bit).
Regenerated 5 welcome-burst snapshots (004 usermode +D) + 2 hardcoded
assertions; s2s::umode propagation test excludes Deaf.
cargo test -p leveva green; clippy clean; cargo build --workspace 0 warnings.
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): 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): 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(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): 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(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): 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): 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): 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): 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): +Q/+F forward-target control (charybdis MODE_DISFORWARD/MODE_FREETARGET) — P11 slice 243
The two recorded follow-ons to slice 242's +f channel forwarding. Both are
plain channel flag modes that live on the forward *target* and gate forwarding
at two different stages:
- +F (free target, MODE_FREETARGET): charybdis chm_forward requires a local
non-oper setting `+f #target` to be a channel operator (+o) of #target; +F on
the target lifts that requirement. This forces the op-on-target permission
gate that slice 242 deferred — leveva previously let any manager point +f at
any valid channel; now a non-op of the target gets 482 (or 403 if the target
doesn't exist), bypassed by +F / oper-override.
- +Q (disforward, MODE_DISFORWARD): a +Q target refuses incoming forwards — a
would-be-forwarded joiner falls through to the source channel's original
reject (no 470, no forward).
Mechanism:
- mode.rs: ChanMode::DisableForward ('Q', 0x1000) + FreeTarget ('F', 0x2000),
both Flag kind; ALL -> [ChanMode; 30]; bit/as_char/mode_name/from_char.
- channel.rs: pure forward_set_verdict(exists, chanop, free) -> ForwardSetVerdict
(fuzzed); forward_set_verdict_for(target, setter) store accessor (chanop = +o
rank, reads the +F bit); forward_disabled(name) (+Q flag, modelled on
blocks_notice).
- command/mode.rs: supported_flag gains 'Q'/'F'; the ModeReq::Forward set arm
runs the +F-gated check (gated on can_manage && !oper_override, ops-checked-
first like the extban-validity gate) -> 403/482 for the target, change skipped.
- command/join.rs: the forward redirect skips a +Q target (forward_disabled).
- ISUPPORT/004: both auto-classify into CHANMODES group D ->
CHANMODES=beIR,k,ljf,psmntiOCcSzTgrQF; MYINFO chan-mode string gains QF.
Divergences: target-op rank is strictly chanop (+o), so a leveva halfop on the
target does not satisfy the +F gate (faithful to charybdis is_chanop); a
nonexistent/invalid +f target is now 403 for a manager-setter (charybdis
find_channel) where slice 242 silently dropped it, but a self-forward stays
silently dropped at the apply layer. No S2S follow-on — plain flag bits ride the
standard MODE/CHANTS machinery; both gates run at the home server (distributed),
same as +f/+g/+r.
Tests: mode/channel/command::mode unit tests (truth tables, store accessors,
482/+F set gate, +Q set/clear inverse); golden_forward_control.rs (both +F and
+Q scenarios with inverses); forward_proptest.rs gains an exhaustive +
proptest model of forward_set_verdict. 9 CHANMODES snapshots regenerated.
cargo test (edited + snapshot binaries) green; clippy -p leveva --tests clean.
feat(leveva): AWAY command (P11 slice 15) — 301/305/306, +a, WHO G/H, WHOIS 301
Add the AWAY command and away-state, the 15th P11 leveva slice. An away message
is stored in the shared registry record (read by other connections), the
server-managed +a (FLAGS_AWAY) bit is toggled in lockstep, and away-ness is wired
into its three observers:
- AWAY :msg -> 306 RPL_NOWAWAY (truncate to TOPICLEN=255, char-boundary safe);
bare/empty AWAY -> 305 RPL_UNAWAY (unconditional, faithful to m_away).
- PRIVMSG (not NOTICE) to an away nick -> 301 RPL_AWAY to the sender.
- WHO shows G (away) / H (here); WHOIS inserts 301 after 312.
+a is server-managed: MODE keeps ignoring 'a', only AWAY toggles it. Grounded in
the original C (b88264f3^: m_away/send_away/who_one/send_whois) + the P5g oracle
port. Unit + boot-golden + proptest (fuzz) coverage; leveva-only, no shared C state.
Gate: cargo test -p leveva (344 lib + golden + proptest) + -p leveva-integration
(10) green; clippy clean; workspace build 0 warnings.
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(leveva): DIE + RESTART + REHASH oper control-plane (P11 slice 25)
The first leveva commands that act on the whole process. Introduces a server
control plane (leveva/src/control.rs: a process-global ServerControl =
Notify + latching AtomicU8) — the process-level analogue of slice 19's
per-connection eject plane.
Faithful to the IRCnet 2.11 m_die/m_restart/m_rehash msgtab gate
({ m_nop, m_nopriv, m_<cmd>, m_nop, m_unreg }): a non-oper -> 481; an oper ->
the handler, which re-gates on is_allowed(ACL_DIE|RESTART|REHASH) -> also 481
without the flag. This wakes the dormant OperPrivilege machinery (parsed since
slice 16): Registered gains a `privileges` set, populated from the matched
block on a successful OPER, and each control command gates on its OperPrivilege
(a non-oper's empty set => 481, reproducing both oracle arms in one check).
- DIE/RESTART (shutdown_all): eject every registered client (issuer included)
with a `Server (Terminating|Restarting). <nick>[<user>@<host>]` NOTICE as the
eject wire, then control::request(Die|Restart). main's select! drains the
ejects over a 200ms grace then exits (Die) or reexec()s the binary (Restart,
CommandExt::exec; CLOEXEC sockets re-bind cleanly).
- REHASH: 382 RPL_REHASHING + re-read/validate the on-disk config.
Documented divergences: killer as <nick>[<user>@<host>]; single-server (no
server-link ERROR branch); RESTART re-exec is review-covered not golden-tested;
REHASH only validates the re-read (applying it to the immutable ServerContext
is deferred); no SCH_NOTICE; KILL/WALLOPS still gate on the oper bit only. No
leveva-integration differential (all three are impure into global buffers).
Verified: unit (control 8; die/restart/rehash 3 each w/ inverses; OPER stores
the set) + control_proptest (gate / eject-conservation / panic-freedom) +
golden_control (mortal 481, oper 382, oper DIE -> NOTICE then exit) + live
boots (DIE->EOF->exit; RESTART->re-exec->port re-bind). cargo test -p leveva
green (lib 468 + all golden/proptest bins), clippy/fmt clean, workspace 0
warnings, leveva-integration unchanged.
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 deaf user mode (charybdis UMODE_DEAF) — P11 slice 247
A +D ("deaf") user receives no channel-addressed messages — PRIVMSG,
NOTICE, TAGMSG, and the +z op-moderation redirect — while private
(nick-target) messages still reach them. Client-settable by any user
(MODE <nick> +D / -D), like +i/+w/+B; no oper gate.
The channel fan-out delivers to local members only on each server, so
the deaf filter runs on the deaf user's home server local fan-out: a
remote server never delivers to a deaf user directly and so never needs
to know. +D is therefore purely local and NOT in SEND_UMODES — the same
precedent as +g/+G/+s.
- mode.rs: UserMode::Deaf (letter D, bit 0x2000, FLAGS_DEAF), threaded
through ALL/as_char/bit/flag_name/from_char/from_bit/Display; new pure
predicate mode::is_deaf (the fuzz seam).
- command/mode.rs: D added to the self-settable umode group + umode_diff.
- command/message.rs + command/tagmsg.rs: skip deaf local members at the
channel fan-out and the +z op-redirect loops.
- isupport: user_modes_string() -> oOiwraWBxsgGZD (004 RPL_MYINFO).
Tests: unit (mode predicate/round-trip, self-settable + clear inverse,
channel-blocked-but-private-delivered + un-deaf round-trip for
PRIVMSG/NOTICE/TAGMSG), boot-golden golden_deaf.rs (sentinel-ordering
proves the channel line is dropped while a direct marker arrives), fuzz
deaf_proptest.rs (is_deaf vs independent model + unique letter/bit).
Regenerated 5 welcome-burst snapshots (004 usermode +D) + 2 hardcoded
assertions; s2s::umode propagation test excludes Deaf.
cargo test -p leveva green; clippy clean; cargo build --workspace 0 warnings.
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): charybdis-style extended bans (P11 slice 164)
Add `+b`/`+e`/`+I` ban-list entries of the form `$[~]<type>[:<data>]`
that match a richer client predicate than a plain nick!user@host glob,
ported faithfully from Elemental-IRCd (doc/technical/extban.txt,
src/extban.c, extensions/extb_*.c).
A new `leveva::extban` module holds the framework (the $/~/: parse,
Verdict/ModeType/Subject/ChannelView, match_extban/valid_extban/
entry_matches/extban_chars) plus one handler file per type: $a account,
$o oper, $z ssl, $r realname, $x extgecos, $s server, $c on-channel,
$j banned-from-channel, $m usermode. The nine handlers were implemented
in parallel via a multi-agent workflow, one per extb_*.c.
Extbans are enforced at the JOIN gate: check_join's last param is now
&extban::SubjectAttrs (was is_oper: bool), and its +b/+e/+I iteration
runs through extban::entry_matches against a Subject built in place. A
private LiveChannels ChannelView adapter resolves $c/$j from the
already-locked channel map (no re-lock) with a depth-1 recursion guard
for nested $j. join.rs builds SubjectAttrs from the registry (account,
certfp->ssl, realname, modes->oper/umodes) plus the server name.
ISUPPORT advertises EXTBAN=$,acjmorsxz (re-chunking nine existing 005
golden bursts, content-identical).
Divergences (leveva-native, documented): JOIN-gate-only enforcement
(no PRIVMSG/quiet plane; +q is the slice-158 owner mode), $s matches
the joiner's server (= me.name for a local JOIN), $j caps at depth 1,
$x has no DynSpoof retry, and add-time validity rejection is deferred.
Tests: 97 extban unit tests, elemental_extban_proptest (parser
totality, negation duality, $a model, extban_chars invariant), and a
real-binary golden_extban.
Assisted-by: Claude Opus 4.8 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>
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(leveva): +f channel forwarding (charybdis MODE_FORWARD) — P11 slice 242
A JOIN refused by a forwardable reject (+i/+l/+b/+r) on a +f channel is
redirected to the forward target instead of erroring: the joiner gets
470 RPL_LINKCHANNEL <from> <to> and a clean single-hop JOIN of the target.
- mode.rs: ChanMode::Forward (letter f, bit 0x10000, Param kind), ALL→28.
- channel.rs: ChannelModes.forward; pure seams forwardable() + valid_forward_target()
(valid ChanName + not-self, fold-aware); ModeChange::Forward applied (set re-validates,
invalid/self silently dropped; trusted-peer verbatim); 324 render + forward_target().
- command/{mode,join}.rs: +f param parse (461 on bare +f, -f clears); join_one gains
allow_forward — single hop, no chaining (SAJOIN/OJOIN pass false).
- numeric.rs: RplLinkchannel = 470.
- S2S: rides the live channel-MODE plane (relay render + s2s/mode parse → apply_modes_as_server);
not in the netburst CHANTS, matching the +j precedent (documented divergence).
- ISUPPORT/004: +f auto-classifies into CHANMODES group C (beIR,k,ljf,…); MYINFO gains f.
Tests: channel/mode/command::mode/s2s::mode units; golden_forward (470 redirect +
inverse); forward_proptest (forwardable + valid_forward_target totality/model);
ISUPPORT/004 snapshots + characterization literals updated for the trailing f.
Divergences: single hop (charybdis chains); invalid/self target silently dropped;
+k bad-key and the hard +O/+S gates never forward; +Q/+F are follow-on slices.
feat(leveva): +Q/+F forward-target control (charybdis MODE_DISFORWARD/MODE_FREETARGET) — P11 slice 243
The two recorded follow-ons to slice 242's +f channel forwarding. Both are
plain channel flag modes that live on the forward *target* and gate forwarding
at two different stages:
- +F (free target, MODE_FREETARGET): charybdis chm_forward requires a local
non-oper setting `+f #target` to be a channel operator (+o) of #target; +F on
the target lifts that requirement. This forces the op-on-target permission
gate that slice 242 deferred — leveva previously let any manager point +f at
any valid channel; now a non-op of the target gets 482 (or 403 if the target
doesn't exist), bypassed by +F / oper-override.
- +Q (disforward, MODE_DISFORWARD): a +Q target refuses incoming forwards — a
would-be-forwarded joiner falls through to the source channel's original
reject (no 470, no forward).
Mechanism:
- mode.rs: ChanMode::DisableForward ('Q', 0x1000) + FreeTarget ('F', 0x2000),
both Flag kind; ALL -> [ChanMode; 30]; bit/as_char/mode_name/from_char.
- channel.rs: pure forward_set_verdict(exists, chanop, free) -> ForwardSetVerdict
(fuzzed); forward_set_verdict_for(target, setter) store accessor (chanop = +o
rank, reads the +F bit); forward_disabled(name) (+Q flag, modelled on
blocks_notice).
- command/mode.rs: supported_flag gains 'Q'/'F'; the ModeReq::Forward set arm
runs the +F-gated check (gated on can_manage && !oper_override, ops-checked-
first like the extban-validity gate) -> 403/482 for the target, change skipped.
- command/join.rs: the forward redirect skips a +Q target (forward_disabled).
- ISUPPORT/004: both auto-classify into CHANMODES group D ->
CHANMODES=beIR,k,ljf,psmntiOCcSzTgrQF; MYINFO chan-mode string gains QF.
Divergences: target-op rank is strictly chanop (+o), so a leveva halfop on the
target does not satisfy the +F gate (faithful to charybdis is_chanop); a
nonexistent/invalid +f target is now 403 for a manager-setter (charybdis
find_channel) where slice 242 silently dropped it, but a self-forward stays
silently dropped at the apply layer. No S2S follow-on — plain flag bits ride the
standard MODE/CHANTS machinery; both gates run at the home server (distributed),
same as +f/+g/+r.
Tests: mode/channel/command::mode unit tests (truth tables, store accessors,
482/+F set gate, +Q set/clear inverse); golden_forward_control.rs (both +F and
+Q scenarios with inverses); forward_proptest.rs gains an exhaustive +
proptest model of forward_set_verdict. 9 CHANMODES snapshots regenerated.
cargo test (edited + snapshot binaries) green; clippy -p leveva --tests clean.
feat(leveva): charybdis alias{} services command aliases (P11 slice 303)
Port charybdis's alias{} mechanism (modules/m_alias.c + newconf.c alias_entry):
an `alias "<name>" { target "<t>" }` block makes <name> a command that rewrites
`<name> <text...>` into `PRIVMSG <target> :<text...>`, delivered through the message
plane. A real command always takes precedence (the hook is the existing 421 fallback).
Found by comparing against a charybdis checkout: the 'configurable IDENTIFY nicks'
originally scoped does not exist in charybdis (the nicks are hardcoded #defines); the
alias{} block is the real, faithful, more general mechanism.
- alias.rs pure seam: parse_target (split on first @ -> nick vs user@server),
combined_args / reconstruct; fuzzed by tests/alias_proptest.rs.
- new top-level alias{} config block (model/parse/from_kdl), held live + REHASH-able
through ConfStore (live_aliases, the service-string chain); main.rs boot seed.
- command/alias.rs: deliver_to_service_nick shared core (target must be a present +S
service else 440 ERR_SERVICESDOWN; empty text -> 412; else synth PRIVMSG +
message::message, so a remote service is reached by UID routing). new numeric 440.
- folds in the slice-302 IDENTIFY faithfulness fix the comparison surfaced: empty args
-> 412 (was 461), absent/non-+S agent -> 440 (was 401), via the shared core.
- user@server target parsed/fuzzed but not yet routed (-> 440, documented follow-on).
Tests: alias seam + command + config-parse units; identify units updated; extended
rehash_conf_proptest alias reload; golden_alias (S2S +S burst: route + 440 + 421
inverses); golden_identify rewritten (S2S +S NickServ/ChanServ).
cargo test -p leveva green / clippy clean / build --workspace 0 warnings.
feat(leveva): IP cloaking / the +x hidden-host usermode + user modes on connect (P11 slice 72)
Ports Elemental-IRCd's extensions/ip_cloaking.c to leveva as a client-settable
`+x` usermode that hides a client's host behind a deterministic FNV-keyed
scramble of its original host. The host change is distributed by reusing the
slice-71 chghost plane, so a cap co-member sees an in-place CHGHOST and the
network an ENCAP CHGHOST.
- cloak.rs: faithful port of the C — fnv_hash(s,32), cloak_ip (keep IPv4 first
two octets / IPv6 first half, substitute the rest from the g–z alphabet),
cloak_host (scramble first-label letters then digits), dispatch on IpAddr.
Wire-safety: never introduces a leading ':'.
- mode.rs/numeric.rs: UserMode::Cloak (+x, 0x0100, appended last); 396
RPL_HOSTHIDDEN. +x is NOT in SEND_UMODES — it propagates as a host change,
not a umode diff (no double-propagation).
- registry.rs: immutable ClientRecord.orighost (set at try_claim, never by
set_host) so the cloak is computed from / reverts to the real connect host.
- command/mode.rs: 'x' joins the i|w|B settable arm; apply_cloak_change cloaks/
restores the host, mirrors set_host, distributes over the chghost plane, and
emits 396 (is now your hidden host / hostname reset).
- config/parse.rs: default-user-modes now accepts 'x' so a network can
auto-cloak everyone; a default-+x client is cloaked at registration (the C
check_new_user path).
- session.rs: clients are now told their user modes on connect (:nick MODE nick
:+<modes> after the welcome burst).
leveva-native (no C oracle) → unit + golden + proptest, no differential. Tests:
cloak/mode/numeric/registry/command/session/config units + golden_ip_cloaking
(127.0.0.1 -> 127.0.y.p) + cloak_proptest (the fuzz target). 4 registration
snapshots regenerated (004 -> oOiwraWBx + the trailing MODE notice). clippy
clean, 0 warnings.
feat(leveva): +j join throttle channel mode — P11 slice 234
Charybdis-style `+j n:t` (MODE_JOINTHROTTLE): a channel admits at most n
joins per t-second window; the next join bounces 480 ERR_THROTTLE and is
not added. The first parameter-bearing flag mode since +l/+k and the first
JOIN-rate gate; continues the channel-mode parity track (220 +C, 232 +c,
233 +S). leveva-native — gate is unit + golden + proptest.
- Pure core join_throttle.rs: parse_param(n:t) + format_param + the charybdis
fixed-window decide() (both fuzz seams); JoinThrottle counter store (reads no
clock, self-draining) housed inside Channels (zero ServerContext-literal churn).
- ChanMode::JoinThrottle ('j', bit 0x8000000, Param kind) threaded through both
mode parsers + the three ModeChange matches + 324/CHANMODES-type-C/004 render.
- JOIN gate in command::join::join_one: non-members, local path only (remote
NJOIN gated at its home server); SAJOIN bypasses; refusal -> 480 ErrThrottle.
- Tests: 12 core units + 2 channel + 1 mode units; jointhrottle_proptest (5,
incl. no-window-over-admits) + golden_jointhrottle; 8 005/004 snapshots
regenerated (CHANMODES ...,k,lj,... / 004 ...IRklj, token-only).
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): +r registered-only-join channel mode (charybdis MODE_REGONLY) — P11 slice 241
Adds the leveva-native channel flag mode +r: on a +r channel only a client
signed in to a services account may JOIN; a signed-out client is refused 477
(charybdis ERR_NEEDREGGEDNICK, which overloads numeric 477 — reuses
Numeric::ErrNochanmodes since a duplicate-discriminant variant is impossible).
The join-plane sibling of +g; a hard JOIN gate like +O/+S (an INVITE/key/
exception does NOT bypass it — account identity is a user property), so KNOCK to
a +r channel is refused too.
- mode.rs: ChanMode::RegisteredOnly, letter r, bit 0x80000000 (last free u32
bit), Flag kind; added to ALL/as_char/bit/mode_name/from_char.
- command/mode.rs: supported_flag 'r' (the second allowlist).
- channel.rs: pure regonly_blocks(set, has_account) seam + the hard-gate clause
in check_join (reads attrs.account, same source as $a extban); new
JoinReject::RegisteredOnly.
- command/join.rs + command/knock.rs: reject mapping + KNOCK refusal.
- ISUPPORT/MYINFO auto-derive (CHANMODES …SzTgr, MYINFO …SzTgr…); 10 snapshots
+ isupport/registration assertions updated (token-only).
Reclaiming the slice-77 ripped-out reop letter r triggered the
unknown-chanmode-letter hazard: removed the obsolete ripped_out_reop_is_unknown
test, updated chan_mode_bits_match_oracle, switched golden_modes's unknown-mode
probe to +>, and repurposed the modes_proptest AnonReop op to BareAdmin.
Tests: golden_regonly.rs (RED-first), channel/mode/command::mode units (gate +
inverse + hard-gate proof + truth table), regonly_proptest.rs, modes_proptest
FLAGS += RegisteredOnly.
cargo test -p leveva green; cargo clippy -p leveva --tests 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): 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): 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): OPER command (P11 slice 16) — 381/491/464, +o/+O, WHOIS 313
Authenticate `OPER <name> <password>` against the configured operator blocks
(name IRC-fold + user@host mask glob + Password::verify), granting +o (or +O for
a local operator) with a MODE echo + 381 RPL_YOUREOPER, mirrored into the shared
registry so WHOIS reports 313 RPL_WHOISOPERATOR (after the 301 away slot). The
491-vs-464 split distinguishes "no O-line for your host" from a wrong password.
- Password::verify: Plain → byte compare; Hashed → pwhash::unix::verify (new
pure-Rust crypt dependency; libc's crypt isn't available and leveva links no
libcrypt). ServerContext carries the operator blocks from config.
- WHOIS gains 313 in send_whois order (311 [319] 312 [301] [313] 318).
- Grounded in the oracle m_oper/find_Oline/send_whois (git b88264f3^, P5 port).
- Tests: password verify (+2), command/oper.rs (+8 with inverses), whois (+2),
golden_oper boot test, oper_proptest fuzzing (2 properties, 400 cases).
- Documented divergences: no class oper limit, no LUSERS oper count, no S2S
+o propagation; any matching block may authenticate (not strictly the first).
Gate: cargo test -p leveva 417 + leveva-integration 10 green; clippy clean;
cargo 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(leveva): +z op-moderation channel mode — P11 slice 235
A port of charybdis chm_simple MODE_OPMODERATE. On a +z channel a message
that would be blocked from reaching the channel — by +n (external), +m
(moderated), or a +b ban/quiet (CanSend::External/Moderated/Banned) — is not
refused 404; it is delivered to the channel's operators (rank >= +o) only, so
ops can see what muted, banned, or external users are saying. Ok/NoSuchChannel
verdicts are never redirected. Extends the speech-plane can_send work of slices
214/220/232.
- mode.rs: ChanMode::OpModerate ('z', bit 0x10000000, Flag kind, MODE_OPMODERATE);
CHANMODES + 004 chan-mode string auto-derive from ALL/kind().
- command/mode.rs: 'z' in the supported_flag allowlist (the recurring flag-mode
gotcha — needs both the ChanMode and this second allowlist or MODE +z 472s).
- channel.rs: pure opmod_redirects(set, verdict) + Channels::op_moderated /
op_members (rank >= op).
- command/message.rs: the block arm redirects to local ops when op_moderated —
no 404, no echo, no relay (TAGMSG/REDACT + S2S op-redirect are documented
follow-ons), else the existing 404/silent.
Tests: mode/channel/command-mode units (5) incl. inverses; fuzz opmod_proptest
(opmod_redirects vs an independent model over every (bool, CanSend); op_members
exactly the rank>=op set over arbitrary membership); golden_opmod (real binary:
+mz redirects bob's muted line to the op, not to carol/bob, no 404; -z restores
the 404). Snapshot/assertion churn: isupport/registration/config literals gain z
(+z is now an accepted default flag; unknown-letter test uses '>'); 6 golden
004/005 snapshots regenerated (token-only z).
Gate: cargo test -p leveva green (pre-existing golden_restricted_op read_until
flake aside); cargo clippy -p leveva --tests clean; cargo build --workspace 0
warnings.
feat(leveva): +P permanent channel (charybdis MODE_PERMANENT/chm_staff) — P11 slice 244
A channel carrying +P is not destroyed when its last member leaves: its
topic, modes, and list masks persist with zero members, so the next joiner
enters an existing channel and is NOT made creator-op. +P is oper-only —
only a server operator (or a SAMODE override) may set or clear it (a
non-oper gets 481, checked before the chanop gate, matching chm_staff).
- mode.rs: ChanMode::Permanent (letter P, bit 0x80000, MODE_PERMANENT, Flag).
- channel.rs: pure destroy_when_empty(flags) + permanent_set_allowed(...)
decision seams (fuzzed); permanent(name) accessor; part/kick/remove_everywhere
skip the empty-channel deletion for +P; join() decides creator-op from
`created`, not members.is_empty() (the permanent-empty-channel fix).
- command/mode.rs: supported_flag gains P; the Flag arm refuses a non-oper
+P/-P with 481.
- isupport/004: CHANMODES group D + MYINFO gain a trailing P.
Divergences: a bare (non-chanop) oper still hits the 482 op-gate — use
SAMODE (the 481-vs-482 precedence is honoured); bursting empty permanent
channels on link is a documented follow-on.
Tests: unit (mode letter/bit/name/kind; channel persistence across
PART/KICK/QUIT + no-op-on-rejoin + flag tracking; command 481 oper-gate),
golden_permanent.rs (persistence + topic preserved + creator-op inverse +
non-oper 481), permanent_proptest.rs (destroy_when_empty + permanent_set_allowed
totality/model), regenerated CHANMODES snapshots.
feat(leveva): +r registered-only-join channel mode (charybdis MODE_REGONLY) — P11 slice 241
Adds the leveva-native channel flag mode +r: on a +r channel only a client
signed in to a services account may JOIN; a signed-out client is refused 477
(charybdis ERR_NEEDREGGEDNICK, which overloads numeric 477 — reuses
Numeric::ErrNochanmodes since a duplicate-discriminant variant is impossible).
The join-plane sibling of +g; a hard JOIN gate like +O/+S (an INVITE/key/
exception does NOT bypass it — account identity is a user property), so KNOCK to
a +r channel is refused too.
- mode.rs: ChanMode::RegisteredOnly, letter r, bit 0x80000000 (last free u32
bit), Flag kind; added to ALL/as_char/bit/mode_name/from_char.
- command/mode.rs: supported_flag 'r' (the second allowlist).
- channel.rs: pure regonly_blocks(set, has_account) seam + the hard-gate clause
in check_join (reads attrs.account, same source as $a extban); new
JoinReject::RegisteredOnly.
- command/join.rs + command/knock.rs: reject mapping + KNOCK refusal.
- ISUPPORT/MYINFO auto-derive (CHANMODES …SzTgr, MYINFO …SzTgr…); 10 snapshots
+ isupport/registration assertions updated (token-only).
Reclaiming the slice-77 ripped-out reop letter r triggered the
unknown-chanmode-letter hazard: removed the obsolete ripped_out_reop_is_unknown
test, updated chan_mode_bits_match_oracle, switched golden_modes's unknown-mode
probe to +>, and repurposed the modes_proptest AnonReop op to BareAdmin.
Tests: golden_regonly.rs (RED-first), channel/mode/command::mode units (gate +
inverse + hard-gate proof + truth table), regonly_proptest.rs, modes_proptest
FLAGS += RegisteredOnly.
cargo test -p leveva green; cargo clippy -p leveva --tests clean; cargo build
--workspace 0 warnings.
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).
fix(leveva): burst NJOIN carries the channel TS — P11 slice 215
A channel a server learned **for the first time in a burst** was re-clocked to
the receiver's local nanosecond clock instead of adopting the origin's
`created_at`: the leading `CHANTS` is dropped on an unknown channel
(`apply_encap_chants` → `ChanTsOutcome::Unknown`), and the burst `NJOIN` was
TS-less, so `handle_njoin` stamped `clock::unixnano()`. Two servers then
disagreed on a channel's TS by *when each learned it*, and the next merge
deopped the later learner — the divergence slice 167 fixed for the live NJOIN,
left unfixed on the burst path. Observed in prod: updating a server to v0.1.0
and relinking stripped `#xe`'s ops + `+R` that should have survived the merge.
Fix: the burst `NJOIN` now carries the channel TS as a middle param
(`:<sid> NJOIN <chan> <ts> :<members>`, the live form since slice 167) so a
peer adopts the origin's TS. Safe w.r.t. the merge case despite the slice-167
caveat: the burst is CHANTS-first (slice 171), so `we_lost` reads the
pre-merge `created_at` before NJOIN runs, and `njoin_member` only stamps on
creation — so for an existing channel the NJOIN-TS is a no-op (CHANTS owns
arbitration), and it only supplies the TS for a newly-learned channel.
`njoin_member_chunks` subtracts `1 + ts_digits` from the line budget; the boot
canonicalizer masks the new `NJOIN <chan> <ts> :` TS like CHANTS/USERTS.
Tests: burst_channel_ts_is_adopted_not_reclocked (the regression),
burst_njoin_line_carries_the_ts_middle_param, …_does_not_clobber_an_existing
_channels_arbitrated_ts (inverse merge), and a fuzz round-trip over arbitrary
origin TS. Updated the two burst snapshots + golden_s2s_njoin_live.
Gate: cargo test -p leveva green (pre-existing golden_s2s_keepalive BrokenPipe
flake aside); clippy clean; workspace build 0 warnings.
feat(leveva): burst empty +P permanent channel over S2S — stale-S2S-flag-allowlist fix — P11 slice 269
Closes slice 244's documented "Bursting empty permanent channels on
link" follow-on. A +P channel survives memberless so its topic/modes
persist, but a freshly-linked peer's NJOIN carries only the
empty-channel placeholder (.), so the receiver dropped the whole channel
block (CHANTS on an unknown channel was a no-op, the . NJOIN added
nobody, and the following MODE/TOPIC landed on a nonexistent channel).
Receiver-only fix: s2s::chants::apply_encap_chants now materializes the
empty channel from the burst CHANTS line via the new
Channels::create_permanent_from_burst, gated on +P (pure
channel::burst_creates_permanent, the inverse of destroy_when_empty) so
a leaky non-permanent empty channel is never created and a known channel
is never clobbered.
Also fixes a root-cause sub-bug surfaced while scoping: the S2S
burst/MODE parser s2s::mode::supported_flag carried a stale nmtipsO-only
flag-letter allowlist that silently dropped every leveva-native channel
flag (+C +c +S +z +T +g +r +Q +F +P +L) off a server burst/MODE, so
they never replicated across a link. Both the client and S2S parsers now
delegate to one canonical ChanMode::flag_from_char so they can never
drift again.
Tests (TDD + fuzz): golden_s2s_permanent (MODE->324 +Pkl, TOPIC->332,
inverse non-+P->403); unit tests in channel/chants/mode; permanent_proptest
extended (burst_creates_permanent totality+inverse, create_permanent_from_burst
gated/never-clobbers).
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): learn the SASL mechanism list from services (ENCAP * MECHLIST) (P11 slice 299)
A linked SASL services agent announces its mechanisms via
`:<svcSID> ENCAP * MECHLIST :<comma-list>`; leveva learns the list, advertises
it (client-facing `sasl=` cap value + `908 RPL_SASLMECHS`) instead of the
hardcoded `PLAIN,EXTERNAL`, and relays whichever advertised mechanism a client
picks — faithful charybdis transparent relay (special-casing only EXTERNAL for
the CertFP; an unadvertised mechanism → 908+904, never relayed).
- sasl.rs: pure fuzzed `parse_mechlist`; `Mechanism` reworked
`{Plain,External,Other(Box<str>)}` with `from_advertised`/`name`/`is_external`.
- s2s/links.rs: PeerLinks learned-mechlist store, cleared when the last sasl
agent unlinks.
- s2s/mechlist.rs (new): `apply_encap_mechlist`, dispatched in forward.rs's
interpret-and-onward-relay block (broadcast, like SU).
- cap.rs: `apply`/`ls`/`req` `sasl_available: bool` → `sasl_mechs: Option<&str>`.
- session.rs: AUTHENTICATE gate uses `from_advertised`; 908 lists the advertised
set; relay_start takes &Mechanism.
leveva-native (the C 2.11 oracle predates SASL). Tests cover the happy path and
every inverse invariant (unadvertised rejected, all-junk keeps the prior list,
unlink clears, default fallback) + 2 proptests.
feat(leveva): +S TLS-only channel mode — P11 slice 233
A leveva-native channel flag porting charybdis chm_sslonly (MODE_SSLONLY): a
JOIN of a +S channel by a client NOT on a secure (TLS) transport is refused
519 ERR_SSLONLYCHAN :Cannot join channel (+S) - SSL/TLS required and the client
is not added. Builds on slice 227's +Z secure user mode and the +C/+c flag-mode
wiring (220/232).
A hard JOIN gate like +O: checked in Channels::check_join alongside +O, before
the invite override, so INVITE/+I do not bypass it (a transport requirement,
not an access list); ops not exempt; existing members keep their seat (only new
joins gated, matching charybdis's can_join hook). KNOCK to a +S channel is
refused like +O.
The secure signal is the joiner's +Z (UserMode::Secure) bit via
mode::is_secure(attrs.umodes), NOT attrs.is_ssl — the latter is certfp-based
and undercounts TLS users with no client cert (the gap slice 227 closed). $z
extban semantics are left untouched. check_join runs for local joins only;
remote joins arrive via NJOIN and bypass it.
ChanMode::SslOnly ('S', bit 0x4000000, MODE_SSLONLY, Flag) wired through both
flag-mode allowlists (mode.rs ALL/as_char/bit/mode_name/from_char +
command::mode::supported_flag). JoinReject::SecureOnly → join_reject maps to the
new ErrSslonlychan = 519. CHANMODES/004/MYINFO auto-derive S.
Pure seam channel::sslonly_blocks(set, secure). Tests: 2 unit
(check_join_enforces_ssl_only incl. INVITE-no-bypass + -S round-trip;
sslonly_blocks_truth_table), sslonly_proptest (gate keys only off +Z over
arbitrary u32 umode masks; plain channel never gates; toggling +Z flips),
golden_sslonly end-to-end (plaintext JOIN → 519, not added, NAMES confirms; -S
re-opens), 9 regenerated 004/005 snapshots (chanmode string only).
cargo test -p leveva 2298 pass; clippy clean; workspace builds 0 warnings.
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): TIME + ADMIN + INFO commands (P11 slice 22)
Server-information query commands, ported as a pure read-only trio (previously
caught by dispatch's 421 fallback). All three reach the CLIENT and OPER msgtab
columns (no oper gate) and ignore the single-server hunt_server target arg.
- TIME -> a single 391; the time renders as unix seconds (leveva's wire-time
convention, like 333/312/314). Pure time_at(now) core + a thin clock-reading
wrapper.
- ADMIN -> the 256/257/258/259 block from a new ServerContext.admin config
field (257=name, 258=location, 259=email); 423 when all fields are empty
(unreachable -- the admin block is mandatory with name+email required).
- INFO -> leveva's own 371* description block (with an On-line since <created>
line) then 374; leveva content, oracle shape (as with VERSION's URL).
The new admin field touched the 19 proptest struct-literal sites. Canonicalizer
gained a 391-seconds + On-line-since mask. Verified by unit tests, a
golden_time_admin_info boot golden, and a 4-property server_query_proptest
(512 cases): TIME shape, ADMIN block-xor-423, INFO 371*-then-374, and
arbitrary-input panic-freedom.
No leveva-integration differential (m_time/m_admin/m_info sendto_one into global
buffers -> no pure oracle entry point).
Gate: cargo test -p leveva green (lib 429 + all golden/proptest binaries);
clippy --all-targets clean; fmt clean; build --workspace 0 warnings.
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): user modes (MODE <nick> → +i/+w) + config default +iw
P11 slice 14: the first *user*-mode slice. `MODE <nick>` was a stub
(221 `+` / 502); now a client has real, tracked user modes, a
configurable registration default, and +i (invisible) affects WHO.
- State: a u32 FLAGS_* bitmask (reusing the P10 UserMode enum) on
command::Registered (authoritative) + registry::ClientRecord (the
WHO-visible snapshot), synced by Registry::set_modes.
- Handler (command/mode.rs): faithful to the oracle m_umode resolved
to the client-toggleable set — other nick → 502; own nick query →
221 +<render>; change string applies i/w, silently ignores o/O/r/a
(no 501), 501s any unknown letter; on a net change echoes
:nick MODE nick :<diff> (send_umode sign-grouped diff) + mirrors to
the registry. No change → no echo.
- Config: `default-user-modes` (options block), restricted to i/w,
absent → +iw; Options::Default matches so a config with no options
block is also +iw (the out-of-box default). Seeded silently at
registration; documented in examples/*.kdl.
- WHO: +i users are omitted from the user sweeps (no-arg/0/*, exact,
glob) unless the requester shares a channel or is them; channel WHO
is unaffected. Retires the "no +i filtering" divergence.
Tests: +10 umode unit (with inverses), +4 WHO invisible-filter unit,
+1 config matrix, golden_usermode boot snapshot, usermode_proptest
(3 properties / 400 cases: model lockstep, WHO visibility matrix,
arbitrary-bytes panic-freedom). golden_who regenerated — carol now
hidden from the global sweep (a clean +iw-default demonstration); the
12 direct-ServerContext proptest harnesses get default_user_modes: 0.
cargo test -p leveva (328 lib + golden + proptest) + -p
leveva-integration green; clippy clean; workspace 0 warnings.
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): 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): 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): charybdis-style extended bans (P11 slice 164)
Add `+b`/`+e`/`+I` ban-list entries of the form `$[~]<type>[:<data>]`
that match a richer client predicate than a plain nick!user@host glob,
ported faithfully from Elemental-IRCd (doc/technical/extban.txt,
src/extban.c, extensions/extb_*.c).
A new `leveva::extban` module holds the framework (the $/~/: parse,
Verdict/ModeType/Subject/ChannelView, match_extban/valid_extban/
entry_matches/extban_chars) plus one handler file per type: $a account,
$o oper, $z ssl, $r realname, $x extgecos, $s server, $c on-channel,
$j banned-from-channel, $m usermode. The nine handlers were implemented
in parallel via a multi-agent workflow, one per extb_*.c.
Extbans are enforced at the JOIN gate: check_join's last param is now
&extban::SubjectAttrs (was is_oper: bool), and its +b/+e/+I iteration
runs through extban::entry_matches against a Subject built in place. A
private LiveChannels ChannelView adapter resolves $c/$j from the
already-locked channel map (no re-lock) with a depth-1 recursion guard
for nested $j. join.rs builds SubjectAttrs from the registry (account,
certfp->ssl, realname, modes->oper/umodes) plus the server name.
ISUPPORT advertises EXTBAN=$,acjmorsxz (re-chunking nine existing 005
golden bursts, content-identical).
Divergences (leveva-native, documented): JOIN-gate-only enforcement
(no PRIVMSG/quiet plane; +q is the slice-158 owner mode), $s matches
the joiner's server (= me.name for a local JOIN), $j caps at depth 1,
$x has no DynSpoof retry, and add-time validity rejection is deferred.
Tests: 97 extban unit tests, elemental_extban_proptest (parser
totality, negation duality, $a model, extban_chars invariant), and a
real-binary golden_extban.
Assisted-by: Claude Opus 4.8 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>
feat(leveva): +j join throttle channel mode — P11 slice 234
Charybdis-style `+j n:t` (MODE_JOINTHROTTLE): a channel admits at most n
joins per t-second window; the next join bounces 480 ERR_THROTTLE and is
not added. The first parameter-bearing flag mode since +l/+k and the first
JOIN-rate gate; continues the channel-mode parity track (220 +C, 232 +c,
233 +S). leveva-native — gate is unit + golden + proptest.
- Pure core join_throttle.rs: parse_param(n:t) + format_param + the charybdis
fixed-window decide() (both fuzz seams); JoinThrottle counter store (reads no
clock, self-draining) housed inside Channels (zero ServerContext-literal churn).
- ChanMode::JoinThrottle ('j', bit 0x8000000, Param kind) threaded through both
mode parsers + the three ModeChange matches + 324/CHANMODES-type-C/004 render.
- JOIN gate in command::join::join_one: non-members, local path only (remote
NJOIN gated at its home server); SAJOIN bypasses; refusal -> 480 ErrThrottle.
- Tests: 12 core units + 2 channel + 1 mode units; jointhrottle_proptest (5,
incl. no-window-over-admits) + golden_jointhrottle; 8 005/004 snapshots
regenerated (CHANMODES ...,k,lj,... / 004 ...IRklj, token-only).
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): 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): 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): 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): 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): KNOCK per-channel flood throttle (712 ERR_TOOMANYKNOCK) (P11 slice 200)
Close the last KNOCK follow-on (the slice-198/199 deferral). A KNOCK to a
restricted channel delivered unconditionally, letting a user spam a channel's
operators by re-knocking in a loop. A channel now has a per-channel cooldown
(knock_throttle::KnockThrottle, charybdis knock_delay_channel, 60s): it admits
at most one KNOCK per window; a knock inside the window is refused with 712
ERR_TOOMANYKNOCK and notifies nobody (local ops and, via S2S, remote ops).
The store is clock-injected (caller passes unix-second now, like kline/
autoconnect) so it is deterministic under test, case-folds the channel key, and
self-prunes expired holds so it never leaks. Throttle is local-path only by
design: an inbound relayed ENCAP * KNOCK is unthrottled (the origin server
already throttled its own user; charybdis throttles per-server). The per-user
knock_delay stays out of scope. The KNOCK family (198/199/200) is now complete.
Adding the shared ServerContext.knock_throttle field touched the two
command::testutil literals and every integration-test ctx() literal (they build
ServerContext by hand, not via from_config).
Tests (RED first, inverse invariants, fuzzing): 7 knock_throttle units +
2 command::knock units + tests/knock_throttle_proptest.rs (PROPTEST_CASES=2000).
Gate: cargo test -p leveva --lib 1915 pass/0 fail; clippy --tests clean;
build --workspace 0 warnings.
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): +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): 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): 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): 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): 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): 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): 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): 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): 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): 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): 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): charybdis-style extended bans (P11 slice 164)
Add `+b`/`+e`/`+I` ban-list entries of the form `$[~]<type>[:<data>]`
that match a richer client predicate than a plain nick!user@host glob,
ported faithfully from Elemental-IRCd (doc/technical/extban.txt,
src/extban.c, extensions/extb_*.c).
A new `leveva::extban` module holds the framework (the $/~/: parse,
Verdict/ModeType/Subject/ChannelView, match_extban/valid_extban/
entry_matches/extban_chars) plus one handler file per type: $a account,
$o oper, $z ssl, $r realname, $x extgecos, $s server, $c on-channel,
$j banned-from-channel, $m usermode. The nine handlers were implemented
in parallel via a multi-agent workflow, one per extb_*.c.
Extbans are enforced at the JOIN gate: check_join's last param is now
&extban::SubjectAttrs (was is_oper: bool), and its +b/+e/+I iteration
runs through extban::entry_matches against a Subject built in place. A
private LiveChannels ChannelView adapter resolves $c/$j from the
already-locked channel map (no re-lock) with a depth-1 recursion guard
for nested $j. join.rs builds SubjectAttrs from the registry (account,
certfp->ssl, realname, modes->oper/umodes) plus the server name.
ISUPPORT advertises EXTBAN=$,acjmorsxz (re-chunking nine existing 005
golden bursts, content-identical).
Divergences (leveva-native, documented): JOIN-gate-only enforcement
(no PRIVMSG/quiet plane; +q is the slice-158 owner mode), $s matches
the joiner's server (= me.name for a local JOIN), $j caps at depth 1,
$x has no DynSpoof retry, and add-time validity rejection is deferred.
Tests: 97 extban unit tests, elemental_extban_proptest (parser
totality, negation duality, $a model, extban_chars invariant), and a
real-binary golden_extban.
Assisted-by: Claude Opus 4.8 via Claude Code
Signed-off-by: Xe Iaso <me@xeiaso.net>
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): 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): +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(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): +z op-moderation channel mode — P11 slice 235
A port of charybdis chm_simple MODE_OPMODERATE. On a +z channel a message
that would be blocked from reaching the channel — by +n (external), +m
(moderated), or a +b ban/quiet (CanSend::External/Moderated/Banned) — is not
refused 404; it is delivered to the channel's operators (rank >= +o) only, so
ops can see what muted, banned, or external users are saying. Ok/NoSuchChannel
verdicts are never redirected. Extends the speech-plane can_send work of slices
214/220/232.
- mode.rs: ChanMode::OpModerate ('z', bit 0x10000000, Flag kind, MODE_OPMODERATE);
CHANMODES + 004 chan-mode string auto-derive from ALL/kind().
- command/mode.rs: 'z' in the supported_flag allowlist (the recurring flag-mode
gotcha — needs both the ChanMode and this second allowlist or MODE +z 472s).
- channel.rs: pure opmod_redirects(set, verdict) + Channels::op_moderated /
op_members (rank >= op).
- command/message.rs: the block arm redirects to local ops when op_moderated —
no 404, no echo, no relay (TAGMSG/REDACT + S2S op-redirect are documented
follow-ons), else the existing 404/silent.
Tests: mode/channel/command-mode units (5) incl. inverses; fuzz opmod_proptest
(opmod_redirects vs an independent model over every (bool, CanSend); op_members
exactly the rank>=op set over arbitrary membership); golden_opmod (real binary:
+mz redirects bob's muted line to the op, not to carol/bob, no 404; -z restores
the 404). Snapshot/assertion churn: isupport/registration/config literals gain z
(+z is now an accepted default flag; unknown-letter test uses '>'); 6 golden
004/005 snapshots regenerated (token-only z).
Gate: cargo test -p leveva green (pre-existing golden_restricted_op read_until
flake aside); cargo clippy -p leveva --tests clean; cargo build --workspace 0
warnings.
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): 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): 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): 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): 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): 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): 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): 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): +r registered-only-join channel mode (charybdis MODE_REGONLY) — P11 slice 241
Adds the leveva-native channel flag mode +r: on a +r channel only a client
signed in to a services account may JOIN; a signed-out client is refused 477
(charybdis ERR_NEEDREGGEDNICK, which overloads numeric 477 — reuses
Numeric::ErrNochanmodes since a duplicate-discriminant variant is impossible).
The join-plane sibling of +g; a hard JOIN gate like +O/+S (an INVITE/key/
exception does NOT bypass it — account identity is a user property), so KNOCK to
a +r channel is refused too.
- mode.rs: ChanMode::RegisteredOnly, letter r, bit 0x80000000 (last free u32
bit), Flag kind; added to ALL/as_char/bit/mode_name/from_char.
- command/mode.rs: supported_flag 'r' (the second allowlist).
- channel.rs: pure regonly_blocks(set, has_account) seam + the hard-gate clause
in check_join (reads attrs.account, same source as $a extban); new
JoinReject::RegisteredOnly.
- command/join.rs + command/knock.rs: reject mapping + KNOCK refusal.
- ISUPPORT/MYINFO auto-derive (CHANMODES …SzTgr, MYINFO …SzTgr…); 10 snapshots
+ isupport/registration assertions updated (token-only).
Reclaiming the slice-77 ripped-out reop letter r triggered the
unknown-chanmode-letter hazard: removed the obsolete ripped_out_reop_is_unknown
test, updated chan_mode_bits_match_oracle, switched golden_modes's unknown-mode
probe to +>, and repurposed the modes_proptest AnonReop op to BareAdmin.
Tests: golden_regonly.rs (RED-first), channel/mode/command::mode units (gate +
inverse + hard-gate proof + truth table), regonly_proptest.rs, modes_proptest
FLAGS += RegisteredOnly.
cargo test -p leveva green; cargo clippy -p leveva --tests clean; cargo build
--workspace 0 warnings.
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): 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): LINKS/MAP enumerate the true network tree via RemoteServer.parent (P11 slice 88)
m_links/m_map hardcoded single-server output despite the Network mirror tracking
the whole topology since slices 31-87 (the gap slice 52 flagged). Both now enumerate
the mirror as the oracle does, rendering the genuine multi-level tree (no flattening,
per the user).
RemoteServer.uplink is the routing direct-peer, not the tree parent; the oracle prints
serv->up->name (the real spanning-tree edge). So add a display-only RemoteServer.parent
(the true tree parent = the announcing SERVER/SMASK line prefix), populated at the three
real introduction sites (handshake = our SID, server.rs = the :announcing_sid prefix,
smask = announcer) + ~20 test fixtures. Routing/squit_subtree still key on uplink.
New command/topology.rs: topology() enumerator (me first, remotes in Sid order, per-
server user counts, orphan-reparents-to-root) + a pure map_lines() tree renderer
faithful to dump_map's ' |- '/' `- ' connector cells with a visited-set cycle guard so
every server renders exactly once. links() shows each server's true upstream; map()
nests behind-peer servers under their parent. Single-server output is byte-identical
(zero existing-snapshot churn). Divergences: MAP s remote version '*' (unmirrored),
Sid-sorted order, orphan->root reparenting.
fix(leveva): burst NJOIN carries the channel TS — P11 slice 215
A channel a server learned **for the first time in a burst** was re-clocked to
the receiver's local nanosecond clock instead of adopting the origin's
`created_at`: the leading `CHANTS` is dropped on an unknown channel
(`apply_encap_chants` → `ChanTsOutcome::Unknown`), and the burst `NJOIN` was
TS-less, so `handle_njoin` stamped `clock::unixnano()`. Two servers then
disagreed on a channel's TS by *when each learned it*, and the next merge
deopped the later learner — the divergence slice 167 fixed for the live NJOIN,
left unfixed on the burst path. Observed in prod: updating a server to v0.1.0
and relinking stripped `#xe`'s ops + `+R` that should have survived the merge.
Fix: the burst `NJOIN` now carries the channel TS as a middle param
(`:<sid> NJOIN <chan> <ts> :<members>`, the live form since slice 167) so a
peer adopts the origin's TS. Safe w.r.t. the merge case despite the slice-167
caveat: the burst is CHANTS-first (slice 171), so `we_lost` reads the
pre-merge `created_at` before NJOIN runs, and `njoin_member` only stamps on
creation — so for an existing channel the NJOIN-TS is a no-op (CHANTS owns
arbitration), and it only supplies the TS for a newly-learned channel.
`njoin_member_chunks` subtracts `1 + ts_digits` from the line budget; the boot
canonicalizer masks the new `NJOIN <chan> <ts> :` TS like CHANTS/USERTS.
Tests: burst_channel_ts_is_adopted_not_reclocked (the regression),
burst_njoin_line_carries_the_ts_middle_param, …_does_not_clobber_an_existing
_channels_arbitrated_ts (inverse merge), and a fuzz round-trip over arbitrary
origin TS. Updated the two burst snapshots + golden_s2s_njoin_live.
Gate: cargo test -p leveva green (pre-existing golden_s2s_keepalive BrokenPipe
flake aside); clippy clean; workspace build 0 warnings.
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): learn the SASL mechanism list from services (ENCAP * MECHLIST) (P11 slice 299)
A linked SASL services agent announces its mechanisms via
`:<svcSID> ENCAP * MECHLIST :<comma-list>`; leveva learns the list, advertises
it (client-facing `sasl=` cap value + `908 RPL_SASLMECHS`) instead of the
hardcoded `PLAIN,EXTERNAL`, and relays whichever advertised mechanism a client
picks — faithful charybdis transparent relay (special-casing only EXTERNAL for
the CertFP; an unadvertised mechanism → 908+904, never relayed).
- sasl.rs: pure fuzzed `parse_mechlist`; `Mechanism` reworked
`{Plain,External,Other(Box<str>)}` with `from_advertised`/`name`/`is_external`.
- s2s/links.rs: PeerLinks learned-mechlist store, cleared when the last sasl
agent unlinks.
- s2s/mechlist.rs (new): `apply_encap_mechlist`, dispatched in forward.rs's
interpret-and-onward-relay block (broadcast, like SU).
- cap.rs: `apply`/`ls`/`req` `sasl_available: bool` → `sasl_mechs: Option<&str>`.
- session.rs: AUTHENTICATE gate uses `from_advertised`; 908 lists the advertised
set; relay_start takes &Mechanism.
leveva-native (the C 2.11 oracle predates SASL). Tests cover the happy path and
every inverse invariant (unadvertised rejected, all-junk keeps the prior list,
unlink clears, default fallback) + 2 proptests.
feat(leveva): learn the SASL mechanism list from services (ENCAP * MECHLIST) (P11 slice 299)
A linked SASL services agent announces its mechanisms via
`:<svcSID> ENCAP * MECHLIST :<comma-list>`; leveva learns the list, advertises
it (client-facing `sasl=` cap value + `908 RPL_SASLMECHS`) instead of the
hardcoded `PLAIN,EXTERNAL`, and relays whichever advertised mechanism a client
picks — faithful charybdis transparent relay (special-casing only EXTERNAL for
the CertFP; an unadvertised mechanism → 908+904, never relayed).
- sasl.rs: pure fuzzed `parse_mechlist`; `Mechanism` reworked
`{Plain,External,Other(Box<str>)}` with `from_advertised`/`name`/`is_external`.
- s2s/links.rs: PeerLinks learned-mechlist store, cleared when the last sasl
agent unlinks.
- s2s/mechlist.rs (new): `apply_encap_mechlist`, dispatched in forward.rs's
interpret-and-onward-relay block (broadcast, like SU).
- cap.rs: `apply`/`ls`/`req` `sasl_available: bool` → `sasl_mechs: Option<&str>`.
- session.rs: AUTHENTICATE gate uses `from_advertised`; 908 lists the advertised
set; relay_start takes &Mechanism.
leveva-native (the C 2.11 oracle predates SASL). Tests cover the happy path and
every inverse invariant (unadvertised rejected, all-junk keeps the prior list,
unlink clears, default fallback) + 2 proptests.
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): 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): 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): 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): +s/+y SPY snomask producer — STATS-request spy notices — P11 slice 260
Wire the third producer-less snomask category opened by slice 257 (after `n`
NCHANGE in 258 and `x` EXTERNAL in 259). charybdis (`SNO_SPY`, letter `y`) fans a
notice to local `+s +y` opers whenever a client requests STATS from this server —
the "someone is poking at the server" spy.
- snotice.rs: pure builder `stats_spy_notice(letter, nick, user, host, server)` ->
`STATS <c> requested by <nick> (<user>@<host>) [<server>]` (the fuzz seam).
- snomask.rs: `SnoMask::spy()` accessor (the `y` bit, reserved since 257); doc-table
row flipped to its producer.
- command/stats.rs: fire at the `stats` chokepoint before answering, gated on a
selector char being present AND the requester resolving to a local registry
record (its user@host source; unresolved only in synthetic tests). Fires for any
selector (even unrecognized), skips bare STATS; no self-exclusion; local-only
([<server>] = ctx.name, STATS answered locally).
Tests (RED first): builder render+embed units; `spy()` letter round-trip; stats
units (happy +s+y delivery with numerics asserted unchanged, inverses: +s+k-only
and -s get nothing, bare STATS fans nothing, unrecognized selector still fans,
unclaimed caller fans nothing); fuzz tests/spy_snomask_proptest.rs (builder never
panics, scaffold + each field verbatim).
Plan: docs/superpowers/plans/2026-06-18-p11-slice260-spy-snomask.md
feat(leveva): +S TLS-only channel mode — P11 slice 233
A leveva-native channel flag porting charybdis chm_sslonly (MODE_SSLONLY): a
JOIN of a +S channel by a client NOT on a secure (TLS) transport is refused
519 ERR_SSLONLYCHAN :Cannot join channel (+S) - SSL/TLS required and the client
is not added. Builds on slice 227's +Z secure user mode and the +C/+c flag-mode
wiring (220/232).
A hard JOIN gate like +O: checked in Channels::check_join alongside +O, before
the invite override, so INVITE/+I do not bypass it (a transport requirement,
not an access list); ops not exempt; existing members keep their seat (only new
joins gated, matching charybdis's can_join hook). KNOCK to a +S channel is
refused like +O.
The secure signal is the joiner's +Z (UserMode::Secure) bit via
mode::is_secure(attrs.umodes), NOT attrs.is_ssl — the latter is certfp-based
and undercounts TLS users with no client cert (the gap slice 227 closed). $z
extban semantics are left untouched. check_join runs for local joins only;
remote joins arrive via NJOIN and bypass it.
ChanMode::SslOnly ('S', bit 0x4000000, MODE_SSLONLY, Flag) wired through both
flag-mode allowlists (mode.rs ALL/as_char/bit/mode_name/from_char +
command::mode::supported_flag). JoinReject::SecureOnly → join_reject maps to the
new ErrSslonlychan = 519. CHANMODES/004/MYINFO auto-derive S.
Pure seam channel::sslonly_blocks(set, secure). Tests: 2 unit
(check_join_enforces_ssl_only incl. INVITE-no-bypass + -S round-trip;
sslonly_blocks_truth_table), sslonly_proptest (gate keys only off +Z over
arbitrary u32 umode masks; plain channel never gates; toggling +Z flips),
golden_sslonly end-to-end (plaintext JOIN → 519, not added, NAMES confirms; -S
re-opens), 9 regenerated 004/005 snapshots (chanmode string only).
cargo test -p leveva 2298 pass; clippy clean; workspace builds 0 warnings.
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): 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): 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): 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): 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): 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): 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): 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): 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): 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): 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): 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): 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)
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): 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): 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): 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): 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)