mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-27 12:00:34 +01:00
Complete game_engine title string body (zero credit) and record wave w3c batch 1
_game_engine_generate_title_string was structurally incomplete (1088/70 against January's 1152/73) and skipped January's common null-termination tail on an unrecognised win result. The rewritten single-exit body reaches January's size, relocation count and frame layout with two team-name wchar_t[8] buffers instead of the union spelling, and 391/391 instructions with one transposed push. It is still [sha] residual, so it carries ZERO byte credit; the reopen criterion is in the ledger. Wave w3c batch 1 (8 groups, 36,384 spendable padded bytes) landed no strict exact function. The per-object ledgers record the measured blockers, the rejected _bitmap_2d_smooth reopen (it loses the exact _bitmap_2d_uncompress_from_mipmap row) and the proposals raised. Full ninja, parks 280/0/0, stable diff vs scratch/claude250k-start.json: gained 0, regressions 0; fake scan 0 leads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0483bde89e
commit
aa2ada3f52
10 files changed
+1388
-101
No files matched your search
@@ -0,0 +1,167 @@
|
||||
# `actor_combat.obj`: second pass (opus5 250K lane, wave w3c, 2026-09-15)
|
||||
|
||||
## Scope and provenance
|
||||
|
||||
- Lane `opus/250k-house-clean-20260915`, HEAD `0483bde89`, worktree
|
||||
`C:\halo-worktrees\opus5-150k-house-clean-20260914`. Worker `w3c:actor_combat`; the only file this worker
|
||||
could modify is `source/ai/actor_combat.c`. **It is unchanged** (`git diff --stat -- source/ai/actor_combat.c`
|
||||
is empty). No header, config, build or tool file was touched.
|
||||
- Target: `build/split/source/ai/actor_combat.obj`. Compiler XDK VC7 13.00.9254, repository flags via
|
||||
`tools/campaign/gate.py`.
|
||||
- Worker notes with the per-function report blocks: `scratch/workers/w3c_actor_combat.md`.
|
||||
Scratch candidates and objects: `scratch/workers/w3c_actor_combat/` (`g1-g4`, `p1-p6`, `r1-r3`, `score.py`).
|
||||
- Evidence used: January target COFF (disassembly, relocations, per-function relocation census),
|
||||
HCEA `halocea-review/src/blam/ai/actor_aim_grenade.c` (semantics/topology only), `scratch/atlas/actor_combat.obj.txt`,
|
||||
`config/parked.json`, and the prior ledgers listed in the notes file.
|
||||
- Laws applied as detectors: WORKER_BRIEF 9, `scratch/w2/laws_w2.md` (A4, A5, A6, A11, A20, A24 precursor,
|
||||
A30 in w3), `scratch/w3/laws_w3.md` (A24, A30, A31, A35, R13, R16, E18).
|
||||
|
||||
## Baseline and final (real file)
|
||||
|
||||
`python -B tools/campaign/gate.py source/ai/actor_combat --all --forbid-emitted-symbol _point_from_line3d`
|
||||
|
||||
| | result |
|
||||
| --- | --- |
|
||||
| baseline | `== exact 28 residual 6 unwritten 0 (of 34)`; guard passed; parkcheck `parks 4 drift 0` |
|
||||
| final (real file, unchanged) | identical listing; guard passed; parks 4/4 undrifted; `tools/fake_match_scan.py` 0 leads |
|
||||
|
||||
No row is newly exact. Nothing landed; this wave produced evidence, a refined reopen criterion for two parks,
|
||||
and one owner-ruling request.
|
||||
|
||||
## Per-function outcomes
|
||||
|
||||
| function | January padded / relocs | state | outcome |
|
||||
| --- | --- | --- | --- |
|
||||
| `_actor_aim_grenade` | 544 / 22 (ours 576) | residual `[size]` | NOT-LANDED; 4 shapes; g4 closes the output block, frame + facing-address CSE remain; owner ruling requested |
|
||||
| `_actor_combat_plan_grenade_trajectory` | 288 / 5 | PARK | scratch-only; **A24 confirmed**: 18 hunks -> 6, frame 0x34 -> 0x30 exact; not exact, no reopen |
|
||||
| `_actor_combat_reaim_grenade` | 448 / 16 | PARK | scratch-only; 3 shapes, all byte-identical; no reopen |
|
||||
| `_actor_aim_projectile` | 720 / 27 | PARK | SKIPPED-EXHAUSTED (2-instruction copy-pipelining tie; shared with plan) |
|
||||
| `_actor_combat_find_nearby_target` | 352 / 12 | PARK | SKIPPED-EXHAUSTED (x87 last-use fold; new counter-example found, no lever) |
|
||||
| `_actor_start_burst` | 1968 / 67 | residual `[sha]` | SKIPPED-EXHAUSTED (14 spellings across 3 lanes; w1 reopen criterion unmet) |
|
||||
|
||||
## `_actor_aim_grenade` (the only non-parked structural row)
|
||||
|
||||
Three independent facts now explain the 32-byte gap.
|
||||
|
||||
1. **Aim-speed x87 CSE — solved.** January loads `actor->control.grenade_current_aim_speed` once
|
||||
(`fld [edi+0x6c8]`) and spends it as `fmul st(1)` twice plus a folded `fmul [aim_vector.k]`. Our source
|
||||
multiplied each component by the field, reloading the 6-byte operand three times. Candidate `g4`
|
||||
(`real aim_speed = actor->control.grenade_current_aim_speed;` then `aim_speed*aim_vector.i/j/k`, matching
|
||||
HCEA's `throw_speed`) reproduces January's final block instruction for instruction and takes the differing
|
||||
target lines from 78 to 73. It cannot land alone (a written residual lands only when strict EXACT).
|
||||
2. **Facing-vector address CSE — open.** January materialises `lea ecx,[edi+0x174]` and reads the facing vector
|
||||
as `[ecx]` / `[ecx+4]` in the 2D dot and the 2D cross, then `mov edx,ecx` for the 12-byte
|
||||
`new_aim_vector` copy. Ours emits seven 6-byte `[edi+0x174..0x17c]` operands. A block-local
|
||||
`real_vector3d const *facing_vector` (g1) and a genuine inlined `cross_product2d` call with the admitted
|
||||
`(real_vector2d const *)` cast (g2) are both byte-identical to the current file: VC7 constant-folds the
|
||||
field address in every spelling we can write, so the register form has some other cause.
|
||||
3. **Frame 0x24 vs 0x28.** January shares `[-0x24..-0x19]` between `desired_grenade_target` and `aim_vector`,
|
||||
and packs the `(counterclockwise ? 1 : -1)` fild temp into the dead `aim_vector2d.j` cell `[-8]`. Ours gives
|
||||
the fild temp its own cell and hands the dead retarget-point cells to `new_aim_vector` instead.
|
||||
|
||||
HCEA's lift of the same function uses ONE working triple (`direction_x/y/z`): assigned from the retarget point
|
||||
in the prop branch, overwritten by the refreshed aim vector on the on-foot path, and multiplied by the throw
|
||||
speed at the end. That is precisely January's shared `[-0x24..-0x19]` words, and it also explains the
|
||||
vehicle-plus-retarget behaviour recorded by `actor_combat_obj_grenade_vehicle_semantic_withdrawal_20260905.md`.
|
||||
|
||||
**I did not build that arrangement.** The 20260905 audit records an explicit hold ("Do not restore the
|
||||
point/vector cast or equivalent explicit position-as-velocity carrier"), and laws_w3 R13 makes older holds
|
||||
binding on later waves.
|
||||
|
||||
### Owner ruling asked for (no header/config text)
|
||||
|
||||
Rule on whether `_actor_aim_grenade` may use a single working direction vector — the variable that receives
|
||||
the prop body position (+0.2 z) for the retarget call and is then overwritten by
|
||||
`actor->control.grenade_current_aim_vector` on the on-foot path — spelled with the already-admitted
|
||||
`(real_point3d const *)` / `(real_vector3d *)` cast at the retarget call and a
|
||||
`/* BUG (preserved for exact matching): ... */` note for the vehicle path (where January, like the current
|
||||
tree, reads the working words without writing them when no retarget happened).
|
||||
|
||||
- For: HCEA's independent lift has exactly this shape; it is the only hypothesis that explains January's frame
|
||||
without an allocator coincidence; the current tree *already* contains the same uninitialised-read path, so
|
||||
the ruling does not add undefined behaviour, it only changes which variable carries the value.
|
||||
- Against: brief section 5 forbids representation punning, and the 20260905 audit withheld semantic acceptance
|
||||
pending a release-time `vehicle_index == NONE` lifecycle proof.
|
||||
- If allowed: replay g4's `aim_speed` local on top and re-gate; expect the frame to close to 0x24, leaving only
|
||||
the facing-address CSE (item 2) to adjudicate. 544 padded bytes are at stake.
|
||||
|
||||
## `_actor_combat_plan_grenade_trajectory`: A24 confirmed on a pointer parameter
|
||||
|
||||
The park is recorded as `register-allocation` with the criterion "authoritative source or a natural
|
||||
same-compiler stack-lifetime donor". The w3 law A24 (parameter-home offer) is exactly such a donor and it
|
||||
fires here: January's `&aim_gravity` is `lea edx,[ebp+0x10]`, the incoming home of the `grenade_target`
|
||||
pointer parameter, which is enregistered into EDI on the entry path; ours allocates a seventh cell
|
||||
(frame 0x34) and shifts every local by 4.
|
||||
|
||||
| shape | result |
|
||||
| --- | --- |
|
||||
| `p1` aim_gravity declared first among the scalars | byte-identical (18 hunks / 20 lines) |
|
||||
| `p2` declarations in the callee's out-parameter order | byte-identical |
|
||||
| `p3` nested `if`s instead of the `&&` chain | byte-identical |
|
||||
| **`p4` entry copy `real_point3d const *grenade_target_position = grenade_target;` (2 genuine uses)** | **frame 0x30, all slots match, 18 hunks -> 6, 20 -> 5 lines; 288/5 sha `7454798a13f3419b`** |
|
||||
| `p5` p4 + the ignore-index store moved after the aim-vector assignment | same 6/5 (store order between fields of one base is canonicalised) |
|
||||
| `p6` p4 + declaration-order store block | worse (8/6/6) |
|
||||
|
||||
What remains under p4 is a 12-byte-copy scheduling tie: January loads `aim_vector.i` and `.j` before the first
|
||||
store, interleaves the `grenade_current_ignore_object_index` store between `.i` and `.j`, and sinks the `.k`
|
||||
store past the speed and lob stores. Store-order permutations are measured inert, so no source statement order
|
||||
reproduces it.
|
||||
|
||||
Not proposed as a reopen: p4 is not strict exact, and a bare pointer rename of a parameter is R16-adjacent
|
||||
(A24's landed precedent `real v_max = base_velocity;` had a semantic role that this alias lacks). The park stays
|
||||
locked and undrifted.
|
||||
|
||||
**Refined reopen criterion** (for `config/parked.json` if the orchestrator wants it recorded): the frame half
|
||||
is solved by an A24 parameter-home copy; the remaining blocker is VC7's load-ahead pipelining of a 12-byte
|
||||
struct copy, which is *the same* tie as the whole residual of `_actor_aim_projectile`. One donor closes both
|
||||
(288 + 720 = 1,008 padded bytes).
|
||||
|
||||
## `_actor_combat_reaim_grenade`
|
||||
|
||||
January's frame 0x2c packs `aim_gravity` into the dead `aim_vector2d.j` cell `[ebp-0xc]`; ours (0x30) gives it
|
||||
its own cell and additionally ranks `aim_ticks` above `aim_vector2d` where January's ranking follows the
|
||||
refs/size rule. Three scope/declaration shapes were measured, all byte-identical to the park body:
|
||||
`r1` (declare `aim_vector2d` inside the `projectile_aim` block — laws_w2 A6 nested-block packing side law),
|
||||
`r2` (hoist `aim_velocity`/`aim_gravity` to function scope), `r3` (swap the inner declaration order). With w1's
|
||||
`g1` (gravity as the `?:` argument temp) that is four inert probes; the packing decision has no source lever we
|
||||
can find. Park unchanged, criterion unchanged.
|
||||
|
||||
## `_actor_aim_projectile` and `_actor_combat_find_nearby_target`
|
||||
|
||||
- `aim_projectile`: 6 hunks / 5 lines, all of it the two transposed instructions of the
|
||||
`actor_debug_info->field_98 = weapon_vector;` copy (January hoists the `.j` load above the `lea` and sinks the
|
||||
`.j` store past the `field_88` byte store). The park already spent the statement-order matrix; no w2/w3 law
|
||||
fires (A20 is satisfied, A31(c) needs a parameter-based base). Same behaviour as the plan residual above.
|
||||
- `find_nearby_target`: unchanged 2-instruction x87 tie (January keeps `distance` live to an explicit
|
||||
`fstp st(0)`; VC7 folds the last use). New context: the *inverse* of this decision appears in
|
||||
`_actor_aim_grenade`'s magnitude block (January folds, ours pops), so operand order does not control the
|
||||
fold; both spellings exist in this one object with opposite outcomes. No shape spent.
|
||||
|
||||
## `_actor_start_burst`
|
||||
|
||||
Skipped as exhausted: 5 shapes in w1, 9 in the 100K lane and the PDB lane's flips/scoping/`*=` matrix are all
|
||||
on do-not-repeat lists, and the recorded reopen criterion (a spelling that spills `limit*1.5f` to memory before
|
||||
the compare yet still sources the origin-radius store from the x87) is not produced by any w2/w3 law. The
|
||||
"write the capped expression twice" idea is already the shape in the tree.
|
||||
|
||||
## Hygiene observation (not landed; laws_w3 E18)
|
||||
|
||||
`g2` removes the per-TU `#define cross_product2d cross_product2d_inline` rename *and* the hand-written TU-local
|
||||
`cross_product2d` definition, calling the genuine `real_math.h` helper at the one site whose expression is a 2D
|
||||
cross product (`_actor_aim_grenade`'s `counterclockwise`). All 34 rows stay byte-identical, `_cross_product2d`
|
||||
stays EXACT (now as the header's select-any COMDAT), and the A30 rename defect disappears. Evidence that
|
||||
January's source really called the helper there: `_cross_product2d` is an owner of January's object
|
||||
(file offset 0000F9B0) with **zero** call relocations anywhere in the object — a non-static `__inline` emits its
|
||||
surplus COMDAT only when it is used, so the call site exists and VC7 inlined it. Not landed because brief
|
||||
section 8 requires an empty file diff in a unit where nothing lands; the orchestrator can take it as a
|
||||
hygiene hunk. Caveat: it moves the COMDAT's section position earlier in the object (section 8 vs 39; January
|
||||
has it at 15, adjacent to the trig wrappers and `_add_vectors3d`, which matches the current TU-local position).
|
||||
|
||||
## Reopen criteria (summary)
|
||||
|
||||
- `_actor_aim_grenade`: owner ruling on the single working direction vector (then replay `g4`), or a donor for
|
||||
VC7's struct-field address CSE (`lea` + `[reg]` operands) without a helper call.
|
||||
- `_actor_combat_plan_grenade_trajectory` / `_actor_aim_projectile`: a donor for VC7's load-ahead pipelining of
|
||||
a 12-byte struct copy. The plan frame is solved by an A24 parameter-home copy (`p4`).
|
||||
- `_actor_combat_reaim_grenade`: a donor that packs a scalar local into the dead half of an in-scope aggregate.
|
||||
- `_actor_combat_find_nearby_target`, `_actor_start_burst`: unchanged.
|
||||
@@ -0,0 +1,156 @@
|
||||
# `bitmap_utilities.obj` second pass — opus5 250K lane, wave w3c (2026-09-15)
|
||||
|
||||
## Result
|
||||
|
||||
The real file `source/bitmaps/bitmap_utilities.c` is **unchanged** (`git diff --stat` empty). Final real-file gate is
|
||||
identical to baseline: `== exact 43 residual 5 unwritten 0`, `_point_from_line3d` guard passes, park drift 0,
|
||||
owner census identical to `build/base`, fake scan 0 leads.
|
||||
|
||||
The wave produced one **strict-exact scratch body** and one **strictly-closer scratch body**, both blocked from
|
||||
landing by a single sibling regression, plus a new measured VC7 law and a TU-context diagnosis.
|
||||
|
||||
| Function | Padded | Baseline | This wave (scratch) | Status |
|
||||
| --- | ---: | --- | --- | --- |
|
||||
| `_bitmap_2d_smooth` | 1136 | 1120/27 `50140a12` (park) | **1136/27 `90b74220` = target, strict EXACT** | reopen proposed, BLOCKED |
|
||||
| `_bitmap_3d_smooth` | 1824 | 1792/28 `dc74abcc` (park) | 1824/28 `f8881250`, 608 of 610 instructions identical | strictly-closer re-baseline |
|
||||
| `_bitmap_2d_alpha_bleed` | 560 | 560/24, 1 reload transposition | 5 shapes, all byte-identical or worse | tie budget spent |
|
||||
| `_bitmap_2d_sharpen` | 1152 | 1184/29, 47 hunks | no shape spent; 4 new byte facts recorded | keystone, criterion unmet |
|
||||
| `_bitmap_sharpen` | 352 | 352/23, normalized sha **equal** | none possible | tooling/owner |
|
||||
|
||||
Scratch candidates: `scratch/workers/w3c_bitmap_utilities/` (`m4.c` = 2d_smooth reopen only; `m7.c` = + 3d_smooth;
|
||||
`m10.c` = m7 + the 16-site assert-cast authenticity fix; `h1.c` = HEAD + that fix alone).
|
||||
Worker notes with every shape and measurement: `scratch/workers/w3c_bitmap_utilities.md`.
|
||||
|
||||
## Baseline and duplicate prevention
|
||||
|
||||
Baseline rows (January padded / tags): `_bitmap_2d_alpha_bleed` 560 [sha]; `_bitmap_2d_sharpen` 1152
|
||||
[size 1184!=1152, sha]; `_bitmap_2d_smooth` 1136 [size 1120!=1136, sha]; `_bitmap_3d_smooth` 1824
|
||||
[size 1792!=1824, sha]; `_bitmap_sharpen` 352 [reloc-identity]. All five are parked; parkcheck drift 0 at baseline.
|
||||
|
||||
Read first: all eight `bitmap_utilities_obj_*` ledgers (w1 150K, smooth/sharpen completion, selective donor
|
||||
reconciliation, the four jonas ledgers), the w1 worker notes `scratch/workers/bitmap_utilities.md` with its
|
||||
do-not-repeat list, the 150K checkpoint, `scratch/w2/laws_w2.md` (A1-A22, R1-R12) and `scratch/w3/laws_w3.md`
|
||||
(A23-A45, R13-R19). `git log --all --oneline -- source/bitmaps/bitmap_utilities.c`: 13 commits, none newer than the
|
||||
w1 landing; w1's `branch_sweep.py` found no blob better than current. The three functions w1 reopened
|
||||
(`_bitmap_2d_shrink`, `_bitmap_3d_shrink`, `_bitmap_2d_uncompress_from_mipmap`) are inherited exact and are not
|
||||
re-claimed here. No C4013/C4133 site exists in this unit (`scratch/gate4/c4013.txt`).
|
||||
|
||||
## New law: NAMED-TEMPORARY NORMALIZER (refines laws_w2 A12 / A5; answers the w1 reopen criterion)
|
||||
|
||||
**Law.** For a loop-invariant round-and-shift normalisation `(sum + (1 << (2*n - 1))) >> (2*n)`, VC7 assigns the
|
||||
registers and the two spill slots from the *expression structure*, not from the declaration:
|
||||
|
||||
- written as **one expression** (the natural spelling, repeated per channel or through a function-like macro), the
|
||||
`2*n` CSE is created first and stays in its own register in place — January's
|
||||
`movsx eax,di; add eax,eax` ... `mov esi,1; shl esi,cl`, slots shift `-0x24`, rounding `-0x28`;
|
||||
- written as **two named `long` locals** (`shift = 2*n; rounding = 1 << (2*n - 1);`), the doubling is moved out with
|
||||
`lea esi,[eax+eax]` and the `1 <<` temp takes EAX — registers **and** slots swapped, whatever the order of the
|
||||
declarations or of the assignments.
|
||||
|
||||
**Controls measured this wave.** Declaration-order swap `long rounding, shift;` vs `long shift, rounding;` is
|
||||
byte-identical (m1 vs m2), so *the slot follows the register, not the declaration*; the macro form alone on the
|
||||
otherwise unchanged parked body already flips the preheader to January's exact register/slot assignment (m3), which
|
||||
isolates the lever from the rest of the restructuring. w1's measured negatives stand and are explained by the law:
|
||||
`rounding = 1 << (shift - 1)` and "no rounding variable" both fall back to 1120 because they still name a normaliser.
|
||||
|
||||
**Co-factors, each proven necessary** (removing either loses exactness): one `short x, y;` shared by both passes,
|
||||
declared at the `if (width >= filter_size && height >= filter_size)` block (m5 = 1136 [sha]); and the coefficient
|
||||
read placed **after** the pixel load inside the tap loop (m6 = 1136 [sha]). Both were already evidenced by w1.
|
||||
|
||||
**Closures.** `_bitmap_2d_smooth` 1136/27, `alndiff` 376/376 instructions with zero non-artifact hunks.
|
||||
The same three-part treatment of `_bitmap_3d_smooth` takes it from 1792/28 with 49 diff blocks to 1824/28 (January's
|
||||
size and relocation count) with `alndiff` 610/610 and only two hunks.
|
||||
|
||||
## The blocker: a TU-context coin, and the 16 casts that currently buy an exact row
|
||||
|
||||
Every exact spelling of `_bitmap_2d_smooth` removes five declarators from the function, and that flips
|
||||
`_bitmap_2d_uncompress_from_mipmap` (880, EXACT at baseline, **not** parked) to residual. Measured in five contexts
|
||||
(m4, m7, m10, p1, p2), and the flip also occurs when only `_bitmap_3d_smooth` is reopened (m8). No spelling of
|
||||
uncompress recovers it: u1-u4 permute every declaration order/grouping of its locals and are byte-identical.
|
||||
|
||||
Four rows of this object differ from January by **nothing except the order of two independent register reloads at a
|
||||
join**, and in each case ours is the exact reverse of January:
|
||||
|
||||
| function | site | January | ours |
|
||||
| --- | --- | --- | --- |
|
||||
| `_bitmap_2d_alpha_bleed` | +0x191 | `ecx=[ebp-0x10]` (x), `eax=[ebp-0x20]` (x*4) | reversed |
|
||||
| `_bitmap_2d_uncompress_from_mipmap` | +0x33a | `edi=[ebp-0x24]` (height), `ebx=[ebp+0x10]` (mipmap index) | reversed |
|
||||
| `_bitmap_3d_smooth` (m7) | +0x522 | `edx=[ebp-0x40]` (-filter_size), `esi=[ebp-8]` (rounding) | reversed |
|
||||
| `_bitmap_3d_smooth` (m7) | +0x601 | `esi=[ebp-8]` (rounding), `eax=[ebp-0x20]` (shift) | reversed |
|
||||
|
||||
Nine body-local shapes across three functions (alpha_bleed a1-a3/a5, uncompress u1-u4, 3d_smooth n2-n3) were
|
||||
byte-identical: there is no body lever. The coin is set by TU-wide text — w1's definition-order reorder flipped
|
||||
uncompress on; the 2d_smooth reopen, the 3d_smooth reopen, an unrelated alpha_bleed probe (a4) and the assert-cast
|
||||
authenticity fix each flip it off.
|
||||
|
||||
**Critically, HEAD's uncompress exact row is bought with text January's own assert literals refute.** Sixteen
|
||||
`match_vassert(file, line, <expr containing a no-op `(short)` cast>, "<same expr without the cast>")` sites exist in
|
||||
this TU; the literal is January's stringised original, so January's source had no cast. Candidate `h1.c` = HEAD with
|
||||
those sixteen sites rewritten as `match_assert(file, line, <expr without the cast>)` — nothing else changed — is
|
||||
`42 exact / 6 residual` with park drift 0: the only row that moves is `_bitmap_2d_uncompress_from_mipmap`. So the
|
||||
880-byte exact row at HEAD depends on sixteen reconstruction artifacts, and any authentic cleanup of this TU costs it.
|
||||
|
||||
**Emission-order evidence for the underlying gap.** The candidate's code-section order still differs from January's.
|
||||
January defers `_bitmap_2d_height_map`, `_bitmap_3d_height_map` and all three `*_vector_map` statics past the colour
|
||||
conversions and emits `_rgb_colors_interpolate`/`_and_scale` next to last; our object emits every static in plain
|
||||
source order. The deferred set is exactly the two statics that call the `real_math.h` helpers (`cross_product3d`,
|
||||
`normalize3d`, `fast_ftol`) plus their transitive same-TU callers — `_bitmap_cm_height_map`, which calls none of
|
||||
them, is not deferred — and our object additionally **defines** the eight select-any COMDATs
|
||||
(`_fast_ftol, _square_root, _scale_vector3d, _magnitude_squared3d, _magnitude3d, _normalize3d, _cross_product3d,
|
||||
_valid_real`) that January references undefined. That is the header-inline linkage property (laws_w3 A30/A41 and the
|
||||
header-inline-linkage law), which a worker cannot change from this `.c`.
|
||||
|
||||
## `_bitmap_2d_sharpen`: new byte facts (no shape spent)
|
||||
|
||||
The w1 reopen criterion ("evidence for why January keeps `temporary_pixels` out of EDI") is still unmet, and no law
|
||||
in laws_w2/laws_w3 predicts which pointer wins a callee-saved register (A24 does not fire: no January temporary sits
|
||||
in a parameter home here). Four facts were recovered for the next attempt:
|
||||
|
||||
1. January's prologue is `push ebx; mov ebx,[ebp+8]` and it shrink-wraps `push edi` to `+0xf1` inside the
|
||||
allocation-success block: **`bitmap` owns EBX from entry, EDI is the `y`/`byte_index` web, and
|
||||
`temporary_pixels` is never enregistered** (`mov [ebp-0x24],eax` at `+0xe4`, reloaded at `+0x158`). Ours is the
|
||||
mirror image (`push edi; mov edi,[ebp+8]`, `mov ebx,eax` for `temporary_pixels`, `push ebx` at `+0xc4`).
|
||||
2. The private ABI passes `negative_table` in ESI (`+0x87 test esi,esi`, ESI never pushed); both builds agree.
|
||||
3. Loops 2 and 3 run as down-counters over `previous_row + byte_index` with `[ebp-0x28] = destination_row -
|
||||
previous_row` (store `+0x312 mov [ebx+edx],cl`); ours picks `destination_row + x` as the IV representative, which
|
||||
follows from fact 1 rather than from the kernel term order (w1 already refuted term order with a 417-order sweep).
|
||||
4. The interior bound is a **16-bit** compare (`+0x25a cmp di,cx`) against `(4*width)-4` and loop 3 reuses that slot
|
||||
`+= 4`, so the row bounds are short-typed; loop 1 rematerialises `4*bitmap->width + byte_index` from `[ebp+8]`
|
||||
every iteration (`+0x23b mov ebx,[ebp+8]`), i.e. no long-lived row-size register.
|
||||
|
||||
This function is the only remaining structurally wrong body between `_bitmap_2d_smooth` and
|
||||
`_bitmap_2d_uncompress_from_mipmap` in compile order and is therefore the most likely keystone for the coin class.
|
||||
|
||||
## `_bitmap_sharpen`: park evidence refreshed
|
||||
|
||||
`relocdiff` reports `size 352/352, relocations 23/23, sha equal`. Only two relocation **spellings** differ, both
|
||||
resolving to the same image address: `+0x00a6` January `_bitmap_sharpen_negative_table+510` vs ours
|
||||
`_bitmap_sharpen_positive_table-2` (3260670), and `+0x00bb` January `_extract_data+42` vs ours
|
||||
`_bitmap_sharpen_negative_table-2` (3260158). The park evidence text is **stale**: it names the second January anchor
|
||||
`_bss_0031bed4+42`; at this HEAD csplit spells it `_extract_data+42` (a symbol owned by another object). Because the
|
||||
machine code is byte-identical, no source spelling can change the relocation's target address — this is purely
|
||||
csplit's nearest-preceding-symbol choice (laws_w3 A45) and needs the comparator-side resolved-equal admission, an
|
||||
orchestrator action with zero strict credit.
|
||||
|
||||
## Rejected / not proposed
|
||||
|
||||
- Landing `m4`/`m10` as-is: violates admission checklist item 2 (`_bitmap_2d_uncompress_from_mipmap` would go
|
||||
exact -> residual). Reported as a blocked park-reopen instead.
|
||||
- The 16-site assert-cast authenticity fix as a standalone hygiene landing: it costs the same exact row, and
|
||||
brief section 8 forbids a byte-inert-only diff in a unit where nothing lands.
|
||||
- Compensating for the coin by perturbing unrelated exact bodies (merging/splitting declarations elsewhere): that is
|
||||
steering with no authenticity basis; not attempted beyond diagnostics.
|
||||
- Any further body shapes on the four reload-transposition rows: nine measured-identical shapes say no body lever
|
||||
exists.
|
||||
|
||||
## Reopen criteria
|
||||
|
||||
- `_bitmap_2d_smooth` (1136) and `_bitmap_3d_smooth` (1824): land the bodies in
|
||||
`scratch/workers/w3c_bitmap_utilities/m10.c` together with whatever keeps `_bitmap_2d_uncompress_from_mipmap`
|
||||
exact in the same context — most plausibly a correct `_bitmap_2d_sharpen` — or with an owner ruling that accepts
|
||||
the exchange on the grounds that the HEAD row depends on sixteen casts January's assert literals refute
|
||||
(net +1136 gained, -880 lost, and the 16-site cleanup comes for free).
|
||||
- `_bitmap_2d_sharpen` (1152): a source-level reason for `bitmap` owning EBX and `temporary_pixels` staying in
|
||||
memory; start from w1 `s5f.c` plus the four facts above.
|
||||
- `_bitmap_2d_alpha_bleed` (560): TU-context only; do not spend body shapes again.
|
||||
- `_bitmap_sharpen` (352): comparator-side resolved-equal admission.
|
||||
@@ -0,0 +1,171 @@
|
||||
# `game_engine.obj` opus5 250K house-clean lane, wave w3c (2026-09-15)
|
||||
|
||||
## Scope and provenance
|
||||
|
||||
- Translation unit: `source/game/game_engine.c` (the only file this worker edited).
|
||||
- Target: `build/split/source/game/game_engine.obj` (January 2002 Xbox debug split) - the byte authority.
|
||||
- Compiler: XDK 3911 VC7 13.00.9254, checked-in `build.ninja` flags; every candidate compiled through
|
||||
`tools/campaign/gate.py --source` only. No ninja, configure, header or config edit.
|
||||
- Lane: `C:\halo-worktrees\opus5-150k-house-clean-20260914`, branch `opus/250k-house-clean-20260915`.
|
||||
- Ledgers read in full: `game_engine_obj.md` (GE01-GE31), `_codex_checkpoint`,
|
||||
`_fable_salvage_admission_20260902`, `_fable_small_families_20260901`, the three `_jonas_*` ledgers,
|
||||
`_opus5_fresh_graphs_20260914`, `_opus5_100k_waveC_20260914`, `_opus5_150k_w1_20260914`, plus the w1
|
||||
worker notes (`scratch/workers/game_engine.md`) and the waveC/w1 scratch candidates.
|
||||
- Laws applied as detectors over every non-exact row and the park: `scratch/w2/laws_w2.md` (A1-A22, R1-R12)
|
||||
and `scratch/w3/laws_w3.md` (A23-A45, R13-R19).
|
||||
- Per-function worker blocks: `scratch/workers/w3c_game_engine.md`. Harness:
|
||||
`scratch/workers/w3c_game_engine/probe.py`; standalone compiler lab `scratch/workers/w3c_game_engine/lab.py`.
|
||||
|
||||
## Baseline and result
|
||||
|
||||
`python -B tools/campaign/gate.py source/game/game_engine --all --forbid-emitted-symbol _point_from_line3d`
|
||||
|
||||
```text
|
||||
baseline == exact 174 residual 6 unwritten 0 (of 180 listed) guard passed
|
||||
final == exact 174 residual 6 unwritten 0 (of 180 listed) guard passed
|
||||
```
|
||||
|
||||
Row-by-row diff of the two `--all` listings, the only change:
|
||||
|
||||
```text
|
||||
- residual 1152 _game_engine_generate_title_string [size 1088!=1152, relocs 70!=73, sha]
|
||||
+ residual 1152 _game_engine_generate_title_string [sha]
|
||||
```
|
||||
|
||||
No new strict-exact row (**newly_exact is empty**). Park drift 0/1, owner census PASS (41 inherited
|
||||
candidate-only names equal `build/base`, none new, none missing), `tools/fake_match_scan.py` 0 leads,
|
||||
`git diff --check` clean.
|
||||
|
||||
| Function | Outcome | Padded / relocs |
|
||||
|---|---|---|
|
||||
| `_game_engine_generate_title_string` | **FUZZY-LANDED** (zero credit, structural closure) | 1152 / 73 (target 1152 / 73) |
|
||||
| `_drawline` | SKIPPED-EXHAUSTED (new mechanism recorded) | 112 / 7 |
|
||||
| `_game_engine_post_rasterize_post_game` | NOT-LANDED (blocked on `_drawline`) | 2528 / 148 |
|
||||
| `_game_engine_get_starting_location_rating` | SKIPPED-EXHAUSTED (EBX/EDI mirror) | 96 / 6 |
|
||||
| `_default_starting_location_rate_function` | SKIPPED-EXHAUSTED (EBX/EDI mirror) | 176 / 10 |
|
||||
| `_game_engine_should_spawn_player` (parked) | SKIPPED-EXHAUSTED (constant-register pinning) | 256 / 9 |
|
||||
|
||||
## Accepted control: the title-string team buffers are two `wchar_t[8]`
|
||||
|
||||
The previous body carried a hand-made storage union
|
||||
(`union { wchar_t team_names[22]; struct postgame_statistic_entry entry; } branch_storage;` with
|
||||
`&branch_storage.team_names[14]` for team 0) and per-arm `return`s. It was 1088/70 against a 1152/73 target
|
||||
- 64 bytes and three call relocations short. The landed body removes the union entirely.
|
||||
|
||||
January's frame facts (`alndiff`, target offsets):
|
||||
|
||||
| Offset | Object | Evidence |
|
||||
|---|---|---|
|
||||
| `[ebp-0x330]` | `score_string[256]` | `lea eax,[ebp-0x330]` at 0x3d9 and 0x44b |
|
||||
| `[ebp-0x130]` | `life_string[128]` | `lea eax,[ebp-0x130]` at 0xac/0xbd, terminator `mov word [ebp-0x32],0` |
|
||||
| `[ebp-0x30]` | team 1 name buffer | `lea eax,[ebp-0x30]; push eax; push 1; call [ecx+0x54]` at 0x2d1 |
|
||||
| `[ebp-0x20]` | `struct postgame_statistic_entry entry` (28 B) | 0x3ce, `rep movsd` ecx=7 at 0x3e8, 0x453 |
|
||||
| `[ebp-0x14]` | team 0 name buffer | `lea edx,[ebp-0x14]; push edx; push 0; call [eax+0x54]` at 0x2c2 |
|
||||
| `[ebp-4]` | `secondary_string` | stored at 0x22, reloaded at 0x31a/0x363/0x3aa/0x448 |
|
||||
|
||||
Frame `sub esp,0x330` = 512 + 256 + 44 + 4, so the two team buffers plus the entry cell occupy exactly
|
||||
44 bytes with the entry cell (28 B) overlapping them. Measured allocator behaviour for this block pair:
|
||||
|
||||
- two **16-byte** buffers: the first one used is placed at `-0x14` (packed over the top of the
|
||||
free-for-all `entry` cell) and the second below the entry cell at `-0x30` - **exactly January**;
|
||||
- `[8]`+`[14]` and `[14]`+`[8]` (waveC G2a/G2b - declaration order is inert): the 28-byte buffer shares the
|
||||
28-byte `entry` cell at `-0x20` and the 16-byte buffer drops to `-0x30`, i.e. the two teams swap slots;
|
||||
- `[14]`+`[14]` (waveC G2c): frame 0x33c.
|
||||
|
||||
So `wchar_t team0_name[8]; wchar_t team1_name[8];` is the unique measured fit, and it is the natural
|
||||
spelling: two same-sized buffers, one per team, each handed straight to `game_engine->format_team_name`.
|
||||
|
||||
The control flow is waveC's G2i shape, which the SINGLE-EXIT LAW (brief section 9) and January's bytes
|
||||
require: every postgame arm falls into a shared `ustrncpy` + `title_string[79] = 0` + epilogue tail that
|
||||
VC7 tail-duplicates into each arm (the previous per-arm `return` body could not produce the three extra
|
||||
`ustrncpy`/terminator copies, which is where the 64 bytes and 3 relocations were missing). HCEA
|
||||
`game/game_engine_generate_title_string.c` uses the same `switch (did_win)` over the tri-state result.
|
||||
|
||||
Result: 1152/73, `relocdiff --count-by-target` 73/73 with 0 differing rows, frame and every stack slot equal
|
||||
to the target, **391/391 instructions with a single transposed pair**:
|
||||
|
||||
```text
|
||||
target 448 mov edx,[ebp-4] | 44b lea eax,[ebp-0x330] | 451 push edx | 452 push eax
|
||||
ours 448 mov edx,[ebp-4] | 44b push edx | 44c lea eax,[ebp-0x330] | 452 push eax
|
||||
```
|
||||
|
||||
That is the last free-for-all `usnprintf`. January emits `mov; push; lea; push` (our order) at both team
|
||||
`usnprintf` sites (0x31a, 0x3aa); the free-for-all site is the only one whose next argument is a
|
||||
register-ABI static call (`get_place_string(&entry)`, `lea eax,[ebp-0x20]; call`). A standalone lab TU
|
||||
(`scratch/workers/w3c_game_engine/l2.c`, `l3.c`) reproduces our order and shows VC7 hoisting a different
|
||||
argument-input load into the same `mov`/`push` gap, so the remaining difference is a gap-filling scheduler choice on
|
||||
an identical DAG, not a structural or store-order fact.
|
||||
|
||||
Landed under brief section 6 (structurally incomplete row, zero credit): the body is complete, natural,
|
||||
strictly closer in every measure, and no sibling, park, owner or fake-scan status changes.
|
||||
|
||||
## Experiment matrix (this wave)
|
||||
|
||||
| ID | Function | Shape | Result | Decision |
|
||||
|---|---|---|---|---|
|
||||
| p1 | generate_title_string | G2i control flow + `team0_name[8]` / `team1_name[8]` | **1152/73, 391/391, 1 insn** | landed (as p2) |
|
||||
| q1 | generate_title_string | p1 + `&score_string[0]` argument | identical | rejected |
|
||||
| q3 | generate_title_string | p1 + swap `life_string`/`score_string` declaration order | identical (slots unchanged) | rejected |
|
||||
| q4 | generate_title_string | p1 + `score_string` declared in the free-for-all block | identical (frame preserved) | rejected |
|
||||
| p2 | generate_title_string | p1 minus a stray blank line | identical | **landed** |
|
||||
| inc1 | whole unit | `#include "main/console.h"` (the C4013 at game_engine.c:3806) | all 180 rows identical | not landed (see below) |
|
||||
| d1 lab | drawline | 12 ordinate spellings in one lab TU | 11 straight-line spellings identical to ours | rejected |
|
||||
| l1-l4 lab | generate_title_string | free-for-all call shape in a standalone TU | reproduces our push order | diagnostic |
|
||||
|
||||
## Residual classification
|
||||
|
||||
- `_game_engine_generate_title_string`: argument-schedule tie (one transposed pair). Structural debt closed.
|
||||
- `_drawline`: **new mechanism.** January computes `row*9` twice (`lea edx,[esi+esi*8]; shl edx,1` for `y0`,
|
||||
then `lea eax,[esi+esi*8]; lea ecx,[eax+eax+0x1a]` for `y1`); ours keeps `row*18` alive in EAX and adds
|
||||
0x1a. Twelve arithmetic spellings compiled in one lab TU (`d1.c`: `(row+1)*18+8`, `row*18+26`,
|
||||
`18*row+26`, `row*9*2`, `2*(row*9)+26`, named `short` ordinate, reversed statement order,
|
||||
`(short)(row*18)+26`, `(short)((row+1)*18)+8`, `row*18+18+8`, `(row*2+2)*9+8`) all emit our bytes, so the
|
||||
arithmetic spelling is not the lever. The real difference is where the `justification` argument load
|
||||
(`mov edx,[ebp+0xc]`) is scheduled: January puts it *between* the two ordinate stores, which frees the
|
||||
register holding `row*18` and forces the rematerialisation; ours issues it first, right after
|
||||
`offset_rectangle2d` returns. Class: argument-load scheduling / rematerialisation tie.
|
||||
- `_game_engine_post_rasterize_post_game`: six inlined `drawline` copies carry the same rematerialisation
|
||||
gap, plus the EBX/EDI colouring of the hoisted 350/500 and 0/1 constants and the `entry_count` spill
|
||||
order. Best body remains waveC P22 (`scratch/workers/game_engine/pr_p22re.c`, 2528/148, 751/752
|
||||
instructions, frame 0x670 and every slot equal); it is not strict exact and the row is `[sha]` only
|
||||
(size and relocations already match), so section 6 does not admit a fuzzy landing.
|
||||
- Rating pair: private-ABI mirror only - January keeps `player_index` in EBX, ours in EDI (plus one
|
||||
`mov eax` vs `mov ecx` in the callee). 46/46 and 72/72 instructions, everything else equal.
|
||||
- `_game_engine_should_spawn_player` (parked): January widens the boolean TRUE store to `mov ebx,1` and
|
||||
then spends EBX as the 32-bit compare operand for `respawn_timer == 1`; ours writes `mov bl,1` and
|
||||
rematerialises `cmp eax,1`. Recurring constant-register pinning; no w2/w3 law explains it.
|
||||
|
||||
## C4013 census item (orchestrator lead)
|
||||
|
||||
`game_engine.c(3806): warning C4013: 'console_printf' undefined`. The genuine owner header is
|
||||
`source/main/console.h` (`void console_printf(boolean clear, const char *format, ...);`). The call sits in
|
||||
`_game_engine_update_teleporter`, which is **already strict EXACT** with the implicit declaration, and the
|
||||
measured include (`scratch/workers/w3c_game_engine/inc1.c`, `#include "main/console.h"` before
|
||||
`"main/main.h"`) leaves **all 180 rows identical**. It therefore unlocks nothing and is not landed here;
|
||||
it is available as a byte-inert hygiene hunk if the orchestrator wants the warning gone (laws_w3 E18 class).
|
||||
|
||||
## Do-not-repeat (adds to the w1/waveC lists)
|
||||
|
||||
- generate_title_string: q1 (`&score_string[0]`), q3 (buffer declaration order), q4 (free-for-all-block
|
||||
`score_string`) - all byte-identical to p1; do not re-spin team-buffer sizes: `[8]`+`[8]` is the fit,
|
||||
`[8]`+`[14]`, `[14]`+`[8]`, `[14]`+`[14]` and `team_names[22]` are measured.
|
||||
- drawline: the twelve `d1.c` lab spellings; no arithmetic spelling defeats the CSE.
|
||||
- rating pair, should_spawn: no shapes spent; the recorded ties are unchanged and no law fires.
|
||||
|
||||
## Reopen criteria
|
||||
|
||||
- `_game_engine_generate_title_string`: a measured VC7 control that moves the `lea` of a stack array above
|
||||
the `push` of a spilled pointer when the next argument is a register-ABI call. Apply it to
|
||||
`scratch/workers/w3c_game_engine/p2.defs`; everything else is already byte-identical.
|
||||
- `_drawline` / `_game_engine_post_rasterize_post_game`: a control that delays a stack-parameter argument
|
||||
load past a store to an escaped local (freeing the ordinate register). Close `_drawline` first, then
|
||||
re-gate P22.
|
||||
- Rating pair: a callee register-pressure lever that moves an incoming private-ABI parameter from EDI to EBX.
|
||||
- `_game_engine_should_spawn_player`: a measured control where a boolean TRUE store is materialised as a
|
||||
32-bit constant register reused by a later int compare.
|
||||
|
||||
## Disposition
|
||||
|
||||
Real file stays 174/180 strict exact (no credited bytes this wave). `_game_engine_generate_title_string` is
|
||||
now structurally complete (size, relocations, frame, slots and 390 of 391 instructions equal to January) and
|
||||
free of the storage union; the object stays `NonMatching` and active.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Opus5 250K house-clean lane: checkpoint ledger (2026-09-15)
|
||||
|
||||
Continuation of `opus/150k-house-clean-20260914` (HEAD `0483bde89`, +89,085 strict meaningful) on branch
|
||||
`opus/250k-house-clean-20260915`, in the same worktree `C:\halo-worktrees\opus5-150k-house-clean-20260914`.
|
||||
Lane base snapshot: `scratch/claude150k-before.json` (commit `12f7375d4`, 7,149 functions / 1,244,970 meaningful).
|
||||
Target: +250,000 strict meaningful (`scratch/lane_manifest.py`: `TARGET = 1494970`, remaining computed against 250,000).
|
||||
|
||||
## 1. Startup proof (2026-09-15, at 0483bde89)
|
||||
|
||||
| check | expected | observed |
|
||||
| --- | --- | --- |
|
||||
| tracked tree / HEAD | clean / 0483bde89 | clean / 0483bde89 |
|
||||
| `ninja` (incl. parked-function check) | pass | pass; "Validated parked compiler ties: 280" |
|
||||
| stable diff `claude250k-start.json` vs `claude150k-before.json` | gained 144 90112; regressions 0; 8,245 / 7,263 | gained 144 90112 bytes; regressions 0; 8,245 functions, 7,263 exact |
|
||||
| `tools.parked_functions` | 280 / 0 / 0 | 280 active / 0 stale / 0 invalid |
|
||||
| `tools.audit_object_admission` | 0 contradicted / 7 rejected / 7 candidates | 0 / 7 / 7 |
|
||||
| `pytest --basetemp scratch/pytest-250k-start` | 1151 passed, 5 skipped | 1151 passed, 5 skipped, 26 subtests passed |
|
||||
| `lane_manifest.py` strict_new_meaningful | 89,085 | 89,085 (144 fns, 90,112 padded; 4 non-strict accepted / 2,195 excluded) |
|
||||
|
||||
## 2. Owner rulings (2026-09-15, asked at startup; strategy step A)
|
||||
|
||||
The owner took the strict option on every held item. Nothing below is landed or credited:
|
||||
|
||||
- collision_bsp `_collision_surface_test_sphere` (880; unit-local SSE `__asm` distance macro, p1.c): leave parked.
|
||||
- env_fog 21-static .bss split (+800) and models 13-static .bss split (+1,296): neither lands.
|
||||
- editor_flying_camera `is_scripted` linkage-anchor split (304; the w3 ledger says the split alone would also unlock
|
||||
`_editor_camera_flying_update` 1,408 and `_editor_camera_set_scripted` 432): held.
|
||||
- The 7 whole-object admission candidates: not admitted. P7 `projection_from_vector3d`: stays reverted, no worker spend.
|
||||
|
||||
These are recorded in `scratch/WORKER_BRIEF.md` section 9b as final for this lane.
|
||||
|
||||
## 3. Pool at HEAD (scratch/gate4, regenerated 2026-09-15)
|
||||
|
||||
`gate.py <unit> --all --forbid-emitted-symbol _point_from_line3d` over the 151 units with non-exact rows (no guard for
|
||||
action_charge / ai_debug / real_math): 239,536 residual + 192,176 parked + 6,088 unwritten padded bytes. The 90 units
|
||||
that never got a w3 pass hold 110,832 residual + 100,768 parked + 3,144 unwritten. After removing protected units,
|
||||
`rasterizer_xbox_transparent_geometry`, do-not-spend, owner-declined/standing holds and laws_w2 D do-not-repeat rows,
|
||||
`scratch/build_wave3c_groups.py` leaves 157,832 spendable padded bytes in 53 groups / 81 units.
|
||||
|
||||
## 4. Strategy step C: C4013 census (zero credit, analysis only)
|
||||
|
||||
`CL /Zs /W3` over all 468 source units (`scratch/gate4/c4013.txt`, 112 C4013 + 23 C4133 lines;
|
||||
`scratch/gate4/c4013_map.json` maps each site to its caller and gate status). Outside libtiff, only 7 sites are inside
|
||||
non-exact functions (7,392 padded): rasterizer_xbox_models `_rasterizer_model_draw_environment_shader` (park),
|
||||
action_vehicle `_action_vehicle_evaluate_seat`, light_volumes `_light_volume_render` (park), hud_weapon
|
||||
`_render_grenade_hud` (`weapon_prevents_grenade_throwing` has no owner prototype), ai_communication
|
||||
`_ai_communication_update_speech_timers` (park), action_uncover `_action_uncover_perform` (park), main
|
||||
`_main_game_render` (park). All 7 were already in the w3 census; the un-run units carry them in their w3c group notes.
|
||||
The other sites are in functions that are already exact (a prototype there is a regression risk, not a lever).
|
||||
|
||||
## 5. Strategy step D: static-linkage census (negative)
|
||||
|
||||
`scratch/gate4/static_census.py`: 53 external data symbols in January split objects with no January PDB public and no
|
||||
cross-object relocation, referenced by at least one non-exact function at HEAD (74,880 B of referencing rows, double
|
||||
counted). A scratch csplit with 50 of them `"static": true` (placeholder `_data_`/`_bss_` names excluded) changed
|
||||
only the 33 owner objects (`scratch/static_probe/changed_objects.json`).
|
||||
|
||||
- Config only (HEAD objects vs the static split): 0 rows changed in all 33 units.
|
||||
- C `static` added to the definition (tentative COMMON becomes a defined .bss symbol; storage 3 verified in the
|
||||
candidate objects) with the matching static split: **0 rows changed** in sound_manager, virtual_keyboard,
|
||||
stack_walk_windows, actor_perception, weather_particle_systems, rasterizer_xbox_active_camouflage, draw_string,
|
||||
dead_camera, render_particles, props, shader_transparent_chicago_preprocessor, debug_memory, key_agreement,
|
||||
bitmap_utilities (both tables), rasterizer_transparent_geometry (5 globals), rasterizer_xbox.
|
||||
- game_engine_king `king_globals` static with the (single-consumer) header extern removed: gains nothing and loses
|
||||
`_find_next_hill` (112) and `_king_engine_initialize_for_new_map` (272). Same as the w2 static probe.
|
||||
- Already `static` in C (config flip only, byte-inert): collision_debug x2, rasterizer_lights x4, player_effects x2,
|
||||
profile_globals, dsound_error_string.
|
||||
- Not probed: `extern` layout-anchor declarations inside their own .c (ui_widget_globals_storage,
|
||||
dsound_effects_image, bink_playback x3, xbox_sound_cache_globals); editor_camera_* (owner-declined split); the
|
||||
header-extern globals lightning, light_volumes, race (w2 measured them as no effect), director x3 (rows are
|
||||
R3/A17 ruling-blocked) and game_globals (`_game_load` 208).
|
||||
|
||||
Conclusion: at HEAD the static-linkage law has no remaining closures for these residuals.
|
||||
@@ -0,0 +1,143 @@
|
||||
# `rasterizer_frame_statistics.obj` — opus5 250K lane, wave w3c (2026-09-15)
|
||||
|
||||
## Verdict
|
||||
|
||||
**No production source change; zero new strict bytes.** All three non-exact rows were re-examined with the
|
||||
w2/w3 law set as detectors. Two are closed with law-based refutations of their only remaining candidate
|
||||
shapes; the third (`count_static_vertices`) advanced from "unclassified callee-save schedule" to a fully
|
||||
decoded two-clause mechanism with two scratch bodies that sit one hunk from exact, but no house-rule-admissible
|
||||
spelling reaches it. `git diff --stat -- source/rasterizer/rasterizer_frame_statistics.c` is empty.
|
||||
|
||||
## Baseline and final gate
|
||||
|
||||
`python -B tools/campaign/gate.py source/rasterizer/rasterizer_frame_statistics --all --forbid-emitted-symbol _point_from_line3d`
|
||||
|
||||
| Function | Target | Candidate | Tag | Wave outcome |
|
||||
| --- | ---: | ---: | --- | --- |
|
||||
| `_eat_my_shorts` (parked) | 32 / 0 | 16 / 0 | size, sha | SKIPPED-EXHAUSTED (A42 refutes the last shape) |
|
||||
| `_rasterizer_frame_statistics_count_static_vertices` (parked) | 64 / 0 | 64 / 0 | sha | NOT-LANDED (mechanism decoded) |
|
||||
| `_rasterizer_frame_statistics_draw` | 4176 / 322 | 4176 / 322 | sha | SKIPPED-EXHAUSTED (C2 allocator tie) |
|
||||
|
||||
Baseline and final are both `== exact 7 residual 3 unwritten 0`, guard passed. `tinfo` confirms the object has
|
||||
exactly these 10 functions, none unwritten and none a `_code_` placeholder, so this wave had no callee-first
|
||||
work available. `scratch/parkcheck.py` reports parks 2 / drift 0; `tools/fake_match_scan.py` 0 leads; owner
|
||||
census unchanged (no source change). Inherited exact and never re-touched:
|
||||
`_rasterizer_frame_statistics_get_fps` (100K lane, 384/21).
|
||||
|
||||
Evidence read: all 10 prior object ledgers, `scratch/workers/rasterizer_frame_statistics.md` (w1),
|
||||
`scratch/ghidra/out/rasterizer_frame_statistics.obj.decomp.c`, `scratch/atlas/rasterizer_frame_statistics.obj.txt`,
|
||||
HCEA `blam/rasterizer/rasterizer_frame_statistics_count_static_vertices.c`, `scratch/gate4/c4013.txt`.
|
||||
Two evidence cautions recorded for later waves: (1) the atlas records for this object are Halo-CE map entries
|
||||
(`@rasterizer_frame_statistics_count_static_vertices@8`) — the `@N` decoration is the CE build's fastcall and
|
||||
must not be read as a January calling convention, whose bytes are plain cdecl `[ebp+8]`/`[ebp+0xc]`;
|
||||
(2) the HCEA body is a retail stub (`return 0;`) and carries no January topology.
|
||||
|
||||
## 1. `_rasterizer_frame_statistics_count_static_vertices` — mechanism decoded, still parked
|
||||
|
||||
January's complete stream (decoded this wave):
|
||||
|
||||
```
|
||||
0 push ebp 14 mov cx,[edx] 26 test cx,cx
|
||||
1 mov ebp,esp 17 cmp cx,1 29 jne 0x2e
|
||||
3 mov edx,[ebp+8] 1b jne 0x26 2b mov eax,[esi+4]
|
||||
6 xor eax,eax 1d mov eax,[edx+4] 2e pop esi
|
||||
8 test edx,edx 20 add eax,2 2f nop
|
||||
a je 0x30 23 pop esi 30 pop ebp
|
||||
c push esi 24 pop ebp 31 ret
|
||||
d mov esi,[ebp+0xc] 25 ret
|
||||
10 test esi,esi
|
||||
12 je 0x2e
|
||||
```
|
||||
|
||||
January shrink-wraps `push esi` past the `triangle_buffer` test and splits ONE epilogue into two entry points
|
||||
(0x2e for the paths that pushed esi, 0x30 for the `triangle_buffer == NULL` path); the `nop` at 0x2f is
|
||||
jump-target alignment for 0x30. Detectors that confirm the current source is right in every other respect:
|
||||
A42 (the entry `xor eax,eax` before the first test proves the declaration initializer `long vertex_count = 0;`),
|
||||
A18/A34 (`mov cx,[edx]`, `cmp cx,1`, `test cx,cx` prove the 16-bit `type` field and the strip-then-triangles
|
||||
order). Ghidra's `return *(int *)(param_1 + 2) + 2;` is the duplicated epilogue at 0x23, not a source return.
|
||||
|
||||
Shapes measured in scratch (`scratch/workers/w3c_rasterizer_frame_statistics/`, all gated with `--source`):
|
||||
|
||||
| Shape | Form | Result |
|
||||
| --- | --- | --- |
|
||||
| t1 | `if (!triangle_buffer) { return vertex_count; }` then `if (vertex_buffer) {...}` | 64/0; **push esi sinks exactly like January**, entry eax=0 reused (no remat); early exit laid out inline at 0xc (`jne 0xe; pop ebp; ret`) instead of jumping to the bottom tail — 1 hunk |
|
||||
| t2 | two separate early returns | 64/0; two inline exit blocks, worse |
|
||||
| t3 | nested `if (tb) { if (vb) {...} }` | v0 fixed point (push esi at 0xa) — re-confirms the park note |
|
||||
| t4 | nested + `return vertex_count;` at the end of the tb block + final `return vertex_count;` | **22 of 23 code instructions identical incl. `je`→bottom and `push esi` at 0xc**; the bottom block rematerialises `xor eax,eax` instead of sharing January's tail — 1 hunk (control only: double return) |
|
||||
| t5 | `if (!tb \|\| !vb) { return vertex_count; }` + flat if/else-if | sink lost, separate `xor eax,eax; pop esi` tail, worse |
|
||||
| t6 | t4 with the inner return inside the `vertex_buffer` block | sink lost (vb-null path reaches the bottom with esi pushed), worse |
|
||||
|
||||
**Candidate law A46 (two clauses, measured here):**
|
||||
(a) VC7 sinks a callee-save `push` past the first test only when that test's exit is a *separate return
|
||||
statement* whose block never touches the register; with `&&` or a nested guard the exit is the shared epilogue
|
||||
that pops the register, so the push can only sink to the end of the entry block.
|
||||
(b) A return statement laid out at the BOTTOM whose value is a compile-time constant on that path
|
||||
rematerialises the constant in its exit block; a return laid out immediately after the definition reuses the
|
||||
entry definition.
|
||||
|
||||
January needs (a) while keeping the entry `xor eax,eax` live to 0x30 — one exit edge that is separate for
|
||||
register-save purposes but is not a second `return` statement in the source. t1 satisfies the value half,
|
||||
t4 satisfies the placement half, and nothing admissible satisfies both: the only bottom-placed forms are
|
||||
double returns (R1/R12 class), and the park text already records the rejection of a same-size topology change
|
||||
made "solely to steer code generation" (R13 binds it).
|
||||
|
||||
**Reopen criterion (sharpened, replaces "explain the delayed ESI save"):** an authentic January spelling that
|
||||
gives the `triangle_buffer`-null path its own register-free exit edge without a second `return` statement
|
||||
(January source/local records, or an authenticated guard idiom), or evidence that this TU's C2 state rather
|
||||
than its source picks the sink. Re-measure `t1.c` and `t4.c` first — each is one hunk from exact.
|
||||
|
||||
## 2. `_eat_my_shorts` — exhausted, and the last candidate shape is now positively refuted
|
||||
|
||||
January: `mov ax,[ebp+8]; cmp ax,[ebp+0xc]; jbe 0x11; mov al,1; pop ebp; ret; 0x11: xor al,al; pop ebp; ret`.
|
||||
`jbe` proves unsigned `word` operands and the `first > second` polarity with TRUE as the fall-through (the
|
||||
current source is correct); the 8-bit constants prove the `boolean` return. VC7 if-converts every natural
|
||||
spelling to `seta` (16 B).
|
||||
|
||||
The only 32-byte shape ever produced, w1's `boolean result = FALSE; if (first > second) result = TRUE;
|
||||
return result;`, puts the zero at the entry and emits a single epilogue. **A42 refutes it from January's own
|
||||
bytes**: VC7 does not hoist a constant into the entry, so January's `xor al,al` sitting in the branch target
|
||||
proves there is no initializer at all. A38 gives the same conclusion (an initializer declared in the enclosing
|
||||
block is emitted between the compare and the jcc). A3/A29 (single exit), A10 (conditional initializer),
|
||||
A23/A39/A40 (loop/switch/inline-helper levers) and A43 (tail duplication has no source lever) do not fire —
|
||||
this function has no call, loop, switch or helper. w1's k=1..46 declaration sweep already showed the row is
|
||||
not TU-state dependent. The reachable natural set is {16 B `seta`, 16/32 B `sbb/neg`, 32 B entry-zero
|
||||
single-epilogue}; January's form is in none of them.
|
||||
|
||||
Reopen criterion unchanged: authoritative January source/local records, or a natural same-compiler context
|
||||
that suppresses the setcc if-conversion while keeping both epilogues and the late `xor al,al`.
|
||||
|
||||
## 3. `_rasterizer_frame_statistics_draw` — C2 allocator tie, donor match proven unreproducible
|
||||
|
||||
The residual is 3 sites / 6 instruction rows, all in the opening aggregate sums: 0x6e/0x7e/0x8d (statistics
|
||||
`+0xB0`/`+0xA0`), 0xca/0xd3/0xd9 (`+0xA8`/`+0xB4`) and 0x10f/0x117/0x197 plus 0x19a/0x1a0/0x1a6/0x1a8/0x1b1
|
||||
(`+0xE4`/`+0xD8`, `+0xDC`/`+0xE8`, `+0xE0`). In every case both builds issue the same two loads in the same two
|
||||
instruction slots and the same semantic operand order in the following `lea`/`add`; only the physical register
|
||||
each load lands in is swapped (ecx<->eax, edx<->ecx), which renames the destination of the `lea`/`add` and one
|
||||
store. The other 1,172 instructions are identical, and the remaining alndiff rows are `symbol:` versus
|
||||
`defined-noncode:.rdata:` descriptions of the same literal owners (a `--source` gating artifact).
|
||||
|
||||
Detectors run, all negative: A35 (leaf age / dot canonicalisation is x87; these are integer register
|
||||
assignments), A12 (not a loop preheader), A20/A44 (no stores or calls in the hunks), A24 (no parameters),
|
||||
A6 (frame identical — the `[ebp-0x24]` store matches), A11/A36 (no float constant), A7 (this TU has no implicit
|
||||
declaration; the only frame-statistics C4013 in the whole build is `rasterizer_xbox_models.c(1723)`, which is
|
||||
packet E4 and unlocks 0 B).
|
||||
|
||||
New evidence: the historical reconciled donor body (blob `6dac0962`, commit `5d3444f79`) gates
|
||||
`exact 6 residual 4` at this HEAD — i.e. **the donor draw is residual now** — and the original donor blob
|
||||
`4168c4a3` (commit `7841c6ac3`, the "exact draw") no longer compiles against the shared owner header. The
|
||||
20260906 hold's donor match is unreproducible in any form at this HEAD, which confirms it was TU/C2 state and
|
||||
not source topology, and closes the "import the donor source" avenue for good.
|
||||
|
||||
Classification: C2 register-allocation tie, definition-position driven (C2 POGO attribution: the allocator
|
||||
record carries no spill-cost field; zero-register pinning residual). The only known lever is declaration
|
||||
count/order, forbidden by the 20260906 hold and measured by w1 as a lottery with no k in 0..48 reaching zero
|
||||
hunks. Reopen only with an authentic January include/declaration environment for this TU (a preprocessed
|
||||
listing or the original header set) or a January source record — and re-measure whenever a predecessor body in
|
||||
this TU changes, because the pair lottery is coupled to them.
|
||||
|
||||
## 4. Proposals
|
||||
|
||||
No header or config change is requested by this wave. (`E4` — putting `rasterizer_xbox_models.c` on this
|
||||
object's owner header — remains an owner decision worth 0 B and is not re-proposed.) Candidate law A46 above is
|
||||
offered for `scratch/w3/laws_w3.md`'s successor; it is measured only on this function and should be narrowed
|
||||
accordingly.
|
||||
@@ -0,0 +1,142 @@
|
||||
# `rasterizer_xbox_environment.obj`: opus5 250K house-clean lane, wave w3c (2026-09-15)
|
||||
|
||||
## Scope and provenance
|
||||
|
||||
- Translation unit `source/rasterizer/xbox/rasterizer_xbox_environment.c`, target
|
||||
`build/split/source/rasterizer/xbox/rasterizer_xbox_environment.obj` (the January split COFF is the byte authority).
|
||||
- Lane `opus/250k-house-clean-20260915` (continues `opus/150k-house-clean-20260914`). Worker-only measurements with
|
||||
`tools/campaign/gate.py`, `tools.campaign.alndiff`, `tools.campaign.tinfo`, `scratch/parkcheck.py`,
|
||||
`tools/fake_match_scan.py`. No ninja, header, config or tool edits; no other source file touched.
|
||||
- Prior ledgers read in full: `_codex_small_exact_20260902`, `_diffuse_texture_reconciliation_20260909`,
|
||||
`_lightmap_draw_fuzzy_20260912`, `_opus_reflections_reconciliation_20260909`, `_opus5_100k_20260914` (wave B),
|
||||
`_opus5_100k_waveC_20260914`, `_opus5_150k_w1_20260914`; worker notes
|
||||
`scratch/workers/rasterizer_xbox_environment.md`; the w1 verifier verdict in `scratch/w1/w1-results.json`.
|
||||
- Laws applied as detectors: WORKER_BRIEF section 9, `scratch/w2/laws_w2.md` (A1-A22, R1-R12, D) and
|
||||
`scratch/w3/laws_w3.md` (A23-A45, R13-R19, C, D).
|
||||
- Worker notes for this wave: `scratch/workers/w3c_rasterizer_xbox_environment.md`;
|
||||
scratch dir `scratch/workers/w3c_rasterizer_xbox_environment/`.
|
||||
|
||||
## Baseline and final gate (identical; nothing landed)
|
||||
|
||||
`python -B tools/campaign/gate.py source/rasterizer/xbox/rasterizer_xbox_environment --all --forbid-emitted-symbol _point_from_line3d`
|
||||
|
||||
**exact 42, residual 2, unwritten 0 of 44** - point guard passed, `scratch/parkcheck.py` 1 park drift 0,
|
||||
`fake_match_scan.py` 0 leads, `git diff --stat -- source/rasterizer/xbox/rasterizer_xbox_environment.c` empty.
|
||||
|
||||
| Row | Target size/relocs/sha16 | Real file | Status |
|
||||
| --- | --- | --- | --- |
|
||||
| `__rasterizer_environment_lightmap_draw` | 4016 / 248 / 7818e559325c1524 | 3984 / 246 / 02f716db92e8099f | residual [size, relocs, sha] |
|
||||
| `_rasterizer_environment_specular_spot_light_begin` | 960 / 64 / e0331f6b94a74f9c | 944 / 64 / d103843ee5f01bad | residual, PARKED |
|
||||
|
||||
Context: `__rasterizer_environment_diffuse_light_begin` (w1 park reopen) is EXACT at HEAD and
|
||||
`_IDirect3DDevice8_SetTexture@12` is inherited exact; neither was revisited. The w1 `lightmap_draw` landing was
|
||||
rejected by its verifier and reverted, so the row is back at the 100K baseline.
|
||||
|
||||
## `__rasterizer_environment_lightmap_draw` - SKIPPED-EXHAUSTED (0 shapes spent)
|
||||
|
||||
**What is left.** Against the wave-B candidate (`scratch/workers/rasterizer_xbox_environment/v0.obj`, 4000/248) the
|
||||
entire remaining 16-byte / 2-relocation gap is the `t` argument of the two `_point_from_line3d` calls:
|
||||
|
||||
```
|
||||
January @b88 fld dword [ebp-4] ; add esp,0xc ; lea eax,[ebp-0x5c] ; push eax ; push ecx ;
|
||||
lea ecx,[edi+0x19c] ; fstp dword [esp] ; push ecx ; lea edx,[ebp-0x5c] ; push edx ; call
|
||||
ours @b88 mov ecx,[ebp-4] ; lea eax,[ebp-0x5c] ; push eax ; push ecx ; ... (and one merged add esp,0x44)
|
||||
```
|
||||
|
||||
Everything else in the self-illumination block already matches byte for byte: the three
|
||||
`periodic_function_evaluate` argument stages, both `fld __real@3f800000; fsub [ebp-N]` scale arguments, both plasma
|
||||
`push 0x3f800000` constants, and - decisively - the **integer** push `mov eax,[ebp-0x50]` of `plasma_value` into
|
||||
`real_alpha_to_pixel32` in the same function. Same declaration class, same block, integer-copied: the trigger is not
|
||||
the declaration of the local.
|
||||
|
||||
**New evidence gathered this wave.**
|
||||
|
||||
1. *January-wide census* (re-using the 100K lane's `fldscan.py` over every `build/split` object): of the 71 pure
|
||||
`fld dword [mem]` -> `fstp dword [esp]` argument stages in the whole January image, only three read a STACK slot -
|
||||
these two sites and `_ai_test_line_of_fire @70` (`[ebp+eax-0x4e4]`, an indexed stack array element). The other 68
|
||||
stage a pointer field (`[reg+off]`). `lightmap_draw` is therefore a member of the unresolved x87-staged-real-argument
|
||||
family recorded in `laws_w3` C3 (`_object_test_vector`, `_player_examine_nearby_device`, `_ai_test_line_of_fire`,
|
||||
`_biped_update_moving`), not an isolated puzzle. The family's only known reproduction - a parenthesised argument
|
||||
produced by a genuine macro - is measured INERT on a stack-local leaf (w1 p1 = 4000), so the `_object_test_vector`
|
||||
form does not transfer here.
|
||||
2. *Donor re-check.* Ghidra `scratch/ghidra/out/rasterizer_xbox_environment.obj.decomp.c:1416-1430` shows a bare local
|
||||
copy for the `t` argument (`local_264 = (undefined4 *)local_8;`). HCEA's later-build
|
||||
`_rasterizer_environment_lightmap_draw_pp.c:156-213` computes `on*blend + off*(1-blend)` componentwise with **no**
|
||||
intensity term and copies the plasma colours directly. Both corroborate the w1 verifier's rejection of the constant
|
||||
factor; neither satisfies the reopen criterion. The punpckhdq and Stian trees contain no body for this object.
|
||||
|
||||
**Detectors run, none fires.** A23 (no loop), A24 (frame 0x218 and all three value slots already identical),
|
||||
A25/A29 (single return, no join store), A31(a) (the `add esp` flush positions already match), A33 (block scoping
|
||||
without the factor measured 4000: w1 f2/g2n), A35 (not a commutative product), A36 (the constant is exactly 1.0f),
|
||||
A38 (inner-block declare+init temporaries measured 4000: w1 f2), A42 (no store to prove).
|
||||
|
||||
**Why no shape was spent.** Every exact form on record (w1 c1/e2/f1/g2 and waveC k16/k17/k22) requires the constant
|
||||
1.0 identity factor or an explicit cast on a c2-folded expression. The w1 verifier rejected that tree as fake
|
||||
arithmetic and required a full revert including the wave-B hunks; R13 binds that rejection, and no w2/w3 law or donor
|
||||
supplies a genuine intensity/brightness term or a double intermediate. Wave B's four structural corrections alone
|
||||
reach only 4000/248 and cannot land for an already-written residual (brief section 6).
|
||||
|
||||
**Classification.** Unresolved source form (x87 argument staging), not a register tie.
|
||||
|
||||
**Reopen criterion.** Unchanged from w1 - January or donor evidence of a real intensity/brightness term or a
|
||||
double/cast intermediate - OR an owner/policy ruling on the `laws_w3` C3 x87-staged-argument family that also covers
|
||||
stack-local leaves. Start from `scratch/workers/rasterizer_xbox_environment/v0.c` (4000/248).
|
||||
|
||||
## `_rasterizer_environment_specular_spot_light_begin` - NOT LANDED (park locked; 1 shape, 2 refutations)
|
||||
|
||||
w1 closed the structural half in scratch: the frame is a `real_matrix4x3 matrix` whose `scale` (-0x34) and `position`
|
||||
(-0xc) are never written (forward -0x30, left -0x24, up -0x18), and `s3a.c`
|
||||
(`matrix.forward = light->forward; matrix.up = light->up; normalize3d(cross_product3d(&light->forward, &light->up,
|
||||
&matrix.left));`) reaches 960/64 with frame parity and 15 small blocks left.
|
||||
|
||||
**Shape p1 (new, evidence-led, refuted).** `source/math/matrix_math.c:337-346` shows the house idiom for building a
|
||||
basis - `matrix->forward = *forward; cross_product3d(...); matrix->up = *up;` - i.e. the up copy AFTER the cross.
|
||||
Under A35 that should make `up` the younger leaf and flip the j/k operand order towards January's.
|
||||
Measured (`scratch/workers/w3c_rasterizer_xbox_environment/p1.c`, `p1.obj`): 960 [sha], but structurally worse than
|
||||
s3a - the i-term flips to forward-first (`fld [esi+0x14]`), the up copy is pushed past the cross and loses January's
|
||||
`lea ecx,[esi+0x1c]; mov edx,ecx` twin-pointer form, and the `push ebx` prologue register disappears. This **refutes**
|
||||
the matrix_math ordering for this function: January's interleaved twin-pointer copies require both copies before the
|
||||
cross, exactly as s3a spells it.
|
||||
|
||||
**Two controls that pin the source form (no shape spent).**
|
||||
|
||||
- Re-reading w1's `s3b.obj`: taking the cross operands from the matrix members makes VC7 read the LOCAL slots
|
||||
(`fld [ebp-0x10]; fmul [ebp-0x2c]`), whereas January reads light-relative addresses
|
||||
(`[eax+..]`, `[ecx+..]`, `[esi+0x20/0x24]`). VC7 does not forward the struct copy, so January's cross arguments are
|
||||
`&light->forward, &light->up`; every mixed spelling (`&matrix.forward, &light->up` and friends) is excluded by the
|
||||
same address evidence.
|
||||
- Sibling control inside this object: the EXACT `__rasterizer_environment_diffuse_light_begin` inlines the same
|
||||
`real_math.h` `cross_product3d` from local matrix members, and January loads operand b (up) first in **all six**
|
||||
products. The spot light loads b first in 5 of 6 (the exception is the i-term subtrahend, whose up operand is read
|
||||
through the light base ESI before `lea eax` exists); s3a loads b first in only 2 of 6. The order tracks leaf age and
|
||||
pointer availability inside the shared inline; this TU cannot change it without moving the operand addresses away
|
||||
from January's.
|
||||
|
||||
**Remaining 15 blocks in s3a:** four cross-product `fld`/`fmul` operand orders, one eax/ecx/edx rotation in the
|
||||
`light->position` copy, one `fxch st(1)` before the last vertex constant, and the `rasterizer_set_pixel_shader` push
|
||||
placement - the last three all downstream of the operand order (the two x87 stack residents at the tail are
|
||||
`cone_scale` and `radius*0.5f`, swapped only because of the earlier product order).
|
||||
|
||||
**Classification.** x87 leaf-age / allocator tie inside the shared `real_math.h cross_product3d` inline; the source
|
||||
spelling is pinned by January's addresses; no TU-local lever remains. Do not re-spend on cross-operand permutations
|
||||
(9 shapes total across w1 and w3c).
|
||||
|
||||
**Reopen criterion (refined; supersedes w1's).** w1 asked for "a natural cross-product spelling that loads up.i/up.j
|
||||
first in the j/k terms"; this wave shows no such spelling exists from this TU. Reopen only on (a) a measured VC7 law
|
||||
explaining the `fld` order for pointer-read commutative operands, or (b) an owner-approved `real_math.h`
|
||||
`cross_product3d` change measured across its consumers - noting that the current k,j,i body is REQUIRED by the exact
|
||||
sibling `__rasterizer_environment_diffuse_light_begin`, so any such change must keep that row exact. Best scratch body
|
||||
remains `scratch/workers/rasterizer_xbox_environment/s3a.c` (960/64, frame 0x84, sha16 9c8a4202366a9d91).
|
||||
|
||||
## Rejected / do-not-repeat (added by this wave)
|
||||
|
||||
- The matrix_math.c copy/cross/copy ordering in the spot light (p1): structurally worse; both copies precede the cross.
|
||||
- Cross operands read from the matrix members or from a mixed member/pointer pair: wrong operand addresses (s3b proof
|
||||
that VC7 does not forward the struct copy).
|
||||
- Re-proposing the constant `intensity = 1.0f` factor (or any identity/cast wrapper) in `lightmap_draw`: rejected by
|
||||
the w1 verifier, corroborated as absent by HCEA and Ghidra; R13 binds.
|
||||
|
||||
## Proposals
|
||||
|
||||
None. No header, config, symbols.json or parked.json need arises from this wave; the park stays locked and the real
|
||||
file is unchanged.
|
||||
@@ -0,0 +1,197 @@
|
||||
# `sound_manager.obj`: opus5 250K house-clean lane, wave w3c (2026-09-15)
|
||||
|
||||
## 1. Scope and provenance
|
||||
|
||||
- Translation unit `source/sound/sound_manager.c`; target `build/split/source/sound/sound_manager.obj`.
|
||||
- Lane worktree `C:\halo-worktrees\opus5-150k-house-clean-20260914`, branch `opus/250k-house-clean-20260915`,
|
||||
HEAD `0483bde89`. Compiler XDK VC7 13.00.9254 with the repository flags; no flag was changed or passed.
|
||||
- Nothing was written to `sound_manager.c`, to any header, or to `config/*.json`. No ninja, configure, pytest or
|
||||
git write command was run. `git diff --stat -- source/sound/sound_manager.c` is empty.
|
||||
- Worker notes `scratch/workers/w3c_sound_manager.md`; candidates and dumps in
|
||||
`scratch/workers/w3c_sound_manager/` (`base.obj`, `d1.c/d2.c`, `rl1.c`..`rl3.c` with objects,
|
||||
`rl_target.txt`, `rl_ours.txt`).
|
||||
- Evidence: January split-object bytes, relocations and section order (authoritative); HCEA
|
||||
`cache/sound_dispose_from_old_map.c`, `cache/sound_refresh_looping.c`,
|
||||
`game/update_channel_for_impulse_sound.c` (later build; semantics and corroboration only);
|
||||
`config/parked.json` park entries; all ten earlier `sound_manager_obj_*` ledgers and
|
||||
`scratch/workers/sound_manager.md`; `scratch/w2/laws_w2.md` and `scratch/w3/laws_w3.md` applied as detectors.
|
||||
|
||||
## 2. Baseline (unchanged at the end of the wave)
|
||||
|
||||
`python -B tools/campaign/gate.py source/sound/sound_manager --all --forbid-emitted-symbol _point_from_line3d`
|
||||
reports `== exact 58 residual 7 unwritten 0 (of 65 listed)`; the guard passed; `scratch/parkcheck.py`
|
||||
reports `parks 5 drift 0`; `tools/fake_match_scan.py` reports 0 review leads.
|
||||
|
||||
| Function | Target padded / relocs | Base | Tag | Park |
|
||||
|---|---:|---|---|---|
|
||||
| `_refresh_listener` | 496 / 25 | 496 / 25 | sha | - |
|
||||
| `_sound_dispose_from_old_map` | 240 / 21 | 272 / 23 | size, relocs, sha | - |
|
||||
| `_sound_find_like_channel` | 272 / 16 | 272 / 16 | sha | P |
|
||||
| `_sound_refresh_looping` | 1136 / 43 | 1088 / 42 | size, relocs, sha | P |
|
||||
| `_sound_set_definition_end` | 208 / 9 | 208 / 9 | sha | P |
|
||||
| `_update_channel_for_impulse_sound` | 528 / 29 | 528 / 29 | sha | P |
|
||||
| `_update_channel_for_looping_sound` | 1360 / 61 | 1376 / 61 | size, sha | P |
|
||||
|
||||
## 3. Result
|
||||
|
||||
Nothing landed. Two of the seven rows are unparked and both are measured ties or provably spelling-inert; three
|
||||
parks are ties whose known levers are already measured; two parks are blocked on one owner ruling. The wave's
|
||||
substantive result is on `_sound_refresh_looping`: a new, byte-proven structural finding that fixes the park's own
|
||||
recorded blocker (the missing relocation) in scratch and sharpens the residual to a single register-colouring fact.
|
||||
|
||||
## 4. `_sound_refresh_looping` - new structural finding (scratch only, park untouched)
|
||||
|
||||
### 4.1 The missing relocation is a source fact, not a merge accident
|
||||
|
||||
`relocdiff --count-by-target` shows January with **four** `_sound_start_fade` relocations and the parked body with
|
||||
three. The park entry itself describes this as "a compiler-merged duplicate fade-call tail". The merge is visible in
|
||||
our object: the alternate-fade call site ends `push ecx; jmp 0x3bf` and lands inside the fade-in site's push
|
||||
sequence. Its cause is the parked source's `real fade_in_time;` local: an if / else-if / else phi that is homed at
|
||||
`[ebp-0x18]` (the extra frame cell - frame 0x18 against January's 0x14) and lets both arms share one call.
|
||||
|
||||
January's bytes give the authentic shape directly (0x2d2-0x305):
|
||||
|
||||
```
|
||||
2d2 cmp word ptr [ebp+0x14], 0 ; refresh_state != _looping_sound_refresh_start
|
||||
2d7 jne 0x2e7 ; -> inaudible arm
|
||||
2d9 test byte ptr [edi], 1 ; TEST_FLAG(track->flags, _fade_in_at_start_bit)
|
||||
2dc je 0x2fb ; -> no fade, straight to the store
|
||||
2de mov ecx, [edi+8] ; track->fade_in_duration
|
||||
2e1 push -1 / push esi / push ecx / jmp 0x2f1
|
||||
2e7 mov edx, [_sound_inaudible_fade_out_time]
|
||||
2ed push -1 / push esi / push edx
|
||||
2f1 push 0 / call _sound_start_fade
|
||||
2fb mov [ebx+eax*4+0xd4], esi ; *playing_sound_index = new_sound_index
|
||||
```
|
||||
|
||||
Each arm builds its own argument triple and the two merge only at `push 0; call`. That is two source-level calls,
|
||||
no `fade_in_time` local and no `continue`; the store is the common statement after the if/else-if.
|
||||
HCEA's later build refactored this into one call with a `fade` local, so HCEA is not evidence here - January's
|
||||
relocation count is.
|
||||
|
||||
Rewriting the block that way (`scratch/workers/w3c_sound_manager/rl1.c`) gives **1120 / 43 /
|
||||
`035c62df5f0f973d`** from 1088 / 42: the relocation identity is now exact (43/43, per-target counts equal) and the
|
||||
frame is exactly January's 0x14. All 58 exact siblings are unchanged; only this park drifts; fakescan is clean.
|
||||
|
||||
### 4.2 Exit decode: the remaining 16 bytes are one colouring fact
|
||||
|
||||
January has four epilogues:
|
||||
|
||||
| Address | Form | Reached from |
|
||||
|---|---|---|
|
||||
| 0x134 | `mov al,1` | the `component_sound_count == 0` datum_delete path |
|
||||
| 0x448 | `xor al,al` | the `looping_sound_new` failure **and** the fall-through from the bottom of the enabled block |
|
||||
| 0x451 | `mov al,cl` (`mov cl,1` hoisted at 0x84, before the found test) | the stop + not-found path |
|
||||
| 0x45a | `mov al,[ebp-1]` | both disabled tests (`initialized`, `enabled`) |
|
||||
|
||||
`[ebp-1]` carries `result` at entry (`sete byte [ebp-1]` at 0x10) and is reused for `new_looping_sound`
|
||||
(`mov byte [ebp-1],0` at 0x80, `,1` at 0xa5), so `result` is dead inside the enabled block - only possible for
|
||||
locals in different nested blocks (laws_w2 A6 side law). HCEA's tail `return 0;` corroborates that the bottom of
|
||||
the enabled block is an explicit `return FALSE;`, which is what shares the `xor al,al` epilogue with the
|
||||
new-failed return; and the register-carried TRUE at 0x451 (rather than a second `mov al,1`) indicates a returned
|
||||
variable constant-folded on that path.
|
||||
|
||||
Our build colours `result` into `BL` instead of spilling it. That single decision produces every remaining
|
||||
difference: `source` is pushed out of EBX into ESI, ESI is then re-used for `definition_index` so `[ebp+0x10]` has
|
||||
to be reloaded before `looping_sound_new` (January pushes EBX at 0x93), and every `return` of a register-carried
|
||||
boolean merges with the disabled-path `mov al,bl`, collapsing January's four epilogues into three (the 16 bytes).
|
||||
|
||||
### 4.3 Shapes measured this wave (5, the whole budget)
|
||||
|
||||
| id | shape | size / relocs | verdict |
|
||||
|---|---|---|---|
|
||||
| rl1 | two separate `sound_start_fade` calls, no `fade_in_time` local, no `continue`, common store after | 1120 / 43 | best; relocs + frame exact |
|
||||
| rl2 | rl1 + early `return result` + bottom `return FALSE` | 1104 / 43 | epilogues merge further |
|
||||
| rl2a | rl1 + early `return result` only | 1104 / 43 | merges with the disabled-path exit |
|
||||
| rl2b | rl1 + bottom `return FALSE` only (HCEA-corroborated) | 1104 / 43 | merges with the early FALSE exit |
|
||||
| rl3 | rl2 + split declaration/assignment of `result` (A38 stack-home probe) | 1104 / 43 | inert |
|
||||
|
||||
### 4.4 Reopen criterion (replaces the w1 criterion)
|
||||
|
||||
A source-level fact that gives `result` a frame home shared with `new_looping_sound` at `[ebp-1]` - that is,
|
||||
`sete byte [ebp-1]` at entry with EBX left to the `source` parameter - applied on top of `rl1.c` together with
|
||||
rl2's exits (`return result` in the stop + not-found arm, `return FALSE` at the bottom of the enabled block).
|
||||
Everything else in `rl1.c` is byte-proven. Do not re-spend the five shapes above, the waveC R1-R10 fade/stop-arm
|
||||
variants, or the w1 S1-S8 return-materialisation variants.
|
||||
|
||||
### 4.5 Proposal (orchestrator; zero strict credit)
|
||||
|
||||
Re-baseline the `config/parked.json` entry for `_sound_refresh_looping` from `1088 / 42 / 4820b25c...` to
|
||||
`rl1.c`'s `1120 / 43 / 035c62df...` and land the `rl1.c` body with that edit. It is strictly closer (size +32
|
||||
toward 1136, relocation identity exact, frame exact), it resolves the mechanism the park entry itself names, and
|
||||
it deletes an unnecessary local rather than adding anything. This is not the R11 pattern: it is strictly closer
|
||||
and it is tied to the sharpened reopen criterion above.
|
||||
|
||||
## 5. The other six rows
|
||||
|
||||
### `_sound_dispose_from_old_map` (active residual, 240 / 21 vs 272 / 23)
|
||||
|
||||
Target and candidate are byte-identical through 0xa6, including the entire ten-instruction wait-loop test
|
||||
(`call _system_milliseconds; test eax,eax; mov [ebp-8],eax; fild; jge; fadd __real@4f800000; fcomp [ebp-4];
|
||||
fnstsw; test ah,5; jp exit`). January closes the loop with one `jmp 0x82` back to that test; our build duplicates
|
||||
the whole test into the latch (`jnp 0xa1`), which is the +12 instructions, +32 padded bytes and +2 relocations
|
||||
(one `_system_milliseconds`, one `__real@4f800000`). The same function shows January rotating the preceding fade
|
||||
loop into a guarded do-while, so the decision is per loop, not per function. HCEA spells the wait loop exactly as
|
||||
we do.
|
||||
|
||||
New negatives this wave: `for (; cond; ) { sound_idle(); }` (d1) and the A23 for-increment probe
|
||||
`for (; cond; sound_idle()) { }` (d2) are both byte-identical to the baseline. Together with the four earlier
|
||||
lanes (while, while + continue, `while (TRUE)` + real local, `for(;;)` + break, inline deadline, HCEA `any_sounds`
|
||||
flag, captured `paused`, definition position, whole-TU compile-order reorder) this proves the loop **spelling** is
|
||||
not the lever; the header duplication is decided after the IL. Reopen: an exact January sibling whose
|
||||
`while (call() < real)` loop keeps a single header copy, with a nameable source cause.
|
||||
|
||||
### `_refresh_listener` (active residual, 496 / 25, 178/178 instructions)
|
||||
|
||||
One transposition at the loop latch: January `mov edi,[ebp-4]; mov esi,[ebp-8]`, ours the reverse (the two loop
|
||||
IVs reloaded after `matrix4x3_inverse_transform_vector`). Detector pass over laws_w2/laws_w3: A24 does not fire
|
||||
(no parameter home is involved, both IVs own cells), A12 is about preheaders, A6 does not fire (frames are equal),
|
||||
A20 needs stores. Declaration order, in-loop declaration, void single exit, the HCEA inverted arm and a whole-TU
|
||||
compile-order reorder are already measured inert. No shape spent; criterion unchanged.
|
||||
|
||||
### `_update_channel_for_impulse_sound` (park, 528 / 29, 170/170 instructions)
|
||||
|
||||
Three ordering deltas remain inside one basic block: (a) January pre-pushes the
|
||||
`sound_definition_get_minimum_distance` argument (`mov eax,[esi+8]; push eax`) into the gain product; (b)
|
||||
`fld [esi+0x88]; fmul [edx+0x30]` against our `fld [edx+0x30]; fmul [esi+0x88]` for
|
||||
`sound->pitch * pitch_range->playback_rate` (A35 leaf age); (c) January groups the three cone loads and wedges the
|
||||
`FLT_MAX` store between the cone stores (the A4 "all loads then all stores" fingerprint). Both admissible levers
|
||||
for (b) are already measured - a source operand swap is canonicalised away (waveC I1) and the named pitch local is
|
||||
worse (waveC I2, 544) - and the only source form that would produce (c) is an aggregate copy or helper that does
|
||||
not exist in January's tag layout (an invented owner, R14/R15). Exactness is therefore unreachable through (a)/(c)
|
||||
alone, so no shape was spent.
|
||||
|
||||
### `_sound_set_definition_end` (park, 208 / 9) and `_update_channel_for_looping_sound` (park, 1360 vs 1376)
|
||||
|
||||
Both carry the same single mechanism, and laws_w3 A34 names it: January loads the `short` field
|
||||
`sound->pitch_range_index` for a call argument as `xor eax,eax; mov ax,word [esi+0x8e]` (set_definition_end 0x3c;
|
||||
looping 0x2ea), the fingerprint of a `short` prototype parameter, while `sound_definitions.h` publishes
|
||||
`long pitch_range_index`, whose C semantics force our genuine conversion `movzx`. For `_sound_set_definition_end`
|
||||
that load plus the resulting two-store shift is the *only* difference (72 vs 73 instructions);
|
||||
`_update_channel_for_looping_sound` additionally shows a frame-cell permutation and one extra `xor eax,eax`, and
|
||||
waveC measured it at exactly 1360/61 under an emulated `short` prototype. The owner ruled that prototype an ABI
|
||||
lie (the `sound_definitions.c` definition is `long` and casts every use), so both rows stay blocked on that owner
|
||||
decision; nothing in `sound_manager.c` can close them, and a mask or cast trick would be R7. When the ruling
|
||||
unblocks the looping row, also fix the behavioural defect the w1 ledger recorded in the parked body (the
|
||||
next-permutation test is nested, so the permutation advance is skipped).
|
||||
|
||||
### `_sound_find_like_channel` (park, 272 / 16, 91/91 instructions)
|
||||
|
||||
One callee-saved colouring swap (January `si`/`ebx` where we use `bx`/`esi`, including the `mov ax,si` return
|
||||
copy). No law fires; declaration order and a named channel pointer are measured inert (waveC F1-F3). No shape
|
||||
spent.
|
||||
|
||||
## 6. Checks
|
||||
|
||||
- Final real-file gate identical to baseline row for row: `== exact 58 residual 7 unwritten 0`;
|
||||
`_point_from_line3d` guard passed.
|
||||
- `scratch/parkcheck.py` on the real object: `parks 5 drift 0`.
|
||||
- `tools/fake_match_scan.py source/sound/sound_manager.c`: 0 review leads (also 0 on `rl1.c`).
|
||||
- `git diff --stat -- source/sound/sound_manager.c`: empty.
|
||||
|
||||
## 7. Disposition
|
||||
|
||||
`sound_manager.obj` stays at 58/65 strict exact; this wave claims no bytes. It leaves one actionable zero-credit
|
||||
proposal (the `_sound_refresh_looping` park re-baseline to `rl1.c`), one owner ruling that would unlock 1,568
|
||||
padded bytes across `_sound_set_definition_end` and `_update_channel_for_looping_sound`, and four rows classified
|
||||
as measured ties with their levers exhausted.
|
||||
@@ -0,0 +1,110 @@
|
||||
# StructureLensFlares (opus5 250K house-clean lane, wave w3c, 2026-09-15): residual mechanism decoded, still owner-blocked
|
||||
|
||||
Worker lane `opus/250k-house-clean-20260915`. **No production source changed.**
|
||||
`git diff --stat -- source/structures/structure_lens_flares.c` is empty; the final real-file gate equals the baseline.
|
||||
|
||||
## 1. Baseline and final (real file, whole-TU gate, `_point_from_line3d` guard passed)
|
||||
|
||||
`== exact 3 residual 1 unwritten 0 (of 4 listed)` — unchanged at the end of the wave.
|
||||
|
||||
| Row | January (padded / relocs / sha16) | Real file |
|
||||
| --- | --- | --- |
|
||||
| `_build_structure_lens_flares` (PARKED, `instruction-scheduling`) | 4336 / 156 / `40aa8e486e52fe25` | 4336 / 156 / `57d6f033f3793735`; 1327/1327 instructions, 13 differing aligned blocks |
|
||||
| `_cluster_index_from_point` | 96 / 3 | EXACT |
|
||||
| `_compare_temp_markers` | 32 / 0 | EXACT |
|
||||
| `_structure_lens_flares_place` | 16 / 2 | EXACT |
|
||||
|
||||
## 2. Duplicate prevention
|
||||
|
||||
Read: the four canonical Jonas ledgers (grid topology 0826, policy 0829, Fable uniform boundary 0830, authenticated
|
||||
fuzzy closeout 0901), the w2 ledger `structure_lens_flares_obj_opus5_150k_w2_20260914.md` and its worker notes
|
||||
`scratch/workers/structure_lens_flares_breakable_surfaces.md`, `scratch/w2/laws_w2.md`, `scratch/w3/laws_w3.md`,
|
||||
and the memory records (lens-flares 4-instruction witness, mechanism-proven parks, fast_ftol, no-fake-matching).
|
||||
`git log --all -- source/structures/structure_lens_flares.c`: 21 commits. `branch_sweep.py`: 19 unique blobs,
|
||||
14 compile-fail, the others 0-2 exact with 2-4 unwritten — **HEAD is the best blob in the corpus**. The Fable census
|
||||
(ledger 0830) covered 1,562 worktrees and 903 distinct objects with zero strict-exact bodies.
|
||||
|
||||
## 3. Residual decomposition (alndiff vs `build/split`, re-measured at this HEAD)
|
||||
|
||||
Frame layout is identical to January's: `[ebp-0x34]/-0x30/-0x2c` = `s_temp.n.i/j/k`, `[ebp-0x24]/-0x20/-0x1c` =
|
||||
`origin.x/y/z`, `[ebp-0x88]/-0x84/-0x80` = `t_plane.n.i/j/k`.
|
||||
|
||||
- **N1 @0xa65** — January `fstp [ebp-0x2c]`, then j*j, then a reload `fld [ebp-0x2c]; fmul [ebp-0x2c]`; ours forwards k
|
||||
in st(0) (`fst` + `fmul`).
|
||||
- **N2/N3/N4 @0xb05, @0xb3d, @0xbb0** — every s_temp/s_plane sum (magnitude_squared3d inside `normalize3d`,
|
||||
`s_temp.d = dot_product3d(origin, n)`, and both `plane3d_distance_to_point` sites) is **j,k,i** in January and
|
||||
**k,j,i** in ours. The t_plane sums are **k,j,i in both** and match; k is the youngest t leaf, so ours is the plain
|
||||
laws_w3 A35(2) "youngest term first" order and January's s-sums are the tie-broken ones.
|
||||
- **derivative @0xdee** — 2-byte `mov edi,edi` vs 3-byte `lea ecx,[ecx]` loop padding, a pure consequence of the 3-byte
|
||||
shift from N1; it disappears whenever N is fixed.
|
||||
- **tie A @0xe28** (`fld [ebp-0x84]` vs `mov [ebp-0x44],eax`, s-loop preheader) and **tie B @0xe6a** (`push ebx` vs
|
||||
`fadd [ebp-0x24]`, inside project_point3d's argument pushes) — int-vs-FP interleave transpositions, Fable
|
||||
dbg32b-certified DAG-creation-order tie-breaks after ~15k probes.
|
||||
|
||||
## 4. New evidence from this wave
|
||||
|
||||
1. **The marker-search statement is byte-insensitive to its spelling.** `alndiff base.obj vs f1.obj` (f1 = w2's lf_F1,
|
||||
i.e. HEAD with `point_from_line3d(&test_point, &direction, offset, &test_point)` restored) shows the two objects are
|
||||
**byte-identical from 0xdf0 to the end of the function**, with identical frame size and identical `[ebp-N]` offsets.
|
||||
The genuine inline call and HEAD's hand expansion emit exactly the same local code; the call's whole effect is a
|
||||
global IL/DAG tie-break perturbation ~1,000 bytes earlier (N1-N4 and the padding). January's bytes therefore cannot
|
||||
discriminate the two spellings locally. This is the "per-basin lottery" the Fable ledger recorded, promoted here from
|
||||
a hypothesis to a measurement, and it is the reason no COMDAT-free respelling can be argued from byte evidence.
|
||||
2. **laws_w3 A35(4) is confirmed for this function** (the law file already names this group N as its example): the hand
|
||||
expansion ages `direction`/`test_point` field names and flips the later s-sums.
|
||||
3. **A31(b) / A35(1) pointer-write routing is refuted here.** `set_real_vector3d(&direction, ...)` — the lever that
|
||||
closed breakable_surfaces' cross-product roles and `_lightning_offset_marker_position` — makes this function worse
|
||||
(13 -> 16 differing blocks) and adds a candidate-only `_set_real_vector3d` COMDAT that the January object does not
|
||||
own (census: `('code','_set_real_vector3d')` absent from target).
|
||||
4. **Premise correction to the w2 ledger.** w2 recorded the d-only plane form as blocked by "a representation cast
|
||||
(house rule)". That is void: laws_w2 section B and laws_w3 section B both ADMIT point-to-vector `(real_vector3d *)`
|
||||
casts, and `source/math/real_math.h:1325` (`plane3d_from_point_and_normal`) itself writes
|
||||
`dot_product3d((real_vector3d *)point, &plane->n)`. The d-only form is house-rule admissible; it is simply inert on
|
||||
its own. The **sole** remaining blocker for group N is the `_point_from_line3d` COMDAT.
|
||||
|
||||
## 5. Law detector pass and shapes tried (3 of 5; scratch only, siblings 3/3 exact in every probe)
|
||||
|
||||
| Probe | Shape (law) | Result |
|
||||
| --- | --- | --- |
|
||||
| `scratch/workers/w3c_structure_lens_flares/p1.c` | marker update as `test_point.x += direction.i * offset;` x3 (natural-spelling control for A35(4)) | 4336/156, 13 blocks; **function bytes identical to base** |
|
||||
| `.../p2.c` | `set_real_vector3d(&direction, ...)` initialisation (A31(b) + A35(1)) | 4336/156, **16 blocks — worse**; new candidate-only `_set_real_vector3d` owner |
|
||||
| `.../p3.c` | `s_temp.d = dot_product3d((real_vector3d const *)&origin, &s_temp.n);` alone, no `point_from_line3d` (corrected cast premise, single-plane granularity; w2's F2 tested both planes together) | 4336/156, 13 blocks; **function bytes identical to base** — VC7 fully eliminates the `plane3d_from_point_and_normal` self-copy |
|
||||
|
||||
Detectors that did not fire: A12 touches tie A but w2's P* probes already spent the six `s_grid`/`s_count`/`t_distance`
|
||||
decl-init orders in this basin (no flip); A31(a) does not apply (neither tie site is a post-call stack adjust — tie A is
|
||||
a preheader integer store against a hoisted x87 invariant, tie B is one push inside a push sequence); A24 is inert (the
|
||||
frame already equals January's); A23, A25-A30, A32-A34, A36-A45 have no hook (no unwritten row, no size/reloc delta, no
|
||||
frame gap, no switch/loop-spelling question, no C4013 site in `scratch/gate4/c4013.txt`, no static-linkage candidate, no
|
||||
`_code_` label, no alias class).
|
||||
|
||||
Not repeated (earlier waves): L1, LB1/LB2, L2/L2b, LS2-LS4, the 16-combination `POINT_DOT_VECTOR3D` lattice, F4-F6,
|
||||
G1-G3, M1/M2, K1-K4, P*, and the Fable ~15k-probe tie search.
|
||||
|
||||
## 6. Outcome
|
||||
|
||||
**NOT LANDED — OWNER-BLOCKED (group N) + SKIPPED-EXHAUSTED (ties A/B). No proposal.**
|
||||
|
||||
Strict EXACT is unreachable without emitting `_point_from_line3d`, which WORKER_BRIEF sections 0 and 9b make a lane
|
||||
rule and which laws_w3 R14 forbids re-proposing; and even with it the body stays two instruction pairs short (w2's
|
||||
lf_F3/lf_F7). Brief section 6 allows an already-written residual to land only when it becomes strict EXACT, so no
|
||||
body — however much closer — is landable here. Deliberately no orchestrator proposal: the w2 ledger already records
|
||||
this function on the `point_from_line3d` owner-ruling list.
|
||||
|
||||
## 7. Reopen criterion (revised; replaces the w2 three-clause criterion)
|
||||
|
||||
Reopen only if **both**: (a) the owner lifts the `_point_from_line3d` no-emission rule; and (b) a source lever is found
|
||||
for the two int-vs-FP transpositions at +0xe28 and +0xe6a. The w2 criterion's third clause ("a cast-free d-only plane
|
||||
spelling") is **struck**: the cast is admitted policy and the d-only form is byte-inert on its own.
|
||||
|
||||
Do **not** spend further waves searching for COMDAT-free respellings of the marker-search update. This wave proved the
|
||||
statement's local bytes are spelling-insensitive, so no byte evidence can select one, and any COMDAT-free spelling that
|
||||
happened to win the global tie-break would be an unfalsifiable lottery pick barred by the no-fake-matching gate.
|
||||
|
||||
## 8. Verification
|
||||
|
||||
- `python -B tools/campaign/gate.py source/structures/structure_lens_flares --all --forbid-emitted-symbol _point_from_line3d`:
|
||||
guard passed, `== exact 3 residual 1 unwritten 0` (equals baseline).
|
||||
- `python -B scratch/parkcheck.py source/structures/structure_lens_flares <base.obj>`: parks 1, drift 0.
|
||||
- owner census vs `build/base` and `build/split`: candidate-only `[]`, base-only `[]`.
|
||||
- `python -B tools/fake_match_scan.py source/structures/structure_lens_flares.c`: 0 review leads.
|
||||
- `git diff --stat -- source/structures/structure_lens_flares.c`: empty.
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
# `ui_widget_game_data_input_functions.obj` — opus5 250K house-clean lane, wave w3c (2026-09-15)
|
||||
|
||||
Worktree `C:\halo-worktrees\opus5-150k-house-clean-20260914`, branch `opus/250k-house-clean-20260915`.
|
||||
Worker scope: `source/interface/ui_widget_game_data_input_functions.c` only. No header, config, build or git
|
||||
operation was performed. Worker totals are not credit; only the orchestrator's full build counts.
|
||||
|
||||
**Outcome: nothing landed — honest early exit. The real file is byte-for-byte unchanged
|
||||
(`git diff --stat` empty).** The unit's only strict-reachable non-exact row is a measured block-layout tie; the
|
||||
other five rows are either accepted-semantic, csplit-alias-bound (strict exact unreachable), or a locked park whose
|
||||
recorded blocker no w2/w3 law explains.
|
||||
|
||||
## Baseline and final
|
||||
|
||||
`gate.py source/interface/ui_widget_game_data_input_functions --all --forbid-emitted-symbol _point_from_line3d`
|
||||
|
||||
| | exact | residual | unwritten | guard |
|
||||
|---|---:|---:|---:|---|
|
||||
| baseline (HEAD) | 40 | 6 | 0 | passed |
|
||||
| final (unchanged) | 40 | 6 | 0 | passed |
|
||||
|
||||
Parks: `_solo_level_select_list_update_displayed_items` — `scratch/parkcheck.py`: **parks 1, drift 0**.
|
||||
`tools/fake_match_scan.py`: 0 review leads. Owner census: unchanged (no edit).
|
||||
|
||||
| function | padded | tag | w3c verdict |
|
||||
|---|---:|---|---|
|
||||
| `_multiplayer_game_directions` | 320 | sha | NOT-LANDED — block-layout tie (A43 family), 1 new shape + 8 lab spellings |
|
||||
| `_player_profile_1wide_list_update` | 1,152 | sha | OWNER-BLOCKED — duplicate-store ruling, and reloc-identity even then (zero strict credit) |
|
||||
| `_player_profile_3wide_list_update` | 1,232 | reloc-identity | SKIPPED — accepted_ledger (semantic tier) |
|
||||
| `_player_profile_update_cache_for_nwide_list` | 272 | reloc-identity | SKIPPED-EXHAUSTED — bytes already equal; csplit alias (A45) |
|
||||
| `_solo_level_select_list_update_displayed_items` | 704 | sha | SKIPPED-EXHAUSTED — parked two-reload transposition; no law fires |
|
||||
| `_splitscreen_pregame_status_screen_update` | 1,216 | reloc-identity | SKIPPED-EXHAUSTED — bytes already equal; csplit alias (A45) |
|
||||
|
||||
There are no UNWRITTEN rows in this object, so the w3 work order started at the structural/residual rows.
|
||||
|
||||
Prior ledgers read in full: `*_obj_opus5_150k_w1_20260914.md`, `*_obj_fable_salvage_20260902.md`,
|
||||
`ui_widget_game_data_profile_fuzzy_reconciliation_20260909.md`, the park text in `config/parked.json`, plus
|
||||
`scratch/w2/laws_w2.md` and `scratch/w3/laws_w3.md` (applied as detectors to every row; see below).
|
||||
|
||||
## `_multiplayer_game_directions` (320) — the only strict-reachable row
|
||||
|
||||
w1 had already driven this to 122/122 instructions with equal size and relocations using
|
||||
`scratch/workers/ui_widget_game_data_input_functions/mgd_a.c` (the real body plus the teams `if/else` join, i.e. one
|
||||
`widget->visible = TRUE;` after the teams arms — itself the laws_w3 **A25** join-store form, confirmed by January's
|
||||
tail-duplicated per-arm stores). The single remaining hunk is block placement:
|
||||
|
||||
```
|
||||
January ours (mgd_a)
|
||||
55 cmp word [esi+0x112],di 55 cmp word [esi+0x112],di
|
||||
5c jl 0x89 <- machine arm 5c jge 0x6f <- skip over inline arm
|
||||
5e call is_splitscreen 5e .. machine arm (0x22) + ret
|
||||
.. 6f call is_splitscreen
|
||||
78 player arm (0x23) + ret 89 player arm (0x23) + ret
|
||||
89 machine arm (0x22) + ret
|
||||
```
|
||||
|
||||
Flow graph, register allocation (widget in EBX, the shared `mov edi,2` constant), relocations and every other byte
|
||||
are identical. January keeps the two test chains contiguous and emits both cold arms afterwards, player arm first.
|
||||
|
||||
### New work this wave
|
||||
|
||||
1. **f1 (A25 join-store applied to the server block)** — `scratch/workers/w3c_ui_widget_game_data_input_functions/f1.c`:
|
||||
`short string_list_index = NONE;` assigned in the two arms, then one guarded store plus `visible = TRUE`.
|
||||
Result **336 != 320 [size]**: VC7 does tail-duplicate the stores into both arms (A25 holds) but materialises the
|
||||
value in a register (`mov eax,0x22 … mov word [ebx+0x40],ax`), and the arm order does not move. Reverted.
|
||||
2. **Lab census** (`scratch/workers/w3c_ui_widget_game_data_input_functions/lab1.c`, `lab2.c`, runner `lab.py`,
|
||||
compiled with this unit's ninja cflags). `h1` reproduces our real layout exactly, so the lab is faithful.
|
||||
All of these leave the machine arm inline: else-if ladder (f2, h2 control), `while` instead of the for-increment
|
||||
teams loop (f3 — laws_w3 **A23** frequency probe), the whole teams tail removed (f4), a `visible = FALSE` exit
|
||||
inside the `if (server)` block (f5), and an extra nesting level on the splitscreen test (h3).
|
||||
`h2` (the two ifs swapped in source order) swaps the **test** order in the emitted bytes, which positively proves
|
||||
January's source order is machine-test-first — i.e. our source order is right and the difference is layout only.
|
||||
|
||||
Together with w1's five shapes (local join store, else-if, flat single-exit chain, global visible join, condition
|
||||
boolean local) that is **14 measured spellings**. Classification: block-layout tie, laws_w3 **A43** family (no source
|
||||
lever has ever moved late block/epilogue placement). laws_w3 A39's switch device does not apply (no switch; both arms
|
||||
already end in an explicit `return`), and A25/A23/A16/A26 were each tested above.
|
||||
|
||||
**Reopen criterion:** a measured law that predicts which of two cold early-return arms C2 emits first (a real
|
||||
block-frequency/placement decode), or January-side evidence that the machine arm is not a plain `if`-then in source.
|
||||
Do not re-spend shapes on if/else-if, condition booleans, join stores, nesting or loop respellings.
|
||||
|
||||
## `_player_profile_1wide_list_update` (1,152) — owner-blocked and strict-unreachable
|
||||
|
||||
Re-measured w1's shape C (`scratch/workers/ui_widget_game_data_input_functions/p1_final.c`) at this HEAD:
|
||||
**1,152/70, normalized bytes equal, tag [reloc-identity]** (the extra residual row in that gate is only because the
|
||||
file predates the landed `_network_pregame_status_screen_update` unpark).
|
||||
|
||||
Two independent reasons it cannot land in this wave:
|
||||
|
||||
1. The body depends on January's byte-proven duplicated `text[0xFF] = 0` store (default-profile valid path stores at
|
||||
+0x370 and again at +0x408). Brief section 5 prohibits duplicated stores; the w1 owner-ruling request is still open
|
||||
(laws_w3 C3 "byte-proven redundant stores/branches", the A42 family) and the 2026-09-15 rulings do not cover it.
|
||||
2. **Even with that ruling the row stays [reloc-identity]**: the remaining relocation differences are the csplit
|
||||
one-past-the-end alias at +0x1a9 and the `L""` / `"\r\n"` literal COMDATs January references undefined
|
||||
(laws_w3 **A45**). So it is worth **zero strict credit**, and brief section 6 forbids landing an already-written
|
||||
residual that does not become strict EXACT.
|
||||
|
||||
For the orchestrator: `_player_profile_3wide_list_update`, `_player_profile_update_cache_for_nwide_list` and
|
||||
`_splitscreen_pregame_status_screen_update` are all already in `build/semantic_report.json` accepted_ledger, so w1's
|
||||
semantic-credit request for the latter two is satisfied; `_player_profile_1wide_list_update` is the only alias-class
|
||||
row in this object that is uncredited, and it needs the duplicate-store ruling first.
|
||||
|
||||
## `_solo_level_select_list_update_displayed_items` (704, PARKED) — no law fires
|
||||
|
||||
Park class `instruction-scheduling`; target and parked base are both 704/45 with objdiff 99.89 %. Measured today:
|
||||
214/214 instructions with **one** transposition — the loop back-edge block at +0x9a reloads
|
||||
`mov eax,[ebp-0xc]` (item_index) then `mov edi,[ebp+8]` (list_widget) in January and the reverse in ours. The loop
|
||||
bottom is `mov eax,[ebp-0xc]; inc eax; cmp eax,3; mov [ebp-0xc],eax; jl 0x9a`, so both reloads are allocator-redundant;
|
||||
the frame (profile −0x54, index array −0x24, item_index −0xc, marker homes −0x10/−0x14/−0x18) and all 45 relocations
|
||||
already match.
|
||||
|
||||
Detectors run with no hit: A6/A33 (frame layout, block scoping — the frame is already exact), A12 (preheader invariant
|
||||
order — this is a back-edge reload block, not a preheader), A24 (parameter-home offer — no home is packed differently),
|
||||
A5 (alias removal — there is no alias), A23/A25/A39 (layout/frequency — no block moves), A35 (x87 only).
|
||||
The park's recorded cause is the shared `player_profile.h` ownership: the older exact body used a TU-local shadow
|
||||
struct, which brief section 5 prohibits, and the park text forbids source-pressure tuning. No scratch candidate was
|
||||
produced, because any edit here would be a pure two-load steering change.
|
||||
|
||||
**Reopen criterion:** a measured law predicting the order of two independent spill reloads in a loop back-edge block,
|
||||
or January-side evidence that `struct player_profile` / the `player_ui_get_active_player_profile` signature differs
|
||||
from the shared header in a way that changes allocation.
|
||||
|
||||
## Other rows
|
||||
|
||||
- `_player_profile_update_cache_for_nwide_list` (272) and `_splitscreen_pregame_status_screen_update` (1,216): landed
|
||||
byte-identical in w1; the residual tag is purely the csplit one-past-the-end alias (+0x40/+0x79 and +0x4a1
|
||||
respectively). laws_w3 A45 makes strict exact unreachable; no source work is possible or useful.
|
||||
- `_player_profile_3wide_list_update` (1,232): accepted_ledger, semantic tier, untouched.
|
||||
|
||||
## C4013 note (no action)
|
||||
|
||||
`scratch/gate4/c4013.txt` reports one implicit declaration for this unit,
|
||||
`ui_widget_game_data_input_functions.c(648) : warning C4013: 'error' undefined`. The site is inside
|
||||
`_ui_widget_game_data_function_invoke`, which is **already strict EXACT**; laws_w3 A32 records that A7 includes whose
|
||||
C4013 result is discarded or already exact are byte-inert, and E18 forbids landing byte-inert hygiene includes in a
|
||||
unit where nothing else lands. No include was added.
|
||||
|
||||
## Proposals
|
||||
|
||||
None. No header, config or owner packet is needed for any row of this object beyond the two rulings already on the
|
||||
orchestrator's list (the `_player_profile_1wide_list_update` duplicate-store ruling, which yields zero strict credit,
|
||||
and the standing park criterion for `_solo_level_select_list_update_displayed_items`).
|
||||
+87
-101
@@ -1137,11 +1137,6 @@ static void game_engine_generate_title_string(
|
||||
wchar_t *secondary_string;
|
||||
wchar_t life_string[128];
|
||||
wchar_t score_string[256];
|
||||
union
|
||||
{
|
||||
wchar_t team_names[22];
|
||||
struct postgame_statistic_entry entry;
|
||||
} branch_storage;
|
||||
long string_list_index;
|
||||
wchar_t *format_string;
|
||||
|
||||
@@ -1212,41 +1207,41 @@ static void game_engine_generate_title_string(
|
||||
{
|
||||
long did_player_win = game_engine_did_player_win(player_index);
|
||||
boolean has_teams = FALSE;
|
||||
wchar_t *outcome_string;
|
||||
|
||||
if (game_engine)
|
||||
has_teams = global_variant.has_teams;
|
||||
|
||||
if (did_player_win == NONE)
|
||||
switch (did_player_win)
|
||||
{
|
||||
case NONE:
|
||||
string_list_index =
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
ustrncpy(
|
||||
title_string,
|
||||
unicode_string_list_get_string(string_list_index, 0x37),
|
||||
80);
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
outcome_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x37);
|
||||
}
|
||||
}
|
||||
else if (did_player_win == FALSE)
|
||||
{
|
||||
else
|
||||
outcome_string = L"";
|
||||
ustrncpy(title_string, outcome_string, 80);
|
||||
break;
|
||||
|
||||
case FALSE:
|
||||
if (has_teams)
|
||||
{
|
||||
string_list_index =
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
ustrncpy(
|
||||
title_string,
|
||||
unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x38),
|
||||
80);
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
outcome_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x38);
|
||||
}
|
||||
else
|
||||
outcome_string = L"";
|
||||
ustrncpy(title_string, outcome_string, 80);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1254,37 +1249,30 @@ static void game_engine_generate_title_string(
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
ustrncpy(
|
||||
title_string,
|
||||
unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x39),
|
||||
80);
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
outcome_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x39);
|
||||
}
|
||||
else
|
||||
outcome_string = L"";
|
||||
ustrncpy(title_string, outcome_string, 80);
|
||||
}
|
||||
}
|
||||
else if (did_player_win == TRUE)
|
||||
{
|
||||
break;
|
||||
|
||||
case TRUE:
|
||||
if (has_teams)
|
||||
{
|
||||
string_list_index =
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
wchar_t *outcome_string =
|
||||
unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x3A);
|
||||
|
||||
ustrncpy(
|
||||
title_string,
|
||||
outcome_string,
|
||||
80);
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
outcome_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x3A);
|
||||
}
|
||||
else
|
||||
outcome_string = L"";
|
||||
ustrncpy(title_string, outcome_string, 80);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1292,36 +1280,30 @@ static void game_engine_generate_title_string(
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
ustrncpy(
|
||||
title_string,
|
||||
unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x3B),
|
||||
80);
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
outcome_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x3B);
|
||||
}
|
||||
else
|
||||
outcome_string = L"";
|
||||
ustrncpy(title_string, outcome_string, 80);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
ustrncpy(title_string, L"", 80);
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (game_engine && global_variant.has_teams)
|
||||
else if (game_engine && global_variant.has_teams)
|
||||
{
|
||||
wchar_t team0_name[8];
|
||||
wchar_t team1_name[8];
|
||||
long team0_score;
|
||||
long team1_score;
|
||||
|
||||
game_engine->format_team_name(
|
||||
0,
|
||||
&branch_storage.team_names[14]);
|
||||
team0_name);
|
||||
game_engine->format_team_name(
|
||||
1,
|
||||
&branch_storage.team_names[0]);
|
||||
team1_name);
|
||||
team0_score = game_engine_get_team_score(0);
|
||||
team1_score = game_engine_get_team_score(1);
|
||||
|
||||
@@ -1341,8 +1323,8 @@ static void game_engine_generate_title_string(
|
||||
title_string,
|
||||
80,
|
||||
format_string,
|
||||
&branch_storage.team_names[14],
|
||||
&branch_storage.team_names[0],
|
||||
team0_name,
|
||||
team1_name,
|
||||
secondary_string);
|
||||
}
|
||||
else if (team0_score < team1_score)
|
||||
@@ -1361,8 +1343,8 @@ static void game_engine_generate_title_string(
|
||||
title_string,
|
||||
80,
|
||||
format_string,
|
||||
&branch_storage.team_names[0],
|
||||
&branch_storage.team_names[14],
|
||||
team1_name,
|
||||
team0_name,
|
||||
secondary_string);
|
||||
}
|
||||
else
|
||||
@@ -1381,50 +1363,54 @@ static void game_engine_generate_title_string(
|
||||
title_string,
|
||||
80,
|
||||
format_string,
|
||||
&branch_storage.team_names[0],
|
||||
team1_name,
|
||||
secondary_string);
|
||||
}
|
||||
|
||||
title_string[79] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
branch_storage.entry =
|
||||
*game_engine_get_player_place(&branch_storage.entry, player_index);
|
||||
game_engine->format_player_score(player_index, score_string);
|
||||
|
||||
if (is_place_tied(&branch_storage.entry))
|
||||
{
|
||||
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
format_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x3F);
|
||||
}
|
||||
else
|
||||
format_string = L"";
|
||||
}
|
||||
else
|
||||
{
|
||||
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
struct postgame_statistic_entry entry;
|
||||
|
||||
entry =
|
||||
*game_engine_get_player_place(&entry, player_index);
|
||||
game_engine->format_player_score(player_index, score_string);
|
||||
|
||||
if (is_place_tied(&entry))
|
||||
{
|
||||
format_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x40);
|
||||
string_list_index =
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
format_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x3F);
|
||||
}
|
||||
else
|
||||
format_string = L"";
|
||||
}
|
||||
else
|
||||
format_string = L"";
|
||||
{
|
||||
string_list_index =
|
||||
tag_loaded('ustr', "ui\\multiplayer_game_text");
|
||||
if (string_list_index != NONE)
|
||||
{
|
||||
format_string = unicode_string_list_get_string(
|
||||
string_list_index,
|
||||
0x40);
|
||||
}
|
||||
else
|
||||
format_string = L"";
|
||||
}
|
||||
|
||||
usnprintf(
|
||||
title_string,
|
||||
80,
|
||||
format_string,
|
||||
get_place_string(&entry),
|
||||
score_string,
|
||||
secondary_string);
|
||||
}
|
||||
|
||||
usnprintf(
|
||||
title_string,
|
||||
80,
|
||||
format_string,
|
||||
get_place_string(&branch_storage.entry),
|
||||
score_string,
|
||||
secondary_string);
|
||||
title_string[79] = 0;
|
||||
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user