|
| 1 | +--- |
| 2 | +mode: agent |
| 3 | +description: Propagate post-meeting changes through all draft and alpha branches. |
| 4 | +--- |
| 5 | + |
| 6 | +# Post-meeting: propagate changes through draft & alpha branches |
| 7 | + |
| 8 | +You are propagating the changes merged into the current "starting" draft branch (after a TC49-TG2 committee meeting) forward through every future draft and alpha branch. See `admin/branch-diagram.md` for the rationale. |
| 9 | + |
| 10 | +## Assumptions |
| 11 | + |
| 12 | +- The committee secretary has already merged all approved PRs into the starting branch (default: `draft-v8`). Do **not** merge any other open PRs. |
| 13 | +- The `.github/workflows/update-on-merge.yaml` workflow will open an automated PR titled "Automated Section renumber and grammar extraction" on each branch that receives a push. These auto-PRs **must be merged** before the next propagation hop. |
| 14 | +- You have `git` and `gh` available, and push permission to this repo. |
| 15 | + |
| 16 | +## Propagation chain |
| 17 | + |
| 18 | +Walk these branches in order. Each step merges the previous branch into the next with a regular merge commit and pushes. |
| 19 | + |
| 20 | +1. `draft-v8` (starting branch — no merge in; just merge its auto-PR) |
| 21 | +2. `draft-v9` ← merges `draft-v8` |
| 22 | +3. `v9-alpha` ← merges `draft-v9` |
| 23 | +4. `draft-v10` ← merges `v9-alpha` |
| 24 | +5. `v10-alpha` ← merges `draft-v10` |
| 25 | +6. `draft-v11` ← merges `v10-alpha` |
| 26 | +7. `v11-alpha` ← merges `draft-v11` |
| 27 | +8. `draft-v12` ← merges `v11-alpha` |
| 28 | + |
| 29 | +> When new version branches are added (v12-alpha, draft-v13, etc.), append |
| 30 | +> them here in the same pattern: each `draft-v(N+1)` merges `vN-alpha`, and |
| 31 | +> each `vN-alpha` merges `draft-vN`. Also add the new branches to |
| 32 | +> `.github/workflows/update-on-merge.yaml` `on.push.branches`. |
| 33 | +
|
| 34 | +If the user names a different starting branch, start there and propagate to |
| 35 | +every later branch in the list. |
| 36 | + |
| 37 | +## Pre-flight (run once, before walking the chain) |
| 38 | + |
| 39 | +These artifacts are referenced by Step B (conflict resolution) and Step B.6 |
| 40 | +(future-version comment inventory). Capture them up front and persist them |
| 41 | +for the duration of the run. |
| 42 | + |
| 43 | +1. **Baseline.** Determine the SHA on each branch in the chain at the |
| 44 | + *previous* propagation. A reliable proxy is the most recent merge commit whose subject begins with `Post-meeting propagation:` on that branch (`git log --grep '^Post-meeting propagation:' -1 --format=%H origin/<branch>`). Record `BASE_<branch>` for each branch. If a branch has no such commit yet, fall back to the branch point and warn the user. |
| 45 | + |
| 46 | +2. **Deletion inventory** for the starting branch. Identify text the |
| 47 | + committee removed in this cycle so Step B can recognize resurrection: |
| 48 | + |
| 49 | + ```bash |
| 50 | + # Files where lines were removed since the previous propagation: |
| 51 | + git log "$BASE_<starting>"..origin/<starting> --diff-filter=MD \ |
| 52 | + --name-only --pretty=format: -- standard/ | sort -u |
| 53 | + |
| 54 | + # Hunks (negative lines) for review: |
| 55 | + git log "$BASE_<starting>"..origin/<starting> -p -- standard/ \ |
| 56 | + > /tmp/starting-deletions.patch |
| 57 | + ``` |
| 58 | + |
| 59 | + Show the user the list of PRs merged this cycle (`gh pr list --base <starting> --state merged --search 'merged:>=<last-meeting-date>'`) and ask which performed substantive prose removals. Persist that list. |
| 60 | + |
| 61 | +3. **vNext-comment baseline** for every branch in the chain. Snapshot the current set of HTML comments in `standard/*.md` mentioning a future version, so Step B.6 can diff against it after each merge: |
| 62 | + |
| 63 | + ```bash |
| 64 | + for b in <chain>; do |
| 65 | + git --no-pager grep -nE '<!--[^>]*(vNext|v[0-9]+|future|upcoming|TODO)' \ |
| 66 | + "origin/$b" -- 'standard/*.md' > /tmp/vnext-baseline-$b.txt || true |
| 67 | + done |
| 68 | + ``` |
| 69 | + |
| 70 | + The grep is intentionally loose (false positives are fine — Phase 4 surfaces them for human triage; nothing is auto-applied). |
| 71 | + |
| 72 | +## Procedure |
| 73 | + |
| 74 | +Before starting, confirm the chain with the user and show which branches will be touched. Confirm the pre-flight artifacts above are captured. Then for each branch in order: |
| 75 | + |
| 76 | +### Step A — Process auto-PR on the current branch |
| 77 | + |
| 78 | +1. `git fetch --all --prune` |
| 79 | +2. `git checkout <branch>` and `git pull --ff-only` |
| 80 | +3. Find the auto-PR opened by `update-on-merge.yaml`: |
| 81 | + |
| 82 | + ```bash |
| 83 | + gh pr list --base <branch> --state open \ |
| 84 | + --search 'in:title "Automated Section renumber and grammar extraction"' \ |
| 85 | + --json number,headRefName,mergeable,mergeStateStatus |
| 86 | + ``` |
| 87 | + |
| 88 | +4. If found: |
| 89 | + - Wait until checks pass (`gh pr checks <num> --watch` is acceptable, with a reasonable timeout — if it doesn't go green within a few minutes, stop and ask the user). |
| 90 | + - The auto-PR's checks include the `StandardAnchorTags` job. If that job reports any `TOC002` ("`<ref>` not found") diagnostic, **stop** even if `gh pr checks` reports the PR overall as mergeable — broken cross-references must be resolved before merging. |
| 91 | + - Merge it with a **merge commit**: `gh pr merge <num> --merge --delete-branch`. |
| 92 | + - `git pull --ff-only` on the branch. |
| 93 | +5. If not found and this is the starting branch, ask the user whether to wait, run the tools locally (`tools/run-smarten.sh`, `tools/run-section-renumber.sh`), or proceed without them. Do not run tools locally without explicit consent. |
| 94 | +6. If not found on a downstream branch (it should appear after the merge in step B below), continue. |
| 95 | + |
| 96 | +### Step B — Merge from previous branch (skip on the starting branch) |
| 97 | + |
| 98 | +1. Still on `<branch>`, run: |
| 99 | + |
| 100 | + ```bash |
| 101 | + git merge --no-ff origin/<previous-branch> \ |
| 102 | + -m "Post-meeting propagation: merge <previous-branch> into <branch>" |
| 103 | + ``` |
| 104 | + |
| 105 | +2. **Conflicts:** |
| 106 | + - **Never blanket "take upstream"** on a conflict whose hunks touch |
| 107 | + prose in `standard/*.md`. Doing so can silently resurrect text the |
| 108 | + committee deleted on the downstream branch in this cycle or a prior |
| 109 | + one. |
| 110 | + - For each conflicted hunk in `standard/*.md`: |
| 111 | + a. Cross-check the hunk's file and line range against the deletion inventory captured in Pre-flight (`/tmp/starting-deletions.patch`) **and** against any prior `Post-meeting propagation:` merges on the downstream branch (`git log --grep '^Post-meeting propagation:' -p origin/<branch> -- <file>`). |
| 112 | + b. If the downstream side intentionally removed the text, keep the deletion and re-apply only non-overlapping upstream edits to the surrounding region. |
| 113 | + c. If unclear, **abort the merge** (`git merge --abort`) and report to the user with the file, line range, and both sides of the hunk. |
| 114 | + - Mechanical "take upstream" is acceptable **only** for: |
| 115 | + - regenerated `standard/grammar.md`, |
| 116 | + - TOC blocks below the `<!-- The remaining text is generated by a tool. Do not hand edit -->`marker, |
| 117 | + - the generated TOC in `standard/README.md`. |
| 118 | + - For any conflict in `tools/`, `.github/`, or any prose conflict you are not 100% sure is mechanical: **abort the merge** and stop. |
| 119 | +3. After conflicts are resolved (or if the merge was clean), **do not push yet**. Run Steps B.5 and B.6 below first. |
| 120 | + |
| 121 | +### Step B.5 — Cross-reference validation |
| 122 | + |
| 123 | +Run the section-renumber tool in dry-run mode against the post-merge working tree to surface broken or drifted cross-references *before* pushing: |
| 124 | + |
| 125 | +```bash |
| 126 | +( cd tools && dotnet run --project StandardAnchorTags -- \ |
| 127 | + --owner dotnet --repo csharpstandard --dryrun ) |
| 128 | +``` |
| 129 | + |
| 130 | +1. **Broken references.** Any `TOC002` ("`<ref>` not found") diagnostic is a **hard stop**. Reset the merge commit (`git reset --hard origin/<branch>`), report the failing references to the user, and do not push. |
| 131 | +2. **Concept drift.** Count how many section numbers the dry run would change (lines beginning with `§` in the tool's diff output). If more than ~25 sections shift, sections have drifted enough that surviving cross-references like `§X.Y (Foo)` may now point at a different concept — the renumber tool fixes the *number* but cannot detect when the *concept* (parenthetical name, surrounding prose) is now wrong. Pause, list the affected references to the user, and proceed only on explicit confirmation. |
| 132 | +3. The actual renumber/grammar regeneration runs in the auto-PR opened by `update-on-merge.yaml` after push (Step A on the next iteration); do not commit dry-run output. |
| 133 | + |
| 134 | +### Step B.6 — Future-version comment inventory |
| 135 | + |
| 136 | +Diff the current branch's HTML comments mentioning future versions |
| 137 | +against the Pre-flight baseline to surface anything new this propagation brought in (these are notes the committee left for upcoming versions and need to be routed to the appropriate feature PRs by `post-meeting-rebase-prs.prompt.md`): |
| 138 | + |
| 139 | +```bash |
| 140 | +git --no-pager grep -nE '<!--[^>]*(vNext|v[0-9]+|future|upcoming|TODO)' \ |
| 141 | + HEAD -- 'standard/*.md' > /tmp/vnext-current-<branch>.txt |
| 142 | +diff /tmp/vnext-baseline-<branch>.txt /tmp/vnext-current-<branch>.txt \ |
| 143 | + > /tmp/vnext-delta-<branch>.txt || true |
| 144 | +``` |
| 145 | + |
| 146 | +For each *new* comment in the delta, record: |
| 147 | + |
| 148 | +- file path and line number, |
| 149 | +- full comment text, |
| 150 | +- branch where it appeared (`<branch>`), |
| 151 | +- best-guess target version parsed from the comment (e.g. `v10` from `<!-- v10: tighten wording -->`); leave blank if not parseable. |
| 152 | + |
| 153 | +Persist the accumulated list across the whole run. Include it in the final report so `post-meeting-rebase-prs.prompt.md` can consume it. **Do not edit `standard/*.md` to remove or apply these comments.** |
| 154 | + |
| 155 | +### Step B.7 — Push |
| 156 | + |
| 157 | +1. Push: `git push origin <branch>`. |
| 158 | +2. The push triggers `update-on-merge.yaml`, which will open a fresh auto-PR. Loop back to Step A for this branch before moving on. |
| 159 | + |
| 160 | +### Step C — Move to the next branch |
| 161 | + |
| 162 | +Repeat A–B for the next branch in the chain. Continue until the chain is done. |
| 163 | + |
| 164 | +## Reporting |
| 165 | + |
| 166 | +When finished (or when stopped on a conflict), produce a short report: |
| 167 | + |
| 168 | +- For each branch: action taken (auto-PR merged, propagation merge SHA, skipped). |
| 169 | +- Any branches where you stopped and why. |
| 170 | +- The deletion inventory captured in Pre-flight (file list + originating PR numbers). |
| 171 | +- The accumulated future-version comment inventory from Step B.6 (file:line, comment text, source branch, best-guess target version). Hand this to `post-meeting-rebase-prs.prompt.md`. |
| 172 | +- A reminder to the user to run `post-meeting-rebase-prs.prompt.md` next. |
| 173 | + |
| 174 | +## Safety rules |
| 175 | + |
| 176 | +- Never force-push to any `draft-v*` or `v*-alpha` branch. |
| 177 | +- Never use `git reset --hard` on a tracked branch. |
| 178 | +- Never merge any PR other than the automated renumber/grammar PR. |
| 179 | +- If `gh` shows the auto-PR's checks failing, stop and ask the user. |
0 commit comments