ui/phase-15: planet inspector production controls + order-draft collapse
Adds the second end-to-end command (`setProductionType`) with a collapse-by-`planetNumber` rule on the order draft, the segmented production-controls component on the planet inspector, the FBS encoder/decoder pair for `CommandPlanetProduce`, and the `localShipClass` projection on `GameReport`. Forecast number is deferred and tracked in the new `ui/docs/calc-bridge.md`.
This commit is contained in:
+109
-21
@@ -1686,38 +1686,126 @@ Verified on local-ci run 11 (`success`, f80c623).
|
||||
Status: pending.
|
||||
|
||||
Goal: let the user switch a planet's production type to industry,
|
||||
materials, research a science, or build a ship class; each change
|
||||
appends a command to the order draft.
|
||||
materials, research a tech field, or build a ship class; each change
|
||||
appends a command to the order draft. Repeated changes for the same
|
||||
planet collapse to the latest choice.
|
||||
|
||||
Artifacts:
|
||||
Decisions taken with the project owner during implementation:
|
||||
|
||||
- `ui/frontend/src/lib/inspectors/planet/production.svelte` segmented
|
||||
control with the four production options; a sub-picker for science
|
||||
and ship class targets
|
||||
- `ui/frontend/src/sync/order-types.ts` extends with
|
||||
`SetProductionType` command variant
|
||||
- references to `pkg/calc/` predictions (free production potential,
|
||||
forecast output for current type) — wired through `ui/core/calc/`
|
||||
- audit `ui/docs/calc-bridge.md` updates this phase's required calc
|
||||
functions; if any are missing in `pkg/calc/`, raise as blocker
|
||||
1. **Forecast is deferred and raised as a blocker.** The plan's audit
|
||||
clause discovered that `pkg/calc/` only carries the two ship-side
|
||||
functions (`ShipProductionCost`, `PlanetProduceShipMass`); every
|
||||
other forecast formula (industry, materials, per-tech research,
|
||||
production capacity) lives inside
|
||||
`game/internal/model/game/planet.go` and is not exported.
|
||||
`ui/core/calc/` and `ui/docs/calc-bridge.md` did not exist at all.
|
||||
Phase 15 creates `ui/docs/calc-bridge.md` documenting the gap and
|
||||
waives the forecast deliverable until a dedicated future phase
|
||||
builds the real Go → WASM → TS bridge. The inspector continues to
|
||||
show only the existing `freeIndustry` (free production potential)
|
||||
number, which is computed engine-side and ships in the report
|
||||
payload.
|
||||
2. **Sub-pickers expose only what the game data already supports.**
|
||||
"Research" sub-row shows the four implicit tech fields
|
||||
(DRIVE / WEAPONS / SHIELDS / CARGO); custom `LocalScience`
|
||||
entries are deferred until the science designer phase introduces
|
||||
them. "Build Ship" sub-row shows `LocalShipClass` entries; the
|
||||
`GameReport` projection is extended with a minimal
|
||||
`ShipClassSummary { name }` so the e2e spec can seed one ship
|
||||
class and exercise the SHIP branch end-to-end. Empty
|
||||
`LocalShipClass` collapses to a localised "no ship classes
|
||||
designed yet" placeholder.
|
||||
3. **Re-clicks always emit a command.** The collapse-by-`planetNumber`
|
||||
rule keeps at most one `setProductionType` per planet in the
|
||||
draft. A click that lands on the segment matching `report.production`
|
||||
still emits a command; the engine accepts repeat submits
|
||||
idempotently. Avoids a fragile reverse-mapping from
|
||||
`report.production` display strings (`"Drive"`, ship-class name,
|
||||
science name) back to the FBS enum.
|
||||
4. **Inspector layout split.** `ui/frontend/src/lib/inspectors/planet/
|
||||
production.svelte` is the new component; the parent
|
||||
`inspectors/planet.svelte` mounts it for `kind === "local"`
|
||||
planets and drops the static read-only "current production" row
|
||||
on that branch (the row stays for non-local planets). The mobile
|
||||
sheet (`planet-sheet.svelte`) and the sidebar
|
||||
(`sidebar/inspector-tab.svelte`) both forward
|
||||
`localShipClass` from the rendered-report context.
|
||||
|
||||
Artifacts (delivered):
|
||||
|
||||
- `ui/frontend/src/sync/order-types.ts` — `SetProductionTypeCommand`
|
||||
variant + `ProductionType` literal union + `PRODUCTION_TYPE_VALUES`
|
||||
/ `isProductionType` helpers.
|
||||
- `ui/frontend/src/sync/order-draft.svelte.ts` — `validateCommand`
|
||||
branch (mirrors the engine's `subject=Production` rule); `add`
|
||||
enforces collapse-by-`planetNumber` for the new variant only.
|
||||
- `ui/frontend/src/sync/submit.ts` — encodes
|
||||
`CommandPlanetProduce` via the new `productionTypeToFBS` helper.
|
||||
- `ui/frontend/src/sync/order-load.ts` — decodes
|
||||
`CommandPlanetProduce` via `productionTypeFromFBS` and skips
|
||||
`PlanetProduction.UNKNOWN` rows.
|
||||
- `ui/frontend/src/api/game-state.ts` — `applyOrderOverlay` rewrites
|
||||
`planet.production` for `setProductionType` (helper
|
||||
`productionDisplayFromCommand` mirrors
|
||||
`Cache.PlanetProductionDisplayName`); new `ShipClassSummary` type
|
||||
and `GameReport.localShipClass` projection (decoded from
|
||||
`report.localShipClass`).
|
||||
- `ui/frontend/src/lib/inspectors/planet/production.svelte` — new
|
||||
segmented control with Research / Build-Ship sub-rows.
|
||||
- `ui/frontend/src/lib/inspectors/planet.svelte` — accepts
|
||||
`localShipClass` prop, mounts `<Production />` for local planets,
|
||||
drops the static production row on that branch only.
|
||||
- `ui/frontend/src/lib/inspectors/planet-sheet.svelte` and
|
||||
`ui/frontend/src/lib/sidebar/inspector-tab.svelte` — forward
|
||||
`localShipClass` from the rendered report context.
|
||||
- `ui/frontend/src/routes/games/[id]/+layout.svelte` — derives
|
||||
`localShipClass` and passes it to the mobile sheet.
|
||||
- `ui/frontend/src/lib/sidebar/order-tab.svelte` — new label branch
|
||||
for `setProductionType` using the new locale key.
|
||||
- `ui/frontend/src/lib/i18n/locales/{en,ru}.ts` — production-control
|
||||
copy plus the new order-tab label.
|
||||
- `ui/frontend/tests/e2e/fixtures/report-fbs.ts` — extended with a
|
||||
`localShipClass` fixture vector.
|
||||
- `ui/frontend/tests/e2e/fixtures/order-fbs.ts` — discriminated
|
||||
fixture union supporting both `planetRename` and
|
||||
`setProductionType` payloads.
|
||||
- `ui/docs/calc-bridge.md` (new) — calc-bridge gap analysis and the
|
||||
Phase 15 waiver.
|
||||
- `ui/docs/order-composer.md` — updated discriminated-union
|
||||
reference + new "Collapse-by-target rule" section.
|
||||
- Tests: extended `order-draft.test.ts`, `submit.test.ts`,
|
||||
`order-load.test.ts`, `order-overlay.test.ts`,
|
||||
`game-state.test.ts`, `inspector-planet.test.ts`; new
|
||||
`inspector-planet-production.test.ts` Vitest component spec; new
|
||||
`tests/e2e/planet-production.spec.ts` Playwright spec.
|
||||
|
||||
Dependencies: Phase 14.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- changing production type adds exactly one `SetProductionType`
|
||||
command to the order draft;
|
||||
- changing production type adds exactly one `setProductionType`
|
||||
command to the order draft, with the engine wire shape
|
||||
(`CommandPlanetProduce` + `subject` rule for `SCIENCE` / `SHIP`);
|
||||
- repeated changes for the same planet collapse to the latest choice
|
||||
(no duplicate commands per planet);
|
||||
- forecast output number reflects the chosen production type and
|
||||
matches `pkg/calc/` outputs.
|
||||
(no duplicate `setProductionType` commands per planet); other
|
||||
variants (e.g. `planetRename`) keep their append-only behaviour;
|
||||
- forecast output number is intentionally **not** rendered in this
|
||||
phase (waived per decision 1; tracked in `ui/docs/calc-bridge.md`).
|
||||
|
||||
Targeted tests:
|
||||
|
||||
- Vitest unit tests for the collapse-duplicates logic in order draft;
|
||||
- Vitest component tests for forecast number rendering;
|
||||
- Playwright e2e: switch production three times, submit, confirm
|
||||
server reflects the latest choice.
|
||||
- Vitest unit tests for the collapse-by-`planetNumber` logic in
|
||||
`OrderDraftStore.add` and the `setProductionType` branch of
|
||||
`validateCommand`;
|
||||
- Vitest unit tests for the FBS encoder / decoder round-trip and the
|
||||
`productionDisplayFromCommand` helper;
|
||||
- Vitest component tests for the segmented control's segment
|
||||
emission, sub-row reveal, empty-classes placeholder, and active-
|
||||
highlight derivation;
|
||||
- Playwright e2e: switch production three times across all four
|
||||
segments, confirm the order tab carries exactly one row at every
|
||||
step, gateway records the latest choice (`SHIP` + class name),
|
||||
reload preserves the row through `user.games.order.get`.
|
||||
|
||||
## Phase 16. Inspector — Cargo Routes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user