diff --git a/docs/ADMIN-GUIDE/security/discord-ingress.md b/docs/ADMIN-GUIDE/security/discord-ingress.md index 14fd6742..4165adb7 100644 --- a/docs/ADMIN-GUIDE/security/discord-ingress.md +++ b/docs/ADMIN-GUIDE/security/discord-ingress.md @@ -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 ` 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 ` 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. diff --git a/docs/DEVELOPER-GUIDE/architecture/channel-protocol.md b/docs/DEVELOPER-GUIDE/architecture/channel-protocol.md index f0ca308b..9815d049 100644 --- a/docs/DEVELOPER-GUIDE/architecture/channel-protocol.md +++ b/docs/DEVELOPER-GUIDE/architecture/channel-protocol.md @@ -32,7 +32,7 @@ The migration from `docs/_old_structure/architecture/channel-protocol.md` is a d The current source boundaries also distinguish two identities: 1. A channel route carries a configuration-owned logical agent and response destination. -2. The gateway chooses the durable session, provider, model, and runtime session internally. +2. The gateway chooses provider, model, and runtime session internally. Durable-session enrollment is separate and is not proven by the external channel route alone. A route is therefore not a claim that a channel adapter owns or exposes a harness, provider, model, process, or native runtime-session identity. @@ -152,15 +152,21 @@ The gateway exposes the `/chat` Socket.IO namespace. A Discord connection authen This path is intentionally described as compatibility: the gateway receives a signed Discord envelope and reconstructs chat input; it does not currently receive a complete `ChannelIngressDto` from the host registry. +### Persistence and durability boundary + +The Discord `conversationId` is an external route string such as `:discord:`. Persisted conversations and messages use UUID conversation IDs. No current route-mapping layer was found that resolves the external route to a generated UUID before ordinary Discord writes. The gateway catches persistence/binding failures and may continue dispatch, so live output does not prove durable history or restart/resume continuity. + +The focused cross-surface integration test explicitly pre-enrolls a durable session before exercising control flow. It does not prove that a fresh ordinary Discord message creates durable conversation/message rows. Current architecture claims are therefore limited to authenticated routing and live delivery. Durable Discord continuity requires a route-to-UUID mapping, observable persistence failures, ordinary-ingress enrollment where required, and a fresh-database restart test. + ### Thread and conversation behavior -| Inbound case | Current route and side effect | -| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| Authorized untagged message in a parent channel | Uses the parent channel as the response target; no thread is created. | -| Authorized bot mention in a parent channel | Creates a public thread, or reuses the thread already attached to that message, and routes the response to that thread. | -| Authorized follow-up in an existing thread | Authorizes against the configured parent channel and keeps the existing thread; it does not create a nested thread. | -| `/approve` or `/stop ` | Uses the current parent/thread durable session and does not create a new topic. | -| Requested thread creation fails | Does not dispatch the message, because the requested response target cannot be honored. | +| Inbound case | Current route and side effect | +| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Authorized untagged message in a parent channel | Uses the parent channel as the response target; no thread is created. | +| Authorized bot mention in a parent channel | Creates a public thread, or reuses the thread already attached to that message, and routes the response to that thread. | +| Authorized follow-up in an existing thread | Authorizes against the configured parent channel and keeps the existing thread; it does not create a nested thread. | +| `/approve` or `/stop ` | Uses the current parent/thread route and requires an already enrolled durable session; ordinary chat does not prove enrollment. | +| Requested thread creation fails | Does not dispatch the message, because the requested response target cannot be honored. | ### Discord egress and health @@ -265,7 +271,7 @@ Discord evidence: - [`apps/gateway/src/chat/chat.gateway.ts`](../../../apps/gateway/src/chat/chat.gateway.ts) — `/chat` namespace, service/session authentication, signed-envelope reconstruction, trusted binding selection, and raw stream egress. - [`apps/gateway/src/chat/chat.gateway-auth.ts`](../../../apps/gateway/src/chat/chat.gateway-auth.ts) — Discord 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, binding, attachment, 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) — focused Discord-to-durable-session integration. +- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — focused control-flow test with explicit durable-session pre-enrollment; not ordinary persistence evidence. Hosting and compatibility evidence: diff --git a/docs/DEVELOPER-GUIDE/integrations/channel-adapters.md b/docs/DEVELOPER-GUIDE/integrations/channel-adapters.md index 35ff1ae7..a1438401 100644 --- a/docs/DEVELOPER-GUIDE/integrations/channel-adapters.md +++ b/docs/DEVELOPER-GUIDE/integrations/channel-adapters.md @@ -66,7 +66,7 @@ The Discord adapter derives: :discord: ``` -The binding address is derived from the configured guild, parent channel, and logical-agent instance. The route intentionally omits runtime provider, harness, model, process, and native runtime-session identifiers. Gateway durable-session and provider layers own those identities. +The binding address is derived from the configured guild, parent channel, and logical-agent instance. The route intentionally omits runtime provider, harness, model, process, and native runtime-session identifiers. Gateway provider/runtime layers own those identities; durable-session ownership applies only after explicit enrollment and is not implied by the external route. This is a route-integrity rule, not proof that the gateway has a universal channel session API. A future adapter must derive its route from trusted configuration and native channel/thread identity; it must not accept a caller-selected logical agent or runtime target. @@ -94,10 +94,10 @@ The gateway-hosted plugin is currently constructed without a direct `ChannelIngr 2. Normal sends emit a signed `message` envelope; approval and stop emit `discord:approve` and `discord:stop` envelopes. 3. The HMAC-SHA-256 signature covers the ordered Discord payload using `DISCORD_SERVICE_TOKEN`. 4. The gateway verifies the service token/signature, allowlists, binding/operation role, stable conversation ID, attachment bounds, and replay key before dispatch. -5. The gateway selects the binding's trusted `agentConfigId`, verifies its name equals the logical-agent instance, and creates/resumes the conversation without generic provider routing for Discord ingress. +5. The gateway selects the binding's trusted `agentConfigId` and verifies its name equals the logical-agent instance. It attempts normal conversation binding/persistence before dispatch, but the external route is not a UUID and no route-to-UUID mapping currently proves durable ordinary-chat history. 6. Agent output currently returns as raw Socket.IO `agent:start`, `agent:text`, and `agent:end` events. The plugin buffers the text and calls its typed Discord egress at stream end. -This compatibility path carries enough normalized identity to preserve current security and routing behavior, but it is not a gateway-produced `ChannelIngressDto`/`ChannelEgressDto` flow through a shared host registry. +This compatibility path carries enough normalized identity to preserve current security and routing behavior, but it is not a gateway-produced `ChannelIngressDto`/`ChannelEgressDto` flow through a shared host registry. The gateway can continue live dispatch after persistence failure; adapter authors must not claim durable continuity until external routes map to UUID conversations and fresh-message restart tests pass. ### Egress and health @@ -172,7 +172,7 @@ These commands do not require starting Gateway, Discord, Telegram, Matrix, a que - [`apps/gateway/src/chat/chat.gateway.ts`](../../../apps/gateway/src/chat/chat.gateway.ts) — service/session auth, signed envelope validation, replay, trusted agent selection, and raw stream events. - [`apps/gateway/src/chat/chat.gateway-auth.ts`](../../../apps/gateway/src/chat/chat.gateway-auth.ts) — timing-safe Discord service-token and BetterAuth session checks. - [`apps/gateway/src/plugin/discord-ingress.security.spec.ts`](../../../apps/gateway/src/plugin/discord-ingress.security.spec.ts) — gateway security and privileged-operation tests. -- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — current Discord durable-session integration. +- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — control-flow test with explicit durable-session pre-enrollment; not ordinary Discord persistence evidence. - [`apps/gateway/src/plugin/plugin.interface.ts`](../../../apps/gateway/src/plugin/plugin.interface.ts), [`plugin.module.ts`](../../../apps/gateway/src/plugin/plugin.module.ts), and [`plugin.service.ts`](../../../apps/gateway/src/plugin/plugin.service.ts) — lifecycle-only host registry. - [`plugins/telegram/src/index.ts`](../../../plugins/telegram/src/index.ts) and [`plugins/telegram/package.json`](../../../plugins/telegram/package.json) — raw Telegram behavior and no-test script. - [Canonical channel protocol architecture](../architecture/channel-protocol.md) — shared contract and explicit current/draft boundary. diff --git a/docs/USER-GUIDE/workflows/discord-conversations.md b/docs/USER-GUIDE/workflows/discord-conversations.md index e834cb76..61a9d09a 100644 --- a/docs/USER-GUIDE/workflows/discord-conversations.md +++ b/docs/USER-GUIDE/workflows/discord-conversations.md @@ -10,12 +10,12 @@ This workflow assumes an administrator has configured the Discord bot, gateway c ## Current versus planned -| Surface | Status | What you can rely on | -| ----------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| Discord guild messages | **Current** | Authorized messages route to the configured logical agent; parent-channel and thread behavior below is implemented and tested. | -| Telegram | **Not shared-contract parity** | A raw legacy plugin exists, but its current source has no equivalent documented authorization, pairing, route, or focused package tests. | -| Matrix | **Not implemented as a channel workflow** | No current gateway channel adapter and test boundary establishes a Matrix conversation workflow. | -| Shared channel registry | **Not implemented** | The gateway's current registry hosts lifecycle wrappers; it does not provide universal channel routing or health. | +| Surface | Status | What you can rely on | +| ----------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| Discord guild messages | **Current live routing** | Authorized messages route to the configured logical agent; parent/thread delivery is tested, but ordinary durable history is not guaranteed. | +| Telegram | **Not shared-contract parity** | A raw legacy plugin exists, but its current source has no equivalent documented authorization, pairing, route, or focused package tests. | +| Matrix | **Not implemented as a channel workflow** | No current gateway channel adapter and test boundary establishes a Matrix conversation workflow. | +| Shared channel registry | **Not implemented** | The gateway's current registry hosts lifecycle wrappers; it does not provide universal channel routing or health. | ## Start in a configured parent channel @@ -59,7 +59,13 @@ The stable conversation address is formed from the configured logical agent, cha :discord: ``` -It does not contain Claude, Codex, Pi, OpenCode, a model, a provider, a process, or a native runtime-session ID. The gateway owns the durable session and runtime selection behind that route, so changing the runtime/provider does not require a new Discord address. +It does not contain Claude, Codex, Pi, OpenCode, a model, a provider, a process, or a native runtime-session ID. The gateway owns runtime selection behind that route, so changing the runtime/provider does not require a new Discord address. + +### Durability limitation + +Treat the current Discord path as **live routing and delivery**, not guaranteed durable conversation history. The Discord conversation address above is an external route string, while persisted conversation/message rows use UUID conversation IDs. No current external-route-to-UUID mapping was found. The gateway can continue dispatching after a persistence/binding failure, so a reply may appear in Discord without durable history or restart/resume continuity. + +Do not rely on Discord as the sole record of a conversation. Durable history requires an implementation that maps the external route to a UUID, surfaces persistence failure, and proves fresh-message persistence and restart recovery in an integration test. ## Attachments @@ -76,7 +82,7 @@ The current Discord text controls are: /stop ``` -They remain on the current parent/thread durable session and do not create a new topic. Approval and stop are privileged operations: the paired user must have the `admin` role and a provisioned `mosaicUserId`, the gateway must have a tenant configured for the control path, and the durable session must still belong to the bound logical agent. A stop must present the exact approval reference created for that target; approval consumption is one-time. +They remain on the current parent/thread route and do not create a new topic. Approval and stop require an already enrolled durable session; ordinary Discord chat does not prove that enrollment occurred. These are privileged operations: the paired user must have the `admin` role and a provisioned `mosaicUserId`, the gateway must have a tenant configured for the control path, and the enrolled durable session must still belong to the bound logical agent. A stop must present the exact approval reference created for that target; approval consumption is one-time. If these checks fail, the control operation is denied or produces no successful control result. Do not assume that being able to read a channel grants control authority. @@ -97,7 +103,7 @@ Check these possibilities with the administrator: 5. The bot is not connected to Discord or the gateway Socket.IO `/chat` namespace. 6. A mentioned topic could not create/fetch its thread. 7. The gateway rejected the signed envelope, route, attachment, or replayed native message ID. -8. `/approve` or `/stop ` was attempted without the required admin pairing, tenant, durable session, or exact approval. +8. `/approve` or `/stop ` was attempted without the required admin pairing, tenant, pre-enrolled durable session, or exact approval. These failures are intentionally fail-closed; an unauthorized or unverifiable message should not create a thread or agent side effect. @@ -118,5 +124,5 @@ Those are parity/design gaps, not alternate user workflows. - [`plugins/discord/src/index.ts`](../../../plugins/discord/src/index.ts) — native Discord routing and delivery implementation. - [`plugins/discord/src/index.test.ts`](../../../plugins/discord/src/index.test.ts) — parent, mention, existing-thread, authorization, attachment, rate, egress, and health tests. - [`apps/gateway/src/plugin/discord-ingress.security.spec.ts`](../../../apps/gateway/src/plugin/discord-ingress.security.spec.ts) — gateway signature, replay, binding, attachment, approval, and stop tests. -- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — current durable-session Discord control-flow test. +- [`apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts`](../../../apps/gateway/src/__tests__/integration/tess-cross-surface.integration.test.ts) — Discord control-flow test with explicit durable-session pre-enrollment; it is not fresh-message persistence evidence. - [User Guide](../README.md) diff --git a/docs/scratchpads/DOCS-IA-002-catalog-audit.md b/docs/scratchpads/DOCS-IA-002-catalog-audit.md index 12ea7512..e63508d2 100644 --- a/docs/scratchpads/DOCS-IA-002-catalog-audit.md +++ b/docs/scratchpads/DOCS-IA-002-catalog-audit.md @@ -55,11 +55,11 @@ Shared indexes, navigation, audit records, integration review, and final commits ### Final review lanes -| Lane | Assignment | State | -| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | -| `docs-nav-review` | Independently audit current-page ownership, reachability, relative links, lifecycle labels, and sitemap accuracy. | Launching. | -| `docs-safety-review` | Independently review new current/held pages against source/tests and database/runtime safety constraints. | Launching. | -| `docs-stop-review` | Confirm that remaining unmigrated groups require authority decisions or coupled source/test migrations, and identify any missed safe slice. | Launching. | +| Lane | Assignment | State | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `docs-nav-review` | Independently audit current-page ownership, reachability, relative links, lifecycle labels, and sitemap accuracy. | Complete — findings remediated: artifact indexes added, quarantine links removed, stale sitemap copy corrected, mission label no longer overrides control state. | +| `docs-safety-review` | Independently review new current/held pages against source/tests and database/runtime safety constraints. | Complete — Discord durability blocker found; all affected pages now limit claims to live routing/delivery and disclose missing route-to-UUID persistence evidence. | +| `docs-stop-review` | Confirm that remaining unmigrated groups require authority decisions or coupled source/test migrations, and identify any missed safe slice. | Complete — historical mission bundle migrated; remaining Fleet, Federation, Kanban, Tess/API, and deployment groups are authority- or source/test-coupled. | ## Progress @@ -84,6 +84,8 @@ Shared indexes, navigation, audit records, integration review, and final commits - [x] Complete and integrate the four implementation-agent slices after independent scope and evidence review. - [x] Complete wave 2 audience, testing, RFC, and dashboard migrations and connect every page to its owning index and sitemap. - [x] Replace the stale sitemap link inventory with fully resolvable current navigation and an authority-gated backlog summary. +- [x] Complete independent navigation, safety, and stop-condition reviews; remediate every autonomous finding. +- [x] Migrate the bounded historical mission archive and repair its two broken sibling links. ## Initial findings @@ -97,13 +99,14 @@ Shared indexes, navigation, audit records, integration review, and final commits - `docs/openapi-tess.yaml` parses as OpenAPI 3.1 with 17 paths, but remains a legacy root-level Tess-scoped contract rather than the full API SSOT. - The baseline `.gitignore` ignored `docs/reports/`, conflicting with the new documentation contract and lint-staged. The blanket rule is now removed so canonical evidence can be tracked normally. - The scaffold slice adds `USER-GUIDE/README.md`, `ADMIN-GUIDE/README.md`, `ADMIN-GUIDE/security/README.md`, `DEVELOPER-GUIDE/README.md`, `DEVELOPER-GUIDE/architecture/README.md`, and `API/README.md`; legacy pages remain unchanged. -- `SITEMAP.md` now contains 40 resolvable current relative links and no stale legacy targets. Authority-gated Fleet, Federation, Kanban, Tess/API, and deployment groups are summarized without presenting quarantine paths as current navigation. +- `SITEMAP.md` now contains 43 resolvable current relative links and no stale legacy targets. Authority-gated Fleet, Federation, Kanban, Tess/API, and deployment groups are summarized without presenting quarantine paths as current navigation. - `docs/PERFORMANCE.md` had no live source/test dependency or internal links; it moved unchanged to `docs/reports/qa/p8-003-performance-optimization.md`. The admin index and current sitemap now classify it as historical evidence, not an operator runbook. - `PRD-TUI_Improvements.md` and `TASKS-TUI_Improvements.md` had no live source/test dependencies beyond their internal relative link; both moved unchanged to `docs/archive/tui/`, and `docs/archive/README.md` labels them historical. - The empty `docs/QUICKSTART.md` placeholder was replaced by `docs/USER-GUIDE/getting-started/quickstart.md`, based on verified installer, wizard, CLI, and runtime-safety behavior. The page explicitly excludes held PostgreSQL/source-checkout routes. - The SSO guide now documents Authentik/WorkOS/Keycloak discovery, OIDC callbacks, Keycloak SAML fallback, partial-config failures, and the absence of frontend feature flags. The root guide and stale `.env.example` flags were removed. - The lease-broker acceptance suites directly consumed two quarantined `docs/architecture/` paths; promoting the protocol, security, mutator-gate, and compaction-revocation contracts to `DEVELOPER-GUIDE/architecture/` and updating those consumers restored the intended contract family without changing runtime behavior. - The #756 Discord code-review, security-review, and documentation-checklist reports had no source/test consumers and moved byte-identically to their canonical report categories. `docs/reports/README.md` labels their historical evidence boundary. +- Independent safety review found that Discord external route strings are not proven to map to UUID conversation rows. Current pages now promise live routing/delivery only, disclose that persistence can fail while dispatch continues, and require pre-enrollment for privileged durable-session controls. ## Method @@ -153,5 +156,12 @@ Shared indexes, navigation, audit records, integration review, and final commits | Lease-broker verification | PASS — safe static/test workflow is current; startup, recovery, mutation, service management, and cleanup remain held | | Optional egress RFC | PASS — proposal remains draft/non-operative; model and runtime-provider boundaries are separated and candidates are not integrated | | Web dashboard guide | PASS — current routes, views, chat persistence, and absent project/task creation controls are documented from source/tests | -| Sitemap refresh | PASS — 40/40 relative links resolve; legacy link farm replaced by a non-linked authority-gated backlog summary | -| Canonical link audit | BLOCKED ONLY BY CONTROL DOCS — 273 links scanned, 17 unresolved; all are in maintainer/orchestrator-owned `PRD.md`, `TASKS.md`, or `MISSION-MANIFEST.md` | +| Sitemap refresh | PASS — 43/43 relative links resolve; legacy link farm replaced by a non-linked authority-gated backlog summary | +| Canonical link audit | BLOCKED ONLY BY CONTROL DOCS — 296 links scanned, 17 unresolved; all are in maintainer/orchestrator-owned `PRD.md`, `TASKS.md`, or `MISSION-MANIFEST.md` | +| Navigation review | PASS AFTER REMEDIATION — plan/scratchpad indexes added, current quarantine links removed, lifecycle/status copy aligned | +| Safety review | PASS AFTER REMEDIATION — Discord pages no longer claim unproven ordinary persistence or restart continuity | +| Stop-condition review | AUTONOMOUS COMPLETE — historical mission bundle migrated; remaining groups require authority or coupled source/test work | +| Repository pre-push checks | PASS — `pnpm preflight`, `pnpm typecheck`, `pnpm lint`, and `pnpm format:check` with `DATABASE_URL` unset | +| Root test suite | BLOCKED/FAILED SAFELY — Fleet tests require missing `docs/fleet/`; gateway isolation test inherited a daemon DSN and failed authentication before cleanup DML. Not retried. | +| Focused final tests | PASS — types 71, Discord 44, web 33, focused gateway 32, and lease-broker/mutator acceptance 57; `DATABASE_URL` unset, no services started | +| Historical mission archive | PASS — 11 completed/superseded records moved under `archive/missions/`, indexed, and two broken sibling links repaired |