acdream/docs/plans/2026-07-26-modern-runtime-slice-j3-hardening.md

7.9 KiB

Modern runtime J3.6 — adversarial lifetime hardening and closeout

Status: COMPLETE 2026-07-26 at 119b7c115107245546180b2f5cb3cb44c7d5476a Parent: 2026-07-25-modern-runtime-slice-j3.md Required production base: ce3ac310d92722ffb637e81cb1957458874dd220 Prior closeout: ../research/2026-07-26-slice-j3-5-canonical-delta-stream.md

Objective

Close the canonical entity/object lifetime group under failure, re-entrancy, reset, and disposal before J4 moves another gameplay owner.

This slice adds no feature, cross-frame/background queue, retry timer, renderer fallback, or gameplay behavior. Its synchronous re-entrant dispatch drain preserves one observer-visible sequence within the committing call. It proves that Runtime's canonical identity/object owner and App's exact-key graphical projection either complete each transaction or retain one explicitly retryable suffix, and that every terminal path converges to zero.

Fixed boundary

  • Runtime remains the sole GUID/incarnation/local-ID, accepted-wire, parent-relation, object-table, direct-view, and entity/object-event owner.
  • App remains an exact-key projection and resource host.
  • The server remains authoritative.
  • Existing synchronous retail ordering remains unchanged.
  • J4 chat, vitals, enchantments, spells/components, cooldowns, and ViewModel-facing revisions do not enter this slice.
  • A failure test may expose a production ownership defect. Fix the owning transaction at its commit/acknowledgement boundary; do not add a suppression flag, timer, retry loop, or symptom guard.

Execution

1. Pin the complete ownership ledger

Create one assertion helper that reports every J3 owner:

  • active Runtime records;
  • teardown Runtime records and claimed local IDs;
  • accepted snapshot/timestamp and parent-relation entries;
  • active and teardown App projections;
  • materialized world entities and graphical resource registrations;
  • spatial loaded/pending projection keys;
  • animation, remote-motion, projectile, root-object, effect, light, script, and equipped-child bindings;
  • object-table objects, containers, pending moves, and replacement state;
  • Runtime stream subscriptions, dispatch failures, and pending work.

The helper must distinguish an intentionally retained retry receipt from a leak. A stable terminal checkpoint permits neither.

2. Failure-inject canonical registration and hydration

Exercise failures and re-entry:

  • before and after Runtime active-record/local-ID commit;
  • same-incarnation refresh;
  • generation replacement while prior App teardown succeeds or fails;
  • projection sidecar creation;
  • world-entity factory;
  • resource registration before commit and after partial commit;
  • resource rollback before and after commit;
  • animation/physics/effect/relationship/ready publication stages;
  • observer replacement, delete, and session clear during each callback.

Prove that a still-active Runtime incarnation never loses its key, a failed partial owner remains reachable by one exact teardown receipt, and retry cannot replay create-time resources already committed.

3. Failure-inject accepted updates and placement

Cover ObjDesc, motion, vector, state, position, parent, pickup, explicit rebucket, withdrawal, and child-NoDraw:

  • stale/equal/new/wrapped timestamps;
  • loaded-to-loaded, loaded-to-pending, pending-to-loaded, and cellless transitions;
  • projection callback failure before and after the graphical mutation;
  • observer delete/recreate or same-record newer update;
  • parent event before the parent, before the child, and across GUID reuse;
  • malformed or missing-object updates.

Assert the shared stream publishes only committed canonical facts, consumes no sequence for rejected packets, never emits renderer visibility as a withdrawal, and never applies a displaced callback to a replacement incarnation.

4. Failure-inject object-table transactions

Run the exact object-table behavior through the Runtime stream:

  • create/add versus update;
  • optimistic container move;
  • confirmation;
  • rejection rollback;
  • wield/container replacement;
  • stack/value/property refresh;
  • unknown-object move;
  • authoritative entity delete;
  • dormant/offscreen delete;
  • clear and next-generation reuse;
  • callback mutation of the same object or containing container.

Verify callback order, exact removed generation, immediate borrowed-view visibility, and no second retained inventory collection.

5. Prove reset, retry, and disposal convergence

Inject a failure at every App teardown stage, then repeatedly invoke the existing retryable teardown entry until it completes. Exercise:

  • ordinary authoritative delete;
  • delete/recreate with the same GUID;
  • session reset during create, update, object callback, and teardown callback;
  • logout;
  • transport replacement;
  • mid-portal disconnect;
  • Runtime and App disposal;
  • repeated subscription disposal and disposal from inside dispatch.

At convergence assert the complete ownership ledger is zero, the retired generation cannot publish, the next generation starts at sequence one, and later object-table mutations cannot reach disposed observers.

6. Runtime-only end-to-end fixture

Without loading App, UI, Silk.NET, OpenAL, Arch, or ImGui:

  1. construct Runtime;
  2. bind a generation and frame clock;
  3. register several conflicting entity/object shapes;
  4. apply properties, motion/vector/state/position, parent/container moves, Hidden, pickup, delete/recreate, and clear;
  5. visit direct views after each commit;
  6. record the exact shared delta stream;
  7. reset and reconnect;
  8. dispose.

Run the same normalized input script through the graphical harness and require exact equality. Assert the Runtime assembly load closure remains backend-free.

7. Closeout gates

Run, in order:

  1. focused Runtime lifetime/stream failure matrix;
  2. Core ClientObjectTable* and ObjectTableWiring*;
  3. focused App hydration, projection, update, parent, rebucket, delete, session-reset, selection, inventory, and paperdoll suites;
  4. Runtime-only versus graphical normalized parity;
  5. all Runtime tests;
  6. all App tests;
  7. dotnet build AcDream.slnx -c Release;
  8. dotnet test AcDream.slnx -c Release --no-build;
  9. exact-binary connected lifecycle/reconnect;
  10. canonical nine-stop connected world route;
  11. documentation, divergence, dependency, and source-ownership audit.

A user visual pause is required only if automated or connected evidence shows a visible inventory, selection, radar, paperdoll, portal, or world-object symptom.

Acceptance

J3 is complete only when:

  • every canonical mutation and terminal path has adversarial coverage;
  • direct and graphical traces remain exact;
  • rejected/stale work consumes no event sequence;
  • no callback can mutate a superseded incarnation;
  • every partial acquisition remains reachable and retryable;
  • every stable reset/disposal checkpoint has zero records, tombstones, keys, projections, resources, container entries, parent candidates, subscriptions, and pending deltas;
  • Runtime-only construction and lifecycle load no presentation/backend assembly;
  • full Release and both exact-binary connected routes pass;
  • architecture, roadmap, milestones, AGENTS/CLAUDE, durable memory, and exact rollback are synchronized.

Rollback

J3.6 is independently reversible:

git revert 119b7c115107245546180b2f5cb3cb44c7d5476a

J3.5 remains independently reversible with git revert ce3ac310d92722ffb637e81cb1957458874dd220. Never revert J3.4 or J3.3 to mask a later failure.

Closeout evidence

The complete failure matrix, zero-owner ledger, 8,484-test Release result, exact-binary lifecycle/reconnect gate, canonical nine-stop route, divergence audit, and rollback are recorded in ../research/2026-07-26-slice-j3-6-lifetime-closeout.md.

Next boundary

J3 is closed. Execute J4 from docs/plans/2026-07-25-modern-runtime-slice-j.md: move the remaining presentation-independent gameplay-state owners in coherent lifetime groups, with direct/graphical parity and zero-mirror deletion after every group.