DRIFTLANDS co-op survival on drifting tides — studio progress

Architecture Review Report — 2026-08-28

Mode: /architecture-review (full) · Verdict: CONCERNS
Engine: Unity 6.3 LTS (6000.3) · URP 2D (Render Graph) · NGO 2.x · Input System 1.20 · Addressables 2.x
Loaded: 5 full GDDs + 8 quick-specs + art bible §4.3/§7/§8 (13 design docs) · 8 ADRs (all Proposed) · architecture.md v1.0 · engine reference (VERSION, breaking-changes, deprecated-apis, current-best-practices, modules ×4, plugins/addressables) · tr-registry.yaml (was empty) · docs/consistency-failures.md absent.
Method: three Sonnet verifiers checked every baseline row against the source doc text and confirmed the ADR-driven GDD amendments; the Unity specialist (Opus) audited every engine claim against the live 6000.3 / NGO 2.x / Addressables 2.x / Input System 1.20 docs.


Traceability Summary

architecture.md claims "102 requirements"; its table holds 94 rows. All 94 were confirmed against their source docs (3 misstated — corrected in the registry) and 17 additional architectural requirements were surfaced → 111 total, now registered as stable TR-IDs in tr-registry.yaml (version 2).

Status Count
✅ Covered64
⚠️ Partial28
❌ Gap19

Foundation layer: 0 gaps. Every gap sits in Core/Feature/Presentation and is assigned to a not-yet-written ADR (0008–0014) or deliberately deferred to implementation. The full matrix is in traceability-index.md.

Baseline corrections (registry text updated, IDs unchanged)

Coverage gaps (no ADR)

ID System Requirement Suggested ADR Domain Engine risk
TR-net-003Netcodelate-join full snapshotADR-0008 (playtest-gated)NetworkingHIGH
TR-net-005NetcodeSteam transport packageADR-0008 (playtest-gated)TransportHIGH
TR-cam-002Camerafollow + aim bias, never detachesdeferred to implementation (architecture ruling)CoreLOW
TR-move-002Movementowner-auth predicted locomotion 6 u/sADR-0009NetworkingHIGH
TR-move-003Movementcollision blocks never damages; layer matrixADR-0011Physics 2DLOW
TR-move-004Movementremotes interpolated (NetworkTransform.OnUpdate)ADR-0009NetworkingHIGH
TR-inv-002InventoryCARRY owner-rail / STORAGE host-rail instancesADR-0010NetworkingHIGH
TR-inv-004Inventoryno world items; 2 equipment slotsADR-0010ScopeLOW
TR-inv-007 newInventoryCARRY replication representation — undefined in the quick-spec and not flagged as deferred (only STORAGE is)ADR-0010NetworkingHIGH
TR-craft-008Craftingcraft beat client-predicted; host commitADR-0008 + crafting runtime ADR (see Required ADRs)NetworkingMEDIUM
TR-bb-009Base Buildingghost/grid overlay < 100 draw callsADR-0013RenderingHIGH (Render Graph domain)
TR-ai-002Enemy AIseparation steering; aggro/leashADR-0012CoreLOW
TR-ui-001/002/003UI/HUDHUD list; co-op affordances; reason stringsADR-0014UIMEDIUM (strict USS)
TR-tint-001/002/003Tide-Tintsprite shader + globals; DriftLayer; Render-Graph-native futureADR-0013RenderingHIGH
TR-tint-004 newArt/Netcodeflipbook animation via synced frameIndex (art bible §8.B.4)ADR-0008 / ADR-0012Networking / RenderingMEDIUM

Cross-ADR Conflicts

C1 — Two callers of tide Advance · Pattern / Timing · CONCERN (blocking once code exists)

C2 — clientSeq dedup keyed by clientId vs PlayerKey · State · CONCERN

C3 — Declared dependency cycles · Dependency · 🔴 flagged per protocol (substantively benign)

C4 — ADR-0006 stage 4 "telegraph ≥ 400 ms is a NEW load rule with no combat AC" · Integration · NOTE

Combat AC-20 and the telegraphFloor knob ("hard floor 400 = the Rule 11 contract") already specify the load rejection. Correct the wording; Rule = combat.AC-20.

C5 — Unarmed SwingLanded · Integration · NOTE

Combat GDD (Crafting dependency row) says durability events are "never emitted for unarmed swings"; ADR-0003 emits SwingLanded with WeaponInstance = null for unarmed so presenters get DamageDealt. Keep the ADR shape; amend the GDD row to "Crafting ignores null instances".

C6 — Knob file homes · Data · NOTE

ADR-0005 places landTemplateBudgetMB in land-dock.json; ADR-0006 §1's land-dock.json row does not list it. PreloadLeadTime is owned by tide.json (ADR-0001) and only "cited" by land-dock.json — say "read-only reference".

C7 — TR-harv-001 assignment · Ownership · NOTE

architecture.md Required-ADR table assigns harvest-node replication to row 8; ADR-0005 and §2 assign it to ADR-0010 (QQ-13). Pick one (ADR-0010 recommended — it already owns the NodesReady gate).

Known conflict-prone areas: docs/consistency-failures.md does not exist; nothing to carry forward.


ADR Dependency Order (topologically sorted, after C3 relabel)

Foundation:
  1. ADR-0001 Tide Scheduler pure assembly            (no deps)
  2. ADR-0002 Host commit model                       (0001; 0006 → Related)
  3. ADR-0003 Assembly + purity boundaries            (0001, 0002)
  4. ADR-0006 Game data loading + validation          (0001, 0003; 0004 → Amends)
  5. ADR-0004 Save format + reconcile pipeline        (0001, 0002, 0003, [0006 weak])
  6. ADR-0005 Land lifecycle on Addressables          (0001, 0002, 0003, 0004, 0006)
  7. ADR-0007 Input action map                        (0003, 0004, 0006)
Core:
  8. ADR-0015 Combat model                            (0002, 0003, 0006, 0007)
Not yet written:
  ADR-0008 Netcode wire (friend-group playtest) → ADR-0009, 0010, 0011, 0012 → ADR-0013, 0014

⚠️ Every "Depends On" currently points at a Proposed ADR (all eight are Proposed). Per the TD sign-off condition, ADRs 1–7 must be Accepted before the first implementation story; this review recommends the amendments below land first (user ruling 2026-08-28: apply amendments 1–5, then flip).


GDD Revision Flags (Architecture → Design Feedback)

No GDD revision flags — no GDD assumption conflicts with verified engine behaviour. The specialist confirmed the tide purity model, the two rails, per-drain durability, SoftClose-first and the no-offline-simulation pillar are all deliverable on 6000.3 as designed. Systems index left unchanged.

Three doc-sync items (not design revisions):

Doc Item Action
tide-scheduler.mdAC-44/45 header still says "advisory until the TD signs off"; OQ2 still open — ADR-0001 records the TD ruling as hard gatesmark AC-44/45 hard, close OQ2; if C1 resolves to per-tick Advance, the ±5 s tolerance becomes ±(5 s + 1 tick) — make that the GDD's number
save-persistence quick-specRule 2 tide block lacks socketCount (ADR-0006 amended ADR-0004 §1 but not the quick-spec)add the field
land-dock-undock quick-specRule 9 "Concrete MB budget → asset pass" vs footer "→ ADR-0005 (64 MB)"point Rule 9 at ADR-0005

Confirmed already landed: tide EC18 0.40; save Rule 3 + saveDebounceMs restatement; combat maxTargets / reviveReach rows + OQ10; movement Rule 5 downedCrawlSpeed carve-out; BB OQ6 resolved (gridCellSize = 1 u); art bible §8.A.5 / §8.B.1 atlas wording.


Engine Compatibility Issues

Engine Audit Results

Engine: Unity 6.3 LTS (6000.3) · ADRs with Engine Compatibility section: 8 / 8 · Version agreement: 8 / 8 Deprecated API references: none (every ServerRpc/ClientRpc/SetupRenderPasses/UnityEngine.Input/NetworkTransform.Update/Compatibility-Mode/Multiplay hit is in "don't use" context). Stale version references: none. Post-cutoff API conflicts between ADRs: none beyond C1.

Engine Specialist Findings (Opus, live-doc verified)

# ADR Finding Severity
E10001 vs 0015Two Advance callers — see C1CONCERN
E20007 §Post-Cutoff (a), §1 UI row"UI Toolkit consumes the UI map via PanelEventHandler with no EventSystem" — wrong mechanism. PanelEventHandler (+PanelRaycaster) is created only when a uGUI EventSystem exists and then routes through InputSystemUIInputModule; the no-EventSystem path is UI Toolkit's built-in scene-independent default runtime event system. The outcome (no components needed; project-wide UI map consumed directly; map/action names must not change) is correct.NOTE — fix the sentence
E30001 §4Whether Awaitable.WaitForSecondsAsync honours Time.timeScale is UNVERIFIED; scheduling a 600 s+ wall-clock lead on a possibly-scaled timer stalls under timeScale = 0. Timer = hint, UTC = truth. Moot if C1 resolves to per-tick Advance.CONCERN
E40004 §4Application.wantsToQuit is a synchronous Func<bool>; "return false, await FlushAllAsync, re-Quit()" needs an explicit latch (or the second Quit() re-enters and loops) and an Awaitable continuation may never resume during player-loop teardown. Use the bounded blocking wait the ADR already permits, bound by flushDeadlineMs. Add EditorApplication.playModeStateChanged for Editor parity (wantsToQuit does not fire on Play-mode exit).CONCERN
E50005NetworkList initial contents delivered before OnNetworkSpawn is not doc-attested (only NetworkVariable is) — keep the NodesReady fallback, mark UNVERIFIED not "specialist-confirmed". The NetworkPrefabHandler "~1 s" timeout figure is from the NGO 1.15 page; drop the number (the design does not depend on it).NOTE
E60002 V5, 0015 V1"Multiplayer Play Mode 2.0.x unfit for automated tests" is UNVERIFIED (forum-sourced); MPPM @latest resolves to 3.0 on 6.3. The decision (two standalone builds under Network Simulator) is safe regardless.NOTE
E70004"Newtonsoft is Unity-maintained" → Unity-distributed (v3.2.2 wrapping Json.NET 13.0.2); "STJ not in the 6.3 BCL" → "not shipped; vendoring required". Conclusions unchanged.NOTE
E80015Burst MidpointRounding.AwayFromZero bug is staff-acknowledged (Apr 2023), not confirmed still-open on 6.3; the mitigation (Rules never references Burst) is costless — keep, reword.NOTE
E90007InputFrame as a sealed record (class) ≈ 10 KB/s at 60 fps, not "~4 KB/s"; a record struct matches TideState/Cell/StrikeIntent.NOTE
E10engine-referencemodules/networking.md teaches [ServerRpc]/[ClientRpc], Input.GetKey, and server-authoritative movement — three project-forbidden patterns; modules/input.md is 1.11-era. Both need a DEPRECATED — DO NOT USE banner, not just in-ADR disclaimers.CONCERN (process)
E11processNo Unity project exists yet (Packages/manifest.json, packages-lock.json, ProjectSettings/, Assets/ absent); every package version in the ADRs is aspirational. ADR-0005's CI gate depends on a packages-lock.json pin — first implementation commit.NOTE
E120002[Rpc(SendTo.Server, Delivery = RpcDelivery.Reliable, RequireOwnership = false)] — both properties documented independently; the combined literal is not doc-attested. Valid C#; flag as inference.NOTE
E130005 V1AsyncOperationHandle.Task exists; no GetAwaiter on the handle itself in 2.x — await handle.Task is the only form; the Completed → MainThreadAsync fallback stays necessary.NOTE

Confirmed correct by live docs: NetworkTickSystem.Tick fires "before NetworkVariable changes are collected" (NGO 2.5 — the stage is still undocumented, so ADR-0002 Verification 1 stays open); reliable RPC order guaranteed per NetworkObject (NGO 2.6); NetworkVariable values delivered before OnNetworkSpawn; SubsystemRegistration precedes scene Awake; project-wide actions auto-instantiate and auto-enable; NetworkPrefabHandler asset-readiness warning is verbatim; all four Awaitable members incl. AwaitableCompletionSource<T>; all four Addressables 2.x members; Application.wantsToQuit semantics; File.Replace atomicity.


Architecture Document Coverage


Verdict: CONCERNS

Foundation is fully covered and internally consistent in substance; no engine finding invalidates a decision. Off PASS because of: two real cross-ADR inconsistencies (C1, C2), a declared dependency cycle to relabel (C3), three engine CONCERNs (E3/E4 implementation-shaped, E10 process), and 19 gaps — all Core/Feature/Presentation, all assigned to ADRs 0008–0014 whose wire halves are gated on the friend-group playtest by CD ruling. Not FAIL: no Foundation requirement is uncovered and no conflict requires re-deciding anything.

Blocking issues

None at FAIL level. Required before flipping ADR-0001–0007 + 0015 to Accepted (user ruling 2026-08-28):

Required ADRs (most foundational first)

Pre-gate checklist (checked 2026-08-28)

Re-run /architecture-review after each new ADR to verify coverage improves.


History

Date Verdict Covered / Partial / Gap Notes
2026-08-28CONCERNS64 / 28 / 19 of 111First review; 8 ADRs Proposed; TR registry v2 created
2026-08-28 (same session)CONCERNS → amendments applied—Amendments 1–5 applied to ADR-0001/0002/0004/0005/0006/0007 (+ ADR-0015 amendment table); all eight ADRs flipped to Accepted; architecture.md header/audit and technical-preferences.md ADR log synced. Open: E10 engine-reference banners, the three GDD doc-sync items, ADR-0008–0014.