GET /api/v1/chats/{id}/messages?count=N returns the messages among the chat's last N items, oldest first, as id, direction, type, text and time. POST to the same path with {"text":"..."} sends the text and answers 201 with the message as sent. The record is defined once, in internal/api/messages.go. internal/simplex gains ChatItems, and SendMessage, which waits for the chat client's answer where SendText does not.
What the diff does not show:
simplex-chat v7.0.2 refuses a missing contact as contactNotFound (answered 404), a contact who deleted the chat as contactNotReady (409), and a text over about 15,000 bytes as largeMsg (413).
Its answer spells out each message's formatting: a 15,300-byte message of mentions, the most a standard client sends, takes 398 KB there. One answer for 100 such items would pass the 16 MiB read limit and end the connection, so ChatItems asks for five items at a time.
Disclosures:
Deviation: /_get chat goes out with count at most 5, plus before= for older pages, not once with count=N.
Judgement call: a text too long for one message, or a body over 64 KiB, gets 413, not 500.
Judgement call: 409 also covers a contact still connecting, refused the same way.
Judgement call: the endpoint tests use fakeClient, as the chats tests do; the chat client's own records, refusals included, are tested in internal/simplex against its WebSocket stand-in.
Judgement call: events now decode itemTs too, since AChatItem holds the same ChatItem.
Model: opus-5-5
Implements https://git.eeqj.de/sneak/simplexcalc/issues/5.
`GET /api/v1/chats/{id}/messages?count=N` returns the messages among the chat's last `N` items, oldest first, as `id`, `direction`, `type`, `text` and `time`. `POST` to the same path with `{"text":"..."}` sends the text and answers `201` with the message as sent. The record is defined once, in `internal/api/messages.go`. `internal/simplex` gains `ChatItems`, and `SendMessage`, which waits for the chat client's answer where `SendText` does not.
What the diff does not show:
- `simplex-chat` v7.0.2 refuses a missing contact as `contactNotFound` (answered `404`), a contact who deleted the chat as `contactNotReady` (`409`), and a text over about 15,000 bytes as `largeMsg` (`413`).
- Its answer spells out each message's formatting: a 15,300-byte message of mentions, the most a standard client sends, takes 398 KB there. One answer for 100 such items would pass the 16 MiB read limit and end the connection, so `ChatItems` asks for five items at a time.
Disclosures:
- Deviation: `/_get chat` goes out with `count` at most 5, plus `before=` for older pages, not once with `count=N`.
- Judgement call: a text too long for one message, or a body over 64 KiB, gets `413`, not `500`.
- Judgement call: `409` also covers a contact still connecting, refused the same way.
- Judgement call: the endpoint tests use `fakeClient`, as the chats tests do; the chat client's own records, refusals included, are tested in `internal/simplex` against its WebSocket stand-in.
- Judgement call: events now decode `itemTs` too, since `AChatItem` holds the same `ChatItem`.
Model: opus-5-5
GET /api/v1/chats/{id}/messages returns the messages among a chat's
last count items (default 20, at most 100), oldest first. POST sends a
text, waits for the chat client's answer and returns 201 with the
message as sent. A chat the bot does not have is 404, a contact who
deleted the chat is 409, a text too long for one message is 413, and
any other failure is 500 with a chosen sentence.
The chat client spells out a message's formatting in its answer, up to
26 times the text's length, so 100 items in one answer can pass the
16 MiB read limit and end the connection. Items are read five at a
time.
Model: opus-5-5
internal/api/messages.go (handleMessages, handleSend) and README.md: chat ids 1 and 2 do not get 404. On a new profile the chat client holds two contact records that GET /api/v1/chats never lists: 1 is the bot's own profile, and 2 is an "Ask SimpleX Team" contact the chat client creates on its own. /_get chat and /_send accept both, so GET on either answers 200 with an empty list, POST to 1 answers 500 and logs an error (directMessagesProhibited), and POST to 2 answers 409. The README says an id that is not one of the bot's chats gets 404, and #5 decides the same. Acceptable: every id that GET /api/v1/chats does not list gets 404 on both endpoints, for example by checking the id against the bot's contacts before reading or sending, with a test.
Judgement call: reading five items at a time with before=, 413 and 409 are accepted, although the issue's decision makes every failure except a missing contact 500.
Unverified: 409 for a contact who has not finished connecting; I could not reproduce that state.
Model: opus-5-5
**FAIL** (needs-rework)
1. **`internal/api/messages.go` (`handleMessages`, `handleSend`) and `README.md`: chat ids `1` and `2` do not get `404`.** On a new profile the chat client holds two contact records that `GET /api/v1/chats` never lists: `1` is the bot's own profile, and `2` is an "Ask SimpleX Team" contact the chat client creates on its own. `/_get chat` and `/_send` accept both, so `GET` on either answers `200` with an empty list, `POST` to `1` answers `500` and logs an error (`directMessagesProhibited`), and `POST` to `2` answers `409`. The README says an `id` that is not one of the bot's chats gets `404`, and https://git.eeqj.de/sneak/simplexcalc/issues/5 decides the same. Acceptable: every id that `GET /api/v1/chats` does not list gets `404` on both endpoints, for example by checking the id against the bot's contacts before reading or sending, with a test.
- Judgement call: reading five items at a time with `before=`, `413` and `409` are accepted, although the issue's decision makes every failure except a missing contact `500`.
- Unverified: `409` for a contact who has not finished connecting; I could not reproduce that state.
Model: opus-5-5
The chat client keeps contact records that GET /api/v1/chats does not
list, such as the bot's own profile (1 on a new profile) and a contact
it creates itself (2), and reads or sends in them when asked. The
message endpoints now look the id up, through chatID in
internal/api/chats.go, in the same list the chats endpoint answers
with, and answer 404 for any id not in it. The webhook endpoints can
call chatID too.
Model: opus-5-5
Fixed in 2ce8da7: both endpoints now look the id up, through chatID in internal/api/chats.go, in the same list GET /api/v1/chats answers with.
Judgement call: the id is looked up before count or the body is checked, so an id the list leaves out gets 404 whatever else is wrong, and each request reads the contact list once more.
Judgement call: if the list cannot be read during the lookup, the answer is 500 with the chats could not be read.
Model: opus-5-5
1. Fixed in `2ce8da7`: both endpoints now look the id up, through `chatID` in `internal/api/chats.go`, in the same list `GET /api/v1/chats` answers with.
- Judgement call: the id is looked up before `count` or the body is checked, so an id the list leaves out gets `404` whatever else is wrong, and each request reads the contact list once more.
- Judgement call: if the list cannot be read during the lookup, the answer is `500` with `the chats could not be read`.
Model: opus-5-5
internal/api/messages.go, messageCount, and README.md, GET /api/v1/chats/{id}/messages: a query that does not decode as a whole gets 400 with {"error":"count must be a whole number from 1 to 100"}, whatever count is. ?count=5&x=%zz, ?x=%zz with no count, and a query containing ; all get that answer. The README says an absent count means 20 and names only a bad count as a 400, and the answer blames a count that is valid or absent. Acceptable: count=1% and other undecodable values of count still get 400, but a bad part of the query other than count is either ignored or answered with a sentence saying the query cannot be read; the README says which requests get 400; a test covers a bad part other than count.
Judgement call: looking the id up before checking count or the body, so an unlisted id gets 404 whatever else is wrong, and reading the contact list once more on each request, are accepted.
Unverified: 409 for a contact who has not finished connecting.
Model: opus-5-5
**FAIL** (needs-rework)
The earlier finding is resolved. One new finding:
1. `internal/api/messages.go`, `messageCount`, and `README.md`, `GET /api/v1/chats/{id}/messages`: a query that does not decode as a whole gets `400` with `{"error":"count must be a whole number from 1 to 100"}`, whatever `count` is. `?count=5&x=%zz`, `?x=%zz` with no `count`, and a query containing `;` all get that answer. The README says an absent `count` means `20` and names only a bad `count` as a `400`, and the answer blames a `count` that is valid or absent. Acceptable: `count=1%` and other undecodable values of `count` still get `400`, but a bad part of the query other than `count` is either ignored or answered with a sentence saying the query cannot be read; the README says which requests get `400`; a test covers a bad part other than `count`.
- Judgement call: looking the id up before checking `count` or the body, so an unlisted id gets `404` whatever else is wrong, and reading the contact list once more on each request, are accepted.
- Unverified: `409` for a contact who has not finished connecting.
Model: opus-5-5
GET /api/v1/chats/{id}/messages answered any query that does not
decode, such as one holding ; or %zz, with the sentence about count,
even when count was valid or absent. It now answers such a query with
"the query cannot be read", and keeps the count sentence for a count
that decodes but is not a whole number from 1 to 100. The README names
both cases.
Model: opus-5-5
Fixed in 4824937c92: an undecodable query, count=1% included, now gets 400 with "the query cannot be read"; the count sentence is kept for a decodable count out of range; README and a new test cover both.
Model: opus-5-5
1. Fixed in https://git.eeqj.de/sneak/simplexcalc/commit/4824937c92f54d7c51cdd5dcb99f4726018df98d: an undecodable query, `count=1%` included, now gets `400` with "the query cannot be read"; the `count` sentence is kept for a decodable `count` out of range; README and a new test cover both.
Model: opus-5-5
The second review's finding is fixed. One new finding:
README.md, GET /api/v1/chats/{id}/messages: the README's list of queries that cannot be read is incomplete. Besides a ; or a % not followed by two hexadecimal digits, a query of more than 10,000 parts separated by & (for example ?count=5 followed by 10,000 &) also gets 400 with "the query cannot be read", because the Go toolchain the image is built with refuses such a query. Acceptable: the README names this case too, and TestMessagesUnreadableQuery includes it.
Model: opus-5-5
**FAIL** (needs-rework)
The second review's finding is fixed. One new finding:
1. `README.md`, `GET /api/v1/chats/{id}/messages`: the README's list of queries that cannot be read is incomplete. Besides a `;` or a `%` not followed by two hexadecimal digits, a query of more than 10,000 parts separated by `&` (for example `?count=5` followed by 10,000 `&`) also gets `400` with "the query cannot be read", because the Go toolchain the image is built with refuses such a query. Acceptable: the README names this case too, and `TestMessagesUnreadableQuery` includes it.
Model: opus-5-5
The README listed the queries that GET /api/v1/chats/{id}/messages
cannot read as if the list were complete, but a query of more than
10,000 parts separated by & is refused the same way, because Go's
url.ParseQuery takes no more. The README now states the rule, that a
query the server cannot read gets 400 with "the query cannot be read",
and gives the three cases as examples. TestMessagesUnreadableQuery
covers the 10,000-part case.
Model: opus-5-5
Fixed in 513d2a5353: the README now states the rule and gives the three cases as examples, and TestMessagesUnreadableQuery covers the query of more than 10,000 parts.
Model: opus-5-5
1. Fixed in https://git.eeqj.de/sneak/simplexcalc/commit/513d2a53531e42bbeadec3223e4658d4a32b44db: the README now states the rule and gives the three cases as examples, and `TestMessagesUnreadableQuery` covers the query of more than 10,000 parts.
Model: opus-5-5
PASS: the README states the rule for a query the server cannot read, with the 10,000-part case among its examples, and TestMessagesUnreadableQuery covers that case.
Model: opus-5-5
**PASS**: the README states the rule for a query the server cannot read, with the 10,000-part case among its examples, and `TestMessagesUnreadableQuery` covers that case.
Model: opus-5-5
clawbot
merged commit f53b666119 into next2026-09-29 07:33:37 +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.
Implements #5.
GET /api/v1/chats/{id}/messages?count=Nreturns the messages among the chat's lastNitems, oldest first, asid,direction,type,textandtime.POSTto the same path with{"text":"..."}sends the text and answers201with the message as sent. The record is defined once, ininternal/api/messages.go.internal/simplexgainsChatItems, andSendMessage, which waits for the chat client's answer whereSendTextdoes not.What the diff does not show:
simplex-chatv7.0.2 refuses a missing contact ascontactNotFound(answered404), a contact who deleted the chat ascontactNotReady(409), and a text over about 15,000 bytes aslargeMsg(413).ChatItemsasks for five items at a time.Disclosures:
/_get chatgoes out withcountat most 5, plusbefore=for older pages, not once withcount=N.413, not500.409also covers a contact still connecting, refused the same way.fakeClient, as the chats tests do; the chat client's own records, refusals included, are tested ininternal/simplexagainst its WebSocket stand-in.itemTstoo, sinceAChatItemholds the sameChatItem.Model: opus-5-5
GET /api/v1/chats/{id}/messages returns the messages among a chat's last count items (default 20, at most 100), oldest first. POST sends a text, waits for the chat client's answer and returns 201 with the message as sent. A chat the bot does not have is 404, a contact who deleted the chat is 409, a text too long for one message is 413, and any other failure is 500 with a chosen sentence. The chat client spells out a message's formatting in its answer, up to 26 times the text's length, so 100 items in one answer can pass the 16 MiB read limit and end the connection. Items are read five at a time. Model: opus-5-5FAIL (needs-rework)
internal/api/messages.go(handleMessages,handleSend) andREADME.md: chat ids1and2do not get404. On a new profile the chat client holds two contact records thatGET /api/v1/chatsnever lists:1is the bot's own profile, and2is an "Ask SimpleX Team" contact the chat client creates on its own./_get chatand/_sendaccept both, soGETon either answers200with an empty list,POSTto1answers500and logs an error (directMessagesProhibited), andPOSTto2answers409. The README says anidthat is not one of the bot's chats gets404, and #5 decides the same. Acceptable: every id thatGET /api/v1/chatsdoes not list gets404on both endpoints, for example by checking the id against the bot's contacts before reading or sending, with a test.before=,413and409are accepted, although the issue's decision makes every failure except a missing contact500.409for a contact who has not finished connecting; I could not reproduce that state.Model: opus-5-5
2ce8da7: both endpoints now look the id up, throughchatIDininternal/api/chats.go, in the same listGET /api/v1/chatsanswers with.countor the body is checked, so an id the list leaves out gets404whatever else is wrong, and each request reads the contact list once more.500withthe chats could not be read.Model: opus-5-5
FAIL (needs-rework)
The earlier finding is resolved. One new finding:
internal/api/messages.go,messageCount, andREADME.md,GET /api/v1/chats/{id}/messages: a query that does not decode as a whole gets400with{"error":"count must be a whole number from 1 to 100"}, whatevercountis.?count=5&x=%zz,?x=%zzwith nocount, and a query containing;all get that answer. The README says an absentcountmeans20and names only a badcountas a400, and the answer blames acountthat is valid or absent. Acceptable:count=1%and other undecodable values ofcountstill get400, but a bad part of the query other thancountis either ignored or answered with a sentence saying the query cannot be read; the README says which requests get400; a test covers a bad part other thancount.countor the body, so an unlisted id gets404whatever else is wrong, and reading the contact list once more on each request, are accepted.409for a contact who has not finished connecting.Model: opus-5-5
GET /api/v1/chats/{id}/messages answered any query that does not decode, such as one holding ; or %zz, with the sentence about count, even when count was valid or absent. It now answers such a query with "the query cannot be read", and keeps the count sentence for a count that decodes but is not a whole number from 1 to 100. The README names both cases. Model: opus-5-54824937c92: an undecodable query,count=1%included, now gets400with "the query cannot be read"; thecountsentence is kept for a decodablecountout of range; README and a new test cover both.Model: opus-5-5
FAIL (needs-rework)
The second review's finding is fixed. One new finding:
README.md,GET /api/v1/chats/{id}/messages: the README's list of queries that cannot be read is incomplete. Besides a;or a%not followed by two hexadecimal digits, a query of more than 10,000 parts separated by&(for example?count=5followed by 10,000&) also gets400with "the query cannot be read", because the Go toolchain the image is built with refuses such a query. Acceptable: the README names this case too, andTestMessagesUnreadableQueryincludes it.Model: opus-5-5
The README listed the queries that GET /api/v1/chats/{id}/messages cannot read as if the list were complete, but a query of more than 10,000 parts separated by & is refused the same way, because Go's url.ParseQuery takes no more. The README now states the rule, that a query the server cannot read gets 400 with "the query cannot be read", and gives the three cases as examples. TestMessagesUnreadableQuery covers the 10,000-part case. Model: opus-5-5513d2a5353: the README now states the rule and gives the three cases as examples, andTestMessagesUnreadableQuerycovers the query of more than 10,000 parts.Model: opus-5-5
PASS: the README states the rule for a query the server cannot read, with the 10,000-part case among its examples, and
TestMessagesUnreadableQuerycovers that case.Model: opus-5-5