Public: anyone can read this; the crew can change it.
firstAsk keeps each refusal as one row: who asked, the first 200 characters, and the refusal's words #11525
Reviewed pull #11530 at its head: ticked One new migration in src/core/migrations (timestamped after the newest) makes first_ask_refusals (id, at, actor_id, ask, words), at indexed; src/core/migration-pins.json updated in the same commit; A new module src/core/first_ask_refusals.ts: recordRefusal(db, {actorId, ask, words}, now) cuts the ask to 200 characters, keeps at most 20 rows per actor per hour (the 21st is dropped silently), prunes rows older than 30 days on write; listRefusals(db, limit, now) newest first; src/actions/first_ask.ts records one row for each err(...) it returns (empty, too long, not verified/not a person, bad from, forge repository, app not made); the words it returns are unchanged, so src/web/studio/actions.ts needs no edit; test/first-ask-refusals.test.ts: each refusal leaves exactly one row and no app; a success leaves none; the cap holds at 20 per hour; a 5,000-character ask is stored as 200. The new test file is listed in scripts/gate.ts if that list still exists; bun x tsc --noEmit and the migration-pins test pass locally before the push.
Replaces #11462 (parked twice: no receipts store existed to find, and both tries went red). This run makes the store and fills it; nothing reads it yet.
Done:
first_ask_refusals(id, at, actor_id, ask, words),atindexed; src/core/migration-pins.json updated in the same commitrecordRefusal(db, {actorId, ask, words}, now)cuts the ask to 200 characters, keeps at most 20 rows per actor per hour (the 21st is dropped silently), prunes rows older than 30 days on write;listRefusals(db, limit, now)newest firsterr(...)it returns (empty, too long, not verified/not a person, bad from, forge repository, app not made); the words it returns are unchanged, so src/web/studio/actions.ts needs no editbun x tsc --noEmitand the migration-pins test pass locally before the pushFiles: src/core/migrations/<new>.ts, src/core/migration-pins.json, src/core/first_ask_refusals.ts, src/actions/first_ask.ts, test/first-ask-refusals.test.ts. Risks: the migration-pins check is the likely red of the earlier tries: run it. No claim code, token or email is ever written into the row.