fix(runtime): restore interaction completion ownership
Preserve prepublication local motion completion, require the PartArray enter-world lifecycle port, and balance deferred Use busy ownership across dispatch and cancellation. Reconcile the completed GameWindow connected gates and add regression coverage. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
5c955c36ec
commit
f9736ece6c
26 changed files with 675 additions and 68 deletions
|
|
@ -30,9 +30,9 @@ What does NOT go here:
|
|||
automated closeout are complete. The 1,622-line native shell has typed
|
||||
startup, frame, callback, and shutdown owners; 293 focused tests, the
|
||||
7,823/5 Release suite, the lifecycle/reconnect route, two canonical
|
||||
nine-stop soaks, and the Slice-7 framebuffer comparison pass. Only the
|
||||
user's final connected visual matrix remains before the campaign is marked
|
||||
complete in [`docs/architecture/code-structure.md`](architecture/code-structure.md).
|
||||
nine-stop soaks, and the Slice-7 framebuffer comparison pass. The user's
|
||||
connected visual matrix passed 2026-07-23, so the campaign is complete in
|
||||
[`docs/architecture/code-structure.md`](architecture/code-structure.md).
|
||||
- **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its
|
||||
connected performance, lifetime, and unattended portal routes pass.
|
||||
- **Carried behavior debt:** `#153` far-teleport unstreamed-edge arrival and
|
||||
|
|
@ -7600,6 +7600,40 @@ outdoors at the angle that previously erased it.
|
|||
|
||||
# Recently closed
|
||||
|
||||
## #234 — [DONE 2026-07-23] Cancelled close-range Use could strand the busy cursor
|
||||
|
||||
**Closed:** 2026-07-23
|
||||
**Severity:** HIGH
|
||||
**Component:** interaction / retained UI / local approach
|
||||
|
||||
**Resolution:** `ItemInteractionController` acquired retail's shared busy
|
||||
reference before `SelectionInteractionController` completed a close-range
|
||||
turn. If that pre-wire approach was cancelled, failed to install, lost its
|
||||
session, or crossed an entity-incarnation boundary, no Use packet existed and
|
||||
therefore ACE could never return the `UseDone` needed to release the count.
|
||||
|
||||
An explicit, generation-bound `ItemUseRequestReservation` now owns that
|
||||
boundary. Successful wire dispatch transfers ownership to authoritative
|
||||
`UseDone`; every pre-dispatch cancellation path releases the reservation
|
||||
locally and idempotently. Session reset invalidates late reservations so an
|
||||
old callback cannot decrement a new session. Focused tests pin cancellation,
|
||||
failed movement installation, stale identity, synchronous turn completion,
|
||||
successful dispatch, and late post-reset resolution.
|
||||
|
||||
The connected report itself completed normally: the log contained the
|
||||
successful NPC Use and `UseDone(0)`, and a managed heap snapshot afterward
|
||||
showed busy count zero with no pending inventory or auto-wield transaction.
|
||||
That evidence separated an ordinary in-flight rejection from the real latent
|
||||
pre-wire leak.
|
||||
|
||||
**Connected gate:** Passed 2026-07-23. Cancelling the close-range turn no
|
||||
longer strands the busy cursor, and the next NPC/item Use succeeds normally.
|
||||
|
||||
**Research:**
|
||||
[`docs/research/2026-07-23-retail-use-busy-ownership-pseudocode.md`](research/2026-07-23-retail-use-busy-ownership-pseudocode.md).
|
||||
|
||||
---
|
||||
|
||||
## #229 — [DONE 2026-07-20] Initial login revealed an incomplete world
|
||||
|
||||
**Closed:** 2026-07-20
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
**Status:** Living document. Created 2026-05-16; implementation reconciliation
|
||||
completed 2026-07-21; Slices 1–8 and their automated closeout landed by
|
||||
2026-07-22. The final connected visual matrix remains before new M4 subsystems
|
||||
enter the App layer.
|
||||
2026-07-22. The connected visual matrix passed 2026-07-23; the campaign is
|
||||
complete and new M4 subsystems may enter through the extracted owners.
|
||||
**Purpose:** Describe the desired structural state of the App layer,
|
||||
explain the rules we've adopted, and lay out the safe extraction
|
||||
sequence from today's reality (one 15,723-line `GameWindow.cs` at the
|
||||
|
|
@ -758,7 +758,9 @@ with graceful exits; deterministic framebuffer captures preserve accepted
|
|||
Slice 7 geometry, UI/paperdoll layering, private viewports, depth/alpha, and
|
||||
reveal. The clean solution build retains only the 17 test-project warnings
|
||||
tracked by #228, and all three final corrected-diff reviews are clean. Only the
|
||||
user's final connected visual matrix remains.
|
||||
user's connected visual matrix passed 2026-07-23, including first-login radar,
|
||||
movement/combat, shared retained panels, recall/portal presentation, and
|
||||
graceful reconnect.
|
||||
|
||||
### 4.4 Exit criteria
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# acdream — strategic roadmap
|
||||
|
||||
**Status:** Living document. Updated 2026-07-22. **M3 landed; M4 is next after the final `GameWindow` visual handoff.** M3's retail casting/UI, R6 locomotion/collision/projectile/teleport/radar rebaseline, deterministic fresh-login/portal world lifecycle, and final two-client portal observer flow are user-gated. All eight slices of the behavior-preserving ownership campaign in [`docs/architecture/code-structure.md`](../architecture/code-structure.md) and their automated closeout are complete; only the user's connected visual matrix remains. Issue #225's lifestone/particle alpha comparison remains a separate rendering visual gate.
|
||||
**Status:** Living document. Updated 2026-07-23. **M3 landed; M4 is active.** M3's retail casting/UI, R6 locomotion/collision/projectile/teleport/radar rebaseline, deterministic fresh-login/portal world lifecycle, and final two-client portal observer flow are user-gated. All eight slices of the behavior-preserving ownership campaign in [`docs/architecture/code-structure.md`](../architecture/code-structure.md), their automated closeout, and the user's connected visual matrix are complete. Issue #225's lifestone/particle alpha comparison remains a separate rendering visual gate.
|
||||
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
|
||||
|
||||
---
|
||||
|
|
@ -116,7 +116,8 @@ snapshots and closes #232 through two clean fresh-process nine-stop routes.
|
|||
The shell is 1,622 raw lines. All 293 focused tests, App Release 3,451/3, the
|
||||
complete Release suite 7,823/5, connected lifecycle/reconnect, both canonical
|
||||
soaks, three corrected-diff reviews, and the exact Slice-7 framebuffer
|
||||
comparison pass. Only the user's final connected visual matrix remains.
|
||||
comparison pass. The user's connected visual matrix passed 2026-07-23 and the
|
||||
structural program is complete.
|
||||
|
||||
This is a behavior-preserving structural program. Severe regressions still get
|
||||
root-cause fixes in separate commits; ordinary feature work resumes with M4
|
||||
|
|
|
|||
|
|
@ -74,8 +74,9 @@ without loosening the process thresholds. The automated Slice 8 closeout is
|
|||
complete: `GameWindow` is 1,622 raw lines; 293 focused tests, App Release
|
||||
3,451/3, the complete Release suite 7,823/5, lifecycle/reconnect, both
|
||||
canonical soaks, all three corrected-diff reviews, and the Slice-7 framebuffer
|
||||
comparison pass. Only the user's final connected visual matrix remains before
|
||||
new M4 feature bodies begin.
|
||||
comparison pass. The user's connected visual matrix passed 2026-07-23,
|
||||
including the post-closeout radar correction, so new M4 feature bodies may
|
||||
begin through the extracted owners.
|
||||
|
||||
Carried:
|
||||
#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus
|
||||
|
|
|
|||
117
docs/research/2026-07-23-retail-use-busy-ownership-pseudocode.md
Normal file
117
docs/research/2026-07-23-retail-use-busy-ownership-pseudocode.md
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
# Retail Use busy-reference ownership
|
||||
|
||||
Date: 2026-07-23
|
||||
|
||||
Scope: the retained UI busy cursor and the
|
||||
`You can only move or use one item at a time` gate while an object/NPC Use
|
||||
crosses acdream's close-range turn/approach boundary.
|
||||
|
||||
## Retail oracle
|
||||
|
||||
Named Sept-2013 retail symbols:
|
||||
|
||||
- `ItemHolder::UseObject @ 0x00588A80`
|
||||
- `ClientUISystem::Handle_Item__UseDone @ 0x00564900`
|
||||
- `CM_Item::DispatchUI_UseDone @ 0x006A8510`
|
||||
- `ClientUISystem::UsageCallback @ 0x00565B20`
|
||||
|
||||
`ItemHolder::UseObject` checks the 200 ms throttle and
|
||||
`IsPlayerReadyToMakeInventoryRequest`, emits `CM_Inventory::Event_UseEvent`,
|
||||
increments `ClientUISystem::m_cBusy`, and then calls
|
||||
`CPlayerSystem::UsingItem`. The confirmation callback has the same order.
|
||||
`CM_Item::DispatchUI_UseDone` routes event `0x01C7` to
|
||||
`Handle_Item__UseDone`, which decrements exactly one busy reference and updates
|
||||
the cursor when the count reaches zero.
|
||||
|
||||
Therefore the invariant is:
|
||||
|
||||
```text
|
||||
one accepted Use request that reached the wire
|
||||
owns one busy reference
|
||||
until one authoritative UseDone arrives
|
||||
```
|
||||
|
||||
There is no retail timeout and movement cancellation is not a substitute for
|
||||
`UseDone` after dispatch.
|
||||
|
||||
## ACE and protocol cross-reference
|
||||
|
||||
- ACE `GameActionUseItem` and `Player_Use.TryUseItem` confirm that the Use
|
||||
request owns the server-side operation and that every completed/rejected
|
||||
operation returns `UseDone`.
|
||||
- ACE `Player_Move.CreateMoveToChain` confirms that the server may approach a
|
||||
distant target before executing that operation.
|
||||
- holtburger `inventory/actions.rs` and `inventory/events.rs` independently
|
||||
confirm the one Use action / one UseDone event protocol pair.
|
||||
|
||||
The existing close-range compatibility seam is recorded as divergence AD-27:
|
||||
acdream may finish its local turn before emitting Use. That seam creates a
|
||||
real pre-wire interval which retail does not have, so it needs explicit
|
||||
ownership rather than pretending a server completion is already owed.
|
||||
|
||||
## Ported ownership pseudocode
|
||||
|
||||
```text
|
||||
BeginAcceptedUse(object):
|
||||
reservation = BusyOwner.Reserve()
|
||||
busyCount += 1
|
||||
RequestUse(object, reservation)
|
||||
|
||||
RequestUse(object, reservation):
|
||||
if session/identity/approach is invalid:
|
||||
reservation.CancelBeforeDispatch()
|
||||
return
|
||||
|
||||
if a close-range turn must finish first:
|
||||
pending = (exact object incarnation, approach token, reservation)
|
||||
if movement installation fails:
|
||||
pending.reservation.CancelBeforeDispatch()
|
||||
return
|
||||
|
||||
if SendUse(object) succeeds:
|
||||
reservation.MarkDispatched()
|
||||
else:
|
||||
reservation.CancelBeforeDispatch()
|
||||
|
||||
OnNaturalApproachCompletion(pending):
|
||||
if pending incarnation is stale:
|
||||
pending.reservation.CancelBeforeDispatch()
|
||||
else if SendUse(pending.object) succeeds:
|
||||
pending.reservation.MarkDispatched()
|
||||
else:
|
||||
pending.reservation.CancelBeforeDispatch()
|
||||
|
||||
OnApproachCancelledOrTargetRemoved(pending):
|
||||
pending.reservation.CancelBeforeDispatch()
|
||||
|
||||
reservation.MarkDispatched():
|
||||
// Ownership transfers to the server completion. Keep busyCount unchanged.
|
||||
make later local cancellation inert
|
||||
|
||||
reservation.CancelBeforeDispatch():
|
||||
// No packet exists, therefore no UseDone can arrive for this reservation.
|
||||
busyCount -= 1
|
||||
make duplicate cancellation inert
|
||||
|
||||
OnUseDone(error):
|
||||
busyCount -= 1
|
||||
if busyCount == 0:
|
||||
update cursor
|
||||
|
||||
OnSessionReset():
|
||||
invalidate the reservation generation
|
||||
busyCount = 0
|
||||
```
|
||||
|
||||
The reservation is idempotent and generation-bound. A late callback from a
|
||||
retired session cannot decrement a new session's busy reference.
|
||||
|
||||
## Regression evidence
|
||||
|
||||
The connected trace showed successful NPC Use packets and matching
|
||||
`UseDone(0)`. A managed heap snapshot after the final completion showed
|
||||
`ItemInteractionController._busyCount == 0`, no pending inventory request, and
|
||||
no pending auto-wield transaction. The permanent failure path was instead the
|
||||
pre-wire close-range branch: it incremented busy before local movement, but
|
||||
cancellation or stale identity discarded the pending send, leaving no packet
|
||||
and therefore no possible `UseDone`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue