Pitches: listeners' votes on them, and the listener songs that answer them. Owner: src/content-store.ts reads and writes both, for src/content.ts (the routes); src/data.ts reads them for the data tab.
What is identifying here, and why (migrations/CLAUDE.md): a vote names the account that cast it, so each account votes once per pitch and can take its vote back. Like every row, it is public: the data tab shows who voted for what (worker/README.md, What is public). Times are milliseconds since the epoch, UTC.
One account's vote for one pitch; taking it back deletes the row. Only a public pitch can be voted on (content.ts checks; a held pitch's votes, if it were ever held after, stay as they were).
14CREATE TABLE pitch_votes ( 15 pitch TEXT NOT NULL REFERENCES pitches (id) ON DELETE CASCADE, 16 user_id TEXT NOT NULL REFERENCES users (id) ON DELETE CASCADE, 17 created_at INTEGER NOT NULL CHECK (created_at > 0), 18 PRIMARY KEY (pitch, user_id) 19) STRICT; 20CREATE INDEX pitch_votes_by_user ON pitch_votes (user_id);
The pitch a listener song answers, set by the song's author (a site song
says so in its SPEC.md, pitch:, which the build reads): the maker of a
song is the one who can say what it answers. NULL when it answers none,
and again if the pitch is deleted.