Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Rehearse a live-app schema change + backfill on a snapshot-seeded preview deployment, verify, then promote the proven change to prod with the snapshot as rollback.
.claude/skills/get-convex-convex-migrate-rehearse/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 13% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 49% | 0% |
| case-10 | ✗→✓ | ▲ Improved | -16% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 53% | 0% |
<!-- GENERATED from convex-agents content/capabilities/migrate-rehearse.json — do not edit by hand. -->
A schema push on Convex validates every existing document against the new schema and FAILS the push if any row doesn't conform — a real data-conformance gate. The safe way to use that gate is to let it fail on a rehearsal copy, not on prod. This capability turns a preview deployment into that copy: seed it with a prod snapshot, push the new schema + run the backfill there, watch the gate, and only promote once it's green. It composes deploy-guard (target classification), migrate (the optional-then-tighten pattern), and @convex-dev/migrations (the batched, resumable backfill).
CONVEX_DEPLOY_KEY before any --preview-create/--preview-name deploy — a plain npx convex login session cannot create previews, and this is a paid-tier feature. If no preview key is available, fall back to rehearsing on the personal dev deployment seeded with the snapshot, and say so.npx convex export --path snapshot.zip (from the deployment holding the real data; add --include-file-storage only if the migration touches files). This is a read; it changes nothing.npx convex deploy --preview-create migrate-<slug> (needs the preview key; auto-expires ~5 days). Seed it: npx convex import snapshot.zip --deployment migrate-<slug> (import targets a deployment by NAME with --deployment; there is no --preview-name flag on import). The import succeeds because the data still matches the old schema.npx convex deploy --preview-name migrate-<slug> (re-deploys to the SAME preview, keeping its data; NOT convex dev, which targets personal dev): (a) make the new/changed field OPTIONAL and deploy — if existing rows violate it the push FAILS HERE on the copy with the offending shape; fix and re-push until green. (b) write a @convex-dev/migrations backfill and run it against the preview; verify every row is now valid. (c) tighten the validator (required / narrowed union) and deploy again — the gate now passes because the backfill ran.run/runOneoffQuery pointed at the preview, or a smoke query) to confirm behavior and shape.npx convex import snapshot.zip --replace --prod); state plainly that data written after the snapshot is lost, so keep the promote window short.deploy --preview-name, import targets it with --deployment.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 20,386 | 16,787 | -18% | 1 | 1 | 0% | 3,096 | 3,484 | +13% | 0 | 0 | — |
case-02 | fail→fail | 23,043 | 5,711 | -75% | 1 | 1 | 0% | 3,027 | 2,088 | -31% | 0 | 0 | — |
case-03 | fail→pass | 21,130 | 14,225 | -33% | 1 | 1 | 0% | 2,979 | 3,223 | +8% | 0 | 0 | — |
case-04 | pass→pass | 14,405 | 8,680 | -40% | 1 | 1 | 0% | 2,493 | 2,286 | -8% | 0 | 0 | — |
case-05 | pass→pass | 16,484 | 13,333 | -19% | 1 | 1 | 0% | 2,516 | 3,479 | +38% | 0 | 0 | — |
case-06 | pass→pass | 14,928 | 13,915 | -7% | 1 | 1 | 0% | 3,068 | 3,853 | +26% | 0 | 0 | — |
case-07 | pass→pass | 15,037 | 10,776 | -28% | 1 | 1 | 0% | 1,956 | 2,946 | +51% | 0 | 0 | — |
case-08 | fail→pass | 8,668 | 4,832 | -44% | 1 | 1 | 0% | 1,154 | 1,723 | +49% | 0 | 0 | — |
case-09 | pass→pass | 10,087 | 7,879 | -22% | 1 | 1 | 0% | 1,605 | 2,093 | +30% | 0 | 0 | — |
case-10 | fail→pass | 12,903 | 3,377 | -74% | 1 | 1 | 0% | 1,945 | 1,630 | -16% | 0 | 0 | — |
case-11 | pass→pass | 9,749 | 3,451 | -65% | 1 | 1 | 0% | 1,763 | 1,538 | -13% | 0 | 0 | — |
case-12 | pass→pass | 12,265 | 12,156 | -1% | 1 | 1 | 0% | 2,110 | 2,843 | +35% | 0 | 0 | — |
case-13 | fail→pass | 9,526 | 6,075 | -36% | 1 | 1 | 0% | 1,337 | 2,051 | +53% | 0 | 0 | — |
case-14 | fail→pass | 14,691 | 12,763 | -13% | 1 | 1 | 0% | 2,190 | 2,723 | +24% | 0 | 0 | — |
case-15 | fail→pass | 12,996 | 4,676 | -64% | 1 | 1 | 0% | 1,878 | 1,655 | -12% | 0 | 0 | — |
case-16 | fail→fail | 11,833 | 6,664 | -44% | 1 | 1 | 0% | 2,032 | 2,155 | +6% | 0 | 0 | — |
case-17 | fail→pass | 16,029 | 4,511 | -72% | 1 | 1 | 0% | 2,072 | 1,667 | -20% | 0 | 0 | — |
case-18 | pass→pass | 11,421 | 5,661 | -50% | 1 | 1 | 0% | 1,455 | 1,759 | +21% | 0 | 0 | — |
case-19 | fail→pass | 7,573 | 2,236 | -70% | 1 | 1 | 0% | 1,115 | 1,279 | +15% | 0 | 0 | — |
case-20 | fail→pass | 9,345 | 3,778 | -60% | 1 | 1 | 0% | 1,247 | 1,570 | +26% | 0 | 0 | — |
case-21 | pass→pass | 11,853 | 7,438 | -37% | 1 | 1 | 0% | 1,659 | 2,362 | +42% | 0 | 0 | — |
case-22 | fail→pass | 14,255 | 10,307 | -28% | 1 | 1 | 0% | 2,101 | 2,409 | +15% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +50 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.