A nursery for the pyramid
Ask anyone who's stuck with one of these games for a decade why they keep loading the same save, and it's rarely the trophy. It's the sixteen-year-old. The one who turned up in an intake you almost didn't read, played badly for two seasons, and then didn't.
A club you only ever buy players for is a rental agreement. So: the academy.
What landed is the whole foundation rather than a screen — intake flows, squad registration, U21 competitions, and the eligibility rules that everything else has to respect. It runs across the API, the shared contracts, the game UI, admin, and the Go workers, because a youth setup that only exists in one of those places is a demo.
The decision I'd defend hardest is that youth got real competitions from day one — a U21 league and a U21 cup — instead of a list of prospects with ages next to them. A list teaches you nothing. You find out whether a kid is worth a senior shirt by watching him get minutes against other kids, and that only exists if there are fixtures. Same reason the cup mattered in the first place: a competition is a machine for generating opinions about your own players.
Registration was the fiddly part. A parent-club manager needs to see enough of the academy to register players and pick a youth side, without senior and youth collapsing into one big undifferentiated squad bag where you accidentally name a seventeen-year-old in a relegation six-pointer because he sorted well by form. Two squads, one manager, clear boundaries. Eligibility gets checked where lineups are actually built, so tactics knows about it too.
The same change finished the Nest houseclean, which is why it's a big diff. Nest's game-clock surface is now read, preview, and sync, plus admin helpers that enqueue and preview — not a parallel set of lifecycle executors sitting alongside Go's. The last duplicate tick and domain paths are out. Youth cup bracket generation follows the enqueue-and-poll pattern: admin asks for it, Go does it, the UI waits. It would have been quicker to reimplement bracket logic on the API side for this one case. It would also have been the first step back toward two runtimes with opinions.
Mixing product and architecture in one PR isn't something I'd normally recommend. Here it was the right call, because shipping an academy on top of leftover tick residue would have meant untangling both later, and the realism work I want next is exactly the kind of thing that goes wrong twice if the clock runs twice.
Which is where this goes next. Birth ceilings, bloom, intake potential anchored to the division a club is actually in — growth rules that are meaningless until there are academy players in the world and U21 minutes for them to grow into. There are now.