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:
@@ -0,0 +1,82 @@
|
||||
# Calc bridge
|
||||
|
||||
The Galaxy frontend renders predictive numbers (free production
|
||||
potential, forecast output for a chosen production type, ship build
|
||||
progress, tech progress) that depend on the same formulas the engine
|
||||
uses at turn cutoff. To keep one source of truth, those formulas live
|
||||
in Go under `pkg/calc/` and are surfaced to the UI through a planned
|
||||
Go → WASM → TypeScript bridge mounted under `ui/core/calc/` and a
|
||||
matching TS adapter in `ui/frontend/src/`.
|
||||
|
||||
The bridge does not exist yet. This document is the audit trail for
|
||||
what it must expose, what is already in place, and what is missing.
|
||||
|
||||
## Current `pkg/calc/` exports
|
||||
|
||||
| Function | Purpose |
|
||||
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
|
||||
| `ShipProductionCost(shipEmptyMass float64) float64` | Production units required per unit of ship empty mass (×10). |
|
||||
| `PlanetProduceShipMass(L, Mat, Res float64) float64` | Ship mass produced per turn given free production `L`, material stockpile `Mat`, resources `Res`.|
|
||||
| `DriveEffective`, `Speed`, `EmptyMass`, `FullMass`, … | Ship-level derivations (`pkg/calc/ship.go`). |
|
||||
| `ValidateShipTypeValues`, `CheckShipTypeValueDWSC` | Ship-design validators (`pkg/calc/validator.go`). |
|
||||
|
||||
Nothing else lives in `pkg/calc/` today. Production-side formulas
|
||||
(industry / materials / per-tech research / production capacity) sit
|
||||
in `game/internal/model/game/planet.go` and `…/science.go` and have
|
||||
never been exported.
|
||||
|
||||
## Required calc functions per UI feature
|
||||
|
||||
The table below tracks what UI features need from the bridge and
|
||||
whether the underlying Go function exists.
|
||||
|
||||
| UI feature | Go formula | In `pkg/calc/`? | Surfaced to TS? |
|
||||
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | :-------------: | :-------------: |
|
||||
| Free production potential (`freeIndustry`) | `Planet.ProductionCapacity` → `industry*0.75 + population*0.25` (`game/internal/model/game/planet.go`) | no | no |
|
||||
| Industry production output per turn | `Planet.ProduceIndustry(freeProduction)` (`planet.go`); `freeProduction/5` modulo material constraint | no | no |
|
||||
| Materials production output per turn | `Planet.ProduceMaterial(freeProduction)` (`planet.go`); `freeProduction * resources` | no | no |
|
||||
| Per-tech research progress (DRIVE/WEAPONS/…) | `ResearchTech` (`game/internal/model/game/science.go`); `freeProduction / 5000` per tech level | no | no |
|
||||
| Custom-science progress | weighted form of `ResearchTech` driven by `Race.Sciences[].(Drive\|Weapons\|Shields\|Cargo)` (`science.go`) | no | no |
|
||||
| Ship build progress | `PlanetProduceShipMass(L, Mat, Res) / ShipProductionCost(class.EmptyMass)` (combination of two existing exports) | partial | no |
|
||||
|
||||
`partial` means the Go primitives exist in `pkg/calc/` but the
|
||||
composition (and the conversion of TS-side `ReportPlanet`/
|
||||
`ShipClass` to the formula inputs) is not implemented anywhere.
|
||||
|
||||
## Phase 15 waiver
|
||||
|
||||
Phase 15 ships the inspector's planet production controls
|
||||
(segmented control + sub-pickers + collapse-by-`planetNumber`
|
||||
order command) but **deliberately does not surface the per-type
|
||||
forecast number**. The planning gate explicitly raised the gap as
|
||||
a blocker per the plan's audit clause ("if any are missing in
|
||||
`pkg/calc/`, raise as blocker") and the project owner approved
|
||||
deferring the forecast to a dedicated future bridge phase. The
|
||||
inspector still renders the existing `freeIndustry` row (free
|
||||
production potential) — that number is computed engine-side and
|
||||
ships in the report payload, so no calc-bridge access is required
|
||||
for it today.
|
||||
|
||||
Acceptance criterion 3 of Phase 15 ("forecast output number
|
||||
reflects the chosen production type and matches `pkg/calc/`
|
||||
outputs") is therefore intentionally not satisfied; the rewritten
|
||||
Phase 15 stage text records this decision and points back at this
|
||||
document.
|
||||
|
||||
## Planned bridge shape (follow-up phase)
|
||||
|
||||
When the bridge phase lands, the contract should be:
|
||||
|
||||
1. Promote every formula in the table above into `pkg/calc/` so the
|
||||
engine and the UI share one Go-side implementation. The engine
|
||||
continues to call them through `game/internal/...` wrappers.
|
||||
2. Mount a `ui/core/calc/` Go module that re-exports the subset the
|
||||
UI needs. Keep it WASM-friendly (no `unsafe`, no goroutines,
|
||||
simple in/out values).
|
||||
3. Wire the WASM glue in `ui/wasm/main.go` so each calc function is
|
||||
reachable from `globalThis.galaxyCore`.
|
||||
4. Add a TypeScript adapter under `ui/frontend/src/platform/core/`
|
||||
that wraps the WASM calls in typed helpers
|
||||
(`forecastIndustry(freeProduction, …)` etc.).
|
||||
5. Update this document with the live function inventory and
|
||||
delete the "missing" rows above.
|
||||
Reference in New Issue
Block a user