mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-29 04:01:10 +01:00
fe77cd542f80de4dfd05ad35e86fe65b41d603c3
2352
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4f4c85021d |
Reconcile Lane C with canonical house-rule audit
Integrate verified source and data progress; exclude unproven COMMON ownership, held UB/asm forms, and address-named data credit. Stable sweep: 23 exact functions gained, zero lost. |
||
|
|
a01115aaf5 |
Integrate verified Claude Lane B campaign
# Conflicts: # config/parked.json |
||
|
|
ccf3b4125d |
Lane B wave 3: path.c complete - three strict-exact functions (+2,783 meaningful / +2,800 padded)
New strict exact (function board for ai/path is now 32/32):
ai/path :: _path_state_traverse 2096
ai/path :: _path_state_estimated_distance 496
ai/path :: _closest_point_to_attractor 208
This is the owner's all-inlined COMDAT admission (2026-09-21: "admit the class
... genuine shared-header __inline, byte-identical COMDAT, strict-exact caller,
full ownership/build sweep, zero regressions. No hand expansions.") doing what
it was for: path.c HAND-EXPANDED point_from_line3d at three sites because the
old emission guard forbade the real helper, and those sites were the whole
residue. The three hand expansions are replaced by the REAL
point_from_line3d(...) call. path.obj therefore newly emits _point_from_line3d
(48 B, math/real_math.h, byte-identical to January's single folded copy credited
to ai/action_charge); all three callers are strict exact. admit_check.py: PASS.
Other source changes, each read from the first-party /Od build first and then
confirmed in January's bytes:
- _path_state_estimated_distance: a genuine reconstruction BUG. After the first
walk /Od does `current_node_index = child_node_index;` (0x4c657e) and the
second walk tests and advances current_node_index, as does the `?:`. We
iterated child_node_index. With the copy, January's spilled result byte web and
its EDI/ESI/EBX assignment appear - every row of the previous ledger. Exact on
the first compile.
- _path_state_traverse: `closest_distance < 4.0f` (was distance_to_destination;
/Od 0x4c76ee compares closest_distance); the second collision_bsp pointer is a
block-scoped local; and the local below.
DISCLOSURE for owner awareness - a local that is written once and never read:
struct path_node previous_node_values; ... previous_node_values = *new_node;
It is a first-party debugging snapshot, NOT an invention: the /Od RTC descriptor
NAMES it (`previous_node_values`, size 68 = sizeof(struct path_node), [ebp-0x8ec])
and /Od does the `rep movsd` right after path_get_node. VC7 deletes the copy in
the optimised build (no rep movs, frame 0x85c unchanged), but the extra IL local
is what yields January's x87 ordering at 0x2cc-0x2d8; January also shows a
constant +1 assert-line drift across this span, consistent with extra source
lines here. Strip test on the final file: without it the function is [sha].
Same class as `jet_marker_count` in
|
||
|
|
3ba2eb9106 |
Lane B: three exact functions under the owner's per-site rule-24 admission (+2,802 meaningful / +2,816 padded)
New strict exact:
ai/path_structure_bsp :: _structure_test_line2d 1104 (object now 6/6)
ai/action_obey :: _action_obey_control 992 (object now 27/27)
ai/actions :: _actor_action_try_to_dive 720
OWNER ADMISSION (2026-09-21), quoted: "Admit only with per-site /Od attestation,
byte-inert cast, compatible prefix layout, strict exactness, and ledger
disclosure. Land the three; keep the fighter held."
DISCLOSURE - every NEW 3D->2D view cast in this commit, with the first-party
/Od + /RTC build (halo_cache_symbols.exe) instructions that attest the SAME
punned object at the SAME site. The punning is Bungie's: C cannot pass or copy a
3D object as a 2D one without it.
1. _actor_action_try_to_dive - ONE cast:
dot_product2d(&left_animation_alignment, (real_vector2d const *)&actor->input.facing_vector)
/Od fn 0x42c1f0: 0042c3e6 mov edx,[ebp-8] ; actor
0042c3e9 add edx,0x140 ; &actor->input.facing_vector (real_vector3d)
0042c3ef push edx
0042c3f0 call -> fn 0x42dd30
and fn 0x42dd30 is dot_product2d: a[0]*b[0] + a[1]*b[1], two components only.
Byte-inert: with the cast deleted the TU compiles (C4133) and the function is
STILL strict exact 720.
2. _structure_test_line2d - FOUR casts, (real_point2d const *)&vertexN->point:
vector_from_points2d(v0, v1, &e0e1); (v0, p1, &e0p1); (p0, v0, &p0e0); (p0, v1, &p0e1)
/Od fn 0x4cee00, call sites 0x4cefb6 / 0x4cefca / 0x4cefe1 / 0x4ceff8: the
vertex pointer locals [ebp-0x5c] and [ebp-0x60] (results of
tag_block_get_element; the 3D point is at offset 0) are pushed DIRECTLY as the
2D point arguments, in exactly that argument order, to fn 0x42e350 =
vector_from_points2d (two 2-component subtractions).
Byte-inert: with the five casts deleted (operands kept) the function is STILL
strict exact 1104.
3. _action_obey_control - ONE cast, an aggregate COPY rather than an argument:
alignment_vector = *(real_vector2d const *)&actor->input.facing_vector;
/Od fn 0x43c2d0: 0043c7c7 mov eax,[ebp-8] ; actor
0043c7ca mov ecx,[eax+0x140]
0043c7d0 mov edx,[eax+0x144]
0043c7d6 mov [ebp-0x2c],ecx
0043c7d9 mov [ebp-0x28],edx
0043c7dc lea eax,[ebp-0x2c] / push eax / call normalize2d
Integer mov pairs = an 8-byte STRUCT ASSIGNMENT out of the 3D vector straight
into the one 2D local that is then normalised (member-wise real copies compile
to movss at /Od, and there is no intermediate temp). This replaces our
member-wise copy through a `facing` temporary.
Byte-inertness caveat, stated plainly: this cast cannot be strip-tested - C
rejects an aggregate assignment across types outright - so the showing here is
the /Od aggregate copy plus the fact that a pointer cast emits no code. The
reviewer measured every undecorated alternative (.i/.j, .j/.i,
set_real_vector2d, bound 3D pointer member-wise) as residual.
Compatible prefix layout (math/real_math.h): real_vector2d is `real n[2]`,
real_vector3d `real n[3]`; real_point2d `real n[2]`, real_point3d `real n[3]` -
each 2D union is exactly the first 8 bytes of its 3D counterpart.
The idiom already appears 72 times in 21 canonical files, incl. math/real_math.c.
Other source evidence:
- _structure_test_line2d: both loop heads are `mov 1 / test / je` in /Od
(while (TRUE)); the inner break lands on the outer back-jump so the tail sits
inside the inner loop; two blocked copies. Depends on the assert-spacing
relocation identity taken from the data lane in
|
||
|
|
f0b191bc68 |
Lane B: three exact functions under the owner's all-inlined COMDAT admission (+2,545 meaningful / +2,560 padded)
New strict exact:
ai/actor_type_flood :: _actor_type_flood_desire_shamble 1296 (object now 2/2)
units/vehicles :: _update_human_plane_physics 928
ai/path_smoothing :: _find_tangent_point 336 (object now 6/6)
OWNER ADMISSION (2026-09-21), quoted: "Sufficient: admit the class. Require a
genuine shared-header __inline, byte-identical COMDAT, strict-exact caller, full
ownership/build sweep, and zero regressions. No hand expansions."
Each landing newly emits ONE header-inline COMDAT that January's split credits
to another object. Conditions verified per landing by scratch/orch/admit_check.py:
_real_random_range 32 B math/real_math.h January owner ai/action_alert byte-identical
_interpolate_scalar 64 B math/real_math.h January owner game/player_control byte-identical
_set_real_point2d 32 B math/real_math.h January owner ai/path_obstacles byte-identical
All three callers are strict exact; no hand expansion is used anywhere in them.
The evidence the owner accepted:
(1) Compiler (scratch/orch/inline_lab.py): VC7 13.00.9254 with the campaign's
real flags (/O2 /Oy- /DDEBUG /Dxbox) emits the out-of-line COMDAT for a
non-static __inline whose EVERY call site inlined, and emits nothing when
the inline is unused - so emission implies use in that TU.
(2) January's own image (scratch/orch/inline_owner_census.py): of 104
header-inline COMDATs, 65 are owned - per January's PDB section
contributions - by an object that holds ZERO references to them (e.g.
_cross_product2d in actor_combat.obj). Owners cluster at the earliest
link-order TUs, as "folded survivor = first emitter" predicts. The split's
single definition is therefore a link-fold artifact, not evidence that the
other TUs did not emit the COMDAT.
Source evidence (all read from the first-party /Od build first, then confirmed
in January's bytes):
- _actor_type_flood_desire_shamble: result/switching flags zeroed at the top, all
six `result = FALSE` arms, chain-assigned counters, `--timer == 0`, per-arm
two-argument helper calls, MAX with double evaluation; `< 15.0f` confirmed by
January's `test ah,5`. real_random_range is byte-REQUIRED (a hand expansion
measures 1280 != 1296; January shows the inlined parameter temporaries).
- _update_human_plane_physics: uses the real interpolate_scalar helper.
- _find_tangent_point: every call is a real real_math.h helper including
set_real_point2d; store-by-store spellings are residual and worse than baseline.
Held alongside (NOT landed): _update_alien_fighter_physics_new (1,088, exact in
scratch) - needs a NEW 3D->2D view cast whose site is not /Od-attested; owner:
"keep the fighter held".
Config: config/parked.json - _actor_type_flood_desire_shamble entry removed
(now exact). Parks 173 / 0 / 0. No header, symbols.json, flag or tool change.
Verification: full ninja all_source progress semantic_progress pass (Code
1451421 -> 1453966, 7306 -> 7309). stable_verdicts vs the FROZEN baseline:
gained 18 / 10128 bytes, regressions 0. All 11,060 function and 1,706 section
report rows: 0 lost 100%, 0 missing. Guard, fake scan, line endings and the
new-punning-cast screen clean. git diff --check clean.
Reviewer: independent adversarial agents confirmed each body EXACT and credible
and held them ONLY on the ownership question the owner has now ruled on.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
74c9cb2a02 |
Lane B wave 2: zero-credit fuzzy source corrections (path, collisions, action_charge)
ZERO exact credit. Better-evidenced bodies retained per house rule 11. No new representation-punning casts (screened), no ownership change, no new fake_match_scan lead, line endings preserved. - physics/collisions.c _collision_move_point (4,752 B, not parked): reviewer byte compare with relocation sites zeroed - differing bytes 3,847 -> 6. Size 4752 == 4752 and relocations 226 == 226. The remaining six bytes (0x595-0x597, 0x59b-0x59d) are ONE transposition of two independent instructions, so the body is semantically January on every path. Each hunk was strip-tested alone and is byte-bearing (position block scope, post-increment placement, ...). The owner's collisions[-1] ban is respected; line 1572 is untouched. - ai/path.c (both PARKED, entries refreshed in this commit): _path_state_traverse (2,096 B): rewritten statement-for-statement from the /Od build (fn 0x4c6a70) with each fact confirmed in January's bytes. Frame and return count are now January's; differing regions 132 -> 61; objdiff 64.6% -> 98.6%. Padded size is now 2112 vs 2096. Residue is confined to 0x10b-0x4cc, at the hand-expanded point_from_line3d sites forced by the emission guard (path.obj is in the owner's still-guarded all-inlined class). _path_state_estimated_distance (496 B): size now equal (was 528), 191 == 191 instructions, objdiff 77.5% -> 95.5%; residue is a three-register cycle. - ai/action_charge.c _action_charge_perform (3,248 B, not parked): three hunks accepted - melee arm first, the `!ranged || underwater` arm, and the two-store unreachable test - each a pure block move or an equivalent rewrite with the same evaluation order. NOT landed: the worker's `__inline` added to eleven baseline-exact local math helpers (flips their COMDAT selection for zero credit; two earlier lanes declined the same lever; needs a helper-linkage ruling). action_charge still emits the January-owned _point_from_line3d. Config: config/parked.json - the two path entries re-measured in place by line surgery (base size / sha / objdiff percent) with a dated evidence note each. Parks 174 active / 0 stale / 0 invalid. Verification: see the preceding strict commit (same build): 0 exact regressions, 0 report rows lost. Reviewer: independent adversarial agent per unit, ACCEPT_FUZZY_ZERO_CREDIT; partial files built by the reviewers and re-gated by the orchestrator. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d57ba30c0d |
Lane B wave 2: nine strict-exact functions (+4,715 meaningful / +4,784 padded)
New strict exact (unit :: function, padded bytes): game/player_control :: _player_control_modify_desired_angles 1584 ai/actor_combat :: _actor_aim_projectile 720 memory/stack_memory_pool:: _stack_memory_pool_allocate 640 memory/stack_memory_pool:: _stack_memory_pool_resize_block 192 ai/action_vehicle :: _action_vehicle_setup_impromptu 464 scenario/wind :: _wind_variance_initialize 384 ai/actions :: _actors_searching_same_position 320 ai/action_converse :: _action_converse_perform 256 game/game_engine_race :: _race_engine_get_score 224 Function boards now complete: action_converse 9/9, wind 9/9, stack_memory_pool 33/33, game_engine_race 36/36, player_control 49/49 (objects NOT marked Matching: whole-object data/ownership audit not done; player_control .rdata is owner-held). Method. Every closure started from the SOURCE SHAPE read out of the first-party unoptimised /Od + /RTC build (halo_cache_symbols.exe, scratch/orch/odbuild.py) and was then confirmed against January's own bytes before it was relied on (double attestation); none is a spelling search. - _player_control_modify_desired_angles: both autolevel products are `error * K * magnitude3d(v)`; three lines, no local, cast or parenthesis. - _actor_aim_projectile: weapon_vector is scoped to its own inner block, the dot product is tested directly (no `alignment` local), and the three debug-info stores follow January's order (flag first). Reviewer strip tests: block alone, order alone and alignment-drop alone are each residual; only the combination is exact. - _stack_memory_pool_allocate: result zeroed before the 0x342 assert, ONE return, positive guard with the assert in the else, in-place size arithmetic. The worker's unattested `last_block` pointer local was REMOVED by the reviewer; the /Od arm spelling lands instead. - _stack_memory_pool_resize_block: body untouched. The static helper stack_memory_pool_dispose_block takes (pool, reference), as /Od pushes them and as the callee forwards them to valid_block(pool, reference). - _action_vehicle_setup_impromptu: passes state_data->attempt_distance / ->continue_distance (the fields just stored) instead of the parameters. - _wind_variance_initialize: block-local `word control_point_indices[4]` assigned inside the innermost axis loop; name and size from the /Od RTC descriptor. - _actors_searching_same_position: four pointer locals, result = FALSE after the four calls, if / else-if arms assigning result, one return. Requires actor_get_pursuit_location (baseline exact, STILL exact 64) to read uncover.pursuit_location through its own union member in a second arm, as /Od has it. The evade-direction enum gains its two real middle constants; values are unchanged (_actor_evade_random is still 4). - _action_converse_perform: REMOVES a pre-existing `true_value` dummy local from production. `in_range = TRUE` is assigned in two arms (if / else-if): /Od has two distinct stores, impossible from one `||` statement, and January has `mov ebx,1` with two bl stores each with two in-edges. One return. - _race_engine_get_score: a `score` accumulator assigned on both arms with ONE return (single-exit law); team_index/laps/flags_touched are block locals of the non-team arm. Orchestrator overrides of reviewer-approved text (not landed, zero credit lost beyond what is listed under HELD): - action_vehicle: the reviewer's landing.c also rewrote _find_destination with 16 NEW 3D->2D view casts. Owner ruling 2026-09-21 keeps rule 24 strict for new representation-punning casts, so only the two-line exact closure lands. - actions: _actor_action_try_to_dive (720, exact in scratch) needs ONE new view cast -> HELD. _actor_action_handle_vehicle_entry's fuzzy rewrite introduced an empty `if` arm holding only a `//` comment (new fake_match_scan lead the reviewer missed) -> reverted to production. Config: config/parked.json - six entries REMOVED (now exact): _action_converse_perform, _wind_variance_initialize, _actor_aim_projectile, _actors_searching_same_position, _player_control_modify_desired_angles, _race_engine_get_score. No header, symbols.json, flag or tool change. Verification (tip of the following fuzzy commit): full ninja all_source progress semantic_progress pass, Code 1446706 -> 1451421, 7297 -> 7306 functions. stable_verdicts vs the FROZEN baseline: gained 15 / 7568 bytes, regressions 0. All 11,060 function and 1,706 section report rows: 0 lost 100%, 0 missing. Parks 174 active / 0 stale / 0 invalid. Admission audit 23 / 0 / 8 / 0. Guard, ownership, fake scan, line endings, new-punning-cast screen: clean on every landed file. git diff --check clean. Reviewer: independent adversarial agent per unit, ACCEPT_EXACT for all nine; orchestrator re-gated every file through scratch/orch/land.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
479341043f |
Lane B wave 1: zero-credit fuzzy source corrections (infection, bipeds, physics)
ZERO exact credit. Better-evidenced source retained per house rule 11; none of these functions is parked, so no park entry moves. - ai/actor_type_infection.c _infection_swarm_control (3,616 B): partial rewrite from January's bytes. Baseline was 256 bytes short with a wrong frame and a wrong constant multiset (missing 1.0f, -1/15, (double)1e-4f, +/-pi/2; an extra _normalize3d call). Now residual [sha] ONLY: size 3616 == 3616 and relocations 104 == 104. Side effect: the unit's .rdata section (228 B) now matches January (data +228, not counted as Lane B code credit). Adds the include of ai_scenario_definitions.h for the _ai_atom_move_facing_* enum the recovered obey-facing switch needs (no header edited). - units/bipeds.c _biped_update_moving (4,080 B): four in-function corrections, each read from January: `0.01f` not the double `0.01` (January's constant is __real@3f847ae140000000 = (double)0.01f); `!(fabs(dyaw) < _real_epsilon)`; the two ground_tangential_* stores in January's order; no (short) cast on actor_index. The reviewer measured the worker's file-scope `realcmp` macro as byte-inert and it was DROPPED (strip test). Still residual [size, sha]. - physics/physics.c _physics_update_old (5,168 B): rotation_axis is assigned immediately before normalize3d, after object_translate - a store cannot cross a call, so its position relative to the call IS January's statement order. The reviewer REJECTED the rest of the physics candidate (21 PHYSICS_POINT_FROM_LINE3D macro sites and body rewrites) pending an owner ruling; only this two-line change lands. Verification: same full build and sweeps as the preceding strict commit - 0 exact regressions, 0 report rows lost, parks 180 / 0 / 0. Reviewer: independent adversarial agent, ACCEPT_FUZZY_ZERO_CREDIT for each; partial-landing files produced by the reviewers and re-verified by the orchestrator (unitcheck NO LOSS, guard, ownership, fake scan, line endings). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
01e16607f0 |
Lane B wave 1: six strict-exact functions (+2,727 meaningful / +2,784 padded)
New strict exact (unit :: function, padded bytes, relocations): game/aim_assist :: _local_player_aim_assist 368 12 game/game_engine_king :: _king_calculate_hill_state 448 32 units/unit_dialogue :: _unit_describe_speech 272 units/unit_dialogue :: _unit_make_damage_sound 784 units/biped_limp_noodle:: _biped_limp_noodle_relax_nodes_onto_environment 256 units/vehicles :: _create_ghost_effect 656 game_engine_king is now 29/29 on the function board (object NOT admitted: its .bss naming is owner-held and its .data is blocked, see below). Evidence per function: - _local_player_aim_assist: the later Win32 /Od build (halo_cache_symbols.exe fn 0x589420) and its RTC descriptor attest, independently of any compile, the result local initialised first with ONE return, the nested player_control_get_zoom_level argument, the real subtract_vectors3d call with RTC names velocity/target_velocity/magnetism_velocity, and two STORED pointer locals. /Od neither invents locals nor inlines. Closed on the first compile after the evidence; every element strip-tested alone -> residual. - _king_calculate_hill_state: the LAW Z negative-set member. January has ONE hill_controlled_count == HILL_CONTROL_TIME test at the bottom, not three; the team arm counts red/blue with the uncontrolled arm in the middle; each arm owns its data_iterator. That restores the two missing _king_globals references and January's pinned zero register with no zero-store steering. - _unit_describe_speech: the one board function whose loop differs by pure shape (January top-tested). A done-flag `while (!done)` loop, the Marathon idiom. - _unit_make_damage_sound: single-exit law (January 1 ret, ours had 2); the body is guarded by dialogue_index != NONE instead of an early return. - _biped_limp_noodle_relax_nodes_onto_environment: accessor-binding law - the object_get() result is bound to a local (non-destructive lea), as January does. - _create_ghost_effect: the marker count is TWO shorts summed in the loop test (hover_marker_count from the call, jet_marker_count = 0). First-party attestation: the later unoptimised debug build (halo_cache_symbols.exe fn 0x8f5530) stores the call result to one short, zero-initialises a SECOND short, then marker_index, and its loop test is movsx idx / movsx a / movsx b / add / cmp; the sibling create_pelican_effect (0x8f5c90) has the same three slots with the second one counting "jet thrusters". January's store order (`mov [ebp-4],0` then the call result) is exactly that. The zero-valued local is therefore an attested source variable, not a steering dummy; without it the body is the old residual. Flagged in the handoff for owner awareness. Zero-credit riders in the same files (no credit claimed): - vehicles.c _update_alien_fighter_physics_new: credible restructure with scoped blocks and real names; still residual [relocs 33!=32, sha]. The reviewer measured `real const` thrust locals as byte-neutral, so the plain literals land. - game_engine_king.c: adds the MISSING `struct game_engine king_engine` table (declared in the header, referenced from game_engine_list.c, defined nowhere). 136 bytes, 0 content bytes differ from January, 23/23 relocations identical. objdiff still scores the section <100%: January leaves the "king" literal undefined in this object and `$`-literal relocations match only by combined address (same cause as race_engine). Correct source, zero data credit. Config: config/parked.json - four entries REMOVED (now exact): _king_calculate_hill_state, _biped_limp_noodle_relax_nodes_onto_environment, _unit_describe_speech, _unit_make_damage_sound. Parks 184 -> 180, 0 stale, 0 invalid. No header, symbols.json, flag, tool or semantic-override change. Verification: full ninja all_source progress semantic_progress pass (Code 1443979 -> 1446706, 7291 -> 7297 functions). stable_verdicts vs the frozen baseline: gained 6 / 2784 bytes, regressions 0. Row diff of all 11,060 function and 1,706 section report rows: 0 rows lost 100%. Admission audit 19/0/8/0. _point_from_line3d guard, ownership (newly defined symbols vs January) and fake_match_scan: clean on every changed file. git diff --check clean. Reviewer: an independent adversarial agent re-gated every candidate from scratch and returned ACCEPT_EXACT for all six; orchestrator re-verified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
7583df5d62 |
Lane B prerequisite: take the data lane's hunks in six Lane B files
Identical text to claude/data-section-credit-20260920 for these six files
(git diff against that branch is empty), so the two branches merge cleanly.
ZERO Lane B credit is claimed: the five data sections belong to the data lane.
Taken deliberately because three of the hunks change relocation IDENTITIES
that Lane B code residuals need before they can ever gate exact:
action_vehicle.c 0.1225f -> 0.35f*0.35f (__real@3dfae147, January's
folded product) - _action_vehicle_find_destination
collision_debug.c assert text count<=14 - _collision_debug_render
path_structure_bsp.c assert spacing - _structure_test_line2d
and three are the .bss layout law (= 0 / = FALSE on debug globals):
player_control.c, collisions.c, bipeds.c
Units/functions: none change verdict. Strict meaningful +0, padded +0.
Fuzzy: none. Data: +489 B (116+300+43+26+4), credited to the data lane.
Stable regression: scratch/lane_b_before.json -> lane_b_w0.json, 0 regressions,
0 gains. Lane inventory row-diff: 0 losses, 0 moves. Parks 0 stale / 0 invalid.
Full ninja all_source progress semantic_progress: pass
(Code 1443979 / 1770166, 7291 / 7574; Data 2360994 -> 2361483).
Config/header changes: none. Reviewer: data lane's own verification; re-verified
here by full build and row diff.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
f910bd2754 |
encounters.obj CLOSED 61/61: _encounter_create EXACT (+752), switch at one site
Owner ruling 2026-09-20: admit at the single byte-proven site only; document the
threading-law evidence; leave the byte-invisible site natural.
The random-leader case now tests the marine type with a single-case switch,
switch (actor_type) { case _actor_marine: ... break; }, instead of an if. The
normal-leader site keeps its natural if. No source comment is added; the
evidence is recorded here and in the lane ledger.
WHY THIS SITE. January re-tests actor_type on the fall-through from the normal
case into the random case - mov ecx,[ebp-0x14] at 0x223, cmp cx,7 at 0x226 -
and that test is semantically redundant, because the dominating normal-case test
has already established actor_type == _actor_marine on that path. The redundant
test physically survives in January's bytes at the random-case site, which makes
that site the byte-proven one.
THE THREADING LAW (decoded, VC7 13.00.9254). The jump threader carries branch
knowledge from if compares but not from switch case edges, and it does not
thread an edge into a switch-dispatch test. With an if at both sites our build
threads the fall-through past the random test (jmp over it); about 25 if-based
spellings all stay threaded. A single-case switch at the random site is exactly
the shape that keeps January's re-test. The same law reproduces in a standalone
repro TU. The normal site's form is invisible in the bytes - a switch there also
matches - so it stays an if, per the ruling.
Measurement note: objdiff's fuzzy figure reads 94.19%, not 100, because of
recorded trap #2/#4 - January's jump table relocates onto _encounter_create+0x2c0
and ours onto an internal $L label, the same seven bytes spelled differently. The
strict comparator reports 38/38 relocations with 0 differing rows and the build
credits the function.
Verified: full ninja green; code 1,463,135 -> 1,463,880 (7,305 -> 7,306
functions); encounters 60/1 -> 61/0; 11,060 function rows and 1,706 section rows
diffed board-wide, 0 worse; no symbol added or removed; parks 179 / 0 / 0; forbid
guard exit 0; fake_match_scan 0 findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
3ad3622623 |
props.obj CLOSED 17/17: _prop_get_active_by_unit_index EXACT (+144)
Owner ruling 2026-09-20: admit as proposed - the iterator and single-exit result
are natural; document the load-bearing declaration order in the ledger, not with
an intrusive source comment. No source comment is added.
The loop is rewritten with prop_iterator, this file's own idiom: both props.c
siblings that walk props use it (prop_get_base_by_unit_index,
prop_new_unacknowledged), January inlines it in both - there are no
_prop_iterator_* relocations - and January's prop_get_base bytes show the same
inlined header, cmp ecx,-1 then index := next then je, as this function. The
match predicate and the single-exit result follow the sibling. No new symbol is
defined.
LEDGER - THE LOAD-BEARING DECLARATION ORDER. The one fact that decides the match
is not visible in January's bytes: the single-exit initialiser long result =
NONE must EXECUTE AFTER the target-actor selection, so it is the last
declaration. Its web and the -1 constant then sit in the pre-loop join block that
initialises the cursor, lifting the cursor web's priority from 36 to 40 - a tie
with the state web that the [W+0x44] position tie-break awards to the cursor, so
it takes ecx, which is January's colouring. Declaring result first, as the
sibling does, is measured residual. Both the result web and the constant vanish
from the final code, which is why more than fifty earlier spellings - all without
a result variable, or with it initialised first - never reached it. The decoded
allocator's force-test confirms the threshold exactly (state <= 36 or cursor >= 40).
This reverses recorded conclusions R16 ("closed class-C colouring tie"), the
wave-I oracle's "UNREACHABLE by natural source", and props_obj.md's "do not
repeat" on the combined predicate, which does fail inside the plain loop but is
exact inside the iterator loop.
Verified: full ninja green; code 1,462,991 -> 1,463,135 (7,304 -> 7,305
functions); props 16/1 -> 17/0 with .text at 100%; 11,060 function rows and
1,706 section rows diffed board-wide, 0 worse; parks 179 / 0 / 0; forbid guard
exit 0; fake_match_scan 0 findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
ba612bffb7 |
_actor_customize_unit EXACT (+640) under the narrow _random_range exception
Owner ruling 2026-09-20: allow the narrow _random_range COMDAT exception and land +640. Do not extend it to _point_from_line3d; its explicit guard remains. One line. The grenade count is computed with the header's __inline helper, random_range(lower, upper + 1), instead of spelling out seed_random_range(get_global_random_seed_address(), lower, upper + 1). This is exactly how the already-exact _ai_scripting_renew in ai_script.c computes the same grenade count from the same fields. The decoded allocator predicts why it matters: the helper's two inlined parameters raise the grenade block's pressure from 3 to 5, lifting actor_variant_definition's web from 53 to 65 - one point above change_colors at 64 - so it takes ebx and change_colors spills, which is January's allocation. The same form also fixes the push order at 0x18e. One source fact resolves both halves of what had been classed as "allocator decision plus a separate difference". THE EXCEPTION, and its limits. The change newly defines exactly one symbol, _random_range, a COMDAT byte-identical to January's single copy, which the split credits to action_obey.obj. That emission is admitted by the ruling above and by nothing broader; ai_script.obj and encounters.obj already emit the same COMDAT. The _point_from_line3d guard still exits 0 on this unit. The function was parked; its entry is removed by brace-depth line surgery. Verified: full ninja green; code 1,462,353 -> 1,462,991 (7,303 -> 7,304 functions); actors 73/3 -> 74/2; 11,060 function rows and 1,706 section rows diffed board-wide, 0 worse; newly defined symbols: _random_range only; parks 180 -> 179 active, 0 stale, 0 invalid; fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
a0343465fc |
_actor_create_for_unit EXACT (+624): one return statement instead of five
The residual was one source fact. January's actor_create_for_unit has a single
exit - long actor_index = NONE; if (unit_index != NONE &&
actor_variant_definition_index != NONE) { ... } return actor_index; - with no
inner returns. Ours had five return statements.
This is the recorded single-exit law, and the shape is attested in this very
file: actor_new opens with the same long actor_index = NONE guard and returns
once. With one return VC7 splits the bottom return per incoming edge, which gives
the NONE initialiser its own web coloured esi; the -1 constant is then rescued
into esi by copy preference - January's pin - and the guard-fail exit becomes a
separate epilogue that does not pop ebx, so push ebx sinks below the guards.
Every piece of the recorded "-1 pin plus fifth epilogue" residual follows.
The biped rejection now clears a boolean valid flag, the attested carrier for
this idiom (actor_firing_position.c, ai_communication.c and action_charge.c use
the same spelling). It is not what buys the bytes: VC7 threads it away entirely,
leaving no register, slot or instruction, and four different spellings of it
compile to identical bytes. Restoring any single early return breaks the match.
The function was parked (class register-allocation); its entry is removed by
brace-depth line surgery, never re-serialized, and parks go 181 -> 180.
Verified: full ninja green; code 1,461,731 -> 1,462,353 (7,302 -> 7,303
functions); actors 72/4 -> 73/3; 11,060 function rows and 1,706 section rows
diffed board-wide, 0 worse; parks 180 active / 0 stale / 0 invalid; forbid guard
exit 0; fake_match_scan 0 findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
3fdad47e67 |
_ai_communication_event: evidenced corrections, relocations now equal - ZERO bytes
Owner ruling 2026-09-20: land the package minus the invented flag and the unproven actor-arm polarity change; keep all evidenced corrections, document it as fuzzy, grant zero credit. The function stays residual and this is not scoreboard movement. Result: relocations 335 -> 336, equal to January with an identical multiset; the frame now matches January's 0x126c (was 0x1268); REAL regions 339 -> 253. Padded size moves from 16 short to 64 over - accepted because relocation identity outranks padded size in the lane's ordered key, and on this function size is dominated by the non-local branch-width noise wave H measured. THE BEHAVIOUR FIX, proven by a controlled experiment rather than taken on trust. The encounter arm of enemy_status[5] read !subject_encounter->enemy_alive. Flipping ONLY that negation, with nothing else changed, turns exactly one instruction - the je after the byte load at [esi+0x44] - into jne, and January has jne at that site. So January's source tested enemy_alive; ours was wrong. WHAT WAS DELIBERATELY LEFT OUT, per the ruling: - the invented negative-sense protagonist_invalid flag. It moved padded size only (the frame matches January without it), the same profile as the steering rejected in _actor_look_update. - the matching flip in the ACTOR arm. On the floor that flip is byte-inert, so January's bytes cannot decide it; it stays !target_really_alive. For the record, within this package it is not inert - 8,096 bytes with it against 8,128 without, but REAL regions favour the other way (265 against 253) - so the signals conflict and nothing proves either polarity. Other evidenced corrections kept: the 2.0f literal at the player-rating assignment, value-identical to the real const it replaces, where January references that global once and we did twice; char locals for the two %c debug codes, which January computes at 8 bits; statement orders recovered from store positions relative to calls. Disclosed per the verifier: play_type now lives in candidate scope, so a reply candidate stores _unit_play_speech_none instead of a stale value - dead data, since play_type is read only on the non-reply path. Verified: full ninja green; 11,060 function rows and 1,706 section rows diffed board-wide, 0 worse; ai_communication 45/3 unchanged; its .rdata stays 100%; no symbol added or removed; parks 181 active / 0 stale / 0 invalid; forbid guard exit 0; fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0269a75997 |
_ai_debug_render_actor: fix seven January-proven defects - ZERO bytes banked
A source-correctness landing under the standing "correct source beats a
misleading byte score" ruling. The function stays residual and this is not
scoreboard movement - though here every key improves as well: padded size
25024 -> 25008 against 24976, REAL regions 529 -> 340, and the frame now
matches January exactly, sub esp,0x80c -> 0x810.
Each defect was confirmed by its own January byte window becoming register-blind
identical, and by leave-one-out (dropping any one raises the blind region count).
V1 a real UNINITIALISED READ. January passes lea [ebp-8] and lea [ebp-4] as the
full and partial vision-distance out-pointers and reads [ebp+edx-8] in the
second loop nest: it is ONE real[2] array. Our full_distance_reference[1] was
never written. Fixing it is what brings the frame to 0x810.
P2 an UNREACHABLE ARM. January's je 0x5c5f from both the render_paths_current
test and the has-path test lands on the "following path" status text, so it
sits outside that block; our "no current path" else could never run.
N1 normalize2d writes straight into desired_facing's own cells before the > 0
test, spelled as at actor_combat.c:2304 and eight other AI sites.
X four cross blocks read p0.x, not p1.x (fld [ebp-0x18]): p0.x = p0.x - 0.2f.
P1 the paths block indexes steps by the short local, not the char field.
SR1 the avoidance-objects loop addresses through an element pointer, as at
actor_moving.c:903.
FA2 the flying-axes blocks use the existing __inline helpers scale_vector3d and
point_from_line3d in January's term-major order. These are ordinary calls to
existing helpers, which house rule 13 permits; nothing is written out.
Disclosure the verifier required: FA2 adds twelve (real_point3d *) casts on the
point_from_line3d arguments. All twelve are strip-test inert - the section is
byte-identical with them removed - and the cast is the tree-wide idiom.
Verified: full ninja green; 11,060 function rows and 1,706 section rows diffed
board-wide, 0 worse; ai_debug 59/1 unchanged; no symbol added or removed; the
pre-existing _point_from_line3d guard finding stays at exactly one; parks 181
active / 0 stale / 0 invalid; fake_match_scan 0 findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
fd57245a6e |
_actor_move_vector_avoidance: 96 bytes short -> 16 - ZERO bytes banked
The function stays residual; this is not scoreboard movement. Padded size goes 4048 -> 4128 against January's 4144, relocations stay at 135/135, and REAL regions go 180 -> 170. This recovers most of the size an earlier landing traded away to get the relocation count exact. THE PERPENDICULAR SITE is written as a two-axis accumulation - rotation starts from *global_zero_vector3d and takes only the left and up terms - instead of a call to actor_move_transform_avoidance_vector. This is a reconstruction of January's own code, not the helper body written out: January's bytes at 0xe73-0xf02 contain no forward-axis term at all, no load of avoidance_data.forward and no multiply by __real@00000000. VC7 13.00.9254 never folds x*0.0f; with the helper genuinely inlined at this very site it leaves three fmul by zero. So January's source computed only two axes, in its own text. A comment at the site says so. The remaining hunks are statement reorders fixed by store positions relative to calls, and a declaration moved to where January's frame puts it. The verifier found a dead store, perpendicular.i = 0.f, never read once the forward term is gone. It is byte-inert - the function's bytes are identical with and without it - so by the strip test the plain spelling is the admissible one, and it is removed. No diagnostic-only dummy locals are present. Verified: full ninja green; 11,060 function rows and 1,706 section rows diffed board-wide, 0 worse; actor_moving 31/5 unchanged; newly defined symbols versus the floor: none; parks 181 active / 0 stale / 0 invalid; forbid guard exit 0; fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2ee8bfefe8 |
_actor_move_update: fix a proven allow_jump defect - ZERO bytes banked
The function stays residual at [sha]; this is not scoreboard movement. REAL regions 57 -> 53 with size, relocations and real code end all unchanged. THE DEFECT, verified from January's bytes before landing. Our source set allow_jump only when BOTH vehicle->vehicle.hover < 0.7f AND up.k < 0.8f. January tests hover (fcomp __real@3f333333 at 0x54e, jp 0x5fa), then executes mov byte ptr [ebp-3], 1 at 0x562 - allow_jump = TRUE - and only then tests up.k (fcomp __real@3f4ccccd at 0x566, jp 0x5fa). So January sets allow_jump whenever hover < 0.7, and falls through when up.k >= 0.8. Our source had a real behaviour difference; the if is now nested accordingly. The escape direction, crouch and break stay inside the up.k test. Also: rotation is scaled with the existing scale_vector3d helper instead of three *= statements. WHAT WAS NOT LANDED. The wave's primary variant PA also rewrote a negation with negate_vector3d, which makes actor_moving.obj newly define a _negate_vector3d COMDAT. January's actor_moving.obj does not define that symbol, so under the 2026-09-20 ownership ruling it cannot be emitted; PA_noNG, landed here, adds no new symbol. A further variant PB is byte-worse on padded size (+16) and its extra levers are neutral respellings rather than fixes, so it stays held. Verified: full ninja green; 11,060 function rows and 1,706 section rows diffed board-wide, 0 worse; actor_moving 31/5 unchanged; newly defined symbols versus the floor: none; parks 181 active / 0 stale / 0 invalid; forbid guard exit 0; fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
5dddede52e |
_ai_test_line_of_sight: take HCEX-attested local names - byte-identical, ZERO bytes
Renames the function's parameters and locals to the names HCEX.pdb records: point0 -> p0, cluster0 -> p0_cluster_index, point1 -> p1, cluster1 -> p1_cluster_index, collision_fraction -> collision_t, and the expand-source / expand-target corners to p0a/p0b and p1a/p1b/p1c. Per the house rule on real names. All 128 non-debug sections of ai.obj are byte-identical before and after, so the parked entry stays valid and nothing is scoreboard movement. WHAT WAVE H ESTABLISHED ABOUT THIS FUNCTION - recorded because it overturns a committed "proof". R11, R25 and res7 said no shape closes its 12-byte frame gap. Every probe behind that kept four separate objects and only changed scopes. The ledger now closes to the byte: 34 real bytes = the 7-byte collision_t initialiser (the correct behaviour we keep, since January's bytes prove it reads an uninitialised slot on the heavy-fog path) + 27 bytes from ONE surplus 12-byte frame cell - 24 bytes of disp8 -> disp32 lea widening because our frame crosses 0x80, and 3 bytes for a cross-jump January can take and we cannot. The mechanism: ai.c's TU-private REAL_MATH_EXTERNAL_NORMALIZE3D and REAL_MATH_EXTERNAL_POINT_FROM_LINE3D defines make perpendicular address-exposed, which blocks liveness packing and forces the interleaved struct copy. With the helper bodies visible, the separate-locals source HCEX attests reproduces January's frame, slot census and copy order exactly; size, 50 relocations and 331 instructions all match, and 37 ModRM bytes plus one esi/edi decision remain. That route is dead under the 2026-09-20 ownership ruling: visible bodies make ai.obj emit a _point_from_line3d COMDAT that January's split does not attribute to it. So the function stays residual, now for a stated reason rather than a false impossibility proof. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f5698ba245 |
_actor_look_update: land owner-admitted (a)+(b) only - ZERO bytes banked
Owner ruling 2026-09-20: admit (a) and (b) only; reject (c) as semantically
inert steering; keep the function fuzzy at zero credit and audit the helper's
COMDAT ownership. It stays residual at [size 4704!=4720, sha] and this is not
scoreboard movement.
(a) valid_real_normal2d's definition takes the __inline specifier. Its sibling
valid_real_normal3d is __inline in real_math.h, and four January objects
reference this function. The call stays out of line.
(b) the aiming-speed tail is two separate tests rather than one disjunction;
HCEX's line table puts them on separate lines, 1740 and 1745.
Both carry in-file disclosure comments, which were checked to leave the
function's bytes identical to the measured candidate.
What was NOT landed, and why:
- (c) can_look = TRUE on the asleep path - rejected by the ruling.
- the copy of desired_aiming into desired_looking moved after update_facing.
It was paired with (c). Without it, the asleep path has already set both
vectors from desired_facing, so the move adds only a redundant store of an
equal value - the same inert steering (c) was rejected as.
- the plain-source edits (the minor_valid flag, the 2D struct copies and dot
order). Ablated one subset at a time: without (c) they push padded size from
4704 to 4688 and instructions away from January's 1,439, so under the lane's
ordered key they are WORSE and stay out.
(a)+(b) alone ties every higher key - size 4704, relocations, 1,439
instructions, real code end 4690 - and improves REAL regions 120 -> 119.
COMDAT OWNERSHIP AUDIT, as directed: CLEAN. In both builds actor_looking.obj is
the only definer of _valid_real_normal2d and actors, actor_moving and units are
its only referencers. The one difference is the COMDAT selection flag, now
select-any against the split's no-duplicates - but csplit writes no-duplicates
for all 8,223 function COMDATs and never records select-any, even for helpers
that were certainly __inline in January such as valid_real_normal3d and
dot_product3d. The flag carries no evidence, and our build already differs this
way on 162 functions including that sibling.
Verified: full ninja green; 11,060 function rows and 1,706 section rows diffed
board-wide, 0 worse; actor_moving 31/5, actors 72/4 and units 189/189
unchanged; parks 181 active / 0 stale / 0 invalid; forbid guard exit 0;
fake_match_scan 0 findings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
923940b71b |
_actor_emotion_unopposable_retreat EXACT (+1,264): reuse the admitted square macro
Owner ruling 2026-09-20: admit the macro reuse, and update its evidence comment to disclose that the hand-written parenthesised form also matches here. The function closes strictly exact from plain source plus one reuse of the already-admitted TU-private actor_perception_distance_squared macro, at the friend-target distance square. The plain-source parts, each shown load-bearing by reverting it alone: - actor_emotion_assess_unopposable_danger spells its priority as if (facing <= 1) priority = 3; else priority = 2; rather than (facing<=1)+2. Both constants then thread through the inlined helper before if-conversion, which removes the join test that had exiled the visibility arm out of line. The helper itself stays byte-identical and EXACT at 112. This answers what suppresses a hoist: remove the reason for the join test, not the placement. - a redundant if (target_count > 0) guard around the priority-adjust loop is deleted; that IL-changing, code-preserving guard had tipped a whole-function allocator state to the wrong side. - block-scope iterator, one function-scope target_index, and named upper_bound / lower_bound reals at both random-range sites (the action_guard.c idiom). The macro comment now carries the honest ladder, re-derived independently before the ruling: d*d and (d*d) fail at size 1280, while (d)*(d) and the macro's ((d)*(d)) both match. Unlike the first site, the single-parenthesis hand spelling also matches here, so this site alone does not prove a macro stood there; the comment says so, and that the macro is used here by ruling. Verified: full ninja green; code 1,460,468 -> 1,461,731 (7,301 -> 7,302 functions); 11,060 function rows and 1,706 section rows diffed board-wide with 0 worse, the only movement being the target and actor_perception .text; actor_perception 39/5 -> 40/4; parks 181 active / 0 stale / 0 invalid; forbid guard exit 0; fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b423909b1d |
Name ai_sound_volume_enum_strings from HCEX: +1,560 data bytes
ai.obj's 1,560-byte .data section sat at 97.8% with ZERO differing content
bytes. January's split has no name for the five-entry sound-volume table, so it
spelled the enum's reference to it as _ai_update_section + 0x5f8, while ours
spelled it _ai_sound_volume_names + 0 - the same address. objdiff credits a data
section all-or-nothing, so that one relocation spelling held back all of it.
AUTHENTICATED PROVENANCE, as the lane brief requires for symbols.json. The HCEA
SHIP PDB (HCEX.pdb), read with DIA2Dump -compiland on
..\..\..\build\x360\SHIP\halo\ai.obj, records:
Data : static, File Static, Type: char *[0x5], ai_sound_volume_enum_strings
A five-pointer array is exactly the 20 bytes between +1528 and +1548, and it is
file-static. That also shows our name was WRONG: Bungie's is
ai_sound_volume_enum_strings, not ai_sound_volume_names. Per the house rule on
real names for private globals it is renamed in ai.c - two lines, and since it
is static nothing outside the file references it.
symbols.json gains one line, by line surgery with its CRLF endings preserved,
at a file offset where nothing existed before, so there is no alias-precedence
risk at a shared offset:
{ "file_offset": 2847464, "flags": 0,
"name": "_ai_sound_volume_enum_strings", "static": true }
The form matches the 273 existing data statics.
Verified:
re-split every one of the 833 split objects hashed before and after;
exactly ONE changed, source/ai/ai.obj; none new or vanished
board 11,060 function rows: 0 worse, 0 better, 0 vanished, 0 new
1,706 section rows: 0 worse, 1 better (ai .data 97.814 -> 100.000)
metric Data 2,376,514 -> 2,378,074 (+1,560); code unchanged
lane all 11 units unchanged at 523 exact / 24 residual
gates parks 181 active / 0 stale / 0 invalid; ai forbid guard exit 0
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
264ddd8a3a |
Declare game_allegiance_get_incidents and restore its caller: +11,600 data bytes
Owner ruling 2026-09-20: approve with full sweep - land the prototype and the
decoded block only after all 12 consumers, ownership, guard, full build and
zero-regression checks pass. All passed.
game_allegiance_get_incidents is defined in game_allegiance.c and called from
nowhere, and was declared in no header - a genuine omission, since every sibling
function of that file is declared in game_allegiance.h in exactly this style. The
declaration is placed between game_team_is_ally and game_allegiance_provoke,
matching the definition order in the .c.
The caller is the block decoded from January's _ai_communication_event at
0x3c1-0x409: when ai_debug.print_allegiance is set and the allegiance still
holds, it prints the incident count against the threshold, substituting 999 for
a NONE threshold. It sits inside if (observed) where broken is in scope; the
argument order is fixed by January's reuse of the cause_team slot at 0x40c.
WHY IT PAYS. objdiff credits a data section all-or-nothing, and
ai_communication's 11,600-byte .rdata sat at 99.5% purely because this block's
two string literals were never emitted. Data moves 2,364,914 -> 2,376,514,
exactly the +11,600 measured beforehand on a scratch candidate.
_ai_communication_event stays residual - 16 bytes short instead of 96, 335 of
336 relocations - so the code metric is unchanged at 1,460,468 / 7,301.
THE SWEEP, as required:
full board 11,060 function rows and 1,706 section rows diffed before/after:
0 worse, 0 vanished, 0 new; 3 better (the target function, and
ai_communication .rdata 99.51 -> 100.00 and .text 94.90 -> 95.24)
consumers strict gate rows for all 12 files that include the header:
exactly one row moved, the target, and it improved; no EXACT lost
guard --forbid-emitted-symbol _point_from_line3d identical on all 12
ownership the change newly defines exactly two symbols, both string literals
that January's ai_communication.obj also defines, and newly
references one, which January's object also references - CLEAN
build full ninja green; parks 181 active / 0 stale / 0 invalid;
fake_match_scan 0 findings; no C4013 implicit declarations
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
94c3273708 |
Define and use ai_script_squad_separator: +3,920 data bytes
January's ai_script.obj carries a one-byte external .rdata object, _ai_script_squad_separator = '/', which our build did not emit at all. Our source used the literal '/' at the one site that splits an "encounter/squad" name with strrchr. Now defined as a file-scope char const and used at that site. VC7 folds the const into the immediate, so the function's code is byte-identical and ai_script stays 116/116 exact - and because the object keeps external linkage it is still emitted, matching January exactly: .rdata, one byte, class external, 0x2f, and zero code relocations to it on either side. The defining-only variant also matches the bytes but was rejected: a global that nothing uses exists only to emit a byte, which is what the no-fake-matching rule forbids. Using it at the split site is what explains why January had it. The data metric moved far more than one byte, from 2,360,994 to 2,364,914 (+3,920), which suggests the build credits a unit's data only once all of it matches. That is being investigated separately. Verified: full ninja green, code unchanged at 1,460,468 / 7,301, parks 181 active / 0 stale / 0 invalid, forbid guard exit 0, fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
67a1117544 |
Fix swapped colour arguments in _ai_debug_render_actor and re-baseline it
Owner ruling 2026-09-20: land it and re-baseline the fuzzy floor; correct source outweighs a misleading byte score; grant zero exact credit and document the backend artifact. ZERO exact credit. The function stays residual at 24,976 padded bytes and this is not scoreboard movement. ai_debug.c:1100 and :1110 had their colour arguments swapped relative to January. Verified from January's bytes before landing: January pins the color local in EBX for the whole loop body, selecting white, yellow or aqua at 0x5a7, 0x5c5 and 0x5cd, then pushes EBX at the first site and _global_real_argb_blue at the second - the latter immediately followed by push 0x3f800000, the 1.f argument of render_debug_vector. Our source had them exactly reversed. The fix takes a 480-byte window from 431 differing bytes to 13. The floor is numerically worse: padded size goes from 24976 to 25024 and REAL regions from 495 to 529. That previous size equality was never a match - it was the padding coincidence recorded in wave C, whose "the code length comes back" claim was already retracted. The new number is an honest floor measured against correct source. No sibling moved; ai_debug is 59/60 before and after. The 48 bytes are NOT caused by the colour fix. They are an independent branch-shortening FIXPOINT, and that is the reusable finding: of the eight branches where January emits SHORT and we emit NEAR, five have final spans comfortably inside +/-127, and for one of them January's span and ours are the identical 123 bytes. Three seed branches one byte over the line block the other five. It is the largest byte family in the function, has no known source lever, and is invisible to every region metric - trap #6 at scale. It also explains the non-additive sizes earlier waves measured. Corollary that changes the plan here: the 4-byte-short frame is currently paying for the branch tax, so correcting it in isolation makes the function +39 rather than +12. No future wave should attack the frame on its own. Verified: full ninja green, halobetacache 1,460,468 / 7,301 unchanged by this commit, parks 181 active / 0 stale / 0 invalid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
8e4309dd16 |
Admit January's out-of-bounds threat scan: _actor_emotion_update EXACT (+1,664)
Owner ruling 2026-09-20: admit as a target-proven BUG with a precise source comment, a layout assertion, and independent verification. January scans the threat array from NUMBER_OF_ACTOR_THREAT_TYPES rather than from NUMBER_OF_ACTOR_THREAT_TYPES-1, so its first iteration reads specific_threats[9] - one element past the end. Proven from raw bytes: mov eax,9 at +0xf5, a six-byte alignment nop touching neither EAX nor memory, the loop head at +0x100, the load at +0x103, and dec eax only at +0x10d, after the load. The same read was refused earlier because it was being landed on a function that would stay fuzzy. That premise no longer holds - the function is now STRICT EXACT, so January's own bytes prove the access rather than a reconstruction guessing at it. Per the ruling the layout is now ASSERTED rather than assumed. Two compile-time assertions in this file's existing assertion block state that specific_threats holds exactly NUMBER_OF_ACTOR_THREAT_TYPES elements and that cumulative_threats begins immediately after it, so the stray index is cumulative_threats[_actor_threat_none] and nothing else. If either stops holding, the file stops compiling. Independent verification, done before the landing rather than taken on trust: every use of cumulative_threats in the whole tree is index 1 through 8 or the literal 5; index 0 is never written anywhere; and the single variable-index use is a read-only csprintf argument in the actor_debug_print_threat debug macro. The stray byte is therefore always zero, the early-out never fires on it, and observable behaviour is unchanged. The comment now records all of that. The byte ledger closes exactly at 19 differing bytes and was verified additively - closing either half alone leaves the function residual at 13 or 18 bytes, so the crouch restructure could not have been landed alone. The second half is a semantics-preserving if/else-if restructure; all four input combinations traced. Verified: full ninja green, halobetacache 1,460,468 / 1,770,166 (7,301 / 7,574), actor_perception 38/6 to 39/5 with no sibling lost, relocations 38/38 and zero differing rows, parks 181 active / 0 stale / 0 invalid, forbid-guard exit 0, fake_match_scan 0 findings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b6c4100427 |
Reorder two statement pairs in _actor_move_update - ZERO bytes banked
The function does not close, so this banks zero bytes and is not scoreboard movement. REAL regions 63 to 57; size 3136 and relocations 72 already matched and still do. Both hunks are pure statement reorders with identical semantics. crouch = FALSE moves after the vector_from_points3d call, and move_in_3d = TRUE moves ahead of two independent local assignments. Neither value is read by anything it crosses. The positions are January's: a store's position relative to a CALL is source statement order. Verified: full ninja green, parks 181 active / 0 stale / 0 invalid, no gate row moved anywhere in the unit, forbid-guard exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c23d0f5386 |
Wave F fidelity landings: three improvements, ZERO bytes banked
None of these three close a function. The board metric is unchanged at 1,458,814 / 7,300 and none of this is scoreboard movement. _ai_debug_render_actor - binds actor->input.position.head_position to a named local, which is the recorded accessor-binding law: the inline field reference folds the offset destructively, while binding it forces the non-destructive form. It emits January's fsubr [ebx+4] / fsubr [ebx+8] for the first time and recovers 6 real bytes. Wave E's refutation of the "this family needs a header prerequisite" claim stands - point_from_line3d and scale_vector3d are already __inline in real_math.h and already called this way in this file. _actor_move_vector_avoidance - relocation COUNT goes 140 to 135, which is January's exactly, and relocation identity goes 5 differing rows to 2. REAL regions 200 to 180, register-and-frame-blind 100 to 84, frame 0x60ec to 0x60e4 against January's 0x60e0. Key 3 moved AWAY and by more than the padded figure shows - real-code distance went from +47 to -87 - which is acceptable only because relocation identity outranks padded size in the lane's ordered key. The verifier required that disclosure survive into any summary, and it does. _ai_communication_event - closes 80 of the 176 missing bytes, from 7888 to 7968 against 8064, by writing the actor_get plus actor_type_get_race sequence we were missing entirely. The separate 72-byte block remains header-blocked on game_allegiance_get_incidents and was left strictly alone: no header edit and no consumer-local prototype. Verified: full ninja green, parks 181 active / 0 stale / 0 invalid, exactly one gate row moved per unit with none lost, forbid-guards exit 0 on all three units, fake_match_scan 0 findings on all three files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
ea507d5bc7 |
Wave E fidelity landings: four improvements, ZERO bytes banked
None of these four close a function, so none of them bank a byte and the record says so plainly. The board metric is unchanged at 1,458,814 / 7,300. _actor_perception_aiming_vector_test_blockage - the only one that moves a HIGHER ranked key. The 16-byte size gap is closed: both builds are 400 padded bytes and the gate row goes [size 384!=400, sha] to [sha], with REAL regions 9 to 7. January does not use a result/blockage PAIR but ONE short carrier whose live range VC7 splits three ways. That was forced by running the return-width law BACKWARDS: in a short function a literal return 1; emits mov ax,1, but January emits mov eax,1, so January's constants are assignments to a short local whose register home is eax. The decode independently corroborates the cascade I read from January's bytes earlier in this session. _actor_emotion_unopposable_retreat 47 -> 44 REAL regions. _actor_destination_update 24 -> 20 REAL regions. _actor_move_update ties every ranked key; one instruction moves from differing to matching. Its one-line change is spelling vehicle->vehicle.airborne_ticks as > 0. I verified the load-bearing claim myself and it is stronger than stated: the field is byte at vehicle_datum.h:26, so the two forms are provably identical on an unsigned type; vehicles.c:2309 spells this exact expression on this exact field; and EVERY other use of the field in the tree is an explicit comparison, so the bare truth test was the anomaly. The blockage landing stales a second parked entry, whose evidence explicitly said the size gap was 'not attributed to a proved compiler mechanism'. It now is, so the measurements are refreshed and the evidence records the decode. objdiff falls 56.21528 to 54.791668 there, which is diagnostic only and never credit - every authoritative key improved or held. Both functions stay parked because neither is exact. parked.json was edited by line surgery. Verified: full ninja green, parks 181 active / 0 stale / 0 invalid, all 11 lane units gated per row with no row lost, forbid-guards exit 0, fake_match_scan 0 findings on both touched files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b3223f36e8 |
Narrow-return package LANDED: +8,400 strict bytes - my 'proven impossible' was wrong
I committed in
|
||
|
|
73c0519846 |
Land the owner-approved parenthesised accessor: _ai_test_line_of_fire EXACT (+336)
Owner ruling 2026-09-20: admit the named TU-private accessor macro with
disclosure - it is semantically meaningful and hygienically parenthesized - and
keep the equivalent collisions.c precedent.
#define LINE_OF_FIRE_PILL_SPHERE_RADIUS(pill) ((pill).width)
The function's own park entry named the reopening criterion as 'an attested or
owner-approved parenthesising spelling'. That criterion is now met, so the park
is removed; parks go 182 to 181, and the validator reports 181 active, 0 stale,
0 invalid.
The result is byte-identical to January over all 336 bytes including every
relocation addend and all padding - not merely normalized-equal - with 10/10
relocations at identical addresses and an identical 419-record symbol table.
Exactly one gate row moved across all 46 functions of ai.obj; the unit goes
43/3 to 44/2 and both survivors are pre-existing parks with unchanged tags. The
forbid-emitted-symbol guard exits 0 against a floor of 0, and fake_match_scan
reports the same 2 pre-existing #pragma findings before and after.
The comment now cites the first-party evidence for the naming that the original
packet missed: real_math.h:409 declares fast_vector_intersects_sphere's fourth
parameter as radius, while vector_intersects_pill3d's fifth at real_math.h:536
is pill_width. The asymmetric reading across the two arms is exactly the
asymmetry Bungie's own header draws.
parked.json was edited by line surgery, never re-serialized.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
2c9223514e |
Collapse _prop_get_active_by_unit_index from 7 real regions to 2 - ZERO bytes banked
The function does not close, so this banks zero bytes. It is landed as a fidelity improvement and because the resulting source is the more natural spelling. The whole 144-byte residual is a two-register swap - next_prop_index and prop->state are ECX/EDX in January and EDX/ECX in ours - plus its one consequence, that January can load _prop_data into EDX before pushing the index while we must push EDX before overwriting it. Size, relocations and instruction count were already equal; the gate row is [sha] alone. Fourteen shapes locate the lever precisely: read-count changes are inert and statement ORDER is the whole story. Moving the NONE test above the copy flips the colouring to January's ECX and takes the function from 7 REAL regions to 2. Scope, declaration order and three loop spellings are then all byte-identical, confirming the recorded law that declaration order is inert. What remains is one instruction: January speculates 'mov esi,ecx' into the flag-latency slot above the branch, we sink it into the call setup. The two REAL regions are the same instruction at its two positions. The bind is that assign-before-test puts the copy above the branch but colours EDX, while test-before-assign colours ECX and sinks the copy; no shape produced both, and the for-header carry that comes closest emits the increment twice for +16 bytes. Guards: no gate row moved anywhere in the unit, forbid-emitted-symbol exit 0 against a floor of 0, fake_match_scan 0 findings before and after, and the change is function-local in a single TU with no header touched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
edd8b386bb |
Wave D: two more EXACT, +1,671 meaningful bytes, 0 regressions
ai_debug _code_00039990 EXACT 848 ai_communication _ai_communication_get_player_rating EXACT 832 source/ai/ai_debug goes 58/60 to 59/60; source/ai/ai_communication 44/48 to 45/48. halobetacache 1,448,422 -> 1,450,093 (7,295 -> 7,297). Both land as DISCLOSED INFERRED constructs under the owner's standing rule - TU-private, descriptively named, carrying a comment that says plainly the shape is inferred from January's bytes and not attested, with the measurement table that forced it - and both reach STRICT EXACT, which the owner set as the bar. _code_00039990. The residual was one parenthesised group at a call argument. I did NOT land the proposer's bare `(point_height+0.15f)`: its adversarial verifier surveyed all 477 non-vendored .c files and found a whole-argument parenthesised SUM occurs ZERO times in the tree, and corrected the proposer's claim that it was "attested 11 times" - the cited ai_debug.c:1722-1724 sites parenthesise the OPERANDS and leave the top-level sum bare, which is the shape that does not match. Nine spellings reach exact; I took the one the owner's ruling names, a TU-private macro `ai_debug_attractor_label_height(height)`, which also gives the bare 0.15f a name it did not have. _ai_communication_get_player_rating. Binding the two real_point3d endpoints to named const pointers before the vector is taken fixes the order in which the compiler squares the components: an address-of expression and a pointer value are different operand forms here. CORRECTED BEFORE LANDING - the verifier found a real error in the comment text that would have shipped: its first row claimed the untouched spelling already squares k,i,j when it measures k,j,i, which would have told a future reader the change was unnecessary. Table fixed and re-verified EXACT. A park retired: _ai_communication_get_player_rating was parked `instruction-scheduling`. parked.json 183 -> 182, no other entry touched, never re-serialized. Guard note: `--forbid-emitted-symbol _point_from_line3d` exits 1 on ai_debug both BEFORE and AFTER this change - that file genuinely calls the helper, so the COMDAT is the known systemic extra-COMDAT gap and not a regression. On ai_communication it exits 0 before and after. Checked both ways rather than assumed. Verified: ninja exit 0; stable_verdicts gained 5 / 5,920 padded bytes with REGRESSIONS 0; parked 182 active / 0 stale / 0 invalid; audit 0 contradicted / 0 revoked; fake_match_scan 0 findings on both files; diff --check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
f1299316c8 |
Wave C part 2: the flagship and the two actor_moving rows, 0 regressions
Three more zero-credit fidelity landings. All three functions remain residual,
so this banks ZERO strict bytes.
ai_debug _ai_debug_render_actor (24,976 B, a third of the portfolio)
FOUR target-proven reconstruction defects plus the NULL-deref fix:
- a wrong constant, 1.6f where January pushes 1.f (immediate census
T14/O13 and T1/O2, the one surviving 1.6f at a site that matches)
- alignment_vector_3d built from control.current_fire_target_aim_vector
instead of output.animation.alignment_vector promoted to 3D with k=0
(+0x6ec is the impulse BOTH builds test, so +0x6f0/+0x6f4 is the 2D
alignment vector, and the local NAME corroborates it)
- p1 taken from control.desired_aiming_vector instead of burst_origin
(+0x64c burst_initial_position is lea'd by both builds for the
preceding line; +0x658 is the adjacent member. Plotting a unit
DIRECTION as a world point in a Burst Geometry block was just wrong)
- an if/else with an inner ternary that made VC7 cross-jump two copies
of the same five-argument render_debug_vector call; one call with a
nested ternary reproduces January three-arm colour block and REMOVES
a duplicated call from our source
frame sub esp 0x81c to 0x80c against January 0x810, i.e. +12 to -4;
relocations 1905 = target; regions 252 to 206; census 58/2 with the whole
per-function gate table byte-identical to pristine.
actor_moving _actor_move_update size 3120 to 3136 = target, relocation
TYPE sequence from about 20 mismatched rows to zero, byte-LCS unmatched
target bytes 455 to 232, regions 142 to 103.
actor_moving _actor_move_vector_avoidance hand-rolled cross-product math
replaced by the existing cross_product3d helper; regions 236 to 227.
TWO CORRECTIONS TO MY OWN RECORD, both from the adversarial verifiers:
1. I wrote that the four fixes make "the code length come back" so the section
is 24,976 again. It does not. January code ends at 0x5ffd with 12 bytes of
trailing pad; pristine and the landing end at 0x6009 with none. Both sections
are 24,976 only because January padding absorbs the difference, which is an
arithmetic coincidence and exactly the padding trap this lane keeps warning
about. The landing stands on the defect fixes and the region and instruction
evidence, NOT on the padded-size argument. Real code is still 12 bytes long.
2. The seed I wrote for that agent was wrong: "January has 31 dword slots and
the candidate has 30, diff the SETS". Both frames are DENSE, so a set diff
localises nothing; January simply has one more granule. The agent said so and
worked from invariant multiset censuses instead.
Verified: ninja exit 0; halobetacache 1,448,422 / 1,770,166 (7,295 / 7,574)
unchanged as expected; stable_verdicts REGRESSIONS 0; parked 183 / 0 / 0; the
--forbid-emitted-symbol _point_from_line3d guard exits 0; diff --check clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
694396011e |
Wave C part 1: three zero-credit fidelity landings, 0 regressions
All three functions remain residual, so this banks ZERO strict bytes. A
residual's padded size is its potential, not a realized gain, and the record
says so throughout.
ai_communication _ai_communication_event
restores a re-fetched actor_get(subject_actor_index) January has in the
_comm_look_direction_danger case. size 7856 -> 7888 (target 8064),
relocations 328 -> 330 (target 336). The identifier is not invented:
January's assert macro baked `subject_actor->danger_zone.object_index
!= NONE` into the object, so any other name swaps a string COMDAT.
actor_perception _prop_status_refresh
three boolean stores put in props.h declaration order (noncombat,
in_combat, fighting - we had fighting first), plus the owner-approved
macro at its squared-distance site. REAL regions 52 -> 4.
actor_perception _actor_perception_update
the owner-approved macro at its two remaining sites.
REAL regions 14 -> 2.
The _prop_status_refresh decode is the best mechanism work of the wave. A
register-blind structural diff (normalise every register name, then re-diff)
showed the instruction multiset identical in every cluster but one: January
`xor edx,edx; mov dx,[eax+0x182]` against our `movsx eax,[eax+0x182]`. That
single site was the whole deficit, and the renaming FORCES it - ours landed the
destination on EAX which also held the definition pointer, making
`xor eax,eax; mov ax,[eax+...]` impossible. Control: the sibling site in
_actor_perception_refresh_danger_zone compiles to `xor ecx,ecx; mov cx,[eax+0x182]`
in BOTH builds from identical source, proving it is not a type or cast issue.
Verified: ninja exit 0, halobetacache 1,448,422 / 1,770,166 (7,295 / 7,574)
unchanged as expected; stable_verdicts REGRESSIONS 0; parked 183 active / 0
stale / 0 invalid; the mandatory
`gate.py source/ai/actor_perception --forbid-emitted-symbol _point_from_line3d`
guard still exits 0; git diff --check clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
5186c5bd2a |
Land _actor_perception_refresh EXACT on the owner's ruling (+2,416 bytes)
OWNER RULING: "Land _actor_perception_refresh (+2,416) with a TU-private,
descriptively named inferred macro and documented evidence. Do not land
_ai_test_line_of_sight uninitialized read."
Both parts honoured. _ai_test_line_of_sight stays held and unlanded; its diff
and evidence remain in scratch only.
The macro is translation-unit private - a #define in the .c, no header touched -
named actor_perception_distance_squared to match its sibling
actor_perception_distance_squared2d already in the same macro block, and it
carries a comment that says plainly it is INFERRED FROM JANUARY'S BYTES and not
attested in any surviving source. The comment reproduces the measurement that
justifies it, with the rest of the function held constant:
prop->distance * prop->distance residual
(prop->distance) * (prop->distance) residual
(prop->distance * prop->distance) residual
bind a local first, (distance * distance) residual
((prop->distance) * (prop->distance)) EXACT
Only the canonical macro expansion reaches January. A hand-written expression
does not produce the doubly-parenthesised form; a correctly written macro
produces it inevitably, which is why the byte evidence is itself the argument
that a macro stood here. The second hunk - an explicit if/else giving that
else-if arm its own cross-jump resolution - carries its own comment recording
that the two are required jointly; I measured each alone and both are residual.
Verified: EXACT 2416, relocdiff `sha equal` with 0 differing rows, 86/86
relocations, unit census 35/9 -> 36/8, fake_match_scan 0 findings, no sibling
lost, comments did not shift any match_assert line literal.
Wave B totals after this landing:
halobetacache 1,448,422 / 1,770,166 (7,295 / 7,574)
overall 1,469,654 (7,562)
stable_verdicts gained 3, 4,240 padded bytes, REGRESSIONS 0
parked 183 active / 0 stale / 0 invalid
Net for the wave: +4,229 meaningful bytes, +3 functions, 0 regressions, one
whole object closed and one park retired.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
7e83d31bce |
Lane A wave B: two objects closer, one whole object closed
Ten residuals decoded in parallel, each on its own scratch copy, every proposed
landing re-measured by an adversarial verifier and a third time by the
orchestrator against the pristine tree. Targets were picked by the board
censuses added earlier this session.
EXACT, +1,817 meaningful bytes / +2 functions / 0 regressions:
source/ai/actor_firing_position _pre_evaluator_attack 1120 B
26/27 -> 27/27, THE WHOLE OBJECT CLOSES
source/ai/ai_debug _code_0003a910 704 B
57/60 -> 58/60
_pre_evaluator_attack was the +12 frame class, and the census called it: the
function homed twelve bytes more than January with [ebp-0x40] never referenced
at all - the elided-aggregate-member signature. The cause was a hand-expanded
library idiom, scale_vector3d + add_vectors3d + a real_vector3d temporary,
where January writes point_from_line3d in place. That spelling, casts included,
is verbatim real_math.c:2536 inside point_to_line_distance_squared3d, and the
change is a net deletion. Frames now agree at sub esp,0x34; relocdiff 39/39,
0 differing rows. The verifier confirmed the patched function's RAW bytes are
identical to January's, not merely equal under the normalized hash.
_code_0003a910 is target-proven: January emits ONE fdivr against 1.0f and THREE
fmul, so `scale = 1.0f/vertex_count` then three `*= scale` is its source, not a
rounding liberty; three `/=` divides would emit three fdivs. vehicle_stuck in
units/vehicles.c writes the same centroid the same way.
Landed at explicitly ZERO credit, because both functions remain residual and
both verifiers were emphatic that a residual's potential is not a realized
gain:
ai_debug _ai_debug_render_actor a real off-by-one CORRECTED
actor_perception _actor_perception_update an invented macro replaced by
real_math.h's genuine helper
The render_actor fix is a defect, not byte-steering: `switch (target_type-1)`
with case labels that are the enumerators and _actor_target_none == 0 dispatches
every type onto the previous colour and sends _actor_target_damaging_enemy into
the asserting default arm. January proves the compiler subtracts 1 itself
(`dec eax` where we emitted `add eax,-2`).
A park retired. _pre_evaluator_attack was parked `unclassified`; the frame
census contradicted that class and was right. parked.json 184 -> 183 entries,
no other entry touched, never re-serialized. First park retired by the census;
it says 35 more carry the same kind of evidence.
HELD, not landed, and both are deliberate:
_ai_test_line_of_sight drops an initialiser January lacks, which is
byte-proven, but lands an uninitialised read on a function that stays
residual - the same class as the owner's standing hold on
_actor_emotion_update's out-of-bounds read, and worth zero credit.
_actor_perception_refresh gates strictly EXACT at 2,416 bytes, the biggest
win this wave found, but needs a macro we would be inventing. A five-way
strip test shows ONLY the full canonical macro expansion ((a) * (a))
reaches January - four simpler spellings all stay residual - and neither
of its two hunks works alone. That cuts both ways and the ruling is the
owner's, not a lane orchestrator's. Full evidence in the wave report.
Negatives worth more than some landings: _encounter_create, 23 shapes, no
landing - its -4 frame is not a missing local but which pointer wins EBX, and
the previous wave's "spill slot" reading is refuted by `count` at [ebp-8].
_prop_get_active_by_unit_index, 60 gated builds mapping the entire reachable
image of a 144-byte function to three hashes, January's not among them - a
whole-function ECX/EDX two-colouring. Both agents also caught metric traps
where a shape matches January's instruction count by coincidence while
diverging earlier.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
8fd76228b9 |
Apply independent-review corrections to the ai_script BUG disclosure
The owner's ruling was to accept the 214-byte ai_script match only with a documented target-proven BUG and an independent review. The review returned CONFIRMED WITH CORRECTIONS; this commit lands every correction it required. Code (comment only, zero bytes changed): - Evidence now leads with January's 34-byte .rdata literal "%s: ai_migrate_and_speak %s %s %s". The 0x14 cleanup proves three VALUES; only the literal proves four CONVERSIONS, so the literal is the primary evidence and the cleanup is corroboration. - Struck "so no shipping configuration runs it". Both gate flags are exposed as the HaloScript external globals ai_print_migration / ai_print_scripting (source/hs/hs_globals_external.c:1468,1470) and are therefore settable at runtime by a scenario script or the debug console in the very build being matched. The disclosure now says the path is reachable. Documentation: - Removed the dangling "house rule 24" citation; docs/campaign_house_rules.md has 22 rules. The governing text is the original-bug policy in docs/matching_methodology.md, now cited directly with a correction note. - Withdrew the "always-executed paths" distinction from the two donors the owner previously excluded; reachability is not the owner's stated reason. - Recorded the review itself, including the two checks it added that the author had not made (the literal has exactly one relocation in the whole object; the 2020 cross-build defect verified first-hand at VA 0x00948864) and its finding that fake_match_scan cannot clear a variadic-arity case. - Manifest: split source_commit into per-row landing_commit and lane_tip_commit, which were previously conflated. Re-verified after the edit: EXACT 224, source/ai/ai_script 116/116, relocdiff sha equal with 0 differing rows, 16/16 relocations; full rebuild reproduces 1,444,193 / 1,770,166 (7,292 / 7,574); parks 184 active / 0 stale / 0 invalid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
3e44bc7829 |
Lane A wave A6 and closeout: house-rule 9 cleanup and deliverables
Zero strict bytes, zero regressions, zero exact credit.
ai_communication.c drops three consumer-local prototypes - game_team_is_enemy,
game_team_is_ally and game_allegiance_incident - that were hiding missing owner
declarations in a consumer C file. Wave A5 added the genuine owner header
game/game_allegiance.h, which declares all three at lines 23, 26 and 38; a /W3
compile reports no C4013, and the change is byte-inert with all 44 exact
siblings preserved.
Deliverables:
claude_lane_a_ai_core_HANDOFF_20260920.md - full handoff, including a
complete disposition table for all 35 owners totalling exactly 79,657
meaningful bytes, each with its live gate row and a concrete reopening
condition
claude_lane_a_ai_core_admission_manifest_20260920.json - machine-readable, every
measurement read live from build/split, build/base and the semantic ledger
at generation time; 1 exact row, 8 fuzzy rows at explicit zero credit,
0 regressions
claude_lane_a_ai_core_rejected_hypotheses_20260920.md - 18 numbered negatives
Final verification at this tip: halobetacache 1,444,193 / 1,770,166 (7,292 /
7,574); stable_verdicts diff vs the frozen baseline gained 1 / 224 bytes / 0
regressions (exit 0); accepted ledger +214 meaningful / 0 regressions; parks 184
active / 0 stale / 0 invalid; admission audit 19/0/8/0; tools tests 1,152 passed
/ 5 skipped / 26 subtests; source/ai fake scan 2 findings, both the inherited
ai.c pragma pair; no production file outside the 11-unit allowlist changed; no
header, comparator, target object or build tool changed; ai_debug's inherited
_point_from_line3d COMDAT is byte-identical to a rebuild from the baseline
source and the other ten units emit no copy; git diff --check clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
7356576d32 |
Lane A wave A5: restore the print_allegiance incident report
Zero strict bytes, zero regressions, zero exact credit. _ai_communication_event goes from 7776 to 7856 bytes against January 8064 (gap 288 -> 208) and from 319 to 328 relocations against 336 (gap 17 -> 8). All 44 exact siblings preserved. The first of January's two print_allegiance blocks is restored - a console_printf of "incident between teams %s and %s: %s, %s" with the two team names and the betrayal/accident and observed/unobserved selections - placed where January's bytes put it, after the betrayal/hostility resolution and before the if (observed) allegiance-incident call. It was identified by the same string-relocation audit that drove wave A3. ai_debug.print_allegiance is a real named field of the existing struct ai_debug_state. The change adds #include "game/game_allegiance.h", the genuine owner header of global_game_team_names - house rule 9 satisfied, not circumvented. No header was edited and no consumer-local prototype was written. January's second print_allegiance block calls game_allegiance_get_incidents, which is declared in no header in the tree; that half stays a deferred header prerequisite for source/game/game_allegiance.h and was not attempted. Verification: build unchanged at 1,444,193/1,770,166 (7,292/7,574); stable_verdicts diff vs the frozen baseline gained 1 / 224 bytes / 0 regressions; parks 184/0/0 (this function is not parked); admission 19/0/8/0; fake scan 0 findings in the changed file; git diff --check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e99467da09 |
Lane A wave A4: actor_move_update structural corrections
Zero strict bytes, zero regressions, zero exact credit. _actor_move_update goes from 3088 to 3120 bytes against January 3136 (size gap 48 -> 16) and from 869 to 882 instructions against 888 (gap 19 -> 6). Three changes, each read off January: the initialized-declaration order that the twelve-store prologue emits; the moving_into_fire_timer branch polarity with its arms swapped; and normalize3d(...) != 0.f in place of > 0.f. Two shapes from the worker candidate were rejected and the rejection improved the result. (1) Hand-expanding actor_move_transform_avoidance_vector at two call sites is manual inlining of an ordinary helper, forbidden by house rule 13 and named explicitly on this unit's do-not-repeat list; its measurements are kept as evidence (it does fix test_avoidance_vector's relocation count, 17 -> 16, and shrinks that size gap 208 -> 16, but overshoots). (2) Rewriting TEST_FLAG(flags, crouch ? A : B) as (crouch && TEST_FLAG(A)) || (!crouch && TEST_FLAG(B)) was measured and dropped: restoring the natural ternary gives 3120 bytes where the verbose form gives 3104, so the concise source is also the closer one. Verification: build unchanged at 1,444,193/1,770,166 (7,292/7,574); stable_verdicts diff vs the frozen baseline gained 1 / 224 bytes / 0 regressions; parks 184/0/0 (actor_moving has none); admission 19/0/8/0; fake scan 0 findings in the changed file; point guard passes; git diff --check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4fa32b2c80 |
Lane A wave A3: restore the missing communication diagnostic graph
Zero strict bytes, zero regressions; the largest structural recovery in the lane. _ai_communication_finished goes from 912 bytes / 29 relocations / 305 instructions to 1568 / 86 / 482 against January 1584 / 87 / 484, and objdiff from 42.12 to 91.44 percent. The remaining gap is 16 bytes and ONE relocation, down from 672 bytes and 58 relocations. All 44 exact siblings preserved. Found by a per-function string-literal relocation diff over all 34 Lane A residuals: this function references zero string literals where January references sixteen, no Lane A unit emits a string absent from the January image, and 32 of 34 residuals have exactly matching string sets. January .rdata supplied the exact texts, the prologue supplied the 0x650 frame and the [ebp-0x450] message buffer, and the call sites supplied the asymmetric sprintf-then-csstrcat idiom. Every debug guard resolved to a real named field of the existing struct ai_debug_state, so no new type, header, name or declaration was needed. Also lands ai_debug.c:2281 "has_approach_point>0" -> "has_approach_point" (the field is a boolean); section size stays at January exact 24976 and differing regions go 1452 -> 1451. Rejected from the same candidate: writing the ai_communication_event is-reply player_rating as a 2.0f literal moves relocations 319 -> 318 against 336 and instructions 2280 -> 2278 against 2353, i.e. structurally away on both counts. The rejected-hypotheses file had recorded that probe as never compiled; it is now compiled and negative. config/parked.json: one entry re-baselined with refreshed measurements and a new reopening condition. No park retired, none unrelated touched. Verification: build unchanged at 1,444,193/1,770,166 (7,292/7,574); stable_verdicts diff vs the frozen baseline gained 1 / 224 bytes / 0 regressions; parks 184/0/0; admission 19/0/8/0; fake scan 0 findings in the changed files; point guard passes; git diff --check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
8110e554dc |
Lane A wave A2: three zero-credit source corrections
No new strict bytes and no regressions. All three changes are source-authenticity corrections retained at zero exact credit. actor_firing_position/_pre_evaluator_attack recovers the MISSING RELOCATION (38 -> 39, matching January), differing relocation rows 24 -> 9, objdiff 93.62 -> 96.11. Four byte-decided levers: 20.0f * (d / 2.0f) stops VC7 folding 0.5f*20.0f into 10.0f; two initializers become statements because the zero store sits on the opposite side of call _actor_get_weapon_definition and a stack store cannot be sunk across a call; an explicit strict < replaces MIN(), which expands to ((a)>(b)?(b):(a)) and can only emit test ah,0x41 where January emits test ah,5. ai/_ai_test_ballistic_line_of_fire rebuilds the recorded w3c b5 shape: instruction counts become 296/296 (were 292/296), real differing regions 28 -> 11, objdiff 94.5 -> 98.996. It reproduces January's fsubr / fst-to-dead-parameter-home / post-call fld structure for segment_time exactly. ai/_ai_test_line_of_fire lands only the store-order half of the old lof2 candidate; the rejected bare call-site parentheses are NOT landed and that prior ruling stands. objdiff 88.17 -> 89.20. actors.c drops three "= NULL" initializers that were forcing a 12-byte .bss January does not have. January defines all three in linker_common.obj and references them as undefined, i.e. the original used tentative definitions. These were the only "struct data_array *x = NULL;" definitions in the whole tree; the sibling encounters.c already uses the tentative form. .bss is now absent and the three symbols are COMMON, matching January. config/parked.json: three entries re-baselined (measurements refreshed, evidence extended with the lever and a reopening condition), none retired, none unrelated touched. Parks remain 184 active / 0 stale / 0 invalid. Verification: full ninja build unchanged at 1,444,193/1,770,166 (7,292/7,574); stable_verdicts diff vs the frozen baseline gained 1 / 224 bytes / 0 regressions; accepted ledger +214 meaningful / 0 regressions; admission audit 19/0/8/0; fake scan 0 new findings (source/ai stays at the 2 inherited pragma leads); point guard passes on all three units; git diff --check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
9eca0524de |
Close ai_script.obj at 116/116 (+214 meaningful bytes)
_ai_scripting_migrate_and_speak becomes strict exact: 224/224 padded bytes, 16/16 relocations, relocdiff reports sha equal and zero differing rows. January's call site cleans 0x14 bytes (five dwords) and loads speech_type only afterwards at +0x7d, while the format literal read out of January's .rdata is "%s: ai_migrate_and_speak %s %s %s" - four %s conversions for three values. Our source was passing speech_type as a fourth value and cleaning 0x18. Landed under the original-bug policy with a BUG (preserved for exact matching) comment that records the evidence, the runtime consequence (the fourth conversion's slot is the saved-EDI home, so vsprintf dereferences the caller's entry EDI as a char *) and the corrected form. The branch is reachable only under ai_debug.print_migration / print_scripting. Flagged for owner ratification in the wave report; reverting is a single token. Verification: full ninja build 1,444,193/1,770,166 Halo bytes (7,292/7,574 functions); stable_verdicts diff gained 1 / 224 bytes / 0 regressions; accepted ledger +214 meaningful / 0 regressions; parks 184 active / 0 stale / 0 invalid; admission audit 19/0/8/0; fake scan 0 findings in the changed file and the same 2 inherited findings across source/ai; git diff --check clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
6130661c95 | Reconcile final Astra campaign (+4073 bytes) | ||
|
|
5361eeae52 |
Reconcile Astra exact-match campaign (+8314 bytes)
Integrate six accepted exact functions, two whole-object admissions, evidence-backed zero-credit source corrections, owner-header cleanup, and curated campaign records. Preserve zero regressions and exclude generated scratch archives from canonical history. |
||
|
|
37d513310b | Reconcile evidence-backed 10K exact batch | ||
|
|
9d155f1d60 | Admit ten verified exact objects | ||
|
|
389126d5a7 | Reconcile Claude two-block exact-match campaign | ||
|
|
9b6ad2c75b |
Wave 21: _structure_visibility_traverse_surface_lists strict exact (park reopen)
- surface_index_buffer is declared before the frustum selection (January loads the index buffer before the pvs test) - material looked up through nested typed tag-block gets; the buffer walk skips the two index words and post-increments through the count, matching January's two separate pointer advances - block-scoped vertex0/1/2 pointers read the compressed vertex data per surface, matching January's left-to-right index loads before the call Wave 21 (3 bundle implementers + 1 reviewer, 14 TUs, 22,880 target bytes) closed only this function. Stable diff vs wave 20: 1 gained, 0 regressions; active parks 191 -> 190. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |