docs: correct Discord durability boundary
This commit is contained in:
@@ -31,7 +31,9 @@ For an inbound guild message, the current implementation:
|
||||
|
||||
The gateway then verifies the HMAC-SHA-256 envelope with `DISCORD_SERVICE_TOKEN`, re-applies the allowlists and binding/role check, requires the conversation ID to match the bound logical agent and channel/thread, and claims the native Discord message ID in a bounded replay cache. The default replay cache is in-process, retains IDs for 15 minutes, and is bounded at 10,000 entries; it is not a durable inbox.
|
||||
|
||||
For ordinary chat, the gateway persists and dispatches using `DISCORD_SERVICE_USER_ID`; `DISCORD_SERVICE_TENANT_ID` is used when configured and otherwise ordinary chat falls back to the service user ID as its tenant. Privileged approval and stop additionally require a configured tenant and a paired `mosaicUserId`. The durable session's logical agent must match the binding before approval or stop is accepted. The approval is consumed once against the exact runtime target; the Discord service account is not substituted for the approving paired user.
|
||||
For ordinary chat, the gateway attempts persistence and dispatch using `DISCORD_SERVICE_USER_ID`; `DISCORD_SERVICE_TENANT_ID` is used when configured and otherwise ordinary chat falls back to the service user ID as its tenant. The Discord external route is not a UUID, while persisted conversation IDs are UUIDs; no current route-to-UUID mapping proves that ordinary Discord persistence succeeds. The gateway may continue dispatch after a persistence/binding failure, so successful live delivery is not durable-history evidence.
|
||||
|
||||
Privileged approval and stop additionally require a configured tenant, a paired `mosaicUserId`, and a previously enrolled durable session. The durable session's logical agent must match the binding before approval or stop is accepted. The approval is consumed once against the exact runtime target; the Discord service account is not substituted for the approving paired user.
|
||||
|
||||
The trusted `agentConfigId` in each binding is resolved by the gateway. Its provisioned agent name must exactly equal `instanceId`. Discord cannot choose an arbitrary agent, provider, or model in the message payload, and Discord ingress does not use the general routing engine for a new session.
|
||||
|
||||
@@ -39,20 +41,20 @@ The trusted `agentConfigId` in each binding is resolved by the gateway. Its prov
|
||||
|
||||
The gateway's current plugin factory is in [`plugin.module.ts`](../../../apps/gateway/src/plugin/plugin.module.ts). When `DISCORD_BOT_TOKEN` is present, the following Discord values are required or validated as shown:
|
||||
|
||||
| Name | Required/current behavior |
|
||||
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `DISCORD_BOT_TOKEN` | Enables the Discord plugin and supplies the Discord bot credential. |
|
||||
| `DISCORD_SERVICE_TOKEN` | Required when the bot is enabled. Authenticates the Socket.IO service handshake and signs/verifies ingress envelopes. Treat as a high-entropy secret. |
|
||||
| `DISCORD_SERVICE_USER_ID` | Required when the bot is enabled. Provisioned Mosaic service principal used for ordinary Discord persistence and dispatch. |
|
||||
| `DISCORD_SERVICE_TENANT_ID` | Not required to start ordinary Discord chat, but required for the `/approve` and `/stop <approval>` control path. Use the provisioned tenant for the service boundary. |
|
||||
| `DISCORD_GATEWAY_URL` | Base gateway URL. The plugin connects to `${DISCORD_GATEWAY_URL}/chat`; the gateway factory default is `http://localhost:14242`. |
|
||||
| `DISCORD_GUILD_ID` | Optional guild ID used only by the current project-channel provisioning helper. It is not the message authorization allowlist. |
|
||||
| `DISCORD_ALLOWED_GUILD_IDS` | Required, comma-separated guild IDs. Empty or missing values fail closed during plugin creation. |
|
||||
| `DISCORD_ALLOWED_CHANNEL_IDS` | Required, comma-separated parent text-channel IDs. Thread messages are checked against their configured parent. |
|
||||
| `DISCORD_ALLOWED_USER_IDS` | Required, comma-separated Discord user IDs. This allowlist is checked in addition to `pairedUsers`. |
|
||||
| `DISCORD_INTERACTION_BINDINGS` | Required, non-empty JSON array of configuration-owned bindings. Malformed or empty data fails plugin creation. |
|
||||
| `DISCORD_MESSAGE_RATE_LIMIT_PER_MINUTE` | Optional positive integer; default is `30` authorized turns per guild/channel/user window. Zero, negative, and non-integer values are rejected. |
|
||||
| `DISCORD_THREAD_RATE_LIMIT_PER_MINUTE` | Optional positive integer; default is `5` mention-triggered thread routes per guild/channel/user window. Invalid values are rejected. |
|
||||
| Name | Required/current behavior |
|
||||
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `DISCORD_BOT_TOKEN` | Enables the Discord plugin and supplies the Discord bot credential. |
|
||||
| `DISCORD_SERVICE_TOKEN` | Required when the bot is enabled. Authenticates the Socket.IO service handshake and signs/verifies ingress envelopes. Treat as a high-entropy secret. |
|
||||
| `DISCORD_SERVICE_USER_ID` | Required when the bot is enabled. Provisioned Mosaic service principal used for ordinary Discord dispatch and attempted persistence; durable history is not guaranteed. |
|
||||
| `DISCORD_SERVICE_TENANT_ID` | Not required to start ordinary Discord chat, but required for the `/approve` and `/stop <approval>` control path. Use the provisioned tenant for the service boundary. |
|
||||
| `DISCORD_GATEWAY_URL` | Base gateway URL. The plugin connects to `${DISCORD_GATEWAY_URL}/chat`; the gateway factory default is `http://localhost:14242`. |
|
||||
| `DISCORD_GUILD_ID` | Optional guild ID used only by the current project-channel provisioning helper. It is not the message authorization allowlist. |
|
||||
| `DISCORD_ALLOWED_GUILD_IDS` | Required, comma-separated guild IDs. Empty or missing values fail closed during plugin creation. |
|
||||
| `DISCORD_ALLOWED_CHANNEL_IDS` | Required, comma-separated parent text-channel IDs. Thread messages are checked against their configured parent. |
|
||||
| `DISCORD_ALLOWED_USER_IDS` | Required, comma-separated Discord user IDs. This allowlist is checked in addition to `pairedUsers`. |
|
||||
| `DISCORD_INTERACTION_BINDINGS` | Required, non-empty JSON array of configuration-owned bindings. Malformed or empty data fails plugin creation. |
|
||||
| `DISCORD_MESSAGE_RATE_LIMIT_PER_MINUTE` | Optional positive integer; default is `30` authorized turns per guild/channel/user window. Zero, negative, and non-integer values are rejected. |
|
||||
| `DISCORD_THREAD_RATE_LIMIT_PER_MINUTE` | Optional positive integer; default is `5` mention-triggered thread routes per guild/channel/user window. Invalid values are rejected. |
|
||||
|
||||
`MOSAIC_AGENT_NAME` and `MOSAIC_AGENT_CONFIG_ID` are not substitutes for a Discord binding. The current Discord binding uses `instanceId` and `agentConfigId` inside `DISCORD_INTERACTION_BINDINGS`; do not invent a different environment-based routing contract.
|
||||
|
||||
@@ -114,6 +116,7 @@ The daemon reads its environment from `~/.config/mosaic/gateway/.env` by default
|
||||
| Unsafe attachment metadata or URL | Gateway rejects the message before acknowledgement/dispatch. Current bounds include at most 10 attachments, HTTPS URLs without credentials, query strings, or fragments, and bounded ID/name/URL/metadata lengths. |
|
||||
| Missing `DISCORD_SERVICE_TENANT_ID` for approval/stop | The privileged control handler returns without creating or consuming an approval. |
|
||||
| Agent configuration ID does not resolve or its name differs from `instanceId` | Gateway refuses to create the Discord-bound session. |
|
||||
| External route cannot be persisted as a UUID conversation | Gateway may still dispatch live output; durable history and restart/resume continuity are not guaranteed and must not be inferred from delivery. |
|
||||
|
||||
## Explicitly not current
|
||||
|
||||
@@ -128,7 +131,7 @@ The daemon reads its environment from `~/.config/mosaic/gateway/.env` by default
|
||||
- [`apps/gateway/src/chat/chat.gateway.ts`](../../../apps/gateway/src/chat/chat.gateway.ts) — `/chat` authentication, envelope validation, replay, trusted agent selection, ordinary dispatch, approval, and stop.
|
||||
- [`apps/gateway/src/chat/chat.gateway-auth.ts`](../../../apps/gateway/src/chat/chat.gateway-auth.ts) — timing-safe service-token and BetterAuth session validation.
|
||||
- [`apps/gateway/src/plugin/discord-ingress.security.spec.ts`](../../../apps/gateway/src/plugin/discord-ingress.security.spec.ts) — signature, allowlist, replay, attachment, binding, approval, stop, and logical-agent checks.
|
||||
- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — the current Discord-to-durable-session control-flow evidence.
|
||||
- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — control-flow evidence with explicit durable-session pre-enrollment, not proof of ordinary Discord persistence.
|
||||
- [`packages/mosaic/src/commands/gateway.ts`](../../../packages/mosaic/src/commands/gateway.ts) and [`gateway/config.ts`](../../../packages/mosaic/src/commands/gateway/config.ts) — verified gateway CLI command names and configuration behavior.
|
||||
- [Channel protocol architecture](../../DEVELOPER-GUIDE/architecture/channel-protocol.md) — canonical shared-contract and parity boundary.
|
||||
- [Discord conversation workflow](../../USER-GUIDE/workflows/discord-conversations.md) — end-user behavior.
|
||||
|
||||
Reference in New Issue
Block a user