Surfaced while building dmarzzz/shape-rotator-field-kit#20 (the matrix-bot-setup skill). The skill walks an end-user through /signup/api → /signup/api/crosssign → launch the prod-served landing/responder.py → click Verify in Element. End-state should be: bot signed by the user's USK, no red shields, full E2EE round-trip.
Three issues in landing/{responder.py,sas_verification.py} block that. Listed in priority order.
1. sas_verification.SASVerificationManager is to-device-only (load-bearing)
SASVerificationManager.__init__ (lines ~200–210) registers handlers exclusively under EventType.Class.TO_DEVICE. Modern Element initiates verification in-room when both parties share an E2EE room — m.key.verification.request arrives as an m.room.message content type in the DM, not as a to-device event.
That's exactly the path a user hits when they click "Verify" on the bot from their DM. The event reaches responder.py's on_msg handler, which matches only !ping/!whoami/!help and drops everything else. The SAS state machine never enters.
Repro: spin up a bot via the matrix-bot-setup skill, click Verify on the bot in Element (matrix.org account). Element shows "waiting for verification" forever. No SAS log entries on the responder side.
Fix sketch: extend SASVerificationManager to also listen for in-room m.key.verification.* (treating an m.room.message with msgtype=m.key.verification.request as the same entry point), and have responder.py's on_msg defer those to the manager before its command-dispatch path.
tests/sas_prod.py passes because its _SASInitiator sends to-device directly — but a real Element user never goes through that path.
2. responder.py crashes on the auto-intro post path
landing/responder.py:132:
resp = await client.send_message_event(DM_ROOM, EventType.ROOM_MESSAGE, content)
print(f"POSTED:{resp.event_id}", flush=True)
In current mautrix-python (0.21.0), send_message_event returns a str (the event_id), not an object. The .event_id access raises AttributeError and kills the responder right after a successful send.
Triggers whenever both DM_ROOM and INTRO env vars are set — i.e. anyone trying to use the documented auto-intro feature. The matrix-bot-setup skill bootstrap.py deliberately omits those env vars to dodge it, at the cost of leaving the new bot's auto-DM to the inviter empty (regression of UX in service of not crashing).
Fix: print(f"POSTED:{resp}", flush=True).
3. No logging.basicConfig() in responder.py
sas_verification.py uses logger = logging.getLogger("gateway.platforms.matrix.sas") and calls logger.info(...) for every SAS protocol step — request received, ready sent, accept, key, MAC, done, cancel reason. Without an explicit basicConfig, Python's root logger defaults to WARNING and all of that is silently dropped.
Made the SAS debugging in the field-kit-skill development session pure guesswork until I patched the local copy of responder.py to add logging.basicConfig(level=logging.INFO). Anyone running the prod-served responder will hit the same silent-failure UX.
Fix: one line near the top of responder.py —
logging.basicConfig(
level=os.environ.get("LOG_LEVEL", "INFO"),
format="%(name)s: %(message)s",
)
Severity
(1) is the load-bearing one. Without it the matrix-bot-setup skill produces a bot that's E2EE-capable for !ping/!whoami round-trip but shows as unverified in Element forever, because the Verify click silently no-ops on the bot side. (2) and (3) are quality-of-life — (2) is a regression of a documented feature, (3) is a debug-experience hit.
Happy to PR any/all of these if useful.
🤖 Generated with Claude Code
Surfaced while building dmarzzz/shape-rotator-field-kit#20 (the
matrix-bot-setupskill). The skill walks an end-user through/signup/api→/signup/api/crosssign→ launch the prod-servedlanding/responder.py→ click Verify in Element. End-state should be: bot signed by the user's USK, no red shields, full E2EE round-trip.Three issues in
landing/{responder.py,sas_verification.py}block that. Listed in priority order.1.
sas_verification.SASVerificationManageris to-device-only (load-bearing)SASVerificationManager.__init__(lines ~200–210) registers handlers exclusively underEventType.Class.TO_DEVICE. Modern Element initiates verification in-room when both parties share an E2EE room —m.key.verification.requestarrives as anm.room.messagecontent type in the DM, not as a to-device event.That's exactly the path a user hits when they click "Verify" on the bot from their DM. The event reaches
responder.py'son_msghandler, which matches only!ping/!whoami/!helpand drops everything else. The SAS state machine never enters.Repro: spin up a bot via the matrix-bot-setup skill, click Verify on the bot in Element (matrix.org account). Element shows "waiting for verification" forever. No SAS log entries on the responder side.
Fix sketch: extend
SASVerificationManagerto also listen for in-roomm.key.verification.*(treating anm.room.messagewithmsgtype=m.key.verification.requestas the same entry point), and have responder.py'son_msgdefer those to the manager before its command-dispatch path.tests/sas_prod.pypasses because its_SASInitiatorsends to-device directly — but a real Element user never goes through that path.2. responder.py crashes on the auto-intro post path
landing/responder.py:132:In current
mautrix-python(0.21.0),send_message_eventreturns astr(the event_id), not an object. The.event_idaccess raisesAttributeErrorand kills the responder right after a successful send.Triggers whenever both
DM_ROOMandINTROenv vars are set — i.e. anyone trying to use the documented auto-intro feature. The matrix-bot-setup skill bootstrap.py deliberately omits those env vars to dodge it, at the cost of leaving the new bot's auto-DM to the inviter empty (regression of UX in service of not crashing).Fix:
print(f"POSTED:{resp}", flush=True).3. No
logging.basicConfig()in responder.pysas_verification.pyuseslogger = logging.getLogger("gateway.platforms.matrix.sas")and callslogger.info(...)for every SAS protocol step — request received, ready sent, accept, key, MAC, done, cancel reason. Without an explicitbasicConfig, Python's root logger defaults to WARNING and all of that is silently dropped.Made the SAS debugging in the field-kit-skill development session pure guesswork until I patched the local copy of responder.py to add
logging.basicConfig(level=logging.INFO). Anyone running the prod-served responder will hit the same silent-failure UX.Fix: one line near the top of responder.py —
Severity
(1) is the load-bearing one. Without it the matrix-bot-setup skill produces a bot that's E2EE-capable for
!ping/!whoamiround-trip but shows as unverified in Element forever, because the Verify click silently no-ops on the bot side. (2) and (3) are quality-of-life — (2) is a regression of a documented feature, (3) is a debug-experience hit.Happy to PR any/all of these if useful.
🤖 Generated with Claude Code