ui/synthetic-report: PLAN parity rule + testing doc
Locks in the synthetic-report parity rule as a global "Assumptions and Defaults" entry in ui/PLAN.md: every phase that extends the server->UI report contract must also extend the legacy parser in the same PR (or document in tools/local-dev/legacy-report/README.md why the new field cannot be derived from legacy text). The Go side already enforces shape compatibility via the pkg/model/report import; this rule extends that mechanical guard to "did we remember to wire the new field through". ui/docs/testing.md grows a "Synthetic reports for visual testing" section with the full conversion -> load -> compose loop and the two operational gotchas (no network on synthetic ids, page reload clears the in-memory map). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+19
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user