vouchington-tooling 0.43.0 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -1
- package/dist/cli/commands/fresh-base.d.mts +6 -0
- package/dist/cli/commands/fresh-base.mjs +14 -0
- package/dist/cli/index.mjs +3 -0
- package/dist/cli/parse-fresh-base.d.mts +2 -0
- package/dist/cli/parse-fresh-base.mjs +15 -0
- package/dist/cli/parse.d.mts +5 -0
- package/dist/cli/parse.mjs +3 -0
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +2 -0
- package/dist/fresh-base/classify.d.mts +21 -0
- package/dist/fresh-base/classify.mjs +29 -0
- package/dist/fresh-base/index.d.mts +4 -0
- package/dist/fresh-base/index.mjs +2 -0
- package/dist/fresh-base/run.d.mts +25 -0
- package/dist/fresh-base/run.mjs +66 -0
- package/dist/gh-cli/closing-refs.d.mts +24 -0
- package/dist/gh-cli/closing-refs.mjs +37 -0
- package/dist/gh-cli/index.d.mts +3 -0
- package/dist/gh-cli/index.mjs +2 -0
- package/dist/gh-cli/non-closing-refs.d.mts +11 -0
- package/dist/gh-cli/non-closing-refs.mjs +24 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +3 -0
- package/dist/pull-request-diff/diff-size.d.mts +29 -0
- package/dist/pull-request-diff/diff-size.mjs +35 -0
- package/dist/pull-request-diff/index.d.mts +2 -0
- package/dist/pull-request-diff/index.mjs +1 -0
- package/dist/retrospective-distill/args.d.mts +13 -0
- package/dist/retrospective-distill/args.mjs +27 -0
- package/dist/retrospective-distill/checkpoint-entry.d.mts +2 -0
- package/dist/retrospective-distill/checkpoint-entry.mjs +11 -0
- package/dist/retrospective-distill/fixtures.test-helpers.d.mts +3 -0
- package/dist/retrospective-distill/fixtures.test-helpers.mjs +21 -0
- package/dist/retrospective-distill/flag-args.d.mts +5 -0
- package/dist/retrospective-distill/flag-args.mjs +31 -0
- package/dist/retrospective-distill/index.d.mts +10 -0
- package/dist/retrospective-distill/index.mjs +6 -0
- package/dist/retrospective-distill/partition-records.d.mts +6 -0
- package/dist/retrospective-distill/partition-records.mjs +49 -0
- package/dist/retrospective-distill/retrospective-entry.d.mts +3 -0
- package/dist/retrospective-distill/retrospective-entry.mjs +4 -0
- package/dist/retrospective-distill/run.d.mts +5 -0
- package/dist/retrospective-distill/run.mjs +28 -0
- package/dist/retrospective-distill/session-types.d.mts +17 -0
- package/dist/retrospective-distill/session-types.mjs +1 -0
- package/dist/retrospective-distill/shape.d.mts +29 -0
- package/dist/retrospective-distill/shape.mjs +111 -0
- package/docs/mcp-server.md +1 -1
- package/package.json +18 -3
- package/skills/agent-workflow/SKILL.md +20 -0
- package/skills/agent-workflow/references/four-refs.md +74 -0
- package/skills/blackboard/SKILL.md +21 -1
- package/skills/github-issue/SKILL.md +6 -0
- package/skills/manifest.json +11 -5
- package/skills/postgres-node-performance-tuning/SKILL.md +2 -0
- package/skills/postgres-node-performance-tuning/references/performance-patterns.md +76 -0
- package/skills/postgres-node-performance-tuning/references/reading-plans.md +111 -0
- package/skills/postgres-schema-design/references/relations.md +18 -0
- package/skills/retrospective-distill/SKILL.md +67 -4
- package/skills/revisit-followups/SKILL.md +17 -0
- package/skills/stacked-prs/SKILL.md +47 -16
- package/skills/stacked-prs/references/drain.md +168 -0
- package/skills/stacked-prs/references/gh-stack.md +143 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Drain and keep track
|
|
2
|
+
|
|
3
|
+
Shepherding a layer to ready and merging are different acts. The first covers every pull request
|
|
4
|
+
the worker owns in the stack at once. The second lands the ready prefix in one command, and it is
|
|
5
|
+
never the agent's own decision.
|
|
6
|
+
|
|
7
|
+
## Establish scope
|
|
8
|
+
|
|
9
|
+
1. Resolve the stack from `pulls/<any-layer>.stack`, and record whether the field was present. A
|
|
10
|
+
stack object supplies its number; an explicit `null` means no registered stack. A missing
|
|
11
|
+
preview field: query `stacks?pull_request=<N>`, where one result is the stack and zero means
|
|
12
|
+
unstacked. Do not treat an empty `.stack.number` alone as proof
|
|
13
|
+
that a pull request is unstacked.
|
|
14
|
+
2. Read topology from `repos/{owner}/{repo}/stacks/<n>`, ordered bottom to top. A
|
|
15
|
+
`closed && merged_at == null` layer below an open one means the stack is broken. Report it to
|
|
16
|
+
the human, and never merge across it.
|
|
17
|
+
3. Partition by ownership, using that topology read plus each member's body from `pulls/<N>` (the
|
|
18
|
+
stack response has no bodies). Shepherd only owned pull requests. Never
|
|
19
|
+
poll, fix, rebase, or push the others, but list them in every report. Owned means this session
|
|
20
|
+
opened the pull request, or a human named it in this session.
|
|
21
|
+
- The opened-by-me half is a durable remote fact when the repository's pull request description
|
|
22
|
+
tool stamps each body with the authoring harness and session id. Compare the stamp with the
|
|
23
|
+
current session id.
|
|
24
|
+
- The named-by-a-human half is conversational and cannot be recovered remotely. That is
|
|
25
|
+
acceptable, because the human can restate it after a compaction.
|
|
26
|
+
- Degrade explicitly. A body without a matching stamp, or with a stamp naming no session id,
|
|
27
|
+
is not owned. Report it as "ownership unverifiable" and never poll it.
|
|
28
|
+
- A parent may assign its stack to one worker by listing the pull request numbers and the
|
|
29
|
+
session id stamped on them. The worker treats that list as assigned and still refuses any
|
|
30
|
+
layer outside it.
|
|
31
|
+
|
|
32
|
+
## Shepherd the owned layers
|
|
33
|
+
|
|
34
|
+
Run one stack shepherd poll for the assigned stack, and follow its printed instructions.
|
|
35
|
+
|
|
36
|
+
- A shepherd's own "owned" mark can mean only that the author login equals the authenticated
|
|
37
|
+
viewer. Several sessions often share one account, so filter every printed row against the
|
|
38
|
+
ownership partition above before acting. Never start a per-pull-request session, fix, or push
|
|
39
|
+
for a row outside it, even when the shepherd marks it owned.
|
|
40
|
+
- Apply code fixes, rebases, pushes, and review mutations to owned layers only. Report work
|
|
41
|
+
surfaced on an unowned layer to the human.
|
|
42
|
+
- Fix on the owning layer. Commit there, rebase the layers above it (`gh stack rebase --upstack`),
|
|
43
|
+
`gh stack sync` when there are no local stack commits, `gh stack push` once, then rerun the
|
|
44
|
+
shepherd.
|
|
45
|
+
`rebase --upstack` and `push` act through the top of the stack. When an unowned layer sits above
|
|
46
|
+
an owned one, stop at that layer: do not rebase or push it, and hand the remaining rebase and
|
|
47
|
+
push to its owner.
|
|
48
|
+
- Start the shepherd with the first pull request. While the poll is in a pure wait and the
|
|
49
|
+
worktree is clean, commit the next layer once the lower layer is in decent shape. On a
|
|
50
|
+
fix-code result, finish it on the owning layer before more upper edits. A ready-delay schedules
|
|
51
|
+
the rerun: continue owned work on a later layer, and do not invent unrelated work.
|
|
52
|
+
- Never run a printed merge command unless the human's approval covers that layer and every open
|
|
53
|
+
layer below it, and the checks below pass. `gh stack merge <pr>` lands that pull request and
|
|
54
|
+
every layer below it.
|
|
55
|
+
- Mutating git does not parallelize. Stop the poll before a rebase, sync, or push in the stack's
|
|
56
|
+
shared worktree, because other layers' branches can be rewritten underneath it. Discard a poll
|
|
57
|
+
result that was in flight across the mutation, and start the poll again after the push lands.
|
|
58
|
+
Run at most one git mutation at a time.
|
|
59
|
+
|
|
60
|
+
### Upper-only fast-forward
|
|
61
|
+
|
|
62
|
+
A queued lower layer, or any lower layer that must not be rewritten, does not stop an upper-only
|
|
63
|
+
fast-forward, or upper review and CI work that does not write git.
|
|
64
|
+
|
|
65
|
+
- Before that push, read the forge and capture the parent head, the parent base, the upper remote
|
|
66
|
+
head, and the stack order. Read all four again immediately before pushing.
|
|
67
|
+
- Push only when all four still match, the local upper commit fast-forwards that remote head, and
|
|
68
|
+
it still contains the parent. If anything differs, or the lower layer merges or leaves the queue
|
|
69
|
+
meanwhile, stop and read the forge again. Never push from a stale capture.
|
|
70
|
+
- Do not amend, force-push, `gh stack sync`, or `gh stack rebase` a queued parent: each rewrites
|
|
71
|
+
it. When the lower layer changes, re-read topology before branch work that depends on the new
|
|
72
|
+
parent.
|
|
73
|
+
|
|
74
|
+
### Escalations persist to the pull request
|
|
75
|
+
|
|
76
|
+
When a layer needs a human, because it is ready and waiting on a merge decision or genuinely
|
|
77
|
+
blocked:
|
|
78
|
+
|
|
79
|
+
- Apply the repository's needs-human label and post one comment per escalation event, not per
|
|
80
|
+
poll, with the layer's position and what it needs.
|
|
81
|
+
- When a layer re-escalates, minimize the superseded comment (GraphQL `minimizeComment`,
|
|
82
|
+
`classifier: OUTDATED`). Clear the label once the layer no longer needs a human.
|
|
83
|
+
- A relayed merge command is for visibility only. The shepherd picks its target from ready
|
|
84
|
+
results alone and does not know what the human approved.
|
|
85
|
+
|
|
86
|
+
## Report
|
|
87
|
+
|
|
88
|
+
When the owned set settles, present the stack bottom to top: each layer's number, owner, state,
|
|
89
|
+
and whether it is ready or blocked and why. Never leave a ready bottom layer under a blocked upper
|
|
90
|
+
layer without saying so.
|
|
91
|
+
|
|
92
|
+
## Merge the ready prefix
|
|
93
|
+
|
|
94
|
+
The ready prefix is the bottom-most open layer plus every consecutive layer above it that is also
|
|
95
|
+
ready and inside the approval. Its top layer is the merge target. A shepherd that prints a merge
|
|
96
|
+
of its highest ready layer may name a layer above the approved range. Target the highest approved
|
|
97
|
+
layer of the prefix instead; that is still one command.
|
|
98
|
+
|
|
99
|
+
Merge only on explicit human approval. The approval names what it covers: one layer, a range, or
|
|
100
|
+
the whole stack. Approving the whole stack also covers the next ready prefix after an earlier
|
|
101
|
+
merge. It does not cover a layer added after the approval. Ask before merging any layer outside
|
|
102
|
+
it.
|
|
103
|
+
|
|
104
|
+
Immediately before each approved merge, run these checks in order:
|
|
105
|
+
|
|
106
|
+
1. `gh api repos/{owner}/{repo}/stacks/<target>` must return 404. `gh stack merge` resolves a bare
|
|
107
|
+
number as a stack number first, then a pull request number. A 200 response means `--yes` would
|
|
108
|
+
merge every layer of that stack. Stop and ask.
|
|
109
|
+
2. Re-read topology. Confirm every layer from the bottom-most open layer up to the target is open,
|
|
110
|
+
ready, and inside the approval, with nothing broken below.
|
|
111
|
+
3. For every layer in the prefix, capture `pulls/<N>.head.sha` before the final poll and after it.
|
|
112
|
+
They must match. A mismatch means a push landed inside the evaluation window: discard the
|
|
113
|
+
verdict and poll again.
|
|
114
|
+
4. `gh stack merge <target> --yes` with the repository's merge strategy. It lands the target and
|
|
115
|
+
every open layer below it, which is the ready prefix.
|
|
116
|
+
5. Do not `gh stack sync` here. Return to step 2 of [Establish scope](#establish-scope) and
|
|
117
|
+
re-read topology remotely: rebasing right after a merge can replay already-landed commits from
|
|
118
|
+
a stale local base ref. Keep shepherding the layers above. When the new bottom is ready, merge
|
|
119
|
+
the next ready prefix the same way. Before any local edit, rebase, or push on a remaining
|
|
120
|
+
layer, rerun the fetch and ahead/behind check in
|
|
121
|
+
[Import a stack](gh-stack.md#import-a-stack-before-acting-on-it): GitHub rebases the next
|
|
122
|
+
layer remotely, so local upper branches are stale until fast-forwarded. The drain is complete when no unmerged owned layer remains.
|
|
123
|
+
|
|
124
|
+
The window between the last head read and the merge cannot be closed, because `gh stack merge`
|
|
125
|
+
has no head-SHA pin. Branch protection and rulesets are evaluated when the merge runs, and stacks
|
|
126
|
+
cannot bypass merge requirements. If the merge is rejected, re-read topology instead of retrying
|
|
127
|
+
blindly. Under a merge queue, a successful `gh stack merge` only enqueues: the prefix queues
|
|
128
|
+
together, and a failing layer is ejected along with the layers above it. The next topology
|
|
129
|
+
re-read handles that.
|
|
130
|
+
|
|
131
|
+
When you stop or are blocked (an unresolved escalation, an interrupt or pause, repeated fixes with
|
|
132
|
+
no progress, or an external blocker), report each layer's number and state. If the bottom layers
|
|
133
|
+
are ready, ask whether to merge that ready prefix before continuing.
|
|
134
|
+
|
|
135
|
+
## Keep track: derive the ledger
|
|
136
|
+
|
|
137
|
+
A hand-kept list of "pull requests I opened" drifts, and a compaction or new session erases it.
|
|
138
|
+
The ownership stamp makes the ledger derivable, so state is re-read instead of recalled.
|
|
139
|
+
|
|
140
|
+
Reconcile broadly, partition narrowly. A new session opens a rival stack because it never looks for
|
|
141
|
+
the old one, so the reconcile query is deliberately unfiltered; only the partition is
|
|
142
|
+
session-filtered:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Reconcile, unfiltered: it finds stacks this session did not create.
|
|
146
|
+
gh api --paginate repos/{owner}/{repo}/stacks --jq '.[] | select(.open)' # 30 per page
|
|
147
|
+
gh api --paginate "repos/{owner}/{repo}/pulls?state=open&per_page=100" \
|
|
148
|
+
--jq '.[] | {number, title, user: .user.login, body}'
|
|
149
|
+
# Partition: apply the ownership check from Establish scope to that output.
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- Reconcile before starting anything new. At the start of work, and before opening any pull
|
|
153
|
+
request or stack, surface every open stack or unfinished layer, whoever made it.
|
|
154
|
+
- Close out; do not drift away. Close a layer that will not land. Ending or pausing a session with
|
|
155
|
+
owned open layers requires reporting them.
|
|
156
|
+
- Continue the stack instead of starting a parallel one. Dependent work for an owned open stack is
|
|
157
|
+
a new layer (`gh stack add`, after the layer cap check). For an unowned open stack, report it and
|
|
158
|
+
ask instead of adding to it or starting a rival.
|
|
159
|
+
- Derive state (which pull requests and stacks exist, their positions, their status) every time;
|
|
160
|
+
never cache it. Only intent, such as which stack is being built or what a planned layer is for,
|
|
161
|
+
belongs in the session's plan or journal, and it is a plan, not a record.
|
|
162
|
+
|
|
163
|
+
Known gaps:
|
|
164
|
+
|
|
165
|
+
- An ownership stamp is a body line any writer can edit. It is a signal, not an authorization
|
|
166
|
+
boundary, and that is sound only because every merge is human-gated.
|
|
167
|
+
- Stack and pull request numbers share no guaranteed disjointness, which is why merge check 1
|
|
168
|
+
runs before every merge.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# gh-stack mechanics
|
|
2
|
+
|
|
3
|
+
Official docs (do not copy): [About](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs),
|
|
4
|
+
[CLI](https://docs.github.com/en/pull-requests/reference/stacked-prs-cli-commands),
|
|
5
|
+
[Managing](https://docs.github.com/en/pull-requests/how-tos/create-pull-requests/managing-stacked-pull-requests),
|
|
6
|
+
[Merging](https://docs.github.com/en/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests).
|
|
7
|
+
|
|
8
|
+
## Setup
|
|
9
|
+
|
|
10
|
+
- Install on first stacked use: `gh extension install github/gh-stack`. The feature is in public
|
|
11
|
+
preview.
|
|
12
|
+
- If `gh stack` exits 9 (stacks are not enabled on the repository), do not bundle the source issues
|
|
13
|
+
into one pull request. Open one pull request on the default branch for the bottom issue, wait for
|
|
14
|
+
it to merge, then open the next. Say that stacks are unavailable.
|
|
15
|
+
- Workflows that must run on stacked pull requests must not set `pull_request.branches` or
|
|
16
|
+
`branches-ignore`. GitHub evaluates `branches: [main]` against `stack.base.ref`, but
|
|
17
|
+
`gh stack submit` opens mid-stack pull requests before the stack object exists
|
|
18
|
+
([github/gh-stack#425](https://github.com/github/gh-stack/issues/425)), so the filter skips them
|
|
19
|
+
permanently. After a workflow trigger change lands on the default branch, rebase existing stacks
|
|
20
|
+
(`gh stack rebase` or `gh stack sync`) so parent branches include it.
|
|
21
|
+
|
|
22
|
+
## Agent commands
|
|
23
|
+
|
|
24
|
+
Use only non-interactive forms, and run every `gh stack` command without a TTY. Run
|
|
25
|
+
`git config rerere.enabled true` before the first `init`, which otherwise prompts. An explicit
|
|
26
|
+
`checkout` prompts when local and remote compositions differ, and `submit --auto` prompts to
|
|
27
|
+
create ordinary pull requests when stacks are disabled; without a TTY these fail instead, so treat
|
|
28
|
+
a failure as the exit-9 recovery above rather than answering a prompt.
|
|
29
|
+
|
|
30
|
+
- `gh stack init <branch>`, rooted on the default branch only.
|
|
31
|
+
- `gh stack add <branch>`, after the layer cap check in [SKILL.md](../SKILL.md#work-bottom-up).
|
|
32
|
+
- `gh stack checkout <stack-or-pr-number>` imports an existing remote stack. See
|
|
33
|
+
[Import a stack](#import-a-stack-before-acting-on-it).
|
|
34
|
+
- `gh stack submit --auto` creates drafts. Immediately update each new pull request's title and
|
|
35
|
+
body with the repository's pull request description tool; auto titles and bodies are not
|
|
36
|
+
sufficient, and an unstamped body fails the ownership check in [drain.md](drain.md).
|
|
37
|
+
- `gh stack link <branch-or-pr>...` (bottom to top) registers a stack without local tracking. It
|
|
38
|
+
pushes the branches and creates a draft pull request for any branch without one. Update each
|
|
39
|
+
pull request it created the same way as after `submit --auto`.
|
|
40
|
+
- `gh stack view --json` is for acting only. Never use it, or `gh stack bottom`, to decide
|
|
41
|
+
topology, ownership, or bottom-ness.
|
|
42
|
+
- `gh stack rebase`, `gh stack rebase --upstack`, `gh stack rebase --continue`,
|
|
43
|
+
`gh stack rebase --abort`.
|
|
44
|
+
- `gh stack sync` fetches, fast-forwards the trunk, cascade-rebases every layer onto its updated
|
|
45
|
+
parent, and pushes all branches with `--force-with-lease --atomic`. It rewrites every layer's
|
|
46
|
+
head, so treat it like a rebase: stop the poll first, never run it over a queued layer, and
|
|
47
|
+
expect reviewed heads to change. Do not check out the default branch. Run it without a TTY (a
|
|
48
|
+
TTY prompts on local/remote divergence; without one it aborts) and without `--prune`.
|
|
49
|
+
- `gh stack push`.
|
|
50
|
+
- `gh stack up <n>`, `gh stack down <n>`, `gh stack top`, `gh stack bottom`, for movement only.
|
|
51
|
+
- `gh stack merge <pr> --yes --squash`, or the repository's merge strategy. The pull request number
|
|
52
|
+
is required. `--yes` skips a prompt that a non-interactive runner cannot answer.
|
|
53
|
+
- `gh stack unstack [<stack-number>]` (alias `delete`) recovers a mis-rooted stack. With no
|
|
54
|
+
argument it targets the active stack. It unstacks on GitHub and removes local tracking; add
|
|
55
|
+
`--local` to remove only local tracking. Pull requests and branches survive. GitHub leaves
|
|
56
|
+
queued or auto-merge pull requests stacked, and then keeps the stack.
|
|
57
|
+
|
|
58
|
+
Never run the interactive forms: `gh stack submit` without `--auto`, `gh stack modify`, bare
|
|
59
|
+
`gh stack checkout`, `gh stack switch`, or bare `gh stack merge` (a TUI that lands the whole
|
|
60
|
+
stack). `gh stack checkout <branch>` resolves only stacks this worktree already tracks. Do not run
|
|
61
|
+
`gh stack trunk` from a linked worktree whose default branch is checked out elsewhere.
|
|
62
|
+
|
|
63
|
+
## Worktree and scope
|
|
64
|
+
|
|
65
|
+
- One worktree per stack. Move with `up` and `down`. Do not add a worktree per layer:
|
|
66
|
+
`gh stack rebase --upstack` rewrites upper branches, and git refuses to update a branch checked
|
|
67
|
+
out in another worktree.
|
|
68
|
+
- `git diff --name-only origin/<default>...HEAD` lists what lands if this layer and every layer
|
|
69
|
+
below merge.
|
|
70
|
+
- `git diff --name-only <parent>...HEAD` is this layer's review scope.
|
|
71
|
+
|
|
72
|
+
## Import a stack before acting on it
|
|
73
|
+
|
|
74
|
+
`gh stack rebase`, `sync`, `push`, and movement act only on stacks the worktree's local record
|
|
75
|
+
tracks. A stack created from another worktree, session, or machine is not tracked. Before rebasing
|
|
76
|
+
or pushing a layer, including when a shepherd instruction says to, import the stack:
|
|
77
|
+
|
|
78
|
+
1. `gh stack checkout <stack-number>`, with the number from `pulls/<N>.stack.number`. It records
|
|
79
|
+
the stack and checks out the top-most unmerged layer. When the worktree already tracks a
|
|
80
|
+
matching stack it only switches branches, so remote-tracking refs can be stale.
|
|
81
|
+
2. Resolve the remote gh-stack uses once (`remote.pushDefault` when set, else the only remote,
|
|
82
|
+
else `origin`), and read `origin` below as that remote.
|
|
83
|
+
3. gh-stack keeps existing local layer branches as they are, so a stale one makes the next rebase
|
|
84
|
+
start from stale commits. Run `git fetch origin`, then for each unmerged layer branch `<b>` run
|
|
85
|
+
`git rev-list --left-right --count "$b...origin/$b"` (left: local-only commits; right: commits
|
|
86
|
+
only on the pull request head). Branch names may contain shell metacharacters: pass each as a
|
|
87
|
+
quoted variable, never paste it into a command line, and skip names that start with `-`:
|
|
88
|
+
- `0 0`: up to date.
|
|
89
|
+
- `0 N`: fast-forward. Use `git merge --ff-only origin/<b>` on the checked-out layer and
|
|
90
|
+
`git branch -f <b> origin/<b>` on any other.
|
|
91
|
+
- A left count above `0` (ahead or diverged): inspect before rewriting or pushing, as the
|
|
92
|
+
consumer's git procedure describes. Do not open another pull request for the layer.
|
|
93
|
+
|
|
94
|
+
## Submit and verify the remote stack
|
|
95
|
+
|
|
96
|
+
- A pull request's base branch selects its comparison target. Chaining bases alone does not
|
|
97
|
+
register a native stack. `gh stack init` and `add` record a local plan. Neither local tracking
|
|
98
|
+
nor a successful pull request creation proves GitHub registered the stack.
|
|
99
|
+
- Once an upper layer has committed, reviewable work and its local checks pass, submit the layers
|
|
100
|
+
as drafts with `gh stack submit --auto` while the lower pull request is still open and unqueued.
|
|
101
|
+
- Verify remote registration before asking to merge or enqueue the lower pull request. An open
|
|
102
|
+
pull request already in a merge queue cannot join a new stack. If it was queued externally, stop
|
|
103
|
+
registering and report the blocker. Do not dequeue it without authorization or rewrite it. When
|
|
104
|
+
it leaves the queue, re-read it: retry registration if it is still open and unqueued, or recover
|
|
105
|
+
as below if it merged. If it closed without merging, report the broken dependency.
|
|
106
|
+
- Do not wait for upper-layer CI or ready status to register the dependency. Do not create empty
|
|
107
|
+
placeholder layers, or start work held for approval, only to preserve a stack.
|
|
108
|
+
- After each submission or link, read every intended pull request's `pulls/<N>.stack` and the
|
|
109
|
+
single-stack endpoint. Require the same stack number, the intended bottom-to-top order, and the
|
|
110
|
+
expected bases. Missing preview metadata leaves membership unknown: report that, and do not infer
|
|
111
|
+
success from local tracking.
|
|
112
|
+
- If the lower pull request merges before registration, GitHub can reject linking it. Re-read the
|
|
113
|
+
forge, fetch, and rebase the remaining work onto the updated default branch without replaying
|
|
114
|
+
the merged layer. Keep any upper pull request already created. Register several remaining open
|
|
115
|
+
layers as a stack and verify their bases. For a single survivor, read its remote base, retarget
|
|
116
|
+
it to the default branch if needed, and verify that before shepherding it alone: a head rebase
|
|
117
|
+
does not change a base. Report sequential pull requests when no stack registered. Do not recreate
|
|
118
|
+
the merged bottom or chain bases by hand as a substitute.
|
|
119
|
+
|
|
120
|
+
## Lower-layer review fix
|
|
121
|
+
|
|
122
|
+
Check out the layer that owns the change and commit there. Then run `gh stack rebase --upstack`
|
|
123
|
+
and `gh stack push` once. Do not duplicate the fix in an upper layer.
|
|
124
|
+
|
|
125
|
+
## The forge is the only truth
|
|
126
|
+
|
|
127
|
+
Every fact the procedure branches on (topology, layer state, ownership, head SHA) comes from the
|
|
128
|
+
REST or GraphQL API, never from local gh-stack metadata. A local base ref can go stale after a
|
|
129
|
+
remote relink or rebase and silently replay already-landed commits. `gh stack view --json` also
|
|
130
|
+
errors from a worktree whose current branch is not in the stack, which is normal right after a
|
|
131
|
+
merge retargets it.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
gh api "repos/{owner}/{repo}/pulls/<N>" --jq '{stackPresent: has("stack"), stack: .stack}'
|
|
135
|
+
gh api "repos/{owner}/{repo}/stacks/<n>" # layers bottom to top, with head.sha and author
|
|
136
|
+
gh api --paginate "repos/{owner}/{repo}/stacks" --jq '.[] | select(.open)' # state is null
|
|
137
|
+
# and ?state=open is ignored
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- Use the single-stack endpoint for one stack's layers. The list form returns each layer's
|
|
141
|
+
`base.ref` as `null`.
|
|
142
|
+
- `.stack` is a preview field. Its absence is not proof a pull request is unstacked: report "stack
|
|
143
|
+
membership unknown" instead of assuming it is unstacked.
|