mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-23 05:00:32 +02:00
Recover Units typed debug queries
This commit is contained in:
1 parent
b0ef2704c3
commit
fdffaf4393
2 files changed
+296
No files matched your search
@@ -0,0 +1,206 @@
|
||||
# Units typed debug-query recovery (Jonas, 2026-08-24)
|
||||
|
||||
## Result and boundary
|
||||
|
||||
This bounded wave starts from exact clean cumulative Units commit
|
||||
`266fe153868887f36f6cddc230a7c1055dfe0ec5`. It authenticates the three
|
||||
remaining Claude-era exact owners whose recorded source raised a current
|
||||
natural-source policy question:
|
||||
|
||||
- `unit_export_function_values(long unit_index)`;
|
||||
- `units_debug_get_next_unit(long current_object_index)`; and
|
||||
- `units_debug_get_closest_unit(long reference_object_index)`.
|
||||
|
||||
The two debug queries have complete named typed support in the current tree.
|
||||
Their historical readable bodies were recovered with the numeric dead-bit
|
||||
test replaced by the existing `_object_dead_bit` name. Both were strict exact
|
||||
on the only code-producing candidate compile and are retained. The exporter
|
||||
is deliberately not reconstructed: Claude's complete 30-experiment ledger
|
||||
shows that its exact pointer setup depends on `_ReadWriteBarrier()` after the
|
||||
unit-definition getter. That compiler fence is outside the natural-source
|
||||
boundary. No exporter body was added or compiled in this wave.
|
||||
|
||||
The retained implementation uses no raw offset, pointer pun, union alias,
|
||||
undefined behavior, `volatile`, `_ReadWriteBarrier`, pragma/intrinsic,
|
||||
attribute, register forcing, inline assembly, byte patch, code-generation
|
||||
anchor, or comparator exception. No header, protected source, configuration,
|
||||
storage owner, completion label, semantic ledger, parked-function record, or
|
||||
pre-existing documentation is edited. The only production source edit is 90
|
||||
lines in `source/units/units.c`.
|
||||
|
||||
## Authority and evidence reviewed
|
||||
|
||||
January PC remains the byte authority. The authenticated artifacts are:
|
||||
|
||||
| artifact | bytes | SHA-256 |
|
||||
| --- | ---: | --- |
|
||||
| `cachebeta.exe` | 6,584,672 | `4cc87b45f721270392a96f1674ed2b5cd4a7bb4355faeab4531d1cf1884d9520` |
|
||||
| split `source/units/units.obj` | 138,090 | `e6a24ca597147dacff1f06806613d6bcfa4fa48f359dfbf542c34935f674b19f` |
|
||||
| corrected cumulative pre-wave object | 134,343 | `338c22c3fe456bd1056516a9c8c2b1eb6ab3a019d635f0f0c21f300308fec3ff` |
|
||||
|
||||
Before choosing source, all relevant Claude Units evidence was read: the full
|
||||
consolidated `units_obj.md` history; the dedicated
|
||||
`units_obj_export_functions.md` UEF-0 through UEF-30 record at final commit
|
||||
`751ea0bf`; the exact historical debug-query bodies at `f2f7b6b8` and
|
||||
`cee81f83`; the carrier/caller evidence; and the current Jonas Units ledgers,
|
||||
including the immediately preceding typed-declaration pair. The campaign
|
||||
README, house rules, exact-match acceleration playbook, semantic/progress,
|
||||
admission, parked, regression-gate, and hardened COFF comparator tooling were
|
||||
also reviewed before classification. Historical source is reconstruction
|
||||
evidence, not a patch authority.
|
||||
|
||||
The current `source/objects/objects.h` is Git blob
|
||||
`738c831f77a73e2dc3a1e7e9443144857c480ce8`, identical to the final Claude
|
||||
exact tree's blob. Its ordinary layout places `object.damage_flags` at datum
|
||||
offset `0xB6`; `_object_dead_bit` is the named value two. The unit extension
|
||||
begins at `0x1A4`, so its first two typed longs are
|
||||
`unit.actor_index` at `0x1A4` and `unit.swarm_actor_index` at `0x1A8`.
|
||||
The repository already independently asserts the actor offset in `ai.c`.
|
||||
Thus every target access is expressible through a current named field; no
|
||||
header or layout edit is required. The strict first-shot result below is an
|
||||
additional emitted-code proof of those mappings.
|
||||
|
||||
## January target, relocations, and callers
|
||||
|
||||
The three target sections are independently fingerprinted as follows:
|
||||
|
||||
| January owner | meaningful / padded | relocs | normalized SHA-256 |
|
||||
| --- | ---: | ---: | --- |
|
||||
| `_unit_export_function_values` | 380 / 384 | 18 | `4149e4cd513cba59c251998986db6acd8857e41f96d6182b9692023361b20c35` |
|
||||
| `_units_debug_get_next_unit` | 228 / 240 | 8 | `5098e32812b1e3e53fcb6201a48145c446f16b5ca7146f3bcee4c7bb29632879` |
|
||||
| `_units_debug_get_closest_unit` | 197 / 208 | 6 | `de1f11019c5719a10ef09ec6987d302764cebcc2f9ffdb78fd2747254870034c` |
|
||||
|
||||
The next-unit relocations are exclusively two iterator initializations and
|
||||
six iterator advances. The closest-unit relocations are one iterator
|
||||
initialization, three advances, two origin queries, and the zero-real COMDAT;
|
||||
`distance3d` is naturally inlined. The exporter calls
|
||||
`object_get_and_verify_type`, `tag_get` twice, and
|
||||
`tag_block_get_element_with_size`, with the remaining relocations accounting
|
||||
for its real constants and internal jump table.
|
||||
|
||||
The exporter is address-taken by the January `_unit_data_definition` callback
|
||||
table in `source/objects/object_types.obj` (relocation offset 212). The two
|
||||
debug functions have no same-TU caller; both are called by January
|
||||
`_code_000a79c0` in `source/game/player_control.obj` (relocation offsets 364
|
||||
and 374). These uses agree with ordinary external cdecl definitions. No
|
||||
prototype or ABI invention is needed.
|
||||
|
||||
## Why the exporter fails closed
|
||||
|
||||
Claude's UEF matrix establishes the exporter's complete behavior and nearly
|
||||
all of its natural lowering. UEF-1 through UEF-7 exhaust ordinary typed
|
||||
pointer initializers, assignments, declaration order, constness, and typed
|
||||
member/`offsetof` address forms. The best natural setup remains 384 bytes and
|
||||
18 relocations but schedules the independent output pointer and getter result
|
||||
differently from January. UEF-8 first makes that setup byte-exact only by
|
||||
placing `_ReadWriteBarrier()` immediately after the definition getter.
|
||||
UEF-9 through UEF-30 then resolve the independent signed-short comparison
|
||||
shape while retaining that fence; the final exact source at `751ea0bf` still
|
||||
contains it.
|
||||
|
||||
The record therefore supplies no policy-clean natural source packet for this
|
||||
owner. Raw `+0xB6`, a barrier, volatile forcing, attributes, register/lifetime
|
||||
forcing, or a new unsupported source-shape sweep would merely restate a
|
||||
closed code-generation problem. The exporter remains absent and receives no
|
||||
compile attempt or credit in this wave.
|
||||
|
||||
## One-shot typed adjudication
|
||||
|
||||
The two debug bodies were frozen together before emission. `git diff --check`
|
||||
passed, and a real VC7 `/Zs` parse-only invocation succeeded without touching
|
||||
the copied baseline object. The next code-producing action was exactly one
|
||||
normal Units production compile:
|
||||
|
||||
```text
|
||||
[1/1] RUN configure.py
|
||||
[1/2] CL build\base\source\units\units.obj
|
||||
units.c
|
||||
```
|
||||
|
||||
`configure.py` is the generator edge; there was exactly one Units code
|
||||
emission. The immutable first-shot candidate object is 135,341 bytes with
|
||||
SHA-256
|
||||
`9bd0c61cf76e79bc31d18229baca148ee40861e00a18e2b0b91ad88f168c43ea`.
|
||||
The frozen source hashes as Git blob
|
||||
`26a4f43aebcb230a7e3100ad0a29a52b7276ecab`.
|
||||
|
||||
Strict padded-byte, relocation-masked hash, and complete relocation
|
||||
address/type/destination/addend comparison produced:
|
||||
|
||||
| January owner | result | padded | relocs | normalized SHA-256 |
|
||||
| --- | --- | ---: | ---: | --- |
|
||||
| `_units_debug_get_next_unit` | retain, strict exact | 240 | 8 | `5098e32812b1e3e53fcb6201a48145c446f16b5ca7146f3bcee4c7bb29632879` |
|
||||
| `_units_debug_get_closest_unit` | retain, strict exact | 208 | 6 | `de1f11019c5719a10ef09ec6987d302764cebcc2f9ffdb78fd2747254870034c` |
|
||||
|
||||
The strict gain is two functions, 425 meaningful bytes, 448 padded bytes,
|
||||
and 14 exact relocations. There was no retry, pruning, or source tuning.
|
||||
|
||||
## Corrected baseline and whole-object preservation
|
||||
|
||||
The initially copied integration-lane `build/base` object was stale: it
|
||||
contained two in-progress exact bodies that are not present in tracked commit
|
||||
`266fe153`. Treating that artifact as the baseline would have falsely
|
||||
reported a two-function loss. It was rejected before acceptance. The corrected
|
||||
baseline is the clean committed replay object from the preceding typed-pair
|
||||
lane. Its source blob is exactly `3fd40fa3885b465b0169d86ae3ac506304a508c8`,
|
||||
which is also the tracked `units.c` blob at `266fe153`; its object identity is
|
||||
the `338c22c3...` row above. The emitted candidate itself was never replaced
|
||||
or recompiled during this correction.
|
||||
|
||||
Against that authenticated baseline, the established 189-owner hardened
|
||||
census advances from 158 exact / 11 emitted nonexact / 20 absent to 160 exact
|
||||
/ 11 emitted nonexact / 18 absent. The exact-set delta is precisely the two
|
||||
debug queries, and no inherited exact owner is lost.
|
||||
|
||||
The complete 129-section January runtime-data census is unchanged at 121
|
||||
strict exact / two present nonexact / six absent. A separate candidate versus
|
||||
baseline runtime-owner A/B contains 180 owners on each side: all 180 are
|
||||
common, none is added or removed, and every acceptance fingerprint is
|
||||
identical. Writable `.data` remains 1,564 bytes, seven relocations, normalized
|
||||
SHA-256 `6ed61c39a648905cf23b12b916e2adadfe97b6e5aa492c29a14c7265809ef1a7`;
|
||||
`_unit_globals` remains four BSS bytes, zero relocations, with no raw payload.
|
||||
There is no `.data`, `.bss`, COMMON, aggregate, literal, or storage-owner
|
||||
change and no data credit is claimed.
|
||||
|
||||
## Pre-commit gates
|
||||
|
||||
- Full `halobetacache_build libcmt_build`: pass, all 568 catch-up edges. The
|
||||
frozen Units object was up to date and did not recompile; warnings were
|
||||
inherited from unrelated translation units.
|
||||
- Authenticated local csplit and objdiff report generation: pass. The report
|
||||
is 1,573,188 bytes with SHA-256
|
||||
`01e2fade84abc9d1bc74b48244842e62bf259ec042bfebf0aca2fe0f40dc9e5f`.
|
||||
- Semantic audit: 470 units, 4,228 functions evaluated, 4,087 semantic exact,
|
||||
110 hidden exact, 4,148 accepted exact, and zero unit errors.
|
||||
- Campaign progress: 375/833 objects, 4,126/11,060 functions, and 500,656
|
||||
accepted code bytes.
|
||||
- Object admission: zero candidates and zero revocations; only the inherited
|
||||
unrelated `shell_xbox` completion-label contradiction remains.
|
||||
- Parked validation: three active, zero stale, zero invalid.
|
||||
- Complete tooling suite: 179/179 tests pass.
|
||||
- Source scope, policy scan, target/caller audit, data/ownership A/B,
|
||||
`git diff --check`, and changed/deleted-path review: pass.
|
||||
|
||||
The compiler is Microsoft VC7 `13.00.9254.1`; `xbox/bin/vc7/CL.Exe` is
|
||||
81,920 bytes with SHA-256
|
||||
`483e00c47bb08d699475a642bcff15b5b2036350b31c540e88a506baf101da11`.
|
||||
The natural `/nologo /c /O2 /Oy- /DDEBUG /Dxbox` production rule and include
|
||||
graph are unchanged.
|
||||
|
||||
The copied Ninja log tried to refresh already-installed downloader edges when
|
||||
the report phony target was invoked, but sandboxed network was unavailable.
|
||||
No source or object changed. The already-authenticated installed csplit and
|
||||
objdiff binaries were invoked directly, after which semantic/progress and all
|
||||
other gates passed. This operational detail grants no exception.
|
||||
|
||||
## Commit/replay boundary
|
||||
|
||||
This initial record claims only the frozen one-shot evidence above. The next
|
||||
steps are to commit exactly `source/units/units.c` and this new ledger as
|
||||
Jonas; capture a clean implementation-state regression manifest; verify that
|
||||
the generated object resolves under this isolated worktree; delete only that
|
||||
object; perform one normal same-path rebuild; and immediately rerun the full
|
||||
regression gate, direct two-name comparison, complete 189/129 censuses,
|
||||
runtime-owner A/B, and no-work dry run. Actual replay evidence will be
|
||||
appended to this ledger in one additive ledger-only commit. No amend, push,
|
||||
history rewrite, configuration change, or worktree removal is authorized.
|
||||
@@ -3415,6 +3415,96 @@ void unit_detach_from_parent(
|
||||
return;
|
||||
}
|
||||
|
||||
long units_debug_get_next_unit(
|
||||
long current_object_index)
|
||||
{
|
||||
struct object_iterator iterator;
|
||||
struct unit_datum *unit;
|
||||
long result = NONE;
|
||||
|
||||
if (current_object_index != NONE)
|
||||
{
|
||||
object_iterator_new(&iterator, _object_mask_unit, 0);
|
||||
|
||||
while ((unit = (struct unit_datum *)object_iterator_next(&iterator)) != NULL)
|
||||
{
|
||||
if (iterator.index == current_object_index)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while ((unit = (struct unit_datum *)object_iterator_next(&iterator)) != NULL)
|
||||
{
|
||||
if (unit->unit.actor_index == NONE &&
|
||||
unit->unit.swarm_actor_index == NONE &&
|
||||
!TEST_FLAG(unit->object.damage_flags, _object_dead_bit))
|
||||
{
|
||||
result = iterator.index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == NONE)
|
||||
{
|
||||
object_iterator_new(&iterator, _object_mask_unit, 0);
|
||||
|
||||
while ((unit = (struct unit_datum *)object_iterator_next(&iterator)) != NULL)
|
||||
{
|
||||
if (unit->unit.actor_index == NONE &&
|
||||
unit->unit.swarm_actor_index == NONE &&
|
||||
!TEST_FLAG(unit->object.damage_flags, _object_dead_bit))
|
||||
{
|
||||
return iterator.index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
long units_debug_get_closest_unit(
|
||||
long reference_object_index)
|
||||
{
|
||||
struct object_iterator iterator;
|
||||
struct object_datum *object;
|
||||
long closest_index = NONE;
|
||||
real closest_distance = REAL_MAX;
|
||||
|
||||
object_iterator_new(&iterator, _object_mask_biped, 0);
|
||||
while ((object = (struct object_datum *)object_iterator_next(&iterator)) != NULL)
|
||||
{
|
||||
if (iterator.index != reference_object_index &&
|
||||
!TEST_FLAG(object->object.damage_flags, _object_dead_bit))
|
||||
{
|
||||
real distance;
|
||||
|
||||
if (reference_object_index != NONE)
|
||||
{
|
||||
real_point3d reference_origin;
|
||||
real_point3d object_origin;
|
||||
|
||||
object_get_origin(reference_object_index, &reference_origin);
|
||||
object_get_origin(iterator.index, &object_origin);
|
||||
distance = distance3d(&reference_origin, &object_origin);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = 0.f;
|
||||
}
|
||||
|
||||
if (distance < closest_distance)
|
||||
{
|
||||
closest_index = iterator.index;
|
||||
closest_distance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest_index;
|
||||
}
|
||||
|
||||
boolean unit_get_current_flashlight_state(
|
||||
long unit_index)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user