ui: plan 01-27 done #1

Merged
developer merged 120 commits from ai/ui-client into main 2026-05-13 18:55:14 +00:00
2 changed files with 69 additions and 0 deletions
Showing only changes of commit f5ac9fac59 - Show all commits
+19
View File
@@ -99,6 +99,25 @@ The intended v1 architecture is:
format-compatible with GitHub Actions). Linux runners cover Tier 1 format-compatible with GitHub Actions). Linux runners cover Tier 1
tests; a macOS runner is provisioned only when Tier 2 iOS smoke is tests; a macOS runner is provisioned only when Tier 2 iOS smoke is
needed. needed.
- **Synthetic-report parser parity is a global rule.** A DEV-only
loader on the lobby (`import.meta.env.DEV`) lets the developer feed
the UI a JSON file that mimics a server `Report`, so the map and
inspectors can be exercised against rich game states without playing
many turns end-to-end. The JSON is produced by the Go CLI in
`tools/local-dev/legacy-report/`, which converts legacy text
reports under `tools/local-dev/reports/` into the shape of
`pkg/model/report.Report` (whatever subset the UI currently
decodes). Every phase that **extends the server→UI report contract**
— adding decoding for a new `Report` field in
`ui/frontend/src/api/game-state.ts` — must, in the same PR, extend
the legacy parser to populate that field, **or** explicitly note in
the parser's `README.md` that the field cannot be derived from the
legacy text format and is left empty in synthetic JSON. The point
is to keep `tools/local-dev/legacy-report/` a faithful (and
type-checked, via `pkg/model/report` import) generator of test
inputs as the UI grows; otherwise synthetic data silently lags
behind the contract and visual tests stop covering the new
behaviour.
## Information Architecture and Navigation ## Information Architecture and Navigation
+50
View File
@@ -109,6 +109,56 @@ mode off, troubleshooting common boot issues).
The local-dev stack is independent from the local-ci stack below; The local-dev stack is independent from the local-ci stack below;
they bind different ports and can run side by side. they bind different ports and can run side by side.
## Synthetic reports for visual testing (DEV)
For visual checks of the map, inspectors and order-overlay against
rich game states, the lobby exposes a DEV-only "Load synthetic
report" affordance (`import.meta.env.DEV`). The flow is:
1. Convert a legacy text report (`tools/local-dev/reports/{dg,gplus}/`)
to JSON with the Go CLI:
```sh
go run ./tools/local-dev/legacy-report/cmd/legacy-report-to-json \
--in tools/local-dev/reports/dg/KNNTS039.REP \
--out /tmp/dg39.json
```
See [`../../tools/local-dev/legacy-report/README.md`](../../tools/local-dev/legacy-report/README.md)
for what the parser populates today and how to extend it when a
new UI phase decodes a new `Report` field.
2. Run the UI dev server (`pnpm -C ui/frontend dev`), open the lobby,
and use the "Load JSON…" file picker in the **Synthetic test
reports (DEV)** section. The page navigates to
`/games/synthetic-<uuid>/map` with the report wired into the
in-game shell.
In synthetic mode:
- The map view, inspectors and races view render against the loaded
report exactly as they would for a real game.
- Composing orders works locally (overlay applies through
`applyOrderOverlay` as usual), but **nothing is sent to the
gateway** — `OrderDraftStore.scheduleSync` short-circuits because
the synthetic id is not a UUID and the layout deliberately does
not bind a `GalaxyClient` for this game.
- The order draft is persisted into the platform `Cache` under the
same `order-drafts` namespace as real games, keyed by the
synthetic id, so navigating back into the same synthetic session
restores the draft. The cache is cleared with
`__galaxyDebug.clearOrderDraft(gameId)` (DEV debug surface).
- A page reload loses the in-memory report registry; opening the
same synthetic id afterwards redirects to /lobby. Re-load the JSON
to reseed.
The synthetic-report parity rule (see [`../PLAN.md`](../PLAN.md) §
Assumptions and Defaults) requires every UI phase that extends
`decodeReport` to also extend the legacy parser in lockstep, or to
record in the parser's `README.md` that the new field cannot be
derived from legacy text. This keeps the synthetic-mode coverage in
step with the contract as the UI grows.
## Local CI verification ## Local CI verification
`tools/local-ci/` ships a self-contained Gitea + Actions runner via `tools/local-ci/` ships a self-contained Gitea + Actions runner via