diff --git a/quest/m0/README.md b/quest/m0/README.md index a07461f573..222dcc4449 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -17,8 +17,9 @@ done. moq.pro tracks this repository as a submodule rather than a release, so no release quest gates this milestone. The Pronto GPU integration lives in moq.pro. -Relay hardening: IETF interop leads the ranking, since only those quests -block Seattle. IETF stream types came from m1 in the 2026-09-30 audit +The branch flip ranks first: it is a short cutover that every later PR +targets. Relay hardening: IETF interop leads the rest, since only those +quests block Seattle. IETF stream types came from m1 in the 2026-09-30 audit because a session ended by legal input is exactly what Seattle would hit. The DoS hardening from an external review on 2026-09-29, verified against `main`, stays in m0 as security work. Its quests describe fixes, not exploits. @@ -39,6 +40,7 @@ Published API or wire breaks still land on dev; each quest's Plan says so. ## Required +- [Branch flip](/quest/m0/branch-flip.md) - `dev` becomes the default `main` trunk and today's `main` becomes `release`, where publishing runs - [IETF FIN semantics](/quest/m0/ietf-fin-not-cancel.md) - a request stream FIN stops updates without cancelling, and REQUEST_UPDATE on a subscribe is parsed - [JS unknown bidi](/quest/m0/ietf-unknown-bidi.md) - an unknown moq-transport bidi stream type closes the session in JS, as in Rust - [moq-lite early streams](/quest/m0/lite-early-streams.md) - a lite uni stream that arrives before SETUP is held until SETUP lands, and a second SETUP is fatal diff --git a/quest/m0/branch-flip.md b/quest/m0/branch-flip.md new file mode 100644 index 0000000000..b687084433 --- /dev/null +++ b/quest/m0/branch-flip.md @@ -0,0 +1,91 @@ +# [M] Trunk is main, releases ship from release + +## Goal + +`dev` is renamed `main` and is the default branch: the trunk, where breaking +changes are allowed and every quest and PR lands. Today's `main` is renamed +`release`, a permanent branch where release-plz and all publishing run. Code +reaches `release` when a release is cut, by merging `main` in; urgent fixes in +between are cherry-picked. AGENTS, CONTRIBUTING, and the quest tree describe +that model, with no `dev` left. + +## Plan + +Facts (2026-10-02): + +- Publishing on push: `release-rs` (release-plz), `release-js`, `release-py`, + and `release-go` trigger on `main`; `release-kt-lib` and `release-swift-lib` + on `main` and `dev`. Everything else publishes from tags and is unaffected. +- `workflow_run` chains run the default branch's workflow file, and a + checkout without a ref takes its head. `release-py`, `release-kt-lib`, and + the `release-swift-lib` build pin the triggering `head_sha`; `release-go`, + `release-brew`, and the other `release-swift-lib` checkouts do not, so after + the flip they would build trunk. +- `cache.yml` and `swift.yml` warm caches on `main` on both branches. PRs + read caches only from the default branch, so writers stay on trunk and + need no change. `obs`, `platform`, and `quest` push filters name `main` and + `dev`. Nightly and interop crons run on the default branch. +- Rulesets: "main" targets `~DEFAULT_BRANCH` (linear history, Check and Test + required), so it moves to trunk and forbids a merge-commit back-merge. + "dev" targets `refs/heads/dev` (PRs only, squash or merge commit) and does + not follow a rename. +- Renaming `main` makes GitHub retarget its ~35 open PRs to `release`; `dev`'s 10 + follow it to the new `main`. +- `sh/changed.sh` falls back to `origin/main`, which stays right for trunk. + `quest` hardcodes `main` as the milestone base, which becomes right too. +- About 50 quest files on `main` (40 on `dev`) say "on `dev`"; AGENTS.md (API, + Development, quest sections), CONTRIBUTING.md, `py/AGENTS.md`, and + `quest/README.md` encode the split. +- `nix run github:moq-dev/moq`, `npx skills add moq-dev/moq`, and docs "edit" + links follow the default branch. + +Decided (2026-10-02): + +- ✅ Flip, over keeping `dev` with continuous sync or dropping a stable branch. +- ✅ A release is cut by merging `main` into `release` (merge commit), by + hand. Rejected: resetting `release` to `main`, and backport-only flow. +- ✅ Backports are manual cherry-pick PRs into `release`; automate later if + it hurts. +- ✅ After each publish, a workflow merges `release` back into `main`, so trunk + carries the published versions and CHANGELOGs. Rejected: running the + release-plz PR on `main` and publishing from `release`. +- ✅ Trunk is the default branch. User-facing installs in docs pin `release` + (`github:moq-dev/moq/release`); all branch-triggered publishing, including + kt and swift libs, runs only from `release`. Nightly and edit links stay on + trunk. +- ✅ A new `release` ruleset (no deletion or force push, Check and Test + required, PRs only, merge commits allowed); the `dev` ruleset is deleted. +- ✅ Open PRs that land on `release` through the rename are retargeted to the + new `main`, except any explicitly meant as backports. +- ✅ One mechanical wording sweep: "on `dev`" goes from quests (trunk allows + breaks), the rules describe trunk, `release`, and backports, and + `dev`-only process quests are deleted. +- ✅ One quest, m0, right after dev-sync lands. + +Open: + +- Trunk's linear-history rule rejects the back-merge's merge commit. + Recommended: drop linear history from trunk's ruleset, so the back-merge + lands as a merge commit and advances the merge base; ordinary PRs still + squash. Rejected: squash-merging the back-merge, which leaves the base at + the last cut, so a second publish before the next cut conflicts. + +Sequence: + +1. [dev-sync](/quest/m1/dev-sync.md) (#4720) lands. +2. A PR on `dev`: the wording sweep, trunk stops publishing, `obs`, + `platform`, and `quest` push filters name `main` and `release`, + unpinned `workflow_run` checkouts pin the triggering `head_sha`, the + back-merge workflow, docs pin `release`. +3. A small PR on `main`: publish triggers move to `release`; cache writers + keep `main`, so they stop running there. +4. Admin, back to back, run by the agent only after the maintainer's + go-ahead in chat: rename `main` to `release`, rename `dev` to `main`, set + the default branch, create the `release` ruleset, delete the `dev` + ruleset, retarget open PRs. Release-plz PRs (such as #4596) stay on + `release`. Dry-run first and show the PR list with each PR's class. +5. Verify: a no-op push to `main` publishes nothing; release-plz runs on + `release`; a chained publish builds `release` while trunk differs; the + back-merges of two publishes without a cut between both land on `main`. + +Public API: none. Wire: none. Contributors see the new branch model.