Restore the five stacked PRs that merged into their bases instead of main #160

Merged
JMR-dev merged 19 commits from fix/restore-stack-merges into main 2026-08-29 14:09:46 +00:00
JMR-dev commented 2026-08-27 14:02:10 +00:00 (Migrated from github.com)

#145, #146, #147, #148 and #150 all report MERGED, and none of their content reached main.

They merged into their stack base branches:

PR merged into should have been
#145 test/outputpublisher-seams main
#146 test/readspec-enum-fallbacks main
#147 test/container-capabilities-audio main
#148 test/concatworker-failure-arms main
#150 test/refused-jobs main

What happened

GitHub retargets a stacked PR's base to main when the PR below it merges — verified earlier in this batch, when #144 merged and #149's base flipped from test/fake-provider-scaffolding to main on its own. That retarget is asynchronous.

These five were merged by an automated chain-merger firing them ~30 seconds apart, which is faster than the retarget settles. Each one still pointed at a base branch that had itself already been merged and left behind. Every call returned status: merged, and every one was true — into the wrong branch.

How it was caught

Not by anything that looked like an error. Every PR showed MERGED, the chain-merger reported CHAIN COMPLETE, and gh pr list --state open came back empty.

It was caught by re-measuring coverage on main and getting a number two points lower than the same tree had measured an hour earlier — 85.1% / 66.3% against the 87.1% / 69.1% the chain top had produced, and 470 tests against 502. The first assumption was a stale local main; a fresh git pull changed nothing, which is what turned it into a real question.

git merge-base --is-ancestor <merge-sha> origin/main then answered it in one line, five times: NOT on main.

What this restores

Nothing was lost. The branches had been chained by merging each into the next, so test/mediaprobe-track-seam at 79cca0e still held the whole chain. This merges that.

file what
MediaProbe.kt the #150 track-walk seam — main source, not just tests
MediaProbeTrackWalkTest.kt 11 tests, absent from main entirely
RefusedJobTest.kt 7 tests, absent from main entirely
ContainerCapabilitiesTest.kt the audio half of validate
WorkerEnumFallbackTest.kt readSpec's three enum fallbacks
WorkerCancellationTest.kt, DeniedForegroundStartTest.kt the join-side cancellation and give-up arms
WorkerStubs.kt FailedFuture, shared by the two above

Merged clean, no conflicts.

Verification

On this branch, matching what the chain top measured before any of it merged:

  • 502 tests in 71 classes, 0 failures (main today: 470 in 69)
  • 87.1% line (2025/2324), 69.1% branch (974/1410) (main today: 85.1% / 66.3%)
  • Gate green: assembleDebug, testDebugUnitTest, compileDebugAndroidTestKotlin, ktlintCheck, detekt, lintDebug

The second commit updates CLAUDE.md's coverage entry, deliberately in this PR rather than a separate one: those figures only become true of main when this merges.

The lesson worth keeping

With GitHub's stacked PRs, status: merged is not evidence the work is on main. Confirm the merge commit is an ancestor of main before believing it. Merging a stack fast enough to outrun the retarget is the specific way it goes wrong, so either merge one at a time and re-read baseRefName between, or check afterwards — this PR is what the "afterwards" costs.

**#145, #146, #147, #148 and #150 all report `MERGED`, and none of their content reached `main`.** They merged into their *stack base branches*: | PR | merged into | should have been | |---|---|---| | #145 | `test/outputpublisher-seams` | `main` | | #146 | `test/readspec-enum-fallbacks` | `main` | | #147 | `test/container-capabilities-audio` | `main` | | #148 | `test/concatworker-failure-arms` | `main` | | #150 | `test/refused-jobs` | `main` | ## What happened GitHub retargets a stacked PR's base to `main` when the PR below it merges — verified earlier in this batch, when #144 merged and #149's base flipped from `test/fake-provider-scaffolding` to `main` on its own. **That retarget is asynchronous.** These five were merged by an automated chain-merger firing them ~30 seconds apart, which is faster than the retarget settles. Each one still pointed at a base branch that had itself already been merged and left behind. Every call returned `status: merged`, and every one was true — into the wrong branch. ## How it was caught Not by anything that looked like an error. Every PR showed `MERGED`, the chain-merger reported `CHAIN COMPLETE`, and `gh pr list --state open` came back empty. It was caught by **re-measuring coverage on `main` and getting a number two points lower than the same tree had measured an hour earlier** — 85.1% / 66.3% against the 87.1% / 69.1% the chain top had produced, and 470 tests against 502. The first assumption was a stale local `main`; a fresh `git pull` changed nothing, which is what turned it into a real question. `git merge-base --is-ancestor <merge-sha> origin/main` then answered it in one line, five times: `NOT on main`. ## What this restores Nothing was lost. The branches had been chained by merging each into the next, so `test/mediaprobe-track-seam` at `79cca0e` still held the whole chain. This merges that. | file | what | |---|---| | `MediaProbe.kt` | the #150 track-walk seam — **main source**, not just tests | | `MediaProbeTrackWalkTest.kt` | 11 tests, absent from `main` entirely | | `RefusedJobTest.kt` | 7 tests, absent from `main` entirely | | `ContainerCapabilitiesTest.kt` | the audio half of `validate` | | `WorkerEnumFallbackTest.kt` | `readSpec`'s three enum fallbacks | | `WorkerCancellationTest.kt`, `DeniedForegroundStartTest.kt` | the join-side cancellation and give-up arms | | `WorkerStubs.kt` | `FailedFuture`, shared by the two above | Merged clean, no conflicts. ## Verification On this branch, matching what the chain top measured before any of it merged: - **502 tests in 71 classes, 0 failures** (`main` today: 470 in 69) - **87.1% line (2025/2324), 69.1% branch (974/1410)** (`main` today: 85.1% / 66.3%) - Gate green: `assembleDebug`, `testDebugUnitTest`, `compileDebugAndroidTestKotlin`, `ktlintCheck`, `detekt`, `lintDebug` The second commit updates `CLAUDE.md`'s coverage entry, deliberately in this PR rather than a separate one: those figures only become true of `main` when this merges. ## The lesson worth keeping **With GitHub's stacked PRs, `status: merged` is not evidence the work is on `main`.** Confirm the merge commit is an ancestor of `main` before believing it. Merging a stack fast enough to outrun the retarget is the specific way it goes wrong, so either merge one at a time and re-read `baseRefName` between, or check afterwards — this PR is what the "afterwards" costs.
Sign in to join this conversation.