1@README.md 2 3## Notes for agents 4 5**Never edit a migration once it has deployed; add the next one.** The real database has already run it and will never run it again, so an edit changes only fresh databases (local ones, tests) and they drift from production. Whether one has deployed: `git log` on it against the live release (`curl https://jevstrudel.deizel.workers.dev/release-notes.json`). 6 7**Numbers are contiguous and unique: `0001_`, `0002_`, ….** `src/migrations.test.ts` fails on a gap or a repeat, which is how two branches that each took the same number find out when they meet: renumber yours to follow theirs. 8 9**Every table is `STRICT`**, and says in `CHECK`s what cannot be true (the test enforces `STRICT`). The Worker validates first; the schema is where an invalid row becomes impossible, not merely unwritten. 10 11**The deploy migrates before it publishes, so each migration must work with the Worker that is live before it.** Add tables and nullable or defaulted columns freely. To rename or drop, expand in one deploy (add the new, write both), contract in a later one (stop reading the old, then drop it). 12 13**One table's owner is one module.** Say in the migration's header comment which `src/` file reads and writes it, and add its row to the table in README.md. 14 15**Nothing identifying goes in without a reason written here.** The site stores no address, visitor key or request body today (see `worker/CLAUDE.md`, "Logs carry no visitor"); a table that holds a user or a session says so in its header, with what it is for (`0002_accounts.sql` does: a random id and a chosen display name, passkey public keys, and session token hashes). `0005_pitch_votes.sql` links an account to each pitch it voted for: that is public, who voted and when, since the site shows every vote (the pitches are a community board, and a hidden vote would be a secret the data tab had to withhold). `0006_performance_players.sql` links an account to each take it played, and when: public too, so a listener finds their own takes and everyone sees who played what; the take outlives the account, anonymous. 16 17**Every row is public, secrets aside: a new table joins the data tab.** `src/data.ts` shows every table to anyone (README.md), so a new table gets a read there and a section in `website/src/jev/DataTab.jsx`, and a column that is a secret (a credential, a hash that signs someone in, a one-time value) is listed in data.ts's header and added to `data.test.ts`'s never-answered list. A header comment that says a row is seen only by its author predates the data tab: the migration cannot be edited, so README.md says what holds now. 18 19**A `CHECK` that is NULL passes.** `CHECK (length(x) = 22)` lets a NULL `x` through; say `x IS NOT NULL AND …` when the column is nullable (`0002_accounts.sql`'s `auth_challenges` does, and `auth.test.ts` holds it).