Skip to content

Let somebody ask to join, and let a moderator answer (GRYT-193) - #126

Merged
sivert-io merged 1 commit into
mainfrom
claude/GRYT-193-approval-queue-client
Aug 12, 2026
Merged

Let somebody ask to join, and let a moderator answer (GRYT-193)#126
sivert-io merged 1 commit into
mainfrom
claude/GRYT-193-approval-queue-client

Conversation

@sivert-io

Copy link
Copy Markdown
Member

The client half of GRYT-193. Goes with Gryt-chat/server#46 — that one is a backend nobody
can reach without this: no way to set the policy, no way to see who is waiting, and a refusal
that reads like a failure. Merge them together.

What changed

  • "Who can join" stops being a switch. Two values became three, so it is a select:
    With an invite · After you let them in · Anyone, no invite. A line appears under it
    when the middle one is picked, saying where the people who ask turn up.
    normalizeJoinPolicy mirrors the server's — anything unrecognised reads as invite, so a
    value from a newer server leaves a server harder to get into on both sides of the wire.
  • A Requests tab, beside Invites, because both are about how somebody gets in. A row is a
    nickname, whatever they wrote, and when they asked. That is all there is to go on and the
    row does not dress it up.
  • approval_pending is not an error toast. Nothing went wrong and there is nothing to
    retry — the answer comes from a person, so it is a plain message that says so.
  • The add-server dialog asks for a line up front, since /info publishes the policy, so
    the note is offered before somebody is turned away rather than after. Once the request is
    in, the dialog says so and stops offering the button that would only ask again.

Verified against a running server

Not just compiled — driven against the server from server#46 with the queue live:

step result
policy set to request from the client's own settings event joinPolicy: "request"
two strangers ask, one with a note both refused approval_pending
Requests tab "2 people waiting", Ada with her note, Kari without, both timestamped
Let in on Ada list drops to "1 person waiting"
database afterwards Ada approved, Kari pending, members still just Owner

That last row is the point: approving does not admit anybody. They get in on their next
attempt, which is exactly what the refusal told them would happen.

Worth your attention

  • The note is user text from somebody who is not a member yet — the least trusted string
    in the join path. It is rendered as text, never as markup, capped at 300 both here and on
    the server, and trimmed server-side (the harness sent one padded with spaces and the queue
    shows it clean).
  • Approving asks for the list again rather than removing the row locally. Two moderators
    can be looking at the same queue, and the server broadcasts a UI update on a decision.
  • The note rides on server:verify, not the challenge — same reasoning as the server PR:
    the challenge binds what must not change between the two steps, and a note is a message to a
    person that nothing downstream trusts.
  • Not verified by clicking: the policy select and the add-server dialog's note field and
    waiting callout are rendered UI I mounted rather than clicked through — this app's modals
    cannot be driven from the preview pane. The tab itself was exercised for real, including
    the decision round-trip. The dialog is worth one manual pass.

🤖 Generated with Claude Code

The client half of the approval queue. Without it the server half is a backend
nobody can reach: no way to set the policy, no way to see who is waiting, and a
refusal that reads like a failure.

Who can join stops being a switch. It had two values and now has three, so it is
a select — with a line under it, when the middle one is picked, saying where the
people who ask turn up. normalizeJoinPolicy mirrors the server's: anything
unrecognised reads as invite, so a value from a newer server leaves a server
harder to get into on both sides of the wire.

Requests is a new tab beside Invites, because both are about how somebody gets
in. A row is a nickname, whatever they wrote, and when they asked — which is
all there is to go on, and the row does not dress it up. The note is the only
part they control, so it is rendered as text and never as markup. Approving
asks for the list again rather than dropping the row locally: two moderators can
be looking at the same queue.

On the other side, approval_pending is not an error toast. Nothing went wrong
and there is nothing to retry — the answer comes from a person. The add-server
dialog offers a line to send with the request before anybody tries, since /info
publishes the policy, and stops offering the join button once the request is in.
A denial reads the same as a pending one, because the server refuses to say
which.

Verified against a running server with the queue: two strangers held, both
listed with the notes they sent, Let in decides and the list drops to one, and
the approved row stays approved without making them a member — they get in on
the next attempt, which is what they were told.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sivert-io
sivert-io merged commit dee994a into main Aug 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant