DRIFTLANDS co-op survival on drifting tides — studio progress

Harvesting & Resource Nodes

Status: Designed — independent review applied
Author: Jeroen + agent panel
Last Updated: 2026-08-26
Independent /design-review: NEEDS REVISION 2026-08-26 — all findings applied same day (C1 supply ratio 2.19 corrected in Formulas + AC-28; C2 unharvested-% claim reworked with endpoints; C3 pairwise phase-knob ranges + Edge Case 10b monotonic-band load guard + AC-33b + hard-ceiling 2.0 now load-enforced; H4 windup-tell anticipation rule; H5 memorization honesty clause + Enemy AI live-variance dependency + OQ8; M1 soft-close deposit restated (Edge Case 5b); M2 trip-texture note; M3 no-discard ruling; M4 OQ6 escalated; M5–M7 + L-pass citations/examples. Full report: design/reviews/harvesting-system-review-2026-08-26.md)
Creative Director Review (CD-GDD-ALIGN): CONCERNS 2026-08-26 — all applied same day (C1 supply-invariant scope honesty + deferred trip-count companion; C2 modifier warn ceiling 1.2–2.0, ≤2.0 binding on Crafting; A1 carcass placement purity constraint; A2 fresh-kill silhouette test; A3 Fellowship framing on OQ6). Sinew carcass node ruled LEGAL under Pillar 3 on placement-independence grounds.
Implements Pillar: Pillar 1 — The Tide Waits for No One (harvesting is what the deadline acts on); Pillar 3 — Made by Our Hands (primary material source); serves Discovery aesthetic (#1)

Overview

Harvesting is how the tide's riches become the party's materials: walk up to a resource node on a docked land — an ore seam, a fiber stand, a timber snag — and strike it. Every node is a fast, chunky interaction (a few swings, a satisfying burst of yield straight into your bag), never a hold-to-channel; richer and rarer nodes sit deeper inland, so what you harvest is decided by how far you dare push before the land departs. Beneath the verb sits the machinery the tide demands: node placement and contents are seeded per docking by the scheduler, every node's depletion is host-authoritative shared state recorded as harvest diffs keyed to that specific docking, and harvest legality is checked against Docked at the moment each swing's yield lands — legal until the exact undock instant, gone the moment after. When a land departs, its unharvested nodes leave with it, and when it recurs, it returns regrown: the tide never keeps a tab. MVP ships 2–3 resource types feeding cloth-tier crafting; yields enter the world only through the bag on someone's back (Pillar 3 — no drops, no vendors).

Player Fantasy

Harvesting's fantasy is **the push you shouldn't have made — and made anyway**: you are always deciding whether this is the trip where you go one node too far. The anchor moment: a violet-lit vein deep inland, home out of sight behind the treeline, the bag nearly full and the land groaning at its edges. Two more swings clears the vein; three more reaches the rare seam behind it; the tide-clock has gone full blue. You swing anyway — the burst hits your bag as the ground goes translucent under your boots, and you're already running, laughing in voice chat before you reach the shore threshold. The arc of a good haul is **appetite → bet → sprint → shared relief**. Harvesting's triumph is deliberately noisier and more social than combat's quiet mastery: not "I placed that strike," but *"we got it out in time."*

Its necessary shadow is the disciplined trip — the boring, correct haul home with a half-empty bag because you did the math right and the land simply didn't offer more. Not every trip is the story; some trips are the tax you pay the tide. And the fantasy's long echo is provenance: weeks later, someone forges the group's first bronze sword and you can still name the land its tin came from — docked once, at 2 a.m., seen only by you before it left half-harvested. The veins you lost become group ghost stories exactly as readily as the ones you banked (concept: "missed lands become group lore").

The tide reads as weather, never as a game-show buzzer: indifferent, legible, negotiable by speed alone. The world states facts and never judges — a missed vein is "the land left with it," never failure copy. A caught player is deposited home with the bag intact (tide Rule 9) — the sprint for the shore is pride and texture; the cost of staying too long is the vein you didn't clear, never the bag you filled.

*(Honesty clause — independent review H5: after the first few dockings of a template, the bet narrows from discovering an unknown to executing under a known plan — you know the route; the question is whether tonight's guards, detours, and partners let you run it. That narrowing is the design — earned literacy, same as the tide clock — and what keeps the decision live across repeat visits is guard variation, a named load-bearing dependency on Enemy AI.)*

**Tone and design tests this fantasy imposes (binding on future harvesting features):**

Reference anchors: Minecraft for the chunky, immediate swing feedback; Escape from Tarkov (soft version only) for "what you carry isn't banked until it's home" — opportunity cost, never loss of what you had. Divergences so calibrated players arrive braced: against Minecraft, **the world heals** — nodes regrow on recurrence and the land itself leaves; nothing you mine stays mined. Against Tarkov, extraction has no death stake at all — being caught at departure deposits you home, bag intact; the only loss is what you never swung at.

Detailed Design

Core Rules

States and Transitions

Node (stored fact: swingsRemaining only; state labels are derived):

From Event To Notes
Intactsuccessful swing resolvesPartiallyDepleted / DepletedswingsRemaining -= 1; Depleted when it reaches 0
PartiallyDepletedsuccessful swing resolvesPartiallyDepleted / Depletedsame decrement
Depleted—(no transitions)illegal target — same family as a dead enemy in combat F3
anysoft-close at φ+Wteardowndiff final (tide Rule 9); the node ceases to exist
—recurrence (new cycleIndex)Intact (fresh instance)regrown; the old diff can never match the new key

Swinger: reuses the Strike phase shape (Harvest:Windup → Active → Recovery) with harvesting-owned durations; dash cancels Windup only; the Hurt overlay never blocks (Rule 3). **A harvest intent is accepted only from Idle/Move** (host-validated, Edge Case 15) — intents sent while Dashing or mid-swing are rejected as silent no-ops; this single rule closes both the out-of-order and the intent-while-dashing cases.

Feedback authority split (port of combat's binding table):

Effect Timing
Swing animation, swing sound, impact sparks/chips on the node surfaceInstant — client-predicted (outcome-independent)
Node crack-stage change, yield burst VFX, yield-into-bag flash, swingsRemaining mutation, diff writeHost-confirmed broadcast only

swingsRemaining replicates continuously to nearby clients — crack stages inform the approach decision before anyone commits a swing. Replication mechanism: ADR-0010 §4 (2026-09-11) — swingsRemaining is a row of LandNet.Nodes (NetworkList<NodeNetRow>), written before the land's spawn and on every Decrement; crack stages derive from it on every client.

Interactions with Other Systems

System Harvesting consumes Harvesting provides Interface owner
Tide SchedulercycleIndex/epochIndex (asked, never recomputed); Docked gate re-sampled at completion tick (H1)Diffs written under scheduler-reported keysScheduler owns cycle math; Harvesting owns diff content + write timing
InventoryCanAdd/Add at resolution (atomic)itemId + amount per landed swing; full-bag no-op behavior (delegated to Harvesting by Inventory Rule 3)Inventory owns stacks/capacity; Harvesting owns what-and-how-much
Save & PersistenceReconcile-on-load validity predicate (tide's shape)HarvestDiff = {(epochIndex, socket, cycleIndex, nodeId), swingsRemaining} — sparse: untouched nodes write no rowHarvesting owns diff schema + reconcile semantics; Save owns storage format. Quick-spec ✅ 2026-08-26 — HarvestDiff is the ONLY droppable table (two-class rule)
Land Dock/UndockNode spawn at dock (fresh swingsTotal), teardown at soft-close—LDU owns placement from variationSeed; Harvesting owns depletion state after spawn
Combat— (peer; shares the re-sample principle and the Strike input/phase shape only)The disambiguation rule (enemies win, Rule 2)Peer — no shared tuning constants, by Rule 1
Enemy AIAmbient threat near valuable nodes (no direct API)Handshake constraints: guard presence must scale with node value (joint with Land Dock/Undock); fauna enemies never drop materialsEnemy AI owns behaviors; this GDD owns the constraints
Crafting (downstream)—Material stacks via Inventory (no direct coupling); provenance mechanism ⚑ Crafting/InventoryMediated entirely through Inventory
UI/HUD—Crack-stage derivation (from swingsRemaining/swingsTotal, presentation-only), full-bag cueHarvesting owns derivation; UI owns visualization

Formulas

All harvesting math is deterministic and integer — no RNG anywhere in the yield path (house zero-variance rule; tide-style seeded content provides all variety). round() where it ever appears means round-half-away-from-zero (MidpointRounding.AwayFromZero), matching combat's pinned mode.

Baseline content values (cloth tier, MVP)

Constant Value Rationale
swingsTotal (all node types)3Locked by concept ("three swings, satisfying burst"); one node ≈ a beat, not a channel
yieldPerSwing — Shore band3Node total 9 ≈ 45% of a stack (20) — a slot fills in ~2 nodes' walking-and-swinging
yieldPerSwing — Mid band4Node total 12; 1.33× shore
yieldPerSwing — Deep band5Node total 15; 1.67× shore — the bet pays visibly
Nodes per land template40 (20 shore / 14 mid / 6 deep)50/35/15% split; deep is scarce by design
Band type skewShore: fiber-heavy · Mid: timber-heavy · Deep: sinew + rare fiberEach band answers "why come here"

Supply-vs-haul check (the Pillar 1 invariant): total land supply = 20×9 + 14×12 + 6×15 = 438 units; effective haul per trip = bagSlots(10) × maxStack(20) = 200 units; **supply ratio = 438/200 = 2.19 — a perfectly efficient player needs at least 3 full trips (⌈2.19⌉)** to strip a land. A casual 2-player session (~15–25 nodes visited between them, avg 10.95 units/node) hauls ~165–275 units, leaving ~37–63% of the land unharvested at departure — and even two completely full bags (400 units) cannot strip the 438-unit supply in one trip. The tide always takes something.

**Exported cross-system constants (added 2026-08-27, Base Building design-review BL-1):** the session-haul figures derived above exist as named constants owned by this GDD — downstream CI gates bind to them by name and must never re-derive or hardcode them:

Constant Value Derivation
lowEndPartyHaul165 unitsLow end of the ~165–275 casual 2-player session haul (15–25 nodes × 10.95 avg units/node, above)
mixedHaulTimberPerSessionLow58Party-scoped (the same 2-player casual session as lowEndPartyHaul). Timber share of a casual mixed haul: mid band is 38% of land supply (168/438), routing skew widens to ~35–50%; low end = low haul × low share = 165 × 0.35 = 57.75 → 58. (Re-derived 2026-08-27, BB re-review CS-2: the prior 70/120 did not follow from this arithmetic — it cleared BB's perimeter gate with zero margin and read as reverse-engineered from it; BB shrank its perimeter anchor instead.)
mixedHaulTimberPerSessionHigh138Same derivation, upper end: 275 × 0.50 = 137.5 → 138

**Re-derive all three whenever yieldPerSwing, node counts, bagSlots, or maxStack change** (same trigger list as the supply-vs-haul re-run rule). Known consumer: **Base Building's bootstrapRatio and perimeterSessions CI gates (its AC-45/46)** read these constants live — a stale value here silently mis-tunes three systems' shared balance surface.

Trip-texture note (independent review M2): at these numbers the binding per-trip constraint is bag capacity, not the clock — the fantasy's time-capped sprint trip occurs mainly near departure windows; most disciplined trips end "bag full," not "tide turning." Whether that mix feels right is Open Question 4's playtest; LDU's informational stripTimeEstimate readout (its Rule 7) is what makes strip times visible at authoring — no gate measures the clock (cross-GDD review C3, 2026-08-27). The fantasy text is aspirational on this axis until then. **Re-run this check after any change to yields, node counts, bagSlots, or maxStack** — if total supply / (bagSlots × maxStack) < 1.5, a single trip can strip a land and Pillar 1's tension dies.

**Scope honesty (CD-GDD-ALIGN C1, 2026-08-26; restated 2026-08-27, cross-GDD review C3): this ratio is per-harvester, calibrated to MVP's 2-player scale**. The party-adjusted ratio (÷ concurrent harvesters) is 1.10 at 2 players and 0.44 at 5. **At party scale nothing protects the supply — not this check and not the clock.** The earlier claim that "Pillar 1 is protected by the clock (travel time inside W)" was false: W is 44 hours, and even inside a single two-hour session five harvesters strip a 438-unit land in roughly ten minutes (the LDU party-clock gate built on that claim could never pass and is retired — LDU Rule 7). The honest statement is Rule 12's: a coordinated full-clear is a Fellowship achievement, not a bug, and **Pillar 1's tension is per-session opportunity cost** — the nodes the group chose not to reach tonight, the land that leaves before the next session — never supply scarcity. This check therefore guards exactly one thing: that a single efficient harvester cannot strip a land in one trip. A future retune must not read a passing ratio as party-scale coverage. LDU keeps traversalProfile and an informational stripTimeEstimate readout (no assertion) so strip times are visible at authoring. Tier 1 revisit owned by Open Question 1.

F1. harvestYield

harvestYield = round(yieldPerSwing(nodeType, band) × harvestModifier)

Variables:

Variable Symbol Type Range Description
Per-swing yieldyieldPerSwingint3–5 (band table)Data-driven per node type and band
Harvest modifierharvestModifierfloat1.0 (MVP, fixed) — Tier 1 tool values TBD by CraftingThe tool hook, sibling of combat's DamageModifier: Harvesting owns the signature, Crafting owns the values. Tier 1 tools are efficiency modifiers, never hard gates (Pillar 5 — any weapon harvests any node, always). Binding ceiling on Crafting (CD C2): the top-tier-to-bare-hands ratio must stay ≤ 2.0 — beyond that, efficiency becomes de facto gatekeeping and reintroduces the power divergence the flat-stats decision cut (game-concept, Core Mechanics 5)
ResultharvestYieldint≥ 0Units granted per landed swing, gated by CanAdd (Rules 6–7)

Output Range: 3–5 at MVP (modifier fixed at 1.0); bounded by the tool ladder at Tier 1. Example: deep-band sinew node, no tool bonus: round(5 × 1.0) = 5 per swing, 15 per node. **Midpoint example (the pinned rounding mode is load-bearing here):** at a Tier 1 modifier of 1.5: shore round(3 × 1.5) = round(4.5) = 5; deep `round(5 × 1.5) = round(7.5) = 8` — half-away-from-zero decides both, deterministically.

F2. nodeTotalYield (derived)

nodeTotalYield = swingsTotal × harvestYield — never stored, always computed; the diff stores only swingsRemaining (Rule 4). Worked check: shore fiber = 3 × 3 = 9 ✓ matches the baseline table.

F3. Trip-fill pacing check (design-time)

nodesPerStack = ceil(maxStack / nodeTotalYield) → shore: ⌈20/9⌉ = 3 nodes per stack; a focused 15–30 min trip visiting 12–18 nodes fills 4–6 slots — meaningful without demanding the full bag every trip. Scope: this is the all-shore case — mid (⌈20/12⌉ = 2) and deep (⌈20/15⌉ = 2) nodes fill stacks faster, so a mixed-band push fills the bag in fewer nodes. Re-run alongside the supply-vs-haul check when retuning.

F4. HarvestDiff — data contract, not a formula

`HarvestDiff = { key: (epochIndex, socket, cycleIndex, nodeId), swingsRemaining: int } with 0 ≤ swingsRemaining ≤ swingsTotal(nodeId). swingsTotal` is static content data, never persisted per-instance (a rebalance can't corrupt old diffs); untouched nodes write no row (mirroring the tide diff-key design, which likewise never persists rows for untouched state); Depleted is representable as swingsRemaining: 0 — no boolean. Yield-taken history is deliberately not recorded — the bag owns what was taken; the diff owns only what remains. Example row: {key: (0, 1, 2, "shore_fiber_014"), swingsRemaining: 1} — one swing left, two taken. (Self-declared non-formula — the documentation convention follows combat F6; ranges live here and in Tuning Knobs.)

Edge Cases

Tide soft-close legality and same-tick contest rules originate in Core Rules 6–8; entries below restate them in edge-case form where a QA tester would look for them, and add the genuinely new rulings.

Disconnects

Tide boundaries

5b. If a player is still on the land at φ+W (restatement): they are deposited at the home shoreline with carried inventory untouched (tide Rule 9 / AC-23; also restated by combat and the Inventory quick-spec). Being caught costs position and the unharvested land — never bag contents. Stated here so this doc stands alone (independent review M1).

Config validation (load-time, fail loudly)

10b. **Non-monotonic band yields (`yieldPerSwing[deep] ≤ yieldPerSwing[mid] or yieldPerSwing[mid] ≤ yieldPerSwing[shore]`)** → loud reject — the push-inland premise is a load-enforced invariant, not a table footnote (independent review C3).

Bag interplay

Co-op

Death / Downed

Recurrence / persistence

Scope closures

Dependencies

Upstream (Harvesting depends on):

System Hard/Soft Interface consumed Status
Tide SchedulerHardcycleIndex/epochIndex asked, never recomputed; Docked re-sampled at completion tick (H1); teardown-after-resolution ordering (Edge Case 6)GDD Reviewed — tide's Interactions table already carries the Harvesting row (bidirectional ✓)
Inventory & HaulingHardCanAdd/Add atomic at resolution; full-bag semantics delegated to Harvesting by Inventory Rule 3Quick-spec written 2026-08-26 ✓
Land Dock/UndockHardNode spawn from variationSeed (placement/type/count per docking); teardown at soft-closeQuick-spec ✅ 2026-08-27 — Rule 2 owns placement from variationSeed, Rule 8 socket layout; contract confirmed
Save & PersistenceHardStores/restores sparse HarvestDiff; drops stale/orphaned diffs per Edge Cases 19–20Quick-spec ✅ 2026-08-26 (design/quick-specs/save-persistence-2026-08-26.md — droppable-reconcile stage invokes tide's predicate + these edge cases)
Art bibleConstraint sourceSilhouette-first node identity and richness readability; band terrain reads; no numeric overlaysApproved. ⚑ Art-bible fix-pass item: node rarity needs its own silhouette/size grammar that never competes with the tide's color channel

Downstream (systems that depend on Harvesting):

Dependent Hard/Soft Interface provided
Crafting & Gear (GDD Reviewed)HardThe material set (Fiber/Timber/Sinew) via Inventory; the HarvestModifier hook signature — Crafting owns values, tools are efficiency modifiers, never hard gates (Pillar 5); tool-swing durability events (Tier 1 — cross-GDD W2, 2026-08-27, crafting OQ5's harvesting half): host-side HarvestSwingLanded(swinger, toolInstance) per successful resolution, consumed by crafting F3 once tools exist — no MVP emitter
Base BuildingHard (named constants)lowEndPartyHaul, mixedHaulTimberPerSessionLow/High — the exported Formulas constants BB's CI gates AC-45/46 bind to by name (row added 2026-08-27, cross-GDD W5)
Enemy AI (quick-spec ✅ 2026-08-27)Constraint recipientAll three constraints adopted: fauna-no-drops (its Rule 10), guard-presence-scales-with-value with numbers (its Rule 9, guardDensityByBand monotonic + load-checked), and per-docking guard variation delivered as its Rule 8 — a pure function of variationSeed over composition/patrols/facing; playtest verifies it actually keeps the push decision live (OQ8)
UI/HUD (quick-spec ✅ 2026-08-27)SoftCrack-stage derivation, full-bag cue

Bidirectional-consistency obligations: tide↔harvesting rows verified consistent both ways (2026-08-26); Inventory's Rule 3 explicitly delegates full-bag behavior here ✓; Land Dock/Undock, Save, Enemy AI, and UI/HUD quick-specs, when authored, must list Harvesting as a dependent and consume these interfaces exactly. Combat is a peer, not a dependency — shared Strike input/phase shape and the re-sample principle only, each stated independently (matches combat's own "Harvesting is a parallel peer" note).

Forward references owned elsewhere: intent RPC shape, resolution-tick scheduling, swingsRemaining replication, intent state-validation mechanism → netcode ADR. harvestModifier values, item definitions, provenance mechanism → Crafting GDD. Node placement per template → Land Dock/Undock quick-spec. Diff storage format → **Save quick-spec**.

Tuning Knobs

Not tuning knobs (rules, locked by this GDD): deterministic yields (no RNG), all-or-nothing CanAdd, sparse diff schema, enemies-win disambiguation, damage-never-interrupts, no partial credit at undock, fixed content (no party scaling), tools-never-gates. Changing any of these is a design change requiring GDD revision, not a config edit.

Knob Default Safe range Too low Too high Interacts with
harvestWindup0.10 s0.08–0.15 (pairwise: 0.08 legal only if harvestActive ≥ 0.10)Latency stops hiding in the swingNodes feel mushyGuard: harvestWindup + harvestActive ≥ 0.18 s — resolution must sit ≥ 1 RTT after intent (bounds the stale-state window; same netcode invariant shape as combat's swing guard, independently owned)
harvestActive0.10 s0.08–0.15 (pairwise: 0.08 legal only if harvestWindup ≥ 0.10)same guardSwings feel floatysame guard
harvestRecovery0.05 s0.03–0.10No rhythm, feels like a channelWhiffs on depleted nodes over-punisheddash-cancel exists only in Windup
harvestRange1.6 u1.4–2.0Face-hugging nodesHarvesting across visual gaps reads wrongNo arc/range tolerance widening — the target is static; forgiveness is a latency device, not needed here
yieldPerSwing (shore/mid/deep)3 / 4 / 52–8 per bandTrips feel unproductiveStrip-mining; Pillar 1 diesRe-run the supply-vs-haul check after any change; bands must stay strictly monotonic (deep > mid > shore) or the push-inland premise dies
swingsTotal32–4Nodes pop, no beatDrifts toward channel feelConcept anchor is 3 ("three swings"); crack-stage count follows it
nodesPerLand (shore/mid/deep)20 / 14 / 630–60 totalLand feels emptySupply check fails; visual cluttersupply-vs-haul check; land template authoring (LDU); retune preserving the ~50/35/15 band split — total alone doesn't protect deep scarcity
harvestModifierWarnCeiling1.51.2–1.8 (must stay < 2.0 or the warn band is empty)Tuning experiments naggedDe facto gatekeeping — power divergence returns (CD C2; hard ceiling 2.0 = the F1 binding constraint on Crafting, load-enforced per Edge Case 9)Edge Case 9's warn/reject thresholds

Knob-interaction warnings: yieldPerSwing, nodesPerLand, bagSlots, and maxStack form one balance system — retune together and re-run the Formulas supply-vs-haul and trip-fill checks. The harvest phase guard is a netcode invariant wearing a feel-knob costume (combat's lesson) — enforce at config load. All values live in assets/data/harvesting.json, validated per Edge Cases 7–10.

Visual/Audio Requirements

Harvesting's visual contract is owned by the art bible; this section states what harvesting imposes and cites rather than restates.

Node read contract (binding): a node must communicate three facts in silhouette at solid black, 64–96 px (§5.4), while the world moves (§1): material identity (fiber / timber / sinew — distinct shape families), richness (band/rarity read from **size and shape only — never color**: the color-temperature channel belongs exclusively to the tide clock, and nodes, being land content, are tide-tinted unlike combat sprites — every harvesting read must survive amber, neutral, and violet), and depletion state (crack stages). ⚑ This is the art-bible fix-pass item from Dependencies: node rarity needs its own silhouette/size grammar.

Crack stages: swingsTotal visual stages (3 at MVP), expressed as hard-edged shape subtraction — visible chunks missing, no gradients, no damage decals (§6.2). A Depleted node leaves a husk silhouette, not an empty space — the land visibly remembers the trip's work for the rest of the docking.

Yield burst: chunky, flat-colored, palette-locked particle burst at low count (Nuclear Throne restraint, §9); burst scale may grow with yieldPerSwing so deep-band nodes feel richer; no particle may obscure a silhouette edge (combat's rejected-VFX list applies).

Feedback timing: swing animation/sound client-predicted; crack-stage change, yield burst, and bag flash host-confirmed only (authority table in Detailed Design). Per-material impact audio (ore clink / fiber rustle / sinew tear) desirable, not MVP-blocking; yield audio lands the same frame as the burst.

Silhouette-first test for node assets (pass/fail): at solid black, 64–96 px: material identity legible; richness tier legible by size/shape; crack stage legible; a node must never read as a threat silhouette (enemy proportions are reserved, §5.2); and a carcass node must **never read as a fresh kill left by combat** (CD A2 — guard-scaled deep-band sinew must not look like loot even though it isn't).

📌 *Asset Spec note: after this GDD is approved, run /asset-spec system:harvesting-system to derive per-asset descriptions, dimensions, and generation prompts from this section.*

UI Requirements

Harvesting contributes three things to the UI layer: **world-space crack-stage feedback** (on the node itself — never a HUD health bar for nodes), a glanceable full-bag cue (a non-modal bag pulse on the fruitless-swing no-op — never an error dialog or toast, per the honest-no-op tone rule), and host-confirmed yield flyouts (the harvesting sibling of combat's damage numbers — the only numeric harvest feedback). Binding constraints: bag fill level must be glanceable without opening a menu; **no minimap or overlay may ever show node values or locations beyond sightline discovery** (Core Rule 11 restated as a UI ban); copy follows the world-facts tone rule ("the land left with it").

📌 UX Flag — Harvesting: this system has UI requirements. In Pre-Production, run /ux-design for the bag/HUD elements before writing epics; harvesting stories referencing UI must cite design/ux/hud.md, not this GDD.

Acceptance Criteria

[UNIT] = EditMode NUnit over pure logic (yield math, resolution gates, node state derivation, diff schema, config validation) — the harvest pipeline (Rule 6, F1–F4) must be designed pure/DI-testable, no live NGO session required. [INTEGRATION] = NGO runtime, Multiplayer Play Mode + Network Simulator. [MANUAL] = human feel judgment, never automated (coding standards) — but scoped to a concrete, checkable claim. All criteria use locked baseline values (cloth tier, MVP) unless the vector specifies otherwise.

Verb Shape & Commitment (Rule 1)

Disambiguation (Rule 2)

Damage Non-Interruption (Rule 3)

Node Identity & Depletion (Rule 4)

Deterministic Yield (Rule 5, F1)

Resolution Pipeline (Rule 6)

Full-Bag All-or-Nothing (Rule 7, Edge Case 12)

Contested Nodes (Rule 8, Edge Case 14)

Swinger State Re-Sample (Rule 9, Edge Cases 17–18)

MVP Resource Set (Rule 10)

Depth Bands & Content Skew (Rule 11)

Fixed Content, No Party Scaling (Rule 12)

Formulas — Worked Examples & Design-Time Checks (F1–F4)

Tide Boundary & Teardown Ordering (Edge Cases 4, 6)

Config Validation (load-time, fail loudly — Edge Cases 7–10b)

Intent Validation & Live Contention (Edge Cases 14–15)

Cross-Epoch Reconcile & Orphaned Diffs (Edge Cases 19–20)

Minimum smoke set (run first)

Three are [UNIT]; AC-30/AC-31 are [INTEGRATION] but run headless in Multiplayer Play Mode — together they run in under a minute as a pre-QA-handoff gate, matching combat's smoke-set shape.

Deliberately not criteria (and why)

Coverage note: Core Rules 1–12 and Formulas F1–F4 each have ≥1 criterion. Config-validation Edge Cases 7–10 each have a dedicated load-time criterion (AC-32–36, with AC-36 covering the Tuning Knobs phase guard). Edge Case 3 is a closure note (structurally impossible state) — covered by AC-14's atomicity claim, not independently testable. Edge Case 16 (joiner staleness) is replication behavior deferred to the netcode ADR; AC-13/AC-16 cover only the resolution-tick re-sample, which is orthogonal.

Open Questions

# Question Owner Target
1Fixed node content at 5 players — does depth stay a real bet, or does Tier 1 need a different posture? (locked fixed at MVP; pure-function world preserved)Tier 1 design pass + playtestTier 1
2HarvestModifier tool values and tool item design (efficiency-only, never gates)Crafting GDDSystems Design phase
3swingsRemaining replication strategy, intent RPC shape, host state-validation mechanism (Edge Cases 15–16)Netcode ADRAfter friend-group playtest
4Per-swing yield (locked) vs final-swing burst — does the chunky beat land in practice, tested over a full 12–18-node trip (fatigue), not a single node? Also: does the bag-capped trip texture (see Trip-texture note) leave the clock-pressure beat frequent enough?MVP friend-group playtestPost-MVP tuning
5~~Sinew carcass-node fiction and the fauna/enemy boundary (fauna never drop materials — how do carcass nodes spawn?)~~ RESOLVED 2026-08-27 — LDU Rule 2 places carcass nodes as pure variationSeed content; Enemy AI Rule 10 binds fauna to never drop materials or spawn a carcass (cross-GDD W6)~~Enemy AI quick-spec + Land Dock/Undock~~ ResolvedDone
6Do contested-node and full-bag no-ops need subtly distinguishable cues, or stay identical? (mechanically identical by design) Fellowship #2 exposure (CD A3): "my bag is full" and "Alex got there first" carry different co-op coordination meanings — presentation-only differentiation may be required to preserve the coordination signal/ux-design + playtestBefore the first friend-group playtest (escalated by independent review — a distinct presentation cue is cheap and rules-legal)
7~~Reconcile the provisional Save & Persistence diff row when its quick-spec is authored~~ RESOLVED 2026-08-26 — save-persistence quick-spec Rule 5 (droppable-reconcile stage) + Rule 6 (HarvestDiff is the only droppable table)~~Save quick-spec~~ ResolvedDone
8Repeat-docking Discovery: with deterministic content and 2–3 MVP templates, routes are solvable by ~session 4. This GDD deliberately does not provide per-visit variance — it is owned by guard variation (Enemy AI) and the concept's "recurring lands return possibly changed" retention hook. LDU half ANSWERED 2026-08-27 (LDU quick-spec Rule 6): at MVP "changed" = per-docking node/spawn placement variation via variationSeed — template content stays fixed; authored revisions are Tier 1. Enemy AI half: mechanism NAMED 2026-08-27 (enemy-ai quick-spec Rule 8 — guard composition/patrols/facing as a pure function of variationSeed); whether it actually keeps repeat visits live is the remaining playtest question.~~Both quick-specs~~ Playtest verification onlyPlaytest