db-platform-fit (M21) — version · pricing/lock-in · per-platform feature support
M21 audits the project against constraints imposed by the managed platform, not the raw engine.
The same Postgres schema behaves differently on Neon (serverless, scale-to-zero, branching) vs RDS vs
Supabase (RLS-centric, PostgREST). Findings feed both axes: feature gaps (FK support, RLS) are design;
connection/cold-start/version issues are performance.
What it checks
- Version currency — the declared/introspected engine version vs the platform's current supported
range. Flag clearly-old majors. Never fabricate an EOL date or a "supported until" date. If the
exact EOL is not known from a citable source, say "older major, confirm support window with the
platform" and mark
confidence: directional. With WebFetch you MAY cite the vendor's published
version page; quote it, don't paraphrase a number you can't source.
- Pricing / lock-in honesty — name the lock-in trade-off (proprietary features: Supabase Auth/RLS
coupling, PlanetScale Vitess sharding, D1's SQLite dialect, DynamoDB single-table design, Aurora
storage format). Never invent a price, a per-GB cost, or a row/request quota. State the
category of cost (egress, branching compute, read/write units) and that exact figures must be
confirmed on the vendor's current pricing page. Magnitude banded only.
- Per-platform feature support — FK support is the headline check:
- PlanetScale / Vitess — historically does not enforce foreign keys (and sharded FKs are
restricted); a schema relying on DB-enforced FKs needs app-level integrity or
FOREIGN_KEY_CHECKS
awareness. → design + performance, sev 4 when FKs are declared but unenforceable.
- Cloudflare D1 / SQLite — FKs exist but
PRAGMA foreign_keys must be ON; limited concurrency,
DB size ceilings.
- DynamoDB / Firestore — no FKs/joins at all; integrity is an application concern (M3 re-homes).
- Serverless drivers (Neon/PlanetScale HTTP, D1) — direct long-lived PG connections from
serverless/edge are an anti-pattern → cross-checks
db-connection-pooling (M15).
- Supabase — RLS must be ON for any table exposed via the auto REST/Realtime API → cross-checks
db-security-access (M10); RLS-off on an exposed table is sev 5 (design).
- CockroachDB / Yugabyte — PG wire-compatible but distributed: serial/sequence hotspots, no
certain PG extensions, different isolation defaults.
Tier-0 static checks
Detect the platform from references/detection-signals.md signals (supabase/ dir,
@planetscale/database, @neondatabase/serverless, wrangler.toml [[d1_databases]],
@libsql/client, cockroach/yugabyte in connection string/deps). Parse declared engine version from
config/migrations. Cross-reference declared FK constraints against the platform's FK-support reality.
Detect direct-PG drivers (pg, Pool) used in a serverless/edge entrypoint.
Tier-1 verification query
- Postgres family:
SELECT version(); and SHOW server_version;.
- MySQL/PlanetScale:
SELECT VERSION(); and SELECT @@foreign_key_checks;; inspect whether declared
FKs actually exist: SELECT * FROM information_schema.table_constraints WHERE constraint_type='FOREIGN KEY';
- Supabase RLS:
SELECT relname, relrowsecurity FROM pg_class WHERE relkind='r'; and pg_policies.
- D1/SQLite:
PRAGMA foreign_keys;. When the engine/platform isn't reachable → needs_api, never a
false pass.
Findings
Emit per schema/finding.schema.json. Example ids:
M21.platform.fk_unenforced_on_vitess — FK constraints declared but PlanetScale/Vitess won't enforce
them (fail, severity 4, axis both, confidence directional static / established with Tier-1).
M21.platform.rls_off_supabase — table exposed via Supabase API with RLS disabled (fail, severity 5,
axis design, confidence established with Tier-1).
M21.platform.engine_version_old — clearly-old engine major (warn, severity 3, axis both,
confidence directional; no fabricated EOL date — cite vendor page or defer).
M21.platform.serverless_direct_pg — direct long-lived PG connection from edge/serverless (warn,
severity 4, axis performance; cross-ref M15).
Each finding: evidence.observed quotes the real config/DDL/version string verbatim (secrets redacted);
verification.reproduce is a runnable command above using $DATABASE_URL; verification.method is
connection_introspect, schema_introspect, or manual_review; expected_impact carries
{axis, confidence, magnitude, rationale} — banded, never a naked %.
Honesty
- No fabricated EOL dates, prices, or quotas — ever, in findings or design recs. Cite the vendor's
current page via
WebFetch (quote it) or defer with directional and a "confirm on vendor page" note.
- Lock-in is a trade-off, not automatically a defect: name what you'd give up, don't moralize.
- Version "old" without a sourced EOL is
directional and never caps. FK-unenforced caps only at sev 4
(not 5) unless it directly enables orphan financial/auth rows. Unreachable platform → needs_api.
1---2name: db-platform-fit3description: Managed-platform fitness (M21) — checks the project against the realities of its hosting platform (Supabase, Neon, PlanetScale, Turso, Cloudflare D1, CockroachDB, Yugabyte, DynamoDB, RDS/Aurora). Engine version currency (without fabricating EOL dates), honest pricing / vendor lock-in trade-offs, and per-platform feature support — most importantly foreign-key support (PlanetScale Vitess historically restricts FKs; D1/SQLite, serverless drivers, connection limits). Feeds the Design & Integrity AND Performance & Scale scores.4---56# db-platform-fit (M21) — version · pricing/lock-in · per-platform feature support78M21 audits the project against constraints imposed by the **managed platform**, not the raw engine.9The same Postgres schema behaves differently on Neon (serverless, scale-to-zero, branching) vs RDS vs10Supabase (RLS-centric, PostgREST). Findings feed both axes: feature gaps (FK support, RLS) are design;11connection/cold-start/version issues are performance.1213## What it checks141. **Version currency** — the declared/introspected engine version vs the platform's current supported15 range. Flag clearly-old majors. **Never fabricate an EOL date or a "supported until" date.** If the16 exact EOL is not known from a citable source, say "older major, confirm support window with the17 platform" and mark `confidence: directional`. With `WebFetch` you MAY cite the vendor's published18 version page; quote it, don't paraphrase a number you can't source.192. **Pricing / lock-in honesty** — name the lock-in trade-off (proprietary features: Supabase Auth/RLS20 coupling, PlanetScale Vitess sharding, D1's SQLite dialect, DynamoDB single-table design, Aurora21 storage format). **Never invent a price, a per-GB cost, or a row/request quota.** State the22 *category* of cost (egress, branching compute, read/write units) and that exact figures must be23 confirmed on the vendor's current pricing page. Magnitude banded only.243. **Per-platform feature support — FK support is the headline check:**25 - **PlanetScale / Vitess** — historically does not enforce foreign keys (and sharded FKs are26 restricted); a schema relying on DB-enforced FKs needs app-level integrity or `FOREIGN_KEY_CHECKS`27 awareness. → design + performance, sev 4 when FKs are declared but unenforceable.28 - **Cloudflare D1 / SQLite** — FKs exist but `PRAGMA foreign_keys` must be ON; limited concurrency,29 DB size ceilings.30 - **DynamoDB / Firestore** — no FKs/joins at all; integrity is an application concern (M3 re-homes).31 - **Serverless drivers (Neon/PlanetScale HTTP, D1)** — direct long-lived PG connections from32 serverless/edge are an anti-pattern → cross-checks `db-connection-pooling` (M15).33 - **Supabase** — RLS must be ON for any table exposed via the auto REST/Realtime API → cross-checks34 `db-security-access` (M10); RLS-off on an exposed table is sev 5 (design).35 - **CockroachDB / Yugabyte** — PG wire-compatible but distributed: serial/sequence hotspots, no36 certain PG extensions, different isolation defaults.3738## Tier-0 static checks39Detect the platform from `references/detection-signals.md` signals (`supabase/` dir,40`@planetscale/database`, `@neondatabase/serverless`, `wrangler.toml [[d1_databases]]`,41`@libsql/client`, `cockroach`/`yugabyte` in connection string/deps). Parse declared engine version from42config/migrations. Cross-reference declared FK constraints against the platform's FK-support reality.43Detect direct-PG drivers (`pg`, `Pool`) used in a serverless/edge entrypoint.4445## Tier-1 verification query46- Postgres family: `SELECT version();` and `SHOW server_version;`.47- MySQL/PlanetScale: `SELECT VERSION();` and `SELECT @@foreign_key_checks;`; inspect whether declared48 FKs actually exist: `SELECT * FROM information_schema.table_constraints WHERE constraint_type='FOREIGN KEY';`49- Supabase RLS: `SELECT relname, relrowsecurity FROM pg_class WHERE relkind='r';` and `pg_policies`.50- D1/SQLite: `PRAGMA foreign_keys;`. When the engine/platform isn't reachable → `needs_api`, never a51 false `pass`.5253## Findings54Emit per `schema/finding.schema.json`. Example ids:55- `M21.platform.fk_unenforced_on_vitess` — FK constraints declared but PlanetScale/Vitess won't enforce56 them (fail, severity 4, axis `both`, confidence `directional` static / `established` with Tier-1).57- `M21.platform.rls_off_supabase` — table exposed via Supabase API with RLS disabled (fail, severity 5,58 axis `design`, confidence `established` with Tier-1).59- `M21.platform.engine_version_old` — clearly-old engine major (warn, severity 3, axis `both`,60 confidence `directional`; no fabricated EOL date — cite vendor page or defer).61- `M21.platform.serverless_direct_pg` — direct long-lived PG connection from edge/serverless (warn,62 severity 4, axis `performance`; cross-ref M15).63Each finding: `evidence.observed` quotes the real config/DDL/version string verbatim (secrets redacted);64`verification.reproduce` is a runnable command above using `$DATABASE_URL`; `verification.method` is65`connection_introspect`, `schema_introspect`, or `manual_review`; `expected_impact` carries66`{axis, confidence, magnitude, rationale}` — banded, never a naked %.6768## Honesty69- **No fabricated EOL dates, prices, or quotas — ever**, in findings or design recs. Cite the vendor's70 current page via `WebFetch` (quote it) or defer with `directional` and a "confirm on vendor page" note.71- Lock-in is a trade-off, not automatically a defect: name what you'd give up, don't moralize.72- Version "old" without a sourced EOL is `directional` and never caps. FK-unenforced caps only at sev 473 (not 5) unless it directly enables orphan financial/auth rows. Unreachable platform → `needs_api`.