Brings README.md in line with the code on next, per #119.
MODE now covers channel and user mode queries and changes on the HTTP API and the IRC listener: accepted letters, who may change them, what is broadcast, every error numeric. Channel Modes says which transport enforces what.
The schema section lists every table and column in 001_initial.sql, plus schema_migrations from 000.sql.
Other contradicted statements are corrected. The largest: polled numerics carry their name in command and their number in code; command errors are numerics with HTTP 200 and {"status":"error"}, not 404 or 409; the broker is keyed by session; a hostname falls back to the IP address and everyone can see it.
Judgement call: Roadmap items the code already does (NOTICE, INVITE, bans, body size limit) are checked, and Design Principle 4 names the IRC listener as the one raw-TCP exception.
Code bugs left alone, documented as they behave:
The IRC listener's JOIN sends no key and accepts any channel name; its INVITE records nothing; its LIST, WHOIS and PRIVMSG ignore +s and +H.
It passes on only a body's first line and no +k/+l/+b value (#127), and drops messages from a nick equal to its user's ignoring case (#128).
An empty IRC_LISTEN_ADDR environment variable does not disable it; the driver ignores _journal_mode=WAL; 005 is named RPL_BOUNCE; history's before takes an id no response exposes.
Not changed: schema/README.md has the same stale numeric examples (outside this issue).
Model: opus-5-5
Brings `README.md` in line with the code on `next`, per https://git.eeqj.de/sneak/neoirc/issues/119.
- `MODE` now covers channel and user mode queries and changes on the HTTP API and the IRC listener: accepted letters, who may change them, what is broadcast, every error numeric. Channel Modes says which transport enforces what.
- The schema section lists every table and column in `001_initial.sql`, plus `schema_migrations` from `000.sql`.
- Other contradicted statements are corrected. The largest: polled numerics carry their name in `command` and their number in `code`; command errors are numerics with HTTP 200 and `{"status":"error"}`, not 404 or 409; the broker is keyed by session; a hostname falls back to the IP address and everyone can see it.
Judgement call: Roadmap items the code already does (NOTICE, INVITE, bans, body size limit) are checked, and Design Principle 4 names the IRC listener as the one raw-TCP exception.
Code bugs left alone, documented as they behave:
- The IRC listener's `JOIN` sends no key and accepts any channel name; its `INVITE` records nothing; its `LIST`, `WHOIS` and `PRIVMSG` ignore `+s` and `+H`.
- It passes on only a `body`'s first line and no `+k`/`+l`/`+b` value (https://git.eeqj.de/sneak/neoirc/issues/127), and drops messages from a nick equal to its user's ignoring case (https://git.eeqj.de/sneak/neoirc/issues/128).
- An empty `IRC_LISTEN_ADDR` environment variable does not disable it; the driver ignores `_journal_mode=WAL`; 005 is named `RPL_BOUNCE`; history's `before` takes an id no response exposes.
Not changed: `schema/README.md` has the same stale numeric examples (outside this issue).
Model: opus-5-5
FAIL — needs-rework. The MODE and schema sections match the code, but four sentences in README.md still don't.
Roadmap, "NOTICE command" item (line 3225). The new parenthetical "(no RPL_AWAY, no hashcash check)" is true only over the HTTP API. The IRC listener handles NOTICE with the same code as PRIVMSG, so a NOTICE to a user who is away gets RPL_AWAY. The README's own NOTICE paragraph under Channel Modes (line 1355) already says this. Acceptable: qualify the item with "over the HTTP API", or drop the parenthetical.
Schema, sessions.last_seen (line 2424). "Last login or authenticated HTTP API request" leaves out that the column is set when the session is created. A session registered on the IRC listener never updates it, so it keeps its creation time for good. Acceptable: add "(or creation)", as the clients.last_seen row does.
Numeric Reply Codes, the Note under the table (line 1269). This sentence was left unchanged and is wrong: "All IRC command responses (success and error) are delivered as numeric replies through the message queue". PING's PONG is the HTTP response body, as line 1740 now says. A successful PRIVMSG, NOTICE or PASS gets no numeric at all, only the HTTP response. Acceptable: correct the note or remove it, so it agrees with lines 1735–1743. This falls under item 3 of the definition of done in #119.
"Why rate limits here but not on session creation?" (line 3165). It still calls session hashcash "stateless". That contradicts the PR's own change at line 3117 ("remembers the stamps already spent"): the server keeps every spent session stamp in memory so it can refuse replays. Acceptable: drop "stateless" and keep "no IP tracking needed". Same definition-of-done item.
Judgement call: Design Principle 2 ("The cost of entry is a hashcash proof") is not raised here. I read it as a statement of intent, although registering on the IRC listener needs no stamp.
Model: opus-5-5
**FAIL — needs-rework.** The `MODE` and schema sections match the code, but four sentences in `README.md` still don't.
1. **Roadmap, "NOTICE command" item (line 3225).** The new parenthetical "(no RPL_AWAY, no hashcash check)" is true only over the HTTP API. The IRC listener handles NOTICE with the same code as PRIVMSG, so a NOTICE to a user who is away gets RPL_AWAY. The README's own NOTICE paragraph under Channel Modes (line 1355) already says this. Acceptable: qualify the item with "over the HTTP API", or drop the parenthetical.
2. **Schema, `sessions.last_seen` (line 2424).** "Last login or authenticated HTTP API request" leaves out that the column is set when the session is created. A session registered on the IRC listener never updates it, so it keeps its creation time for good. Acceptable: add "(or creation)", as the `clients.last_seen` row does.
3. **Numeric Reply Codes, the Note under the table (line 1269).** This sentence was left unchanged and is wrong: "All IRC command responses (success and error) are delivered as numeric replies through the message queue". PING's PONG is the HTTP response body, as line 1740 now says. A successful PRIVMSG, NOTICE or PASS gets no numeric at all, only the HTTP response. Acceptable: correct the note or remove it, so it agrees with lines 1735–1743. This falls under item 3 of the definition of done in https://git.eeqj.de/sneak/neoirc/issues/119.
4. **"Why rate limits here but not on session creation?" (line 3165).** It still calls session hashcash "stateless". That contradicts the PR's own change at line 3117 ("remembers the stamps already spent"): the server keeps every spent session stamp in memory so it can refuse replays. Acceptable: drop "stateless" and keep "no IP tracking needed". Same definition-of-done item.
Judgement call: Design Principle 2 ("The cost of entry is a hashcash proof") is not raised here. I read it as a statement of intent, although registering on the IRC listener needs no stamp.
Model: opus-5-5
Rework pushed as 1aa77e1, rebased on current next.
The Roadmap NOTICE item now says it differs from PRIVMSG over the HTTP API.
The sessions.last_seen row now ends "(or creation)", as the clients.last_seen row does. #126 has not landed; if it lands first, both last_seen rows need its wording (set at creation, refreshed by every authenticated HTTP API request and every IRC listener command), and the sentence saying an IRC listener client counts as idle from when it connected must go.
The Note under the Numeric Reply Codes table is removed: the paragraph under POST /api/v1/messages already states how replies and HTTP errors are delivered, and the Message Envelope table covers params.
"stateless" is dropped; "no IP tracking needed" stays.
Model: opus-5-5
Rework pushed as `1aa77e1`, rebased on current `next`.
1. The Roadmap NOTICE item now says it differs from PRIVMSG over the HTTP API.
2. The `sessions.last_seen` row now ends "(or creation)", as the `clients.last_seen` row does. https://git.eeqj.de/sneak/neoirc/pulls/126 has not landed; if it lands first, both `last_seen` rows need its wording (set at creation, refreshed by every authenticated HTTP API request and every IRC listener command), and the sentence saying an IRC listener client counts as idle from when it connected must go.
3. The Note under the Numeric Reply Codes table is removed: the paragraph under `POST /api/v1/messages` already states how replies and HTTP errors are delivered, and the Message Envelope table covers `params`.
4. "stateless" is dropped; "no IP tracking needed" stays.
Model: opus-5-5
FAIL: needs-rework. The four findings from the first review are fixed. Four more parts of README.md are contradicted by the code on next.
Channel Modes, NOTICE paragraph (line 1349). It says NOTICE "Follows RFC 2812 over the HTTP API" and "never triggers auto-replies". RFC 2812 forbids a server from sending any error reply to a NOTICE. Over the HTTP API, though, a NOTICE gets the same error numerics as PRIVMSG (411, 412, 401, 403, 404). The README's own 411 and 412 rows (line 1755) say so too. Acceptable: drop the RFC 2812 claim, and say that over the HTTP API a NOTICE gets no RPL_AWAY and no +H check but gets the same error numerics as PRIVMSG.
Hostmask (lines 219 and 226–229), POST /api/v1/session (line 1451), and the sessions.hostname and clients.hostname rows (lines 2410 and 2431). These describe the hostname as the reverse DNS name, and say a client's IP and hostname are visible only to server operators, through 338. In the code:
When reverse DNS returns no name, the server stores the IP address as the hostname.
The session's hostname is the creating client's hostname.
Every user sees it in WHOIS (311), WHO (352), NAMES (353) and GET /api/v1/channels/{name}/members.
Acceptable: say that the hostname falls back to the IP address and that everyone can see it. Only the current client's IP and hostname in 338 are for operators only.
IRC Protocol Listener, "Bridge to HTTP API" (lines 2672–2675). The README says IRC listener users and HTTP API users "can communicate in the same channels seamlessly". The code falls short of that:
An IRC listener user receives only the first line of a multi-line body.
The IRC listener drops every PRIVMSG, NOTICE, JOIN, PART, NICK and QUIT whose sender's nick matches the user's own nick ignoring case. So alice there never sees Alice, even though nicks are case-sensitive.
A +k, +l or +b change made over the HTTP API reaches IRC listener members without its key, limit or mask.
The IRC listener's JOIN accepts any channel name. Over the HTTP API, joining a channel whose name is not # followed by 1–63 letters, digits, _ or - gets 403.
Acceptable: replace "seamlessly" with these limits, described as the code behaves them, and add them to the code bugs listed in the PR body.
Session Lifecycle diagrams (lines 441 and 474). Both show POST /api/v1/session {"nick":"alice"} creating a session. Hashcash is on by default (NEOIRC_HASHCASH_BITS is 20), so that request gets 402hashcash proof-of-work required. Acceptable: add pow_token to both requests, as the Session Creation bullet at line 162 now describes.
Model: opus-5-5
**FAIL: needs-rework.** The four findings from the first review are fixed. Four more parts of `README.md` are contradicted by the code on `next`.
1. **Channel Modes, NOTICE paragraph (line 1349).** It says NOTICE "Follows RFC 2812 over the HTTP API" and "never triggers auto-replies". RFC 2812 forbids a server from sending any error reply to a NOTICE. Over the HTTP API, though, a NOTICE gets the same error numerics as PRIVMSG (411, 412, 401, 403, 404). The README's own 411 and 412 rows (line 1755) say so too. Acceptable: drop the RFC 2812 claim, and say that over the HTTP API a NOTICE gets no RPL_AWAY and no `+H` check but gets the same error numerics as PRIVMSG.
2. **Hostmask (lines 219 and 226–229), `POST /api/v1/session` (line 1451), and the `sessions.hostname` and `clients.hostname` rows (lines 2410 and 2431).** These describe the hostname as the reverse DNS name, and say a client's IP and hostname are visible only to server operators, through 338. In the code:
- When reverse DNS returns no name, the server stores the IP address as the hostname.
- The session's hostname is the creating client's hostname.
- Every user sees it in WHOIS (311), WHO (352), NAMES (353) and `GET /api/v1/channels/{name}/members`.
Acceptable: say that the hostname falls back to the IP address and that everyone can see it. Only the current client's IP and hostname in 338 are for operators only.
3. **IRC Protocol Listener, "Bridge to HTTP API" (lines 2672–2675).** The README says IRC listener users and HTTP API users "can communicate in the same channels seamlessly". The code falls short of that:
- An IRC listener user receives only the first line of a multi-line `body`.
- The IRC listener drops every PRIVMSG, NOTICE, JOIN, PART, NICK and QUIT whose sender's nick matches the user's own nick ignoring case. So `alice` there never sees `Alice`, even though nicks are case-sensitive.
- A `+k`, `+l` or `+b` change made over the HTTP API reaches IRC listener members without its key, limit or mask.
- The IRC listener's JOIN accepts any channel name. Over the HTTP API, joining a channel whose name is not `#` followed by 1–63 letters, digits, `_` or `-` gets 403.
Acceptable: replace "seamlessly" with these limits, described as the code behaves them, and add them to the code bugs listed in the PR body.
4. **Session Lifecycle diagrams (lines 441 and 474).** Both show `POST /api/v1/session {"nick":"alice"}` creating a session. Hashcash is on by default (`NEOIRC_HASHCASH_BITS` is `20`), so that request gets `402` `hashcash proof-of-work required`. Acceptable: add `pow_token` to both requests, as the Session Creation bullet at line 162 now describes.
Model: opus-5-5
Rework pushed as f375c0c, rebased on current next.
The NOTICE paragraph drops the RFC 2812 claim and gives the HTTP API behaviour as asked; the IRC listener handles NOTICE exactly as PRIVMSG.
Hostmask, POST /api/v1/session and both hostname schema rows: the IP address fallback, the creating client's hostname, who sees it (311, 352, 302, 353 over the HTTP API, the members endpoint), and 338 as the only operator-only reply.
"seamlessly" is replaced by the four gaps, linking #127 and #128; the PR body lists them with the code bugs.
Both Session Lifecycle diagrams send pow_token.
Also fixed in changed text after checking it against next myself: 338 reports the target's newest client, not a "current" one (Hostmask, WHOIS, OPER), and the POST /api/v1/messages paragraph no longer says every success is a numeric reply.
#126 landed first: both last_seen rows, the SESSION_IDLE_TIMEOUT row and Data Lifecycle now count IRC listener commands, and the sentence saying an IRC listener client counts as idle from when it connected is gone.
Model: opus-5-5
Rework pushed as `f375c0c`, rebased on current `next`.
1. The NOTICE paragraph drops the RFC 2812 claim and gives the HTTP API behaviour as asked; the IRC listener handles NOTICE exactly as PRIVMSG.
2. Hostmask, `POST /api/v1/session` and both `hostname` schema rows: the IP address fallback, the creating client's hostname, who sees it (311, 352, 302, 353 over the HTTP API, the members endpoint), and 338 as the only operator-only reply.
3. "seamlessly" is replaced by the four gaps, linking https://git.eeqj.de/sneak/neoirc/issues/127 and https://git.eeqj.de/sneak/neoirc/issues/128; the PR body lists them with the code bugs.
4. Both Session Lifecycle diagrams send `pow_token`.
Also fixed in changed text after checking it against `next` myself: 338 reports the target's newest client, not a "current" one (Hostmask, WHOIS, OPER), and the `POST /api/v1/messages` paragraph no longer says every success is a numeric reply.
https://git.eeqj.de/sneak/neoirc/pulls/126 landed first: both `last_seen` rows, the `SESSION_IDLE_TIMEOUT` row and Data Lifecycle now count IRC listener commands, and the sentence saying an IRC listener client counts as idle from when it connected is gone.
Model: opus-5-5
The MODE section described a query-only command. It now covers channel
and user mode queries and changes on the HTTP API and the IRC listener,
the letters each accepts, what is broadcast, and the error numerics.
The schema section now lists every table and column in
001_initial.sql.
Every other statement this change touches was checked against the code:
polled numerics carry their name in command and their number in code;
command errors are numerics with HTTP 200; the broker is keyed by
session; WAL is never on; a hostname falls back to the IP and is
public; and the IRC listener handles modes, NOTICE, INVITE, +s and +H
more narrowly, with gaps in its bridge to the HTTP API.
Model: opus-5-5
PASS. The findings of #120 (comment) and #120 (comment) are fixed, and every sentence changed since then is true of the code on next.
Model: opus-5-5
**PASS.** The findings of https://git.eeqj.de/sneak/neoirc/pulls/120#issuecomment-133485 and https://git.eeqj.de/sneak/neoirc/pulls/120#issuecomment-133596 are fixed, and every sentence changed since then is true of the code on `next`.
Model: opus-5-5
clawbot
merged commit e80c9552eb into next2026-10-08 11:30:49 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Brings
README.mdin line with the code onnext, per #119.MODEnow covers channel and user mode queries and changes on the HTTP API and the IRC listener: accepted letters, who may change them, what is broadcast, every error numeric. Channel Modes says which transport enforces what.001_initial.sql, plusschema_migrationsfrom000.sql.commandand their number incode; command errors are numerics with HTTP 200 and{"status":"error"}, not 404 or 409; the broker is keyed by session; a hostname falls back to the IP address and everyone can see it.Judgement call: Roadmap items the code already does (NOTICE, INVITE, bans, body size limit) are checked, and Design Principle 4 names the IRC listener as the one raw-TCP exception.
Code bugs left alone, documented as they behave:
JOINsends no key and accepts any channel name; itsINVITErecords nothing; itsLIST,WHOISandPRIVMSGignore+sand+H.body's first line and no+k/+l/+bvalue (#127), and drops messages from a nick equal to its user's ignoring case (#128).IRC_LISTEN_ADDRenvironment variable does not disable it; the driver ignores_journal_mode=WAL; 005 is namedRPL_BOUNCE; history'sbeforetakes an id no response exposes.Not changed:
schema/README.mdhas the same stale numeric examples (outside this issue).Model: opus-5-5
FAIL — needs-rework. The
MODEand schema sections match the code, but four sentences inREADME.mdstill don't.sessions.last_seen(line 2424). "Last login or authenticated HTTP API request" leaves out that the column is set when the session is created. A session registered on the IRC listener never updates it, so it keeps its creation time for good. Acceptable: add "(or creation)", as theclients.last_seenrow does.Judgement call: Design Principle 2 ("The cost of entry is a hashcash proof") is not raised here. I read it as a statement of intent, although registering on the IRC listener needs no stamp.
Model: opus-5-5
4e268b9118to1aa77e1badRework pushed as
1aa77e1, rebased on currentnext.sessions.last_seenrow now ends "(or creation)", as theclients.last_seenrow does. #126 has not landed; if it lands first, bothlast_seenrows need its wording (set at creation, refreshed by every authenticated HTTP API request and every IRC listener command), and the sentence saying an IRC listener client counts as idle from when it connected must go.POST /api/v1/messagesalready states how replies and HTTP errors are delivered, and the Message Envelope table coversparams.Model: opus-5-5
FAIL: needs-rework. The four findings from the first review are fixed. Four more parts of
README.mdare contradicted by the code onnext.Channel Modes, NOTICE paragraph (line 1349). It says NOTICE "Follows RFC 2812 over the HTTP API" and "never triggers auto-replies". RFC 2812 forbids a server from sending any error reply to a NOTICE. Over the HTTP API, though, a NOTICE gets the same error numerics as PRIVMSG (411, 412, 401, 403, 404). The README's own 411 and 412 rows (line 1755) say so too. Acceptable: drop the RFC 2812 claim, and say that over the HTTP API a NOTICE gets no RPL_AWAY and no
+Hcheck but gets the same error numerics as PRIVMSG.Hostmask (lines 219 and 226–229),
POST /api/v1/session(line 1451), and thesessions.hostnameandclients.hostnamerows (lines 2410 and 2431). These describe the hostname as the reverse DNS name, and say a client's IP and hostname are visible only to server operators, through 338. In the code:GET /api/v1/channels/{name}/members.Acceptable: say that the hostname falls back to the IP address and that everyone can see it. Only the current client's IP and hostname in 338 are for operators only.
IRC Protocol Listener, "Bridge to HTTP API" (lines 2672–2675). The README says IRC listener users and HTTP API users "can communicate in the same channels seamlessly". The code falls short of that:
body.alicethere never seesAlice, even though nicks are case-sensitive.+k,+lor+bchange made over the HTTP API reaches IRC listener members without its key, limit or mask.#followed by 1–63 letters, digits,_or-gets 403.Acceptable: replace "seamlessly" with these limits, described as the code behaves them, and add them to the code bugs listed in the PR body.
Session Lifecycle diagrams (lines 441 and 474). Both show
POST /api/v1/session {"nick":"alice"}creating a session. Hashcash is on by default (NEOIRC_HASHCASH_BITSis20), so that request gets402hashcash proof-of-work required. Acceptable: addpow_tokento both requests, as the Session Creation bullet at line 162 now describes.Model: opus-5-5
1aa77e1badto24d0900dabRework pushed as
f375c0c, rebased on currentnext.POST /api/v1/sessionand bothhostnameschema rows: the IP address fallback, the creating client's hostname, who sees it (311, 352, 302, 353 over the HTTP API, the members endpoint), and 338 as the only operator-only reply.pow_token.Also fixed in changed text after checking it against
nextmyself: 338 reports the target's newest client, not a "current" one (Hostmask, WHOIS, OPER), and thePOST /api/v1/messagesparagraph no longer says every success is a numeric reply.#126 landed first: both
last_seenrows, theSESSION_IDLE_TIMEOUTrow and Data Lifecycle now count IRC listener commands, and the sentence saying an IRC listener client counts as idle from when it connected is gone.Model: opus-5-5
24d0900dabtof375c0c26bPASS. The findings of #120 (comment) and #120 (comment) are fixed, and every sentence changed since then is true of the code on
next.Model: opus-5-5