Add chat_whoami() and chat_addressed() - #9
Merged
Merged
Conversation
corteza asks two questions of every inbound message: is this mine, and was I addressed. It answered both by parsing Matrix user ids -- splitting "@bot:example.org" on the colon to get a localpart and looking for "@bot" in the body. That is transport knowledge in a consumer that is supposed to be transport-blind. chat_whoami() returns a chat_identity() with the account id and, where the adapter has it without asking the server, a display name. Matrix reads it off the config it already holds, Slack calls auth.test once and caches, IRC reports its NICK, loopback is fixed. chat_addressed() answers the second question, because the plain-text form of a mention is per-transport and writing one into a consumer is how that consumer learns which transport it is on. The default reads declared mentions only, so an adapter that skips it under-reports: a bot that misses being addressed goes quiet, one that over-reports talks over people, and unprompted is worse than absent. Matrix's method fixes a matching bug in passing. The old \\b boundary after "@bot" ends the word at a "." or "-", both legal in a localpart, so "@bot.deploy" read as a mention of "@bot" -- the wrong bot answered and the right one never saw it. A negative lookahead over the localpart grammar gets it right, and identifiers are escaped before interpolation so "@a.bot" no longer matches "@AxBot".
The malformed-user_id test passed with the guard mutated out: with user_id "bot" the fallback pattern is "@bot", and neither "anything at all" nor "bot" distinguishes it from the empty-localpart pattern the guard exists to prevent. Test the helper's own answers, and use a body with a bare @ in it -- the case where an unguarded empty localpart reads every email address as a mention.
State-reading and credential lifecycle. The migration plan assumed the four remaining mx.api calls mapped one-to-one onto missing verbs; three of them are one operation the contract has no shape for, and there are eleven mx.client calls the plan never counted. Records the concrete reason 1f is blocked: corteza rotates its own access token when a /model command renames the bot, and disk is how that rotation reaches the adapter. chat_poll()$client is a symptom of two rotation paths sharing a file, so chat_set_identity() has to come first.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1e of the corteza transport-blindness migration.
corteza asks two questions of every inbound message: is this mine, and was I addressed. It answered both by parsing Matrix user ids — splitting
@bot:example.orgon the colon for a localpart, then looking for@botin the body. That is transport knowledge sitting in the consumer that is supposed to be transport-blind.What lands
chat_whoami(client)returns achat_identity()with the account id and, where the adapter has it without asking the server, a display name. Matrix reads it off the config it already holds, Slack callsauth.testonce and caches it (the answer is a property of the token, andchat_addressed()asks once per message), IRC reports its NICK, loopback is fixed.chat_addressed(client, message)is a second verb rather than a field, because the plain-text form of a mention is per-transport and writing one into a consumer is how that consumer learns which transport it is on. Matrix has@botand the full user id, Slack has<@U0123>, IRC has a bare nick.The default reads declared mentions only, so an adapter that does not override it under-reports. A bot that misses being addressed goes quiet; one that over-reports talks over people, and unprompted is worse than absent.
New capability flag:
whoami. TRUE on all four adapters.A bug fixed on the way through
The old
\bboundary after@botends the word at a.or-, both legal in a Matrix localpart, so@bot.deployread as a mention of@bot— the wrong bot answered and the right one never saw it. A negative lookahead over the localpart grammar gets it right. Identifiers are escaped before interpolation too, so@a.botno longer matches@axbot.Verification
735/735 passing. 15 mutations run against the new guards, all caught.
One survived the first pass and was a real defect, not a test gap: R evaluates arguments lazily, so
identity_mentioned(chat_whoami(client)$id, message)short-circuited at an empty mentions list and never forced the promise. An adapter that could not say who it was quietly answered FALSE to "were you addressed" instead of raising — and silence is what that bug looks like from outside, which is also what working looks like. Fixed withforce(id).A second survived because the test could not discriminate: with a malformed
user_idthe fallback pattern happened to behave the same either way.matrix_localpart()is now tested directly, with a body containing a bare@— the case where an unguarded empty localpart reads every email address as a mention.Also in here
DESIGN.mdgains the two contracts phase 1 does not cover: state-reading (chat_channels,chat_history,chat_pending,chat_mark_read) and credential lifecycle. The second records why phase 1f is blocked — corteza rotates its own access token when a/modelcommand renames the bot, and disk is how that rotation reaches the adapter, sochat_poll()$clientcannot be removed untilchat_set_identity()exists.corteza's consumer is a follow-up PR, gated on this one reaching drat as 0.0.1.15.