David’s design feedback on the V3 pricing page landed mid-morning on April 13. The card structure was too dense, checkmarks were missing, the typography did not match the rest of the product, and checkout-bar behavior on mobile was undefined. The list was longer than a cosmetic pass could fix.
I had a choice. Keep iterating on the existing V3 branch, which already had a week of work in it, or look at what that branch was actually doing to the codebase.
I looked.
the prototype had been building up debt
The V3 packages and events pricing feature had been built inside shared code paths. Org-specific behavior, the logic that only applies when a team-org account navigates the purchase flow, was accumulating inside the same conditionals that handle legacy tournament purchases. Not by design. It just happened. The model generated diffs, I reviewed them, neither of us stopped to ask where new behavior should live.
The risk was not hypothetical. Legacy tournament checkouts are live customer flows. A regression there is not a layout glitch. It is a broken purchase for a paying customer. The prototype code was not dangerous on its own, but it made the next iteration dangerous. Every prompt refining the org pricing UI was one more delta applied to entangled paths.
I saved the branch. Then I closed it and started over.
one boundary stopped the leakage
The restart had one deliberate step before any UI work. I introduced explicit *_TournamentOrg methods gated on pageHQ.orgname. The rule was simple. A session with an orgname gets the org path. Everything else gets the legacy path. The two paths do not share conditionals.
That boundary changed the character of every iteration that followed. Card padding, checkmark rendering, typography alignment, mobile overflow, checkout bar structure, CTA states across multiple breakpoints. The model produced diffs. The diffs landed inside the org-specific methods. The legacy tournament path was structurally unreachable from them. The blast radius was defined.
None of those iterations were risky. That is the whole point.
what the release actually required
The commits from the second half of that day tell a story that the phrase “UI iteration” does not. Compile assets. Restore legacy event headings that V3 had quietly clobbered. Re-enable nav links disabled during the experiment. Add auto-redirect logic for child events so they do not strand navigating users. Fix mobile overflow across both the hto and hto2 clones.
Each item on that list was a consequence of how long the prototype had been sitting inside shared paths before the restart. The longer entangled code sits, the more of this cleanup waits at the other end.
The model helped with all of it. It also introduced two of those surprises by not catching that the legacy heading state was load-bearing. That is not a complaint. Noticing what the model misses is the job.
the sequence worth stealing
I have done a version of this more than once. A prototype accumulates. It starts to feel expensive to redo. Outside feedback, a code review, a failed test, a list from a designer, makes the scoping problem visible for the first time. The temptation is to patch around it.
The cheaper move. Save the broken branch as a reference, cut clean from the last known-good point, define the method boundary before writing any new UI, then iterate hard inside it.
AI makes it cheap to generate UI deltas. It does not make mixed-scope code safer. The model will iterate wherever you point it. The question of where the experiment is allowed to live is yours to answer first.