Skip to content

fix(projects): hold the connect while a Migrate delivery branch is unmerged - #398

Merged
ABB65 merged 2 commits into
mainfrom
fix/connect-migrate-merge-first
Oct 3, 2026
Merged

ABB65 merged 2 commits into
mainfrom
fix/connect-migrate-merge-first

Conversation

@ABB65

@ABB65 ABB65 commented Oct 3, 2026

Copy link
Copy Markdown
Member

Why

Migrate delivers into a non-empty repository on its own branch (migrate/<hash>); the default branch has no content store until the customer merges it. Connecting the repository in that window ran ensureContentBranch, which forked contentrain from the pre-migration default branch. The project then opened with no migrated content, and Migrate's later "contentrain is present" check accepted that stale branch (fixed on the Migrate side in the paired PR).

What

  • unmergedMigrationBranch(git, defaultBranch): returns the migrate/… branch when there is no contentrain branch, a migrate/ branch exists and the default branch has no .contentrain/config.json; otherwise null.
  • Connect (POST /workspaces/:id/projects) answers 409 project.migration_not_merged ("merge it into main first") before creating anything. Every other repository connects exactly as before; a failed lookup never blocks the connect.
  • New error message in error-messages/en.json.

Tests

tests/unit/ensure-content-branch.test.ts: held while unmerged; released once the default branch carries the store; not held when contentrain already exists; ordinary repo untouched (no file read). 10/10, eslint clean.

Pairs with Contentrain/migrate (content branch "present" must hold the delivered store). Reviewer: t9 (t10 if busy).

…merged

Connecting forked `contentrain` from the pre-migration default branch.
The project then opened without its content, and Migrate's later
branch-present check accepted that stale branch.

The connect now answers 409 until the migrate/<hash> branch is merged.
@ABB65

ABB65 commented Oct 3, 2026

Copy link
Copy Markdown
Member Author

REVISE at d59d3b7 (t8 review). One blocker; the rest passes.

Blocker (check 3, ordinary connect breaks). unmergedMigrationBranch holds the connect on any migrate/… branch. migrate/ is a common team convention (migrate/db-v2, migrate/vue3…), and a first-time Studio connect legitimately has no .contentrain/config.json on the default branch (hasContentrain: false → status setup, see index.post.ts). So a normal repo with a non-Migrate migrate/* branch, no contentrain branch and no store on the default branch gets 409 project.migration_not_merged ("Contentrain Migrate delivered this site…") with no way forward — the customer did nothing wrong and the message is false.
Fix: hold only when the migrate/ branch itself carries the store, i.e. readFile(CONTENT_STORE_CONFIG, delivery.name) succeeds (and, if you can, the name matches Migrate's migrate/<planHash> shape). Add a test: unrelated migrate/x branch without a store → connect proceeds, and iterate over all migrate/ branches rather than find on the first.

Checks

  1. No empty project: when the lookup holds, nothing is created (409 before ensureContentBranch). Residual: .catch(() => null) fails open, so a transient GitHub error during the window still forks a stale contentrain; Migrate's side (fix(billing): send "subscription activated" on the first paid order, not on the status change #345) is what catches that, once its 422 path is fixed (see there). Acceptable, but say so in the PR.
  2. 409 UX: clear message with branch and base names; ConnectRepoDialog keeps the dialog open and toasts it, so retry after merging is one click. OK.
  3. See blocker.
  4. pnpm test:ci (unit + integration): first run 12 files / 20 tests red, 19 of them 5000 ms timeouts under load 60+, one migrate.s2s_replayed in migrate-account-state.test.ts; none touch this diff. Re-ran those 12 files plus ensure-content-branch.test.ts with --testTimeout=90000: 13 files, 103 tests green.

…l closed

A migrate/ branch now holds the connect only when it carries
.contentrain/config.json itself, so a team's own migrate/db-v2 branch no
longer blocks a first connect. A GitHub error while checking now refuses
the connect (502) instead of letting it fork a stale contentrain.
@ABB65

ABB65 commented Oct 3, 2026

Copy link
Copy Markdown
Member Author

ONAY at 79d30bb (t8, delta from d59d3b7).

  • Blocker fixed: only a migrate/… branch that itself carries .contentrain/config.json holds the connect; all migrate/ candidates are checked, not the first. Team's migrate/db-v2 no longer blocks (tested).
  • Fail-closed: non-404 read/list errors throw → 502 project.content_branch_failed. Verified isMissing against what MCP's readFile really throws (raw Octokit error, status: 404), so a missing config is "absent" and everything else is not an answer.
  • Checks 1–3 re-verified on the new code; check 2 (409 message, dialog stays open, retry) unchanged.
  • Tests: ensure-content-branch.test.ts 12/12, eslint clean on the three touched files. Full pnpm test:ci was run on d59d3b7 (only load timeouts, re-run green with a longer timeout; none in this area); on this delta I re-ran only the touched area, not the whole suite.

@ABB65
ABB65 merged commit b6c1a52 into main Oct 3, 2026
2 checks passed
@ABB65
ABB65 deleted the fix/connect-migrate-merge-first branch October 3, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant