Repository navigation
Description
What is wrong
ThinkFlowLab/FlyBot main is protected by ruleset 25173372 ("main merge queue"): enforcement: active, bypass_actors: [], current_user_can_bypass: never, with merge_queue (SQUASH) and required_status_checks rules on refs/heads/main. With no bypass actor a push of the fork's main to upstream main is refused — right for protection, fatal for a fast-forward.
The only route used so far is: set the ruleset to disabled, push the fork's main to upstream, set it back to active. That sequence lives in one Bot's head. Nothing in the repository records it, nothing checks that the ruleset came back, and a failure between the two flips leaves main unprotected while the next release PR is prepared. Nor is there a record of the call that works from this machine, where git push to github.com:443 does not connect and only api.github.com answers.
AGENTS.md describes upstream main's merge queue (section "Merge gates") but never says how the fork's commits reach it; the daily-release row names only the release itself.
Expected behaviour
A checked-in runbook another Bot can follow without asking, a read-only check that answers "is the fork in sync and is the ruleset active?", and a sync path whose last step is the restore verified rather than assumed.
The release flow this runbook has to describe (owner, 2026-10-23)
One ruleset window per version. The fast-forward and the tag travel in the same window, and the upstream release is created inside it — never a second window later. Every release leaves the fork ahead again (measured today: fork f20cfa37, upstream 6f9b60c7, ahead_by: 3, behind_by: 0), so this repeats with every version.
The six steps, in this order:
- the release pull request lands on the fork and
main'sTestis green; - the tag goes on the release commit, not on the tip;
- the fork's
Releaseworkflow produces the four assets; check the sha256 of each; - re-run the dry-run and its five gates;
- open the window:
PUTthe ruleset to disabled → fast-forward withforce: false→ restore infinallyand read the ruleset back; - create the release upstream and upload the same asset bytes.
Two facts measured on 2026-10-23 go into the runbook verbatim, not paraphrased:
- a ruleset update is
PUT;PATCHreturns 404 every time; - under the billing lock, both the tag run and
main'sTestare zero-step, 4-second failures — that is the lock, not a failed release, and there is nothing to cancel.
Stop rule: if the fast-forward ancestry no longer holds, do not guess — stop and report to Chief.
Acceptance
docs/release-runbook.mdexists, is linked fromAGENTS.md, and covers in order: the preflight reads (upstream ruleset id and state, bothmainSHAs, the commits to push); the disable call; the fast-forward; the restore call; a post-check that reads the ruleset back and assertsenforcement: active,bypass_actors: [],current_user_can_bypass: never.- The runbook names the write path this machine actually has (
api.github.com, ref update;git pushfails) and the permission needed (admin on the upstream repo), including the exact error to expect without it. - The failure path is written out: what to do when the push fails after the disable, so the ruleset is never left off, and one command that proves the restore.
- A read-only check runs without side effects:
node .github/scripts/upstream-sync.mjs --checkprints bothmainSHAs, ahead/behind/equal, and the ruleset state; it exits 0 only when the SHAs are equal and the ruleset is active with empty bypass, otherwise nonzero naming the failed condition. .github/scripts/upstream-sync.test.mjspins the exit codes for: equal + active (0); behind (nonzero); ruleset inactive (nonzero); non-empty bypass (nonzero); ruleset read 404 (nonzero, message names the id).- Nothing in
--checkwrites to either repository. - The runbook contains the six release steps above, the "one window per version" rule, and the two measured facts verbatim (
PUTvsPATCH404; zero-step 4-second failures are the billing lock). --checkprints theahead_by/behind_bynumbers it read, not only a boolean.
Kill conditions
- A runbook that says "disable the ruleset" without the restore step and the read-back.
- Automation that can push while leaving the ruleset off — no
finally/trap equivalent. - Leaving the runbook only in a pull-request body or in a Bot's memory.
- Claiming the fast-forward is
git pushfrom this machine without having tested it. - Requiring a permission Release does not have, without saying so up front.
- Changing the upstream ruleset's design: the empty
bypass_actorsis a deliberate owner decision, not a bug. - A second ruleset window for the same version, or a tag that reaches upstream without the fast-forward in the same window.
Out of scope
- Adding a bypass actor or any Bot-specific exemption upstream.
- The daily release mechanics (version bump, tag, four assets);
AGENTS.mdand the release PR already cover them. - Upstream CI's billing lock — that belongs to Live E2E has failed on every scheduled run since it landed: the repository secret DEEPSEEK_API_KEY is not configured #794; the runbook may only say how to tell it apart from a real failure.
Activity
Birfy commentedon Oct 23, 2026
Written-by: Release
Claiming this one. Branch
feat/815-upstream-syncinBirfy/FlyBot, pull request #37 ata30f77d2.What is in it:
docs/release-runbook.md(the six steps, one window per version, the disable/fast-forward/restore sequence with the read-back, the write path and the permission, the failure path, and the two measured facts quoted verbatim),node .github/scripts/upstream-sync.mjs --check(bothmainSHAs,ahead_by/behind_by, the ruleset row; exit 0 only when the mains are equal and the ruleset is active with an empty bypass list), its test file, theAGENTS.mdlink, and one changelog fragment.Run on the tip:
node --test .github/scripts/upstream-sync.test.mjs9/9, the whole.github/scripts/*.test.mjssuite 282/282,changelog.mjs check8 fragments,testing-layers.mjs --check326 files / 13 workflows. Live--checkright now exits 1 withahead_by: 3 behind_by: 0 status: aheadandenforcement=active bypass_actors=[] current_user_can_bypass=never, which is the honest pre-window state rather than a failure of the check.Not run:
npm run verifyin full — nothing undercore/,plugins/orpatches/changed. No window was opened for this: the runbook documents the sequence, it does not execute one.Fix the runbook's token and tools, and print the numbers on every path
Document the upstream fast-forward and check it instead of rememberin…
Birfy commentedon Oct 23, 2026
Written-by: Release
Shipped in the fork as
bbd29584: #37 merged at9b755557(PASS by Reviewer2 at that tip), and theTestrun onbbd29584is success.What landed:
docs/release-runbook.md(the six steps, one window per version, disable → fast-forward → restore in afinally→ read-back, the write path and the admin requirement, the failure path, the stop rule, and the two measured facts verbatim),node .github/scripts/upstream-sync.mjs --checkand--commits, their tests, theAGENTS.mdlink and one changelog fragment. Every command in the runbook is anodesnippet: this box has nocurland nojq.It reaches upstream with the
0.2.6fast-forward, in the same window as that release.