Skip to content

ci: automate promotion and sync release history back to staging - #374

Merged
qiuethan merged 4 commits into
stagingfrom
feat/promotion-workflow
Nov 3, 2026
Merged

qiuethan merged 4 commits into
stagingfrom
feat/promotion-workflow

Conversation

@qiuethan

@qiuethan qiuethan commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

What this changes

Production promotions leave a merge commit on main that has to be reconciled into staging before the next release. Add a Production promotion Actions workflow: manually run promote on main to sync outstanding history and open/reuse the release PR. Every push to main automatically runs sync.

The dedicated release App creates a history-only snapshot PR into staging, waits for its full CI run, then merges it with a merge commit. The snapshot must preserve its staging parent's exact tree. Conflicts, content changes, modified PR heads, failed checks, and denied merges stop the run. Concurrent staging work, including a revert of released code, is preserved. Retrying reuses the snapshot/PR or exits if already synced. Production PR review and merge remain manual.

Security and rollout

  • Created the private UTMIST Misty Release App, installed only on this repository, with Contents/Pull requests/Workflows write and Actions read. No Administration permission.
  • Credentials are stored in the release environment, whose branch policy permits only main (no tags).
  • Only this App can bypass staging's PR-review requirement and merge queue (PR-only bypass). Required checks, administrator enforcement, and main protections remain intact; the configuration was read back and compared.
  • The credentialed job runs main's code and uses Git object operations to inspect staging. It never executes staging dependencies or pushes directly to a protected branch.
  • This must merge into staging and be promoted to main before automatic push-triggered sync is active. The first release handles existing history too. There is a manual sync operation for retries.

Changed-file rationale

File Why needed
.github/workflows/promotion.yml Manual promotion entry point, automatic main-push sync, serialized runs, main-only environment and scoped App token.
.github/scripts/promotion.cjs Idempotent Git snapshot/PR orchestration, unchanged-tree validation, CI wait, pinned merge, and ancestry verification.
.github/scripts/promotion.test.cjs Real disposable Git graphs and fake GitHub calls cover history preservation, concurrent writes/reverts, retries, failed CI, tampering, and execution guards.
.github/workflows/ci.yml Run these regressions in the existing required node-test check, including merge groups.
Makefile Include the same regressions in local fast/full test commands and provide make test-promotion.
docs/DEVELOPMENT.md Operator usage, App/environment/bypass setup, activation, retries, rollback, and the current CI inventory.
docs/RELEASING.md Connect the version/wiki release checklist to promotion and explain initial activation.
AGENTS.md Point agents to the release workflow and prevent squash/rebase of ancestry syncs.

This intentionally spans .github, docs, and root for automation and its local checks/runbook. Conflict resolution preserves both the release-version guard and promotion checks, and integrates the current version/wiki release process.

Validation

  • After integrating the latest staging/versioning and documentation changes, make check passed using the pinned Python dependencies and Node 26.8.1; this includes lint/format checks and the repository's fast suites.
  • make test-release test-promotion passed on the integrated branch. Both targets remain included in make test and make test-full.
  • Promotion/release documentation links and anchors checked successfully. After separately merged Document board readiness, holds and issue closure #345/Align agent instructions with board automation #346 were incorporated, the full Markdown scan reports four inherited references to board files that will arrive with open Repair board lifecycle automation and add operational reports #344 (.github/PROJECT-BOARD.md and .github/workflows/project-board.yml); this PR introduces no new broken links. The promotion script and workflows retain their approved behavior.
  • Earlier implementation validation: actionlint passed for the changed workflows; the App-token action is pinned to an inspected v3 commit.
  • git diff --check passed.
  • Fresh CI initially failed only the unchanged chunking speed assertion (test_line_heavy_text_stays_fast: 6.52 seconds against a 5-second limit). The same test passed locally in 0.67 seconds with source paths verified; the failed job was rerun without modifying code or thresholds. Fresh CI passed on commit c46c6584d0af0c74d739ac44516208263ca54f09.
  • The current real main → staging merge was computed locally and its tree exactly matched staging.
  • Verified the App can mint a short-lived installation token restricted to UTMIST/Misty, then revoked the verification token.
  • Live verification: the exact committed script ran with the dedicated App, created zero-file-diff sync PR chore: sync main 9f08888366c6 back into staging #375, waited for full CI, and merged it as app/utmist-misty-release at a361a97022a8e666b2847bf70427dfe34096a34a. Verified main is now an ancestor of staging and staging's tree is unchanged (3355689efe47a8b2ee3c630df55e172410c6538f). The temporary token was revoked and local private-key copy removed.

The normal production deploy remains triggered by merging the reviewed staging → main PR. A history sync is not proof of production deployment health.

@github-project-automation github-project-automation Bot moved this to Backlog in Misty Nov 2, 2026
@github-actions github-actions Bot added size/xl >= 500 lines changed zone: docs Owned by the docs zone (docs/CODE-OWNERSHIP.md) zone: .github Owned by the .github zone (docs/CODE-OWNERSHIP.md) zone: root Owned by the root zone (docs/CODE-OWNERSHIP.md) and removed size/xl >= 500 lines changed labels Nov 2, 2026
@github-project-automation github-project-automation Bot moved this from Backlog to In review in Misty Nov 2, 2026
@Williamzhibo

Copy link
Copy Markdown
Collaborator

[P1] Revalidate the merge result when reusing an existing sync branch

Location: .github/scripts/promotion.cjs, lines 52–72.

assertSnapshot() checks the parent identities and tree equality, but doesn’t verify that the snapshot represents a valid, unchanged merge of those parents. A precreated or replaced automation branch can therefore bypass the merge-tree check used for new branches.

I reproduced two cases through the actual CLI with real Git repositories and simulated GitHub responses:

  • A snapshot using an older staging ancestor as its first parent passes validation, then rolls back staging files when merged.
  • A snapshot omitting a production-only hotfix passes validation and records main as merged, causing subsequent syncs to skip the missing fix.

Since the release App bypasses staging review, please recompute git merge-tree --write-tree <snapshot-first-parent> <main> when validating an existing snapshot, reject conflicts, and require the resulting tree to match the snapshot. Both cases should have regression coverage.

@qiuethan
qiuethan added this pull request to the merge queue Nov 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 3, 2026
@github-actions github-actions Bot added the size/xl >= 500 lines changed label Nov 3, 2026
@qiuethan
qiuethan added this pull request to the merge queue Nov 3, 2026
Merged via the queue into staging with commit 24ba8b2 Nov 3, 2026
26 of 27 checks passed
@qiuethan
qiuethan deleted the feat/promotion-workflow branch November 3, 2026 19:28
@github-project-automation github-project-automation Bot moved this from In review to Done in Misty Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl >= 500 lines changed zone: docs Owned by the docs zone (docs/CODE-OWNERSHIP.md) zone: .github Owned by the .github zone (docs/CODE-OWNERSHIP.md) zone: root Owned by the root zone (docs/CODE-OWNERSHIP.md)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants