Indexer: add down migration for timecurve_unredeemed_launched_token (151-1)

Problem

The migration 20260504180000_timecurve_unredeemed_launched_token ships *.up.sql only — there is no paired *.down.sql. Every other migration in indexer/migrations/ follows the paired pattern.

Impact: Operators cannot roll back this schema step via the SQLx migration runner. A forced post-deploy revert requires manual DROP TABLE plus manual reconciliation of _sqlx_migrations, which blocks clean re-application of the same version and breaks automated rollback playbooks ahead of mainnet/TGE-style deploys.

Split from GitLab #151 (Finding 1 — Medium). Feature background: unredeemed launched-token sweep observability (GitLab #128).

Area Location
Migration (up) indexer/migrations/20260504180000_timecurve_unredeemed_launched_token.up.sql
Down (missing) Add indexer/migrations/20260504180000_timecurve_unredeemed_launched_token.down.sql (new; pair with .up.sql)
Indexer decoder (context) indexer/src/decoder.rs — unredeemed launched-token events
Indexer invariant docs/testing/invariants-and-business-logic.md — anchor INV-INDEXER-128 / unredeemed sweep
Guardrails skill .cursor/skills/yieldomega-guardrails/SKILL.md
Contracts No Solidity change; tables mirror onchain events for UnredeemedLaunchedTokenRecipientSet / sweep (see decoder + #128 (closed))

Contracts / frontend: No code change required for closing this ticket — only the indexer migration pair.

Acceptance criteria

  1. 20260504180000_timecurve_unredeemed_launched_token.down.sql exists and reverses the .up migration: drop indexes (if not dropped with CASCADE) then DROP TABLE IF EXISTS for both idx_timecurve_unredeemed_launched_token_recipient_set and idx_timecurve_unredeemed_launched_token_swept, in an order safe for FK-free standalone tables (match project style for other .down.sql files).
  2. Down is idempotent enough for dev: DROP TABLE IF EXISTS / DROP INDEX IF EXISTS as used elsewhere in this repo’s migrations.
  3. Documented or verified: sqlx migrate revert (or project-standard migrate command) can apply down then up on a throwaway Postgres without error.
  4. If any doc mentions “this migration has no down”, update that note.

Verification checklist

  • ls indexer/migrations/ | grep 20260504180000 shows both .up.sql and .down.sql.
  • Compare .down.sql objects to .up.sql: every CREATE TABLE / CREATE INDEX has a corresponding drop (naming matches).
  • On a clean test DB: sqlx database create (if needed) → sqlx migrate run → confirm tables exist → sqlx migrate revert (one step) → tables gonesqlx migrate run → tables restored.
  • _sqlx_migrations row for 20260504180000 disappears after revert and returns after re-run (no manual version hacks).
  • CI / cargo test for indexer still passes if integration tests touch migrations (indexer/tests/).
  • Cross-read INV-INDEXER-128 in invariants-and-business-logic.md: no doc claim that migrations are intentionally one-way for this version; update if needed.