2026-07-25

Sprint 10 Closes: My Beers Ships, and a Merge-Day Lesson in What 'Independent Branches' Actually Means

Sprint 9 closed with a promise: once the confirmation flow was rebuilt around serving formats and batch confirms, the sprint waiting behind it — a real home for ratings, a want list, personal stats — could finally get built on solid ground instead of a foundation that was still being poured. That sprint is done: six issues, six pull requests, three independent stacked pairs, and a genuinely useful lesson about what "independent" does and doesn't mean once merge day actually arrives.

A rating that doesn't care what glass it came in

The confirmation model now tracks serving format — the same beer confirmed as a draft and again as a can is two rows, two separate credits toward two hundred. Ratings don't work that way, and shouldn't. A rating is an opinion about the beer, not about the pour, so it stays keyed on the beer alone. That means a beer confirmed in three formats shows the same rating on all three rows in the progress feed — which, read cold, looks exactly like a bug. It isn't one; it's the one place in this sprint where the format model deliberately doesn't apply, and the only way to keep a future reader (including a future me) from "fixing" it is to say so directly in the code, not just imply it by omission.

One row per beer, not one row per pour

That same asymmetry shows up on the new My Beers screen. The confirmation feed now hands over multiple rows for a beer confirmed in more than one format, and the screen's job is to turn that back into what a customer actually wants to see: one beer, one row, its formats listed together ("Draft, Can"), sorted by whichever date is most recent. Rendering the raw feed unchanged would have meant the same beer showing up twice with an identical name and a different tag — technically accurate, and exactly the kind of "accurate but useless" result that makes a customer stop trusting the screen.

The want list has to survive a whole round, not just one confirm

The want list's real test isn't adding a beer to it — it's what happens when that beer gets confirmed as part of a five-beer round, alongside four beers that were never on the list at all. The auto-resolve logic hooks into the same shared write path both the single-confirm and batch-confirm endpoints already use, so a want gets satisfied no matter which door the confirmation came through, and a batch with only one wanted beer in it doesn't accidentally clear the other four.

Building the "you got it!" acknowledgment on top of that surfaced something worth naming: the batch endpoint that Sprint 9 shipped never needed to say whether an item was want-listed, because the want list didn't exist yet. Building the screen that needed that flag meant going back into an endpoint that had already shipped, verified, and closed out — a small, honest reminder that "done" for one sprint is scoped to what that sprint actually needed, not to everything a later sprint will turn out to want from the same code.

Counting the same confirmation two different ways in the same query

The personal stats page needed one detail gotten right or the whole thing would quietly lie: a progress-over-time chart should count every confirmation, formats included, because that's what actually moves the number toward two hundred. But a "styles explored" breakdown has to count beers, not confirmations — otherwise a customer who's had one IPA in three formats looks like they've explored three times the variety they actually have. Same underlying rows, two different aggregations, and getting the second one wrong wouldn't throw an error, it would just make the chart subtly overstate how adventurous someone's actually been.

Three branches that had never touched each other's code

This sprint split cleanly into three independent pairs — ratings, want list, stats — each with its own API issue and its own screen, and I built and merged them as six separate pull requests rather than one combined one, the same discipline Sprint 9 used. Two of those three pairs, it turned out, still collided at merge time. Not because the actual features conflicted with each other — a rating field and a want-list endpoint have nothing to do with each other — but because both pairs happened to add a new test to the exact same spot at the bottom of the exact same test file, and two of the three screens both needed to add their own new link to the same shared account page. Git can't tell "these two people are adding unrelated things next to each other" from "these two people are fighting over the same line"; it just sees two changes claiming the same spot and stops to ask a human. Each conflict got resolved the same way: pull the already-merged work into the branch that hadn't landed yet, keep both sides' additions, then re-run the full test suite and a production build before calling it done — not just trusting that a clean merge meant nothing had actually broken.

The PM angle

"Independent" is doing real work in "three independent pairs of issues," and it's worth being precise about what it does and doesn't guarantee. It meant the three pairs could be built, reviewed, and reasoned about without knowing anything about each other — no shared logic, no sequencing dependency, nothing that had to happen in a particular order. It never meant they'd merge without touching the same file. Those are two different kinds of independence, and treating the first as proof of the second is exactly how a team ships three "unrelated" branches and gets surprised by a conflict on merge day. The fix isn't to avoid parallel work — it's to expect the collision at the seams, and to verify the result again once it's resolved instead of assuming a clean git merge means nothing changed.

Where the project stands

Six issues (#95–#100), six pull requests (#118–#123), merged in dependency order onto master. Backend suite: 391 passing. Frontend suite: 250 passing. Clean production build. The want-list auto-resolve, both single and batch, and the stats endpoint's numbers were all verified live against a real Postgres database before any of it shipped, not just trusted from the test suite. Next up: Sprint 11, the push-notification infrastructure that the rest of this epic — badges, automated notifications, the owner's composer, want-list "it's on tap" alerts — has been waiting on.

Comments

Loading comments...