docs(@projects/@magic-civilization): 📝 p3-18 — P4 transport core done; P5 is functionally required (UI uses pathfinder.gd)

Records transport P4a/b/c complete + the finding that the rendered game moves via
GDScript pathfinder.gd (not the Rust pathfinder), so embark works headless only
until P5 plumbs the embark gate into the GDScript path (or routes movement through
Rust). Transport refinements (carried-unit target-protection, AI-use) deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Natalie 2026-06-25 06:17:00 -04:00
parent 8b4c71688f
commit e83362200e

View file

@ -77,16 +77,33 @@ two-tier Civ model on the existing tree (`public/resources/techs/naval.json`):
embark model. mc-core 263 / mc-ai 287 / mc-turn 244 green. Commit `f830a1ce0`.
(api-gdext `legal_actions_for`/`can_invoke` keep the embark FFI inputs as
vestigial/ABI-stable — trimmed in P5.)
- [ ] **P4 — transport load/carry/unload.** Implement the `transport` keyword:
load adjacent land units (≤ capacity) onto a transport ship, they move with it,
unload onto adjacent land. Carried units protected. Unit tests. *(Large fresh
mechanic — cargo state on MapUnit + load/unload + carry-move + combat. Pure
Rust, cargo-test verifiable.)*
- [ ] **P5 — GDScript pathfinder mirror + FFI trim.** `pathfinder.gd::_is_passable`
mirrors the embark gate (or delegates to the Rust pathfinder — Rail 1); drop the
vestigial embark inputs from `legal_actions_for`/`can_invoke` + their GDScript
callers (`unit_panel.gd`, `unit.gd`, `test_unit_actions.gd`). *(Needs the build
host: GUT + dylib; local cargo resolver panics on gdextension-api.)*
- [x] **P4 — transport load/carry/unload (core).** ✅ Built per owner direction.
- **P4a** (`ef697f492`): catalog `UnitStats.keywords` + `is_transport()` +
`TRANSPORT_CAPACITY=2` (data-driven, no unit id hardcoded); `MapUnit.carrier_id`.
- **P4b** (`f05aaff2a`): `process_one_move` board (step onto an adjacent friendly
hull → `carrier_id`, capacity-gated, no embark tech needed) / carry (hull move
drags cargo) / disembark (carried unit → adjacent empty land). Modelled as
automatic moves, no new explicit actions. Tests: `transport_board_carry_then_unload`,
`transport_rejects_boarding_when_full`.
- **P4c** (`93ce7c848`): `prune_orphaned_cargo` after the PvP phase — cargo lost
with a destroyed hull (keeps `unit_upkeep` aligned). Test
`destroyed_transport_loses_cargo`.
**Refinements deferred (documented):** carried units ride the hull's hex
(stacked) — fully shielding them from being *individually* targeted needs combat
target-selection changes that touch 1UPT assumptions (rare for a tier-9 hull;
the prune already handles hull-death). AI does not yet load units onto transports
(negligible value — tier-9 hull the AI rarely builds; embark covers crossing).
- [ ] **P5 — GDScript pathfinder mirror + FFI trim. FUNCTIONALLY REQUIRED.** The
rendered game moves units via `world_map.gd → PathfinderScript.find_path`
(`pathfinder.gd`), NOT the Rust pathfinder — so embark currently works **headless
only** (GdPlayerApi → Rust `process_one_move`), and a human playing the UI cannot
embark until this lands. Either plumb the owner's `EmbarkLevel` into
`pathfinder.gd::_is_passable`/`find_path`/`find_path_with_fog` + their callers,
or (Rail-1 preferred) route world_map movement through the Rust pathfinder. Also
drop the vestigial embark inputs from `legal_actions_for`/`can_invoke` + GDScript
callers. *(Needs the build host: the bridge must expose `embark_level` to
GDScript + GUT/dylib verify; local cargo resolver panics on gdextension-api.)*
- [ ] **P6 — end-to-end.** A headless 1v1 (both sides driven) reaches a decisive
`game_over` by crossing water to capture the enemy capital — the demo that
motivated this objective.