feat(teams): phase 7 — the slash-command seam, and the bot's first tests #157
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/teams-phase7-slash-commands"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 7 of
docs/website/TEAMS.md.api.registerSlashCommandsstops throwing: a module registers a command's definition and handler together, the bot pulls the definitions over the internal listener, and the handler runs here. Forced by §0.4 — the bot container has nomodulesvolume — and the right boundary anyway.Pairs with Module-uo#14 (the
/guildcommand that proves the seam) and docs#161.Org-lead decisions taken before building
/guild; core registers nothing. Core does not own the word for a Team — that is what deleted its Team pages in phase 3 — so it does not publish the noun in a channel either.node --test), andbot-installbecomesbot-tests.POST /internal/refresh-commands, not a ride on/internal/config— whose body carries the decrypted bot token.What is here
Server.
registries.jsgains the staged registration, with validation that rejects anything Discord would reject as a batch — the bot registers the whole set in oneREST.put, so one bad option type costs every command, the bot's own included.utils/slashCommands.jsis the actor resolver, the access gate and the dispatcher. Two routes on the internal listener, both#swagger.ignored and behindrequireInternalKey.Bot.
appInternalClient(base derived fromSITE_INTERNAL_URL's origin, so no compose change),dynamicCommands(pull, merge, defer→dispatch→edit), and/internal/refresh-commands.Five things the tree disagreed with the design about
/teams/:slugdoes not exist, so §7.1's${siteBaseUrl}/teams/${slug}cannot be built. The handler builds its own link frompageUrlTemplate— the same hole phase 6 found in the mail path.auth_providers.kind, not the id slug. The id is operator-chosen; resolving by it would report "not linked" for every user on a deployment that named its provider anything else. Proved on the rig with a provider calledmy-discord.actorcarriesrolebesideisStaff. A module with its own audience rungs cannot place a caller from a boolean. It is the pairprojectRoster's viewer already carried.The live rig
Real ServUO + real sidecar (protocol 4) + the app with module-uo installed, with the bot's own pull/execute path driven against it and a fake standing in for Discord. It proved the audience rung holding over the chat surface (guilds gated to
staff: anonymous and linked-player refused, linked admin served, same command), a banned account resolving as unlinked, the disable nudge firing with its reason and degrading to a log line with no bot running, and the pull emptying + dispatch answeringunknownfor a module switched off at runtime.It found the defect in the second commit. Ephemerality is fixed at the deferral, which happens before the handler has said anything — so the envelope's
ephemeralwas read and then ignored, and/guild's "not shown to your account" refusal was posted into the channel, announcing a member's access level to everyone in it. A private answer to a publicly deferred command now withdraws the deferred reply and follows up ephemerally.Tests
1084 server (+18), 20 bot (new), 248 client.
routes.manifest.json/routes.guards.jsonregenerated — the two internal routes, bothrequireInternalKey. Swagger is byte-identical, as it should be.Not done here
BACKEND_DESIGN.md's mirroredapi-route-inventory.jsonis stale from earlier phases (166 public / 2 internal against a live 208 / 4). I dropped the counts from the prose rather than silently re-snapshotting a file this phase did not touch — worth its own pass.REST.putand a real interaction are the two things this walk could not exercise.🤖 Generated with Claude Code
https://claude.ai/code/session_01WnDSWzpUjw8t8C2hghysNz