ui/phase-21: sciences CRUD list, designer, and production-picker integration

Lights up the player-defined sciences feature: a table view with sort
and filter, a designer with four percent inputs and a strict
sum-equals-100 gate, and a Research-sub-row integration so the
planet production picker lists the user's sciences alongside the
four tech buttons. Phase 21 decisions are baked back into ui/PLAN.md
(no UpdateScience on the wire — write-once via createScience +
removeScience; percentages instead of fractions; sciences live under
the existing Research segment).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 21:32:37 +02:00
parent 0509f2cde2
commit 7bea22b0b5
31 changed files with 2751 additions and 71 deletions
+67 -21
View File
@@ -2307,43 +2307,89 @@ Decisions during stage:
delta. Implemented in `ui/frontend/src/map/ship-groups.ts`
alongside the existing in-space point primitive.
## Phase 21. Sciences — CRUD List + Designer
## ~~Phase 21. Sciences — CRUD List + Designer~~
Status: pending.
Status: done (local-ci run TBD).
Goal: define and manage sciences (named mixes of tech proportions
summing to 1.0) through a table view and a designer.
summing to 1.0) through a table view and a designer, plus surface
them in the planet production picker.
Artifacts:
- `ui/frontend/src/routes/games/[id]/table/sciences/+page.svelte`
list of sciences with name and four tech proportions
- `ui/frontend/src/routes/games/[id]/designer/science/[id]/+page.svelte`
designer with four numeric inputs that auto-normalise to 1.0 and a
name field
- `ui/frontend/src/lib/active-view/table-sciences.svelte` — sciences
list with sort / filter / Delete, mounted by the existing
`routes/games/[id]/table/[entity]` catch-all when `entity ===
"sciences"`.
- `ui/frontend/src/lib/active-view/designer-science.svelte` —
designer with four percent inputs (`step="0.1"`, range
`[0, 100]`), live sum readout, strict sum-equals-100 gate, and a
read-only view mode for the existing
`routes/games/[id]/designer/science/[[scienceId]]` route.
- `ui/frontend/src/sync/order-types.ts` extends with `CreateScience`
and `UpdateScience` command variants
- topic doc `ui/docs/science-designer-ux.md` covering
auto-normalisation, validation, and the relationship to the planet
production picker (Phase 15)
and `RemoveScience` command variants (the original plan mentioned
`UpdateScience`; the wire only carries Create + Remove, so the
decision below replaces Update with Remove).
- `ui/frontend/src/lib/util/science-validation.ts` — the TS-side
mirror of `pkg/calc/validator.go.ValidateScienceValues` plus the
entity-name rules and the percent → fraction conversion.
- `ui/frontend/src/api/game-state.ts` — adds `ScienceSummary`,
`localScience` on `GameReport`, decoder, and overlay branches for
`createScience` / `removeScience`.
- `ui/frontend/src/lib/inspectors/planet/production.svelte` — the
Research sub-row gains one button per defined science; click
emits `setProductionType("SCIENCE", "<name>")`.
- topic doc `ui/docs/science-designer-ux.md` covering the percent
input model, validation, and the planet-production-picker
integration.
Dependencies: Phase 17.
Decisions during stage:
1. `UpdateScience` was a planning error: the wire schema
(`pkg/schema/fbs/order.fbs`) only carries
`CommandScienceCreate` + `CommandScienceRemove`. Sciences are
write-once on the wire — the designer's view mode therefore has
no Save-edits affordance, and an "edit" is a Remove + Create
sequence the player drives manually. Mirrors Phase 17's
ship-class pattern.
2. The production-picker integration places science buttons inside
the existing Research sub-row, alongside the four tech buttons,
instead of adding a fifth top-level segment. A science wins
over a same-named tech display when the engine sends an
ambiguous production string (a science named `Drive` shadows
the Drive tech button).
3. Designer inputs are percentages (`step="0.1"`, `[0, 100]`) with
a strict sum-equals-100 gate (`SUM_EPSILON_PERCENT = 1e-3`),
not auto-rebalanced fractions. The user controls the sum; the
designer converts to fractions only on Save before dispatching
`createScience`.
Acceptance criteria:
- the user can create, edit, and delete sciences;
- proportions auto-normalise on edit so the sum is always 1.0;
- the user can create and delete sciences (no in-place edit — see
decision 1);
- proportions are entered as one-decimal percentages and the four
must sum to exactly `100` for Save to enable;
- the planet production picker (Phase 15) lists the user's sciences
and lets the user select one for research production;
- name validation matches [`rules.txt`](../game/rules.txt) constraints (length, allowed
characters, special characters not at start/end, no triple repeats).
in the Research sub-row and lets the user select one for research
production;
- name validation matches [`rules.txt`](../game/rules.txt)
constraints (length, allowed characters, special characters not
at start/end, no triple repeats).
Targeted tests:
- Vitest unit tests for proportion normalisation;
- Vitest unit tests for science name validation;
- Playwright e2e: create a science, set a planet to research it,
submit, confirm.
- Vitest unit tests for percent-range validation, sum-equals-100
gate, and percent → fraction conversion
(`tests/science-validation.test.ts`);
- Vitest component tests for the table
(`tests/table-sciences.test.ts`) and the designer
(`tests/designer-science.test.ts`);
- Playwright e2e: create a science, set a planet's production to it
via the Research sub-row, delete it
(`tests/e2e/sciences.spec.ts`).
## Phase 22. Races View — War/Peace Toggle and Votes