Repository navigation
feat: GitHub stack actions: async merge and rebase (A6) - #672
Merged
Merged
Conversation
…rom a host-owned draft, reply, resolve, react, edit, labels, reviewers
…scope, labels, stale head, no retry, the host's review draft
…ments against the diff, and read the account's rights, labels and reviewers
…view draft in Files, review sheet, thread reply and resolve, reactions, edits, labels and reviewers
…rom the host: a fresh action state before each, stack routing, merge-message credit cleaning, a linked revert
…ry action, menu group, merge dialog, confirmations, results, the composer message for conflicts and checks, and the credit-cleaning setting
…base one on the host: the operation is host state every thread showing the stack carries, followed across restarts and never submitted again
…stack as the primary and in the menu, the merge and rebase confirmations, the rebase's progress, the operation chip and the stack's toasts
# Conflicts: # crates/core/src/pull_request.rs # crates/protocol/src/lib.rs # crates/protocol/src/pull_request.rs # crates/runtime/src/app/pull_requests.rs # crates/runtime/src/app/pull_requests_tests.rs # crates/services/src/github/pull_request_actions.rs # crates/ui/src/assets.rs # crates/ui/src/pull_requests/compose.rs # crates/ui/src/pull_requests/detail.rs # crates/ui/src/pull_requests/lifecycle.rs # crates/ui/src/pull_requests/mod.rs # locales/en.yml # locales/zh-CN.yml
…the stored layers while GitHub is read
…en, and is refused before running without push access
…erged, not before a 1 s poll
…r for the layers an operation covers; a rebase chip without a target opens nothing; queued stacks don't rebase
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Files:
core::pull_request(stack map policy, operation record),protocol(StackState read, MergeStack/RebaseStack, results, rejections, toast; notes abovePROTOCOL_VERSION),services::github::{stack_actions, stack_rebase},runtime::app::pull_request_stacks,ui::pull_requests::stack(map, confirmations, progress, chip, toasts) and the A5b slots it fills.Closes #642
Evidence
After:
(phone stack map retaken on a synthetic profile: sample data keyed to a non-routable GitHub Enterprise address, so the files list behind the sheet is still loading instead of showing the earlier "Couldn't load the files" card)
Checks run on the final commit:
New tests (real behaviour, no test-only seams):
services/tests/stack_actions.rs: one submission at the target head, merged / enqueued / pending / failed told apart; a 409 naming an operation is followed, one naming none is refused; a moved head, a changed scope, another stack number, a draft, a closed or a merged target send no PUT; real bare-repo rebase: each layer replays only its own commits (committed with the host identity), a second run is all "already up to date"; the lease keeps a branch pushed to since review and the layer below stays pushed; a conflict stops at the failing layer, which is untouched, with the lower layer pushed.runtime pull_requests_tests::a_stack_merge_is_followed_across_a_restart_and_never_submitted_again: Pending → followed → merged toast, one PUT; an unconfirmed record refuses another write; a restarted host past the deadline asks once, records it unconfirmed, never submits again, and the next sync reading the target merged ends it with a "finished late" toast; no GraphQL mutation is ever sent for a stack merge.services/tests/stack_actions.rs::a_layer_the_account_cannot_push_to_refuses_the_rebase_before_anything_runs: push access denied on Bump actions/upload-artifact from 4 to 7 #3 →plan_stack_rebaseanswersNoPushAccess { [3] }, no plan exists so no Git runs, and GitHub saw only reads.runtime pull_requests_tests::an_ended_rebase_is_kept_for_every_device_until_the_next_full_sync_and_blocks_no_write: aRebaseEndedrecord survives the reads its end requests, does not refuse the next write (fails withOperationRunningif the busy check counts it), and the next full sweep drops it.core pull_request::tests::a_layer_waits_only_for_the_write_moving_it_now:PullRequestStackOperation::covers, the one owner the page primary, the menu and the linked rows' signal now share.pull_request_operationsin thread meta and callsresume_stack_operationsdirectly; it does not restart a host process.a_stack_merge_is_followed_across_a_restart_and_never_submitted_again(matches!(operation(&state), Merging …)at line 1842): settled by CONTRIBUTING "When a test fails", step 1. The fixture answered "merged" before submission, so on a slow runner the real 1 s poll could end the operation before the test read it. GitHub now answers "pending" until the test has read the Merging record, then "merged", andrun_untilwaits on the record clearing. The assertions are unchanged.a_stack_layer_is_never_merged_alone_and_a_revert_is_linked_as_creatednow expectsInvalidwhere it expectedInStack(the variant is removed with A5's placeholder, design D5); its contract — a stack layer's single merge or branch update reads and sends nothing — is unchanged (CONTRIBUTING "When a test fails", step 3: the contract is real, the wire name changed).Live, on a disposable private repository with a native stack of #1–#3 (noreply commits; afterwards its pull requests were closed and its branches deleted, the repository stays private (deleting it needs the delete_repo scope, which this token lacks)):
PUT merge-async→ 202 pending, followed at +2 s →merged; chip "Merging stack…" with the operation id in its accessible name, then "Merged Add cross-platform CI and release packaging #1"; GitHub rebased Bump actions/checkout from 4 to 7 #2 onto main.enqueued(merge queues need an organization repository; covered by the fixture test), a merge still pending at five minutes and a restart mid-merge (GitHub finished in ~2 s; covered by the runtime test through the host's restart path).Known costs and accepted deviations
stack_operation_recordreads the first copy it finds; a thread that starts showing the stack mid-operation only gets the record at the next write.LC_ALL=C/LANGUAGE=so the lease refusal ("stale info") is recognised under any host locale.Merge Danger
Door: two-way
Blast Radius: stack
Stack writes force-push branches and land several pull requests at once; both go only from a linked layer, re-read GitHub first, and send exactly the confirmed heads. Wire changes are noted above
PROTOCOL_VERSION; thread metadata gainspull_request_operations(absent when empty).