TL;DR: This is the normal middle of an expand/contract migration, not a broken state. Confirm the expand is fully applied and every writer has moved to the new columns, finish deploying the new code everywhere, then run the contract migration to drop the old columns. The "stuck halfway" feeling comes from treating a designed pause as a failure.

The problem as reported:
```text
the agent applied the expand migration but the contract migration never ran - the old columns are still being written to and the agent is stuck halfway
```

1. Verify the expand fully applied: the new columns exist, the backfill or dual-write is in place, and reads work against the new columns. Expected: the schema matches the expand migration's end state.
2. Verify every app instance runs the new code - check deploy status across all environments and workers. Expected: zero instances still on the old version.
3. Verify nothing still reads the old columns: search the codebase for the old column names and check query logs. Expected: zero references outside the contract migration itself.
4. Run the contract migration (drop the old columns, remove dual writes). Expected: it applies cleanly and the old columns are gone.
5. Smoke-test writes and reads end to end. Expected: the app works with only the new columns present.

## Use this when
- An expand/contract migration paused between phases.
- Old columns are still present and being written.
- You're unsure whether it's safe to run the contract step.

## Not for this skill when
- You never used expand/contract - a plain half-applied sequence is the roll-forward situation, different skill.
- The expand migration itself failed - fix that first; there's nothing to contract yet.

## Variant phrasings
- expand migration done contract never ran
- stuck halfway expand contract migration
- old columns still written after migration
- safe to run contract migration

## Why it happens
Expand/contract deliberately splits a breaking schema change into two safe deploys with a pause between them. The pause is the design - but an agent that loses the plan mid-pause reads "halfway" as "broken".

## Edge cases
- A forgotten cron job, analytics pipeline, or replica still writing the old columns: find it in query logs before contracting, or the contract migration breaks it.
- Contracting on a huge table needs its own low-lock strategy - dropping a column can still take locks.
- If nothing has written the new columns yet, rolling back the expand is also safe - but once dual writes started, forward is the only clean direction.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Wwo2khD8OkeVKqHGlduW9A
