Match action_vehicle seat evaluation and reopen the input_xbox analog park

Wave w3d batch 1 (the structural retarget: census the frame, the [ebp+/-N] slots
and the relocations before proposing any shape).

- action_vehicle _action_vehicle_evaluate_seat (+976): the unit called
  vehicle_specific_definition_get through a C4013 implicit declaration; including
  its genuine owner units/vehicle_definitions.h fixes the call, and January's
  single-exit shape puts the three seat points in the taken branch's own block
  instead of behind an early return.
- input_xbox _input_update_analog_button_state (+48): park reopened and removed.
- effects _effect_allowed_by_environment and _effect_generate_particles: coupled
  A8 callee/caller re-baseline, ZERO credit. Both are now January-exact in padded
  size (and relocation count for the caller) and stay parked and fuzzy; the
  remeasures carry dated evidence in config/parked.json.

Full ninja, parks 277 active / 0 stale / 0 invalid, stable diff vs
scratch/claude250k-start.json: gained 3 / 1,824 bytes, regressions 0; fake scan
0 leads.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jonas VolmanandClaude Opus 5 committed 2026-09-15 20:14:01 -07:00
1 parent df21bd9389
commit ae10935da6
13 files changed
+1861 -188

No files matched your search

+9 -28
View File
@@ -738,25 +738,6 @@
"objdiff_percent": 82.10656
}
},
{
"unit": "source/input/input_xbox",
"function": "_input_update_analog_button_state",
"class": "unclassified",
"evidence": "Genuine January standalone private analog-button hysteresis helper at file offset 780288, with an ordinary static source definition and authentic auto-inlining into the device poller. Target and candidate are 48 padded bytes with no relocations; only sub al,32 versus compiler-canonical add al,-32 differs. Retain the natural threshold subtraction, not assembly, optimizer steering or an invented helper. All 16 inherited exact owners are preserved and no extra code owner or point_from_line3d is emitted. Reopen only for new authentic compiler/source evidence. See docs/object_matching_logs/input_xbox_obj_device_keyboard_pollers_wave_20260904.md. This park grants no exact credit.",
"measurements": {
"target": {
"size": 48,
"relocation_count": 0,
"normalized_sha256": "5850a17e99380c5499a719ba1667ef91f992a37284afe5049ba6e7f04e79c826"
},
"base": {
"size": 48,
"relocation_count": 0,
"normalized_sha256": "78f85bb297cc663f10c1fcea301827288980a1f2dc6cf99b0012b4fe641a1bb9"
},
"objdiff_percent": 97.0
}
},
{
"unit": "source/input/input_xbox",
"function": "_input_get_device_states",
@@ -2988,7 +2969,7 @@
"unit": "source/effects/effects",
"function": "_effect_allowed_by_environment",
"class": "unclassified",
"evidence": "The retained ordinary-C environment switch implements the complete January air, water, vacuum, and anywhere behavior with named enum constants and typed location/point arguments, and the later HCEA reconstruction independently corroborates those four arms. January's invalid-enum arm calls the fatal assertion path and then reloads an uninitialized result byte if system_exit unexpectedly returns. The Opus donor reproduced that indeterminate fallthrough and was exact, but it is rejected under the no-undefined-behavior rule. The closest safe natural source initializes the result from the meaningful anywhere predicate before overriding the air/water arms; invalid and vacuum values therefore remain FALSE. It compiles to 112 padded bytes and ten relocations versus January's 128, with 55.909092 percent objdiff, while preserving the donor's better 1,616-byte and 592-byte shapes in both real callers. Simple FALSE initialization and assignment-after-assert forms also produced 112 bytes but caused both callers to inline the assertion body and regress broadly. The fail-closed classifier returns UNKNOWN. No uninitialized read, false noreturn declaration, volatile/register forcing, barrier, pragma, assembly, fake dependency, or nonsensical branch is retained. Reopen only for authoritative January source proving a safe result lifetime or a truthful shared noreturn contract that naturally reproduces the target.",
"evidence": "The retained ordinary-C environment switch implements the complete January air, water, vacuum, and anywhere behavior with named enum constants and typed location/point arguments, and the later HCEA reconstruction independently corroborates those four arms. January's invalid-enum arm calls the fatal assertion path and then reloads an uninitialized result byte if system_exit unexpectedly returns. The Opus donor reproduced that indeterminate fallthrough and was exact, but it is rejected under the no-undefined-behavior rule. The closest safe natural source initializes the result from the meaningful anywhere predicate before overriding the air/water arms; invalid and vacuum values therefore remain FALSE. It compiles to 112 padded bytes and ten relocations versus January's 128, with 55.909092 percent objdiff, while preserving the donor's better 1,616-byte and 592-byte shapes in both real callers. Simple FALSE initialization and assignment-after-assert forms also produced 112 bytes but caused both callers to inline the assertion body and regress broadly. The fail-closed classifier returns UNKNOWN. No uninitialized read, false noreturn declaration, volatile/register forcing, barrier, pragma, assembly, fake dependency, or nonsensical branch is retained. Reopen only for authoritative January source proving a safe result lifetime or a truthful shared noreturn contract that naturally reproduces the target. 2026-09-15 (250K lane wave w3d): re-measured after the coupled A8 callee re-baseline. The body is strictly closer - padded size is now January-exact (was 112), 10 relocations with every external target identical, and four distinct jump-table case entries instead of three. Zero strict credit; the row stays parked and fuzzy [sha], and its strict-exact reopen criterion is unchanged and NOT met.",
"measurements": {
"target": {
"size": 128,
@@ -2996,11 +2977,11 @@
"normalized_sha256": "a005be4ac405246678b6c4e9a4bf65deb16b96b5208fad9454b45df70e8fa7cd"
},
"base": {
"size": 112,
"size": 128,
"relocation_count": 10,
"normalized_sha256": "19760ee664c88645139c9ce8c61958c388596d76ccd0eae8bba88f5c865632df"
"normalized_sha256": "8f9a2185534b3801351e0f354e1fa4e5e3e39f7250559d1020cf2388df9248cf"
},
"objdiff_percent": 55.909092
"objdiff_percent": 63.909092
}
},
{
@@ -3026,7 +3007,7 @@
"unit": "source/effects/effects",
"function": "_effect_generate_particles",
"class": "unclassified",
"evidence": "The retained ordinary-C implementation completes the event-particle traversal, distribution, marker transforms, environment/disposition filtering, velocity/orientation, tint, split-screen limits, and particle creation using named enums, typed structures, cseries flags, and engine real types. January disassembly and relocations establish the same behavior, and the later HCEA reconstruction corroborates the algorithm. The candidate is 1,616 padded bytes with the same 46 relocation count versus January's 1,888 bytes, at 68.30481 percent objdiff. January inlines effect_real_random_range at three sites, whereas VC7 keeps natural calls in this context; forcing inline would violate the house rule and disturb the exact out-of-line/helper schedule. The fail-closed classifier returns UNKNOWN. No forced inline, duplicated helper body, volatile/register forcing, barrier, pragma, assembly, raw offset, or fake control flow is retained. Reopen only for authoritative January source or natural compatible-compiler evidence for the three helper-inline decisions. On September 14 (lane opus/100k-consolidated-20260914, wave D, adversarially verified) the parked body's particle loop was corrected to January's per-instance count (hoisted count reloaded per instance, dec/jne proven at 0x187-0x196) as the coupled prerequisite of the exact effect_update reopen: 2048 bytes, 55 relocations, still fuzzy; the residual is the environment-helper inline decision plus the loop guard and register form. See docs/object_matching_logs/effects_obj_opus5_100k_waveD_20260914.md.",
"evidence": "The retained ordinary-C implementation completes the event-particle traversal, distribution, marker transforms, environment/disposition filtering, velocity/orientation, tint, split-screen limits, and particle creation using named enums, typed structures, cseries flags, and engine real types. January disassembly and relocations establish the same behavior, and the later HCEA reconstruction corroborates the algorithm. The candidate is 1,616 padded bytes with the same 46 relocation count versus January's 1,888 bytes, at 68.30481 percent objdiff. January inlines effect_real_random_range at three sites, whereas VC7 keeps natural calls in this context; forcing inline would violate the house rule and disturb the exact out-of-line/helper schedule. The fail-closed classifier returns UNKNOWN. No forced inline, duplicated helper body, volatile/register forcing, barrier, pragma, assembly, raw offset, or fake control flow is retained. Reopen only for authoritative January source or natural compatible-compiler evidence for the three helper-inline decisions. On September 14 (lane opus/100k-consolidated-20260914, wave D, adversarially verified) the parked body's particle loop was corrected to January's per-instance count (hoisted count reloaded per instance, dec/jne proven at 0x187-0x196) as the coupled prerequisite of the exact effect_update reopen: 2048 bytes, 55 relocations, still fuzzy; the residual is the environment-helper inline decision plus the loop guard and register form. See docs/object_matching_logs/effects_obj_opus5_100k_waveD_20260914.md. 2026-09-15 (250K lane wave w3d): re-measured as the caller of the re-baselined callee (A8 cascade). Padded size AND relocation count are now January-exact (was 2048/55), all 46 relocations agree by target, the frame sub esp,0xe4 matches, and the body is 566 vs 562 instructions with 75 aligned diff blocks (was 622 instructions / 120 blocks). Zero strict credit; stays parked and fuzzy [sha].",
"measurements": {
"target": {
"size": 1888,
@@ -3034,11 +3015,11 @@
"normalized_sha256": "d196a029c22bfe043323cd0def8c1f0365590b559f3fbb65f23c9ef5b4065ef5"
},
"base": {
"size": 2048,
"relocation_count": 55,
"normalized_sha256": "2dccf111fad130493ba4305ac4012e6d5d2b0f724894fa2f468b2e8d01130c27"
"size": 1888,
"relocation_count": 46,
"normalized_sha256": "c251b0c184dbcdeb303b45ddd8ad38706f8e446888df359a7177b6bc55a964f9"
},
"objdiff_percent": 80.361855
"objdiff_percent": 92.56863
}
},
{
@@ -0,0 +1,166 @@
# action_vehicle.obj - opus5 250K house-clean lane, wave w3d (2026-09-15)
Unit: `source/ai/action_vehicle.c`. Worker notes: `scratch/workers/w3d_action_vehicle.md`.
Scratch: `scratch/workers/w3d_action_vehicle/`. Predecessors: the 11 earlier
`action_vehicle_obj_*` ledgers, in particular `_obj_opus5_100k_20260914.md` and `_obj_opus5_150k_w1_20260914.md`.
## Baseline and result
| | exact | residual | unwritten |
| --- | ---: | ---: | ---: |
| HEAD (baseline, guard on) | 12 | 5 | 0 |
| after w3d | 13 | 4 | 0 |
Newly strict EXACT: `_action_vehicle_evaluate_seat` - 976 padded bytes, 30 relocations, sha 9f67690555e799a6.
No parks for this unit; no baseline-exact row changed; `_point_from_line3d` emitted-symbol guard passed.
Remaining non-exact rows: `_action_vehicle_desirable` 272 [size 288, sha], `_action_vehicle_find_destination`
1232 [size 1248, sha], `_action_vehicle_setup_impromptu` 464 [sha], `_distance3d` 64 [sha].
## 1. What unblocked the object
`scratch/w3/laws_w3.md` section B lists, under "Newly ADMITTED by verifiers (do not avoid)":
"(real_point2d const *)&point3d casts into 2D helpers (32 source sites, HCEA); A15 role order for distance2d",
landed in wave w3a as `_actor_move_avoidance_setup` (see `actor_moving_obj_opus5_150k_w3_20260914.md` line 77).
Wave w1 had already produced a strict-EXACT `_action_vehicle_evaluate_seat` body and withheld it for exactly that
policy. The 2026-09-15 owner rulings (brief sections 9b/9c) do not touch the cast class, so no new ruling was needed.
## 2. `_action_vehicle_evaluate_seat` - EXACT, landed
Target 976 / 30 / 9f67690555e799a6; HEAD was 960 / 31 / sha.
Structural census before the work:
- One relocation too many (31 vs 30). January calls `_normalize2d` twice (@0x00c1 for the entry facing, @0x0283
for the to-seat direction) and `_tag_get` twice; ours inlined the second normalize2d and emitted an extra
`_tag_get` produced by the C4013 implicit declaration of `vehicle_specific_definition_get` at line 471
(`scratch/gate4/c4013.txt`).
- 16 bytes short (960 vs 976) from the same two effects plus the frame.
The landed body combines five measured levers:
1. **A7 missing prototype.** `#include "units/vehicle_definitions.h"` - the genuine owner, which defines
`vehicle_specific_definition_get` as a macro over `tag_get` at vehicle_definitions.h:30. No consumer-local
prototype (R8). This also removes the paired C4047 "differs in levels of indirection" warning.
2. **Admitted 2D-helper casts.** `normalize2d((real_vector2d *)&facing)`,
`distance2d((real_point2d const *)&actor->input.position.body_position, (real_point2d const *)&entrance_point)`,
the MIN of that and the seat distance, `vector_from_points2d(... , &to_seat_direction)` and
`dot_product2d(&to_seat_direction, (real_vector2d const *)&actor->input.facing_vector)`. `const` is used wherever
the real_math.h parameter is `const`, matching the admitted w3a idiom.
3. **A23-class loop spelling.** `while (prop = prop_iterator_next(&iterator))`. A rotated
`for (prop = next; prop; prop = next)` inflates the estimated frequency of the code after the loop and inlines
the second `normalize2d`; the while form leaves it out of line exactly like January. The idiom is already in the
tree at actions.c:4454, action_obey.c:1826 and actor_looking.c:734.
4. **Sibling scope.** The prop iterator and `prop` live in their own block around the loop, so VC7 shares their
8-byte slot with `to_seat_direction` ([ebp-0x18]) and the frame drops 0x5c -> 0x54.
5. **A3/A29 single exit.** `result = TRUE` after the entrance-point success, `result = FALSE; break;` for the
conflicting actor, the whole publish tail under `if (result)`, one `return result;`. This reproduces January's
three epilogues: the break threads to `xor al,al`, the success path tail-duplicates `mov al,1`, the failures
share `mov al,bl`.
6. **A17 discarded validation call.** The `if (!allow_any_seat)` block is the bare statement
`vehicle_specific_definition_get(vehicle->definition_index);` followed by
`unit_seat_is_driver(vehicle_index, seat_index);`. The earlier candidate used an unused local plus a `(void)`
cast, which A17 rejects.
Shapes: E1 (the w1 body, re-gated at this HEAD) EXACT; v1 = E1 plus the const casts and the A17 bare statement,
EXACT - landed.
Checks: all 12 baseline-EXACT rows preserved (row-by-row `--all` diff); guard passed; `scratch/parkcheck.py` reports
no parks for the unit; owner census versus `build/base` adds only `_dot_product2d`, a real_math.h select-any
header-inline COMDAT of the class laws_w2 A4 accepts as systemic (`_vector_from_points3d`, `_magnitude_squared3d`,
`_normalize2d`, `_square_root`, `_scale_vector2d`, `_vector_from_points2d`, `_magnitude2d`, `_magnitude_squared2d`,
`_distance_squared3d` are already candidate-only owners at HEAD, so R14 is not newly triggered); no data, BSS or
COMMON change; `tools/fake_match_scan.py` 0 leads (HEAD 0); `CL /Zs /W3` removes C4013 and C4047 and adds nothing.
Authenticity: the routine computes the seat entry facing from entrance to seat in the XY plane, falls back to the
actor own facing vector when that degenerates, takes the nearer of the entrance and seat 2D distances, rejects the
seat when a friendly actor is already closer to the same seat, and publishes weight / range / facing / fake flags
only for an accepted seat. Every helper used is the real_math.h routine the arithmetic is named after.
## 3. `_action_vehicle_find_destination` - structural gap closed in scratch, not landed
Target 1232 / 34 / 698d66d07e83af5b; HEAD 1248 / 34, frame 0x468 against the January 0x464.
Census (recorded before any shape):
- **Relocation census by target**: 34 versus 34, every symbol count equal, with ONE real difference -
January references `__real@3dfae147` where we emit `__real@3dfae148`. `0x3dfae147` is `(float)(0.35f*0.35f)`,
the square of the float 0.35f; `0x3dfae148` is the decimal literal `0.1225f`. The HEAD source writes the folded
literal; January wrote the product. This is an emitted-constant fidelity defect, not a tie.
- **Relocation ORDER**: January calls `_global_collision_bsp_get` at @0x40f, BEFORE the `_global_up3d` read at
@0x418; ours calls it at @0x47e just before `_collision_bsp_test_vector`. By the store/call-order law the BSP
pointer is obtained before the test_point and down_vector statements, i.e. it is a block-top declaration
`struct collision_bsp *collision_bsp = global_collision_bsp_get();`, not an inline argument.
- **Frame census** (`slots.py` over `alndiff --include-equal`): January `sub esp,0x464`, ours `sub esp,0x468`.
Ours owns one extra dword `[ebp-0x50]` (3 references, all in the trailing collision block) which pushes the
collision result buffer from `[ebp-0x464]` to `[ebp-0x468]`. January packs BOTH trailing aggregates into slots
the earlier block already owns (test_point -> [ebp-0x10..-8], down_vector -> [ebp-0x24..-0x1c]); ours packs only
down_vector. laws_w2 A6 side law: nested-block locals may pack.
- **Statement order from the aligned stream**: January computes `marker.x - actor_position->x` and
`marker.y - actor_position->y` at @0x116/@0x130, i.e. in the OUTER block before `anchor_point` is assigned, and
reuses those two cells in the `t` numerator and the perpendicular sign test - a named outer-block 2D vector is
missing from HEAD. The tail is single-exit (`test al,al; je <fail>` with the success block inline, `mov al,1`
and a separate `xor al,al` epilogue). `*surface_index_reference` is stored FIRST, its load interleaved into the
x destination product.
All five defects are implemented by the w1 diagnostic body `x5.c`, which the cast admission now makes usable. On
top of it this wave spent five evidence-led shapes:
| shape | change | result |
| --- | --- | --- |
| s1 | the two hand-written 2D sign dots become `dot_product2d(...)` calls (A35(1)+(2)) | 411 vs 412 insns; also closed the point_from_line2d x87 CSE pop and the magnitude_squared3d k,j,i sum order. KEPT |
| s2 | `collision.t*down_vector.i + test_point.x` (t-first) | byte identical, inert. REVERTED |
| s3 | `scale_vector3d(global_down3d, 4.0f, &down_vector);` for the three component multiplies (A35(1) leaf age) | 412 vs 412 instructions at IDENTICAL addresses; closed the stray `fxch st(1)` and the Y/Z destination products. KEPT |
| s4 | surface_index store moved after the destination stores | worse. REVERTED |
| s5 | dot-2 argument swap | byte identical - confirms laws_w3 A44. REVERTED |
Fixed point `scratch/workers/w3d_action_vehicle/fd_cand.c` (the current real file with only find_destination
replaced): 1232 / 34, `[sha]` only - the `[size]` tag is gone - 412/412 instructions at identical addresses,
whole-TU `== exact 13 residual 4`, guard passed, fakescan 0 leads, no new warnings, owner census +`_dot_product2d`
and +`_scale_vector3d` (both A30/A4 accepted class) and the `.rdata` literal corrected to `__real@3dfae147`.
Eleven instructions remain, in four x87 leaf-age / scheduling families: the i-term of the first inlined
`dot_product2d` (@0x284), both terms of the second (@0x36e, @0x377), the interleave of the
`debug->field_F8 = chosen_point` loads against the `debug->field_F4 = TRUE` byte store (@0x3dd), and the X
destination product (@0x483/@0x48c; Y and Z now match).
NOT LANDED under brief section 6: an already-written residual may be landed only when it becomes strict EXACT, and
this candidate is not below the January size or relocation count, so the fuzzy allowance does not apply.
Reopen criterion: a source lever that flips x87 leaf age inside an inlined `dot_product2d` or a named-local product
without an R3 operand swap (A35 is diagnostic only today); or an orchestrator decision to take the strictly-closer
zero-credit body for its proven fidelity content - notably the emitted constant, where HEAD writes `0.1225f`
(`__real@3dfae148`) and January writes `0.35f*0.35f` (`__real@3dfae147`).
## 4. `_action_vehicle_desirable` - initializer proven, blocked by the pending A42 ruling
Target 272 / 7 / e3b1ecf64be4fb82; HEAD 288 / 7 (100 versus 112 instructions).
Census: relocations 7/7 with identical targets; frame slots identical apart from one extra `[ebp-8]` read. The
16-byte gap is therefore not a frame gap: it is our two extra reloads of the datum homed at `[ebp-8]` plus the
position of `xor bl,bl`.
New evidence this wave: laws_w3 A38/A42 fire. January zeroes BL at 0x2b, before the `test al,4` dead-bit compare at
0x2d, which A42 reads as proof of a declaration initializer. Shape `d4` - `boolean desirable = FALSE;` at the
declaration plus `if (!TEST_FLAG(vehicle->object.damage_flags, _object_dead_bit)) { if (scripted_request) ... else
... }`, with no redundant store anywhere - reproduces that hoisted `xor bl,bl` exactly and brings the row to
**272 bytes, the January size**, at 101 versus 100 instructions. So the initializer, not the w1 `vd` redundant
dead-arm store, is what the January entry proves.
Two families still differ in `d4`, and they are coupled:
- January keeps `vehicle_index` in its incoming ESI and the vehicle datum in EDI (pushing only ebx and edi);
`d4` moves `vehicle_index` into EDI and the vehicle datum into ESI, which flips the private ABI of the static.
`_action_vehicle_perform` (768) and `_action_vehicle_setup_specific` (336), both exact at HEAD, then fall back to
`[sha]` (`== exact 11 residual 6`). Losing an exact row is a regression, so `d4` is not landable.
- January lays the not-dead block out of line (`je 0x58`, `jmp 0x31` back); the `d4` `if (!dead) { ... }` body stays
inline. HEAD's `if (dead) X; else if ... else ...` chain reproduces the January layout, but its first arm cannot
be empty, so the only spelling carrying BOTH the initializer and the chain is the w1 `vd` redundant store.
Reopen criterion: the pending A42 owner ruling on byte-proven redundant stores (laws_w3 C3 groups
`_encounter_test_rule`, `_extract_sequence`, `_action_alert_next_position` and `_action_obey_command_begin` here).
If granted, `vd` plus this wave's initializer evidence closes desirable at 272, and the w1 ledger records that
`_action_vehicle_setup_impromptu` then has only the inlined x,z,y square order left.
## 5. Not targets this wave
`_action_vehicle_setup_impromptu` (464, [sha]) and `_distance3d` (64, [sha]) were not in the w3d TARGET list and no
shapes were spent. w1 classified setup_impromptu as desirable-dependent (it inlines desirable) plus one x87
square-order tie, and `_distance3d` as exhausted - a caller-independent header COMDAT body whose two frozen waves
and the w1 `g1` rename-removal probe all produce z,x,y or z,y,x against the January x,y,z.
@@ -0,0 +1,218 @@
# `actor_moving.obj` — opus5 250K house-clean lane, wave w3d (structural pass, 2026-09-15)
## 1. Scope and provenance
- Translation unit `source/ai/actor_moving.c`; target `build/split/source/ai/actor_moving.obj`
(January 2002 Xbox debug build, VC7 13.00.9254, XDK 3911).
- Narrow structural pass over three rows only: `_actor_move_vector_avoidance`, `_actor_move_update`,
`_actor_get_stopping_distances`. No other row was touched.
- Measurements: `tools/campaign/gate.py --forbid-emitted-symbol _point_from_line3d`,
`tools.campaign.tinfo`, `tools.campaign.alndiff` (`--include-equal` for the frame census),
`tools.campaign.relocdiff --count-by-target --allow-structural`, `tools/campaign/branch_sweep.py`,
`tools/fake_match_scan.py`.
- Worker report with every census and shape: `scratch/workers/w3d_t3_actor_moving.md`.
Candidates and dumps: `scratch/workers/w3d_t3_actor_moving/`
(`base.c/base.obj`, `va_alndiff.txt`, `va_full.txt`, `mu_alndiff.txt`, `mu_full.txt`, `sd_alndiff.txt`,
`slots.py`, `va1.c/va1.obj`, `sd1.c`).
- Prior ledgers read: all fifteen `actor_moving_obj_*.md`, plus `scratch/WORKER_BRIEF.md`,
`scratch/w2/laws_w2.md` and `scratch/w3/laws_w3.md` (sections A–E).
## 2. Baseline and result
| | exact | residual | unwritten |
|---|---:|---:|---:|
| baseline (real file at HEAD) | 29 | 7 | 0 |
| final real-file gate | **29** | 7 | 0 |
`_point_from_line3d` guard passes at baseline and at the end. The unit has **no parks**, so there is no
park drift. `git diff --stat -- source/ai/actor_moving.c` is **empty**: nothing landed, by design.
`tools/fake_match_scan.py`: 0 review leads. Two shapes were spent in total (one per closable target),
both reverted in scratch.
Duplicate prevention: `git log --all --oneline -- source/ai/actor_moving.c` (21 commits; the newest is the
w3 landing `901a6ae73`, already in the baseline). `branch_sweep.py source/ai/actor_moving`: 18 unique blobs
across all branches; **HEAD is the best of them** (exact 29; next best 26). No donor body exists for any of
the three targets.
## 3. `_actor_move_vector_avoidance` — NOT LANDED; structural gap fully quantified, policy-blocked
Target 4144 / 135 relocs / `a8a8010c11375e82`; ours 4192 / 140. 1212 vs 1229 instructions; 236 hunks.
### Frame census
January `sub esp, 0x60e0`; ours `sub esp, 0x60ec` — **+12 = exactly one `real_vector3d`.**
The thirteen referenced cells of the `avoidance_data` aggregate have an identical shape in both builds
(4 cells, an 8-byte hole, then 9 cells) and are simply shifted by 0xc; the small-local region starts at
January `-0xa0` and ours `-0xac`. So ours allocates one surplus 12-byte cell and everything above it moves
down. The last six aggregate cells (`avoidance_data.left`, `.up`) are read **4× by January and 3× by us**.
### Relocation census
Only five rows differ, and they sum exactly to 140 − 135 = +5 (the `symbol:` vs
`defined-noncode:.rdata:` spelling of `__real@…` is a csplit artifact and is combined):
| target | JAN | OURS | delta |
|---|---:|---:|---:|
| `__real@00000000` | 21 | 24 | +3 |
| `__real@3f800000` | 24 | 28 | +4 |
| `_avoid_ray_avoidance_weights+4` | 4 | 2 | −2 |
| `_actor_move_transform_avoidance_vector` (REL32) | 1 | 2 | +1 |
| `_global_zero_vector3d` | 3 | 2 | −1 |
Everything else matches, including both `_actor_move_test_avoidance_vector` calls, both
`_actor_move_vector_avoidance_find_direction` calls, `_csmemset`, `_csmemcpy`, `_angle_between_vectors3d`,
`_avoidance_directions+0/+4/+8`, `_sense_rays`, `_avoidance_rays` and the five
`__real@3f1a36e2e0000000` normalize3d epsilons (**normalize3d inlines at the same 5 sites in both builds**).
### Defect (a): January inlines the transform at the `perpendicular` site — one mechanism, four deltas
January's only `_actor_move_transform_avoidance_vector` REL32 is at `+0xbff`, inside the `sharp_turn`
block (`_angle_between_vectors3d` follows at `+0xc92`). Its **third** `_global_zero_vector3d` reference is at
`+0xe74`, inside the `else if (maximum_sense_emergency > 0.f)` arm, and the bytes there are the transform
body expanded with the `forward` group folded away:
```
e73 mov eax,[_global_zero_vector3d] ; *direction_vector = *global_zero_vector3d
e7b mov ecx,[eax]; edx,[eax+4]; eax,[eax+8] -> [ebp-0x24]/[ebp-0x20]/[ebp-0x1c] (= rotation)
e86 movsx eax, word [ebp-0x28]; lea eax,[eax+eax*2]; shl eax,2 ; best_avoidance_direction*12
e96 fld [eax+_avoidance_directions+8]; fchs ; component = -avoidance_directions[best].k
ea5 fld [ebp-0x60bc] / [ebp-0x60b8] / [ebp-0x60b4] ; avoidance_data.left.i/.j/.k
ecc fld [eax+_avoidance_directions+4]; fst [ebp-0x44] ; component = avoidance_directions[best].j
ed5 fmul [ebp-0x60b0] / [ebp-0x60ac] / [ebp-0x60a8] ; avoidance_data.up.i/.j/.k
```
No `perpendicular` storage exists (the two components are consumed straight off the x87 stack) and no
`forward` term is emitted, because `perpendicular.i` is the compile-time constant `0.f`. That single
mechanism explains every remaining census delta: the extra call in ours, the missing
`_global_zero_vector3d`, the six missing `left`/`up` reads, and the +12 frame (VC7 scalar-replaces
`perpendicular` once the call is inlined).
**Why it cannot be landed.** `__forceinline` is forbidden (forced inlining, brief §5). The transform body
cannot be made cheaper: January's own bytes prove the `real component;` local (`fld [edx]` once at
`+0x25/+0x45/+0x65`, then `fld st(0)` to duplicate) and the `*global_zero_vector3d` copy, and the row is
already strict EXACT at 144. Writing the site out by hand is manual inlining (house rule 13 / laws_w3 R15);
the w3 worker self-withheld exactly that form, and it is the only reason w1's `va6.c` reached 4128/135.
### Defect (b): byte-proven arm polarity in the avoid-ray weight loop (new, admissible)
January at `+0x4a0`: `cmp word [esi],0 ; fld 1.0f ; jne 0x51b` — the **clear** case is the fall-through
THEN arm and the obstructed case is the block at the end. Our source spells it
`if (avoidance_types[ray_index] != _actor_vector_avoidance_clear) {obstructed} else {clear}`, so we lay the
obstructed arm out first (`je 0x4e5`). January's source is therefore
`if (avoidance_types[ray_index] == _actor_vector_avoidance_clear) { … } else { … }`
(laws_w3 A26 / laws_w2 A16: block layout follows source arm order).
### Defect (c): the weight multiply is tail-duplicated in January
January emits `fmul dword ptr [ecx]` (the strength-reduced `avoid_ray_avoidance_weights+4` walker) at FOUR
sites (`+0x4be`, `+0x4f2`, `+0x511`, `+0x536`) — one per PIN arm of `clear_fraction` plus the obstructed
arm; we emit it twice because all clear sub-arms jump to a shared multiply. This is the
`−2 _avoid_ray_avoidance_weights+4` row.
### Shape measured
**va1** (`scratch/workers/w3d_t3_actor_moving/va1.c`) — defect (b) only. Result **4208 / 142**
(baseline 4192 / 140; target 4144 / 135), 239 hunks.
It **confirms (b) and (c) together**: the loop body becomes instruction-for-instruction January's shape and
the `_avoid_ray_avoidance_weights+4` relocation row goes 2 → **4 = January's 4**. The only residual left
inside the loop is a register fact: January keeps `obstructed` in **BL** (`xor bl,bl` in the preheader,
`mov bl,1` at `+0x53c`) while we spill it to `[ebp-0x39]`, which costs the +16 bytes.
NOT landed: an already-written residual may land only when strict EXACT (brief §6), and va1 is not strictly
closer on size, relocations or hunk count.
### Reopen criterion
(i) A measured VC7 mechanism that makes a same-TU, non-`__inline`, 13-statement function inline at ONE call
site — the one whose vector argument has a compile-time-zero component — while staying a call at the other;
or (ii) an owner ruling admitting the written-out transform at the `perpendicular` site. Start from `va1.c`
(loop shape already correct) plus a cause for `obstructed` living in BL.
## 4. `_actor_move_update` — SKIPPED-EXHAUSTED; the `[size]` tag is NOT structural
On the brief's DO-NOT-SPEND list; touched only for the mandated census, zero shapes spent.
- **Frame census: identical.** January `sub esp,0x44`, ours `sub esp,0x44`; every `[ebp-N]` cell exists in
both builds, none is JAN-only or OURS-only.
- **Relocation census: 72 / 72, every row equal.** No missing or extra call, global, literal or assert
string (including both `_normalize3d`, both `_normalize2d`, both `_valid_real_normal3d`,
`_vector_from_points3d`, `_rotate_vector_about_axis`, `_actor_move_vector_avoidance`,
`_actor_move_calculate_movement`).
- Only four slot use-counts differ: `[ebp-0x8]` (`crouch`) **20 vs 9**, `[ebp+8]` (the `actor_index`
parameter home) 6 vs 4, `[ebp-0x3c]` 6 vs 5, `[ebp-0xc]` 6 vs 7.
The entire 48-byte / 19-instruction gap is **register-allocation write-back traffic**: January writes
`crouch` back to its home at every assignment (`xor bl,bl; mov byte [ebp-8],bl`, sixteen sites) even though
`[ebp-8]` is never read back as a byte, while our build elides eleven of those write-through stores; plus
two extra `[ebp+8]` re-reads and one zero-register pin (`cmp word [esi+0x15e], 0` vs our
`cmp word [esi+0x15e], di`). A25's join-store lever already fires correctly for the one if/else that assigns
`crouch` — both builds emit the merged `mov byte [ebp-8],bl` at the join (JAN `+0x400`, ours `+0x3f3`) — and
the remaining sixteen sites are switch-case constant assignments with no arm to merge.
**Recommendation:** reclassify this row from `[size]`-structural to an allocation tie so that no future wave
spends a structural pass on it. Reopen criterion: a measured VC7 lever that forces write-through of a byte
local sharing a recycled, address-taken 4-byte cell.
## 5. `_actor_get_stopping_distances` — NOT LANDED; the laws_w3 C1 reopen criterion is REFUTED
Target 464 / 11 relocs; ours **464 / 11**. 156 vs 156 instructions. Frame identical. Relocation census:
**0 differing rows**. Exactly one real hunk:
```
T f6 fld dword ptr [esi + 0x24] ; biped->object.forward.i
T f9 fmul dword ptr [esi + 0x18] ; biped->object.translational_velocity.i
O f6 fld dword ptr [esi + 0x18]
O f9 fmul dword ptr [esi + 0x24]
```
`laws_w3` C1 (A35(4)) asks for "an earlier by-name read of the same fields … an earlier hand expansion that
ages velocity/forward before the dot". A full scan of the **target** stream for `esi`-based field reads
gives `[esi] 2, [esi+0x18] 2, [esi+0x1c] 2, [esi+0x20] 2, [esi+0x24] 2, [esi+0x28] 2, [esi+0x2c] 2` —
each velocity/forward component is read exactly twice in January, once in the vehicle dot at `+0x89` and
once in the biped dot at `+0xf6`, and `[esi]` twice for the two `definition_index` loads. **There is no
earlier read of `translational_velocity` or `forward`, by name or otherwise, anywhere in January's
`_actor_get_stopping_distances`**, so the A35 leaf-aging mechanism cannot explain this row.
What January does show: the two dots are the same inlined `dot_product3d` spelling, and January flips the
i-term in the biped one only (vehicle `+0x89` `fld [esi+0x18]; fmul [esi+0x24]`, biped `+0xf6`
`fld [esi+0x24]; fmul [esi+0x18]`), with the j and k terms identical at both sites. The instructions
interleaved into the biped dot (`mov ecx,eax` / `mov al,[ecx+0x2f4]` / `add esp,8` / `test al,4`) are
byte-identical to ours, so the flip is decided inside VC7's commutative x87 lowering (laws_w3 A44, "the
inliner canonicalises inline-call evaluation order by liveness"), not by anything visible at the call site.
laws_w2 R3 forbids an operand swap justified only by x87 load order, and the helper body lives in
`source/math/real_math.h`, which workers may not edit.
Shape measured — **sd1** (`scratch/workers/w3d_t3_actor_moving/sd1.c`): move `biped_definition_get` after
the dot (`struct biped_definition *definition;` + assignment) so the leaf creation order changes.
Result **448 != 464 [size]** — structurally worse, refuted; it also positively proves that January's
definition fetch precedes the dot (`call tag_get` at `+0xd6` before the first `fld` at `+0xdb`).
**Reopen criterion (replaces the refuted A35(4) one):** a measured VC7 rule that decides the `fld` operand of
a commutative `mem*mem` product differently for two identically-spelled inlined `dot_product3d` calls inside
one function, or an owner ruling on editing `real_math.h`'s `dot_product3d` association.
## 6. Proposals
No header, `symbols.json`, `parked.json` or other config change is needed or proposed by this wave.
Two board-hygiene items for the orchestrator (no bytes, no source change):
1. Reclassify `_actor_move_update` (3136) from a `[size]`-structural residual to an allocation tie
(census in §4: frame identical, relocations identical).
2. Retire the `laws_w3` C1 row for `_actor_get_stopping_distances` (464): its stated reopen criterion is
refuted by January's own bytes (§5). It is a one-instruction-pair commutative x87 tie.
## 7. Do-not-repeat (added)
- `_actor_move_vector_avoidance`: do not re-derive the frame gap — it is `perpendicular`, and it disappears
only when the transform is inlined at that site. Do not re-measure a call/`__inline`/`__forceinline` form
of the transform (w1 already measured `__forceinline` at 4304). The arm polarity of the avoid-ray weight
loop is settled by January's `jne` at `+0x4aa` (clear arm first); va1 measures it at 4208/142.
- `_actor_move_update`: do not spend a structural pass — frame and relocations are identical; the gap is
`crouch` write-back traffic.
- `_actor_get_stopping_distances`: do not look for an earlier by-name read of the biped velocity/forward
components; January has none. Do not re-order the `biped_definition_get` fetch (sd1, 448 [size]).
## 8. Disposition
`actor_moving.obj` remains active, not Matching: 29 / 36 strict exact, unchanged by this wave. No new exact
credit, no fuzzy landing, no park change, no owner change, and the real file is byte-identical to HEAD.
The wave's product is the three censuses, the two new measured facts in `_actor_move_vector_avoidance`, and
the refutation of one third-pass candidate.
@@ -0,0 +1,219 @@
# `actors.obj` Opus5 250K lane, wave w3d: structural pass on the three size-gap parks (2026-09-15)
## Scope and provenance
- Translation unit `source/ai/actors.c`, target `build/split/source/ai/actors.obj`.
- Lane `C:\halo-worktrees\opus5-150k-house-clean-20260914`, branch `opus/250k-house-clean-20260915`.
`source/ai/actors.c` is unchanged since `5a84a96dd`; **the real file was not modified in this wave**
(`git diff --stat -- source/ai/actors.c` is empty).
- Compiler: XDK VC7 13.00.9254 `/O2 /Oy- /DDEBUG /Dxbox` (build.ninja, unchanged).
- Assignment: STRUCTURAL PASS over `_actor_input_update` (2384 vs 2400), `_actor_place` (800 vs 816, w3 C1
third-pass row with law A24) and `_actor_customize_unit` (640 vs 672). All three are parked, so every
measurement is scratch-only.
- Evidence used: the January split COFF and its listings; `relocdiff --count-by-target --allow-structural`;
per-function `[ebp±N]` frame censuses; `scratch/w2/laws_w2.md` and `scratch/w3/laws_w3.md` applied as
detectors; HCEA `blam/ai/actor_place.c`, `actor_customize_unit.c`, `actor_input_update.c` (behaviour and
statement order only); the w2/w3 scratch bodies re-gated at HEAD.
- Worker notes: `scratch/workers/w3d_t3_actors.md`. Scratch: `scratch/workers/w3d_t3_actors/`.
## Baseline and final (real file)
`gate.py source/ai/actors --all --forbid-emitted-symbol _point_from_line3d`
- **Baseline:** 70 exact, 6 residual, 0 unwritten; point guard passes
(`scratch/workers/w3d_t3_actors/baseline_gate.txt`).
- **Final:** byte-identical listing (`final_gate.txt`; `diff` against the baseline is empty). Guard passes.
- **Parks:** `scratch/parkcheck.py` reports 5 parks, 0 drift.
- **Fake scan:** `tools/fake_match_scan.py source/ai/actors.c`, 0 review leads.
- **Owner census:** not applicable to the real file (unchanged); measured for the scratch candidates below.
- **branch_sweep:** 34 unique blobs, current HEAD blob is the best (70 exact).
| Function | Target | Real file | Park class | w3d outcome |
| --- | ---: | ---: | --- | --- |
| `_actor_create_for_unit` | 624 / 29 | 624 | register-allocation | not a target this wave |
| `_actor_customize_unit` | 640 / 26 | 672 | unclassified | **not landed** — full census, 2 shapes, tie |
| `_actors_spawn_from_unit` | 672 / 29 | 672 | instruction-scheduling | not a target this wave |
| `_actor_place` | 800 / 41 | 816 | unclassified | **not landed; STRUCTURAL GAP CLOSED in scratch (800/41)** |
| `_actor_input_update` | 2384 / 89 | 2400 | unclassified | **not landed** — census shows no new structural gap |
| `_actor_unit_control` | 784 / 48 | 784 | — | owner-blocked (units.c protected, E1) |
## 1. `_actor_place` — the structural gap is a STATEMENT ORDER defect (A20)
### Census
- **Relocations:** 41/41, identical target multiset. No missing or extra call.
- **Frame:** January `sub esp,0x190`, ours `sub esp,0x194`. Ours carries **one extra own 4-byte cell**.
- January: `encounter_name[256]` at `[ebp-0x190]`, `placement_data` (0x88) at `[ebp-0x90]`,
`swarm` at `[ebp-8]`, `initially_braindead` at `[ebp-4]`; `unit_index` lives in `initial_variant`'s
parameter home `[ebp+0x1c]` and `initial_state` in `upgrade_major`'s home `[ebp+0x18]`;
`default_state` and `actor_definition` never leave EDI.
- Ours: the same aggregates shifted by 4, **plus `unit_index` in its own cell `[ebp-8]`**, `swarm` pushed to
`[ebp-0xc]`; `actor_definition` spilled to `[ebp+0x18]` at 0x9e and `default_state` homed as well.
- So ours spills six values into five slots where January spills four into four. The two extra spilled values
are `actor_definition` and `default_state`, both of which January keeps in EDI, because January takes EBX
for `starting_location` at entry (`push ebx` precedes the `starting_location` assert) while ours puts
`starting_location` in EDI and shrink-wraps EBX onto `squad_index` at 0x17b.
### Derived defect and fix
January's independent stores inside `if (encounter_index != NONE)` are, in order, `mov byte [ebp-4],dl`
(`initially_braindead`, 0x224) and then `mov word [ebp+0x18],cx` (`initial_state`, 0x227). By law A20
(independent stores keep source order) the braindead flag is assigned FIRST. HCEA `blam/ai/actor_place.c` has
exactly that order. Our body assigned `initial_state`, `default_state`, then the flag.
**`pl_o1`** — move
`initially_braindead = TEST_FLAG(encounter_definition->flags, _encounter_braindead_bit);`
ahead of the two squad-state assignments, nothing else:
- `_actor_place` **800 / 41**, normalized sha
`ce8124335417a81a5e1448d24f1fa9176741033aa2c9ffc59b15faa6c8b23c03` (target 800/41 `a4258acc…`).
- frame becomes 0x190 and the whole slot map becomes January's, including `unit_index` in `[ebp+0x1c]`
and `initial_state` in `[ebp+0x18]`;
- whole-TU gate: 70 exact, 6 residual, guard passes, no baseline-exact row changes;
- owner census vs `build/base/source/ai/actors.obj`: 190/190, no candidate-only and no base-only owner;
- **no header or config change is needed for this.**
### Remaining residual after `pl_o1` (+ the E11 type fact)
With E11 applied in a shadow tree (`pl_n1`, 800/41,
`3a33538607b4cb44c23e441317ca7e4236b613b3e226db7a7f93269a71ee2295`) January's
`movsx <16-bit>, byte ptr [eax+0x12]` argument form is reproduced and the body is byte-identical up to 0x249.
The entire residual is then the emission order of three argument pre-loads for `actor_create_for_unit`:
```
January: mov edx,[ebp+0x18] (arg 9 initial_state)
xor ecx,ecx / mov cx,[eax+0x1a] (arg 11 command_list_index)
movsx ax, byte [eax+0x12] (arg 12 noncombat_sequence_id)
ours: movsx dx, byte [eax+0x12] (arg 12)
movsx eax, word [eax+0x1a] (arg 11, dest==base -> the w2 lab-t11 movsx form)
mov ecx,[ebp+0x18] (arg 9)
```
January evaluates 9, 11, 12 (left to right), ours 12, 11, 9. Everything after that (ecx/eax/edx rotations in the
two warning blocks and the epilogues) follows from it. 270 vs 269 instructions; sizes and relocations equal.
### Shapes (7)
| shape | change | result |
| --- | --- | --- |
| pl_d1 | `long unit_index;` declared before `placement_data` | 816/41, identical to base |
| pl_d2 | pointer/scalar declarations moved after the aggregates | 816/41, identical to base |
| **pl_o1** | braindead assignment first (A20 + HCEA) | **800/41 `ce812433…` — structural gap closed** |
| pl_o2 | pl_o1 + squad fetch and state assignments in a nested block | 800/41 `9466a0dc` |
| pl_n1 | pl_o1 + E11 `short noncombat_sequence_id` (shadow header) | 800/41 `3a335386` |
| pl_n2 | pl_o2 + E11 | 800/41 `c932b184` |
| pl_n3 | pl_n1 + `initial_state`/`default_state` declaration swap | identical to pl_n1 (inert) |
## 2. `_actor_customize_unit` — the `[size]` tag is a coalescing tie, not a structural gap
### Census
- **Relocations:** 26/26, identical target multiset.
- **Frame:** `sub esp,0x98` in both, four dword slots plus `placement_data` in both, identical parameter homes.
The only difference is the occupant of `[ebp-0xc]`: January spills the `change_colors` element pointer there,
ours spills `actor_variant_definition`. A24 does not fire.
### Byte accounting (+21 real bytes)
3 (`actor_variant_definition` spill at 0x25) + 2 (memory-only loop-counter init) + 4 (`jle` rel8->rel32)
− 3 (`change_colors` kept in EBX) + 3 (memory-only loop increment) + 3 + 3 + 3 (three `unit` reloads at joins)
+ 8 (two `je error` rel8->rel32 because the error block is sunk past the first epilogue) − 5 (camo block).
Root cause: callee-saved coalescing. January pairs EDI = `unit` then the loop counter and keeps EBX =
`actor_variant_definition` for the whole function; ours pairs EBX = `unit_index` then `change_colors` and keeps
`unit` re-cached in ESI at three joins, which leaves the loop counter in memory. The error-block sink and all
three jump growths are downstream of the extra join blocks.
### Shapes (2)
- **cu1** — equipment powerup test written positive-first
(`!= _equipment_powerup_none && != _equipment_powerup_grenade`, placement body as the then-arm, `error()` in
the else arm), which is the form HCEA `blam/ai/actor_customize_unit.c` keeps. Result 672/26, sha `0a9c42b8`,
**byte-identical to base**: VC7 canonicalises the polarity and still sinks the error block.
- **cu2** — `short change_color_index;` declared ahead of `struct object_placement_data placement_data;`.
672/26, byte-identical to base.
Classification: SKIPPED-EXHAUSTED / register-coalescing tie.
## 3. `_actor_input_update` — no structural gap remains beyond the existing scratch body
### Census
- **Relocations:** 89/89, identical target multiset.
- **Frame:** `sub esp,0x24` in both, the same seven slots plus `[ebp+8]`. Only the reference counts differ
(`[ebp-4]` 4 vs 9, `[ebp-8]` 7 vs 3, `[ebp-0x10]` 2 vs 4): ours makes one extra `unit` reload, which raises
`unit`'s reference density and swaps the `-4`/`-8` occupants (the w2 finding, re-confirmed).
### The structural gap is already closed by `iu3`
`scratch/workers/w3_actors/iu3.c`, re-gated at this HEAD as `scratch/workers/w3d_t3_actors/iu3.obj`:
**2384 / 89**, sha `f6ff0151006bb86f` — target size and target relocation count, 70 exact rows unchanged,
guard passes. Its residual has one root:
1. `0x6a6` — January `lea edx,[ebx+0x1ec]` keeps EBX = `unit` live into the join, where `add ebx,0x210` is its
last use; ours does `add ebx,0x1ec` and then reloads `mov eax,[ebp-4]` at the join.
2. That reload produces the `-4`/`-8` slot swap and the register rotations at 0x4d3 / 0x517 / 0x590 / 0x5b0
(all pure renames — the apparent `game_team_is_enemy` argument difference in the aligned diff is an
alignment artifact; the two byte streams are structurally identical there).
3. Five of the twelve products in the two inlined `cross_product3d` bodies `fld` the other leaf (A22/A35). The
helper argument roles were re-verified against HCEA and are correct, as is the `normalize2d` polarity
(January `test ah,0x41; jne` makes the `> 0` case the fall-through, which is our then-arm) and the
`burning_to_death` / `melee_attacker_attached` / `delayed_attached_projectile_index` store order.
No new shapes were spent: the census produces no structural defect beyond what `iu3` already fixes, and the w3
do-not-repeat table (iu3, iu4) plus R13 bind the tie budget.
## Orchestrator proposals
### P-A — `_actor_place` park re-baseline (actors.c only, no header edit)
Apply the `pl_o1` statement reorder and re-baseline the `_actor_place` entry in `config/parked.json` from
`816 / 41 / ff120b98736b6eb6…` to `800 / 41 / ce8124335417a81a5e1448d24f1fa9176741033aa2c9ffc59b15faa6c8b23c03`.
Evidence: A20 store order in January (0x224 braindead before 0x227 initial_state) plus HCEA
`blam/ai/actor_place.c`. Effect: frame 0x194 -> 0x190 with January's exact slot map; 70 exact rows unchanged;
owner set identical to `build/base`; guard passes; other four parks unchanged. Strictly closer, zero strict
credit (R11), so it is worth landing as the prerequisite for the reopen criterion below or together with P-B.
### P-B — E11 upgraded: `short noncombat_sequence_id` (header packet)
- Text: `source/ai/actors.h:1038` `\tchar noncombat_sequence_id);` -> `\tshort noncombat_sequence_id);`, and the
matching definition line in `source/ai/actors.c`. Do **not** change the struct field at `actors.h:457`
(`char noncombat_sequence_id;`) — January's `movsx <16-bit>, byte ptr [eax+0x12]` proves a signed *byte
field* read into a *short parameter*.
- Evidence: January `_actor_place` +0x252; the w2 lab t11 table (`signed char` field + `short` param ->
`movsx r16, byte ptr`; + `char` param -> `xor r,r; mov r8`, which is today's form).
- Consumers: 46 `actors.h` includers. Only three TUs call `actor_create_for_unit`: `actors.c` (2 sites),
`ai.c` (`ai_disconnect_from_structure_bsp`), `ai_script.c` (`ai_scripting_attach_unit`,
`ai_scripting_attach_free`); the latter two push the constant 0.
- Measured through a shadow header (pickup proven with an injected `#error`): `source/ai/ai` stays 42/46 and
`source/ai/ai_script` stays 112/116 with identical residual rows; `actors.obj` stays 70/76 with
`_actor_place` at 800/41 `3a33538607b4cb44…`. A full-board rebuild is still required.
- Note: VC7 13.00.9254 does not reject a `char` prototype against a `short` definition, so both halves must be
changed together for source correctness.
### P-C — unchanged
units.h/units.c `short animation_impulse` (E1) remains the only blocker for `_actor_unit_control` 784;
`units.c` is protected in this lane.
## Do-not-repeat (additions)
| Function | Spellings that are inert or rejected |
| --- | --- |
| customize_unit | positive-first equipment powerup test (byte-identical); `change_color_index` declaration moved ahead of `placement_data` (byte-identical) |
| place | `unit_index` / `actor_definition` declaration-position moves (byte-identical); `initial_state`/`default_state` declaration swap on top of pl_o1 (inert); squad fetch in a nested block (pl_o2/pl_n2, 800/41 but a different sha and no closer) |
## Reopen criteria
- `_actor_place`: any source form that makes VC7 evaluate the 9th argument (`initial_state`) before the two
`starting_location->` field arguments of `actor_create_for_unit`. With pl_o1 + P-B in place that is the only
remaining difference and the function becomes strict exact (800 B).
- `_actor_customize_unit`: a same-compiler allocation donor (or January local records) explaining why EBX goes
to the definition pointer and the loop counter is enregistered while `change_colors` spills.
- `_actor_input_update`: unchanged — a lever for the `unit` live-range split at the aiming join; start from
`scratch/workers/w3d_t3_actors/iu3.c` (2384/89).
## Disposition
The object is still 70/76 strict. Nothing was landed, no fuzzy credit was taken, and the real file is
byte-identical to HEAD.
@@ -0,0 +1,215 @@
# `effects.obj` Opus5 250K house-clean lane, wave w3d: structural pass (2026-09-15)
## Scope and provenance
- Translation unit `source/effects/effects.c`, target `build/split/source/effects/effects.obj`.
- Compiler VC7 13.00.9254 (XDK 3911). No header, config, flag or tooling change.
- Lane `opus/250k-house-clean-20260915` (worktree `opus5-150k-house-clean-20260914`), worker `w3d:effects`.
- Assigned TARGETs (both parked and locked): `_effect_generate_particles` (1888, `[size 2048!=1888,
relocs 55!=46, sha]`) and `_effect_allowed_by_environment` (128, `[size 112!=128, sha]`).
`_effect_generate_part` was explicitly out of scope this wave.
- Every experiment ran on scratch copies under `scratch/workers/w3d_effects/`.
**The production file is unchanged** (`git diff --stat -- source/effects/effects.c` is empty).
- Worker notes with the mandatory censuses and per-function blocks: `scratch/workers/w3d_effects.md`.
- Evidence: the January target COFF (disassembly, relocations, jump tables, frame slots); the ledgers
`effects_obj_opus5_150k_w2_20260914.md`, `effects_obj_opus5_100k_waveD_20260914.md` and
`effects_obj_opus_reconciliation_20260904.md`; `config/parked.json`; the later HCEA per-function sources
(semantics only); effects.c's own exact functions for idiom precedent.
## Baseline (real file, HEAD)
`== exact 38 residual 3 unwritten 0 (of 41 listed)`. Point guard passes; park drift 0/3.
| residual (all parked) | target | base | tag |
|---|---|---|---|
| `_effect_allowed_by_environment` | 128/10 | 112/10 | size, sha |
| `_effect_generate_part` | 992/27 | 976/28 | size, relocs, sha (not a target) |
| `_effect_generate_particles` | 1888/46 | 2048/55 | size, relocs, sha |
## Census 1 - `_effect_allowed_by_environment`
**Frame census.** January: `push ebp; mov ebp,esp; push ecx` - exactly one 4-byte cell, read once at
`0x5f` (`mov al, byte ptr [ebp-1]`) and **never written on any path** (the whole 59-instruction body was
disassembled). Ours: frameless, no `[ebp-N]` at all.
**Control flow (jump-table order = case value order).**
```
ja 0x45 -> default
case 0 anywhere @0x13 : mov al,1
case 1 air @0x19 : call scenario_location_underwater; neg al; sbb al,al; inc al
case 2 water @0x2f : call scenario_location_underwater
case 3 vacuum @0x3f : xor al,al
default @0x45 : display_assert(NULL, file, 888, TRUE); system_exit(-1);
mov al,[ebp-1] <- returns an UNINITIALISED stack byte
```
**Relocation census.** 10 vs 10, every target identical; only the four internal jump-table entries differ -
January `[0x13,0x19,0x2f,0x3f]` (four distinct blocks), HEAD `[0x5b,0x16,0x2e,0x5b]` (case 0 and case 3
merged by the `boolean allowed = environment == _effect_environment_anywhere;` initializer). **No call or
global is missing on either side.**
**Structural defect derived.** The 16-byte gap is one extra exit block plus the 4-byte frame. January has
five distinct exits; HEAD has four, because its default arm returns a value that is neither `TRUE` nor
`FALSE` but a load of a never-written local.
## Census 2 - `_effect_generate_particles`
**Relocation census by target** (`relocdiff --count-by-target --allow-structural`): the whole +9 is one
inlined copy of the environment helper.
| target | January | HEAD | delta |
|---|---:|---:|---:|
| `_effect_allowed_by_environment` (call) | 1 | 0 | -1 |
| `_scenario_location_underwater` | 0 | 2 | +2 |
| effects.c `__FILE__` literal | 1 | 2 | +1 |
| `_display_assert` | 1 | 2 | +1 |
| `_system_exit` | 1 | 2 | +1 |
| `internal:` (table base + 4 entries) | 0 | 5 | +5 |
| all 26 other targets | = | = | 0 |
**Frame census** (`scratch/workers/w3d_effects/slots.py`): January `sub esp,0xe4`, HEAD `sub esp,0xe8`.
The aggregate set is identical, shifted one cell; the extra cell is the home of `count_delta`
(`mov [ebp-0xc8],ebx` @0x12d, reloaded @0x190) which January keeps in EBX while homing `instance` at
`[ebp-0xc]`. That is a register-role swap downstream of the inline (laws_w3 A44).
**Conclusion.** No missing statement, call, local or loop shape: the entire structural gap was one inline
decision.
## Results
Candidate: `scratch/workers/w3d_effects/c1_crlf.c` (CRLF, three hunks against the real file; LF twin
`c1.c`, object `c1_crlf.obj`).
| row | HEAD | candidate c1 | change |
|---|---|---|---|
| `_effect_allowed_by_environment` | 112/10 `[size, sha]` | **128/10 `[sha]`** | size + relocation identity now exact |
| `_effect_generate_particles` | 2048/55 `[size, relocs, sha]` | **1888/46 `[sha]`** | size + relocs now exact, frame exact |
| all 38 exact rows | EXACT | EXACT | unchanged (row-by-row diff) |
| `_effect_generate_part` | 976/28 | 976/28 | untouched |
Neither row becomes strict EXACT, so this wave claims **zero strict bytes**. Both rows are parked, so the
candidate is a **coupled park re-baseline** (laws_w3 "newly ADMITTED": a coupled re-baseline of a still-parked
callee to a strictly closer body when a control proves the caller needs it). The control is u1/v0:
with the same caller body, the helper is out of line only when the callee body changes.
### The three source hunks
1. `effect_allowed_by_environment`: `boolean allowed = FALSE;` and `case _effect_environment_anywhere:
allowed = TRUE; break;` replace the computed `allowed = environment == _effect_environment_anywhere;`
initializer. Semantics are unchanged (anywhere TRUE, air `!underwater`, water `underwater`, vacuum and
invalid FALSE) and the default-deny reading matches HCEA's reconstruction of the out-of-range case.
2. `effect_generate_particles`, attached arm: the file's own idiom
`short node_index = instance->node_designator; if (node_index != NONE) node_index &= ...;` replaces the
`?:`. Proven by January 0x3de-0x402, which stores the designator register itself in the NONE arm.
In-file precedent: effects.c:1672 and effects.c:1804 (both inside the exact-adjacent
`_effect_generate_part`).
3. `effect_generate_particles`, count computation: a separate `long last_particle_count` statement
evaluated first. Proven by January 0xd6-0x11d, which calls the integral with `last_event_fraction`
([ebp-0xc4]) first and homes that result in a 4-byte slot before calling with `event_fraction`
([ebp-0x14]). With this hunk the candidate is byte-identical to January from 0xd6 through 0x11d,
including the `movzx edx, byte ptr [ebx+edi+0xdc]` addressing HEAD does not produce.
### NEW LAW (w3d-1): the callee body, not the call site, sets a TU-static's inline decision
Call-site levers are inert at this site: respelling the inner `for`-with-increment as a `while` (A23
detector, g1) and adding an `if (count_delta > 0)` nesting level instead of `continue` (inline-frequency
detector, g4) both leave the row at 2048/55 with the helper still inlined. The callee body is decisive and
orders by cost:
| env body | env | generate_particles | generate_parts |
|---|---|---|---|
| per-case `return`s (cheapest) | 112/10 | 2016/55 (inlined) | **688/24 - exact row lost** |
| computed initializer (HEAD) | 112/10 | 2048/55 (inlined) | EXACT (called) |
| constant initializer + one assigning case | 128/10 | 1952/46 (**called**) | EXACT (called) |
| uninitialised local (January, prohibited) | EXACT | 1952/46 (**called**) | EXACT (called) |
Detector for other units: when January *calls* a TU-static at a hot site that we inline, do not respell the
caller - count January's distinct exit blocks in the CALLEE and reproduce them.
### The park's recorded negative is stale
`config/parked.json` for `_effect_allowed_by_environment` says "Simple FALSE initialization and
assignment-after-assert forms also produced 112 bytes but caused both callers to inline the assertion body
and regress broadly". The same entry dates itself by naming "the donor's better 1,616-byte and 592-byte
shapes in both real callers"; `_effect_generate_particles` was re-based to the corrected per-instance loop
nest (2048/55) on 2026-09-14. Against that caller the simple-FALSE-initialization form measures 128/10 with
both callers intact. The assignment-after-assert half of the premise still holds (112, probe e5).
### Why strict EXACT is still owner-blocked
`_effect_allowed_by_environment` reaches EXACT only with `boolean allowed;` left uninitialised so the
default arm returns the never-written home (probe u1, EXACT). That is prohibited by WORKER_BRIEF section 5
(uninitialised read) and fails R19: effects.c's own post-fatal-assert precedent,
`_effect_evaluate_function_integral` (exact at HEAD), returns a DEFINED fallback. HCEA
(`effect_allowed_by_environment.c:4`) corroborates the indeterminate original but is not a licence.
With the safe initializer the residual is a result-storage tie: a definite initializer makes `allowed` live
from entry across two `scenario_location_underwater` calls, so VC7 gives it a callee-saved register
(`push ebx; xor bl,bl; ... mov al,bl; pop ebx`); only the uninitialised local, whose live range starts
inside the arms, produces January's `push ecx` frame and AL-per-arm returns.
`_effect_generate_particles` residual under the candidate: 566 vs 562 instructions (was 622), 75 vs 120
aligned diff blocks. The four extra instructions are `mov [ebp-0xc0],ebx` (count_delta spilled) and the
per-instance `test bx,bx; jle` guard January elides because count_delta stays in EBX - exactly the
"loop guard and register form" the park text already records. Its environment-helper half is resolved.
## Experiment matrix (all scratch)
| probe | change | env | generate_particles | generate_parts |
|---|---|---|---|---|
| v0 | control (= HEAD) | 112/10 | 2048/55 | EXACT |
| e1 | env per-case `return`s | 112/10 | 2016/55 | 688/24 LOST |
| e2 | env `= FALSE` init + anywhere TRUE | **128/10** | **1952/46** | EXACT |
| e3 | env `= TRUE` init + vacuum FALSE | 128/10 | 1952/46 | EXACT |
| e4 | env `= FALSE` init, every case assigns | 112/10 | 2016/55 | EXACT |
| e5 | env default assigns FALSE before the assert | 112/10 | 2016/55 | EXACT |
| e6 | e5 with vacuum falling through | 144/10 | 1952/46 | EXACT |
| u1 | env uninitialised local (PROHIBITED, evidence only) | EXACT | 1952/46 | EXACT |
| g1 | inner `for` -> `while` + increment (A23) | 112/10 | 2048/55 inert | EXACT |
| g2 | node_index idiom | 112/10 | 2032/55 | EXACT |
| g3 | g2 + `last_particle_count` statement | 112/10 | 2048/55 | EXACT |
| g4 | `if (count_delta > 0)` instead of `continue` | 112/10 | 2048/55 inert | EXACT |
| u2 | u1 + g2 | EXACT | 1904/46 | EXACT |
| u3 | u1 + g2 + g3 | EXACT | 1888/46 | EXACT |
| **c1** | **e2 + g2 + g3** | **128/10** | **1888/46** | EXACT |
| c2 | e3 + g2 + g3 | 128/10 | 1888/46 | EXACT |
## Do-not-repeat (added by this wave)
- Call-site levers for the environment-helper inline: loop respelling (A23) and extra `if` nesting are both
measured INERT in `_effect_generate_particles`.
- `effect_allowed_by_environment` written with per-case `return` statements: it is cheaper to inline and
costs the exact `_effect_generate_parts` row.
- `effect_allowed_by_environment` with every case assigning explicitly (e4), or with the default assigning
before the assert (e5): both 112.
## Orchestrator proposals
1. **Coupled park re-baseline (zero strict credit)** of `_effect_allowed_by_environment` and
`_effect_generate_particles` from `scratch/workers/w3d_effects/c1_crlf.c`, as one object commit.
New park bases: env 128 / 10 / `8f9a2185534b3801`; generate_particles 1888 / 46 / `c251b0c184dbcdeb`.
Both are strictly closer (size and relocation count now exact on both rows); `_effect_generate_part`
does not drift; all 38 exact rows are unchanged.
2. **Park evidence text**, `_effect_allowed_by_environment`: replace the stale sentence about simple-FALSE
initialization with the e2/e5 measurements above; the reopen criterion (owner ruling (a)) is unchanged.
3. **Park evidence text**, `_effect_generate_particles`: the environment-helper inline decision is resolved
by a natural safe callee body; the remaining residual is the count_delta-EBX vs instance-EBX role swap
and the per-instance loop guard.
4. **Owner ruling (a) (unchanged question, now fully quantified):** if a read reachable only when
`system_exit(-1)` returns is admitted, `scratch/workers/w3d_effects/u3.c` makes
`_effect_allowed_by_environment` strict EXACT (128 B) and leaves `_effect_generate_particles` at
1888/46 `[sha]`. Without it, c1 is the ceiling.
## Checks (candidate c1)
Gate `== exact 38 residual 3`, only the two proposed rows change; point guard passes; `scratch/parkcheck.py`
drifts exactly those two parks and leaves `_effect_generate_part` at base; owner census vs `build/base` and
`build/split` is identical (no new candidate-only code/data/BSS/COMMON owner); `tools/fake_match_scan.py`
reports 0 leads, the same as HEAD.
## Final real-file gate
`== exact 38 residual 3 unwritten 0`, identical to the baseline row by row. Point guard passes, park drift
0/3, owner census identical, fake scan 0 leads. `git diff --stat -- source/effects/effects.c` is empty and
`newly_exact` is empty: nothing in this wave is strict EXACT without an owner ruling.
@@ -0,0 +1,123 @@
# `glow.obj`: Opus5 250K house-clean lane, wave w3d (structural pass, 2026-09-15)
## Result
Nothing landed. `source/objects/widgets/glow.c` is **unchanged** (`git diff --stat` empty).
Baseline and final real-file gate, with the `_point_from_line3d` guard: **exact 24 / residual 1 /
unwritten 0**, row-for-row identical. Park drift 0, fake scan 0 leads.
The single residual `_get_particle_world_position` (1,744 padded) is parked and blocked on an owner
ruling. This wave contributes:
1. a **quantitative January-side proof** of the original defect, from the relocation census, that the
w1 ledger could only infer;
2. **cross-build corroboration** from HCEA that the same defect shipped;
3. a **re-verification** that the w1 scratch candidate is still strict EXACT at this HEAD, and that it
now closes the whole object 25/25 with no header packet (the packet w1 needed for
`_glow_trailing_particle_new` has landed since).
## Duplicate checks
Ledgers read: `glow_obj_opus5_150k_w1_20260914`, `glow_obj_house_rule_reconciliation_20260908`,
`glow_obj_opus_source_admission_hold_20260906`, `glow_obj_jonas_complete_hcea_packet_20260830`,
`glow_obj_jonas_new_20260829`, `glow_obj_jonas_delete_20260829`,
`glow_obj_jonas_nonuniform_spline_pair_20260827`, `glow_obj_jonas_parametric_line_leaf_20260821`.
The w1 do-not-repeat list (four-statement knot copies, a bound marker pointer, cross-product
reordering, the unnamed `cos`/`sin` form, any further defined-C repair aimed at exactness) was
honoured; R13 binds it.
## Census (mandatory)
| | padded / relocs / sha16 |
| --- | --- |
| January target | 1744 / 43 / `84720a5067d22512` |
| real file (parked body) | 2528 / 55 / `fb7bb3c6b7236d62` |
**Relocation census by target** (`relocdiff --count-by-target --allow-structural`):
| relocation target | January | ours | delta |
| --- | ---: | ---: | ---: |
| `_display_assert` | 3 | 3 | 0 |
| `_system_exit` | 3 | 3 | 0 |
| `_nonuniform_cubic_spline_vector3d` | 3 | 3 | 0 |
| assert / file string literals | 6 | 6 | 0 |
| `__real@3f000000` (0.5f) | 14 | 20 | **+6** |
| `__real@3e800000` (0.25f) | 7 | 10 | **+3** |
| `__real@3f400000` (0.75f) | 7 | 10 | **+3** |
| TOTAL | 43 | 55 | +12 |
**Nothing is missing from our body.** There is no missing call, no missing global, no missing string.
Our body carries twelve *extra* float-constant references and 784 extra code bytes.
`point_from_parametric_line` inlines three components per call, so
- +3 at 0.25f and +3 at 0.75f is exactly one extra pair of parametric-line interpolations - the
two-marker path's side vectors;
- +6 at 0.5f is exactly two extra midpoint interpolations - the two three-marker sub-cases' side
vectors.
That is precisely the code that fills `sides[0..3]` on the degenerate paths. **The relocation census
therefore proves, from January's own bytes, that January never builds the side control vectors on the
two- and three-marker paths while still passing `&sides[0..3]` to the third
`nonuniform_cubic_spline_vector3d` call.** The w1 ledger asserted this from the frame layout; it is now
measured, and it also proves no defined-C body can reach 1744/43, because any correct initialization of
`sides[]` emits exactly those twelve references.
**Frame.** Not a frame gap. The local set is identical (`sides[4]`, `ups[4]`, `positions[4]`,
`knots[4]`, `delta`, `side`, `up`, `angle`, `sine`, `cosine`, four shorts); the difference is 784 bytes
of extra straight-line interpolation code inside two switch arms.
## New evidence beyond w1
**Cross-build corroboration.** HCEA's disasm-verified reconstruction of the shipped Xbox build
(`...\halocea-review\src\blam\objects\widgets\get_particle_world_position.c`, function at 0x8380BB00)
states in its own header comment, independently of this campaign, that the degenerate paths
"carry faithful shipped quirks and are reproduced verbatim: (a) several z-component interior control
points are lerped onto the *y* base of the endpoint rather than the z base; (b) the side-vector control
points (side_ctrl) are never filled on the 2/3 marker paths; and (c) the 3-marker interval-1 path reads
knot1 from the never-written knot scratch." Corroboration only - the January-side proof is the census
above - but it removes the "reconstruction artifact" reading of the w1 candidate.
**Candidate re-verified at this HEAD.**
`gate.py source/objects/widgets/glow --source scratch/workers/glow/owner_candidate.c --all
--forbid-emitted-symbol _point_from_line3d` -> **exact 25 / residual 0 / unwritten 0**, with
`_get_particle_world_position` EXACT at 1744. w1 measured 24/25 because `_glow_trailing_particle_new`
then required header packet C; that packet has since landed, so the candidate needs no header or config
change at all. Checks re-run at HEAD: guard passes; `scratch/parkcheck.py` reports drift only on the
reopened park itself (2528/55 -> 1744/43/`84720a5067d22512`, i.e. to the target - the expected reopen
signature); the owner census versus `build/base/source/objects/widgets/glow.obj` is identical, with no
new candidate-only code, data, BSS or COMMON owner; `tools/fake_match_scan.py` reports 0 leads.
## Shapes tried
None. Triage (brief step 0) classifies this row as an owner-ruling block rather than a live shape
search, and the relocation census makes that conclusive: our body is a strict superset of January's,
and the surplus is exactly the defect repair.
## Owner-ruling proposal (re-raised, with the new quantitative evidence)
Admit, for `_get_particle_world_position` only, the reproduction of two original Bungie defects under
the docs' `/* BUG (preserved for exact matching): ... */` form, then replace the parked body with the
body in `scratch/workers/glow/owner_candidate.c` and unpark it in a dedicated commit:
1. the two- and three-marker paths never fill `sides[0..3]`, which the unconditional third
`nonuniform_cubic_spline_vector3d` call then reads;
2. on the three-marker `parent_marker_index == 1` path the midpoint knot is written over `knots[2]`
instead of `knots[1]`, so `knots[1]` is never set
(`marker_time_index[1]` loaded at +0x2EA, midpoint stored at +0x5C6 into `[ebp-8]`, `[ebp-0xc]`
read unwritten at +0x5D2).
Both are reads of an indeterminate value from an address-taken automatic array, which brief section 5
currently lists among the undefined-behaviour exclusions. Supporting evidence: the January-side
relocation census; the January-side offsets above; HCEA's independent shipped-build reconstruction
naming both quirks; and a candidate that is strict EXACT, closes the object 25/25, loses no sibling,
adds no owner and scans clean.
Value: **1,744 padded bytes**, and it is the last non-exact row in `glow.obj`.
## Reopen criterion (unchanged, restated)
An owner ruling that admits these two preserved original defects for this function, or January evidence
that two- and three-marker glows can never reach the side spline (which would make the `sides[]` read
unreachable rather than indeterminate). No further defined-C repair should be attempted: the relocation
census proves that any correct initialization of `sides[]` adds the twelve constant references that
constitute the entire remaining gap.
@@ -0,0 +1,260 @@
# `input_xbox.obj` structural pass — opus5 250K house-clean lane, wave w3d (2026-09-15)
## Scope and baseline
- Worktree `C:\halo-worktrees\opus5-150k-house-clean-20260914`, branch `opus/250k-house-clean-20260915`.
- Owned source: `source/input/input_xbox.c` only. No header, config, build, tool or other source was touched and
nothing was committed. All three non-exact rows are parked in `config/parked.json`, so every body was built and
measured in scratch only; the real file is byte-unchanged (`git diff --stat -- source/input/input_xbox.c` empty)
and its final gate is identical to the baseline.
- Baseline and final real-file gate (with the `_point_from_line3d` guard): **`== exact 24 residual 3 unwritten 0`**.
- Park drift on the real file: none (`scratch/parkcheck.py`, 3 parks, 0 drift).
| function | January padded / relocs / sha16 | real file | wave outcome |
| --- | --- | --- | --- |
| `_input_get_device_states` | 1232 / 28 / `56316233dc2ab683` | 1280 / 32 / `b7cded6529564446` | NOT LANDED — 1 allocator hunk (best scratch 1216 / 28) |
| `_input_update_analog_button_state` | 48 / 0 / `5850a17e99380c54` | 48 / 0 / `78f85bb297cc663f` | **PARK-REOPEN PROPOSED — strict EXACT** |
| `_input_update_keyboard_devices` | 640 / 49 / `80bcd2f76c52c728` | 640 / 51 | NOT LANDED — pin + the same allocator hunk |
Ledgers read: all twelve `input_xbox_obj_*.md` (in particular the w2 park re-investigation
`input_xbox_obj_opus5_150k_w2_20260914.md` and `input_xbox_obj_device_keyboard_pollers_wave_20260904.md`, which
owns the three park criteria), `scratch/w2/laws_w2.md` (R11 rejects the w2 `d2`/`k3` zero-credit park remeasures;
section D lists `_input_update_analog_button_state` as a spent-tie row), `scratch/w3/laws_w3.md`, the 100K handoff.
`git log --all -- source/input/input_xbox.c` (22 commits; latest `e123a1d82`). No branch holds a better blob.
Worker notes with the full probe tables: `scratch/workers/w3d_input_xbox.md`.
Scratch: `scratch/workers/w3d_input_xbox/` (`lab.py` micro-TU compiler using input_xbox.c's own cflags, `run.sh`
whole-TU gate, `sub.py` body splicer, `lab1.c`-`lab5.c` probes, `fn/*.c` bodies, `*.gate.txt`/`*.obj`).
---
## 1. `_input_update_analog_button_state` — EXACT (48 B), park reopen proposed
### The one-instruction gap
January's standalone copy and ours differ in exactly one instruction out of 30:
```
0 test dl,dl 2 je 0x15 4 cmp al,0x20 6 jae 0xc
8 xor al,al a jmp 0xe c sub al,0x20 <-- January; ours: add al,0xe0
e cmp al,[ecx] 10 jbe 0x25 12 mov [ecx],al 14 ret
15 cmp al,0xbf 17 jbe 0x1d 19 or al,0xff 1b jmp 0x1f
1d add al,0x40 1f cmp al,[ecx] 21 jae 0x25 23 mov [ecx],al 25 ret
```
The layout proves the source arm order already in the file (`if (value < OFFSET) … else …` in both paths), and the
release path's `add al,0x40` / `or al,0xff` prove `+= 64` and `= UNSIGNED_CHAR_MAX`. The park's recorded blocker was
"only `sub al,32` versus compiler-canonical `add al,-32`", with the criterion *"Reopen only for new authentic
compiler/source evidence"*.
### New evidence: a measured VC7 byte-width law (new, not a re-run of the w2 search)
Every earlier wave respelled the **subtrahend**. Twelve such spellings were re-measured in a micro-TU built with
`input_xbox.c`'s own cflags (`scratch/workers/w3d_input_xbox/lab2.c`, probes `pa`-`pl`): `value -= 32`,
`value = value - 32`, a `const byte` local, a file-scope `static const byte`, an `enum` constant, `32u`,
`(byte)(value-32)`, `+= -32`, `(int)32`, `0x20`, `sizeof(int)*8`, `(byte)(value-32u)` — **all twelve emit
`add al,0xe0`**. The subtrahend is inert; that direction is closed.
The destination is not. `lab3.c` / `lab4.c` controls:
| probe | source | emitted |
| --- | --- | --- |
| `q_ret8` | `byte f(byte v){ v -= 32; return v; }` | **`sub al,0x20`** |
| `q_branch8` | the same `v -= 32` inside an `if/else` | `add al,0xe0` |
| `q_branch32` | the same shape at 32-bit width | **`sub eax,0x20`** |
| `q_twice` | `v -= 32; v -= 32;` | `sub al,0x40` |
| `q_bigconst` | `v -= 200` | `add al,0x38` |
| `q_mem8/16/32` | `*p -= 32` | `add …,0xe0 / 0xffe0 / -0x20` |
| `b1`-`b5`, `b8`-`b10` | eight further branch shapes that write back into `value` | `add al,0xe0` |
| **`b7`** | `byte result; if (c) result = value - 32; else result = 0; return result;` | **`sub al,0x20`** |
**Law (L1, byte self-update canonicalisation).** At byte width VC7 13.00.9254 rewrites a *self-update*
`x = x - C` into `add x, (256-C)`; it keeps `sub x, C` when the difference is assigned to a **different** variable
(after copy propagation, the function result counts as one). 32-bit arithmetic keeps `sub` in both cases, and a byte
constant above 127 always becomes `add` with the complement. Detector: *January `sub r8,imm` where ours has
`add r8,imm` with the high bit set means the source assigned to a second variable.*
In-tree corroboration: the **current real** `_input_get_device_states` body, which binds the reading to its own
local `byte value` before calling the helper, already emits `sub al,0x20` at its inlined copy of this helper
(`scratch/workers/w3d_input_xbox/realeq.txt`, +0x2B9).
`lab5.c` then showed that the four natural placements of the result variable (function scope, per-arm scope,
declare+initialise via a ternary, press arm only) are **byte-identical** and reproduce every other instruction of
January's body — the bytes do not discriminate them, so the house rules pick.
### Landed body (`fn/h1.c`)
```c
static void input_update_analog_button_state(
byte *threshold,
byte value,
boolean pressed)
{
byte new_threshold;
if (pressed)
{
if (value < ANALOG_BUTTON_PRESS_THRESHOLD_OFFSET)
{
new_threshold = 0;
}
else
{
new_threshold = value - ANALOG_BUTTON_PRESS_THRESHOLD_OFFSET;
}
if (new_threshold > *threshold)
{
*threshold = new_threshold;
}
}
else
{
…the release path with the same named result…
}
return;
}
```
The helper maintains a hysteresis envelope for one analog button: it derives the threshold implied by this frame's
reading and moves `*threshold` towards it (up while held, down while released). Naming that derived quantity and
leaving the incoming `value` parameter unmodified is ordinary defensive C, and it is what January's bytes require.
No cast, no `volatile`, no redundant store, no unused local (three uses per arm), no change to the arm order,
constants or control flow.
### Checks — candidate `scratch/workers/w3d_input_xbox/candidate_reopen.c`
sha256 `c13f310311128753a30fb961b9d874ba98a4614fdd3fa8e081f871801b81beb2` (the current real file plus only this body).
1. Whole-TU gate: `== exact 25 residual 2 unwritten 0`; the row-by-row diff against the baseline listing shows
**exactly one** changed row, `residual 48 _input_update_analog_button_state -> EXACT 48`. No other row moved.
2. `_point_from_line3d` emitted-symbol guard passed.
3. `scratch/parkcheck.py`: `_input_get_device_states` OK (1280 / 32 / `b7cded65…` — unchanged; the helper edit does
**not** drift it), `_input_update_keyboard_devices` OK (640 / 51), and
`_input_update_analog_button_state` drifts to the January target values, as a reopen must.
4. Owner census vs `build/base` and `build/split`: 52 candidate owners vs 52 base and 50 target; the only delta is
the compiler-generated jump-table label `$L8245` -> `$L8246` (present in neither January object).
`target owners missing in candidate: []`. No new or lost real code/data/BSS/COMMON owner.
5. `tools/fake_match_scan.py`: 0 review leads, same as HEAD.
6. CRLF line endings preserved (1229 CRLF, 0 lone LF).
**ORCHESTRATOR PROPOSAL (park-reopen).** Remove the `config/parked.json` entry for
`source/input/input_xbox::_input_update_analog_button_state` and apply the `fn/h1.c` body in the same commit.
Park criterion satisfied: "new authentic compiler/source evidence" — a measured byte-width codegen law with ~20
controls, not an equivalent-expression trial.
---
## 2. `_input_get_device_states` — structural gap closed, one allocator hunk left (NOT landed)
### Census (done before any shape)
- **Frame.** January `sub esp,0x30`; the real body `sub esp,0x44` — five extra cells. January's slots:
`[ebp-8]`/`[ebp-0x10]` gamepad insertions/removals, `[ebp-0x14]`/`[ebp-0x18]` the memory-unit pair, `[ebp-4]`
`device_change_flags`, `[ebp-0xc]` the hot-plug count, `[ebp-0x30]` the `XINPUT_STATE`; then in the poll loop three
homed pointers `[ebp-0xc]` = `raw_gamepad_states` (+282), `[ebp-4]` = `gamepad_states` (+332), `[ebp-8]` =
`gamepad_handles` (+316) and `[ebp-0x10]` = count. The real body additionally builds and homes two table bases
(`mov eax,_gamepad_analog_button_indices; sub eax,_input_globals+332; …; sub eax,0x18`).
- **Relocations.** 32 vs 28. The four extras are those two hand-built table bases plus `_input_globals+284`/`+340`
bases where January uses `+282`/`+332`.
- **Diagnosis.** A missing/extra-local + wrong-cursor problem, i.e. structural, exactly as the tags said. w2's
`fn/d2.c` — index `for` loops over `input_globals.<array>[gamepad_index]` with the insert/remove work in its own
block — already fixes both: **1216 / 28** with `sub esp,0x30` exact.
### This wave
With the new helper body the second of d2's two recorded blockers disappears (`sub cl,0x20` at +0x29F now matches),
leaving a single hunk in the binary-button loop's inlined `update_ticks`:
```
T 2c3 lea eax,[esi+0x18] … 2d4 movzx ecx,[eax] 2d7 inc ecx 2d8 cmp ecx,0xff … 2e9 mov [eax],cl 2eb inc eax
O 2c3 lea ecx,[esi+0x18] … 2d4 movzx eax,[ecx] 2d7 inc eax 2d8 cmp eax,0xff … 2e8 mov [ecx],al 2ea inc ecx
```
The entire 16-byte size gap is the one-byte difference between `cmp ecx,imm32` (6 B) and `cmp eax,imm32` (5 B).
Shapes measured this wave (all with the helper fix in place):
| shape | spelling | result |
| --- | --- | --- |
| `hd1` | w2 `fn/d2.c` + `fn/h1.c` | 1216 / 28, one hunk |
| `e1` | binary loop in its own block with a separate `short binary_button_index` | identical |
| `e2` | mask test operands swapped | identical |
| `e3` | `buttons[button_index + FIRST_GAMEPAD_BINARY_BUTTON]` | identical |
| `e4` | `byte *binary_button_ticks` base indexed by `button_index` | 1248, worse |
| `e5` | tick pointer bound to a local before the call | identical |
| `e6` | binary loop as a pointer/count `while` walk | 1248, worse |
| `hd_d6` | w2 `fn/d6.c` + helper | 1232 (right size) but three extra hunks: `wButtons` reloaded inside the loop instead of hoisted into BL, plus a second EAX/ECX flip at +0x330 |
Classification: **C2 register-allocation tie** (law L2 below), not structural. `hd_d6` also confirms that January
hoists the `wButtons` low byte into BL before the loop, which `d2` reproduces and `d6` does not.
**Not proposed.** Re-baselining this park from 1280/32 to 1216/28 would be a zero-credit park remeasure, and
laws_w2 **R11** already rejected exactly this (`input_xbox d2/k3`). The helper reopen does **not** drift this park
(`parkcheck` reports it OK), so no coupled A8 re-baseline is required either.
**Reopen criterion.** A measured source lever that moves which of EAX/ECX the C2 allocator gives to a pointer IV
versus the inlined `update_ticks` 32-bit temp, in a loop whose body is only that call; then re-gate
`scratch/workers/w3d_input_xbox/hd1.c` (1216 / 28 / `0138629fbb74299e`).
---
## 3. `_input_update_keyboard_devices` — structural gap already closed by w2, two ties left (NOT landed)
### Census
- **Frame.** No `sub esp` gap; slots agree (`[ebp-8]`/`[ebp-4]` insertions/removals, the `key_stroke` at
`[ebp-8..-5]`, the `XINPUT_DEBUG_KEYSTROKE` at `[ebp-4]`).
- **Relocations** (`relocdiff --count-by-target`, real body): 51 vs 49 — `_input_globals+568` **6 vs 5** and
`_input_globals+672` **3 vs 2**; every other target is equal. January walks **one** induction variable over
`key_ticks` (+568) and reaches `key_latches` (+672) through the constant displacement `+0x68`
(`mov cl,[eax+0x68]`, `movzx ecx,[eax]`). w2's `fn/k3.c` (a `short key_code` `for` loop indexing both arrays)
already reproduces that: **640 / 49**. The structural row is therefore closed by an existing body; what remains is
`[sha]`.
### This wave
| shape | spelling | result |
| --- | --- | --- |
| `kA` | **diagnostic only** — ascii else-value `0` instead of `NONE` | the `mov ebx,0xff` pin disappears, `push ebx` moves to January's +0x27 and `pop ebx` to +0xD7, 197 -> 195 instructions, only the EAX/ECX hunk left |
| `kB` | ascii store as `key.ascii_code = keystroke.Ascii; if (table[...] == NONE) key.ascii_code = NONE;` | identical to k3 |
| `kE` | `long key_code` instead of `short` | 656 / 51, much worse — proves `short key_code` |
| `kF` | named `boolean down = input_globals.key_latches[key_code];` | identical to kA |
`kA` identifies the mechanism of the recorded "constant-pinning" blocker: the two in-loop uses of
`UNSIGNED_CHAR_MAX` inside the inlined `update_ticks` and the later **byte** store `key.ascii_code = NONE` are
unified by VC7 into one enregistered 0xFF (`cmp eax,ebx`, `mov eax,ebx`, `mov [ebp-7],bl`), which additionally
forces `push ebx` into the prologue instead of shrink-wrapping it to the hot-plug block. Remove the third use and
VC7 rematerialises the constant exactly as January does. January performs all three 0xFF uses and does not unify
them; the else-value is genuinely `NONE`, so there is no admissible spelling that avoids it.
`kA` also shows the **same** EAX/ECX role swap as `_input_get_device_states`, so this row cannot close on the pin
alone.
**Not proposed** (R11: the w2 `k3` park remeasure was already rejected as zero-credit).
**Reopen criterion.** (a) a source lever that stops VC7 unifying a byte constant across a loop and a later byte
store, **and** (b) the allocator lever the device_states row needs; then re-gate `hk3.c` (640 / 49).
---
## 4. Laws proposed for the wave file
**L1 — BYTE SELF-UPDATE CANONICALISATION (closing; closed 48 B first probe).** At byte width VC7 rewrites
`x = x - C` into `add x,(256-C)`; `sub x,C` appears only when the difference is assigned to a different variable
(or is the function result). 32-bit arithmetic keeps `sub` either way; a byte constant `> 127` always becomes
`add`. Twelve subtrahend spellings and ten branch shapes were controls. Detector: January `sub r8,imm` against our
`add r8,imm` with the high bit set ⇒ the source names a second variable.
**L2 — SOLE-STATEMENT LOOP HELPER ALLOCATION TIE (diagnostic).** In a loop whose body is only an inlined helper
taking (pointer, condition), January gives EAX to the pointer IV and ECX to the helper's 32-bit temp; our build
reverses them in all nine spellings measured across two functions (index loop, separate index variable, operand
swap, index-base swap, one-use pointer local, pointer/count `while`, `long` index, named boolean local, and the
pointer-walk body in the real file today). Where the loop body has other work that also reads through the IV
(the analog-button loop) the assignment matches. Costs one byte per `cmp r32,imm32`. No source lever found.
**L3 — BYTE-CONSTANT UNIFICATION ACROSS A LOOP (diagnostic).** Two in-loop uses of an int constant whose low byte
equals a later byte-store constant are unified into one enregistered value and push the callee-saved register into
the prologue instead of shrink-wrapping it; removing the third use restores rematerialisation. Our-only behaviour
in `_input_update_keyboard_devices`; no admissible source lever (the third use is a genuine `NONE`).
@@ -0,0 +1,163 @@
# `light_volumes.obj`: Opus5 250K house-clean lane, wave w3d (structural pass, 2026-09-15)
## Result
Nothing landed. `source/objects/widgets/light_volumes.c` is **unchanged** (`git diff --stat` empty).
Baseline and final real-file gate, with the `_point_from_line3d` guard: **exact 9 / residual 1 /
unwritten 0**, row-for-row identical. Park drift 0, fake scan 0 leads.
The parked `_light_volume_render` was re-investigated in scratch only. This pass produced a complete
frame/relocation census, **three byte-proven source defects** (two of which together make January's
loop header reproduce instruction-for-instruction), and **three corrections to the recorded w2 evidence
and to the `laws_w3` C1 premise for this row**. No candidate reached strict exact; the retained parked
body is still the smallest body measured.
| | padded / relocs / frame / sha16 | instrs | alndiff hunks |
| --- | --- | ---: | ---: |
| January target | 912 / 47 / 0xa4 / `2e43dbc111ad1255` | 291 | - |
| retained (park base) | 928 / 47 / 0xa8 / `a4e273c7939882fc` | 296 | 64 |
| best this wave (v12) | 944 / 47 / 0xac | 306 | 58 |
| loop-only fix (v7) | 944 / 47 / 0xac | 309 | 59 |
## Duplicate checks
Ledgers read: `light_volumes_obj_opus5_150k_w2_20260914`, `..._credible_fuzzy_closeout_20260831`,
`..._jonas_exhaustive_census_20260830`, `..._jonas_distance_fade_schedule_fixed_point_20260826`,
`..._jonas_interpolator_recovery_20260826`, `..._jonas_partial`. Laws applied as detectors:
laws_w2 A4, A5, A6, A10, A12, A18, A20, A22; laws_w3 A24, A31, A35, A38, A44, plus the C1 third-pass
row for this function and R14/R15/R16. The w2 starting point
`scratch/workers/render_particles_rasterizer_xbox_decals_etc/lvJ.c` was re-measured in this tree
(944/48) rather than assumed.
## Census (mandatory, recorded before any shape)
**Relocations: 47 == 47.** No missing and no extra call or global. The gate tag is `[size, sha]` only.
Calls: `_datum_get`, `_tag_get`, `_light_volume_interpolate_frames`, `_object_get_marker_by_name`,
`_object_get_function_value`, `_rasterizer_widget_begin`, `_rasterizer_widget_set_texture`,
`__CIpow` x4, `_rgb_colors_interpolate`, `_real_argb_color_to_pixel32`,
`_rasterizer_widget_draw_sprite3d`, `_rasterizer_widget_end`. January's object contains no
`_dot_product3d` and no `_vector_from_points3d` COMDAT.
**Frame: `sub esp,0xa4` vs `sub esp,0xa8` - exactly one extra dword local.**
| object | target | ours (retained) |
| --- | --- | --- |
| `marker` (108 B) | `[ebp-0xa4 .. -0x39]` | `[ebp-0xa8 .. -0x3d]` |
| `color` (16 B) | `[ebp-0x38 .. -0x29]` | `[ebp-0x3c .. -0x2d]` |
| loop `position` (12 B) | `[ebp-0x18 .. -0x10]`, **shared with `delta`** | `[ebp-0x2c .. -0x24]` |
| `delta` (12 B) | the same cells | **no slot at all - x87-stack resident** |
| scalars | 7 dwords: radius `-0x28`, color_fraction `-0x24`, divisor `-0x20`, pow1#1 exponent `-0x1c`, sprite_index `-0xc`, distance_fade `-8`, pow1#2-4 exponent / brightness_fraction `-4` | 8 dwords: radius `-0x20`, pow1#1 exp `-0x1c`, pow1#2 exp `-0x18`, brightness_fraction `-0x14`, sprite_index `-0x10`, pow1#3-4 exp `-0xc`, `-8`, distance_fade / color_fraction `-4` |
| `[ebp+8]` (`object_index` home) | `function_value`, then the `count-1` temp, then `offset_fraction` (13 refs) | `parallel_factor`, the `count-1` temp, `offset_fraction` (20 refs) |
The extra dword is a pow1 exponent home: January reuses one home (`[ebp-4]`) for inlined pow1
instances #2/#3/#4; ours uses two.
## Byte-proven source defects found
**(a) `definition->count` is re-read inside the loop instead of using the `count` local (A5 class).**
January loads `[ebx+0x6e]` once (`mov ax,[ebx+0x6e]; test ax,ax; jle; movsx ecx,ax; dec ecx`), converts
`count - 1` to `real` once in the preheader (`mov [ebp+8],ecx; fild [ebp+8]; fstp [ebp-0x20]`) and
divides with `fdiv [ebp-0x20]`. The retained `(real)(definition->count - 1)` re-loads the field and
emits `fidiv [ebp+8]` in the body (the conversion is not hoisted). HCEA independently reconstructs a
named `float divisor = (float)(count - 1);` local.
**(b) the sprite loop is a `for` with a `short` index, not `do { } while (--count)`.**
January emits a 32-bit shadow index in `[ebp-0xc]` and a 16-bit trip counter in `DI`
(`movzx edi,ax` ... `inc ecx; dec edi; mov [ebp-0xc],ecx; jne`); the retained form emits `test di,di`
and no shadow.
**(a)+(b) together make January's loop header instruction-identical** (`scratch/workers/w3d_glow_light_volumes/v7.c`;
target[162..179] equal, only slot numbers and one `lea esp,[esp]` loop-head alignment nop differ, and
that nop is a downstream consequence of the earlier byte offset). Hunks 64 -> 59.
**(c) `real function_value = 1.f;`** - January `mov dword ptr [ebp+8],0x3f800000` at +0xd3, between the
far-fade `fld [ebx+0x38]` (+0xd0) and its `fcomp` (+0xda): the A38 signature of a declaration in the
block enclosing the far-fade `if`. The retained body has no initializer.
## Corrections to the recorded evidence (important for future waves)
**(d) The retained hand-written dot expressions are already January's association and, for the i term,
January's operand order.** January's rule here is "`fld` the SECOND source operand, `fmul` the first":
`marker.i*cam.i` -> `fld [render+28]; fmul [ebp-0x68]`, `cam.k*marker.k` -> `fld [ebp-0x60]; fmul
[render+36]`. The retained `marker.i*cam.i + (cam.j*marker.j + cam.k*marker.k)` predicts all three
target terms, and the `A + (B + C)` association is confirmed by January's `faddp` order ((k+j)+i).
Our build reproduces only the i term; the j/k terms come out global-first because the A22 younger-leaf
rule overrides source order while the delta values are alive on the x87 stack.
The w2 ledger's "wrong operand order: the HCEA hand-written dot-product order" is a mis-attribution.
**(e) `laws_w3` C1's "try genuine `dot_product3d` calls first" is MEASURED and NEGATIVE.**
`dot_product3d(&marker.matrix.forward, &render.camera.forward)` makes all three terms local-first -
it breaks the i term the hand expansion already gets right - and grows the body to 944. Swapping the
arguments is byte-identical (w2's "canonicalised by VC7" note confirmed). A35(1)'s "i global-first,
j/k local-first through dot_product3d parameters" does not reproduce here. **A35 does not fire on this
function; the C1 row should be retired.**
**(f) `vector_from_points3d` does NOT reproduce the delta memory stores** (contradicts w2 evidence #2).
It leaves `delta` entirely on the x87 stack, exactly like the hand-written subtraction, and so does a
`(real_vector3d const *)&delta` cast. The `_vector_from_points3d` surplus-COMDAT owner ruling (R14) is
therefore **not** a blocker for this function.
**(g) Mechanism for the delta home.** The only measured form that reproduces January's immediate
`fstp [ebp-0x18]/[ebp-0x14]/[ebp-0x10]` stores is the aggregate's address escaping to a real
(non-inlined) call - the camera delta and the loop's sprite position being one function-scope
`real_point3d` passed to `rasterizer_widget_draw_sprite3d`. That homes the values but at
`[ebp-0x20..-0x18]` (frame 0xac) and does not fix the j/k operand order, so it is not January's form.
## Shapes measured (all scratch, `scratch/workers/w3d_glow_light_volumes/`)
| shape | change | size / relocs / frame | instrs | hunks |
| --- | --- | --- | ---: | ---: |
| lv_base | retained parked body | 928 / 47 / 0xa8 | 296 | 64 |
| lvJ | w2 starting point re-measured here | 944 / 48 | - | - |
| v1 | `dot_product3d` x2 + `real_vector3d delta` | 944 / 47 | 310 | - |
| v2 | v1 with swapped arguments | 944 / 47 | - | - |
| v3 | v1 + `vector_from_points3d` | 928 / 47 | 301 | - |
| v4 | retained + `dot_product3d` x2 + point->vector cast | 944 / 47 | - | - |
| v5 | v4 with swapped arguments | 944 / 47 | - | - |
| v6 | v4 + one shared `real_point3d` (diagnostic) | 944 / 47 | 307 | - |
| v7 | retained + `count - 1` + `for`/`short sprite_index` | 944 / 47 / 0xac | 309 | 59 |
| v8 | v7 + `dot_product3d` x2 | 944 / 47 | - | 61 |
| v10 | v7 + `real function_value = 1.f;` | 944 / 47 / 0xb0 | 306 | 63 |
| v11 | v10 + `dot_product3d` x2 | 944 / 47 | 304 | 65 |
| v12 | v7 + one shared `real_point3d` | 944 / 47 / 0xac | 306 | 58 |
| v13 | lv_base + `#include "interface/hud_draw.h"` | 928 / 47, sha `a4e273c7939882fc` | 296 | byte-identical |
| v14 | v7 + the same include | 944 / 47 | 309 | - |
Every probe kept all nine sibling rows EXACT and the `_point_from_line3d` guard passing. The owner
census of the `dot_product3d` probes adds only `_dot_product3d`, which laws_w2 A4 accepts as systemic.
## Residual classification
Allocation / x87-scheduling tie sitting on top of the three identified source defects. The three
remaining differences move together and none of the twelve shapes separated them:
1. whether `delta` is memory- or x87-resident;
2. whether `parallel_factor` takes `[ebp+8]` (`fst [ebp+8]; fcomp`) or stays on the x87 stack
(January's non-popping `fcom`);
3. which inlined pow1 instances share an exponent home, and whether that home is written by `fst`
(January) or an integer `mov` pair (ours).
## Proposal (orchestrator decides; zero credit)
Add to `source/objects/widgets/light_volumes.c`, immediately after `#include "cseries/cseries.h"`:
#include "interface/hud_draw.h"
This is the unit's only C4013 (`scratch/gate4/c4013.txt`: `objects\widgets\light_volumes.c(353):
warning C4013: 'real_argb_color_to_pixel32' undefined; assuming extern returning int`). The genuine
owner is `source/interface/hud_draw.h:44`, and the sibling widget file in the same directory,
`source/objects/widgets/lightning.c:50`, already includes it for the identical call. Measured
byte-identical (928/47, sha `a4e273c7939882fc`, all ten rows unchanged), so it is a pure fidelity fix.
It is a consumer-side `#include`, not a header edit. Not landed here because brief section 8 requires
an empty file diff in a unit where nothing lands (E18 class).
## Reopen criterion (replaces the w2 criterion)
Reopen on a source-level fact that gives `delta` a stack home at `[ebp-0x18..-0x10]` **without** adding
a frame slot - something other than sharing one aggregate with the loop's `position`, which homes it at
`[ebp-0x20..-0x18]` (frame 0xac). Apply (a), (b) and (c) together; each is independently byte-proven.
Do not retry: `dot_product3d` in either argument order; `vector_from_points3d`; the
`(real_vector3d const *)` cast; declaring `function_value` in the outer block; or any w2 probe
(declaration order, `function_value` scoping, two-statement versus nested pow1 arguments, `pow` versus
`power` inside `pow1`, ternary or result-variable `pow1`, the if-negate ABS form, making
`light_volume_globals` static).
@@ -0,0 +1,150 @@
# `main.obj` opus5 250K house-clean lane, wave w3d - structural pass (2026-09-15)
Worker `w3d:main`. Unit `source/main/main.c`. **Real file unchanged** (`git diff --stat -- source/main/main.c`
empty). Notes with per-function report blocks: `scratch/workers/w3d_main.md`; candidates, micro-labs and the two
census helpers: `scratch/workers/w3d_main/`.
## Baseline and final
`gate.py source/main/main --all --forbid-emitted-symbol _point_from_line3d`:
**baseline == final == `exact 88 residual 6 unwritten 1`**; `_point_from_line3d` guard passed;
`scratch/parkcheck.py` 5 parks drift 0; `tools/fake_match_scan.py` 0 review leads.
Nothing landed: the three structural targets are PARKED and none reached strict EXACT, and `_main_crash` stays
owner-blocked. Baseline listing: `scratch/workers/w3d_main/base_main.txt`.
Duplicate prevention: read `main_obj_opus5_150k_w1_20260914`, `main_obj_opus5_100k_waveD_20260914`,
`main_obj_natural_state_and_render_packet_20260909`, `main_obj_lifecycle_and_fuzzy_reconstruction_20260909`,
`main_obj_jonas_crash_policy_closeout_20260826`, `small_unwritten_threshold_wave_main_hs_ai_20260913` and
`scratch/workers/tiny_stubs.md`. **waveD's scratch tree (`scratch/workersD/`) no longer exists**, so its
`best_update_time.c` / `frd3a.c` / `gr1.c` / `wc2.c` could not be reused; every finding below was re-derived from
January's bytes. w1's `branch_sweep` over 54 historical blobs (nothing better) was not repeated.
## Tooling added (reusable)
- `scratch/workers/w3d_main/realdiff.py <unit> <fn> <obj>` - alndiff with the relocation *offset* and the
`defined-noncode:.rdata:` vs `symbol:` literal-owner spelling normalised away, so the printed count is genuine
code difference. Raw alndiff row counts over-report by 3-4x on relocation-dense functions.
- `scratch/workers/w3d_main/slots.py <unit> <fn> <obj>` - per-`[ebp+-N]` reference census of both sides
(the laws_w3 A24 detector; modelled on `W:w3_projectiles/slots.py`).
## Per-function outcomes
| Function | Padded | Baseline | Best this wave | Verdict |
| --- | ---: | --- | --- | --- |
| `_main_update_time` (parked) | 1440 | 1440 / **118** relocs, 65 blocks / 353 rows | **1440 / 117 relocs** (== January), 27 blocks / 86 rows, sha c6c6733d193740aa (`ut_v10.c`) | park re-baseline proposed |
| `_main_frame_rate_debug` (parked) | 544 | **528** / **51** relocs | **544** / 51 relocs, 3 blocks / 12 rows (`frd_v2.c`) | 8 B + 1 reloc short |
| `_main_game_render` (parked) | 448 | 464 / 29 relocs | 464 / 29 (one of the two defects closed, `gr_v4.c`) | not closer overall |
| `_main_crash` | 16 | UNWRITTEN | - | OWNER-BLOCKED (NULL-deref UB) |
### `_main_update_time` - size and relocation identity now both EXACT
Census (mandatory step): frame `sub esp,0x34` vs our `0x30` (one missing dword local); relocation count-by-target
differs in exactly one row, `_main_globals+950` 4 vs 5 (a second read of `vblank_interval_current` inside the
ignore-failure conjunction). Twelve byte-proven source defects were found and fixed (full list with the January
byte evidence in the notes file), the most load-bearing being:
1. `60 / (requested_rate ? requested_rate : 30)` - January's `jne` reuses the `test ax,ax` flags of the `>= 0`
test and puts the default 30 in a 32-bit register, so the rate selection is an **int-typed conditional
expression**, not an `if (rate == 0) rate = 30;` statement; the field read must stay inside the `&&` so it CSEs.
2. `short_target_index` and `best_interval = 5` are assigned **after** the first `_snprintf` (this alone restores
the missing frame slot and took the frame from 0x30 to 0x34).
3. the failure-count clamp is `x = counts[slot]; if (x >= 99) x = 99;` - cseries `MIN` is `((a)>(b)?(b):(a))` and
emits the 99 store first, January stores the value first and overwrites (`jl`).
4. `if (!ignore_failure) {record} else {label = "ignor";}`, `if (target >= last + 15) {"ok"} else {"wt"/"dn"}`,
`counts[slot] >= 4 ? "dn" : "wt"` - three arm orders each proven by which block January makes the fall-through.
5. `slot >= vblank_interval_requested`, `(short)(current_interval / 2) <= slot_bucket`,
`(__int64)rasterizer_globals.frame_and_vertical_blank_index > target_index`, strict `>` for
`throttle_start_index > initial_index + slot`, and `" des %d"` printing `best_interval`.
Whole-TU gate of `ut_v10.c`: 88/6/1 with every baseline-EXACT row unchanged, the other four parks drift 0, guard
passed, fake scan clean, and the owner census versus `build/base` shows no new owner. The remaining 27 blocks are
callee-saved assignment of the 64-bit `target_index` pair, one 16-bit-vs-32-bit load of a short struct field whose
upper half is padding, the conditional-expression format-string phi (per-arm push vs a register), and the
placement of the cold `"ignor"` block.
### `_main_frame_rate_debug` - size closed, one relocation short
Census: frame identical (`sub esp,0x214`); exactly two relocation rows differ - `_global_screenshot_count+902`
(`framerate_sample_index`) 4 vs 3, and the threshold literal `__real@3fa26e978d4fdf3c` vs our
`__real@3fa26e978d4fdf3b`. Three byte-proven defects were fixed:
- the threshold is the **folded value of an expression** (0.036000000000000004), not the literal `0.036`;
`1.08/30.0`, `36*0.001`, `3.6/100.0` fold to it, `0.036`, `36.0/1000.0`, `0.03*1.2` do not (measured).
The spelling itself is not byte-identifiable - `1.08 / 30.0` was used and is disclosed as a choice.
- the ring-buffer wrap is a **signed** `% 8` (`movsx`, `and eax,0x80000007`, `jns/dec/or/inc`, 15 B);
`% NUMBEROF(...)` makes the expression `size_t` and collapses to `and dl,7` (3 B) - 12 of the 16 missing bytes.
(R7 forbids `% (long)NUMBEROF(x)`, so the divisor has to be a genuine signed constant.)
- the index is incremented at **char width first** (`inc dl; movsx eax,dl`), i.e. `sample_index++;` as its own
statement; `(sample_index + 1) % 8` reuses the already-extended index and also loses January's `mov eax,1`
hoisted above the SET_FLAG branch.
After those, the only difference in the whole function is that January emits the `framerate_sample_index` load
TWICE with different successors (0x56 on the `!framerate_reset` edge, before the second `debug_frame_rate` test,
and 0x6a on the `framerate_reset && debug_frame_rate` edge, which is jump-threaded straight into the body) while
our build cross-jumps the two identical one-instruction loads into one block - 8 bytes and one relocation.
All four admissible CFG spellings of the predicate (nested both ways, `&&`, `||`) are byte-identical; every
placement that moves the load out of the pre-test position sinks it to a single copy (frd_v3/v7/v8/v10, 528 B).
### `_main_game_render` - the width defect is solved, the tail duplication is not
Census: frame identical (`sub esp,0x14`, five slots, same roles); exactly one relocation row differs,
`_observer_get_camera` 1 vs 2; instructions 0..66 are byte-identical to January.
- **`last_local_player_index` is a `short`, not a `long`.** January stores the raw return of the short-returning
`local_player_get_next` (`mov dword ptr [ebp-0xc], eax`, no `movsx`) yet compares and stores 16-bit. Micro-labs
(`lab/l1.c`, `lab/l2.c`) show VC7 always emits `movsx` for `long x = short_fn()`, and that a **`short` local
whose upper half is never read gets a full dword slot with dword stores** - exactly January's pattern. Stian
(`main.c:4224 __int16 next_player`) and HCEA (`int16_t last_assigned_player`) agree. `gr_v4.c` closes that hunk.
- The remaining defect is that VC7 tail-duplicates the 5-instruction shared observer tail into the film-playback
arm. Micro-labs `lab/l3.c`-`l5.c` reproduce both behaviours exactly: a 5-instruction / 17-byte join block is
duplicated into a fall-through predecessor, a 6-instruction / 20-byte one is not, and January's sixth
instruction is `mov dword ptr [ebp-0x14], eax` - i.e. January does not register-forward `observer` across the
join. Refuted causes: observer live-out of the loop (January pushes literal 0 for the console window and for
`render_frame`), loop-scope declaration, arm polarity, NULL assigned in the arms, `console_window` before
`set_window_camera_values`, and the HCEA flat else-if chain (480/30, worse).
- `gr_v4` is not strictly closer overall (the short type shifts the console-window register rotation), so nothing
is proposed for this park; the finding and the reopen criterion replace waveD's.
### `_main_crash`
Unchanged: the 16 bytes are a store of a literal's address through absolute address 0. Brief section 5 and the
crash-policy closeout forbid reproducing NULL-dereference UB and no new provenance appeared this wave.
## Not spent this wave
`_main_get_window_count` (tail-merged conditional-arm constant block placement) and `_compute_subframe_counts`
(`setl/test/je` for a loop-body if) were left untouched - they are not [size]/[relocs] rows and neither waveD's
reopen criterion has been met by a new law. `_main_load_last_solo_map` (the only non-parked residual) is the
recorded ESI/EDI callee-saved permutation, exhausted in waveD and w1.
## Proposals
1. **Park re-baseline `_main_update_time`** to `scratch/workers/w3d_main/ut_v10.c` (or the combined file
`scratch/workers/w3d_main/combined_ut_frd.c`): 1440 / **117** relocs / sha `c6c6733d193740aa` versus the
recorded base 1440 / 118 / `5f8cfd1a...`. Strictly closer on every axis (relocation identity now equals
January; 353 -> 86 differing instruction rows; the recorded objdiff base was 62.5%). Zero strict credit.
2. **Park re-baseline `_main_frame_rate_debug`** to `scratch/workers/w3d_main/frd_v2.c`: **544** / 51 /
sha `3c132f904203944a` versus the recorded base 528 / 51 / `5608160797d3d13d`. Size now equals January and the
owner census picks up January's own `__real@3fa26e978d4fdf3c` literal COMDAT in place of our `...3b`.
Zero strict credit. Discloses the un-identifiable threshold spelling (`1.08 / 30.0`).
3. No header or config change is needed by anything in this wave.
## Reopen criteria (replacing waveD's)
- `_main_update_time`: start from `ut_v10.c`; what remains is the callee-saved assignment of the 64-bit
`target_index` pair (January keeps the low half in EBX and reloads the high half from its home after the
throttle-flag store) and the format-string conditional-expression phi (per-arm `push` versus a materialised
register).
- `_main_frame_rate_debug`: a natural source form in which the `framerate_reset && debug_frame_rate` path reaches
the sample body without re-testing `debug_frame_rate`, so the two `framerate_sample_index` loads keep different
successors and are not cross-jumped. Everything else already matches byte for byte in `frd_v2.c`.
- `_main_game_render`: a source form that makes VC7 keep the `observer` store at its definition (memory home, not
EAX forwarding) with the loop's register pressure unchanged; with `short last_local_player_index` the rest of
the function is byte-identical to January.
- `_main_crash`: an explicit owner ruling on intentional crash routines (unchanged).
## Candidate index (`scratch/workers/w3d_main/`)
`ut_v1..ut_v10.c` (update_time), `frd_v1..frd_v10.c` (frame_rate_debug), `gr_v1..gr_v8.c` (game_render),
`combined_ut_frd.c` (both park re-baselines in one file), `lab/l1.c..l5.c` + `lab/run.py` (micro-labs),
`realdiff.py`, `slots.py`, `base_main.txt`, `ut_v10_all.txt`, `frd_v2_all.txt`, `combined_all.txt`.
@@ -0,0 +1,184 @@
# `observer.obj` third-pass structural census (Opus5 250K house-clean lane, wave w3d, 2026-09-15)
## Result
No real-file change and no new exact credit. `source/camera/observer.c` stays at **24 exact / 2 residual /
0 unwritten** (guard passes, parks drift 0, owner census unchanged, fake scan 0 leads).
`git diff --stat -- source/camera/observer.c` is empty. Both targets are classified NOT-LANDED /
SKIPPED-EXHAUSTED with a complete structural census recorded, which is the intended outcome of a structural
pass over rows whose structure is already exact in scratch.
## Scope and provenance
- Targets (both PARKED, scratch-only): `_observer_update_command` (1040/33) and `_observer_update_positions`
(1568/40).
- Prior ledgers read in full: `observer_obj_opus5_150k_w3_20260914.md`, `observer_obj_opus5_150k_w2_20260914.md`,
`observer_obj_opus5_100k_waveD_20260914.md` (which themselves consumed
`observer_obj_replacement_exact_packet_20260912.md`, `observer_obj_real_update_caller_cluster_20260905.md`,
`observer_obj_integrator_penetration_independent_review_20260905.md`).
- Worker notes read: `scratch/workers/observer.md` (w2),
`C:/halo-worktrees/opus5-100k-consolidated-20260914/scratch/workersD/observer.md` (waveD),
`scratch/workers/w3_observer_editor_flying_camera/` (w3).
- Laws: `scratch/w2/laws_w2.md` and `scratch/w3/laws_w3.md` read completely and applied as detectors.
- Worker notes for this wave: `scratch/workers/w3d_t3_observer.md`; scratch dir
`scratch/workers/w3d_t3_observer/`.
## Baseline and final gate
`gate.py source/camera/observer --all --forbid-emitted-symbol _point_from_line3d`
- Baseline: exact 24 / residual 2 / unwritten 0; guard pass.
- Final real-file gate (`scratch/workers/w3d_t3_observer/final.gate.txt`, object `final.obj`): row-by-row
identical to the baseline.
- `scratch/parkcheck.py`: parks 2, drift 0 (1056/35 and 1280/28, equal to `measurements.base`).
- `tools/fake_match_scan.py source/camera/observer.c`: 0 review leads.
- Owner census: unchanged by construction (the real file is byte-identical to HEAD).
## The framing fact this pass establishes
The `[size]`/`[relocs]` tags on the two rows describe the FROZEN PARKED bodies, which predate wave D. The best
scratch candidate `scratch/workers/observer/a3.c` (waveD `ecmd1` command body + w2 `pos_a3` positions body)
was re-gated at this HEAD (`scratch/workers/w3d_t3_observer/a3.c` -> `a3.obj`) and gives
residual 1040 _observer_update_command [sha] <- size and relocs EQUAL
residual 1568 _observer_update_positions [sha] <- size and relocs EQUAL
== exact 24 residual 2 unwritten 0, guard pass
so the structural gap the wave was pointed at is already closed in scratch. The censuses below are therefore
taken against the live frontier (`a3.obj`).
## Structural census
### Frame census
| function | January `sub esp,N` | candidate | slots missing | slots extra |
| --- | --- | --- | --- | --- |
| `_observer_update_positions` | 0x84 | 0x84 | none | none |
| `_observer_update_command` | 0xc | 0xc | none | none |
`_observer_update_positions`: every `[ebp-N]` slot matches, including the 56-byte
`struct observer_derivative displacement` at [ebp-0x84] with its untouched 12-byte tail, the ten pointer homes
at -0x1c..-0x48, and the inlined `axis` copy at [ebp-0x10] (i), [ebp-0xc] (j), [ebp-8] (k) with the magnitude
temp at [ebp-4].
`_observer_update_command`: same size and the same three dword slots, with the ROLES permuted -
January [ebp-4] = `parameter_flags` pointer, [ebp-8] = `timer` pointer, [ebp-0xc] = the `valid_real()` int-pun
temp of the 0x172 assert (9 stores); ours [ebp-4] = flags pointer and then the homed down-counter,
[ebp-8] = the temp, [ebp-0xc] = `timer`. This permutation is a consequence of the single defect below, not an
independent one: once VC7 merges the timer induction variable, the `timer` local keeps one reference and drops
below the 18-reference assert temp in the descending-reference frame ranking.
### Relocation census (`relocdiff --count-by-target --allow-structural`)
- Parked positions body: 40 target / 28 candidate, 29 differing rows - surplus `_csmemset`, a surplus
out-of-line `_valid_real_vector3d_axes2` call, 1 vs 7 and 1 vs 3 count-table references, and the missing
`__real@3f800000` x5 / `__real@3f50624de0000000` x3 / `__real@3f1a36e2e0000000` x3 of the inlined
normalize3d and inlined axes predicate. All fixed by `pos_a3`.
- Parked command body: 35 vs 33 (two surplus, fixed by the waveD cross-jumped `MIN(*last_timer, 2.f)` block).
- **a3 candidate vs January, both functions: 40 == 40 and 33 == 33 with equal targets.** The only rows
`relocdiff` reports are the `--source` literal-COMDAT naming artifact (`['symbol', X, 0]` vs
`['defined-noncode', '.rdata', X, 0]`). No call, global or literal is missing or extra.
### Instruction census
471 == 471 (positions) and 307 vs 302 (command). No control-flow, loop-shape, width or branch-polarity
difference in either function.
## `_observer_update_command`: SKIPPED-EXHAUSTED (one backend defect)
The residual reduces to a single mechanism. January keeps FOUR independent loop variables:
edx = `timer` pointer (`add edx,4`), edi = `last_timer` pointer (`add edi,4`), [ebp-4] = the spilled
`parameter_flags` byte pointer (`inc ecx`, reloaded at the top of every iteration), esi = the down-counter
(`mov esi,5` / `dec esi`). VC7 on our source applies a linear-function-test replacement to `timer`: it
computes the loop-invariant delta `esi = timer0 - last0` in the preheader and addresses all four `*timer` uses
as `[esi+edi]`, which frees EDX for the flags pointer and spills the counter into [ebp-4] instead. The four
alndiff hunks (preheader, the three `[edx]` vs `[esi+edi]` accesses, the loop tail, the frame-slot
permutation) are all consequences of that one merge.
Everything else is byte-identical: the 0x172 assert expansion, the `observer->pending_command` reloads after
the assert, the cross-jumped `MIN(*last_timer, 2.f)` block, the `<` NaN polarity of the time-invalid test and
the `rep movsd` struct assignment.
Law detector pass: no law in laws_w2 (A1-A22) or laws_w3 (A23-A45) addresses induction-variable merging.
A5/A33 (indexed access vs pointer walk changes the strength-reduced bias) is the closest and wave D already
spent five indexed/pointer permutations, all worse (raw diffs 52/61/72/119 against 49-54 for the pointer
form); A24 does not apply (the single `short` parameter arrives in AX with no home); A23, A25, A31 and A38 do
not apply to this body. No shapes were spent this wave.
**Reopen criterion.** A January-side reason for VC7 not to apply the linear-function-test replacement to the
`timer` pointer against `last_timer`: a genuine live-out use of one of the two pointers, a loop form that
defeats the merge, or a same-compiler donor function that keeps two same-step pointer induction variables of
DIFFERENT objects unmerged inside a counted loop. Start from `scratch/workers/observer/v1.c`.
## `_observer_update_positions`: NOT LANDED (one backend mechanism + a credibility blocker)
The residual is 18 instructions in three hunks:
1. 0x27b-0x28e - the inlined `normalize3d` -> `magnitude_squared3d` of the `axis` copy inside the inlined
`observer_apply_rotational_displacement`: January k*k, i*i, j*j; ours k*k, j*j, i*i.
2. 0x447-0x461 - the inlined `dot_product3d(&observer->forward, &observer->up)`: January k, i, j; ours k, j, i.
3. 0x4ab-0x4ce - three commutative operand ranks in the repair `cross_product3d` j and k components.
New diagnostic facts (not in any prior ledger):
- (a) Hunks 1 and 2 are ONE mechanism. The positional pattern is identical in both builds - term 1 is the k
term, term 2 loads the FIRST helper parameter first, term 3 loads the SECOND parameter first - and only
WHICH of i/j occupies position 2 differs, even though hunk 1 works on the components of a local struct copy
held in ecx/edx/eax and hunk 2 on memory fields of two different structs. The open question is therefore
narrow: is the offset-0 leaf ranked above or below the offset-4 leaf.
- (b) In the two `valid_real_normal3d` magnitudes at 0x393-0x3b3 and 0x3ea-0x40a, the SAME header helper
(`magnitude_squared3d`) is emitted i,j,k (source order) and our build matches January EXACTLY. There the
three leaves are pre-loaded onto the x87 stack (the A4 "all loads then all products" form). The inversion
therefore only ever appears in the direct-memory-operand form. This clears the real_math.h
`magnitude_squared3d` / `dot_product3d` bodies and localises the A22/A35 family question.
- (c) `_observer_apply_rotational_displacement` compiled out of line is strict EXACT (128 B) from the same
source, with `normalize3d` out of line there, so the exact out-of-line row says nothing about the inlined
rank.
Shapes spent this wave (the two allowed for a residual `[sha]` row), both **measurably inert** - the candidate
`_observer_update_positions` sha stays `fe491b6d48e19230` and all 24 siblings stay exact:
| shape | source change | result |
| --- | --- | --- |
| s2 (`scratch/workers/w3d_t3_observer/s2.c`) | `!(A && B && C)` instead of `!A \|\| !B \|\| !C` for the axes check | 1568/40, byte-identical to a3 |
| s3 (`scratch/workers/w3d_t3_observer/s3.c`) | declare-then-assign split of `axis` / `angle` in `_observer_apply_rotational_displacement` (A38 probe) | 1568/40, byte-identical to a3; out-of-line row stays EXACT |
So the enclosing boolean spelling and the initializer/assignment split do not move the x87 leaf rank; add both
to the do-not-repeat list.
**Credibility blocker.** January inlines the axes predicate (no `_valid_real_vector3d_axes2` relocation, three
0.001 doubles and three 1e-4 doubles). The `real_math.h` body at HEAD (nested `if` plus a named `product`)
stays out of line in this caller, so the only in-lane spellings that reproduce the January inline layout are
(i) writing the three helper calls in `observer.c`, which is manual inlining of an existing owner-header
helper (house rule 13 / R15 class), or (ii) the E6 conjunction header, which laws_w3 records as HOLD (net
-3,664 padded; it loses `_bitmap_copy` 2,784 and `_bitmap_2d_uncompress_from_mipmap` 880) and which wave w3
measured as NOT closer here (the dot order becomes i,k,j). E6 therefore does not unlock observer and no header
proposal is filed.
**Reopen criterion (refined).** A measured VC7 rule that predicts, for a three-term commutative sum whose
leaves are direct memory operands, whether the offset-0 leaf ranks above or below the offset-4 leaf (January
k,i,j against our k,j,i), together with the matching `cross_product3d` operand rank, and that also explains
fact (b). Start from `scratch/workers/observer/pos_a3.c`. Any landing additionally needs a ruling on spelling
(i) or a non-regressing replacement for E6.
## Do-not-repeat (this wave)
- positions: `!(A && B && C)` in place of the negated `||` chain (byte-identical, s2);
- positions: declare-then-assign split of `axis`/`angle` in `_observer_apply_rotational_displacement`
(byte-identical, s3);
- positions: the E6 conjunction header as a route to this row (measured in w3, not closer, and net negative
board-wide);
- command: no shape is worth spending until the induction-variable-merge question has an answer.
## Proposals
None. No park-reopen (neither body is strict EXACT), no header packet, no config change.
## Value for other units
Fact (b) above is reusable by the laws_w3 C1 "local-first x87 products" family
(`_rasterizer_lens_flares_draw`, `_light_volume_render`, `_collision_debug_render`,
`_rasterizer_model_draw_environment_shader`, `_triangle_coplanar`, `_actor_get_stopping_distances`): in this
object the A22/A35 rank inversion never appears when the three leaves are pre-loaded onto the x87 stack, only
when the products consume memory operands directly, and the difference is confined to the relative rank of the
offset-0 and offset-4 leaves.
+130 -143
View File
@@ -95,6 +95,7 @@ symbols in this file:
#include "physics/collisions.h"
#include "scenario/scenario.h"
#include "units/unit_definitions.h"
#include "units/vehicle_definitions.h"
#include "units/vehicles.h"
/* ---------- constants */
@@ -369,180 +370,166 @@ boolean action_vehicle_evaluate_seat(
struct actor_variant_definition *variant_definition =
actor_variant_definition_get(actor->meta.variant_definition_index);
boolean result = FALSE;
real_point3d entrance_point;
real_point3d seat_point;
real_point3d seat_hint_point;
if (unit_seat_filled(vehicle_index, seat_index) ||
(TEST_FLAG(
if (!unit_seat_filled(vehicle_index, seat_index) &&
(!TEST_FLAG(
definition->flags2,
_actor_definition_disallow_vehicle_combat_bit) &&
!unit_seat_allow_noncombatants(vehicle_index, seat_index)) ||
!unit_get_seat_entrance_point(
_actor_definition_disallow_vehicle_combat_bit) ||
unit_seat_allow_noncombatants(vehicle_index, seat_index)))
{
real_point3d entrance_point;
real_point3d seat_point;
real_point3d seat_hint_point;
if (unit_get_seat_entrance_point(
actor->meta.unit_index,
vehicle_index,
seat_index,
&entrance_point,
&seat_point,
&seat_hint_point))
{
return result;
}
{
real_point3d vehicle_origin;
real_vector2d entry_direction;
real_vector2d computed_facing;
real computed_facing_z = 0.0f;
real entrance_dx;
real entrance_dy;
real seat_dx;
real seat_dy;
real distance_to_seat;
struct prop_iterator iterator;
struct prop_datum *prop;
object_get_origin(vehicle_index, &vehicle_origin);
entry_direction.i = seat_point.x - entrance_point.x;
entry_direction.j = seat_point.y - entrance_point.y;
computed_facing = entry_direction;
if (normalize2d(&computed_facing) == 0.0f)
{
computed_facing.i = actor->input.facing_vector.i;
computed_facing.j = actor->input.facing_vector.j;
computed_facing_z = actor->input.facing_vector.k;
}
real_point3d vehicle_origin;
real_vector3d facing;
real distance_to_seat;
entrance_dx = entrance_point.x - actor->input.position.body_position.x;
seat_dx = seat_point.x - actor->input.position.body_position.x;
entrance_dy = entrance_point.y - actor->input.position.body_position.y;
seat_dy = seat_point.y - actor->input.position.body_position.y;
if (square_root(entrance_dy*entrance_dy + entrance_dx*entrance_dx) <=
square_root(seat_dy*seat_dy + seat_dx*seat_dx))
{
distance_to_seat = square_root(
entrance_dy*entrance_dy + entrance_dx*entrance_dx);
}
else
{
distance_to_seat = square_root(seat_dy*seat_dy + seat_dx*seat_dx);
}
result = TRUE;
prop_iterator_new(&iterator, actor_index);
for (prop = prop_iterator_next(&iterator);
prop;
prop = prop_iterator_next(&iterator))
{
if (!prop->enemy && prop->actor_index != NONE)
object_get_origin(vehicle_index, &vehicle_origin);
facing.i = seat_point.x - entrance_point.x;
facing.j = seat_point.y - entrance_point.y;
facing.k = 0.0f;
if (normalize2d((real_vector2d *)&facing) == 0.0f)
{
struct actor_datum *other_actor = actor_try_and_get(prop->actor_index);
facing = actor->input.facing_vector;
}
if (other_actor->state.action == _actor_action_vehicle &&
other_actor->state.action_data.vehicle.vehicle_index == vehicle_index)
distance_to_seat = MIN(
distance2d(
(real_point2d const *)&actor->input.position.body_position,
(real_point2d const *)&entrance_point),
distance2d(
(real_point2d const *)&actor->input.position.body_position,
(real_point2d const *)&seat_point));
{
struct prop_iterator iterator;
struct prop_datum *prop;
prop_iterator_new(&iterator, actor_index);
while (prop = prop_iterator_next(&iterator))
{
struct vehicle_state_data *other_state =
&other_actor->state.action_data.vehicle;
if (other_state->seat_index == seat_index)
if (!prop->enemy && prop->actor_index != NONE)
{
real other_dx = other_state->destination_point.x -
other_actor->input.position.body_position.x;
real other_dy = other_state->destination_point.y -
other_actor->input.position.body_position.y;
struct actor_datum *other_actor =
actor_try_and_get(prop->actor_index);
if (other_dy*other_dy + other_dx*other_dx <
distance_to_seat*distance_to_seat)
if (other_actor->state.action == _actor_action_vehicle &&
other_actor->state.action_data.vehicle.vehicle_index == vehicle_index)
{
return FALSE;
struct vehicle_state_data *other_state =
&other_actor->state.action_data.vehicle;
if (other_state->seat_index == seat_index)
{
real other_dx = other_state->destination_point.x -
other_actor->input.position.body_position.x;
real other_dy = other_state->destination_point.y -
other_actor->input.position.body_position.y;
if (other_dy*other_dy + other_dx*other_dx <
distance_to_seat*distance_to_seat)
{
result = FALSE;
break;
}
}
else
{
unit_seat_is_driver(vehicle_index, other_state->seat_index);
}
}
}
else
{
unit_seat_is_driver(vehicle_index, other_state->seat_index);
}
}
}
}
if (!allow_any_seat)
{
struct unit_datum *vehicle = vehicle_get(vehicle_index);
struct vehicle_definition *vehicle_definition =
vehicle_specific_definition_get(vehicle->definition_index);
(void)vehicle_definition;
unit_seat_is_driver(vehicle_index, seat_index);
}
{
real_vector2d to_seat_direction;
real facing_dot;
boolean within_range;
boolean correct_facing;
boolean could_potentially_fake;
real seat_weight;
to_seat_direction.i =
seat_point.x - actor->input.position.body_position.x;
to_seat_direction.j =
seat_point.y - actor->input.position.body_position.y;
normalize2d(&to_seat_direction);
facing_dot = actor->input.facing_vector.j*to_seat_direction.j +
actor->input.facing_vector.i*to_seat_direction.i;
within_range = distance_to_seat < 0.7f;
correct_facing = facing_dot > 0.6f;
could_potentially_fake =
distance_to_seat < 1.1f && facing_dot > 0.0f;
seat_weight = 10.0f / (distance_to_seat + 1.0f);
if (TEST_FLAG(
variant_definition->flags,
_actor_variant_definition_prefer_passenger_seat_bit))
if (result)
{
if (!unit_seat_is_gunner(vehicle_index, seat_index))
struct unit_datum *vehicle = vehicle_get(vehicle_index);
real_vector2d to_seat_direction;
real facing_dot;
boolean within_range;
boolean correct_facing;
boolean could_potentially_fake;
real seat_weight;
if (!allow_any_seat)
{
vehicle_specific_definition_get(vehicle->definition_index);
unit_seat_is_driver(vehicle_index, seat_index);
}
vector_from_points2d(
(real_point2d const *)&actor->input.position.body_position,
(real_point2d const *)&seat_point,
&to_seat_direction);
normalize2d(&to_seat_direction);
facing_dot = dot_product2d(
&to_seat_direction,
(real_vector2d const *)&actor->input.facing_vector);
within_range = distance_to_seat < 0.7f;
correct_facing = facing_dot > 0.6f;
could_potentially_fake =
distance_to_seat < 1.1f && facing_dot > 0.0f;
seat_weight = 10.0f / (distance_to_seat + 1.0f);
if (TEST_FLAG(
variant_definition->flags,
_actor_variant_definition_prefer_passenger_seat_bit))
{
if (!unit_seat_is_gunner(vehicle_index, seat_index))
{
seat_weight += 3.5f;
}
}
else if (unit_seat_is_gunner(vehicle_index, seat_index))
{
seat_weight += 3.5f;
}
}
else if (unit_seat_is_gunner(vehicle_index, seat_index))
{
seat_weight += 3.5f;
}
if (entry_point)
{
*entry_point = entrance_point;
}
if (entry_facing)
{
entry_facing->i = computed_facing.i;
entry_facing->j = computed_facing.j;
entry_facing->k = computed_facing_z;
}
if (hint_point)
{
*hint_point = seat_hint_point;
}
if (seat_weight_reference)
{
*seat_weight_reference = seat_weight;
}
if (within_range_reference)
{
*within_range_reference = within_range;
}
if (correct_facing_reference)
{
*correct_facing_reference = correct_facing;
}
if (could_potentially_fake_reference)
{
*could_potentially_fake_reference = could_potentially_fake;
if (entry_point)
{
*entry_point = entrance_point;
}
if (entry_facing)
{
*entry_facing = facing;
}
if (hint_point)
{
*hint_point = seat_hint_point;
}
if (seat_weight_reference)
{
*seat_weight_reference = seat_weight;
}
if (within_range_reference)
{
*within_range_reference = within_range;
}
if (correct_facing_reference)
{
*correct_facing_reference = correct_facing;
}
if (could_potentially_fake_reference)
{
*could_potentially_fake_reference = could_potentially_fake;
}
}
}
}
return TRUE;
return result;
}
static boolean action_vehicle_find_destination(
+14 -9
View File
@@ -1961,6 +1961,7 @@ static void effect_generate_particles(
particle_index,
struct effect_particles_definition);
short count_delta;
long last_particle_count;
long location_datum_index;
struct effect_location_datum *instance;
@@ -1977,14 +1978,15 @@ static void effect_generate_particles(
continue;
}
last_particle_count = (long)(effect_evaluate_function_integral(
particles->distribution_function,
last_event_fraction) *
effect->particle_counts[particle_index]);
count_delta = (short)((long)(effect_evaluate_function_integral(
particles->distribution_function,
event_fraction) *
effect->particle_counts[particle_index]) -
(long)(effect_evaluate_function_integral(
particles->distribution_function,
last_event_fraction) *
effect->particle_counts[particle_index]));
last_particle_count);
match_assert(
"c:\\halo\\SOURCE\\effects\\effects.c",
@@ -2095,11 +2097,13 @@ static void effect_generate_particles(
if (TEST_FLAG(particles->flags, _effect_particle_attached_bit))
{
short node_index = instance->node_designator;
if (node_index != NONE)
node_index &= (short)(FLAG(_effect_location_first_person_bit) - 1);
data.object_index = effect->object_index;
data.node_index = instance->node_designator != NONE
? (short)(instance->node_designator &
(FLAG(_effect_location_first_person_bit) - 1))
: NONE;
data.node_index = node_index;
data.initial_impulse = *global_zero_vector3d;
}
else
@@ -2611,11 +2615,12 @@ static boolean effect_allowed_by_environment(
struct location const *location,
real_point3d const *world_point)
{
boolean allowed = environment == _effect_environment_anywhere;
boolean allowed = FALSE;
switch (environment)
{
case _effect_environment_anywhere:
allowed = TRUE;
break;
case _effect_environment_air:
+10 -8
View File
@@ -691,36 +691,38 @@ static void input_update_analog_button_state(
byte value,
boolean pressed)
{
byte new_threshold;
if (pressed)
{
if (value < ANALOG_BUTTON_PRESS_THRESHOLD_OFFSET)
{
value = 0;
new_threshold = 0;
}
else
{
value -= ANALOG_BUTTON_PRESS_THRESHOLD_OFFSET;
new_threshold = value - ANALOG_BUTTON_PRESS_THRESHOLD_OFFSET;
}
if (value > *threshold)
if (new_threshold > *threshold)
{
*threshold = value;
*threshold = new_threshold;
}
}
else
{
if (value > ANALOG_BUTTON_RELEASE_SATURATION)
{
value = UNSIGNED_CHAR_MAX;
new_threshold = UNSIGNED_CHAR_MAX;
}
else
{
value += ANALOG_BUTTON_RELEASE_THRESHOLD_OFFSET;
new_threshold = value + ANALOG_BUTTON_RELEASE_THRESHOLD_OFFSET;
}
if (value < *threshold)
if (new_threshold < *threshold)
{
*threshold = value;
*threshold = new_threshold;
}
}