Follow-up to PR #46 / issue #44 — the last piece that makes v0.10.0 actually usable.
What broke
Every production load of / tripped a React 19 hydration mismatch (#418). In the common race window, the floating TeamBuilder on the default (SSR'd) WORLD MAP tab committed stale props: its DISPATCH button stayed disabled=true permanently — in the very render that printed // LEAD and WILL TAKE N TURN(S) (i.e. blocked === null, leadReason === null). The jump flow was unusable for real users, and CI's two jump tests (the only ones driving that builder on the default tab) timed out — the rest of the suite switches tabs first and passed, which masked it.
Root cause
Next 16 prerenders / statically (build time, s-maxage=31536000), so the SSR HTML carried the build-time wall-clock string while the client rendered the current time. That text mismatch fired #418 on every load; the in-place hydration recovery then raced the 1s setInterval tick and the world/crew fetch setStates, and the builder committed the stale props.
The fix
Hydration-safe banner clock in components/mission-control.tsx: a hydrated state (flipped in a mount useEffect) makes the clock render '' in both SSR and the first client render — no mismatch, no #418, no race. The existing 1s tick keeps the clock moving afterwards, and the builder commits disabled=false as designed. No test changes — the tests are correct; the jump specs go green on CI's e2e against the production build.
Why v0.10.1
One-line behavioural fix on top of v0.10.0, shipped as a patch release (version bump in package.json + CHANGELOG entry). The branch also carries a small docs commit committing the nextjs-agent-rules block that next dev appends to AGENTS.md.
Follow-up to PR #46 / issue #44 — the last piece that makes v0.10.0 actually usable.
## What broke
Every production load of `/` tripped a React 19 hydration mismatch (#418). In the common race window, the floating `TeamBuilder` on the default (SSR'd) WORLD MAP tab committed stale props: its DISPATCH button stayed `disabled=true` permanently — in the very render that printed `// LEAD` and `WILL TAKE N TURN(S)` (i.e. `blocked === null`, `leadReason === null`). The jump flow was unusable for real users, and CI's two jump tests (the only ones driving that builder on the default tab) timed out — the rest of the suite switches tabs first and passed, which masked it.
## Root cause
Next 16 prerenders `/` statically (build time, `s-maxage=31536000`), so the SSR HTML carried the build-time wall-clock string while the client rendered the current time. That text mismatch fired #418 on **every** load; the in-place hydration recovery then raced the 1s `setInterval` tick and the world/crew fetch `setState`s, and the builder committed the stale props.
## The fix
Hydration-safe banner clock in `components/mission-control.tsx`: a `hydrated` state (flipped in a mount `useEffect`) makes the clock render `''` in both SSR and the first client render — no mismatch, no #418, no race. The existing 1s tick keeps the clock moving afterwards, and the builder commits `disabled=false` as designed. No test changes — the tests are correct; the jump specs go green on CI's e2e against the production build.
## Why v0.10.1
One-line behavioural fix on top of v0.10.0, shipped as a patch release (version bump in `package.json` + CHANGELOG entry). The branch also carries a small docs commit committing the `nextjs-agent-rules` block that `next dev` appends to `AGENTS.md`.
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.
Follow-up to PR #46 / issue #44 — the last piece that makes v0.10.0 actually usable.
What broke
Every production load of
/tripped a React 19 hydration mismatch (#418). In the common race window, the floatingTeamBuilderon the default (SSR'd) WORLD MAP tab committed stale props: its DISPATCH button stayeddisabled=truepermanently — in the very render that printed// LEADandWILL TAKE N TURN(S)(i.e.blocked === null,leadReason === null). The jump flow was unusable for real users, and CI's two jump tests (the only ones driving that builder on the default tab) timed out — the rest of the suite switches tabs first and passed, which masked it.Root cause
Next 16 prerenders
/statically (build time,s-maxage=31536000), so the SSR HTML carried the build-time wall-clock string while the client rendered the current time. That text mismatch fired #418 on every load; the in-place hydration recovery then raced the 1ssetIntervaltick and the world/crew fetchsetStates, and the builder committed the stale props.The fix
Hydration-safe banner clock in
components/mission-control.tsx: ahydratedstate (flipped in a mountuseEffect) makes the clock render''in both SSR and the first client render — no mismatch, no #418, no race. The existing 1s tick keeps the clock moving afterwards, and the builder commitsdisabled=falseas designed. No test changes — the tests are correct; the jump specs go green on CI's e2e against the production build.Why v0.10.1
One-line behavioural fix on top of v0.10.0, shipped as a patch release (version bump in
package.json+ CHANGELOG entry). The branch also carries a small docs commit committing thenextjs-agent-rulesblock thatnext devappends toAGENTS.md.