diff --git a/.claude/agent-memory/code-reviewer/project-anti-cheat-invariant.md b/.claude/agent-memory/code-reviewer/project-anti-cheat-invariant.md index 557bce6..01889ba 100644 --- a/.claude/agent-memory/code-reviewer/project-anti-cheat-invariant.md +++ b/.claude/agent-memory/code-reviewer/project-anti-cheat-invariant.md @@ -5,10 +5,13 @@ metadata: type: project --- -The panorama indexes under `src/data/panos/` are ~29 MB of exact round answers. The -team's stated invariant is that `src/lib/regions.js` (client-imported) must never -transitively reach them, enforced by the "client safety" import walk in -`tests/regions.test.js`. +The panorama index is the exact round answers. As of 2026-08-31 it is a Neon +Postgres table (`panoramas`), reached through `src/lib/pano-db.js` and +`src/lib/pano-index.js`; the old ~29 MB `src/data/panos/*.json` are deleted and +the pipeline now writes gitignored `data-build/panos/`. The team's stated +invariant is that `src/lib/regions.js` (client-imported) must never transitively +reach them, enforced by the "client safety" import walk in `tests/regions.test.js` +and `tests/geo-search.test.js`, whose forbidden list now includes `pano-db`. **Why:** a client that can map a panorama id to coordinates scores perfectly every round. @@ -21,3 +24,7 @@ a district's list complete and unsampled in one request. The user has accepted t exposure; do not re-litigate it, but when reviewing changes near regions/pano-index/ new-game, check whether the change makes extraction cheaper, and never treat a passing import-walk test as proof the property holds. + +Since the move to Postgres that route also has a cost dimension: each unauthenticated +call runs a `row_number() OVER (ORDER BY lat, id)` over the whole region (226k rows for +HN) on metered Neon compute. Extraction now bills the project, not just leaks. diff --git a/.claude/agent-memory/code-reviewer/project-quality-gates-blind-spots.md b/.claude/agent-memory/code-reviewer/project-quality-gates-blind-spots.md index 7d7192e..b46b8ac 100644 --- a/.claude/agent-memory/code-reviewer/project-quality-gates-blind-spots.md +++ b/.claude/agent-memory/code-reviewer/project-quality-gates-blind-spots.md @@ -34,6 +34,15 @@ ten setter call sites surviving green). Lint currently emits 4 pre-existing sessions" (they are Redis), and Node 18+ against `engines: >=24`. Check README explicitly on any docs pass; it is never reached by editing `/docs/`. +**Opened 2026-08-31 by the Neon migration:** production SQL now runs against a +driver no gate exercises. `npm test` and `npm run test:integration` both mock +`@neondatabase/serverless` and run PGlite instead, so parameter serialisation, +type inference (`= ANY($n)` on an untyped param, `count(*)` needing `::int`) and +query plans are only ever proven by a manual smoke test against real Neon. There +is also no perf gate: an unindexed `ORDER BY ... OFFSET` or a window-function +sort over 226k rows passes every check. Ask for the index list whenever a diff +adds a query. + **How to apply:** when a diff removes or renames state, props, helpers, or imports, grep the whole file. For any React change, state plainly in the report which criteria are runtime-only. For any doc change, verify each load-bearing