Warden plan

11 - capture gate (audio ingestion: PKCE client → upload → transcription)

← eval suite index


tier: needs-postgres requires: []


11 - capture gate (audio ingestion: PKCE client → upload → transcription)

What it proves

The capture sprint's contract holds deterministically — no live LLM, no live server. Schema: the attachments table exists with its committed migration 0008. Queue: the transcription seam (QUEUE_NAMES.transcription + enqueueTranscription) is present. Adapter: the STT service reads env lazily off process.env (C-23) and never imports bootstrap/env. Authz: the capture scope is registered on the authorization server, core/authz/bearer.ts is the exported bearer choke-point, and /capture/oauth-config is public in BOTH allowlist mirrors. OpenAPI: /capture/uploads is multipart and the oauth2 flows point at /api/auth/oauth2/* (never the retired mcp/authorize). Boot: RESEND_API_KEY is required. Finally the two committed integration suites (PKCE token flow, upload lifecycle) run green against the branch.

Module isolation (modules never import core/oauth) is enforced by dependency-cruiser and already gated by plan 01's pnpm depcruise — cited here, not re-asserted.

Prerequisites

Step 1: schema + queue seam

set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"

# Attachments table in the Drizzle schema.
if grep -Eq "attachments[[:space:]]*=[[:space:]]*pgTable" server/src/db/schema.ts; then
  warden_pass "attachments pgTable present in server/src/db/schema.ts"
else
  warden_fail "attachments pgTable missing from db schema — capture storage gone"
fi

# Committed migration 0008 creates it.
MIG=$(ls server/drizzle/migrations/0008_*.sql 2>/dev/null | head -1)
if [[ -n "$MIG" ]] && grep -q 'CREATE TABLE "attachments"' "$MIG"; then
  warden_pass "migration 0008 creates attachments ($(basename "$MIG"))"
else
  warden_fail "migration 0008 missing or no longer creates attachments"
fi

# Transcription queue name registered.
Q=packages/queue/src/index.ts
if grep -Eq "transcription:[[:space:]]*['\"]transcription['\"]" "$Q"; then
  warden_pass "QUEUE_NAMES.transcription registered in @robin/queue"
else
  warden_fail "QUEUE_NAMES.transcription gone from @robin/queue — worker seam broken"
fi

# Enqueue helper present (manual-snapshot: the seam capture routes call).
if grep -q "enqueueTranscription" "$Q"; then
  warden_pass "enqueueTranscription helper exported by @robin/queue"
else
  warden_fail "enqueueTranscription missing — upload can no longer hand off to STT"
fi

Step 2: env discipline (lazy STT adapter, boot-required RESEND)

set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"

# STT adapter reads process.env lazily (C-23) — no bootstrap/env import,
# so a zero-capture-env boot still survives.
TS=server/src/services/transcription.ts
if grep -q "process.env.STT_API_BASE_URL" "$TS" && ! grep -q "bootstrap/env" "$TS"; then
  warden_pass "STT adapter reads process.env lazily, no bootstrap/env import (C-23)"
else
  warden_fail "STT adapter env discipline broken — eager env or bootstrap/env import"
fi

# RESEND_API_KEY is boot-required.
if grep -q "RESEND_API_KEY" server/src/bootstrap/env.ts; then
  warden_pass "RESEND_API_KEY declared in bootstrap/env.ts"
else
  warden_fail "RESEND_API_KEY no longer in bootstrap/env.ts — boot contract drifted"
fi

# Both .env.example mirrors exist.
if [[ -f server/.env.example && -f app/.env.example ]]; then
  warden_pass "server/.env.example and app/.env.example both present"
else
  warden_fail ".env.example mirror missing (server or app)"
fi

Step 3: authz surface (capture scope, bearer choke-point, public discovery)

set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"

# `capture` scope registered on the authorization server.
if grep -Eq "['\"]capture['\"]" server/src/modules/iam/auth.ts; then
  warden_pass "capture scope registered in iam/auth.ts (AS scopes)"
else
  warden_fail "capture scope gone from iam/auth.ts — PKCE clients can't request it"
fi

# Bearer choke-point exists and is exported from the authz barrel.
if [[ -f server/src/core/authz/bearer.ts ]] && grep -q "captureBearerAuth" server/src/core/authz/index.ts; then
  warden_pass "core/authz/bearer.ts present + captureBearerAuth exported (modules-never-import-core/oauth covered by depcruise, plan 01)"
else
  warden_fail "capture bearer choke-point missing or unexported from core/authz"
fi

# /capture/oauth-config public in BOTH allowlist mirrors.
if grep -q "/capture/oauth-config" server/src/bootstrap/assert-prod-safety.ts \
   && grep -q "/capture/oauth-config" server/src/__tests__/route-allowlist.test.ts; then
  warden_pass "/capture/oauth-config in PUBLIC_ROUTES, both mirrors (prod-safety + allowlist test)"
else
  warden_fail "/capture/oauth-config missing from a PUBLIC_ROUTES mirror — discovery would 401"
fi

Step 4: OpenAPI contract

set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"

OA=server/openapi.json

# Multipart upload surface + capture scope documented.
if jq -e '.paths["/capture/uploads"].post.requestBody.content["multipart/form-data"]' "$OA" >/dev/null \
   && jq -e '.components.securitySchemes.oauth2.flows.authorizationCode.scopes.capture' "$OA" >/dev/null; then
  warden_pass "openapi: /capture/uploads is multipart + capture scope documented"
else
  warden_fail "openapi drift: /capture/uploads multipart body or capture scope missing"
fi

# OAuth2 flow URLs point at the colocated AS.
if jq -e '.components.securitySchemes.oauth2.flows.authorizationCode
          | select(.authorizationUrl == "/api/auth/oauth2/authorize"
                   and .tokenUrl == "/api/auth/oauth2/token")' "$OA" >/dev/null; then
  warden_pass "openapi: oauth2 flow URLs are /api/auth/oauth2/{authorize,token}"
else
  warden_fail "openapi: oauth2 flow URLs drifted off /api/auth/oauth2/*"
fi

# Retired MCP authorize endpoint must NOT resurface.
if ! grep -q "mcp/authorize" "$OA"; then
  warden_pass "openapi: no mcp/authorize anywhere (retired endpoint stays retired)"
else
  warden_fail "openapi: mcp/authorize resurfaced — clients would bind to the retired AS"
fi

Step 5: capture integration tests pass against the branch (DB-backed)

set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
# shellcheck disable=SC1091
source "${WARDEN_ENV_FILE:?WARDEN_ENV_FILE not set — run this plan via .warden/run.sh}"

if pnpm --filter @robin/server exec vitest run \
     src/__tests__/capture-oauth-pkce.integration.test.ts \
     src/__tests__/capture-upload.integration.test.ts \
     >/tmp/warden-capture.log 2>&1; then
  warden_pass "capture PKCE + upload integration suites pass (token flow, multipart lifecycle, retry, public discovery)"
else
  tail -20 /tmp/warden-capture.log
  warden_fail "capture integration tests FAILED — see /tmp/warden-capture.log"
fi

Shape (note for the next author)

Backend-only sprint: zero app code (only app/.env.example), so no agent-browser leg. The authz seam is core/authz/bearer.ts (verification via @robin/oauth, table-less by depcruise packages-own-no-table); the STT adapter is deliberately env-lazy so boot works with zero capture env. If the upload route or worker is refactored, keep the enqueueTranscription handoff and the multipart contract — MCP clients bind to openapi.json.