|
| 1 | +# One branch's unmerged DO migration blocks staging deploys for every other branch |
| 2 | + |
| 3 | +## Problem |
| 4 | + |
| 5 | +`sam-api-staging` is a **single shared Cloudflare Worker**, but Durable Object migrations are |
| 6 | +versioned by a monotonic `tag` in `apps/api/wrangler.toml`. When any branch deploys a migration tag |
| 7 | +that does not exist on `main`, the shared Worker advances to that tag — and every other branch, |
| 8 | +including `main` itself, becomes **undeployable to staging** until that tag lands on `main`. |
| 9 | + |
| 10 | +Observed 2026-08-04: |
| 11 | + |
| 12 | +- `sam/implement-ready-sam-idea-yb534p` (unmerged, no PR open at the time) added |
| 13 | + `[[migrations]] tag = "v20"` / `new_sqlite_classes = ["DiagnosisRunner"]` and deployed to staging. |
| 14 | +- `main` ends at `v19`. |
| 15 | +- Every subsequent staging deploy of `sam/auto-run-html-artifact-preview` — a branch touching |
| 16 | + **zero** `apps/api` and zero wrangler files — failed with: |
| 17 | + |
| 18 | + ``` |
| 19 | + Cannot apply new-sqlite-class migration to class 'ProjectData' |
| 20 | + that is already depended on by existing Durable Objects [code: 10074] |
| 21 | + ``` |
| 22 | + |
| 23 | +- Reproduced twice, the second time on a **completely idle deploy queue**, ruling out a race. |
| 24 | + |
| 25 | +Note the error names `ProjectData` — a class from an old migration that has nothing to do with the |
| 26 | +change. When Wrangler cannot match the remote tag against the local migration list, it appears to |
| 27 | +replay from the beginning and fails on the first already-applied SQLite class. **The error therefore |
| 28 | +points at an innocent class and an innocent branch**, which makes this expensive to diagnose: the |
| 29 | +natural first read is "my branch broke Durable Objects." |
| 30 | + |
| 31 | +## Why this matters |
| 32 | + |
| 33 | +- Staging is a **hard merge gate** (`.claude/rules/13-staging-verification.md`). One agent's |
| 34 | + in-progress branch can therefore block every other agent's merges, indefinitely, with no signal |
| 35 | + that it has done so. |
| 36 | +- The failure is silent about its true cause and misattributes blame to the blocked branch. |
| 37 | +- `.claude/rules/13`'s existing mitigation — check for active runs, wait 5 minutes — **does not help |
| 38 | + here**. The conflicting run had already *completed*; the damage is the persistent migration state |
| 39 | + it left behind, not concurrency. |
| 40 | + |
| 41 | +## Acceptance Criteria |
| 42 | + |
| 43 | +- [ ] Decide the intended model for DO migrations against shared staging. Options to evaluate: |
| 44 | + (a) block staging deploys from branches whose migration tail is not an ancestor of `main`'s; |
| 45 | + (b) detect the mismatch in `Validate Configuration` and fail fast with an explanatory message |
| 46 | + naming the branch that pinned the tag; |
| 47 | + (c) give migration-bearing branches an isolated Worker/environment; |
| 48 | + (d) require migration-bearing branches to merge before others deploy (process-only, weakest). |
| 49 | +- [ ] Implement the chosen mechanism so the failure is either prevented or **self-explanatory**. |
| 50 | + At minimum, when `wrangler deploy` fails with `[code: 10074]`, the deploy workflow should |
| 51 | + surface: "staging is at migration tag X; this branch's list ends at Y; tag X comes from a |
| 52 | + branch not yet merged to main" — instead of the raw `ProjectData` error. |
| 53 | +- [ ] Document the constraint in the deploy/staging guidance so agents recognise it immediately. |
| 54 | +- [ ] Add a check or test that would have caught this before a human had to diagnose it. |
| 55 | + |
| 56 | +## Context |
| 57 | + |
| 58 | +Discovered while running Phase 6 of `tasks/active/2026-08-04-auto-run-html-artifact-preview.md`. |
| 59 | +That branch's first staging deploy (`30958087671`) succeeded and was fully verified; the two later |
| 60 | +deploys (`30959346237`, `30961280231`) failed purely due to this pinning, after the other branch |
| 61 | +deployed at 23:14:33. |
| 62 | + |
| 63 | +## References |
| 64 | + |
| 65 | +- `.claude/rules/13-staging-verification.md` — staging as a merge gate; the 5-minute active-run wait |
| 66 | + that does not cover this case |
| 67 | +- `.claude/rules/31-migration-safety.md` — D1 migration safety (this is the **Durable Object** |
| 68 | + analogue, currently uncovered) |
| 69 | +- `apps/api/wrangler.toml` — the `[[migrations]]` tag sequence |
0 commit comments