Quick Design Spec: Land Dock/Undock
Type: New Small System Scope: The lifecycle executor and content instantiator for docked lands: Addressables preload/activate/teardown on the tide's transition edges, deterministic seed→layout translation, and the KnownLandTemplates registry. Does NOT own: transition detection or selection (Tide — pure function), node/diff semantics (Harvesting), enemy behavior/values (Enemy AI), the era-gate formula (Crafting reads the registry). Date: 2026-08-27 Estimated Implementation: ~5 days (dock/undock round-trip spike-validated — prototypes/tide-scheduler-spike-2026-08-25/)
Overview
The tide decides what docks and when; this system makes it physically exist. On the scheduler's preload notice it asynchronously loads the land template; at φ it activates gameplay content — placing nodes, spawn points, and scatter deterministically from the docking's variationSeed; at φ+W, after the tide's soft-close sequence resolves, it tears down and unloads. It also keeps the group's historical ledger: KnownLandTemplates, the append-only set of every template that has ever docked — the fact crafting's era gate reads. **TD split-watch (systems-index high-risk note): the two concerns inside this system — Addressables lifecycle vs authority/registry — stay internally separated from day one.**
Core Rules
- Lifecycle follows the tide's edges, exactly. Subscribe to scheduler transition events (never poll): async Addressables load begins at
NextBoundary(t) − PreloadLeadTime(cosmetic drift-in, not enterable — tide Edge Case 12); **gameplay existence begins exactly atφ** (tide Rule 8); gameplay ends atφ+Wstrictly after the tide's soft-close ordering completes (deposits resolve first — tide owns that sequence); the land then stays visible and non-interactable through tide'sEvictionGrace(20 s, tide Rule 9 / Edge Case 11 — the one and only drift-out window; LDU owns no second one, cross-GDD W1 2026-08-27) and is despawned + unloaded at its expiry, never earlier; assets unload before the next preload window needs memory. Absent = nothing resident. - Seed→layout is a pure function.
layout(template, variationSeed)withvariationSeed = f(seed, socket, cycleIndex)(tide F-series, handed opaquely). It deterministically places: harvest nodes (per harvesting's counts/bands — placement varies per docking, counts and types never do; carcass-node placement purity per harvesting CD A1), enemy spawn points (positions only — Enemy AI owns everything about behavior/strength), and cosmetic scatter. Same docking key → identical layout on every machine and every reload, no exceptions. - The registry:
KnownLandTemplates. Host-authoritative append-only set (same authority tier asKnownRecipes). AtemplateIdis appended at its first gameplay activation (φ) — never at preload (a land that drifts in cosmetically but never activates was not "offered"). Seeded: the starting template(s) enter the set at world creation — "the first land was always docked" (crafting Edge Case 17 / AC-48 honored). Historical: membership has no removal clause, ever — "docked at least once" survives content patches (crafting Edge Case 18). Persisted via Save as a permanent-class table, union reconcile (save-persistence Rules 2/6). - **Sole-source guard (mechanizing crafting Edge Case 18's authoring rule).** At load, if any known recipe's input source template is absent from the current template pool, emit a loud warning naming the recipe and template — the recipe is now supply-starved forever. Warning, not rejection (the save is valid; the content patch is the mistake).
- Enemy instantiation routes through here (tide's deliberate non-dependency, preserved). At activation, LDU calls Enemy AI's spawn contract with
(template, variationSeed, spawnPoints[]). The hook carries ascalingContextfield reserved but empty at MVP (prosperity scaling is concept-level Tier 1+; the shape exists so the routing decision never gets re-litigated). Enemy AI's quick-spec owns everything inside the call. - **"Recurring lands return possibly changed" — MVP honesty (harvesting OQ8's LDU half).** At MVP, "changed" means: node placement and enemy spawn positions differ per docking (Rule 2's variation seed) and guard composition varies (Enemy AI's load-bearing variation). Template content — node counts, band splits, layout bones — is fixed. This is deliberate and stated: authored-template revisions ("the marsh returns with a new interior") are Tier 1 content work, not an MVP system. The retention hook is delivered at MVP by variation, not by revision.
- **Traversal metadata + the party-strip readout (retired gate — ruled 2026-08-27, cross-GDD review C3).** Every template authors
traversalProfile = {shoreToMidSecs, shoreToDeepSecs}(measured at base move speed, one-way). The prior party-clock gate is retired: `partyClockRatio = totalSupply / (bagSlots × maxStack × harvesters × ⌊W / (2 × shoreToDeepSecs + bagFillSecs)⌋) ≥ 1.0` could never pass — withW= 158,400 s the trips term is ~10³ and the ratio ~4 × 10⁻⁴; even over a two-hour session, five harvesters strip a 438-unit land in roughly ten minutes. The honest fact, now stated rather than gated: **a focused party can strip a land**, and harvesting Rule 12 already names a coordinated full-clear a Fellowship achievement, not a bug. Pillar 1's tension at every party size is per-session opportunity cost — what the group chose not to do tonight — never supply scarcity, and the dock windowWprotects nothing at party scale. What remains is an informational readout, never an assertion: CI computes `stripTimeEstimate(h) = (nodesPerLand / h) × nodeVisitSecs + ⌈totalSupply / (bagSlots × maxStack × h)⌉ × 2 × shoreToDeepSecs` per template forh ∈ {2, 5}and prints it, so a template whose strip time is wildly short or long is seen at authoring time. Harvesting's C1 scope-honesty text updated the same day to drop the "protected by the clock" claim. - Socket layout is authored here, with three constraints: every socket keeps
socketNoBuildRadius(registry, 4 u) of clear shore (BB F4 reads socket positions from this authoring); **every socket carries an authored shorelinedepositPoint** — the fixed point tide Rule 9 deposits caught players at, which must lie withinsocketNoBuildRadiusof its socket (BB AC-63b validates this at load; added 2026-08-27, BB re-review CS-2); and the home island must retain viable placeable area around each socket — re-check both when Tier 1 moves to 3–4 sockets (BB OQ2, owned here). MVP ships 1 socket. - Memory discipline. One land resident at MVP (N=1). Per-template asset budget must fit the 2 GB ceiling with home + one land + one preloading land resident simultaneously (a
φ+Wteardown can overlap the next window's preload at Tier 1 socket counts — budget for the worst case, not the average). Concrete MB budget:landTemplateBudgetMB = 64, owned byLandLifecycle, CI-gated on the Addressables build layout — ADR-0005 (2026-08-28); the asset pass authors within it.
Tuning Knobs
| Knob | Default | Range | Category | Rationale |
|---|---|---|---|---|
PreloadLeadTime | 600 s | 300–1,800 | gate | Tide's knob — cited, not owned (tide Tuning Knobs); LDU consumes the notice |
bagFillSecs (readout input) | 90 s | 45–180 | curve | Estimated on-land harvest time per full bag; retained for authoring estimates, no longer feeds a gate (Rule 7, C3) |
nodeVisitSecs (readout input) | 20 s | 10–40 | curve | Walk-to + three swings per node at 6 u/s, feeds Rule 7's stripTimeEstimate readout only; refine from playtest telemetry |
EvictionGrace | 20 s | 10–60 | gate | Tide's knob — cited, not owned (tide Rule 9 / Edge Case 11): the drift-out window after φ+W during which the land is visible, non-interactable, violet-held, and the AFK force-relocation fires at expiry; LDU despawns and unloads at its expiry. (Replaces the separate teardownGraceMs 500 ms this spec briefly owned — retired 2026-08-27, cross-GDD W1: two windows for one transition.) |
LDU-owned values live in assets/data/land-dock.json; traversalProfile lives per-template in the template's own data.
Acceptance Criteria
- [ ] [UNIT]
layout(template, variationSeed)is pure: same inputs → byte-identical placement across runs, machines, and reloads; differentcycleIndex→ different placement, same node counts/types. - [ ] [UNIT]
KnownLandTemplatesappends exactly at firstφactivation — a preloaded-but-never-activated template is absent; a template docked once in history is present forever after (no removal path exists — schema-negative). - [ ] [UNIT] Fresh world creation → starting template(s) already in the registry before any docking (crafting AC-48's other half).
- [ ] [UNIT] Sole-source guard: pool missing a known recipe's input source template → loud warning naming recipe + template; load proceeds.
- [ ] [UNIT] The party-strip readout recomputes
stripTimeEstimate(2)andstripTimeEstimate(5)per template from live constants (nodesPerLand,nodeVisitSecs, supply, bag constants,traversalProfile) and emits them; the test asserts only that both compute and react arithmetically to a perturbed input (BB AC-45b's shape) — no threshold is asserted; the prior≥ 1.0party-clock assertion is retired (cross-GDD review C3, 2026-08-27). - [ ] [INTEGRATION] Full lifecycle round-trip: preload → activate at
φ(nodes placed, diffs applied by Harvesting's reconcile, enemies spawned via the Enemy AI call) → soft-close atφ+W→ teardown → assets unloaded — the spike scenario reproduced under NGO runtime. - [ ] [INTEGRATION] Teardown never races the soft-close deposit: a player on the land at
φ+Wis deposited home (tide Rule 9) before despawn. - [ ] [EXPERIENTIAL] Drift-in reads as arrival (not pop-in) and departure visibly "lets go" over tide's
EvictionGrace— playtest eye test. - [ ] Regression: activating/tearing down a land never mutates
HarvestDiffsemantics (Harvesting owns application), never triggers crafting/BB commits, and never blocks the home island's simulation.
Systems Index
Already tracked as MVP system #8 (Core, quick-spec, "Round-trip validated (spike)"). On approval: status → Designed (quick-spec) — crafting's LDU ⚑ rows reconcile, harvesting OQ8's LDU half and BB OQ2 get their owner, and the tide's Interactions row stands as written.
Forward refs owned elsewhere: Addressables group layout + label scheme, lifecycle edges, LandNet, per-template MB budget (64 MB) → ADR-0005 (2026-08-28); registry replication to clients → netcode ADR; template asset MB budget → asset pass; guard-variation delivery → Enemy AI quick-spec (its half of harvesting OQ8); Tier 1 multi-socket layout + socketNoBuildRadius re-check → Tier 1 pass (named here, BB OQ2).