acdream/docs
Erik 4e290f00d8 feat(net): N5 - loss observability, lossy decorator, the connected loss gate
Campaign N Slice N5 (docs/plans/2026-07-29-network-transport-campaign.md
section 8 rung 3): the permanent removal of the loopback blindness that let
#260 ship. Local ACE never drops a datagram, so every historical connected
gate was structurally incapable of exercising the N1-N4 recovery machinery;
from this slice on, tools/run-connected-loss-gate.ps1 runs the standard
lifecycle route through deterministic seeded loss and passes only on proven
non-zero recovery.

Observability:
- [net-tick] gains resend/s nak-out/s nak-in/s rej-in/s dup-drop/s parked/s
  reclaim/s cache= nakset= - TransportStats window deltas mirroring the
  acks/s cumulative-delta pattern, plus the two instantaneous depths (the
  unbounded-like-retail sent-packet cache watchdog and the inbound NAK set).
  TransportStats gains RejectsReceived (inbound RejectRetransmit packets).
  Counters increment unconditionally; every string is behind
  NetDiagnostics.ProbeNet (Code Structure Rule 5).
- WorldSession.Dispose emits one cumulative [net-final] totals line so the
  loss gate asserts exact counters instead of reconstructing them from
  rounded per-second rates.
- LinkStatusSnapshot.PacketLossPercentage is deliberately NOT wired: filed
  #261 - retail's CLinkStatusAverages formula
  (LinkStatusHolder::GetPacketLossPercentage @ 0x00411370) must be located
  first; inventing a ratio is forbidden.

N4-review F3 fold-in:
- Fresh reliable sends stamp Header.Iteration = the session iteration
  through the same shared retail header build already cited for Time (N3)
  and the N4 control packets: FlowQueue::TransmitNewPackets @ 0x00547A60,
  the stack build at 0x00547A84/0x00547AA8. The control-header rule now
  holds across all three send shapes (fresh reliable, ack, NAK). ACE reads
  neither Time nor Iteration inbound (campaign section 3) - wire-safe, and
  resends keep the stamp verbatim per the N1 rebuild rule.

Loss injection (Transport/LossyTransportDecorator):
- IWorldSessionTransport wrapper with deterministic seeded per-direction
  loss. Config via NetDiagnostics typed env properties read once:
  ACDREAM_NET_DROP_PCT (0 = off = default), ACDREAM_NET_DROP_SEED (default
  1), ACDREAM_NET_DROP_DIR (out|in|both, default both).
- Arming gate: NOTHING drops in either direction until the decorator has
  FORWARDED the first ENCRYPTED outbound datagram - parse-free check on
  length > 20 with EncryptedChecksum set in the LE flags word at bytes
  4..8. The cleartext handshake always survives and the arming datagram is
  never a casualty; handshake-loss testing belongs to N6's ConnectResponse
  0.333 s retransmit.
- Structurally absent at 0%: WrapIfConfigured returns the raw transport -
  WorldSession's default factory is the only production seam and a normal
  run never constructs the decorator.

Root-cause fix the gate immediately exposed:
- The logoff-confirmation wait in Dispose processed inbound datagrams but
  never pumped the transport, so a lost S2C logoff confirmation was
  gap-detected but its healing NAK never went out. Retail's pump
  (Client::UseTime @ 0x00411C40 -> PacketController::UseTime @ 0x005410D0)
  runs until LogOffServer; the wait now sweeps per processed datagram,
  making the logoff wait the third covered blocking pump (after Tick and
  the handshake loops). A lost C2S logoff REQUEST remains unrecoverable by
  ACE design (arrival-driven NAK; a quiet client is never NAKed - campaign
  section 3 row 1), recorded in the gate header.

Gates:
- tools/run-connected-loss-gate.ps1 (-DropPct 2 -Seed 1): PASS vs local
  ACE - the first automated observation of packet loss in project history.
  Decorator ledger: dropped out=3 in=10 of forwarded out=183 in=496.
  [net-final] resends=2 nak-in=2 nak-out=6 rej-in=0 acks-out=114
  acks-in=119 dup-drop=0 sanity-drop=0 cksum-fail=0 parked=9 reclaimed=0
  uncached-nak=0 cache=1 nakset=0. Every injected loss healed: both
  ACE-driven C2S resend recovery (nak-in=2 -> resends=2) and client-driven
  S2C NAK recovery (parked=9 -> nak-out=6) fired on a real connected
  route, all six checkpoints validated, graceful logout confirmed, ACE
  recorded the transport Disconnect.
- tools/run-connected-world-lifecycle-gate.ps1 (decorator absent): PASS -
  zero behavior change on the no-loss baseline; the gate now defensively
  clears the drop env vars.
- Core.Net Release: 747/747 (737 + 10 N5: decorator determinism/direction/
  arming/structural-absence/env parsing, the 5% seeded WorldSession lossy
  lifecycle with zero message loss both ways + ACE Headroom 256, the
  [net-tick] field pins, the Iteration stamps).
- Full solution Release: 9,763 passed / 5 skipped / 0 failed.

Test-fixture note: FakeAceTransport gains AutoAdvanceOnBlockingReceive so
virtual time can move during the blocking Connect()/EnterWorld() pumps -
with the clock frozen there, a dropped handshake-window datagram could
never be NAK-healed (a fixture artifact, not a transport property).

Campaign section 9 ledger row added (SHA recorded at N6 kickoff).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 16:26:06 +02:00
..
architecture docs(net): N4 accepted - Opus review PASS; AP-125 filed; F1/F5 fixed 2026-07-29 15:40:34 +02:00
audit docs: update audit — Sprint 1 items verified (sequence counters + scenery LCG) 2026-04-13 13:51:39 +02:00
plans feat(net): N5 - loss observability, lossy decorator, the connected loss gate 2026-07-29 16:26:06 +02:00
reference docs(reference): preserve local ACE command catalog 2026-07-27 00:03:58 +02:00
reports docs: the overnight consolidation report, open questions first 2026-07-29 03:54:43 +02:00
research feat(core): adopt retail's SoundType catalog; retire AC2D 2026-07-29 07:38:56 +02:00
superpowers fix(world): remove non-retail portal exit fade 2026-07-15 23:20:52 +02:00
bugs.md docs: reconcile project status and navigation 2026-07-20 13:00:41 +02:00
ISSUES.md feat(net): N5 - loss observability, lossy decorator, the connected loss gate 2026-07-29 16:26:06 +02:00
README.md docs: reconcile project state and refresh README 2026-07-27 12:53:31 +02:00

acdream documentation map

This page is the entry point for project documentation. It distinguishes current sources of truth from implementation history so an old plan or issue banner cannot silently override the current program state.

Current snapshot — 2026-07-27

  • Milestone state: M3, “Cast a spell,” landed 2026-07-21. M4, “Live in the world,” is active.
  • M4 gameplay program: resume the pre-M4 world-interaction completion program. Favorite-spell overflow, status Use/Assess, and the complete assessment surface are user-accepted. Equipped-child picking and vendor browse/transactions remain Slices 46.
  • Structural/runtime state: all eight GameWindow decomposition slices, Modern Runtime Slices AJ, and the connected visual/lifecycle gates are complete. GameWindow is a 1,622-line composition/callback shell. AcDream.Runtime.GameRuntime owns canonical session, entity/object, gameplay, movement, physics, projectile, environment, and portal state; graphical and no-window hosts borrow the same owner graph.
  • Headless state: Slice K is complete. AcDream.Headless is a presentation-free Windows/Linux host with deterministic commands/events, shared immutable content, multi-session isolation, reconnect, resource telemetry, and 1/5/10/30-session gates. The final two-account native-Linux soak completed ten minutes, logged out through ACE, and converged every ownership ledger.
  • Linux graphical state: Slice L0 and the L1 implementation checkpoint are complete at 66f114b2 and 11501d52. Native Windows passes the active modern-GL/audio/window smoke. WSLg X11/Wayland correctly reject their missing GL_ARB_bindless_texture. Physical-Linux validation and L2L6 are explicitly deferred; resume at the supported AMD/NVIDIA L1 gate.
  • Completed gameplay gates: R6 locomotion/collision/projectile/teleport/ radar, two-client portal-out/materialization, indoor prepared collision, loot ordering, local/remote ground drops, and selection-marker lifetime.
  • Separate visual verification: issue #225, the shared-alpha lifestone/particle result; its connected resource-lifetime and performance routes pass.
  • Carried behaviour debt: issue #153 (far teleport onto an unstreamed edge), #116 (narrowed slide response), #235 (capped/RDP jump cadence), and the active temporary-stopgap rows in the divergence register.
  • Divergence audit: 189 active rows — IA 18, AD 38, AP 91, TS 38, and UN 4 — plus retained struck/retired historical rows such as TS-37.
  • Latest automated baseline: the Release build succeeds with the 17 test-project warnings tracked by issue #228; 8,826 tests pass and five are intentionally skipped. App passes 3,763 / 3 skips. The L1 Windows supported smoke and WSLg X11/Wayland negative-capability reports all end with zero window/GL/input/audio ownership.

Sources of truth

Read these in this order when deciding what to do next:

  1. plans/2026-05-12-milestones.md — the active playable outcome, freeze boundaries, and visual gates.
  2. plans/2026-04-11-roadmap.md — strategic phase ledger: shipped, active, deferred, and future work.
  3. ISSUES.md — tactical defects and small follow-ups. The status inside an issue is authoritative; physical order is not.
  4. architecture/retail-divergence-register.md — every known place runtime behavior can differ from retail.
  5. architecture/acdream-architecture.md and architecture/code-structure.md — ownership, dependency, update-thread, and extraction rules.
  6. architecture/worldbuilder-inventory.md — rendering/DAT code already owned in-tree versus mechanisms still ours to port.

If these disagree, milestones control the current outcome, the roadmap controls work ordering, the issue status controls the individual defect, and the architecture documents control implementation shape. Reconcile the stale document in the same change; do not leave both claims standing.

Research and implementation records

  • research/named-retail/ is the primary retail oracle: named pseudo-C, headers, symbols, and types from the Sept 2013 build.
  • research/decompiled/ is the older Ghidra fallback.
  • research/ contains focused pseudocode, traces, fixtures, and gate reports. A dated research note records evidence; it does not become a new roadmap.
  • superpowers/specs/ and superpowers/plans/ are per-slice design and execution records. Completed plans remain historical.
  • audit/ contains completion and conformance audits.
  • reference/ace-commands.md preserves the local ACE server's complete in-game command catalog and points to the authoritative per-command help surface.

Durable memory

  • ../claude-memory/MEMORY.md indexes the live subsystem memories and the render/physics digests. Read a domain digest before changing that subsystem, especially its DO-NOT-RETRY table.
  • ../memory/ contains stable engineering references such as the modern rendering pipeline, two-tier streaming, and toolchain notes.

Memory accelerates recall; it does not outrank the canonical documents above. When current truth changes, update the relevant canonical document and distill only the durable lesson into memory.

Historical and deprecated documents

  • bugs.md is the April 2026 bug snapshot. It is preserved for archaeology and is not an active ledger.
  • Dated plans and specs describe the decision at that time. Their completion wording is historical unless the current milestone/roadmap explicitly links the item as active.
  • Old R1→R8 architecture sequencing is superseded. Current execution comes from the milestones and strategic roadmap.

Documentation maintenance rules

  • Update milestone, roadmap, issue, divergence, architecture, and memory claims in the same commit when a shipped change affects them.
  • Keep one issue ID per defect. Narrow an issue in place; do not reuse another issue's number as a shorthand.
  • Mark automated, connected, and visual gates separately. An automated pass is not a visual acceptance, and an RDP throughput sample is not a local-display visual comparison.
  • Preserve research history, but remove stale “current/next” claims from living documents once the state advances.