From 19936235482d5c5af814d6f7ba340cb5703991da Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Sat, 3 Oct 2026 18:36:15 +0000 Subject: [PATCH 1/4] docs(agents): next.js agent rules block (added by next dev) --- AGENTS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 951bd15..fa30619 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,3 +19,13 @@ ## Other 1. For longer terminal tasks you should use pty_* tools. + + + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + -- 2.54.0 From f1633eb518ef5b0fc674855b74ce407de5716eaf Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Sat, 3 Oct 2026 18:36:19 +0000 Subject: [PATCH 2/4] =?UTF-8?q?fix(ui):=20hydration-safe=20banner=20clock?= =?UTF-8?q?=20=E2=80=94=20no=20build-time=20clock=20in=20the=20prerendered?= =?UTF-8?q?=20banner=20(#44,=20v0.10.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/mission-control.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/components/mission-control.tsx b/components/mission-control.tsx index d45cfba..03e874e 100644 --- a/components/mission-control.tsx +++ b/components/mission-control.tsx @@ -63,6 +63,9 @@ export function MissionControl() { const [activeTab, setActiveTab] = useState(null) // #38 — admin DB CRUD overlay, opened from the header. const [adminOpen, setAdminOpen] = useState(false) + // #44 (v0.10.1) — true only after hydration: the banner clock must render '' in both SSR and the + // first client render, otherwise the prerendered (build-time) string desyncs at hydration. + const [hydrated, setHydrated] = useState(false) // #44 — the four mount fetches, extracted into a callback so the NEXT TURN button (5b) can // re-run them after /api/turn: a tick can change all four snapshots (the turn always; inventory @@ -120,6 +123,9 @@ export function MissionControl() { return () => clearInterval(id) }, []) + // #44 (v0.10.1) — flip after hydration so the banner clock can start (SSR/first render both ''). + useEffect(() => setHydrated(true), []) + // #27 — restore the persisted tab once on mount (validated against TAB_IDS). useEffect(() => { const stored = window.localStorage.getItem(ACTIVE_TAB_KEY) @@ -139,7 +145,9 @@ export function MissionControl() { .catch(() => {}) }, []) - const timeStr = new Date().toLocaleTimeString('en-GB', { hour12: false }) + // #44 (v0.10.1) — hydration-safe: '' until hydrated (SSR and first client render agree), then the + // live time on the 1s tick — no more build-time clock baked into the prerendered HTML. + const timeStr = hydrated ? new Date().toLocaleTimeString('en-GB', { hour12: false }) : '' // Slugs of the researched techs — drives the effective caps + build gates in the SHIP SYSTEMS // tab via the same pure helpers the API enforces (lib/game/tech.ts). -- 2.54.0 From 8f018a6ee9234b745f9f5b6c84963ae98b5bac91 Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Sat, 3 Oct 2026 18:36:40 +0000 Subject: [PATCH 3/4] =?UTF-8?q?chore(release):=20v0.10.1=20=E2=80=94=20hyd?= =?UTF-8?q?ration-safe=20banner=20clock=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1496f..4d757c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v0.10.1 — 2026-10-03 18:36 +- Fix React 19 hydration mismatch (#418) on every production load — the banner's live clock was prerendered at build time in the static page and desynced at hydration, intermittently stranding the world-map team builder's DISPATCH button permanently disabled (jump flow unusable); e2e jump tests now green. + ## v0.10.0 — 2026-10-03 00:57 - Queue-based actions (#44): every game action (jump, explore, ship upgrade/expand/build, research) is now a queued task with an assigned team — a lead + optional helpers. Validation and cost deduction happen at queue time (unknown crew → 404, busy/committed crew → 409, in-transit or second jump → 409); effects apply when the task completes, mission accept is instant and free, and mission-completion checks run when the satisfying task resolves. - Manual time: new `POST /api/turn` advances exactly one turn — each active task ticks down, completions resolve via per-type resolvers (reusing the existing jump/explore/ship/research logic), FIFO successors auto-start; an empty queue is a free skip. `save.turn` now only increments here, and the UI gets the NEXT TURN button (bottom-right) with the turn counter. diff --git a/package.json b/package.json index e9b6db7..cc8f5ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "space-wanderer", - "version": "0.10.0", + "version": "0.10.1", "private": true, "scripts": { "dev": "next dev -p 3000", -- 2.54.0 From e792c8a06cdf18cf8a3ee9e6e3812ab9c5ef046d Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Sat, 3 Oct 2026 23:42:32 +0000 Subject: [PATCH 4/4] =?UTF-8?q?fix(ui):=20team=20builder=20=E2=80=94=20coa?= =?UTF-8?q?lesce=20the=20queued-jump=20block=20to=20null=20so=20an=20empty?= =?UTF-8?q?=20queue=20no=20longer=20disables=20JUMP=20dispatch=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 ++- components/team-builder.tsx | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d757c0..a353e5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog ## v0.10.1 — 2026-10-03 18:36 -- Fix React 19 hydration mismatch (#418) on every production load — the banner's live clock was prerendered at build time in the static page and desynced at hydration, intermittently stranding the world-map team builder's DISPATCH button permanently disabled (jump flow unusable); e2e jump tests now green. +- Fix React 19 hydration mismatch on every production load — the banner's live clock was prerendered at build time in the static page and desynced at hydration (CI-verified: no hydration errors in the job logs). A real fix, but NOT the cause of the red e2e jump specs. +- Fix the world-map jump dispatch — the actual cause of the three deterministically red e2e jump specs: TeamBuilder's `blocked` term was `undefined`, not `null`, whenever no jump was queued (`Array.find` returns `undefined`), so the roster rendered (truthiness check) while the DISPATCH button's `blocked !== null` guard read it as blocked and stayed disabled — the JUMP panel's dispatch was permanently dead on an empty queue (the 300 s `waitForResponse` timeout; present since the builder shipped in v0.10.0, so the UI-jump specs were red on every run since, on a fresh DB; non-JUMP panels were unaffected, their branch yielding `null`). ## v0.10.0 — 2026-10-03 00:57 - Queue-based actions (#44): every game action (jump, explore, ship upgrade/expand/build, research) is now a queued task with an assigned team — a lead + optional helpers. Validation and cost deduction happen at queue time (unknown crew → 404, busy/committed crew → 409, in-transit or second jump → 409); effects apply when the task completes, mission accept is instant and free, and mission-completion checks run when the satisfying task resolves. diff --git a/components/team-builder.tsx b/components/team-builder.tsx index db66b72..f88de85 100644 --- a/components/team-builder.tsx +++ b/components/team-builder.tsx @@ -23,9 +23,13 @@ export function TeamBuilder({ type, hopCount, roster, tasks, onQueue }: { const [helperIds, setHelperIds] = useState([]) // Whole-builder blocks: an ACTIVE jump is in transit (all types); in the jump panel any - // queued jump is — the second-jump 409 (JC-12). + // queued jump is — the second-jump 409 (JC-12). The JUMP branch coalesces find()'s + // undefined to null so blocked is strictly QueueDto | null: the roster ternary below tests + // truthiness, but the button guard compares to null — undefined slipped past it and + // disabled every empty-queue JUMP dispatch (v0.10.1 e2e jump regression). const inTransit = tasks.find((t) => t.type === 'JUMP' && t.status === 'ACTIVE') - const blocked = inTransit ?? (type === 'JUMP' ? tasks.find((t) => t.type === 'JUMP') : null) + const queuedJump = type === 'JUMP' ? (tasks.find((t) => t.type === 'JUMP') ?? null) : null + const blocked = inTransit ?? queuedJump const lead = roster.find((c) => c.id === leadId) ?? null const helpers = roster.filter((c) => helperIds.includes(c.id)) -- 2.54.0