Skip to content

Narrow-set filters the seat's own queue, so a receiver always has an identity (comms-g5zh.6) - #212

Merged
GraemeF merged 1 commit into
mainfrom
comms-g5zh.6
Jul 31, 2026
Merged

GraemeF merged 1 commit into
mainfrom
comms-g5zh.6

Conversation

@GraemeF

@GraemeF GraemeF commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

narrow-set.ts was a client-side filter over the minter's full event stream, so matches took IdentityId | undefined: pre-acquire there was no identity to compare a message's mentions against, and the mention arm had to be gated on that.

With the events queue registered against the seat's own principal (#209, #211), an unbound seat owns no queue to poll — ownerHttp refuses and the producer idles instead of polling (packages/zulip/events.ts, the UnboundEphemeralSession catch). Nothing can reach matches without a binding, so the optional parameter described a state that no longer exists.

What this removes:

  • the botIdentityId !== undefined guard, and with it mentionsMatches — once the guard goes it just forwards to mentionsIdentity, so the wrapper goes too;
  • IdentityId | undefined on NarrowSet.matches;
  • one test that asserted the deleted branch (a mention does not match pre-acquire) — it asserts a case that is no longer representable, and its "a mention of another identity doesn't match" content is already covered by a mention matches message-posted only when the bot is among the mentions.

At the pump's call site (server.ts) an absent binding now means "not this seat's event" rather than "match on channel narrows alone" — the same statement the producer makes one layer down. It is reachable only if a release lands between an event being produced and dispatched; there is no test for that arm, since the closure isn't reachable from outside makeProgram.

The remaining client-side filtering is what the substrate genuinely cannot express: Zulip has no per-topic delivery primitive, so thread narrows stay here. Recording thread intent as realm state via POST /user_topics would demote this filter from authority to cache — real, but a tightening rather than a subtraction, so it's left as follow-up.

The rest of the test churn is mechanical: 45 noBot (= undefined) call sites become a real receiving-seat id.

Gate green inside nix develop: 1212 pass, 0 fail.

…identity (comms-g5zh.6)

The narrow set was a client-side filter over the minter's full event
stream, and `matches` took `IdentityId | undefined` because pre-acquire
there was no identity to compare a message's mentions against.

With the queue registered against the seat's own principal, an unbound
seat owns no queue to poll: `ownerHttp` refuses and the producer idles
rather than polling. Nothing can reach `matches` without a binding, so
the optional parameter described a state that no longer exists.

`mentionsMatches` was the guard and nothing else — with the guard gone it
forwards to `mentionsIdentity`, so it goes too.

At the pump's call site an absent binding now means "not this seat's
event" rather than "match on channel narrows alone": the same statement
the producer makes one layer down.

Claude-Session: https://claude.ai/code/session_016126ihUG75C88Zs5ckuvnp
@GraemeF
GraemeF merged commit 001d2fb into main Jul 31, 2026
2 checks passed
@GraemeF
GraemeF deleted the comms-g5zh.6 branch July 31, 2026 09:57
GraemeF added a commit that referenced this pull request Jul 31, 2026
… nothing (comms-g5zh.7) (#213)

The minter subscribed to every public stream so it could receive on
behalf of a seat that had not yet minted, kept current by a boot-time
reconciler. With the events queue (#209) and the channel subscriptions
(#211, #212) both registered under the seat's own principal, no seat
receives through another — and that layer has nothing left to do.

The minter keeps the jobs that are its own: minting bots, and the
directory and history reads that need no principal.

**Removed**
- `packages/zulip/minter-reconciler.ts` and its tests.
- `reconcileMinterSubscriptions` from the Zulip adapter's shape, its
wiring, and its response schema.
- The boot-time reconcile call in the plugin's `main`, and its logging.
- The no-op stub in the above-port test seam.
- The adapter and `server.test.ts` tests covering the deleted
capability. `lazy mode does NOT mint at boot when COMMY_SUBSCRIBE is
unset` already asserts the property that matters — a seat that never
mints subscribes to nothing.

**Corrected**
Prose that described the retired arrangement: `tools.ts` still claimed
subscribe registered the *minter* for post-boot streams (it has gone out
on the seat's own credential since #211), the adapter's per-event filter
named the minter's subscription list, and the client README's boot
diagram opened with the reconcile step. `docs/agent-experience.md` now
reads as the worked example predicted: topic narrows and the event-queue
handle are what remain client-side, both filtering the agent's own
queue.

Pure subtraction — no new capability, no shims. Subscription
reconstruction (comms-70g4) is downstream of this, not part of it.

https://claude.ai/code/session_01P67vRP5hs9Yvo16vkWru4g
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