87.1% line / 69.1% branch, 502 tests → 88.9% line (2087/2348), 75.4% branch (1011/1340), 546 tests in 76 classes. Measured on main at c6e9a48, after #161–#165.
The entry now explains the branch move rather than just quoting it, because only part of it is new tests:
before
after
change
branches covered
974
1011
+37
branches total
1410
1340
−70
Both are the seam work. Pulling a when out of a lambda inside a collect deletes the coroutine state machine's synthesized branches around it and leaves a plain function whose branches a test can choose. ConversionViewModel$observe$1$1 went from carrying the whole mapping to 6 branches, while the extracted ConversionViewModelKt covers 41 of 42 and JoinViewModelKt38 of 39.
So a seam is worth more than the tests it enables — it also stops the measurement counting scaffolding. And a percentage that rises because the denominator shrank is a different claim from one that rises because more branches are tested. This entry has a documented history of explaining its own movements wrongly, so it now says which is which.
Stacked PRs
A new Conventions entry, from two traps measured on 2026-08-27 while landing #144–#151.
gh pr merge does not work on a stacked PR. It uses the GraphQL mutation, which refuses: "This pull request is part of a stack and must be merged using the asynchronous merge REST API." The plain PUT .../pulls/{n}/merge refuses too. What works:
gh api -X PUT repos/OWNER/REPO/pulls/N/merge-async -f merge_method=merge
# returns a uuid; poll .../merge-async/{uuid} until status is merged or failed
The second trap is worse, because nothing looks wrong. GitHub retargets a stacked PR's base to main when the PR below it merges — but asynchronously. Merging five about thirty seconds apart outran that, so each merged into its own base branch, which had itself already been merged and left behind. Every call returned status: merged. Every PR read MERGED. gh pr list --state open was empty. None of the content was on main.
What caught it was a coverage re-measure reading two points below what the same tree had produced an hour earlier. A fresh git pull changed nothing, which is what turned it from "stale checkout" into a real question. git merge-base --is-ancestor <merge-sha> origin/main answered it in one line, five times. #160 is what the recovery cost.
Also recorded: the auto-retarget belongs to the stacking feature specifically. A PR opened with a plain gh pr create --base some-branch does not retarget when that branch merges — it is left pointing at a dead base and has to be moved by hand, which is what #163 needed.
Docs-only; ktlintCheck and detekt clean.
Two entries, both from work that just landed.
## Coverage
**87.1% line / 69.1% branch, 502 tests → 88.9% line (2087/2348), 75.4% branch (1011/1340), 546 tests in 76 classes.** Measured on `main` at `c6e9a48`, after #161–#165.
The entry now explains the branch move rather than just quoting it, because **only part of it is new tests**:
| | before | after | change |
|---|---|---|---|
| branches covered | 974 | 1011 | **+37** |
| branches total | 1410 | 1340 | **−70** |
Both are the seam work. Pulling a `when` out of a lambda inside a `collect` deletes the coroutine state machine's synthesized branches around it and leaves a plain function whose branches a test can choose. `ConversionViewModel$observe$1$1` went from carrying the whole mapping to **6** branches, while the extracted `ConversionViewModelKt` covers **41 of 42** and `JoinViewModelKt` **38 of 39**.
So a seam is worth more than the tests it enables — it also stops the measurement counting scaffolding. And a percentage that rises because the denominator shrank is a different claim from one that rises because more branches are tested. This entry has a documented history of explaining its own movements wrongly, so it now says which is which.
## Stacked PRs
A new Conventions entry, from two traps measured on 2026-08-27 while landing #144–#151.
**`gh pr merge` does not work on a stacked PR.** It uses the GraphQL mutation, which refuses: *"This pull request is part of a stack and must be merged using the asynchronous merge REST API."* The plain `PUT .../pulls/{n}/merge` refuses too. What works:
```bash
gh api -X PUT repos/OWNER/REPO/pulls/N/merge-async -f merge_method=merge
# returns a uuid; poll .../merge-async/{uuid} until status is merged or failed
```
**The second trap is worse, because nothing looks wrong.** GitHub retargets a stacked PR's base to `main` when the PR below it merges — but asynchronously. Merging five about thirty seconds apart outran that, so each merged into its own base branch, which had itself already been merged and left behind. Every call returned `status: merged`. Every PR read `MERGED`. `gh pr list --state open` was empty. **None of the content was on `main`.**
What caught it was a coverage re-measure reading two points below what the same tree had produced an hour earlier. A fresh `git pull` changed nothing, which is what turned it from "stale checkout" into a real question. `git merge-base --is-ancestor <merge-sha> origin/main` answered it in one line, five times. #160 is what the recovery cost.
Also recorded: **the auto-retarget belongs to the stacking feature specifically.** A PR opened with a plain `gh pr create --base some-branch` does *not* retarget when that branch merges — it is left pointing at a dead base and has to be moved by hand, which is what #163 needed.
Docs-only; `ktlintCheck` and `detekt` clean.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two entries, both from work that just landed.
Coverage
87.1% line / 69.1% branch, 502 tests → 88.9% line (2087/2348), 75.4% branch (1011/1340), 546 tests in 76 classes. Measured on
mainatc6e9a48, after #161–#165.The entry now explains the branch move rather than just quoting it, because only part of it is new tests:
Both are the seam work. Pulling a
whenout of a lambda inside acollectdeletes the coroutine state machine's synthesized branches around it and leaves a plain function whose branches a test can choose.ConversionViewModel$observe$1$1went from carrying the whole mapping to 6 branches, while the extractedConversionViewModelKtcovers 41 of 42 andJoinViewModelKt38 of 39.So a seam is worth more than the tests it enables — it also stops the measurement counting scaffolding. And a percentage that rises because the denominator shrank is a different claim from one that rises because more branches are tested. This entry has a documented history of explaining its own movements wrongly, so it now says which is which.
Stacked PRs
A new Conventions entry, from two traps measured on 2026-08-27 while landing #144–#151.
gh pr mergedoes not work on a stacked PR. It uses the GraphQL mutation, which refuses: "This pull request is part of a stack and must be merged using the asynchronous merge REST API." The plainPUT .../pulls/{n}/mergerefuses too. What works:The second trap is worse, because nothing looks wrong. GitHub retargets a stacked PR's base to
mainwhen the PR below it merges — but asynchronously. Merging five about thirty seconds apart outran that, so each merged into its own base branch, which had itself already been merged and left behind. Every call returnedstatus: merged. Every PR readMERGED.gh pr list --state openwas empty. None of the content was onmain.What caught it was a coverage re-measure reading two points below what the same tree had produced an hour earlier. A fresh
git pullchanged nothing, which is what turned it from "stale checkout" into a real question.git merge-base --is-ancestor <merge-sha> origin/mainanswered it in one line, five times. #160 is what the recovery cost.Also recorded: the auto-retarget belongs to the stacking feature specifically. A PR opened with a plain
gh pr create --base some-branchdoes not retarget when that branch merges — it is left pointing at a dead base and has to be moved by hand, which is what #163 needed.Docs-only;
ktlintCheckanddetektclean.