fix(vendor): 6b/6c review corrections — pre-send guards, accumulating staging, trade-note exemption, drag-over tab switch, full-stack sells
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run

All thirteen findings, each anchored in recovered bytes or pc reads:

Buy All now runs retail's four PRE-SEND guards in order (pyreal and
alt-currency affordability, container and item slot capacity; strings
recovered from .rdata at 0x007b57b4/0x007b5750) — a rejected batch can
no longer destroy the staged list. Staged adds ACCUMULATE with the
5000 cap ("I can't possibly sell you that much!..." @0x007b59d8) and
the shop rows decrement/restore per RemoveFromShop. The max-value sell
rejection exempts trade notes — the raw bytes at 0x005d1add are `not`
(bitwise), not the pseudo-C's misleading `!`, and the early ret skips
the min check too. BF_RETAINED gates selling end to end (the bit was
already on ClientObject; AP-164's three claims were all false once
traced — RETIRED). Dragging over the vendor window auto-opens the
Selling tab per UpdateDragOver — with a correction to the review's own
citation: token 0x100000cd is the SELLING page, the guard is
"don't reopen the current tab." Sells are full-stack-only (three
retail sites; "Cannot sell part of a stack" @0x007b57ec) and Sell Item
acts on the global selection unconditionally. The confirm string gains
its byte-true trailing '?', dies with the session, staged-row
highlights repaint, dead guids unstage with retail's shopping-list
notice, and move-to-use no longer walks to targets the dispatch would
refuse.

AP-162 narrowed, AP-164 retired, AP-167/AP-168 filed honest.

Clean-room complete solution: 11,508 passed / 4 skipped / 0 failed.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-08 12:50:28 +02:00
parent 92ea3977b6
commit c68ad1e646
11 changed files with 1314 additions and 99 deletions

View file

@ -231,18 +231,32 @@ internal sealed class SelectionInteractionController
// TurnToObject branch, Use keeps sending immediately either way (the
// existing RuntimeInteractionTransactionState.TryDispatchUse doc
// comment: "consume the strict 0.2-second gate, send immediately").
if (_query.TryGetApproach(serverGuid, out InteractionApproach approach)
//
// F11 (Slice 6b/6c review): the eligibility TryDispatchUse itself
// gates on (ownedByPlayer || useable) is computed ONCE, up front,
// and checked BEFORE BeginApproach — a prior version of this method
// called BeginApproach unconditionally whenever the target was out
// of close range, kicking off a client-predicted walk toward a
// target the dispatch below was always going to refuse anyway (a
// wasted, visually confusing approach with no possible Use at the
// end of it). Reordering does not change the dispatch itself: an
// ELIGIBLE target still sends immediately, in the same order,
// exactly as before.
bool ownedByPlayer = _items.IsOwnedByPlayer(serverGuid);
bool useable = ownedByPlayer || _query.IsUseable(serverGuid);
if (useable
&& _query.TryGetApproach(serverGuid, out InteractionApproach approach)
&& !approach.IsCloseRange)
{
_movement.BeginApproach(approach);
}
bool ownedByPlayer = _items.IsOwnedByPlayer(serverGuid);
RuntimeInteractionDispatchResult result =
_transactions.TryDispatchUse(
serverGuid,
ownedByPlayer,
ownedByPlayer || _query.IsUseable(serverGuid),
useable,
reservation,
_transport,
out uint sequence);