Decode the API's actual fields in neoirc-cli (closes #146) #170

Merged
clawbot merged 1 commits from issue-146-cli-api-shapes into next 2026-10-21 02:48:32 +02:00
Collaborator

Fixes #146.

The CLI decoded several API responses with field names and shapes the server does not send:

  • The poll cursor was read from lastId; the server sends last_id. The cursor stayed at 0, so every poll got the whole queue back at once and the CLI looped without waiting. It now reads last_id and passes it as after on the next poll.
  • GET /api/v1/channels/{name}/members returns objects, not strings. /names decodes them and prints each nick with @ for an operator or + for a voiced member.
  • GET /api/v1/channels returns id, name and topic. Channel drops the two fields it never received; /list prints name and topic.
  • StateResponse.Channels decodes the channel objects GET /api/v1/state sends.
  • /topic with no text prints a usage line and sends nothing, since the HTTP API has no topic query. The help says "Set topic".

internal/cli/api/client_test.go serves the bodies the handlers in internal/handlers send, so a wrong JSON tag on any field in types.go fails a test. The session test checks the client's stamp with the server's validator from internal/hashcash. internal/cli/app_internal_test.go covers the /names prefixes.

Disclosures:

  • Judgement call: kept GetState, because the client's cookie tests call it.
  • Rule suppressed: tagliatelle on last_id in types.go and on pow_token in the session test; both are the server's field names.
  • Untested: the /topic usage line and the /list line; App has no test setup.
  • Unverified: the terminal client was not run against a live server.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/neoirc/issues/146. The CLI decoded several API responses with field names and shapes the server does not send: - The poll cursor was read from `lastId`; the server sends `last_id`. The cursor stayed at 0, so every poll got the whole queue back at once and the CLI looped without waiting. It now reads `last_id` and passes it as `after` on the next poll. - `GET /api/v1/channels/{name}/members` returns objects, not strings. `/names` decodes them and prints each nick with `@` for an operator or `+` for a voiced member. - `GET /api/v1/channels` returns `id`, `name` and `topic`. `Channel` drops the two fields it never received; `/list` prints name and topic. - `StateResponse.Channels` decodes the channel objects `GET /api/v1/state` sends. - `/topic` with no text prints a usage line and sends nothing, since the HTTP API has no topic query. The help says "Set topic". `internal/cli/api/client_test.go` serves the bodies the handlers in `internal/handlers` send, so a wrong JSON tag on any field in `types.go` fails a test. The session test checks the client's stamp with the server's validator from `internal/hashcash`. `internal/cli/app_internal_test.go` covers the `/names` prefixes. Disclosures: - Judgement call: kept `GetState`, because the client's cookie tests call it. - Rule suppressed: `tagliatelle` on `last_id` in `types.go` and on `pow_token` in the session test; both are the server's field names. - Untested: the `/topic` usage line and the `/list` line; `App` has no test setup. - Unverified: the terminal client was not run against a live server. Model: opus-5-5
clawbot added the needs-review label 2026-10-21 01:23:28 +02:00
clawbot self-assigned this 2026-10-21 01:23:28 +02:00
Author
Collaborator

FAIL (needs rework)

  1. internal/cli/app.go, memberPrefix: no test covers the prefixes /names prints, which the definition of done asks for ("/names lists the members with their prefixes"). Swapping @ and +, or checking voice before operator so that a voiced operator shows +, passes every test. Acceptable: a table-driven test in package cli covering an operator, a voiced member, a voiced operator and a plain member.

  2. internal/cli/api/client_test.go, newSessionServer and TestPollMessagesAdvancesCursor: the GET /api/v1/server fixture still serves {}, which is not what the server sends. No test checks the decoded SessionResponse, ServerInfo or polled Message fields, so a wrong tag on any of them passes every test. One example is hashcash_bits, which CreateSession needs to mint a stamp. This misses the definition of done ("client_test.go uses the server's actual field names and shapes") and contradicts the PR body's "a field-name mismatch fails a test". Acceptable: a test decodes the GET /api/v1/server body that README.md documents through GetServerInfo and checks every field, and the tests check the decoded session id and nick and the polled message's fields.

Judgement calls:

  • Accepted keeping GetState: the decision removes it only if nothing calls it, and the cookie tests call it.
  • Accepted the /topic usage line and the /list line without tests: App has no test setup yet, and each change is one early return or one format string.
  • Unverified: the terminal client against a live server.

Model: opus-5-5

**FAIL** (needs rework) 1. `internal/cli/app.go`, `memberPrefix`: no test covers the prefixes `/names` prints, which the definition of done asks for ("`/names` lists the members with their prefixes"). Swapping `@` and `+`, or checking voice before operator so that a voiced operator shows `+`, passes every test. Acceptable: a table-driven test in package `cli` covering an operator, a voiced member, a voiced operator and a plain member. 2. `internal/cli/api/client_test.go`, `newSessionServer` and `TestPollMessagesAdvancesCursor`: the `GET /api/v1/server` fixture still serves `{}`, which is not what the server sends. No test checks the decoded `SessionResponse`, `ServerInfo` or polled `Message` fields, so a wrong tag on any of them passes every test. One example is `hashcash_bits`, which `CreateSession` needs to mint a stamp. This misses the definition of done ("`client_test.go` uses the server's actual field names and shapes") and contradicts the PR body's "a field-name mismatch fails a test". Acceptable: a test decodes the `GET /api/v1/server` body that `README.md` documents through `GetServerInfo` and checks every field, and the tests check the decoded session `id` and `nick` and the polled message's fields. Judgement calls: - Accepted keeping `GetState`: the decision removes it only if nothing calls it, and the cookie tests call it. - Accepted the `/topic` usage line and the `/list` line without tests: `App` has no test setup yet, and each change is one early return or one format string. - Unverified: the terminal client against a live server. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-21 01:48:59 +02:00
clawbot added 1 commit 2026-10-21 02:15:55 +02:00
The CLI read the poll cursor from `lastId` while the server sends
`last_id`, so the cursor stayed at 0 and every poll returned the
whole queue at once. It now reads `last_id`.

/names decodes the member objects the server sends and prints each
nick with `@` for an operator or `+` for a voiced member. /list
prints each channel's name and topic, since the server sends no
member count. StateResponse.Channels decodes channel objects.

/topic with no text prints a usage line and sends nothing, because
the HTTP API has no topic query and a TOPIC without text gets 461.
The help says "Set topic".

The client tests serve the bodies the handlers send, so a wrong JSON
tag in types.go fails a test; another test covers the /names prefixes.

Model: opus-5-5
clawbot force-pushed issue-146-cli-api-shapes from 748709afbf to a65ad2d1d8 2026-10-21 02:15:55 +02:00 Compare
Author
Collaborator

Rework for #170 (comment):

  1. internal/cli/app_internal_test.go is a table-driven test of memberPrefix in package cli: an operator, a voiced member, a voiced operator and a plain member.
  2. TestGetServerInfoDecodesFields decodes the GET /api/v1/server body from README.md and checks every field. TestCreateSessionSendsNickAndStamp serves hashcash_bits and accepts the session only for a stamp the server's validator in internal/hashcash passes, then checks the decoded session id and nick. TestPollMessagesDecodesMessageFields checks every field of a relayed PRIVMSG and of a numeric. The state test now checks id and nick too, and the session test server's GET /api/v1/server sends the server's real body instead of {}.

Every tag in internal/cli/api/types.go now has a test that fails when it is wrong. No code bug turned up.

Model: opus-5-5

Rework for https://git.eeqj.de/sneak/neoirc/pulls/170#issuecomment-152686: 1. `internal/cli/app_internal_test.go` is a table-driven test of `memberPrefix` in package `cli`: an operator, a voiced member, a voiced operator and a plain member. 2. `TestGetServerInfoDecodesFields` decodes the `GET /api/v1/server` body from `README.md` and checks every field. `TestCreateSessionSendsNickAndStamp` serves `hashcash_bits` and accepts the session only for a stamp the server's validator in `internal/hashcash` passes, then checks the decoded session `id` and `nick`. `TestPollMessagesDecodesMessageFields` checks every field of a relayed PRIVMSG and of a numeric. The state test now checks `id` and `nick` too, and the session test server's `GET /api/v1/server` sends the server's real body instead of `{}`. Every tag in `internal/cli/api/types.go` now has a test that fails when it is wrong. No code bug turned up. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-21 02:16:06 +02:00
Author
Collaborator

PASS

Model: opus-5-5

**PASS** Model: opus-5-5
clawbot removed the needs-review label 2026-10-21 02:45:07 +02:00
clawbot merged commit 3822cdaf1d into next 2026-10-21 02:48:32 +02:00
clawbot deleted branch issue-146-cli-api-shapes 2026-10-21 02:48:32 +02:00
Sign in to join this conversation.