Dated source reference. Current release status: handoff state. Full original relative paths are in the developer archive.
Rules, corrections and overtime — evidence and remaining coverage
Current API checkpoint (October19,2026): private
0.2.0.dev53, HTTPv1/main snapshotABI26/eventABI4 and separate draft1 rule transport. Work62 implements validity-qualified legal state and native rule extensions within explicit coverage. The ten currently named record kinds include double dribble and kicked ball, with scoped handler-credit roles. The sections below retain historical versions, evidence and uncertainties; their pending statements do not override the current API contract or verification ledger.Current scope (October13,2026): Windows-first deep editing and a public extension API; Mac/Linux compatibility follows later. Earlier native-port goals and next-step proposals in this evidence history are superseded. Technical observations and verification limits remain as recorded.
This extends EVENT-CONTRACTS.md and EVENT-SEMANTICS.md. The complete semantic mapping is still unfinished. This milestone verifies several important paths without promoting every numeric code into a named, reliable public event. The intended API remains available to independent third-party tools, as required by PUBLIC-API-REQUIREMENTS.md.
Historical implementation status — October 13
The sections below preserve earlier research milestones; later evidence in API-ENGINE-INTEGRATION supersedes their time-specific pending statements. Development24 passes178 API tests on macOS and Windows; live game integration is Windows only. Multiple full-game exports reconcile with the captured stat stream, including a natural double-overtime run. Natural offensive-rebound retraction and original-credit linkage are verified; controlled offensive/defensive retractions have also been exercised. Live block-retraction validation is deferred at the user's request.
Verified category12 names are eight-second backcourt violation, ten-second backcourt violation, shot-clock violation, blocking foul and shooting foul. Remaining kinds, legal possession/live-ball state and coherent rule mutation are unfinished. The latest research observer captures the game's localization requests to strengthen event-to-presentation evidence; it does not automatically make those labels authoritative API events.
Scope and provenance
Supported supplied Windows x86 EXE: SHA-256 7cb5fdaa30586558a3146dcf9023880b1cceeaabfe0f92f967f461c4644f3704, image base 0x400000. Addresses below are build-specific virtual addresses, not cross-version public API identifiers. Player/node pointers must be resolved per process and match. The stable adapter remains external-mode v0.2; no production API or new native engine was delivered here.
Original executable and NBA2K14-extracted were not modified. Evidence: analysis/rule-completion, original runtime code from analysis/offline-bootstrap/{text,rdata}.bin, and the original english.iff / newscorebug.iff. Attribution is to the supplied NBA 2K14 game and original OpenHoops research; no community installer was run. Tool versions, hashes and sources are pinned in the evidence manifest.
A temporary inspected adapter used 31 guarded entry detours. Its SHA-256 is 65be4807884eb5a797c137527995cdba1250ec2d504b36fcbad48f8a5759c752. MSVC19.51 x86 /W4 /WX /O2 /MT; 124 compiled wrapper cases passed. It observes entry state, not committed transactions. The extension decoder is bound to that DLL: its eleven new DWORDs occupy slots117–127, while the historical header still says format1. Do not decode an unrelated format1 trace as this extension.
This was an instrumented, mutable research session. Snapshot collectors themselves used only ReadProcessMemory. Their inherited receipt text says “no injected mod,” which describes their own collector behavior but is inaccurate as a description of the surrounding session: the tracer was loaded, and separate exact-preimage-guarded fixtures used WriteProcessMemory. Those original receipts remain unaltered; this clarification governs their interpretation.
Live evidence
The complete bounded trace contains 96,035 contiguous observations, one game thread, zero recorded drops, 1,800,125ms duration. It covers menus, two quick-game fixtures, selected play and overtime transitions. It is not a whole natural match or a lossless capture of every game event. Entry coverage is limited to the installed targets; zero ring drops cannot establish completeness.
| Fixture | Setup and observed result | Limit |
|---|---|---|
| Shot-clock expiry | Paused clock 1DEE654 set to0.05; resume called 79E520 at seq9187, then turnover 8BFAE0 with type13 at seq9190. |
Artificial timer setup; ordinary player turnover notification6 absent in that window. The screenshot named shotclock-ui.png shows later resumed play, not the violation banner. |
| Qualifying counters / display | Both full counters seeded4. Natural fouls produced (4,0;4,0)→(5,0;4,0)→(6,0;4,0)→(6,0;5,1). Later UI displayed BONUS for both teams. |
The fouls used shooting awards. No live call to bonus predicate 8A2110 occurred. This is not a live proof of a non-shooting bonus award. |
| Failed aggregate-score override | Home team total was set8→10, matching away10, before accelerated regulation expiry. Engine returned home total to8; regulation ended10–8. | Underlying player stats were unchanged. Directly writing a team aggregate is not a reliable scoring command. Failure retained in fixture-ot.*. |
| Tied regulation → OT | Scoreless rematch, raw period1→4, time→0.05, counters seeded (5,2;6,3). Live engine entered period5, reset all four counters, allocated timeout pools3+0, set180s and performed OT jump ball. |
Synthetic end-of-regulation setup, not four naturally played quarters. |
| OT → 2OT | At0–0, time→0.05 and counters seeded (4,2;4,2). Live engine entered period6, reset counters, allocated3+0 timeouts and180s. |
Same synthetic setup limitation. |
| 2OT → 3OT | A Spurs basket made it2–2 before the pre-expiry capture; accelerated expiry then started period7 at180s. | This is not evidence of a made basket after the buzzer. An interim progress update's “late basket before the finish check” referred to this sequence. |
| 3OT finish | At Miami4–Spurs2, time→0.05. Final UI and nine samples agree: phase19, finish latch1, winner pointer 1D955D0, raw period8, clock0, transition flag1. |
Final expiry happened after the bounded entry trace ended; final state is verified by snapshots/UI, not a complete ordered finish trace. |
Exact reset observations: seq76852→76853 (OT), seq80034→80035 (2OT), seq90511→90512 (3OT). Seeded counter resets in the first two transitions prove an actual change, not just an initial zero. overtime-start.png, overtime2-start.png, and overtime-final.png preserve visible corroboration. The first saved OT screenshot was captured shortly after the visible 3:00 transition; the trace contains the exact180s value.
Final team scoring subrecords were home [4,0,0,0,0,4], away [2,0,0,0,0,2]. Thus the observed second- and third-overtime points accumulate into one slot5, consistent with the captured clamp. External consumers need their own per-overtime ledger if they need separate OT scoring; raw subrecords cannot provide it.
Bonus, fouls and free throws
There are at least three separate quantities:
- Player personal fouls at stats+
244. - Team box-score foul total at teamstats+
3B8and its period slots. - Qualifying full-period / last-two-minute counters at teamstate+
C/10.
Do not substitute one for another. Team-state records in this fixture were 1DEE590 and 1DEE5B0; direction/side should still be resolved through team objects.
The previously tested numeric threshold remains: selector 1E85DBC==0 requires full count≥5 in regulation or≥4 in OT, or late count≥2. Other tested selectors use5/5. Late counter writer uses strict clock<120, not≤120. Numeric selector names beyond observed default remain unverified. Reset 8BDBC0 always clears late count; full count clears for selector0 or period<5, but carries into OT for tested nonzero selectors. Only selector0 resets were verified live here.
New captured-x86 execution covers 504 combinations through the actual non-shooting award consumer 8BDEB0, its real threshold and threshold helpers: selector0/1/2, periods1/4/5/6, full0–6, late0–5. Eligibility query and subsequent FT setup were mocked; the supplied argument0 bypasses ordinary shooting detection. Threshold true writes shooter, FT type4, total2, remaining2 and returns1. Below threshold, with the off-ball fallback absent, no FT award is written. This verifies the connected decision/writes, not the full on-court foul policy.
Four further cases force the shooting branch: FT type1 with2/3 attempts wins even when full foul count is already5. Ball classification bit400 selects3 versus2 on the tested detached-owner path. A shooting foul in a BONUS state is therefore not evidence that the bonus branch supplied the free throws.
Additional static exclusions, requiring live fixtures before public authority:
- Illegal-pick candidate handler
79E8E0calls881C00with qualifier0, while foul credit type14 can still increment the separate box-score team total. - Handler
7A0910/ foul type12 computes its qualifier from880410: increment only when the committing actor's team is not current offensive context. It is not an unconditional qualifier1 path. - Handler
7A1A30/ foul type1 checks the other actor's team against defensive context. If that actor is defensive,AA11B0returns0; otherwise qualifier1. The usual offensive-foul situation is excluded, but calling this handler universally qualifier0 would be wrong. Foul credit8BF490separately excludes type1 from its box-score team-foul increment. - Actor-type4 handler
79DB60directly increments teamstate+14and+C, without the common qualifying writer or its late-counter update. It calls FT helper882110with count1 and the opposing team. This is a coach/technical-penalty candidate, not a live-verified named API event.882110writes FT type8; with no explicit shooter it searches players by a rating helper. This also shows why tracing only881C00misses qualifying-counter mutations.
Display getter 967F70 yields numeric statuses0–4. The inspected consumer near B859D4/B859F1 collapses a nonzero result to a boolean and selects the localized BONUS label (key 7BCF48CB). Do not name statuses1–4 “single/double bonus” from that UI alone. Binding D86CD0 exports the numeric result. Complete selector/display interpretation and technical/intentional/off-ball exception coverage remain open.
Corrections
New tests run the actual conditional block-retraction function 8A39A0, actual stat decrement helper and actual notification fanout across60 combinations. A remembered blocker and unsuppressed correction permit the decrement; the per-period slot must be nonzero. The callback reports subtraction even when both counters are zero. The helper sets 1DEE3F0 even when no decrement occurs. OT uses slot5.
Recovered causal caller 78C4F0 requires current phase10, a non-null input and context type70 from 4C77F0. Its nested record selects OR versus DR retraction. 48 tests execute that caller and the actual retraction helpers with synthetic context objects. The DR branch also restores offense/defense context and remembered shot context; clock/team-feedback effects are mocked. The OR branch sets the pending rebound-retraction flag too. The meaning and lifetime of context type70 still need live provenance.
Across the bonus, forced-shooting, block and rebound-context cases: 616 passed. These are captured-x86 tests on synthetic memory, not a native replacement implementation. Dependencies and exact bytes/hashes are recorded. No actual committed live OR/DR/block retraction was captured in this milestone. Two block-correction entries appeared, but no observed subtraction-helper entry followed; do not publish those calls as successful corrections.
The public event model must distinguish attempted correction, committed negative delta and match/reset/checkpoint rollback. A call to a subtraction notifier alone is insufficient. Final exports must reconcile committed totals, not add every callback delta blindly.
Violations: separate the numeric domains
At least these domains coexist and must not share one enum:
- Rule enablement dispatch (
411F40, numeric rule IDs). - Foul-credit subtype (
8BF490, e.g.5 shooting-path,14 illegal-pick candidate). - Turnover subtype (
8BFAE0, type13 team-only shot-clock path). - Referee signal (
1C48D90), which can still describe a previous action at a handler's entry. - Shared event record kind supplied to
940690. - Localization indices/keys and formatted text.
The shot-clock example alone uses handler 79E520, turnover13, referee signal19 and event-record kind13. Other domains do not consistently coincide.
Recovered and executed 940690 record construction across56 cases (kinds0–27, direction±1). Its descriptor category isC, with two roster-node references and a48-byte payload containing actor/ball position, direction, numeric kind and action flags. Crucially payload+C is offensive direction as a float, not a clock or period. The sink 9436A0 was mocked for these tests. Follow-up recovery establishes that its real path copies into a bounded internal record store before calling a dynamic callback at 1E36508 (details below). GameTrack correspondence and a live event-history contract remain unproven. The constructor's local pointers must be copied synchronously; they cannot become public durable pointers.
Saved violation-record-verification.json describes every payload field tested. violation-record-callers.json lists28 direct call candidates. handler-call-arguments.txt preserves argument-setting assembly, but its initial coarse handler ranges can include adjacent functions: e.g. the event-kind3 call at79DE09 belongs to 79DD50, not preceding79DB60. Use exact instruction/call-site evidence, not range headings as proof of function ownership. Extra decompilation targets and failed boundary guesses are retained as research history.
Targeted caller recovery found the backcourt crossing path 8A1650, a separate expired-backcourt-clock path calling 79E2B0, and the lane-timer caller 8A1BF0 of79D660. An initial padding-based search incorrectly selected preceding8A1A90; that is a different timer path calling738000. These paths are valuable rule-policy leads, but complete geometry/action exemptions and UI labels are not yet validated.
The original English archive resolves the scorebug's localized vocabulary, including out of bounds; backcourt; defensive/offensive three seconds; eight/ten seconds; five seconds, closely guarded and back-to-basket; ball entering from below; goaltending; offensive interference; shot-clock; kicked ball; travel; double dribble; jump ball; and several foul labels. scorebug-string-table.json contains exact keys and archive evidence. Vocabulary present in assets is not proof that every event is implemented or that a guessed numeric kind has that name. The full enum-to-label bridge remains unfinished. Extracting newscorebug.iff did not by itself resolve its binary UI logic.
Internal event storage and correction lookup
Follow-up inspection resolved the jump at 4C7CC0 using an existing runtime capture: allocator 215A2C0 in analysis/portable-saves/protected.bin. Exact range hashes/assembly are in event-storage-code.json. 17 captured-code tests passed through the actual allocator, 4C7E80 copier, 4C77F0 category lookup, 4C77C0 checkpoint lookup and 9436A0 dispatch. This is substantially stronger than treating 4C7E80 as a boolean eligibility query: it mutates and stores records.
The initializer prepares 1,024 reusable 32-byte nodes, two separate byte arenas of128KiB/32KiB, and an eight-entry checkpoint-pointer ring. Node+0 is category; +4/+8 receive float timestamps from 15A5AAC/15A5AB0; +10 points newer, +14 older, +18/+1C to independently copied blocks. Root 15A5AA8 is newest, 15A5AA4 oldest. When the node pool is exhausted, the tested allocator recycles the oldest node: the1,025th append reused the first address. Pointer identity is therefore neither an event ID nor durable history.
4C77F0(0x70), used by rebound retraction, searches newest-to-oldest using+14 and stops at category0. Synthetic tests verify matching, missing, and sentinel cases. This establishes the concrete lookup mechanism, not the basketball meaning of category0x70 or the original event being corrected.
Category6E increments the checkpoint index; the first direct insertion when the index is negative also initializes it. 4C77C0 can retrieve only eight checkpoint pointers. These are not proven match/checkpoint IDs suitable for external clients. 9436A0 suppresses dispatch while the index is negative, then appends and calls the dynamic callback with the current index inECX and newest stored node inEDX. No asynchronous delivery is created by this inspected path.
Tests verify that copied data survives mutation of its original input buffer. They also expose a failure case: insufficient room for a payload can leave the block pointer null while 4C7E80 still returns1. Consumers must validate blocks and reconcile gaps. A successful append return does not mean every payload survived.
Scope limits: the category-schema initializer at4C7070→2179060 is outside the available protected-code capture. The tests explicitly supply synthetic category12 sizes8/48, consistent with the previously recovered constructor; those sizes are not yet verified against the live registration table. Memory-copy/fill, registry setup, downstream consumers and reclamation notifications are mocked. The allocator itself and normal record copy/lookup paths execute captured instructions. Full arena recycling/lifetime, cleanup callbacks, actual clock meanings, live consumers and GameTrack persistence remain open. This bounded store is not an automatic durable whole-match event log.
Coverage required before calling the mapping complete
| Area | Established | Still required |
|---|---|---|
| Shot-clock violation | Live handler and team-only turnover13 sequence | Visible exact-label capture, all ball-flight/expiry cancel conditions and aggregate reconciliation |
| Backcourt / eight-ten seconds / lane timers | Specific caller and handler leads; timer/geometry code | Named-ID bridge, controlled violations, exemptions, exact possession/clock results |
| Travel, double dribble, kicked ball, interference, five-second variants | Localized vocabulary and numeric record/call-site evidence | Authoritative named mappings plus positive/negative fixtures for each |
| Fouls and bonus | Numeric threshold, writers/reset, award consumer tests, live counter changes/display | Live non-shooting bonus award; all subtype names; technical/flagrant/intentional/off-ball exclusions; foul-out/replacement cases |
| Corrections | Actual decrement/fanout and causal rebound-context tests | Nonzero live retraction, correction linkage and later aggregate reconciliation |
| Overtime | Live first/repeat OT startup and final state; resets/timeouts; pooled stats | Other selectors/quarter lengths live, ending-shot/FT/cancellation corner cases, full natural OT match |
| Custom scoreboard | Core stats, clocks, phases, display vocabulary and bonus structure | Coherent publish boundary, full legal live/dead state, pause/replay distinction, pending decision/review states |
| Final export / third-party dynasty tools | Final latch/winner/UI agreement; restart/rematch/save-load counterexamples | Managed match IDs, abort/resume/checkpoint contract, live storage schema/lifetime and GameTrack linkage, reconnect and final reconciliation |
| Deep rules commands | Several authoritative decision paths identified | Safe game-thread command boundary, transactional edits and AI/animation/visual consistency |
Next useful investigation is a live capture of the record schema initializer/table and record consumers, alongside deterministic named-violation and non-shooting-foul fixtures. Do not build a production “complete events” stream from callback guesses. Research remains authorized; no additional user permission is needed for those bounded local investigations.
Verification and cleanup
- 124 compiled-wrapper cases; 616 award/correction cases; 56 record-constructor cases; 17 event-storage cases; 54 evidence-consistency checks.
- Complete trace hash and restore receipt agree. All pre-session save files restored and hash-checked; research-generated saves retained separately on Dell under
logs/rule-completion-complete/saves. - Game exited normally through its menu. Stable DLL hash
003a0c821b81f4abd0851b276fa7f5854de849c07ddb1723d9bd3259a0d2daf4restored. Temporary launch task absent; no recurring automation created. - Windows x86 original-game behavior only. Captured-x86 execution on this Mac is a verification oracle, not a native game or cross-platform completion claim.
Development28a: presentation and two additional event names
Closed run27 and original handler tests support category12kind18 reach_in_foul and kind7 out_of_bounds; see analysis/api-engine/live-27-named-event-evidence.json, reach-in-handler-verification-28.json, out-of-bounds-handler-verification-28.json. These are separate from raw stop-reason values6/18. OOB actor can be substituted by original logic and is not guaranteed last toucher. Experimental presentation and physical holder fields are documented in api/README.md. Legal live/dead and legal possession remain unavailable; timeout remains unnamed. Rules editing and live block retraction are deferred by the user. New scope includes engine-verified settings/sliders reads and writes; these are not implemented yet.