story: Lucas guarantees read-only, migration-safe access

story-westside-mcp-safety Doc

active user-story

User Story

As Lucas, platform operator,
I want Marcus's data access to be read-only, audited, and migration-safe,
so that empowering Marcus never becomes a prod risk, a silent-breakage liability, or a compliance problem.

Guarantees this story demands

  • No write path exists. Two-layer enforcement: marcus_readonly Postgres role has only SELECT grants, AND the connection targets the CNPG read-replica endpoint. Either layer alone would block writes; both together is defense in depth.
  • Sensitive columns are invisible. Password hashes, Stripe IDs, OAuth tokens, internal notes — explicitly excluded via column-level GRANT or view layer. Listed in the Stage-0 sensitive column inventory.
  • Migrations can't silently break the MCP. The drift-check CI (Stage 2+) compares live information_schema against the catalog YAML. Any schema change that orphans a referenced column fails the pipeline.
  • Every query is audited. Loki records session ID, SQL, row count, duration, error state. "What did Marcus ask and when?" is always answerable.
  • Runaway queries can't hurt the primary. Replica-only reads + 5s statement timeout + 1000 row limit. A bad query degrades the replica briefly, not the primary.
  • Revoking access is a single step. Runbook documents: disable the OAuth client OR drop the Postgres role. Either cuts Marcus off immediately.

Success Metric

Zero write-path incidents. Zero silent-breakage incidents across at least one basketball-api schema migration after Stage 2 ships. Runbook rehearsed (access-revocation tested at least once).