diff --git a/config/common_pool_credit.json b/config/common_pool_credit.json new file mode 100644 index 00000000..8d64918b --- /dev/null +++ b/config/common_pool_credit.json @@ -0,0 +1,783 @@ +{ + "schema": "common-pool-credit/1", + "unit": "source/linker_common", + "category": "halobetacache", + "extent_model": "objdiff-3.3.1-combined", + "unit_total_data": 1272664, + "verifier": { + "path": "tools/common_pool_verify.py", + "sha256_lf": "6ca08d007b3a95608e449b4e44a06a5d792a710349c32513a8366a17b044c8be" + }, + "reader": { + "path": "tools/coff_compare.py", + "sha256_lf": "df0004d83c548ed82cd4afe66306ccf9dafbc83e6998fafe23047c3a82ecedd7" + }, + "ledger": { + "path": "research/remaining_frontier_20260926/q10/common_pool_ledger.json", + "sha256_lf": "da1c65de445aac977ed4c14257d929d9c1ada1a1c40e88a573d8688c33300e7f" + }, + "xdk_manifest": { + "path": "research/remaining_frontier_20260926/q10/xdk3911_lib_manifest.json", + "sha256_lf": "1b8a8350bd456bd61efea345970b793ca7ae8b554f9f63d5a0111571a47ebe3b" + }, + "xdk_lib_dir": "C:/tmp/xdk3911_extract/XDK/xbox/lib", + "linked_libraries_not_in_extract": [ + "binkxbox.lib", + "dsstrmh.lib" + ], + "credit": { + "records": 93, + "raw": 660645, + "padding": 367, + "total": 661012 + }, + "reason": "Owner ruling Q10 FINAL (2026-09-28): 'Approve all 85 PASS records - as bounded, per-record COMMON storage credit.' Approved as FULL + v1.4 with the owner's four required additions (Q10 additions): the COFF reader tools/coff_compare.py pinned and bound into the receipt; bytes by tag, raw versus padding and the largest record's share in progress; the binkxbox/dsstrmh list in the credit receipt; L1 trust root 8; and the string-only verifier wording re-pin. The reviewed 85-record allowlist is frozen: records that pass later earn nothing until a separate approval lists them (the four CV-B' records, which passed but were unlisted at Q10 FINAL, are listed by EXT1 below). January's linker pools every COMMON (tentative) record into one '* Linker *' contribution (cachebeta.pdb module 847), which the split exposes as source/linker_common; objdiff has no rebuilt object for it and credits none of its data. tools/common_pool_verify.py (RF-DM, reviewed by RF-DP and RF-DX), run on every progress with --xdk-lib-dir and its pinned XDK manifest (OQ-DM2), reports these 85 Halo records PASS: January's name, size, pool slot and COMMON class equal exactly one tentative definition in our objects, and that definer is the ledger's evidence owner; provenance tag inferred (60) or probable (25), never January-proven. Each earns its objdiff-3.3.1-combined extent share: 657,245 raw + 311 objdiff padding = 657,556 halobetacache data bytes, split into 8,444 inferred (8,220 raw + 224 padding) and 649,112 probable (649,025 raw + 87 padding); one probable record, _render, is 643,744 of it (643,732 raw + 12 padding). PASS-OWNER-UNRESOLVED, FAIL, unlisted PASS, vendor and linker records earn nothing; vendor and linker records keep the categories 38f82c59 gave them. source/linker_common stays MISSING: no whole-pool Matching claim and no function, object, completion or denominator change. OQ-DM1: binkxbox.lib and dsstrmh.lib, linked by January but absent from the XDK 3911 extract, cannot be scanned (accepted, disclosed; carried in every credit receipt). Allowlist extension EXT1 (owner ruling Q-EV1, 2026-09-29: 'approve EXT1 + the proposed wording, conditional on an independent check and fresh full gates at the landing HEAD'; packet research/remaining_frontier_20260926/workers/RF-EV/PACKET_ALLOWLIST_EXT.md; independent check RF-EY, verdict LAND): 8 records that became qualifying PASS after the Q10 FINAL review through zero-credit landings follow the frozen 85 in pool order: _sound_class_data (CP-T B1 6d1040e6, inferred); _debug_sound_cache (CV-B' 0dcdf006, probable); _assertion_count (CV-B' 0dcdf006, probable); _debug_sound_reference_counts (CV-B' 0dcdf006, probable); _wind_globals (CP-T B2 cfe97640, inferred); _build_sprite_globals (CP-T B4 16a33aad, inferred); _light_data (CV-B' 0dcdf006, probable); _glow_globals (CP-T B5 b6d60163, inferred). They earn their objdiff-3.3.1-combined shares under the same verifier, reader, ledger and manifest pins: +3,456 = 3,400 raw + 56 padding (inferred 3,440 = 3,392 raw + 48 padding; probable 16 = 8 raw + 8 padding). The entry now credits 93 records: 660,645 raw + 367 objdiff padding = 661,012 halobetacache data bytes, split into 11,884 inferred (11,612 raw + 272 padding) and 649,128 probable (649,033 raw + 95 padding); _render is 643,744 of it (97.4%). Two records that pass stay unlisted by their own rulings and earn nothing: _debug_sound_channels (Q-B2: 'Keep it outside Q10's credit allowlist') and _director_camera_scripted (B7: 'remain outside the Q10 allowlist'; Q-EV2: 'Standing exclusion, until explicitly revisited').", + "scope": "This lifts Q10 only for those 85 records and the 8 records of allowlist extension EXT1 under this verification contract. It does not certify January ownership, complete pool layout, or a matching executable link.", + "limitation": "L1: pinning prevents unnoticed changes to reviewed assumptions; it does not prove those assumptions or January ownership. The ledger's readout provenance and the XDK manifest are trust roots checked only by their pinned hashes; the verifier checks our tree against January and the libraries, never January's owner. Pins are not protection against a compromised execution environment: the Python interpreter, its module search path and bytecode cache, the unpinned progress code and the generated build outputs are trust roots too (L1 trust root 8).", + "records": [ + { + "symbol": "_debug_looping_sound", + "rva": "0x4e41a1", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/sound/sound_manager.c" + }, + { + "symbol": "_debug_sound", + "rva": "0x4e41a2", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/sound/sound_manager.c" + }, + { + "symbol": "_loud_dialog_hack", + "rva": "0x4e41a3", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/sound/sound_manager.c" + }, + { + "symbol": "_sound_channels", + "rva": "0x4e41c0", + "size": 6144, + "share": 6160, + "tag": "inferred", + "owner": "source/sound/sound_manager.c" + }, + { + "symbol": "_looping_sound_data", + "rva": "0x4e59c0", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/sound/sound_manager.c" + }, + { + "symbol": "_sound_data", + "rva": "0x4e59c4", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/sound/sound_manager.c" + }, + { + "symbol": "_combined_pas", + "rva": "0x4ed2c0", + "size": 64, + "share": 92, + "tag": "inferred", + "owner": "source/sound/game_sound.c" + }, + { + "symbol": "_game_sound_globals", + "rva": "0x4ed300", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/sound/game_sound.c" + }, + { + "symbol": "_game_looping_sound_data", + "rva": "0x4ed304", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/sound/game_sound.c" + }, + { + "symbol": "_recover_saved_games_hack", + "rva": "0x4ed308", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/saved games/game_state.c" + }, + { + "symbol": "_stun_enable", + "rva": "0x4ed318", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/units/units.c" + }, + { + "symbol": "_debug_damage_taken", + "rva": "0x4ed319", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/units/units.c" + }, + { + "symbol": "_debug_unit_illumination", + "rva": "0x4ed31a", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/units/units.c" + }, + { + "symbol": "_debug_unit_animations", + "rva": "0x4ed31b", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/units/units.c" + }, + { + "symbol": "_debug_unit_all_animations", + "rva": "0x4ed31c", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/units/units.c" + }, + { + "symbol": "_file_location_volume_names", + "rva": "0x4ed320", + "size": 512, + "share": 536, + "tag": "probable", + "owner": "source/tag_files/files.c" + }, + { + "symbol": "_debug_fog_planes", + "rva": "0x4ed520", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/structures/structures.c" + }, + { + "symbol": "_structures_use_pvs_for_vs", + "rva": "0x4ed521", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/structures/structure_visibility.c" + }, + { + "symbol": "_debug_portals", + "rva": "0x4ed522", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/structures/structure_visibility.c" + }, + { + "symbol": "_debug_leaf_portals", + "rva": "0x4ed523", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/structures/structure_render.c" + }, + { + "symbol": "_global_game_globals", + "rva": "0x4ee2f4", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/scenario/scenario.c" + }, + { + "symbol": "_global_bsp3d", + "rva": "0x4ee2f8", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/scenario/scenario.c" + }, + { + "symbol": "_global_collision_bsp", + "rva": "0x4ee2fc", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/scenario/scenario.c" + }, + { + "symbol": "_global_structure_bsp", + "rva": "0x4ee300", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/scenario/scenario.c" + }, + { + "symbol": "_global_scenario", + "rva": "0x4ee304", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/scenario/scenario.c" + }, + { + "symbol": "_debug_sprites", + "rva": "0x4ee308", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/render/render_sprite.c" + }, + { + "symbol": "_cached_object_render_states", + "rva": "0x4ee34c", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/render/render_objects.c" + }, + { + "symbol": "_debug_input", + "rva": "0x4ee351", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/render/render_debug.c" + }, + { + "symbol": "_debug_bsp", + "rva": "0x4ee352", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/render/render_debug.c" + }, + { + "symbol": "_render", + "rva": "0x4ee360", + "size": 643732, + "share": 643744, + "tag": "probable", + "owner": "source/render/render.c" + }, + { + "symbol": "_debug_point_physics", + "rva": "0x58dc40", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/physics/point_physics.c" + }, + { + "symbol": "_node_count", + "rva": "0x590b40", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/physics/bsp3d.c" + }, + { + "symbol": "_global_object_marker", + "rva": "0x590b48", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/objects/objects.c" + }, + { + "symbol": "_noncollideable_object_cluster_partition", + "rva": "0x590b50", + "size": 12, + "share": 24, + "tag": "inferred", + "owner": "source/objects/objects.c" + }, + { + "symbol": "_collideable_object_cluster_partition", + "rva": "0x590b60", + "size": 12, + "share": 16, + "tag": "inferred", + "owner": "source/objects/objects.c" + }, + { + "symbol": "_object_header_data", + "rva": "0x590b70", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/objects/objects.c" + }, + { + "symbol": "_first_object_type_definition", + "rva": "0x590b74", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/objects/object_types.c" + }, + { + "symbol": "_debug_lights", + "rva": "0x590b78", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/objects/object_lights.c" + }, + { + "symbol": "_debug_object_lights", + "rva": "0x590b79", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/objects/object_lights.c" + }, + { + "symbol": "_debug_rasterizer_light_count", + "rva": "0x590b7a", + "size": 2, + "share": 4, + "tag": "inferred", + "owner": "source/objects/object_lights.c" + }, + { + "symbol": "_lights_globals", + "rva": "0x590b80", + "size": 848, + "share": 872, + "tag": "inferred", + "owner": "source/objects/object_lights.c" + }, + { + "symbol": "_light_cluster_partition", + "rva": "0x590ed0", + "size": 12, + "share": 16, + "tag": "inferred", + "owner": "source/objects/object_lights.c" + }, + { + "symbol": "_debug_damage", + "rva": "0x590ee0", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/objects/damage.c" + }, + { + "symbol": "_widget_data", + "rva": "0x590ee4", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/objects/widgets/widgets.c" + }, + { + "symbol": "_flag_data", + "rva": "0x590ef0", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/objects/widgets/flags.c" + }, + { + "symbol": "_antenna_data", + "rva": "0x590ef4", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/objects/widgets/antenna.c" + }, + { + "symbol": "_network_game_server_memory_do_not_use_directly", + "rva": "0x590f00", + "size": 1212, + "share": 1232, + "tag": "probable", + "owner": "source/networking/network_server_manager.c" + }, + { + "symbol": "_network_game_client_dont_use_directly", + "rva": "0x5913c0", + "size": 3248, + "share": 3264, + "tag": "probable", + "owner": "source/networking/network_client_manager.c" + }, + { + "symbol": "_debug_render_freeze", + "rva": "0x592075", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/main/main.c" + }, + { + "symbol": "_local_player_index_for_draw_string_and_hack_in_icons", + "rva": "0x59227c", + "size": 2, + "share": 4, + "tag": "inferred", + "owner": "source/interface/ui_widget.c" + }, + { + "symbol": "_ui_plasma_effect_color", + "rva": "0x592280", + "size": 16, + "share": 28, + "tag": "inferred", + "owner": "source/interface/ui_widget.c" + }, + { + "symbol": "_blip_player_index", + "rva": "0x592496", + "size": 2, + "share": 4, + "tag": "inferred", + "owner": "source/interface/motion_sensor.c" + }, + { + "symbol": "_center_point", + "rva": "0x5924a0", + "size": 8, + "share": 8, + "tag": "inferred", + "owner": "source/interface/motion_sensor.c" + }, + { + "symbol": "_hud_msg_def", + "rva": "0x5924ac", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/interface/hud_messaging.c" + }, + { + "symbol": "_temporary_hud", + "rva": "0x5924b0", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/interface/hud.c" + }, + { + "symbol": "_object_list_data", + "rva": "0x5924b4", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/hs/object_lists.c" + }, + { + "symbol": "_object_list_header_data", + "rva": "0x5924b8", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/hs/object_lists.c" + }, + { + "symbol": "_debug_trigger_volumes", + "rva": "0x5924bc", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/hs/hs_runtime.c" + }, + { + "symbol": "_debug_scripting", + "rva": "0x5924bd", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/hs/hs_runtime.c" + }, + { + "symbol": "_hs_global_data", + "rva": "0x5924e0", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/hs/hs_runtime.c" + }, + { + "symbol": "_hs_thread_data", + "rva": "0x5924e4", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/hs/hs_runtime.c" + }, + { + "symbol": "_hs_syntax_data", + "rva": "0x5924e8", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/hs/hs.c" + }, + { + "symbol": "_players_globals", + "rva": "0x5924ec", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/game/players.c" + }, + { + "symbol": "_team_data", + "rva": "0x5924f0", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/game/players.c" + }, + { + "symbol": "_player_data", + "rva": "0x5924f4", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/game/players.c" + }, + { + "symbol": "_global_default_animation_colors", + "rva": "0x592500", + "size": 48, + "share": 72, + "tag": "inferred", + "owner": "source/game/game_engine_king.c" + }, + { + "symbol": "_global_default_animation_values", + "rva": "0x592530", + "size": 16, + "share": 16, + "tag": "inferred", + "owner": "source/game/game_engine_king.c" + }, + { + "symbol": "_weather_particle_data", + "rva": "0x5926bc", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/effects/weather_particle_systems.c" + }, + { + "symbol": "_system_particles", + "rva": "0x5926c4", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/effects/particle_systems.c" + }, + { + "symbol": "_particle_systems", + "rva": "0x5926c8", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/effects/particle_systems.c" + }, + { + "symbol": "_effect_location_data", + "rva": "0x5926cc", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/effects/effects.c" + }, + { + "symbol": "_debug_decals", + "rva": "0x5926d4", + "size": 1, + "share": 4, + "tag": "inferred", + "owner": "source/effects/decals.c" + }, + { + "symbol": "_temporary", + "rva": "0x592f20", + "size": 256, + "share": 256, + "tag": "probable", + "owner": "source/cseries/cseries.c" + }, + { + "symbol": "_pursuit_data", + "rva": "0x59308c", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/ai/encounters.c" + }, + { + "symbol": "_encounter_data", + "rva": "0x593090", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/ai/encounters.c" + }, + { + "symbol": "_platoon_array", + "rva": "0x593094", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/ai/encounters.c" + }, + { + "symbol": "_squad_array", + "rva": "0x593098", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/ai/encounters.c" + }, + { + "symbol": "_global_communication_table_indices", + "rva": "0x61a320", + "size": 114, + "share": 124, + "tag": "inferred", + "owner": "source/ai/ai_communication.c" + }, + { + "symbol": "_swarm_component_data", + "rva": "0x61a3bc", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/ai/actors.c" + }, + { + "symbol": "_swarm_data", + "rva": "0x61a3c0", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/ai/actors.c" + }, + { + "symbol": "_actor_data", + "rva": "0x61a3c4", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/ai/actors.c" + }, + { + "symbol": "_avoidance_rays", + "rva": "0x61a3e0", + "size": 448, + "share": 468, + "tag": "inferred", + "owner": "source/ai/actor_moving.c" + }, + { + "symbol": "_avoidance_directions", + "rva": "0x61a5a0", + "size": 96, + "share": 96, + "tag": "inferred", + "owner": "source/ai/actor_moving.c" + }, + { + "symbol": "_sense_rays", + "rva": "0x61a600", + "size": 252, + "share": 256, + "tag": "inferred", + "owner": "source/ai/actor_moving.c" + }, + { + "symbol": "_global_temporary_render_color", + "rva": "0x61a700", + "size": 16, + "share": 16, + "tag": "inferred", + "owner": "source/ai/actions.c" + }, + { + "symbol": "_sound_class_data", + "rva": "0x4ed2ac", + "size": 4, + "share": 4, + "tag": "inferred", + "owner": "source/sound/sound_classes.c" + }, + { + "symbol": "_debug_sound_cache", + "rva": "0x4ed309", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/cache/xbox_sound_cache.c" + }, + { + "symbol": "_assertion_count", + "rva": "0x4ed30a", + "size": 2, + "share": 4, + "tag": "probable", + "owner": "source/cache/xbox_sound_cache.c" + }, + { + "symbol": "_debug_sound_reference_counts", + "rva": "0x4ed30c", + "size": 1, + "share": 4, + "tag": "probable", + "owner": "source/cache/xbox_sound_cache.c" + }, + { + "symbol": "_wind_globals", + "rva": "0x4ed5e0", + "size": 3340, + "share": 3360, + "tag": "inferred", + "owner": "source/scenario/wind.c" + }, + { + "symbol": "_build_sprite_globals", + "rva": "0x4ee320", + "size": 40, + "share": 64, + "tag": "inferred", + "owner": "source/render/render_sprite.c" + }, + { + "symbol": "_light_data", + "rva": "0x590edc", + "size": 4, + "share": 4, + "tag": "probable", + "owner": "source/objects/object_lights.c" + }, + { + "symbol": "_glow_globals", + "rva": "0x590ee8", + "size": 8, + "share": 12, + "tag": "inferred", + "owner": "source/objects/widgets/glow.c" + } + ] +} diff --git a/config/data_category_reassignments.json b/config/data_category_reassignments.json new file mode 100644 index 00000000..13b5242f --- /dev/null +++ b/config/data_category_reassignments.json @@ -0,0 +1,228 @@ +{ + "categories": [ + { + "id": "linker", + "name": "linker" + } + ], + "entries": [ + { + "unit": "source/linker_common", + "from_category": "halobetacache", + "extent_model": "objdiff-3.3.1-combined", + "unit_total_data": 1272664, + "moved": { + "dsound": 4, + "libcmt": 880, + "linker": 96, + "xapilib": 308 + }, + "reason": "Accounting correction only, not matching progress (owner ruling 2026-09-27, 'Denominator correction'). January's linker pools every COMMON record and two linker-generated .rdata records into one '* Linker *' contribution (PDB module 847), which config lists as the Halo unit source/linker_common. 27 of its records are vendor COMMON (their XDK library members define them COMMON and January links those members) and 2 are the linker's debug directory and CodeView record; this moves their objdiff-3.3.1 extents (1,125 + 88 raw bytes, 1,192 + 96 as objdiff sizes them) out of the Halo data denominator. Halo COMMON (213 records) stays in halobetacache; the All denominator, matched bytes, functions, units and verdicts are unchanged. Q10 remains held: this entry earns and removes no credit.", + "records": [ + { + "symbol": "_rdata_00242ed0", + "section": ".rdata", + "size": 28, + "to_category": "linker", + "evidence": "linker-generated: IMAGE_DEBUG_DIRECTORY (PE data directory 6, type 2 CODEVIEW)" + }, + { + "symbol": "_rdata_002b6a2c", + "section": ".rdata$debug", + "size": 60, + "to_category": "linker", + "evidence": "linker-generated: CodeView NB10 record (c:\\halo\\objects\\halobetacache\\cachebeta.pdb)" + }, + { + "symbol": "_OHCD_GlobalPool", + "section": ".bss", + "size": 48, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member pool.obj defines it COMMON 48 B; January links that member (PDB module 495, xapilib.lib)" + }, + { + "symbol": "_OHCD_InterruptObject", + "section": ".bss", + "size": 112, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member ohcd.obj defines it COMMON 112 B; January links that member (PDB module 494, xapilib.lib)" + }, + { + "symbol": "_XapiAutoPowerDownGlobals", + "section": ".bss", + "size": 80, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member powerdwn.obj defines it COMMON 80 B; January links that member (PDB module 510, xapilib.lib)" + }, + { + "symbol": "_CheckHeapFillPattern", + "section": ".bss", + "size": 16, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member heap.obj defines it COMMON 16 B; January links that member (PDB module 531, xapilib.lib)" + }, + { + "symbol": "_NtGlobalFlag", + "section": ".bss", + "size": 4, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member heap.obj defines it COMMON 4 B; January links that member (PDB module 531, xapilib.lib)" + }, + { + "symbol": "___@@_PchSym_@00@UcylcRurmzouivUkirezgvUmglhUczkrUpDCUoryUlyqUrDIGUyzhvwooOlyq@Xapi_k32", + "section": ".bss", + "size": 4, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member basedll.obj defines it COMMON 4 B; January links that member (PDB module 5, xapilib.lib)" + }, + { + "symbol": "_XapiProcessHeap", + "section": ".bss", + "size": 4, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member xapiheap.obj defines it COMMON 4 B; January links that member (PDB module 504, xapilib.lib)" + }, + { + "symbol": "_XapiCurrentTopLevelFilter", + "section": ".bss", + "size": 4, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member thread.obj defines it COMMON 4 B; January links that member (PDB module 507, xapilib.lib)" + }, + { + "symbol": "_XapiTlsSize", + "section": ".bss", + "size": 4, + "to_category": "xapilib", + "evidence": "vendor COMMON: XDK 3911 xapilib.lib member thread.obj defines it COMMON 4 B; January links that member (PDB module 507, xapilib.lib)" + }, + { + "symbol": "___@@_PchSym_@00@UcylcRurmzouivUkirezgvUdrmwldhUwrivxgcUwhlfmwUwhlfmwUlyqUrDIGUwhlfmwrOlyq@dsound", + "section": ".bss", + "size": 4, + "to_category": "dsound", + "evidence": "vendor COMMON: XDK 3911 dsound.lib member dsoundi.obj defines it COMMON 4 B; January links that member (PDB module 1, dsound.lib)" + }, + { + "symbol": "___mblcid", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 4 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "___ptmbcinfo", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 4 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "___ismbcodepage", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 4 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "__mbctype", + "section": ".bss", + "size": 257, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 257 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "___mbcodepage", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 4 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "___mbulinfo", + "section": ".bss", + "size": 24, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 24 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "__mbcasemap", + "section": ".bss", + "size": 256, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member mbctype.obj defines it COMMON 256 B; January links that member (PDB module 776, LIBCMT.lib)" + }, + { + "symbol": "___active_heap", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member heapinit.obj defines it COMMON 4 B; January links that member (PDB module 803, LIBCMT.lib)" + }, + { + "symbol": "___ptd_glob", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member tidtable.obj defines it COMMON 4 B; January links that member (PDB module 750, LIBCMT.lib)" + }, + { + "symbol": "__nhandle", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member ioinit.obj defines it COMMON 4 B; January links that member (PDB module 780, LIBCMT.lib)" + }, + { + "symbol": "___pioinfo", + "section": ".bss", + "size": 256, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member ioinit.obj defines it COMMON 256 B; January links that member (PDB module 780, LIBCMT.lib)" + }, + { + "symbol": "___piob", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member _file.obj defines it COMMON 4 B; January links that member (PDB module 741, LIBCMT.lib)" + }, + { + "symbol": "__nstream", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member _file.obj defines it COMMON 4 B; January links that member (PDB module 741, LIBCMT.lib)" + }, + { + "symbol": "___env_initialized", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member crt0dat.obj defines it COMMON 4 B; January links that member (PDB module 756, LIBCMT.lib)" + }, + { + "symbol": "___onexitend", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member crt0dat.obj defines it COMMON 4 B; January links that member (PDB module 756, LIBCMT.lib)" + }, + { + "symbol": "___onexitbegin", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member crt0dat.obj defines it COMMON 4 B; January links that member (PDB module 756, LIBCMT.lib)" + }, + { + "symbol": "___mbctype_initialized", + "section": ".bss", + "size": 4, + "to_category": "libcmt", + "evidence": "vendor COMMON: XDK 3911 libcmt.lib member crt0dat.obj defines it COMMON 4 B; January links that member (PDB module 756, LIBCMT.lib)" + } + ] + } + ] +} diff --git a/config/parked.json b/config/parked.json index 992c755b..1dae785a 100644 --- a/config/parked.json +++ b/config/parked.json @@ -23,8 +23,8 @@ { "unit": "source/units/bipeds", "function": "_biped_check_discard", - "class": "instruction-scheduling", - "evidence": "Best complete typed ordinary-C discard check retained from January control flow, relocation topology, diagnostic strings and HCEA semantic corroboration. Target and candidate share the 176-byte padded envelope and all 10 relocation identities; the remaining normalized-code difference is the formatted diagnostic argument evaluation order. No barrier, volatile/register forcing, pragma, assembly, fake dependency or nonsensical branch is retained. This is zero-credit fuzzy source. Reopen only with authoritative January source/local records or a natural same-compiler donor explaining that evaluation order. See docs/object_matching_logs/bipeds_obj_batch7_exact_and_fuzzy_20260912.md.", + "class": "unclassified", + "evidence": "Park reason corrected 2026-09-29 (owner ruling Q-EU1): original varargs argument position; reachable, unbounded formatting. January passes the actor description as the last argument of error(2, format, name, x, y, z, description) while the format expects it second in \"(%s)\" (January 0x5903a0; the Sept-25 and Oct-12-2001 debug builds; /Od 0x8bdd20). The remaining difference is that argument position, not evaluation order or instruction scheduling, so the class is corrected from instruction-scheduling to unclassified (no codegen mechanism is claimed). Our source keeps the correct order: January's order makes an unbounded vsprintf read the low dword of (double)x as a string pointer on a reachable gameplay path, and _error_silent continues, so it falls outside the bounded or halting original-bug exceptions. RF-EU's exact form A1 (+176 B, 0 losses) is preserved as research only, zero credit (research/remaining_frontier_20260926/workers/RF-EU). Earlier evidence: Best complete typed ordinary-C discard check retained from January control flow, relocation topology, diagnostic strings and HCEA semantic corroboration. Target and candidate share the 176-byte padded envelope and all 10 relocation identities; the remaining normalized-code difference is the formatted diagnostic argument evaluation order. No barrier, volatile/register forcing, pragma, assembly, fake dependency or nonsensical branch is retained. This is zero-credit fuzzy source. Reopen only with authoritative January source/local records or a natural same-compiler donor explaining that evaluation order. See docs/object_matching_logs/bipeds_obj_batch7_exact_and_fuzzy_20260912.md.", "measurements": { "target": { "size": 176, @@ -217,7 +217,7 @@ "unit": "source/bungie_net/network/transport_endpoint_set_winsock", "function": "_poll_endpoint_set", "class": "unclassified", - "evidence": "Complete natural January endpoint-set poll reconstructed with its real typed comparator: compact holes, rebuild stock XDK fd_set, clear cached readability, select with word timeout times MILLISECONDS_PER_SECOND, and mark ready endpoints. Correct owner headers provide the endpoint layout and Winsock error API. January's negative select-result branch is preserved without manufacturing its redundant subsequent comparison; its unguarded all-NULL tail compaction is target-proven and explicitly documented as an original defect, not claimed safe. Established short return ABI is retained. Target560B/16relocs versus candidate512B/16; natural allocation/control-flow differences remain. All inherited exact owners and nonce park unchanged, no extra code/COMMON/no point_from_line3d. No compiler controls, false types, fake branches or spelling search. Reopen only for authentic source/type/compiler-context evidence. See docs/object_matching_logs/transport_endpoint_set_winsock_obj_set_operations_cluster_20260904.md. Re-measured 2026-09-23 (Lane D refresh): single-exit result local and per-use set->ep_array[endpoint_index] reloads (the shape January uses in add_endpoint_to_set) bring the body to the target's 560-byte size; the remaining difference is the SOCKET_ERROR tail compare (13 spellings tried, none exact). No /Od body exists for this Xbox path.", + "evidence": "Complete natural January endpoint-set poll reconstructed with its real typed comparator: compact holes, rebuild stock XDK fd_set, clear cached readability, select with word timeout times MILLISECONDS_PER_SECOND, and mark ready endpoints. Correct owner headers provide the endpoint layout and Winsock error API. January's negative select-result branch is preserved without manufacturing its redundant subsequent comparison; its unguarded all-NULL tail compaction is target-proven and explicitly documented as an original defect, not claimed safe. Established short return ABI is retained. Target560B/16relocs versus candidate512B/16; natural allocation/control-flow differences remain. All inherited exact owners and nonce park unchanged, no extra code/COMMON/no point_from_line3d. No compiler controls, false types, fake branches or spelling search. Reopen only for authentic source/type/compiler-context evidence. See docs/object_matching_logs/transport_endpoint_set_winsock_obj_set_operations_cluster_20260904.md. Re-measured 2026-09-23 (Lane D refresh): single-exit result local and per-use set->ep_array[endpoint_index] reloads (the shape January uses in add_endpoint_to_set) bring the body to the target's 560-byte size; the remaining difference is the SOCKET_ERROR tail compare (13 spellings tried, none exact). No /Od body exists for this Xbox path. 2026-09-29 (owner ruling Q-EU2): RF-EU's staging-boolean form s7 is exact (+560 B, 0 losses; it matches the Oct-12-2001 2276P and Sept-25 retail builds) but stays held under AB #9: the immediately tested boolean encodes no test order, and the cross-build matches and IL trace do not independently establish that staging local. It is preserved as research only, zero credit (research/remaining_frontier_20260926/workers/RF-EU); the earlier 'none exact' note is superseded by this sentence.", "measurements": { "target": {"size": 560, "relocation_count": 16, "normalized_sha256": "4a0375522c8a3ff103c5dad92342325f3a41658e90dead5cdcd60d92a8f79f4b"}, "base": {"size": 560, "relocation_count": 16, "normalized_sha256": "9d3107ab7fad24e0717363451d4934edf5df22eb6cd360f0a3b7ab1b1f45ed61"}, @@ -448,7 +448,7 @@ "unit": "source/cache/xbox_sound_cache", "function": "_sound_cache_debug_render", "class": "tu-context-optimization", - "evidence": "Fuzzy-parked under the current house rule with the complete debug page-usage renderer retained in ordinary typed C. Target and candidate share the 368-byte padded envelope and all 14 relocation identities in semantic order. Moving the four debug colors under the debug predicate naturally recovered January's flag/color prefix; the remaining packet is the nested-loop local/register schedule and the equivalent private render helper ECX/EDX allocation. Declaration and scope permutations either reproduce this fixed point or worsen the broader stream. No volatile/register forcing, barrier, pragma, forced inline, assembly, fake dependency, undefined behavior, or nonsensical control flow is retained. Reopen only for authoritative January source/local records, an authenticated compiler/QFE difference, or a natural same-compiler donor that explains the private-helper ABI and nested-loop lifetimes together. Re-measured 2026-09-16: the static helper render_inverse_transform_screen_point became strict exact (add_vectors3d origin), which restores January's private register convention at this caller's call site; the caller body is unchanged and still non-exact (368 bytes / 14 relocations).", + "evidence": "Fuzzy-parked under the current house rule with the complete debug page-usage renderer retained in ordinary typed C. Target and candidate share the 368-byte padded envelope and all 14 relocation identities in semantic order. Moving the four debug colors under the debug predicate naturally recovered January's flag/color prefix; the remaining packet is the nested-loop local/register schedule and the equivalent private render helper ECX/EDX allocation. Declaration and scope permutations either reproduce this fixed point or worsen the broader stream. No volatile/register forcing, barrier, pragma, forced inline, assembly, fake dependency, undefined behavior, or nonsensical control flow is retained. Reopen only for authoritative January source/local records, an authenticated compiler/QFE difference, or a natural same-compiler donor that explains the private-helper ABI and nested-loop lifetimes together. Re-measured 2026-09-16: the static helper render_inverse_transform_screen_point became strict exact (add_vectors3d origin), which restores January's private register convention at this caller's call site; the caller body is unchanged and still non-exact (368 bytes / 14 relocations). 2026-09-27 P-S2 rebaseline (owner-approved, zero credit): the /Od-shaped body (fifty-objects od2; /Od 0x51c780 helper calls already landed as P-S1) replaces the previous body: 116/119 instructions aligned (was 61/119); size 368 and 14 relocations unchanged; base 8ae719b831e3e4705e309f751bbe7567e5ba96cb62d0dbc23278205dc7ccb5d3 / objdiff 86.260506 -> 6b7a4944 / 98.9916. Still residual: the dot product's k-term needs exactly +4 zero-code class-4 records before vec.j's field descriptor, which no first-party source names (RF-DJ); none invented. `short page_index = rows * x` narrows long->short as the /Od imul + 16-bit store shows (C4244 disclosed, no cast); scalar names descriptive, aggregate names /Od RTC-attested.", "measurements": { "target": { "size": 368, @@ -458,9 +458,9 @@ "base": { "size": 368, "relocation_count": 14, - "normalized_sha256": "8ae719b831e3e4705e309f751bbe7567e5ba96cb62d0dbc23278205dc7ccb5d3" + "normalized_sha256": "6b7a4944931a17255b7a7ffaa1f740c07eeab4344bd478ef2cb460a2aa5e2d88" }, - "objdiff_percent": 86.260506 + "objdiff_percent": 98.9916 } }, { @@ -543,7 +543,7 @@ "unit": "source/rasterizer/xbox/rasterizer_xbox_environment", "function": "_rasterizer_environment_specular_spot_light_begin", "class": "register-allocation", - "evidence": "Fuzzy-parked after retaining the complete HCEA-backed spot-light vector and cross-product implementation in ordinary C. January is 960 padded bytes and the candidate 944, with all 64 relocations shared and objdiff at 82.64557 percent. The remaining difference is compiler vector/local allocation and scheduling, not absent renderer behavior; bounded helper and declaration-shape probes did not close it. The source uses project real/vector types and existing math helpers and preserves the January inline schedule without emitting point_from_line3d. No forced inline/noinline, volatile steering, barrier, pragma, assembly, fake arithmetic, raw address, or undefined behavior is retained. Reopen only for authoritative January source/local records or a natural same-compiler donor that explains the vector lifetime schedule.", + "evidence": "Fuzzy-parked after retaining the complete HCEA-backed spot-light vector and cross-product implementation in ordinary C. January is 960 padded bytes and the candidate 944, with all 64 relocations shared and objdiff at 82.64557 percent. The remaining difference is compiler vector/local allocation and scheduling, not absent renderer behavior; bounded helper and declaration-shape probes did not close it. The source uses project real/vector types and existing math helpers and preserves the January inline schedule without emitting point_from_line3d. No forced inline/noinline, volatile steering, barrier, pragma, assembly, fake arithmetic, raw address, or undefined behavior is retained. Reopen only for authoritative January source/local records or a natural same-compiler donor that explains the vector lifetime schedule. 2026-09-27 DA_P1 rebaseline (owner-approved, zero credit): the Aug-15-2001 build (same compiler) compiles this function instruction-for-instruction as the /Od-shaped body with the TU's REAL_MATH_EXTERNAL_SCALE_VECTOR3D define removed (248/248; RF-DA); landed that form. Base moves 944 B / d103843e / objdiff 84.097046 -> 960 B (January's size and frame) / 5099673942f1... / 98.48101, relocations 64 unchanged. Still residual: six x87 products of the inlined cross_product3d need the inline parameter records at IDs == 0 / 7 (mod 8) (today 6 / 5), an Aug->Sept source edit with no other footprint. Reopen on first-party evidence of that edit.", "measurements": { "target": { "size": 960, @@ -551,11 +551,11 @@ "normalized_sha256": "e0331f6b94a74f9c4b4cc2fbed6d8a0cf3d0e3b8d65c487daeac0b7a0e4ab7af" }, "base": { - "size": 944, + "size": 960, "relocation_count": 64, - "normalized_sha256": "d103843ee5f01bad8837e5f3476a8be4de753efdfac7295730c4f47f337533ba" + "normalized_sha256": "5099673942f195f1d208c1c5ee664c9e0e7825418be7c25fd5003bfdba51494e" }, - "objdiff_percent": 84.097046 + "objdiff_percent": 98.48101 } }, { diff --git a/config/semantic_data_matches.json b/config/semantic_data_matches.json index 38005f03..9940b4f5 100644 --- a/config/semantic_data_matches.json +++ b/config/semantic_data_matches.json @@ -21817,5 +21817,1310 @@ } } ] + }, + { + "unit": "source/main/main", + "symbol": "_global_difficulty_level", + "allow_incomplete_unit": true, + "reason": "January and the rebuilt object have identical 52-byte main .data: bytes outside relocations, all 10 relocation sites and types, and independently resolved destinations (the scenario-name literals, provider-proved in ui_widget). CM-P1 (55829429) names the .data+12 symbol January's split lacked (scenario_paths, a later-build HCEX name). objdiff 3.3.1 undercredits the section through its '$'-name relocation defect (RF-CM D_q11probe_main). Owner ruling 2026-09-27: main's +52 data only, after full gates with zero exact-function losses; no code or object credit (main stays NonMatching).", + "measurements": { + "size": 52, + "relocation_count": 10, + "normalized_sha256": "7f308100e81271b591bc1567117e51f624f5a3c28a65a476ce574b23a3f305a6" + } + }, + { + "unit": "source/ai/actions", + "group": "actions-objdiff331-literal-relocations", + "extent_model": "objdiff-3.3.1-combined", + "allow_incomplete_unit": true, + "reason": "objdiff-cli 3.3.1 (sha1 3130e4288d483d259d1588092c8159f8e0230e08) scores these byte-identical data sections below 100% because its data relocation comparator treats the '$' in every MSVC string-literal name (??_C@...?$AA@) as a Metrowerks unique-ID separator, so identical relocation targets compare unequal and fall back to an address test inside objdiff's synthetic combined section, whose COMDAT order differs (docs/objdiff_data_relocation_defect_20260922.md; fixed upstream in 3.6.0). The group holds all 46 target sections of the report sections .data 16 B, .rdata 2,388 B; each is section_infos_equal to the rebuilt object (bytes and relocation addresses, types, destinations and addends) with identical flags, alignment and owner. extent_model objdiff-3.3.1-combined reproduces the reported extents: same-named sections in objdiff order, running offset aligned to max(alignment, 4) after each section, a lone section at its raw size, alignment code 0 = 16 (re-checked independently at e89357ff on all 833 units of the build report: research/remaining_frontier_20260926/workers/RF-BS/evidence/C11_extent_board.json). objdiff's raw report still lists 4 unmatched function(s), hence allow_incomplete_unit; the entry credits data only. The rebuilt object adds 15 select-any literal COMDAT section(s) to these report sections; each is listed in 'surplus' with a pinned snapshot and its unique January provider unit, is proved identical to that provider's January and rebuilt copies, and earns no credit. 13 of them are January undefined references of this unit. The other 2 (__real@3f800000, __real@3f1a36e2e0000000) are named nowhere in January's object: each is a read-only constant reached only through the rebuilt select-any helper _normalize2d, which January's object imports and whose single January definer is that same provider (source/ai/action_charge); the provider's January and rebuilt copies of the helper are byte-, relocation- and image-address-identical to ours and reference, relocation for relocation, constants identical to ours (surplus-helper constant rule, RF-CO research packet). Every member also has an identical section symbol table, COMDAT selection, relocation linkage class and image-address-resolved relocation list in both objects, and the live report must equal a fresh report of the current objects from the sha256-pinned scorer. Credit 2,404 B = 2,338 raw January section bytes + 66 objdiff alignment padding (reported separately, rule 55).", + "members": [ + { + "symbol": "_global_action_functions", + "measurements": { + "target": { + "section": ".rdata", + "size": 888, + "padded_size": 888, + "flags": 1077936192, + "relocation_count": 96, + "normalized_sha256": "b4bd37bc3750a724b625c0254a2b8bc3272c1aff70c71ae46952bac6acd4a9ab", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 888, + "padded_size": 888, + "flags": 1077936192, + "relocation_count": 96, + "normalized_sha256": "b4bd37bc3750a724b625c0254a2b8bc3272c1aff70c71ae46952bac6acd4a9ab", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_05NONFCOJF@avoid?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "def816c1b9723474173002aa7106e71d817e221d7bfd8567d723b42d1d1092ad", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "def816c1b9723474173002aa7106e71d817e221d7bfd8567d723b42d1d1092ad", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_08KNPIOEIC@converse?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 9, + "padded_size": 12, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "1ec12d5583af2dc443815d9ca1b1371037cbbac0c76a9e11535f7c0de3290f4a", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 9, + "padded_size": 12, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "1ec12d5583af2dc443815d9ca1b1371037cbbac0c76a9e11535f7c0de3290f4a", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_04DHBBMIC@obey?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ec3679c8614c72aebe9daaa12e1d7729430171f532ea6f7fbc64748bbc36292d", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ec3679c8614c72aebe9daaa12e1d7729430171f532ea6f7fbc64748bbc36292d", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_06MBMIPGD@charge?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 7, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ea94589dc703acc65a25a230d94490d2d92145b0b2f1c959a1158e5bfa640256", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 7, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ea94589dc703acc65a25a230d94490d2d92145b0b2f1c959a1158e5bfa640256", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_07CJDNLGID@vehicle?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "dac31f374d4c7f15885d7f8312730bfc3796b1e4062c1590cf3738038a4a8efa", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "dac31f374d4c7f15885d7f8312730bfc3796b1e4062c1590cf3738038a4a8efa", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_04PNOAOIAG@wait?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "3d241f3ec83dbd0f5e2e0971fb30376e0cac9ff4f2412c85236bc32cf3134aec", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "3d241f3ec83dbd0f5e2e0971fb30376e0cac9ff4f2412c85236bc32cf3134aec", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_06GFPLNGOC@search?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 7, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "18bde97e3f382ede75c86c5273d2011ff9e918c51a0aba96c8f187159216a9bf", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 7, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "18bde97e3f382ede75c86c5273d2011ff9e918c51a0aba96c8f187159216a9bf", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_05LPIAIMPK@guard?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "60b4cfa713cfea8b15c2b21a7923af38fa8047c9dcab1cce8b59fcf8656c6523", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "60b4cfa713cfea8b15c2b21a7923af38fa8047c9dcab1cce8b59fcf8656c6523", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_07CNKHPIEN@uncover?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "c60bd8e817c5e1bef8b11c68990a8d6982c7765fc7be94f0ef1f97d9d1f2fbff", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "c60bd8e817c5e1bef8b11c68990a8d6982c7765fc7be94f0ef1f97d9d1f2fbff", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_04IMJFEJN@flee?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "564e2e747dc190dc6adac412c6ab4c6a61abfa79711a001f514b423d8a1d59ea", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "564e2e747dc190dc6adac412c6ab4c6a61abfa79711a001f514b423d8a1d59ea", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_05KPNEEOPH@fight?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "37956b5b2d4f9be16d30677f780c2bda11c1915ff2fa983f819d7524266019d3", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "37956b5b2d4f9be16d30677f780c2bda11c1915ff2fa983f819d7524266019d3", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_05MBIJBPBC@alert?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "4f895aeba58cf5a8ee96c6a46c04b2ee12f3cb1727a84c48ceae1b52bd9d886d", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "4f895aeba58cf5a8ee96c6a46c04b2ee12f3cb1727a84c48ceae1b52bd9d886d", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_05PCJCMMHD@sleep?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "720d4cd786150e6b352215f795a86f20e5cdcf3b8156099562b1d124e471c1b0", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 6, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "720d4cd786150e6b352215f795a86f20e5cdcf3b8156099562b1d124e471c1b0", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_04CGFJFPFD@none?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fdbb9db68f1db204d7823d5cbd2ff3eee530677fc945b6304356e1c6658b9ca2", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 5, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fdbb9db68f1db204d7823d5cbd2ff3eee530677fc945b6304356e1c6658b9ca2", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0EH@CGNGLHPB@squad_absolute_index?$DO?$DN0?5?$CG?$CG?5squad@", + "measurements": { + "target": { + "section": ".rdata", + "size": 71, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "a96864664289ddb4a7607e2d044a91992b514da74caf48135021cfeacc34a8f2", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 71, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "a96864664289ddb4a7607e2d044a91992b514da74caf48135021cfeacc34a8f2", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0GB@EMHNKODG@squad_index?$DO?$DN0?5?$CG?$CG?5squad_index?$DMMA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 97, + "padded_size": 104, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "5c48f8298bf00b849cf6ef6653ef2a6c342571633b32800dc5a8d75465632c20", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 97, + "padded_size": 104, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "5c48f8298bf00b849cf6ef6653ef2a6c342571633b32800dc5a8d75465632c20", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0BP@NJNCCKKA@c?3?2halo?2source?2ai?2encounters?4h?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 31, + "padded_size": 32, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "24507aa61759a57f4acd85280dbe49545c2a695fd27760a355fb87d6a3ddd31f", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 31, + "padded_size": 32, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "24507aa61759a57f4acd85280dbe49545c2a695fd27760a355fb87d6a3ddd31f", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0EO@IKFFOKNJ@?$CIactor?9?$DOstate?4action?5?$DO?$DN?50?$CJ?5?$CG?$CG?5?$CIa@", + "measurements": { + "target": { + "section": ".rdata", + "size": 78, + "padded_size": 80, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "33c46d0333bc6dba8af5e7dcb30606f0c2e8f93091271d704f6aa8f228072113", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 78, + "padded_size": 80, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "33c46d0333bc6dba8af5e7dcb30606f0c2e8f93091271d704f6aa8f228072113", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0BM@GPCMGMOB@c?3?2halo?2SOURCE?2ai?2actions?4c?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 28, + "padded_size": 28, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "af3331eae4b74efe402e852217d42d0ff7ad605fa20995cb57028aad6a4b65da", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 28, + "padded_size": 28, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "af3331eae4b74efe402e852217d42d0ff7ad605fa20995cb57028aad6a4b65da", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0FE@KHFDCMPI@?$CIactor?9?$DOstimuli?4panic_type?5?$DN?$DN?50?$CJ@", + "measurements": { + "target": { + "section": ".rdata", + "size": 84, + "padded_size": 88, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "d1f696c578cfea6f5564161da1eb57f67c7fecddc9fb8d667592bf778b2a7e33", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 84, + "padded_size": 88, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "d1f696c578cfea6f5564161da1eb57f67c7fecddc9fb8d667592bf778b2a7e33", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0CI@KJFLMANP@actor?9?$DOtarget?4target_prop_index?5@", + "measurements": { + "target": { + "section": ".rdata", + "size": 40, + "padded_size": 40, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "d2313f9755dd05a8fd4335ee177bb033153c69e5ab13c2f85fea91f9a6197808", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 40, + "padded_size": 40, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "d2313f9755dd05a8fd4335ee177bb033153c69e5ab13c2f85fea91f9a6197808", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0CL@GADKCBCF@actor?9?$DOstate?4action?5?$DN?$DN?5_actor_ac@", + "measurements": { + "target": { + "section": ".rdata", + "size": 43, + "padded_size": 44, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "66c0042dd8de3c4c1404d7df5e38c06771f7c4f7b1a14746aa2c62e425300a9b", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 43, + "padded_size": 44, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "66c0042dd8de3c4c1404d7df5e38c06771f7c4f7b1a14746aa2c62e425300a9b", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0ED@CKGDDGIN@global_action_functions?$FLnew_acti@", + "measurements": { + "target": { + "section": ".rdata", + "size": 67, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "e8517cb0187e6c3da4c127124410f005af480db10583f4986d1cc14485b9de37", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 67, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "e8517cb0187e6c3da4c127124410f005af480db10583f4986d1cc14485b9de37", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0EG@OMPPNNLA@?$CInew_action_type?5?$DO?$DN?50?$CJ?5?$CG?$CG?5?$CInew_a@", + "measurements": { + "target": { + "section": ".rdata", + "size": 70, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "f83ae503b7ee40294298aa8531d9d123f5cc079b6675cfc8de21f3f6dabb48e9", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 70, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "f83ae503b7ee40294298aa8531d9d123f5cc079b6675cfc8de21f3f6dabb48e9", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_07CIFAGBMG@unknown?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "4c5b832482cb7cfb6ee1586012d5aa48a335bc1b00bffae8b63c59f058fe0dda", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "4c5b832482cb7cfb6ee1586012d5aa48a335bc1b00bffae8b63c59f058fe0dda", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0CO@OBMELGHJ@actor?9?$DOstimuli?4panic_prop_index?5@", + "measurements": { + "target": { + "section": ".rdata", + "size": 46, + "padded_size": 48, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "01518b36b6a2e775c424ec77b232f6bbe50074dff611a335be8eb2f5ecc4fc90", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 46, + "padded_size": 48, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "01518b36b6a2e775c424ec77b232f6bbe50074dff611a335be8eb2f5ecc4fc90", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@40c00000", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fedcca07b1ccdacce623cb6d8afdeed0314e8508d763e228871f18d4e0ebb7c4", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fedcca07b1ccdacce623cb6d8afdeed0314e8508d763e228871f18d4e0ebb7c4", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@40400000", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ea2845900b5856c9bf354b1aa9761b5aa6888e5ed61738fe9579ca42bc0f6054", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ea2845900b5856c9bf354b1aa9761b5aa6888e5ed61738fe9579ca42bc0f6054", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0FG@OAJOJGLC@escape_direction_reference?5?$CG?$CG?5es@", + "measurements": { + "target": { + "section": ".rdata", + "size": 86, + "padded_size": 88, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "31bf59da45ba1d98ed9d94b483bd82e95a214fa899faaac65d4b1ad48ddf3292", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 86, + "padded_size": 88, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "31bf59da45ba1d98ed9d94b483bd82e95a214fa899faaac65d4b1ad48ddf3292", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@be99999a", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "7789e3a0f83ccd29ff3405eeb59cf2fc8f09a5e275f557def60de0f24ecf893d", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "7789e3a0f83ccd29ff3405eeb59cf2fc8f09a5e275f557def60de0f24ecf893d", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3d088889", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "c5fd575aaff8d1a1afc8a3410d0e195364aef9d29ec13f623d0c37506f183b2b", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "c5fd575aaff8d1a1afc8a3410d0e195364aef9d29ec13f623d0c37506f183b2b", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0DJ@MMBFFLAI@actor?9?$DOdanger_zone?4danger_type?5?$DO@", + "measurements": { + "target": { + "section": ".rdata", + "size": 57, + "padded_size": 60, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "c2aadf1e1fa3d1589d6bbe018963072e5bf20bb1f628656fd8e59f7b61dd8070", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 57, + "padded_size": 60, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "c2aadf1e1fa3d1589d6bbe018963072e5bf20bb1f628656fd8e59f7b61dd8070", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0CL@HAGOODCI@actor?9?$DOstate?4action?5?$DN?$DN?5_actor_ac@", + "measurements": { + "target": { + "section": ".rdata", + "size": 43, + "padded_size": 44, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "923f280c4f0a370ee5f0c2c8d0323246a0c24822de797dd0341d2b7066859822", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 43, + "padded_size": 44, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "923f280c4f0a370ee5f0c2c8d0323246a0c24822de797dd0341d2b7066859822", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0KG@MODGEEMN@?$CBactor?9?$DOstate?4action_data?4charge@", + "measurements": { + "target": { + "section": ".rdata", + "size": 166, + "padded_size": 168, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "3c3d664e50813a016ad15e704bf141dda201198a49808df69ae7383b428980ea", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 166, + "padded_size": 168, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "3c3d664e50813a016ad15e704bf141dda201198a49808df69ae7383b428980ea", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0DD@BHCNCEDG@?$CBactor?9?$DOstate?4action_data?4charge@", + "measurements": { + "target": { + "section": ".rdata", + "size": 51, + "padded_size": 52, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "2e31cd108238a5dceb6a69014816b54213c5a7ec1e0e8f35f031d3a0c8aa2078", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 51, + "padded_size": 52, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "2e31cd108238a5dceb6a69014816b54213c5a7ec1e0e8f35f031d3a0c8aa2078", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0CM@BKKPPKIL@actor?9?$DOstate?4action?5?$DN?$DN?5_actor_ac@", + "measurements": { + "target": { + "section": ".rdata", + "size": 44, + "padded_size": 44, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "29c6c99d994594c275c385cc70a621531b1e6fe694e3788fd8cd9262e0159ea7", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 44, + "padded_size": 44, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "29c6c99d994594c275c385cc70a621531b1e6fe694e3788fd8cd9262e0159ea7", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_07IPNMCAN@success?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fbc937978dc408356b468ec3d328d7f8de5f4ef82b66b243e42166c89bdb8a51", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fbc937978dc408356b468ec3d328d7f8de5f4ef82b66b243e42166c89bdb8a51", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0EG@EGFAACLG@handled?5?$HM?$HM?5?$CIactor_action_class?$CIa@", + "measurements": { + "target": { + "section": ".rdata", + "size": 70, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "5500016094cb0f9d0d8709d222e4cddf852fa162a002f3ea75eac39233b28fa4", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 70, + "padded_size": 72, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "5500016094cb0f9d0d8709d222e4cddf852fa162a002f3ea75eac39233b28fa4", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_09FGCFOJPF@encounter?$AA@", + "measurements": { + "target": { + "section": ".rdata", + "size": 10, + "padded_size": 12, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "9c9d97947cda5658b9d7d71ce8689469e4b666046d3b496da0bb717752a9eb17", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 10, + "padded_size": 12, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "9c9d97947cda5658b9d7d71ce8689469e4b666046d3b496da0bb717752a9eb17", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0CF@BPNEOJLI@evade_direction?5?$DN?$DN?5_actor_evade_@", + "measurements": { + "target": { + "section": ".rdata", + "size": 37, + "padded_size": 40, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "78c894c09953ff427e4064c8539aa45c4350b1bc07793971d050f23ce4fdd8f9", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 37, + "padded_size": 40, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "78c894c09953ff427e4064c8539aa45c4350b1bc07793971d050f23ce4fdd8f9", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_0FC@DABHPCKC@?$CIpossibility?9?$DOanimation_directio@", + "measurements": { + "target": { + "section": ".rdata", + "size": 82, + "padded_size": 88, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "ce3c77ee57822e99a57f592571da39cd28120121618f332f85ead64b1d3f485d", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 82, + "padded_size": 88, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "ce3c77ee57822e99a57f592571da39cd28120121618f332f85ead64b1d3f485d", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@40e00000", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ee0a6628f97214b7ef5d15c54388ea478862369e517aa4ef4593aea18c3ff618", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "ee0a6628f97214b7ef5d15c54388ea478862369e517aa4ef4593aea18c3ff618", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@42340000", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "9f026d3444cc513ec1ff6522fa56bf3e019d158c785f07c12be84096715db94e", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "9f026d3444cc513ec1ff6522fa56bf3e019d158c785f07c12be84096715db94e", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@7f7fffff", + "measurements": { + "target": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "6048235e823ffe3c303299c2d9ad4cbd9e5ec680a5dc19c9c4eb97538ea6498f", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "6048235e823ffe3c303299c2d9ad4cbd9e5ec680a5dc19c9c4eb97538ea6498f", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "_global_actor_mode_names", + "measurements": { + "target": { + "section": ".data", + "size": 16, + "padded_size": 16, + "flags": 3224371264, + "relocation_count": 3, + "normalized_sha256": "374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb", + "owner": { "value": 0, "type": 0, "storage": 2 } + }, + "base": { + "section": ".data", + "size": 16, + "padded_size": 16, + "flags": 3224371264, + "relocation_count": 3, + "normalized_sha256": "374708fff7719dd5979ec875d56cd2286f6d3cf7ec317a3b25632aab28ec37bb", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + } + ], + "surplus": [ + { + "symbol": "??_C@_06NDKEFKOH@combat?$AA@", + "provider": "source/ai/action_obey", + "measurements": { + "base": { + "section": ".rdata", + "size": 7, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "dd12caa843764cc94b031c4fea67b6696bfa30b3cecd2d8f136cd3548bdb9e74", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "??_C@_06PDPNPFPP@asleep?$AA@", + "provider": "source/ai/action_obey", + "measurements": { + "base": { + "section": ".rdata", + "size": 7, + "padded_size": 8, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "9848cbb6f126e7691b4c8e6326e085357496b020f1b3fd9ea3d9610105d9089e", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@00000000", + "provider": "source/ai/action_charge", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3f800000", + "provider": "source/ai/action_charge", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "e00e5eb9444182f352323374ef4e08ebcb784725fdd4fd612d7730540b3e0c8c", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3f1a36e2e0000000", + "provider": "source/ai/action_charge", + "measurements": { + "base": { + "section": ".rdata", + "size": 8, + "padded_size": 8, + "flags": 1077940288, + "relocation_count": 0, + "normalized_sha256": "564be83b341e452f4492fa81f7d5f215f446119f583c33a94b619cd1ee7287fd", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@41f00000", + "provider": "source/ai/action_alert", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "409303c5035263c102682239f8d654e7e194daae6235aff347c036576a261d96", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3efae147", + "provider": "source/ai/action_search", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "eeacb7c70a55988e1772bae66236c28b361bba5de119afb4075e752269a6890a", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3f5db3d7", + "provider": "source/ai/action_charge", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "fc19be3006f02a83659d43d37cce41fa9fdbf52c772e8e92f59d2630be248576", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3ecccccd", + "provider": "source/ai/action_flee", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "e0fb2d87992a9fc79e7729163ad2aea5efbf14806711292c8c46e873bac1a253", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@42c80000", + "provider": "source/ai/action_uncover", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "2238f30df488055daf5e8f362cf904e370011a172d20df193c1b7ae8e5db8e01", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3e99999a", + "provider": "source/ai/action_charge", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "45a6d738a7607576d3fe0862200bc67b10c12d5ed74167b4d5d5a708974c0f32", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@40600000", + "provider": "source/ai/action_vehicle", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "e21712a06022eecab9f5bd25414b4af9adeb316bb03947134cea060c78afd2d9", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3f000000", + "provider": "source/ai/action_alert", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "d99e58435243d9fef9c88273b8d553b4fba4d0baf8009d29eae74fa99e0d9f57", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3f4ccccd", + "provider": "source/ai/action_charge", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "030a1a64b337c633d995221728d15e8b0d086cc0dcf4557205111b089b04464d", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + }, + { + "symbol": "__real@3f8ccccd", + "provider": "source/ai/action_vehicle", + "measurements": { + "base": { + "section": ".rdata", + "size": 4, + "padded_size": 4, + "flags": 1076891712, + "relocation_count": 0, + "normalized_sha256": "e7d9a957c3c942d3551b291f30acbb11064e373eb6adcf4dc54671f8a64f965f", + "owner": { "value": 0, "type": 0, "storage": 2 } + } + } + } + ] } ] diff --git a/config/symbols.json b/config/symbols.json index 979ae32e..a1ca2d62 100644 --- a/config/symbols.json +++ b/config/symbols.json @@ -648,7 +648,6 @@ { "file_offset": 240592, "flags": 32, "name": "_ai_debug_render_path_storage", "static": true }, { "file_offset": 241408, "flags": 32, "name": "_ai_debug_render_path", "static": true }, { "file_offset": 241552, "flags": 32, "name": "_ai_debug_render_actor", "static": true }, -{ "file_offset": 266128, "flags": 32, "name": "_ai_debug_render_actor_jmptable" }, { "file_offset": 266528, "flags": 32, "name": "_ai_debug_render_paths_failed", "static": true }, { "file_offset": 266704, "flags": 32, "name": "_ai_debug_render_all_actors", "static": true }, { "file_offset": 266784, "flags": 32, "name": "_ai_debug_render_encounter", "static": true }, @@ -22596,6 +22595,7 @@ { "file_offset": 3176476, "flags": 0, "name": "_player_spawn_count" }, { "file_offset": 3176478, "flags": 0, "name": "_global_frame_rate_throttle" }, { "file_offset": 3176480, "flags": 0, "name": "_global_screenshot_size" }, +{ "file_offset": 3176484, "flags": 0, "name": "_scenario_paths", "static": true }, { "file_offset": 3176528, "flags": 0, "name": "_error_geometry_globals", "static": true }, { "file_offset": 3176644, "flags": 0, "name": "_global_convex_hull3d_delta" }, { "file_offset": 3176648, "flags": 0, "name": "_global_convex_hull3d_epsilon" }, diff --git a/docs/object_matching_logs/astra_data_fidelity_reconciliation_20260929.md b/docs/object_matching_logs/astra_data_fidelity_reconciliation_20260929.md new file mode 100644 index 00000000..5f865a3b --- /dev/null +++ b/docs/object_matching_logs/astra_data_fidelity_reconciliation_20260929.md @@ -0,0 +1,166 @@ +# Data and fidelity reconciliation — 2026-09-29 + +Canonical base: `f3aadeab984b09739d80aacfa877cb5aea51a145`, +`jonas/exact-pilots`. Donor production inputs are pinned to +`1940c840afed190756f9f456301c99aed418bab4`, not its moving branch tip. +This reconciles the Sep-29 addendum and its still-unreconciled Sep-28 +prerequisites. The user asked for reconciliation, not a new publication; +these commits are local. Donor trees, the existing README edit and unrelated +untracked research were not changed. + +## Result, measured against canonical + +| Measure | Before | After | Classification | +| --- | ---: | ---: | --- | +| Halo credited code / 1,770,166 | 1,596,429 | 1,597,714 | +1,285 meaningful, recovered debit | +| Halo exact functions | 7,472 / 7,574 | 7,473 / 7,573 | +1 match; separately −1 phantom denominator row | +| Halo credited data | 2,648,123 / 3,923,451 | 3,311,591 / 3,922,163 | +663,468 credit; separately −1,288 denominator | +| Complete Halo objects / 468 | 396 | 396 | No status flips | +| Stable strict owners / 8,252 | 7,645 | 7,646 | One gain, zero regressions | +| Active valid parks | 68 | 68 | No stale/invalid entries | + +The only exact-function gain is +`__rasterizer_model_transparent_geometry_submit`: 1,285 meaningful / 1,296 +padded bytes. K048r2 (`23c8082b`) recovers an approved B3 debit through VC7 +compiler numbering. It is not a new source-body reconstruction. The diagnostic +37-name filler did not land. `_bitmap_copy` remains the unrecovered B3 debit. + +Data credit is separately attributable: + +| Packet | Raw | Padding | Credited | +| --- | ---: | ---: | ---: | +| Original Q10 85 records | 657,245 | 311 | 657,556 | +| Q10 EXT1 eight records | 3,400 | 56 | 3,456 | +| actions extent entry | 2,338 | 66 | 2,404 | +| main single-section entry | 52 | 0 | 52 | +| **Total increase** | **663,035** | **433** | **663,468** | + +The already-credited hs 54,780 bytes and main .rdata are not claimed again. +The data percentage becomes 84.43%; code is 90.26%. All-category totals are +1,664,450 / 2,198,102 code and 3,317,905 / 4,176,062 data. Vendor code gains: zero. + +## Bounded source and storage intake + +- Corrected F_ALLH_R (`b008c540`), T01 (`9fb39730`), C06b (`162474a9`) + and C07 (`4320e7db`): later-build names/types retain their evidence limits. + The corrected 144-name packet includes eight single-PDB names, three also + supported by /Od; five lack that second witness. No January-name claim. +- K031/K059/K060/K061 (`daaa1fdb`) stay one coherent packet. Their joint + ballistic-park fingerprint is unchanged; no speculative refresh was made. +- K048r2 retains the shared unsigned `byte nodes[2]` and January's existing + signed consumer view. No yield-selected filler or alternative header placement. +- P-S1 (`8b7e1d1c`) replaces hand-expanded math with the attested helpers; + P-S2 (`03fc26b6`) retains the closer sound-cache residual and its park history. +- T1 (`c094b6dc`) restores the real `ui_widgets_active` call and the attested + body. T1b's optional initializer was not taken. +- DA_P1 (`773f9f8b`) retains the August-attested spot body and removes the + TU-local scale helper suppression. Spot remains non-exact; Q5 lightmap stays + held. January's four lightmap references authenticate the selected scale + provider under this packet's specific approval, not a generalized + non-exact-caller exception. +- set_random_seed S (`085475b6`) takes both attested call sites together. + Game's former NODUP copy becomes ANY; periodic_functions emits an identical + ANY copy. The reconstructed January split's NODUP selection is not treated + as proof that the original source used a non-inline definition. +- C05 (`c217c735`) keeps three explicit perceptions initializers and an + implicit zero fourth. C09 (`1940c840`) removes redundant product parentheses. + **C09 is admitted as ordinary cleanup under the user's explicit clarification.** + History establishes reconstruction origin, not that they were inserted as + scaffolding. Render-actor remains non-exact and earns zero credit. +- COMMON: CV-A′, CV-S, P-HS′, CV-B′, Q-B2 and CP-T B1/B2/B4/B5/B7, + from `a548d62d`, `2bf71228`, `90f77761`, `0dcdf006`, `c7698d7f`, + `6d1040e6`, `cfe97640`, `16a33aad`, `b6d60163`, `d23568d5`. + These produce 52 new tentative definitions relative to canonical, with no + initialized storage or section-byte changes from the definitions themselves. + Ownership remains inferred under the narrow rulings; it is not certified + January ownership. B7's literal allocation size and label renumbering remain + disclosed. B7 and debug_sound_channels remain outside Q10 credit. +- `_scenario_paths` split name (`55829429`) and phantom jump-table row + removal (`8220b041`) are metadata/accounting, not new source-byte matches. +- The biped-discard and endpoint-poll park text corrections preserve the holds + and measurements. They do not admit the held exact variants. + +Canonical's virtual-keyboard helper/call and static symbol row, both ordered +physics water-depth predicates, and the two canonical physics park histories +are preserved. The unrelated donor libtiff self-alias macros are excluded. +The source intake therefore is not a blind donor-tree replacement. + +## Data verifier and accounting boundary + +The reviewed actions surplus-helper rule (`a448602a`) and entry (`4b9fc69d`) +require January's own import and a unique authenticated provider, identical +helper/constant contents, valid relocation addends, select-any storage, no +weak/alternate aliases and the retained guard. Only January-owned data is +credited, not surplus helper code/constants. Main's 52-byte entry is `aa8129c0`. + +Q10 production is `9ab48dc8` with EXT1 `4551c4e9` and wording `a3d84118`. +The four LF-normalized pins are unchanged: verifier, COFF reader, provenance +ledger and XDK library manifest. The complete mutation catalogue/harness is +preserved, rather than silently letting missing-fixture tests skip. + +Required scope, verbatim: "This lifts Q10 only for those 85 records and the 8 +records of allowlist extension EXT1 under this verification contract. It does +not certify January ownership, complete pool layout, or a matching executable +link." + +Q10 credits 93 records: 660,645 raw + 367 padding = 661,012. By tag: +64 inferred records / 11,884 bytes; 29 probable records / 649,128 bytes. +`_render`, tagged probable, contributes 643,744 bytes (97.4%). Its later-build +type drift remains disclosed; this is bounded COMMON storage credit, not +proof of the whole record's January source type or initialization behavior. +24 owner-unresolved records, 94 FAIL records, the two unlisted PASS records, +27 vendor records and two linker records remain uncredited by Q10. +`source/linker_common` stays MISSING. + +The denominator packet (`38f82c59`) reassigns 29 non-Halo pool records: +libcmt +880, xapilib +308, dsound +4, linker +96. Halo decreases 1,288; +the all-category denominator stays 4,176,062. This is accounting only. + +Limitations are intentionally not silently repaired: + +- `binkxbox.lib` and `dsstrmh.lib` are not in the authenticated XDK extract. +- The current entry expects `C:/tmp/xdk3911_extract/XDK/xbox/lib`; all 38 + manifest libraries were freshly size/hash verified. Another machine needs + those private prerequisites or a separately reviewed path adaptation. +- The hook trusts the freshly invoked pinned verifier. A substituted runner + can still replay a compatible stale PASS against different built objects; + direct receipt-to-current-object binding is the held RF-EZ hardening work. + The ordinary pipeline deletes prior outputs and reruns the verifier. +- Pins do not secure a compromised Python/import environment, unpinned hook + or generated outputs. Provenance is a reviewed trust root, not rediscovered + by the verifier. The frozen allowlist is enforced by its tests and review. + +## Independent verification + +- Source-only checkpoint, complete tooling checkpoint and a clean rebuild + after `ninja -t clean -r cl`: same single strict gain and zero exact losses. + Cold/current sections and COMMON inventories agree in all 467 Halo objects. +- Baseline/current section census: only six units change sections (ai_debug, + xbox_sound_cache, ui_widget, periodic_functions, xbox_environment, + xbox_models). Game additionally changes set_random_seed selection metadata. +- All 56 surplus helper/literal/table copies in sound/environment/game/periodic, + plus game's owned set_random_seed, match January and current providers. + 38 provider pairs / 76 orders: expected unresolved-only exits, no duplicate + or unexpected diagnostics; no images emitted. Periodic object audit PASS; + other differences are precisely their documented residuals. +- Whole-board diagnostic link: unresolved names 471 -> 419, exactly the 52 + new COMMON definitions; no new unresolved or duplicate names. One inherited + duplicate remains. Both attempts fail; this is not a playable-build claim. +- Full `/W3 /Zs`: 4,067 -> 4,071. Only P-S2's one long-to-short conversion + and T1's three bounded 0..3 conversions are added. No warning-silencing casts. +- Source and data policy reviews found no additional blocker under the + approved scopes. RF-EV's independent COFF reader/extent model passes 39/39 + checks against a freshly executed original-85 control and the final93 entry. + The control varied only the entry path, not verifier code or runner; the + production files were never temporarily rewritten for that experiment. +- Final tools suite: 1,663 passed, five skipped, 159 subtests passed. Parks: + 68 valid, zero stale/invalid. Admission: seven candidates, zero contradicted, + rejected or revoked. Fake scan: unchanged 26 leads. `git diff --check` clean. +- Objdiff remains 3.3.1, SHA-256 + `090987aa22c0fe9b7d252b2b44c2c0c92c5dd3e9b5965d353060802226a13677`. + +Receipts, scripts, baseline objects, full diagnostics and independent reviews +are retained in `scratch/astra_data_reconcile_20260929/`; a compact receipt +index accompanies this ledger. Private executables, objects, PDBs and SDK +libraries are not committed. The 51-set, paren class P1/P2/C07/U, BW-P3, +s7, biped A1, K067 and receipt-binding hardening remain research only. diff --git a/research/astra_data_reconciliation_20260929/receipt_index.json b/research/astra_data_reconciliation_20260929/receipt_index.json new file mode 100644 index 00000000..df919461 --- /dev/null +++ b/research/astra_data_reconciliation_20260929/receipt_index.json @@ -0,0 +1,794 @@ +{ + "schema": "astra-reconciliation-receipt-index/1", + "date": "2026-09-29", + "base": "f3aadeab984b09739d80aacfa877cb5aea51a145", + "donor_production": "1940c840afed190756f9f456301c99aed418bab4", + "canonical_branch": "jonas/exact-pilots", + "published": false, + "halo_before": { + "code": 1596429, + "code_total": 1770166, + "functions": 7472, + "functions_total": 7574, + "data": 2648123, + "data_total": 3923451, + "objects": 396, + "objects_total": 468 + }, + "halo_after": { + "code": 1597714, + "code_total": 1770166, + "functions": 7473, + "functions_total": 7573, + "data": 3311591, + "data_total": 3922163, + "objects": 396, + "objects_total": 468 + }, + "delta": { + "code_meaningful": 1285, + "code_padded": 1296, + "functions": 1, + "regressions": 0, + "data_credit": 663468, + "data_raw": 663035, + "data_padding": 433, + "data_denominator": -1288, + "function_denominator": -1, + "objects": 0 + }, + "gain": "__rasterizer_model_transparent_geometry_submit", + "classification": "recovered B3 debit, compiler-numbering dependent; no filler", + "gates": { + "pytest_passed": 1663, + "pytest_skipped": 5, + "subtests_passed": 159, + "parks": 68, + "parks_stale": 0, + "parks_invalid": 0, + "fake_scan": 26, + "admission_candidates": 7, + "admission_contradicted": 0, + "admission_rejected": 0, + "admission_revoked": 0, + "W3_before": 4067, + "W3_after": 4071, + "ext1_independent_checks": "39/39", + "cold_467_object_section_common_changes": 0, + "provider_pairs": 38, + "provider_orders": 76 + }, + "common_definition_delta": { + "count": 52, + "resolved_link_names": [ + "_antenna_data", + "_assertion_count", + "_avoidance_directions", + "_avoidance_rays", + "_blip_player_index", + "_build_sprite_globals", + "_center_point", + "_debug_damage", + "_debug_decals", + "_debug_fog_planes", + "_debug_leaf_portals", + "_debug_lights", + "_debug_looping_sound", + "_debug_object_lights", + "_debug_point_physics", + "_debug_rasterizer_light_count", + "_debug_render_freeze", + "_debug_scripting", + "_debug_sound", + "_debug_sound_cache", + "_debug_sound_channels", + "_debug_sound_reference_counts", + "_debug_sprites", + "_debug_trigger_volumes", + "_director_camera_scripted", + "_effect_location_data", + "_first_object_type_definition", + "_global_communication_table_indices", + "_global_default_animation_colors", + "_global_default_animation_values", + "_glow_globals", + "_hs_debug_data", + "_hs_global_data", + "_hs_thread_data", + "_hud_msg_def", + "_light_cluster_partition", + "_light_data", + "_local_player_index_for_draw_string_and_hack_in_icons", + "_looping_sound_data", + "_loud_dialog_hack", + "_node_count", + "_particle_systems", + "_sense_rays", + "_sound_channels", + "_sound_class_data", + "_sound_data", + "_system_particles", + "_temporary_hud", + "_ui_plasma_effect_color", + "_weather_particle_data", + "_widget_data", + "_wind_globals" + ], + "unresolved_before": 471, + "unresolved_after": 419, + "new_duplicate_names": [], + "whole_program_link_success": false + }, + "q10": { + "outcome": "CREDITED", + "credit": { + "records": 93, + "raw": 660645, + "padding": 367, + "total": 661012, + "by_tag": { + "inferred": { + "records": 64, + "raw": 11612, + "padding": 272, + "share": 11884 + }, + "probable": { + "records": 29, + "raw": 649033, + "padding": 95, + "share": 649128 + } + }, + "largest_record": { + "symbol": "_render", + "tag": "probable", + "raw": 643732, + "padding": 12, + "share": 643744 + }, + "rows": [ + [ + "_debug_looping_sound", + "inferred", + 1, + 4 + ], + [ + "_debug_sound", + "inferred", + 1, + 4 + ], + [ + "_loud_dialog_hack", + "inferred", + 1, + 4 + ], + [ + "_sound_channels", + "inferred", + 6144, + 6160 + ], + [ + "_looping_sound_data", + "inferred", + 4, + 4 + ], + [ + "_sound_data", + "inferred", + 4, + 4 + ], + [ + "_combined_pas", + "inferred", + 64, + 92 + ], + [ + "_game_sound_globals", + "inferred", + 4, + 4 + ], + [ + "_game_looping_sound_data", + "inferred", + 4, + 4 + ], + [ + "_recover_saved_games_hack", + "probable", + 1, + 4 + ], + [ + "_stun_enable", + "probable", + 1, + 4 + ], + [ + "_debug_damage_taken", + "inferred", + 1, + 4 + ], + [ + "_debug_unit_illumination", + "inferred", + 1, + 4 + ], + [ + "_debug_unit_animations", + "inferred", + 1, + 4 + ], + [ + "_debug_unit_all_animations", + "inferred", + 1, + 4 + ], + [ + "_file_location_volume_names", + "probable", + 512, + 536 + ], + [ + "_debug_fog_planes", + "inferred", + 1, + 4 + ], + [ + "_structures_use_pvs_for_vs", + "probable", + 1, + 4 + ], + [ + "_debug_portals", + "inferred", + 1, + 4 + ], + [ + "_debug_leaf_portals", + "inferred", + 1, + 4 + ], + [ + "_global_game_globals", + "probable", + 4, + 4 + ], + [ + "_global_bsp3d", + "probable", + 4, + 4 + ], + [ + "_global_collision_bsp", + "probable", + 4, + 4 + ], + [ + "_global_structure_bsp", + "probable", + 4, + 4 + ], + [ + "_global_scenario", + "probable", + 4, + 4 + ], + [ + "_debug_sprites", + "inferred", + 1, + 4 + ], + [ + "_cached_object_render_states", + "inferred", + 4, + 4 + ], + [ + "_debug_input", + "probable", + 1, + 4 + ], + [ + "_debug_bsp", + "probable", + 1, + 4 + ], + [ + "_render", + "probable", + 643732, + 643744 + ], + [ + "_debug_point_physics", + "inferred", + 1, + 4 + ], + [ + "_node_count", + "inferred", + 4, + 4 + ], + [ + "_global_object_marker", + "probable", + 4, + 4 + ], + [ + "_noncollideable_object_cluster_partition", + "inferred", + 12, + 24 + ], + [ + "_collideable_object_cluster_partition", + "inferred", + 12, + 16 + ], + [ + "_object_header_data", + "probable", + 4, + 4 + ], + [ + "_first_object_type_definition", + "inferred", + 4, + 4 + ], + [ + "_debug_lights", + "inferred", + 1, + 4 + ], + [ + "_debug_object_lights", + "inferred", + 1, + 4 + ], + [ + "_debug_rasterizer_light_count", + "inferred", + 2, + 4 + ], + [ + "_lights_globals", + "inferred", + 848, + 872 + ], + [ + "_light_cluster_partition", + "inferred", + 12, + 16 + ], + [ + "_debug_damage", + "inferred", + 1, + 4 + ], + [ + "_widget_data", + "inferred", + 4, + 4 + ], + [ + "_flag_data", + "inferred", + 4, + 4 + ], + [ + "_antenna_data", + "inferred", + 4, + 4 + ], + [ + "_network_game_server_memory_do_not_use_directly", + "probable", + 1212, + 1232 + ], + [ + "_network_game_client_dont_use_directly", + "probable", + 3248, + 3264 + ], + [ + "_debug_render_freeze", + "inferred", + 1, + 4 + ], + [ + "_local_player_index_for_draw_string_and_hack_in_icons", + "inferred", + 2, + 4 + ], + [ + "_ui_plasma_effect_color", + "inferred", + 16, + 28 + ], + [ + "_blip_player_index", + "inferred", + 2, + 4 + ], + [ + "_center_point", + "inferred", + 8, + 8 + ], + [ + "_hud_msg_def", + "inferred", + 4, + 4 + ], + [ + "_temporary_hud", + "inferred", + 1, + 4 + ], + [ + "_object_list_data", + "inferred", + 4, + 4 + ], + [ + "_object_list_header_data", + "inferred", + 4, + 4 + ], + [ + "_debug_trigger_volumes", + "inferred", + 1, + 4 + ], + [ + "_debug_scripting", + "inferred", + 1, + 4 + ], + [ + "_hs_global_data", + "inferred", + 4, + 4 + ], + [ + "_hs_thread_data", + "inferred", + 4, + 4 + ], + [ + "_hs_syntax_data", + "probable", + 4, + 4 + ], + [ + "_players_globals", + "inferred", + 4, + 4 + ], + [ + "_team_data", + "inferred", + 4, + 4 + ], + [ + "_player_data", + "probable", + 4, + 4 + ], + [ + "_global_default_animation_colors", + "inferred", + 48, + 72 + ], + [ + "_global_default_animation_values", + "inferred", + 16, + 16 + ], + [ + "_weather_particle_data", + "inferred", + 4, + 4 + ], + [ + "_system_particles", + "inferred", + 4, + 4 + ], + [ + "_particle_systems", + "inferred", + 4, + 4 + ], + [ + "_effect_location_data", + "inferred", + 4, + 4 + ], + [ + "_debug_decals", + "inferred", + 1, + 4 + ], + [ + "_temporary", + "probable", + 256, + 256 + ], + [ + "_pursuit_data", + "inferred", + 4, + 4 + ], + [ + "_encounter_data", + "probable", + 4, + 4 + ], + [ + "_platoon_array", + "probable", + 4, + 4 + ], + [ + "_squad_array", + "probable", + 4, + 4 + ], + [ + "_global_communication_table_indices", + "inferred", + 114, + 124 + ], + [ + "_swarm_component_data", + "probable", + 4, + 4 + ], + [ + "_swarm_data", + "probable", + 4, + 4 + ], + [ + "_actor_data", + "probable", + 4, + 4 + ], + [ + "_avoidance_rays", + "inferred", + 448, + 468 + ], + [ + "_avoidance_directions", + "inferred", + 96, + 96 + ], + [ + "_sense_rays", + "inferred", + 252, + 256 + ], + [ + "_global_temporary_render_color", + "inferred", + 16, + 16 + ], + [ + "_sound_class_data", + "inferred", + 4, + 4 + ], + [ + "_debug_sound_cache", + "probable", + 1, + 4 + ], + [ + "_assertion_count", + "probable", + 2, + 4 + ], + [ + "_debug_sound_reference_counts", + "probable", + 1, + 4 + ], + [ + "_wind_globals", + "inferred", + 3340, + 3360 + ], + [ + "_build_sprite_globals", + "inferred", + 40, + 64 + ], + [ + "_light_data", + "probable", + 4, + 4 + ], + [ + "_glow_globals", + "inferred", + 8, + 12 + ] + ], + "uncredited": { + "halo_pass_owner_unresolved": [ + 24, + 565443 + ], + "halo_fail": [ + 94, + 44384 + ], + "halo_pass_not_listed": [ + 2, + 5 + ], + "vendor": [ + 27, + 1125 + ], + "linker_excluded": [ + 2, + 88 + ] + }, + "not_listed": [ + "_debug_sound_channels", + "_director_camera_scripted" + ], + "matched_data_before": { + "overall": 2656893, + "category": 2650579, + "unit": 0 + }, + "matched_data_after": { + "overall": 3317905, + "category": 3311591, + "unit": 661012 + } + }, + "scope": "This lifts Q10 only for those 85 records and the 8 records of allowlist extension EXT1 under this verification contract. It does not certify January ownership, complete pool layout, or a matching executable link.", + "limitations": "L1: pinning prevents unnoticed changes to reviewed assumptions; it does not prove those assumptions or January ownership.", + "environment": "Pins are not protection against a compromised execution environment. The Python interpreter, its module search path and bytecode cache, the unpinned progress code and the generated build outputs are trusted, not pinned (L1 trust root 8).", + "linked_libraries_not_in_extract": [ + "binkxbox.lib", + "dsstrmh.lib" + ] + }, + "C09_ruling": "Allow ordinary redundant-parentheses cleanup with limitation disclosed; history proves reconstruction origin, not scaffolding intent.", + "private_receipts_directory": "scratch/astra_data_reconcile_20260929", + "receipts": { + "before.json": "19cda0ab95539a0bdacb6a55d3461aafae1c24feed1e4915949a93f375a77b8a", + "source.json": "c8696233931220149663c4fda17f4ec267200426a138955d8b781cfccfb33846", + "final.json": "c8696233931220149663c4fda17f4ec267200426a138955d8b781cfccfb33846", + "cold.json": "c8696233931220149663c4fda17f4ec267200426a138955d8b781cfccfb33846", + "source_diff.log": "c8e952998d1003006438cfd554b37a4e5c423e00f5e0a3f7a61947cd04bd92c2", + "cold_diff.log": "c8e952998d1003006438cfd554b37a4e5c423e00f5e0a3f7a61947cd04bd92c2", + "before_build.log": "1d96e35563fec773b5068bcd7ed3571fca281fae912d145db74fee7a640a8d94", + "source_build.log": "ce4920d28fc395a69efe193048d8fcdc6587c1b863374b2080b5edfde97420ad", + "final_build.log": "f017ef609cdebe6ee9ca91af05f75d8caf83247b7e22d03adcd4a5adff8f511d", + "cold_build.log": "18a2618a479e49d3497b419a1d9715c56f9c9c3f84c7bcc1ffd92f6c56d8e5d4", + "cold_pytest.log": "fce1afd6bdd49b8c363e708af5e044eebf217bf7f5d6ab5b9a1a0a3c87b77af6", + "cold_parks.json": "b5c475c232ec2895126bc90d26807d815cbfbaadc927d5c5d08f4a032b8aa775", + "cold_admission.json": "e4dbf7065fbd4028f5b74b8b82193cb3fc7b3d7c05833e2ab60fead49e6860bd", + "cold_fake.log": "bae88b0678f9e172f8e8a8a9134e0648cf7a3b6f53fbcf981d7d27156018d486", + "batch_warning_delta.json": "95024ce35d5dff141201809de7cdab21c4ec71d65b6bd86ce5dedab3612334fa", + "object_census.json": "78bdd61450407db514a8a00362ac8ec50a7756d7f5683f10487d96c0ea18250d", + "cold_object_census.json": "03909eec6b39c17f4f0feb38378ec19034192f9cb421c8164bb43c9895f4c21b", + "link_delta.json": "a37f0c9b38373589e95f08c17f851f350e9c7bbce616446eacf33cd84112e547", + "control85_progress.txt": "22b51a33385ad8bfdd4ae63ca7137d70754051febdd51d61f9c9bdbb53cb37d6", + "control85_credit_receipt.json": "407b3157fdf337c11270581b4410a6eb6c8f2a03e5539e0f8915bbce906b5cbe", + "extended_progress.txt": "298f420229fa22780e031bdc4d623283fe1b9890f4fb9c8d6db330de6ea5a69f", + "ext1_independent.log": "4ebab428585107a44c8e3ca084340547e5b5e4f1c52d50ecb6c667b9e0d353e4", + "review_q10/REVIEW.md": "cbe06f9cf15b395851219efa1b97768d3fa4940a57047da24088e5adebd724e0", + "review_q10/SOURCE_SCOPE_REVIEW.md": "6eb67b5b5641550b9be9d1b847fc47c2355b25a84c1d92e70aed5ab042d0397a", + "review_q10/HELPER_PROVIDER_REVIEW.md": "a17860c00904262b0f7cd00d383f8cb41fc4fe4413c742f79f2ef1d501eb96c5", + "review_q10/helper_audit.json": "34fd09ea3782ddfb332fe0c698d6c8c283859a3fab1ef1d4f1eab5ef32102659" + }, + "production_pins": { + "config/common_pool_credit.json": "bf478a7325c46b4cdc7c4a7a91373719bfb6f9e7edbdaa3b6eb9acd02fc50c3c", + "config/data_category_reassignments.json": "d19f51fd027b9d9b8f90d3507e81526a2d76589c3024728eeddbc5e9df1ef829", + "tools/common_pool_verify.py": "6ca08d007b3a95608e449b4e44a06a5d792a710349c32513a8366a17b044c8be", + "tools/coff_compare.py": "df0004d83c548ed82cd4afe66306ccf9dafbc83e6998fafe23047c3a82ecedd7", + "tools/semantic_progress.py": "b227a7c8c1c3176a55a5d9b890aaf5f168a3d587ae853fffe70721088ce7b3c7", + "research/remaining_frontier_20260926/q10/common_pool_ledger.json": "da1c65de445aac977ed4c14257d929d9c1ada1a1c40e88a573d8688c33300e7f", + "research/remaining_frontier_20260926/q10/xdk3911_lib_manifest.json": "1b8a8350bd456bd61efea345970b793ca7ae8b554f9f63d5a0111571a47ebe3b" + } +} diff --git a/research/remaining_frontier_20260926/q10/common_pool_ledger.json b/research/remaining_frontier_20260926/q10/common_pool_ledger.json new file mode 100644 index 00000000..46596b74 --- /dev/null +++ b/research/remaining_frontier_20260926/q10/common_pool_ledger.json @@ -0,0 +1,249 @@ +{ + "schema": "common-pool-ledger/2", + "status": "DRAFT research only; Q10 held; zero credit; provenance is inferred or weaker, never January-proven; research record kept under research/ until Q10 is approved", + "vocabulary": {"inferred": "owner inferred from later first-party builds (>=2 readouts), consistent with January; not January-proven", "probable": "one definer readout, or readouts with a recorded caveat; not January-proven", "unresolved": "no usable definer readout, or readouts disagree; ownership not established"}, + "derivation": ["research/remaining_frontier_20260926/workers/RF-DE/tools/build_ledger.py (rules R1-R4): ledger v1 (config/common_pool_ledger.json in RF-DE patch bcdde2e5, LF sha256 3a2f4fecc9a08f9e5b88982db6116b11256380979e6eae578979b612c5ec165a)", "research/remaining_frontier_20260926/workers/RF-DM/tools/integrate_ledger.py: v1 -> v2 (vendor_evidence on the 27 vendor records; _hs_debug_data candidate owner + containment_evidence; every other field unchanged)"], + "rulings": ["Q10 mechanism (2026-09-27): \"Draft it - research only. Separate Halo/vendor accounting; exclude linker records. Verify names, sizes, COMMON class, single definers and provenance without treating inferred ownership as proven.\"", "Q10 fixes (2026-09-27): \"Accept both. Fold F1-F9 into the research draft and require --xdk-lib-dir for every accounting run. Fail closed on missing/unverifiable libraries, malformed types, or ambiguous classification - no ledger-only fallback.\"", "Q10 ledger home (2026-09-27): \"Research records only for now. Keep the draft ledger under research/ until Q10 is approved. Vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded.\"", "hs_debug_data ledger (2026-09-27): \"Candidate owner, unresolved. Record hs_runtime and RF-DI's containment evidence, citing the narrow P-HS' ruling. That ruling authorized the tentative definition; it did not establish a new provenance family or upgrade the ledger classification.\"", "Rule 48 / hs_debug_data (2026-09-27): \"Containment supports an inferred first tentative definer, not proof of exclusive ownership. Any contradictory January storage/import evidence vetoes placement.\""], + "records": [ + {"name": "_debug_sound_channels", "rva": "0x4e41a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CV strict /Od SANDWICH(sound_manager.c) (C08)"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); owner sound_manager.obj is not a January referencer (refs: hs_globals_external.obj, sound_dsound_xbox.obj))", "caveats": ["single definer channel (D); owner sound_manager.obj is not a January referencer (refs: hs_globals_external.obj, sound_dsound_xbox.obj)", "readout count alone would allow inferred; tag held at probable by the recorded caveat (never raised by the verifier)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #3", "RF-CV review"]}, + {"name": "_debug_looping_sound", "rva": "0x4e41a1", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CV strict /Od SANDWICH(sound_manager.c) (C08)"}], "basis": "R2a: RF-CV C08 identical evidence to debug_sound (D + strict /Od SANDWICH); owner approved CV-S", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #4", "RF-CV review"]}, + {"name": "_debug_sound", "rva": "0x4e41a2", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(sound_manager.c) (RF-CV)"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+OD) on sound_manager.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #5", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_loud_dialog_hack", "rva": "0x4e41a3", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CV strict /Od SANDWICH(sound_manager.c) (C08)"}], "basis": "R2a: RF-CV C08 identical evidence to debug_sound (D + strict /Od SANDWICH); owner approved CV-S", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #6", "RF-CV review"]}, + {"name": "_sound_channels", "rva": "0x4e41c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on sound_manager.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #7", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_looping_sound_data", "rva": "0x4e59c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on sound_manager.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #8", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_sound_data", "rva": "0x4e59c4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "sound_manager", "owner": "source/sound/sound_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on sound_manager.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #9", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_interrupt_result", "rva": "0x4e59c8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/sound/sound_dsound_xbox.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_dsound_pc", "owner": "source/sound/sound_dsound_xbox.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); platform-sibling mapping: sibling sound_dsound_pc.obj->sound_dsound_xbox.obj)", "caveats": ["single definer channel (D); platform-sibling mapping: sibling sound_dsound_pc.obj->sound_dsound_xbox.obj"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #10", "RF-CV review"]}, + {"name": "_dsound_globals", "rva": "0x4e59e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/sound/sound_dsound_xbox.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_dsound_pc", "owner": "source/sound/sound_dsound_xbox.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); platform-sibling mapping: sibling sound_dsound_pc.obj->sound_dsound_xbox.obj; size not independently confirmed (demo !=134752, HCEX None, Sept map =))", "caveats": ["single definer channel (D); platform-sibling mapping: sibling sound_dsound_pc.obj->sound_dsound_xbox.obj; size not independently confirmed (demo !=134752, HCEX None, Sept map =)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #11", "RF-CV review"]}, + {"name": "_sound_class_data", "rva": "0x4ed2ac", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/sound_classes.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "sound_classes", "owner": "source/sound/sound_classes.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "sound_classes", "owner": "source/sound/sound_classes.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on sound_classes.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #12", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_combined_pas", "rva": "0x4ed2c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/game_sound.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_sound", "owner": "source/sound/game_sound.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_sound", "owner": "source/sound/game_sound.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on game_sound.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #13", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_game_sound_globals", "rva": "0x4ed300", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/game_sound.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_sound", "owner": "source/sound/game_sound.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_sound", "owner": "source/sound/game_sound.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on game_sound.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #14", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_game_looping_sound_data", "rva": "0x4ed304", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/sound/game_sound.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_sound", "owner": "source/sound/game_sound.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_sound", "owner": "source/sound/game_sound.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on game_sound.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #15", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_recover_saved_games_hack", "rva": "0x4ed308", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/saved games/game_state.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_state", "owner": "source/saved games/game_state.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #16", "RF-CV review"]}, + {"name": "_debug_sound_cache", "rva": "0x4ed309", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/cache/xbox_sound_cache.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict not recorded (RF-CV; owner approved the strict rule for records)"}], "basis": "R2: RF-CP PROBABLE (platform-sibling mapping: sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj)", "caveats": ["platform-sibling mapping: sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #17", "RF-CV review"]}, + {"name": "_assertion_count", "rva": "0x4ed30a", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/cache/xbox_sound_cache.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (platform-sibling mapping: sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj)", "caveats": ["platform-sibling mapping: sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #18", "RF-CV review"]}, + {"name": "_debug_sound_reference_counts", "rva": "0x4ed30c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/cache/xbox_sound_cache.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}, {"channel": "XD", "names": "pc_sound_cache", "owner": "source/cache/xbox_sound_cache.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (platform-sibling mapping: sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj; storage contract differs in the demo (real definition, not tentative))", "caveats": ["platform-sibling mapping: sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj; sibling pc_sound_cache.obj->xbox_sound_cache.obj; storage contract differs in the demo (real definition, not tentative)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #19", "RF-CV review"]}, + {"name": "_global_tag_instances", "rva": "0x4ed310", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/cache/cache_files.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "cache_files", "owner": "source/cache/cache_files.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #20", "RF-CV review"]}, + {"name": "_debug_objects_vehicle_powered_mass_points", "rva": "0x4ed314", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/units/vehicles.c", "readouts": [{"channel": "OD", "names": "vehicles", "owner": "source/units/vehicles.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #21", "RF-CV review"]}, + {"name": "_debug_objects_unit_mouth_apeture", "rva": "0x4ed315", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/units/units.c", "readouts": [{"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #22", "RF-CV review"]}, + {"name": "_debug_objects_unit_seats", "rva": "0x4ed316", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/units/units.c", "readouts": [{"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #23", "RF-CV review"]}, + {"name": "_debug_objects_unit_vectors", "rva": "0x4ed317", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #24", "RF-CV review"]}, + {"name": "_stun_enable", "rva": "0x4ed318", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/units/units.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R1-exception: RF-CV DOWNGRADE (DOWNGRADE to single channel (D) under RF-CP standard: OD is EDGE; HCEX set {hs_globals_external,units} contains D)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #25", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: DOWNGRADE to single channel (D) under RF-CP standard: OD is EDGE; HCEX set {hs_globals_external,units} contains D"]}, + {"name": "_debug_damage_taken", "rva": "0x4ed319", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/units/units.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on units.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #26", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_unit_illumination", "rva": "0x4ed31a", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/units/units.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on units.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #27", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_unit_animations", "rva": "0x4ed31b", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/units/units.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on units.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #28", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_unit_all_animations", "rva": "0x4ed31c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/units/units.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "units", "owner": "source/units/units.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on units.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #29", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_objects_biped_autoaim_pills", "rva": "0x4ed31d", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/units/bipeds.c", "readouts": [{"channel": "OD", "names": "bipeds", "owner": "source/units/bipeds.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #30", "RF-CV review"]}, + {"name": "_debug_objects_biped_physics_pills", "rva": "0x4ed31e", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #31", "RF-CV review"]}, + {"name": "_file_location_volume_names", "rva": "0x4ed320", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/tag_files/files.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "files", "owner": "source/tag_files/files.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "files", "owner": "source/tag_files/files.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (size not independently confirmed (demo !=768, HCEX None, Sept map =))", "caveats": ["size not independently confirmed (demo !=768, HCEX None, Sept map =)", "readout count alone would allow inferred; tag held at probable by the recorded caveat (never raised by the verifier)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #32", "RF-CV review"]}, + {"name": "_debug_fog_planes", "rva": "0x4ed520", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/structures/structures.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "structures", "owner": "source/structures/structures.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "structures", "owner": "source/structures/structures.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on structures.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #33", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_structures_use_pvs_for_vs", "rva": "0x4ed521", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/structures/structure_visibility.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "structure_visibility", "owner": "source/structures/structure_visibility.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #34", "RF-CV review"]}, + {"name": "_debug_portals", "rva": "0x4ed522", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/structures/structure_visibility.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "structure_visibility", "owner": "source/structures/structure_visibility.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "structure_visibility", "owner": "source/structures/structure_visibility.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on structure_visibility.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #35", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_leaf_portals", "rva": "0x4ed523", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/structures/structure_render.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "structure_render", "owner": "source/structures/structure_render.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "structure_render", "owner": "source/structures/structure_render.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on structure_render.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #36", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_window_globals", "rva": "0x4ed540", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [{"channel": "D", "names": "shell_windows", "owner": "source/shell/shell_windows.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "shell_xbox", "owner": "source/shell/shell_xbox.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R3: RF-CP UNRESOLVED (definer channels disagree: D=shell_windows.obj, X=shell_xbox.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #37", "RF-CV review"]}, + {"name": "_wind_globals", "rva": "0x4ed5e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/scenario/wind.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "wind", "owner": "source/scenario/wind.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "wind", "owner": "source/scenario/wind.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on wind.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #38", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_debug_sound_environment", "rva": "0x4ee2ec", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #39", "RF-CV review"]}, + {"name": "_scenario_globals", "rva": "0x4ee2f0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/scenario/scenario.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on scenario.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #40", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_global_game_globals", "rva": "0x4ee2f4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/scenario/scenario.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #41", "RF-CV review"]}, + {"name": "_global_bsp3d", "rva": "0x4ee2f8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/scenario/scenario.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #42", "RF-CV review"]}, + {"name": "_global_collision_bsp", "rva": "0x4ee2fc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/scenario/scenario.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #43", "RF-CV review"]}, + {"name": "_global_structure_bsp", "rva": "0x4ee300", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/scenario/scenario.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #44", "RF-CV review"]}, + {"name": "_global_scenario", "rva": "0x4ee304", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/scenario/scenario.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "scenario", "owner": "source/scenario/scenario.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #45", "RF-CV review"]}, + {"name": "_debug_sprites", "rva": "0x4ee308", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/render/render_sprite.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "render_sprite", "owner": "source/render/render_sprite.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "render_sprite", "owner": "source/render/render_sprite.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on render_sprite.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #46", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_build_sprite_globals", "rva": "0x4ee320", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/render/render_sprite.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "render_sprite", "owner": "source/render/render_sprite.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "render_sprite", "owner": "source/render/render_sprite.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on render_sprite.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #47", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_debug_objects", "rva": "0x4ee348", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/render/render_objects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "render_objects", "owner": "source/render/render_objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #48", "RF-CV review"]}, + {"name": "_cached_object_render_states", "rva": "0x4ee34c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/render/render_objects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "render_objects", "owner": "source/render/render_objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "render_objects", "owner": "source/render/render_objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on render_objects.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #49", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_permanent_decals", "rva": "0x4ee350", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #50", "RF-CV review"]}, + {"name": "_debug_input", "rva": "0x4ee351", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/render/render_debug.c", "candidate_owner": null, "readouts": [{"channel": "OD", "names": "render_debug", "owner": "source/render/render_debug.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(render_debug.c) (RF-CV)"}], "basis": "R2b: OD-only, strict /Od SANDWICH(render_debug.c)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #51", "RF-CV review"]}, + {"name": "_debug_bsp", "rva": "0x4ee352", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/render/render_debug.c", "candidate_owner": null, "readouts": [{"channel": "OD", "names": "render_debug", "owner": "source/render/render_debug.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(render_debug.c) (RF-CV)"}], "basis": "R2b: OD-only, strict /Od SANDWICH(render_debug.c)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #52", "RF-CV review"]}, + {"name": "_debug_structure", "rva": "0x4ee353", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/render/render_debug.c", "readouts": [{"channel": "OD", "names": "render_debug", "owner": "source/render/render_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #53", "RF-CV review"]}, + {"name": "_debug_player", "rva": "0x4ee354", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/render/render_debug.c", "readouts": [{"channel": "OD", "names": "render_debug", "owner": "source/render/render_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #54", "RF-CV review"]}, + {"name": "_debug_camera", "rva": "0x4ee355", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/render/render_debug.c", "readouts": [{"channel": "OD", "names": "render_debug", "owner": "source/render/render_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #55", "RF-CV review"]}, + {"name": "_render", "rva": "0x4ee360", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/render/render.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "render", "owner": "source/render/render.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=643736, HCEX !=643736, Sept map ok+gap12))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=643736, HCEX !=643736, Sept map ok+gap12)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #56", "RF-CV review"]}, + {"name": "_rasterizer_lights", "rva": "0x58b600", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/rasterizer/rasterizer_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "rasterizer_lights", "owner": "source/rasterizer/rasterizer_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=7176, HCEX !=7176, Sept map ok+gap28))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=7176, HCEX !=7176, Sept map ok+gap28)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #57", "RF-CV review"]}, + {"name": "_rasterizer_frame_statistics", "rva": "0x58d220", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/rasterizer/rasterizer_frame_statistics.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "rasterizer_frame_statistics", "owner": "source/rasterizer/rasterizer_frame_statistics.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=28, HCEX !=28, Sept map =))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=28, HCEX !=28, Sept map =)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #58", "RF-CV review"]}, + {"name": "_rasterizer_model_cortana_hack", "rva": "0x58d390", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/rasterizer/xbox/rasterizer_xbox_models.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "rasterizer_dx9_models", "owner": "source/rasterizer/xbox/rasterizer_xbox_models.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); platform-sibling mapping: sibling rasterizer_dx9_models.obj->rasterizer_xbox_models.obj)", "caveats": ["single definer channel (D); platform-sibling mapping: sibling rasterizer_dx9_models.obj->rasterizer_xbox_models.obj"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #59", "RF-CV review"]}, + {"name": "_texture_table", "rva": "0x58d3a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #60", "RF-CV review"]}, + {"name": "_texturestagestate_table", "rva": "0x58d3c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #61", "RF-CV review"]}, + {"name": "_renderstate_table", "rva": "0x58d5c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #62", "RF-CV review"]}, + {"name": "_global_d3d_caps", "rva": "0x58d800", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/rasterizer/xbox/rasterizer_xbox.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "rasterizer_dx9", "owner": "source/rasterizer/xbox/rasterizer_xbox.c", "mapping": "sibling", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); platform-sibling mapping: sibling rasterizer_dx9.obj->rasterizer_xbox.obj; size not independently confirmed (demo !=304, HCEX !=304, Sept map ok+gap12))", "caveats": ["single definer channel (D); platform-sibling mapping: sibling rasterizer_dx9.obj->rasterizer_xbox.obj; size not independently confirmed (demo !=304, HCEX !=304, Sept map ok+gap12)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #63", "RF-CV review"]}, + {"name": "_pixel_shader", "rva": "0x58d8e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #64", "RF-CV review"]}, + {"name": "_global_window_parameters", "rva": "0x58d9e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/rasterizer/common/rasterizer_common.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "rasterizer_common", "owner": "source/rasterizer/common/rasterizer_common.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); owner rasterizer_common.obj is not a January referencer (refs: rasterizer.obj, rasterizer_debug.obj, rasterizer_lights.obj, rasterizer_text.obj, rasterizer_transparent_geometry.obj, rasterizer_xbox.obj, rasterizer_xbox_active_camouflage.obj, rasterizer_xbox_debug.obj, rasterizer_xbox_decals.obj, rasterizer_xbox_draw_primitives.obj, rasterizer_xbox_dynavobgeom.obj, rasterizer_xbox_environment.obj, rasterizer_xbox_environment_fog.obj, rasterizer_xbox_lights.obj, rasterizer_xbox_models.obj, rasterizer_xbox_motion_sensor.obj, rasterizer_xbox_profile.obj, rasterizer_xbox_screen_effect.obj, rasterizer_xbox_shadows.obj, rasterizer_xbox_text.obj, rasterizer_xbox_transparent_geometry.obj, rasterizer_xbox_water.obj, rasterizer_xbox_widgets.obj))", "caveats": ["single definer channel (D); owner rasterizer_common.obj is not a January referencer (refs: rasterizer.obj, rasterizer_debug.obj, rasterizer_lights.obj, rasterizer_text.obj, rasterizer_transparent_geometry.obj, rasterizer_xbox.obj, rasterizer_xbox_active_camouflage.obj, rasterizer_xbox_debug.obj, rasterizer_xbox_decals.obj, rasterizer_xbox_draw_primitives.obj, rasterizer_xbox_dynavobgeom.obj, rasterizer_xbox_environment.obj, rasterizer_xbox_environment_fog.obj, rasterizer_xbox_lights.obj, rasterizer_xbox_models.obj, rasterizer_xbox_motion_sensor.obj, rasterizer_xbox_profile.obj, rasterizer_xbox_screen_effect.obj, rasterizer_xbox_shadows.obj, rasterizer_xbox_text.obj, rasterizer_xbox_transparent_geometry.obj, rasterizer_xbox_water.obj, rasterizer_xbox_widgets.obj)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #65", "RF-CV review"]}, + {"name": "_global_frame_parameters", "rva": "0x58dc38", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/rasterizer/common/rasterizer_common.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "rasterizer_common", "owner": "source/rasterizer/common/rasterizer_common.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=16, HCEX !=16, Sept map =))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=16, HCEX !=16, Sept map =)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #66", "RF-CV review"]}, + {"name": "_debug_point_physics", "rva": "0x58dc40", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/physics/point_physics.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "point_physics", "owner": "source/physics/point_physics.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "point_physics", "owner": "source/physics/point_physics.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on point_physics.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #67", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_collision_usage_buffer", "rva": "0x58dc60", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #68", "RF-CV review"]}, + {"name": "_collision_usage_current", "rva": "0x58ff00", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #69", "RF-CV review"]}, + {"name": "_global_current_collision_users", "rva": "0x590aa0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #70", "RF-CV review"]}, + {"name": "_collision_debug_phantom_bsp_point", "rva": "0x590ae0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #71", "RF-CV review"]}, + {"name": "_collision_debug_flags", "rva": "0x590aec", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #72", "RF-CV review"]}, + {"name": "_collision_debug_radius", "rva": "0x590af0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #73", "RF-CV review"]}, + {"name": "_collision_debug_center", "rva": "0x590b00", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #74", "RF-CV review"]}, + {"name": "_collision_debug_vector", "rva": "0x590b10", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #75", "RF-CV review"]}, + {"name": "_collision_debug_point", "rva": "0x590b20", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #76", "RF-CV review"]}, + {"name": "_collision_debug_flag_use_vehicle_physics", "rva": "0x590b2c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #77", "RF-CV review"]}, + {"name": "_collision_debug_flag_skip_passthrough_bipeds", "rva": "0x590b2d", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #78", "RF-CV review"]}, + {"name": "_collision_debug_flag_try_to_keep_location_valid", "rva": "0x590b2e", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #79", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_placeholders", "rva": "0x590b2f", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #80", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_light_fixtures", "rva": "0x590b30", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #81", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_controls", "rva": "0x590b31", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #82", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_machines", "rva": "0x590b32", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #83", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_scenery", "rva": "0x590b33", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #84", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_projectiles", "rva": "0x590b34", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #85", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_equipment", "rva": "0x590b35", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #86", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_weapons", "rva": "0x590b36", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #87", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_vehicles", "rva": "0x590b37", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #88", "RF-CV review"]}, + {"name": "_collision_debug_flag_objects_bipeds", "rva": "0x590b38", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #89", "RF-CV review"]}, + {"name": "_collision_debug_flag_ignore_breakable_surfaces", "rva": "0x590b39", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #90", "RF-CV review"]}, + {"name": "_collision_debug_flag_ignore_two_sided_surfaces", "rva": "0x590b3a", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #91", "RF-CV review"]}, + {"name": "_collision_debug_flag_back_facing_surfaces", "rva": "0x590b3b", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #92", "RF-CV review"]}, + {"name": "_collision_debug_repeat", "rva": "0x590b3c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #93", "RF-CV review"]}, + {"name": "_collision_debug_features", "rva": "0x590b3d", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #94", "RF-CV review"]}, + {"name": "_collision_debug_spray", "rva": "0x590b3e", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #95", "RF-CV review"]}, + {"name": "_collision_debug", "rva": "0x590b3f", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/physics/collision_debug.c", "readouts": [{"channel": "OD", "names": "collision_debug", "owner": "source/physics/collision_debug.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #96", "RF-CV review"]}, + {"name": "_node_count", "rva": "0x590b40", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/physics/bsp3d.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "bsp3d", "owner": "source/physics/bsp3d.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "bsp3d", "owner": "source/physics/bsp3d.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on bsp3d.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #97", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_objects_names", "rva": "0x590b44", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/objects/objects.c", "readouts": [{"channel": "OD", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #98", "RF-CV review"]}, + {"name": "_debug_objects_pathfinding_spheres", "rva": "0x590b45", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/objects/objects.c", "readouts": [{"channel": "OD", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #99", "RF-CV review"]}, + {"name": "_debug_objects_physics", "rva": "0x590b46", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/objects/objects.c", "readouts": [{"channel": "OD", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #100", "RF-CV review"]}, + {"name": "_debug_objects_root_node", "rva": "0x590b47", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/objects/objects.c", "readouts": [{"channel": "OD", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #101", "RF-CV review"]}, + {"name": "_global_object_marker", "rva": "0x590b48", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/objects/objects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #102", "RF-CV review"]}, + {"name": "_noncollideable_object_cluster_partition", "rva": "0x590b50", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/objects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on objects.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #103", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_collideable_object_cluster_partition", "rva": "0x590b60", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/objects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on objects.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #104", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_object_garbage_collection", "rva": "0x590b6c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #105", "RF-CV review"]}, + {"name": "_object_header_data", "rva": "0x590b70", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/objects/objects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "objects", "owner": "source/objects/objects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #106", "RF-CV review"]}, + {"name": "_first_object_type_definition", "rva": "0x590b74", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/object_types.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_types", "owner": "source/objects/object_types.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_types", "owner": "source/objects/object_types.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on object_types.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #107", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_lights", "rva": "0x590b78", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/object_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(object_lights.c) (RF-CV)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on object_lights.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #108", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_object_lights", "rva": "0x590b79", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/object_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(object_lights.c) (RF-CV)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on object_lights.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #109", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_rasterizer_light_count", "rva": "0x590b7a", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/object_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on object_lights.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #110", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_lights_globals", "rva": "0x590b80", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/object_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on object_lights.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #111", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_light_cluster_partition", "rva": "0x590ed0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/object_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on object_lights.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #112", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_light_data", "rva": "0x590edc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/objects/object_lights.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lights", "owner": "source/objects/object_lights.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #113", "RF-CV review"]}, + {"name": "_debug_damage", "rva": "0x590ee0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/damage.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "damage", "owner": "source/objects/damage.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "damage", "owner": "source/objects/damage.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on damage.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #114", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_widget_data", "rva": "0x590ee4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/widgets/widgets.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "widgets", "owner": "source/objects/widgets/widgets.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "widgets", "owner": "source/objects/widgets/widgets.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on widgets.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #115", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_glow_globals", "rva": "0x590ee8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/widgets/glow.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "glow", "owner": "source/objects/widgets/glow.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "glow", "owner": "source/objects/widgets/glow.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on glow.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #116", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_flag_data", "rva": "0x590ef0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/widgets/flags.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "flags", "owner": "source/objects/widgets/flags.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "flags", "owner": "source/objects/widgets/flags.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on flags.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #117", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_antenna_data", "rva": "0x590ef4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/objects/widgets/antenna.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "antenna", "owner": "source/objects/widgets/antenna.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "antenna", "owner": "source/objects/widgets/antenna.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on antenna.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #118", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_network_game_server_memory_do_not_use_directly", "rva": "0x590f00", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/networking/network_server_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "network_server_manager", "owner": "source/networking/network_server_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "L", "names": "network_server_manager", "owner": "source/networking/network_server_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (size not independently confirmed (demo !=2476, HCEX None, Sept map ok+gap4))", "caveats": ["size not independently confirmed (demo !=2476, HCEX None, Sept map ok+gap4)", "readout count alone would allow inferred; tag held at probable by the recorded caveat (never raised by the verifier)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #119", "RF-CV review"]}, + {"name": "_network_game_client_dont_use_directly", "rva": "0x5913c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/networking/network_client_manager.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "network_client_manager", "owner": "source/networking/network_client_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "L", "names": "network_client_manager", "owner": "source/networking/network_client_manager.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (size not independently confirmed (demo !=2956, HCEX None, Sept map =))", "caveats": ["size not independently confirmed (demo !=2956, HCEX None, Sept map =)", "readout count alone would allow inferred; tag held at probable by the recorded caveat (never raised by the verifier)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #120", "RF-CV review"]}, + {"name": "_render_model_no_geometry", "rva": "0x592070", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/models/models.c", "readouts": [{"channel": "OD", "names": "models", "owner": "source/models/models.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #121", "RF-CV review"]}, + {"name": "_render_model_markers", "rva": "0x592071", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/models/models.c", "readouts": [{"channel": "OD", "names": "models", "owner": "source/models/models.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #122", "RF-CV review"]}, + {"name": "_render_model_index_counts", "rva": "0x592072", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/models/models.c", "readouts": [{"channel": "OD", "names": "models", "owner": "source/models/models.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #123", "RF-CV review"]}, + {"name": "_render_model_vertex_counts", "rva": "0x592073", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/models/models.c", "readouts": [{"channel": "OD", "names": "models", "owner": "source/models/models.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R2b: OD-only, strict /Od EDGE -> no counted readout", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #124", "RF-CV review"]}, + {"name": "_render_model_nodes", "rva": "0x592074", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/models/models.c", "candidate_owner": null, "readouts": [{"channel": "X", "names": "models", "owner": "source/models/models.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (X); size not independently confirmed (demo None, HCEX None, Sept map =))", "caveats": ["single definer channel (X); size not independently confirmed (demo None, HCEX None, Sept map =)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #125", "RF-CV review"]}, + {"name": "_debug_render_freeze", "rva": "0x592075", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/main/main.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "main", "owner": "source/main/main.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "main", "owner": "source/main/main.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "main", "owner": "source/main/main.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(main.c) (RF-CV)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on main.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #126", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_cached_variant_profile", "rva": "0x592080", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/interface/ui_widget_game_data_input_functions.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ui_widget_game_data_input_functions", "owner": "source/interface/ui_widget_game_data_input_functions.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=468, HCEX !=468, Sept map ok+gap28))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=468, HCEX !=468, Sept map ok+gap28)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #127", "RF-CV review"]}, + {"name": "_cached_player_profile", "rva": "0x5921e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/interface/ui_widget_game_data_input_functions.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ui_widget_game_data_input_functions", "owner": "source/interface/ui_widget_game_data_input_functions.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=24576, HCEX !=5952, Sept map =))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=24576, HCEX !=5952, Sept map =)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #128", "RF-CV review"]}, + {"name": "_local_player_index_for_draw_string_and_hack_in_icons", "rva": "0x59227c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/ui_widget.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ui_widget", "owner": "source/interface/ui_widget.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "ui_widget", "owner": "source/interface/ui_widget.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on ui_widget.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #129", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_ui_plasma_effect_color", "rva": "0x592280", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/ui_widget.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ui_widget", "owner": "source/interface/ui_widget.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "ui_widget", "owner": "source/interface/ui_widget.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on ui_widget.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #130", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_light_z", "rva": "0x592290", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #131", "RF-CV review"]}, + {"name": "_light_y", "rva": "0x592294", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #132", "RF-CV review"]}, + {"name": "_light_x", "rva": "0x592298", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #133", "RF-CV review"]}, + {"name": "_blur_shader", "rva": "0x5922a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #134", "RF-CV review"]}, + {"name": "_regular_shader", "rva": "0x5923a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #135", "RF-CV review"]}, + {"name": "_current_time", "rva": "0x592490", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #136", "RF-CV review"]}, + {"name": "_profile_graph", "rva": "0x592494", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #137", "RF-CV review"]}, + {"name": "_profile_display", "rva": "0x592495", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #138", "RF-CV review"]}, + {"name": "_blip_player_index", "rva": "0x592496", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/motion_sensor.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on motion_sensor.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #139", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_num_drawn", "rva": "0x592498", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/motion_sensor.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on motion_sensor.obj; no January referencer (unreferenced tentative definition; NOREF link keeps it))", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #140", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE (CP-N): unreferenced; D+X; pool 139/140 bracketed by motion_sensor records; types rest on later builds"]}, + {"name": "_num_triangles", "rva": "0x59249a", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/motion_sensor.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on motion_sensor.obj; no January referencer (unreferenced tentative definition; NOREF link keeps it))", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #141", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE (CP-N): unreferenced; D+X; pool 139/140 bracketed by motion_sensor records; types rest on later builds"]}, + {"name": "_center_point", "rva": "0x5924a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/motion_sensor.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on motion_sensor.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #142", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_color32", "rva": "0x5924a8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/motion_sensor.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "motion_sensor", "owner": "source/interface/motion_sensor.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on motion_sensor.obj; no January referencer (unreferenced tentative definition; NOREF link keeps it))", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #143", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER (CP-N): unreferenced; typedef spelling unrecoverable (unsigned long vs pixel32)"]}, + {"name": "_hud_msg_def", "rva": "0x5924ac", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/hud_messaging.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hud_messaging", "owner": "source/interface/hud_messaging.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "hud_messaging", "owner": "source/interface/hud_messaging.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on hud_messaging.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #144", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_temporary_hud", "rva": "0x5924b0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/interface/hud.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hud", "owner": "source/interface/hud.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "hud", "owner": "source/interface/hud.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on hud.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #145", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_object_list_data", "rva": "0x5924b4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/hs/object_lists.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lists", "owner": "source/hs/object_lists.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lists", "owner": "source/hs/object_lists.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on object_lists.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #146", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_object_list_header_data", "rva": "0x5924b8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/hs/object_lists.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "object_lists", "owner": "source/hs/object_lists.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "object_lists", "owner": "source/hs/object_lists.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on object_lists.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #147", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_trigger_volumes", "rva": "0x5924bc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/hs/hs_runtime.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "OD", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": false, "source": "RF-CP", "note": "not counted: strict /Od verdict EDGE (RF-CV; owner approved the strict rule for records)"}], "basis": "R1: RF-CP PROVEN (3 independent definer channels agree (D+OD+X) on hs_runtime.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #148", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_debug_scripting", "rva": "0x5924bd", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/hs/hs_runtime.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on hs_runtime.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #149", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_hs_debug_data", "rva": "0x5924c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": "source/hs/hs_runtime.c", "readouts": [], "containment_evidence": [{"kind": "pool-containment", "candidate_owner": "source/hs/hs_runtime.c", "lower_neighbours": ["_debug_trigger_volumes", "_debug_scripting"], "upper_neighbours": ["_hs_global_data", "_hs_thread_data"], "neighbour_owner_evidence": "RF-DI (own readers): all four neighbours -> hs_runtime (PC demo LTCG GlobalRefs; HCEX and HCEX_Release non-LTCG singletons; January referencer sets from cachebeta.exe base relocations; Aug/Sept-2001 debug maps in the same order); this ledger tags all four inferred with owner source/hs/hs_runtime.c", "ordering_model": "RF-DI C01 on the production linker (Link 7.00.9290 = the lane linker, byte-identical): the pool follows the linker's module list; each module contributes the COMMON records it FIRST tentatively defined. Records between two records with the same first tentative definer O were first tentatively defined by O. Not implied: exclusivity, that O references it, its type or its declared bound.", "veto_check": "RF-DI: no contradictory January storage/import evidence ('* Linker *' COMMON 32 B, no real definition, no initializer; January referencers hs_runtime 2 + hs_library_external 6 relocations; no imports/exports; 2001 debug maps ; Sept-2001 retail map lacks it: neutral)", "ruling": "Narrow P-HS' ruling (Rule 48 / hs_debug_data, 2026-09-27): containment supports an inferred first tentative definer, not proof of exclusive ownership; P-HS' landed at zero credit (R62i). hs_debug_data ledger ruling (2026-09-27): candidate owner, unresolved; that ruling authorized the tentative definition, it did not establish a new provenance family or upgrade the ledger classification.", "sources": ["research/remaining_frontier_20260926/workers/RF-DI/REPORT.md", "research/remaining_frontier_20260926/workers/RF-DI/NOTES.md (22:03-22:16: neighbours, veto check, verdicts)", "research/remaining_frontier_20260926/workers/RF-DI/cards/C01_production_linker_pool_lab.md", "research/remaining_frontier_20260926/workers/RF-DI/evidence/pool_pdb.tsv", "research/remaining_frontier_20260926/workers/RF-DI/evidence/jan_sites_hs_debug_data.txt", "research/remaining_frontier_20260926/OWNER_PACKET.md (Rule 48 / hs_debug_data; P-HS' landing; hs_debug_data ledger)"]}], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent); candidate owner source/hs/hs_runtime.c from pool containment (RF-DI), recorded as containment_evidence only: containment is not a definer readout and never raises the tag (owner rulings 2026-09-27)", "caveats": ["candidate owner only: containment supports an inferred first tentative definer, not ownership; no definer readout exists (absent from the PC demo and both HCEX PDBs); tag stays unresolved"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #150", "RF-CV review", "RF-DI review (containment, neighbours, veto check)", "OWNER_PACKET 2026-09-27: Rule 48 / hs_debug_data; P-HS'; hs_debug_data ledger"]}, + {"name": "_hs_global_data", "rva": "0x5924e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/hs/hs_runtime.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on hs_runtime.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #151", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_hs_thread_data", "rva": "0x5924e4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/hs/hs_runtime.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "hs_runtime", "owner": "source/hs/hs_runtime.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on hs_runtime.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #152", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_hs_syntax_data", "rva": "0x5924e8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/hs/hs.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "hs", "owner": "source/hs/hs.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #153", "RF-CV review"]}, + {"name": "_players_globals", "rva": "0x5924ec", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/game/players.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "players", "owner": "source/game/players.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "players", "owner": "source/game/players.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on players.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #154", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_team_data", "rva": "0x5924f0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/game/players.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "players", "owner": "source/game/players.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "players", "owner": "source/game/players.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on players.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #155", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_player_data", "rva": "0x5924f4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/game/players.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "players", "owner": "source/game/players.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #156", "RF-CV review"]}, + {"name": "_global_default_animation_colors", "rva": "0x592500", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/game/game_engine_king.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_engine_king", "owner": "source/game/game_engine_king.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_engine_king", "owner": "source/game/game_engine_king.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on game_engine_king.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #157", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_global_default_animation_values", "rva": "0x592530", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/game/game_engine_king.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_engine_king", "owner": "source/game/game_engine_king.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_engine_king", "owner": "source/game/game_engine_king.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on game_engine_king.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #158", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_game_engine_globals", "rva": "0x592540", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/game/game_engine.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_engine", "owner": "source/game/game_engine.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_engine", "owner": "source/game/game_engine.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on game_engine.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #159", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_timeout_for_endgame_sound", "rva": "0x592564", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/game/game_engine.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_engine", "owner": "source/game/game_engine.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #160", "RF-CV review"]}, + {"name": "_global_stage", "rva": "0x592580", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/game/game_engine.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game_engine", "owner": "source/game/game_engine.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game_engine", "owner": "source/game/game_engine.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (size not independently confirmed (demo !=216, HCEX !=216, Sept map ok+gap24))", "caveats": ["size not independently confirmed (demo !=216, HCEX !=216, Sept map ok+gap24)", "readout count alone would allow inferred; tag held at probable by the recorded caveat (never raised by the verifier)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #161", "RF-CV review"]}, + {"name": "_game_variant_global", "rva": "0x592640", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/game/game.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "game", "owner": "source/game/game.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "game", "owner": "source/game/game.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (size not independently confirmed (demo !=152, HCEX !=152, Sept map ok+gap8))", "caveats": ["size not independently confirmed (demo !=152, HCEX !=152, Sept map ok+gap8)", "readout count alone would allow inferred; tag held at probable by the recorded caveat (never raised by the verifier)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #162", "RF-CV review"]}, + {"name": "_cheat", "rva": "0x5926b0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/game/cheats.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "cheats", "owner": "source/game/cheats.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #163", "RF-CV review"]}, + {"name": "_weather_particle_data", "rva": "0x5926bc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/effects/weather_particle_systems.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "weather_particle_systems", "owner": "source/effects/weather_particle_systems.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "weather_particle_systems", "owner": "source/effects/weather_particle_systems.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on weather_particle_systems.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #164", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_particle_data", "rva": "0x5926c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/effects/particles.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "particles", "owner": "source/effects/particles.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #165", "RF-CV review"]}, + {"name": "_system_particles", "rva": "0x5926c4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/effects/particle_systems.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "particle_systems", "owner": "source/effects/particle_systems.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "particle_systems", "owner": "source/effects/particle_systems.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on particle_systems.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #166", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_particle_systems", "rva": "0x5926c8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/effects/particle_systems.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "particle_systems", "owner": "source/effects/particle_systems.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "particle_systems", "owner": "source/effects/particle_systems.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on particle_systems.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #167", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_effect_location_data", "rva": "0x5926cc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/effects/effects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "effects", "owner": "source/effects/effects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "effects", "owner": "source/effects/effects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on effects.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #168", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_effect_data", "rva": "0x5926d0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/effects/effects.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "effects", "owner": "source/effects/effects.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #169", "RF-CV review"]}, + {"name": "_debug_decals", "rva": "0x5926d4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/effects/decals.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "decals", "owner": "source/effects/decals.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "decals", "owner": "source/effects/decals.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on decals.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #170", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_global_decal_data", "rva": "0x5926d8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/effects/decals.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "decals", "owner": "source/effects/decals.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #171", "RF-CV review"]}, + {"name": "_contrail_point_data", "rva": "0x5926dc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/effects/contrails.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "contrails", "owner": "source/effects/contrails.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #172", "RF-CV review"]}, + {"name": "_contrail_data", "rva": "0x5926e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/effects/contrails.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "contrails", "owner": "source/effects/contrails.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #173", "RF-CV review"]}, + {"name": "_debug_objects_devices", "rva": "0x5926e4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #174", "RF-CV review"]}, + {"name": "_device_groups_data", "rva": "0x5926e8", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/devices/devices.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "devices", "owner": "source/devices/devices.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #175", "RF-CV review"]}, + {"name": "_error_globals", "rva": "0x592700", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/cseries/errors.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "errors", "owner": "source/cseries/errors.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); size not independently confirmed (demo !=4106, HCEX !=4106, Sept map ok+gap24))", "caveats": ["single definer channel (D); size not independently confirmed (demo !=4106, HCEX !=4106, Sept map ok+gap24)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #176", "RF-CV review"]}, + {"name": "_temporary", "rva": "0x592f20", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/cseries/cseries.c", "candidate_owner": null, "readouts": [{"channel": "X", "names": "cseries", "owner": "source/cseries/cseries.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (X); owner cseries.obj is not a January referencer (refs: action_obey.obj, actor_combat.obj, actor_firing_position.obj, actor_looking.obj, actor_moving.obj, actors.obj, ai.obj, ai_communication.obj, ai_debug.obj, ai_script.obj, encounters.obj, path_obstacle_avoidance.obj, bink_playback.obj, bitmap_drawing.obj, bitmap_utilities.obj, bitmaps.obj, cache_files.obj, cache_files_windows.obj, xbox_sound_cache.obj, bored_camera.obj, camera_scripting.obj, dead_camera.obj, editor_flying_camera.obj, first_person_camera.obj, flying_camera.obj, following_camera.obj, observer.obj, orbiting_camera.obj, static_camera.obj, debug_memory.obj, recorded_animations.obj, contrails.obj, decals.obj, effects.obj, particles.obj, player_effects.obj, aim_assist.obj, player_control.obj, player_queues_new.obj, players.obj, hs_library_external.obj, hs_runtime.obj, hud.obj, hud_draw.obj, hud_messaging.obj, hud_nav_points.obj, hud_unit.obj, hud_weapon.obj, motion_sensor.obj, terminal.obj, projectiles.obj, weapons.obj, integer_math.obj, real_math.obj, byte_swapping.obj, circular_queue.obj, data.obj, data_packets.obj, lra_cache.obj, lrar_cache.obj, lru_cache.obj, memory_pool.obj, model_animations.obj, network_messages.obj, object_types.obj, objects.obj, collisions.obj, physics.obj, point_physics.obj, rasterizer.obj, rasterizer_geometry.obj, rasterizer_xbox.obj, render_cameras.obj, render_sprite.obj, game_state.obj, game_state_xbox.obj, scenario.obj, sound_dsound_xbox.obj, cluster_partitions.obj, tag_groups.obj, international_strings.obj, error_geometry.obj, bipeds.obj, units.obj); size not independently confirmed (demo None, HCEX None, Sept map =))", "caveats": ["single definer channel (X); owner cseries.obj is not a January referencer (refs: action_obey.obj, actor_combat.obj, actor_firing_position.obj, actor_looking.obj, actor_moving.obj, actors.obj, ai.obj, ai_communication.obj, ai_debug.obj, ai_script.obj, encounters.obj, path_obstacle_avoidance.obj, bink_playback.obj, bitmap_drawing.obj, bitmap_utilities.obj, bitmaps.obj, cache_files.obj, cache_files_windows.obj, xbox_sound_cache.obj, bored_camera.obj, camera_scripting.obj, dead_camera.obj, editor_flying_camera.obj, first_person_camera.obj, flying_camera.obj, following_camera.obj, observer.obj, orbiting_camera.obj, static_camera.obj, debug_memory.obj, recorded_animations.obj, contrails.obj, decals.obj, effects.obj, particles.obj, player_effects.obj, aim_assist.obj, player_control.obj, player_queues_new.obj, players.obj, hs_library_external.obj, hs_runtime.obj, hud.obj, hud_draw.obj, hud_messaging.obj, hud_nav_points.obj, hud_unit.obj, hud_weapon.obj, motion_sensor.obj, terminal.obj, projectiles.obj, weapons.obj, integer_math.obj, real_math.obj, byte_swapping.obj, circular_queue.obj, data.obj, data_packets.obj, lra_cache.obj, lrar_cache.obj, lru_cache.obj, memory_pool.obj, model_animations.obj, network_messages.obj, object_types.obj, objects.obj, collisions.obj, physics.obj, point_physics.obj, rasterizer.obj, rasterizer_geometry.obj, rasterizer_xbox.obj, render_cameras.obj, render_sprite.obj, game_state.obj, game_state_xbox.obj, scenario.obj, sound_dsound_xbox.obj, cluster_partitions.obj, tag_groups.obj, international_strings.obj, error_geometry.obj, bipeds.obj, units.obj); size not independently confirmed (demo None, HCEX None, Sept map =)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #177", "RF-CV review"]}, + {"name": "_director_camera_scripted", "rva": "0x593020", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/camera/director.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "director", "owner": "source/camera/director.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "director", "owner": "source/camera/director.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on director.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #178", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE SPELLING OPEN (CP-T)"]}, + {"name": "_server_transport_globals", "rva": "0x593024", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #179", "RF-CV review"]}, + {"name": "_global_key", "rva": "0x593030", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #180", "RF-CV review"]}, + {"name": "_global_key_id", "rva": "0x593040", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #181", "RF-CV review"]}, + {"name": "_global_nonce", "rva": "0x593048", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #182", "RF-CV review"]}, + {"name": "_global_address", "rva": "0x593050", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #183", "RF-CV review"]}, + {"name": "_prop_data", "rva": "0x59305c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/props.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "props", "owner": "source/ai/props.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #184", "RF-CV review"]}, + {"name": "_debug_obstacle_path_radius", "rva": "0x593060", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #185", "RF-CV review"]}, + {"name": "_debug_ignore_broken_surfaces", "rva": "0x593064", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #186", "RF-CV review"]}, + {"name": "_debug_obstacle_path_finishing", "rva": "0x593065", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #187", "RF-CV review"]}, + {"name": "_debug_obstacle_path_goal_surface_index", "rva": "0x593068", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (compiled out (demo hs table entry has NULL address)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #188", "RF-CV review"]}, + {"name": "_debug_obstacle_path_goal_point", "rva": "0x593070", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #189", "RF-CV review"]}, + {"name": "_debug_obstacle_path_start_surface_index", "rva": "0x59307c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/path_obstacle_avoidance.c", "candidate_owner": null, "readouts": [{"channel": "OD", "names": "path_obstacle_avoidance", "owner": "source/ai/path_obstacle_avoidance.c", "mapping": "direct", "counted": true, "source": "RF-CP", "note": "strict /Od SANDWICH(path_obstacle_avoidance.c) (RF-CV)"}], "basis": "R2b: OD-only, strict /Od SANDWICH(path_obstacle_avoidance.c)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #190", "RF-CV review"]}, + {"name": "_debug_obstacle_path_start_point", "rva": "0x593080", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #191", "RF-CV review"]}, + {"name": "_pursuit_data", "rva": "0x59308c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/ai/encounters.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "encounters", "owner": "source/ai/encounters.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "encounters", "owner": "source/ai/encounters.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on encounters.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #192", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_encounter_data", "rva": "0x593090", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/encounters.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "encounters", "owner": "source/ai/encounters.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #193", "RF-CV review"]}, + {"name": "_platoon_array", "rva": "0x593094", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/encounters.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "encounters", "owner": "source/ai/encounters.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #194", "RF-CV review"]}, + {"name": "_squad_array", "rva": "0x593098", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/encounters.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "encounters", "owner": "source/ai/encounters.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #195", "RF-CV review"]}, + {"name": "_profilestring", "rva": "0x5930a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #196", "RF-CV review"]}, + {"name": "_global_ai_profile_string_position", "rva": "0x5938a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #197", "RF-CV review"]}, + {"name": "_ai_profile", "rva": "0x5938c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #198", "RF-CV review"]}, + {"name": "_global_ai_debug_string_position", "rva": "0x5947ac", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #199", "RF-CV review"]}, + {"name": "_global_ai_debug_drawstack_height", "rva": "0x5947b0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #200", "RF-CV review"]}, + {"name": "_global_ai_debug_drawstack_last_position", "rva": "0x5947c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #201", "RF-CV review"]}, + {"name": "_global_ai_debug_drawstack_next_position", "rva": "0x5947d0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #202", "RF-CV review"]}, + {"name": "_ai_debug", "rva": "0x5947e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "unresolved", "owner": null, "candidate_owner": null, "readouts": [], "basis": "R3: RF-CP UNRESOLVED (no affirmative definer observation: absent from PC demo (no demo record and no hs table entry (Xbox-only or debug-only, removed)); HCEX: absent)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #203", "RF-CV review"]}, + {"name": "_conversation_data", "rva": "0x61a30c", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/ai_communication.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ai_communication", "owner": "source/ai/ai_communication.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #204", "RF-CV review"]}, + {"name": "_global_communication_table_indices", "rva": "0x61a320", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/ai/ai_communication.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ai_communication", "owner": "source/ai/ai_communication.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "ai_communication", "owner": "source/ai/ai_communication.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on ai_communication.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #205", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; FIX placement (A1 line is in the prototypes block) -> F1"]}, + {"name": "_ai_globals", "rva": "0x61a394", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/ai.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ai", "owner": "source/ai/ai.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #206", "RF-CV review"]}, + {"name": "_global_continuous_damage_reference", "rva": "0x61a3a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/ai.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ai", "owner": "source/ai/ai.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); no January referencer (unreferenced tentative definition; NOREF link keeps it))", "caveats": ["single definer channel (D); no January referencer (unreferenced tentative definition; NOREF link keeps it)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #207", "RF-CV review"]}, + {"name": "_global_damage_reference", "rva": "0x61a3b0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/ai.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "ai", "owner": "source/ai/ai.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D); no January referencer (unreferenced tentative definition; NOREF link keeps it))", "caveats": ["single definer channel (D); no January referencer (unreferenced tentative definition; NOREF link keeps it)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #208", "RF-CV review"]}, + {"name": "_swarm_component_data", "rva": "0x61a3bc", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/actors.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actors", "owner": "source/ai/actors.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #209", "RF-CV review"]}, + {"name": "_swarm_data", "rva": "0x61a3c0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/actors.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actors", "owner": "source/ai/actors.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #210", "RF-CV review"]}, + {"name": "_actor_data", "rva": "0x61a3c4", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "source/ai/actors.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actors", "owner": "source/ai/actors.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R2: RF-CP PROBABLE (single definer channel (D))", "caveats": ["single definer channel (D)"], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #211", "RF-CV review"]}, + {"name": "_avoidance_rays", "rva": "0x61a3e0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/ai/actor_moving.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actor_moving", "owner": "source/ai/actor_moving.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "actor_moving", "owner": "source/ai/actor_moving.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on actor_moving.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #212", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE-OWNER; TYPE OK (RF-CP misread [2][8]); move CP-T -> CP-A1"]}, + {"name": "_avoidance_directions", "rva": "0x61a5a0", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/ai/actor_moving.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actor_moving", "owner": "source/ai/actor_moving.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "actor_moving", "owner": "source/ai/actor_moving.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on actor_moving.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #213", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_sense_rays", "rva": "0x61a600", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/ai/actor_moving.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actor_moving", "owner": "source/ai/actor_moving.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "actor_moving", "owner": "source/ai/actor_moving.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on actor_moving.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #214", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_global_temporary_render_color", "rva": "0x61a700", "segment": "halo", "category": "halobetacache", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "inferred", "owner": "source/ai/actions.c", "candidate_owner": null, "readouts": [{"channel": "D", "names": "actions", "owner": "source/ai/actions.c", "mapping": "direct", "counted": true, "source": "RF-CP"}, {"channel": "X", "names": "actions", "owner": "source/ai/actions.c", "mapping": "direct", "counted": true, "source": "RF-CP"}], "basis": "R1: RF-CP PROVEN (2 independent definer channels agree (D+X) on actions.obj)", "caveats": [], "sources": ["RF-CP PER_RECORD_TABLE_49905d70.tsv #215", "RF-CV review", "RF-CV PROVEN_REVIEW verdict: AGREE"]}, + {"name": "_OHCD_GlobalPool", "rva": "0x61a720", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\pool.obj defines this exact name as COMMON(48) == January extent", "tag": "probable", "owner": "libs/xapilib/pool.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\pool.obj", "owner": "libs/xapilib/pool.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\pool.obj", "definition": "COMMON", "size": 48, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 495 = obj\\i386\\pool.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 495 = obj\\i386\\pool.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_OHCD_InterruptObject", "rva": "0x61a760", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\ohcd.obj defines this exact name as COMMON(112) == January extent", "tag": "probable", "owner": "libs/xapilib/ohcd.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\ohcd.obj", "owner": "libs/xapilib/ohcd.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\ohcd.obj", "definition": "COMMON", "size": 112, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 494 = obj\\i386\\ohcd.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 494 = obj\\i386\\ohcd.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_XapiAutoPowerDownGlobals", "rva": "0x61a7e0", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\powerdwn.obj defines this exact name as COMMON(80) == January extent", "tag": "probable", "owner": "libs/xapilib/powerdwn.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\powerdwn.obj", "owner": "libs/xapilib/powerdwn.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\powerdwn.obj", "definition": "COMMON", "size": 80, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 510 = obj\\i386\\powerdwn.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 510 = obj\\i386\\powerdwn.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_CheckHeapFillPattern", "rva": "0x61a830", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\heap.obj defines this exact name as COMMON(16) == January extent", "tag": "probable", "owner": "libs/xapilib/heap.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\heap.obj", "owner": "libs/xapilib/heap.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\heap.obj", "definition": "COMMON", "size": 16, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 531 = obj\\i386\\heap.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 531 = obj\\i386\\heap.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_NtGlobalFlag", "rva": "0x61a840", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\heap.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/xapilib/heap.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\heap.obj", "owner": "libs/xapilib/heap.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\heap.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 531 = obj\\i386\\heap.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 531 = obj\\i386\\heap.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "___@@_PchSym_@00@UcylcRurmzouivUkirezgvUmglhUczkrUpDCUoryUlyqUrDIGUyzhvwooOlyq@Xapi_k32", "rva": "0x61a844", "segment": "vendor", "category": "xapilib", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "libs/xapilib/basedll.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\basedll.obj", "owner": "libs/xapilib/basedll.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\basedll.obj", "definition": "COMMON", "size": 4, "january_public": true, "january_pdb_module": "January cachebeta.pdb module 5 = obj\\i386\\basedll.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 5 = obj\\i386\\basedll.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link", "owner module 5 is not a config.json unit: no object of ours can define it"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_XapiProcessHeap", "rva": "0x61a848", "segment": "vendor", "category": "xapilib", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "libs/xapilib/xapiheap.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\xapiheap.obj", "owner": "libs/xapilib/xapiheap.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\xapiheap.obj", "definition": "COMMON", "size": 4, "january_public": true, "january_pdb_module": "January cachebeta.pdb module 504 = obj\\i386\\xapiheap.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 504 = obj\\i386\\xapiheap.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_XapiCurrentTopLevelFilter", "rva": "0x61a84c", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\thread.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/xapilib/thread.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\thread.obj", "owner": "libs/xapilib/thread.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\thread.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 507 = obj\\i386\\thread.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 507 = obj\\i386\\thread.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "_XapiTlsSize", "rva": "0x61a850", "segment": "vendor", "category": "xapilib", "name_evidence": "no January public; XDK 3911 xapilib.lib member obj\\i386\\thread.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/xapilib/thread.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "xapilib.lib", "member": "obj\\i386\\thread.obj", "owner": "libs/xapilib/thread.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "xapilib.lib", "library_sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", "member": "obj\\i386\\thread.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 507 = obj\\i386\\thread.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 507 = obj\\i386\\thread.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\xapilib.lib is in the link"], "sources": ["XDK 3911 xapilib.lib", "January cachebeta.pdb module list"]}, + {"name": "___@@_PchSym_@00@UcylcRurmzouivUkirezgvUdrmwldhUwrivxgcUwhlfmwUwhlfmwUlyqUrDIGUwhlfmwrOlyq@dsound", "rva": "0x61a854", "segment": "vendor", "category": "dsound", "name_evidence": "January cachebeta.pdb S_PUB32 of this name at this RVA", "tag": "probable", "owner": "libs/dsound/dsoundi.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "dsound.lib", "member": "obj\\i386\\dsoundi.obj", "owner": "libs/dsound/dsoundi.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "dsound.lib", "library_sha256": "0a07e97bdef6f18f5ec3b74aa4996d1bfe5cdbcdf561ceef22c0b671021ea136", "member": "obj\\i386\\dsoundi.obj", "definition": "COMMON", "size": 4, "january_public": true, "january_pdb_module": "January cachebeta.pdb module 1 = obj\\i386\\dsoundi.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\dsound.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 1 = obj\\i386\\dsoundi.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\dsound.lib is in the link"], "sources": ["XDK 3911 dsound.lib", "January cachebeta.pdb module list"]}, + {"name": "___mblcid", "rva": "0x61a858", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___ptmbcinfo", "rva": "0x61a85c", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___ismbcodepage", "rva": "0x61a860", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "__mbctype", "rva": "0x61a880", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(257) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 257, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___mbcodepage", "rva": "0x61a984", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___mbulinfo", "rva": "0x61a9a0", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(24) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 24, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "__mbcasemap", "rva": "0x61a9c0", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\mbctype.obj defines this exact name as COMMON(256) == January extent", "tag": "probable", "owner": "libs/libcmt/mbctype.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\mbctype.obj", "owner": "libs/libcmt/mbctype.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\mbctype.obj", "definition": "COMMON", "size": 256, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 776 = obj\\i386\\mbctype.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___active_heap", "rva": "0x61aac0", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\heapinit.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/heapinit.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\heapinit.obj", "owner": "libs/libcmt/heapinit.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\heapinit.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 803 = obj\\i386\\heapinit.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 803 = obj\\i386\\heapinit.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___ptd_glob", "rva": "0x61aac4", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\tidtable.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/tidtable.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\tidtable.obj", "owner": "libs/libcmt/tidtable.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\tidtable.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 750 = obj\\i386\\tidtable.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 750 = obj\\i386\\tidtable.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "__nhandle", "rva": "0x61aac8", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\ioinit.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/ioinit.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\ioinit.obj", "owner": "libs/libcmt/ioinit.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\ioinit.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 780 = obj\\i386\\ioinit.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 780 = obj\\i386\\ioinit.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___pioinfo", "rva": "0x61aae0", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\ioinit.obj defines this exact name as COMMON(256) == January extent", "tag": "probable", "owner": "libs/libcmt/ioinit.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\ioinit.obj", "owner": "libs/libcmt/ioinit.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\ioinit.obj", "definition": "COMMON", "size": 256, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 780 = obj\\i386\\ioinit.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 780 = obj\\i386\\ioinit.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___piob", "rva": "0x61abe0", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\_file.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/_file.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\_file.obj", "owner": "libs/libcmt/_file.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\_file.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 741 = obj\\i386\\_file.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 741 = obj\\i386\\_file.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "__nstream", "rva": "0x61abe4", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\_file.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/_file.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\_file.obj", "owner": "libs/libcmt/_file.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\_file.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 741 = obj\\i386\\_file.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 741 = obj\\i386\\_file.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___env_initialized", "rva": "0x61abe8", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\crt0dat.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/crt0dat.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\crt0dat.obj", "owner": "libs/libcmt/crt0dat.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\crt0dat.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___onexitend", "rva": "0x61abec", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\crt0dat.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/crt0dat.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\crt0dat.obj", "owner": "libs/libcmt/crt0dat.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\crt0dat.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___onexitbegin", "rva": "0x61abf0", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\crt0dat.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/crt0dat.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\crt0dat.obj", "owner": "libs/libcmt/crt0dat.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\crt0dat.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]}, + {"name": "___mbctype_initialized", "rva": "0x61abf4", "segment": "vendor", "category": "libcmt", "name_evidence": "no January public; XDK 3911 libcmt.lib member obj\\i386\\crt0dat.obj defines this exact name as COMMON(4) == January extent", "tag": "probable", "owner": "libs/libcmt/crt0dat.c", "candidate_owner": null, "readouts": [{"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\crt0dat.obj", "owner": "libs/libcmt/crt0dat.c", "mapping": "direct", "counted": true, "source": "XDK 3911 library (read as data)"}], "vendor_evidence": {"support": "xdk-library-member-only", "library": "libcmt.lib", "library_sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", "member": "obj\\i386\\crt0dat.obj", "definition": "COMMON", "size": 4, "january_public": false, "january_pdb_module": "January cachebeta.pdb module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib", "statement": "Supported only by an XDK 3911 library member (one evidence family: tag ceiling probable). Owner ruling 2026-09-27: vendor records supported only by an XDK library member remain probable, with that evidence explicitly recorded. Library version identity with January is inferred (the release library reproduces January's COMMON size; January's PDB module table lists the member)."}, "basis": "R4: single XDK readout (vendor library member defines the COMMON)", "caveats": ["library version identity with January inferred (XDK 3911); January PDB module 756 = obj\\i386\\crt0dat.obj from C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\LIBCMT.lib is in the link"], "sources": ["XDK 3911 libcmt.lib", "January cachebeta.pdb module list"]} + ] +} diff --git a/research/remaining_frontier_20260926/q10/mutation/KILLS.txt b/research/remaining_frontier_20260926/q10/mutation/KILLS.txt new file mode 100644 index 00000000..7aa28ea3 --- /dev/null +++ b/research/remaining_frontier_20260926/q10/mutation/KILLS.txt @@ -0,0 +1,125 @@ +BASELINE (unmutated) exit 0: 152 passed, 1 skipped in 5.73s +KILLED DE01 RF-DE size-mismatch: killers 2 failed 2 | 2 failed in 0.37s +KILLED DE02 RF-DE alignment-class-differs: killers 1 failed 1 | 1 failed in 0.33s +KILLED DE03 RF-DE duplicate-definers: killers 2 failed 2 | 2 failed in 0.39s +KILLED DE04 RF-DE no-definer: killers 3 failed 3 | 4 failed in 0.45s +KILLED DE05 RF-DE real-definition: killers 3 failed 3 | 5 failed in 0.52s +KILLED DE06 RF-DE static-definition: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE07 RF-DE static scan: killers 1 failed 1 | 1 failed in 0.31s +KILLED DE08 RF-DE missing-provenance-tag: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE09 RF-DE invalid-provenance-tag: killers 1 failed 1 | 4 failed in 0.50s +KILLED DE10 RF-DE tag-exceeds-evidence: killers 5 failed 5 | 10 failed in 0.78s +KILLED DE11 RF-DE ceiling: families not deduplicated: killers 1 failed 1 | 1 failed, 5 passed in 0.43s +KILLED DE12 RF-DE ceiling: sibling counts as direct: killers 1 failed 1 | 1 failed, 5 passed in 0.43s +KILLED DE13 RF-DE ceiling: uncounted readouts count: killers 2 failed 2 | 7 failed, 5 passed in 0.71s +KILLED DE14 RF-DE ceiling: other owner counts: killers 1 failed 1 | 1 failed, 5 passed in 0.45s +KILLED DE15 RF-DE missing-name-evidence: killers 1 failed 1 | 1 failed in 0.34s +KILLED DE16 RF-DE missing-evidence-owner: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE17 RF-DE unresolved-record-carries-owner: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE18 RF-DE definer-disagrees-with-evidence-owner: killers 1 failed 1 | 1 failed in 0.32s +KILLED DE19 RF-DE owner-violates-pool-order: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE20 RF-DE no-ledger-entry: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE21 RF-DE ledger-rva-mismatch: killers 1 failed 1 | 1 failed in 0.29s +KILLED DE22 RF-DE linker-record-in-ledger: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE23 RF-DE ledger-entry-not-in-pool: killers 1 failed 1 | 1 failed in 0.30s +KILLED DE24 RF-DE surplus-common: killers 1 failed 1 | 1 failed in 0.32s +KILLED DE25 RF-DE linker rows counted: killers 28 failed 28 | 32 failed, 3 passed in 2.48s +KILLED DE26 RF-DE tally accepts linker rows: killers 1 failed 1 | 1 failed in 0.26s +KILLED DE27 RF-DE tally accepts mixed rows: killers 1 failed 1 | 1 failed in 0.26s +KILLED DE28 RF-DE segment conflicts still tallied: killers 11 failed 11 | 15 failed, 3 passed in 1.37s +KILLED DE29 RF-DE readout-channel-not-valid-for-segment: killers 1 failed 1 | 1 failed in 0.37s +KILLED DE30 RF-DE owner-category-mismatch: killers 1 failed 1 | 1 failed in 0.34s +KILLED DE31 RF-DE definer-category-mismatch: killers 2 failed 2 | 2 failed in 0.41s +KILLED DE32 RF-DE definer-category-unknown: killers 2 failed 2 | 2 failed in 0.43s +KILLED DE33 RF-DE halo-record-defined-by-vendor-library: killers 2 failed 2 | 4 failed in 0.63s +KILLED DE34 RF-DE vendor-readout-not-reproduced: killers 2 failed 2 | 2 failed in 0.43s +KILLED DE35 RF-DE vendor-readout-library-not-category: killers 1 failed 1 | 1 failed in 0.34s +KILLED DE36 RF-DE segment-order-conflict: killers 2 failed 2 | 2 failed in 0.47s +KILLED DE37 RF-DE january-alignment-law: killers 1 failed 1 | 1 failed in 0.33s +KILLED DE38 RF-DE january-misaligned: killers 1 failed 1 | 1 failed in 0.36s +KILLED DE39 RF-DE january-slot-inconsistent: killers 3 failed 3 | 3 failed in 0.50s +KILLED DE40 RF-DE january static flag: killers 1 failed 1 | 1 failed in 0.39s +KILLED DE41 RF-DE split size check: killers 1 failed 1 | 1 failed in 0.36s +KILLED DE42 RF-DE law: no 32 cap: killers 1 failed 1 | 1 failed in 0.29s +KILLED DE43 RF-DE conservation always true: killers 1 failed 1 | 1 failed in 0.33s +KILLED DH01 RF-DH F1 tree reasons back in SEGMENT_CONFLICTS: killers 1 failed 1 | 1 failed in 0.32s +KILLED DH02 RF-DH F2 vendor needs library readout: killers 1 failed 1 | 1 failed in 0.33s +KILLED DH03 RF-DH F2 unreproduced readout not a conflict: killers 2 failed 2 | 2 failed in 0.44s +KILLED DH04 RF-DH F2 order check one-sided: killers 1 failed 1 | 1 failed in 0.41s +KILLED DH05 RF-DH F2 ledger-only fallback restored: killers 2 failed 2 | 2 failed in 0.43s +KILLED DH06 RF-DH F3 code definitions skipped: killers 1 failed 1 | 1 failed, 1 passed in 0.38s +KILLED DH07 RF-DH F3 weak externals skipped: killers 1 failed 1 | 1 failed, 1 passed in 0.40s +KILLED DH08 RF-DH F4 counted type unchecked: killers 3 failed 3 | 8 failed, 17 passed in 1.27s +KILLED DH09 RF-DH F5 duplicates tallied: killers 1 failed 1 | 1 failed in 0.45s +KILLED DH10 RF-DH F6 readouts shape unchecked: killers 3 failed 3 | 9 failed, 16 passed in 1.42s +KILLED DH11 RF-DH F6 generic malformed input no longer fails closed: killers 1 failed 1 | 1 failed in 0.46s +KILLED DH12 RF-DH F6 duplicate January name: killers 1 failed 1 | 1 failed in 0.41s +KILLED DH13 RF-DH F7 writable data excluded as linker: killers 1 failed 1 | 1 failed in 0.41s +KILLED DH14 RF-DH F8 names unchecked: killers 1 failed 1 | 1 failed in 0.41s +KILLED DH15 RF-DH F9 caveat ignored: killers 1 failed 1 | 1 failed in 0.41s +KILLED DH16 RF-DH F9 referencer ignored: killers 1 failed 1 | 1 failed in 0.37s +KILLED DM01 RF-DM manifest not required: killers 1 failed 1 | 1 failed in 0.44s +KILLED DM02 RF-DM library sha256/size not compared: killers 3 failed 3 | 3 failed in 0.56s +KILLED DM03 RF-DM library size not compared: killers 1 failed 1 | 1 failed in 0.35s +KILLED DM04 RF-DM missing library accepted: killers 1 failed 1 | 1 failed in 0.36s +KILLED DM05 RF-DM unlisted library accepted: killers 1 failed 1 | 1 failed in 0.35s +KILLED DM06 RF-DM vendor category without library accepted: killers 1 failed 1 | 1 failed in 0.33s +KILLED DM07 RF-DM vendor records of an absent library accepted: killers 1 failed 1 | 1 failed in 0.34s +KILLED DM08 RF-DM anonymous member skipped: killers 1 failed 1 | 1 failed in 0.34s +KILLED DM09 RF-DM non-i386 members skipped (the RF-DE/RF-DH reader): killers 2 failed 2 | 3 failed, 1 passed in 0.48s +KILLED DM10 RF-DM CVTRES zero-length string table rejected: killers 1 failed 1 | 1 failed, 2 passed in 0.45s +KILLED DM11 RF-DM schema: unknown keys accepted: killers 1 failed 1 | 2 failed, 11 passed in 0.74s +KILLED DM12 RF-DM schema: types unchecked: killers 4 failed 4 | 16 failed, 15 passed in 1.79s +KILLED DM13 RF-DM schema: missing keys accepted: killers 2 failed 2 | 3 failed, 16 passed in 0.96s +KILLED DM14 RF-DM schema: ledger version unchecked: killers 1 failed 1 | 1 failed, 12 passed in 0.72s +KILLED DM15 RF-DM ambiguous classification tallied: killers 15 failed 15 | 19 failed, 3 passed in 2.39s +KILLED DM16 RF-DM unexpected contribution not fail-closed: killers 1 failed 1 | 1 failed in 0.38s +KILLED DM17 RF-DM tally accepts unclassified rows: killers 1 failed 1 | 1 failed in 0.30s +KILLED DM18 RF-DM containment counted as a definer readout: killers 3 failed 3 | 3 failed in 0.46s +KILLED DM19 RF-DM candidate owner reported as owner: killers 2 failed 2 | 2 failed in 0.38s +KILLED DM20 RF-DM containment candidate unchecked: killers 1 failed 1 | 1 failed in 0.39s +KILLED DM21 RF-DM vendor evidence missing accepted: killers 1 failed 1 | 1 failed in 0.35s +KILLED DM22 RF-DM vendor evidence hash unchecked: killers 1 failed 1 | 1 failed, 5 passed in 0.49s +KILLED DM23 RF-DM vendor evidence hash mismatch not a conflict: killers 1 failed 1 | 1 failed, 5 passed in 0.46s +KILLED DM24 RF-DM vendor record raised to inferred: killers 1 failed 1 | 1 failed in 0.38s +KILLED DM25 RF-DM vendor evidence on a Halo record accepted: killers 1 failed 1 | 1 failed in 0.33s +KILLED DM26 RF-DM receipt: wrong verifier hash: killers 1 failed 1 | 1 failed in 0.44s +KILLED DM27 RF-DM receipt: not written on fail-closed runs: killers 5 failed 5 | 10 failed in 0.99s +KILLED DM28 RF-DM receipt: ledger hash depends on line endings: killers 1 failed 1 | 1 failed in 0.36s +KILLED DM29 RF-DM receipt: build snapshot not recursive: killers 1 failed 1 | 1 failed in 0.31s +KILLED DM30 RF-DM truncated archive member accepted: killers 1 failed 1 | 1 failed in 0.29s +KILLED DM31 RF-DM manifest duplicate library accepted: killers 1 failed 1 | 1 failed, 5 passed in 0.45s +KILLED DM32 RF-DM manifest sha256 format unchecked: killers 1 failed 1 | 1 failed, 5 passed in 0.48s +KILLED DM33 RF-DM unlinked library satisfies a category: killers 1 failed 1 | 1 failed in 0.37s +KILLED DM34 RF-DM unlinked libraries scanned: killers 1 failed 1 | 1 failed in 0.39s +KILLED DM35 RF-DM absent linked libraries not disclosed: killers 1 failed 1 | 1 failed in 0.33s +KILLED DM36 RF-DM malformed generic errors reported as failures: killers 1 failed 1 | 1 failed in 0.38s +KILLED DP01 RF-DP D3 duplicate JSON keys accepted again: killers 2 failed 2 | 4 failed in 0.54s +KILLED DP02 RF-DP D2 linked flag no longer tied to the January module count: killers 1 failed 1 | 1 failed in 0.43s +KILLED DP03 RF-DP D2 absent library may claim 0 January modules: killers 1 failed 1 | 1 failed in 0.33s +KILLED DP04 RF-DP D2 config vendor category's listed library may be unlinked: killers 1 failed 1 | 1 failed in 0.36s +KILLED DP05 RF-DP D2 a present library may be declared absent: killers 1 failed 1 | 1 failed in 0.34s +KILLED DP06 RF-DP D2 a listed library's category may be declared absent: killers 1 failed 1 | 1 failed in 0.36s +KILLED DP07 RF-DP D10 library names differing only in case accepted: killers 1 failed 1 | 1 failed in 0.34s +KILLED DP08 RF-DP D8 absent object of a built unit skipped again: killers 1 failed 1 | 1 failed in 0.32s +KILLED DP09 RF-DP D6 section number no longer bounded: killers 1 failed 1 | 1 failed in 0.31s +KILLED DP10 RF-DP D7 missing January split object skipped again: killers 2 failed 2 | 2 failed in 0.37s +KILLED DP11 RF-DP D7 missing/unreadable split objects no longer fail closed: killers 2 failed 2 | 2 failed in 0.36s +KILLED DP12 RF-DP D5 inputs changed during the run accepted: killers 1 failed 1 | 1 failed in 0.32s +KILLED DP13 RF-DP D6 OSError escapes as a traceback (exit 1, no receipt): killers 1 failed 1 | 1 failed in 0.34s +KILLED DP14 RF-DP D6 unreadable recorded library no longer a library failure: killers 1 failed 1 | 1 failed in 0.35s +KILLED DP15 RF-DP D9 excluded-record inconsistency ignored again: killers 1 failed 1 | 1 failed in 0.33s +KILLED DP16 RF-DP P10 vendor readout reproduced from any library: killers 1 failed 1 | 1 failed in 0.33s +KILLED DP17 RF-DP P15 manifest may declare a present library absent: killers 1 failed 1 | 1 failed in 0.36s +KILLED DP18 RF-DP P39 split section count vs contributions unchecked: killers 1 failed 1 | 1 failed in 0.31s +KILLED DP19 RF-DP P47 upper-case .LIB invisible to the unlisted check: killers 1 failed 1 | 1 failed in 0.32s +KILLED DX01 RF-DX D6 unanticipated exception escapes as status 1 again (catch-all narrowed): killers 1 failed 1 | 1 failed in 0.39s +KILLED DX02 RF-DX D6 a report that cannot be written escapes as status 1 again: killers 1 failed 1 | 2 failed in 0.47s +KILLED DX03 RF-DX D6 an exit-2 run leaves the reports it already wrote (accounting) behind: killers 2 failed 2 | 2 failed, 1 passed in 0.42s +KILLED DX04 RF-DX D6 an unlistable library directory is exit 2 instead of a library failure (3): killers 1 failed 1 | 1 failed in 0.32s +KILLED DX05 RF-DX D11 another linked library defining a vendor name is ignored: killers 1 failed 1 | 2 failed in 0.39s +KILLED DX06 RF-DX D11 another linked library defining a vendor name is only a record FAIL (no fail-closed): killers 1 failed 1 | 2 failed in 0.38s +KILLED DX07 RF-DX D6 IndexError no longer malformed input (falls through to the catch-all, exit 2): killers 1 failed 1 | 1 failed in 0.34s +KILLED DX08 RF-DX D6 a run whose receipt cannot be written keeps its reports: killers 1 failed 1 | 1 failed in 0.31s +KILLED DX09 RF-DX D2 (optional pin) a manifest other than the reviewed one accepted: killers 1 failed 1 | 1 failed in 0.31s +mutations 123, not killed 0 diff --git a/research/remaining_frontier_20260926/q10/mutation/mutations.json b/research/remaining_frontier_20260926/q10/mutation/mutations.json new file mode 100644 index 00000000..a8d9250c --- /dev/null +++ b/research/remaining_frontier_20260926/q10/mutation/mutations.json @@ -0,0 +1,1463 @@ +{ + "schema": "q10-mutation-catalogue/1", + "status": "research only; Q10 held; zero credit", + "target": "tools/common_pool_verify.py", + "tests": "tools/test_common_pool_verify.py", + "rule": "a mutation is KILLED only if every named killer test fails (pytest exit 1, no collection or setup error) with the mutation applied to an isolated copy; each mutation must occur exactly once in the target", + "sources": [ + "RF-DE tools/mutate.py (43)", + "RF-DH tools/rfdh_mutate.py (43 re-used + 16), sha256 b263d3bb", + "RF-DM integration mutations", + "RF-DP tools/rfdp_fix_mutations.py (19 mutations of the RF-DP fixes and own survivors)", + "RF-DX review mutations DX01-DX08 (D6 completion: catch-all, report/receipt write, listing; D11)", + "RF-DX optional manifest pin mutation DX09 (D2 residual)" + ], + "mutations": [ + { + "id": "DE01", + "origin": "RF-DE", + "label": "size-mismatch", + "old": "if size != record[\"size\"]:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_wrong_size_fails_with_alignment_class", + "test_wrong_size_same_alignment_class_still_fails" + ] + }, + { + "id": "DE02", + "origin": "RF-DE", + "label": "alignment-class-differs", + "old": "if law_alignment(size) != record[\"alignment\"]:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_wrong_size_fails_with_alignment_class" + ] + }, + { + "id": "DE03", + "origin": "RF-DE", + "label": "duplicate-definers", + "old": "elif len(definers) > 1:", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_duplicate_definers_fail", + "test_tree_side_definer_facts_never_move_a_record_out_of_its_segment" + ] + }, + { + "id": "DE04", + "origin": "RF-DE", + "label": "no-definer", + "old": "if len(definers) == 0:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_initialised_or_real_definition_fails", + "test_missing_definer_extern_only_and_absent", + "test_static_definition_fails" + ] + }, + { + "id": "DE05", + "origin": "RF-DE", + "label": "real-definition", + "old": "for obj, obj_category, section in real:", + "new": "for obj, obj_category, section in []:", + "retarget": null, + "killers": [ + "test_function_or_weak_alias_named_like_a_record_fails", + "test_initialised_or_real_definition_fails", + "test_real_definition_beside_a_common_still_fails" + ] + }, + { + "id": "DE06", + "origin": "RF-DE", + "label": "static-definition", + "old": "reasons.append(f\"static-definition: {obj} ({section})\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_static_definition_fails" + ] + }, + { + "id": "DE07", + "origin": "RF-DE", + "label": "static scan", + "old": "elif storage == IMAGE_SYM_CLASS_STATIC:", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_static_definition_fails" + ] + }, + { + "id": "DE08", + "origin": "RF-DE", + "label": "missing-provenance-tag", + "old": "reasons.append(\"missing-provenance-tag\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_missing_evidence_tag_fails" + ] + }, + { + "id": "DE09", + "origin": "RF-DE", + "label": "invalid-provenance-tag", + "old": "elif not isinstance(tag, str) or tag not in TAG_RANK:", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_proof_vocabulary_is_rejected" + ] + }, + { + "id": "DE10", + "origin": "RF-DE", + "label": "tag-exceeds-evidence", + "old": "if TAG_RANK[tag] > TAG_RANK[ceiling]:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_containment_cannot_be_smuggled_in_as_a_readout", + "test_containment_is_recorded_but_never_raises_a_tag", + "test_inferred_needs_two_direct_readout_families", + "test_probable_needs_a_readout_and_unresolved_carries_no_owner", + "test_vendor_record_supported_only_by_a_library_member_stays_probable" + ] + }, + { + "id": "DE11", + "origin": "RF-DE", + "label": "ceiling: families not deduplicated", + "old": "family = CHANNEL_FAMILY[channel]", + "new": "family = channel", + "retarget": null, + "killers": [ + "test_inferred_needs_two_direct_readout_families" + ] + }, + { + "id": "DE12", + "origin": "RF-DE", + "label": "ceiling: sibling counts as direct", + "old": "if readout.get(\"mapping\") == \"direct\":", + "new": "if True:", + "retarget": null, + "killers": [ + "test_inferred_needs_two_direct_readout_families" + ] + }, + { + "id": "DE13", + "origin": "RF-DE", + "label": "ceiling: uncounted readouts count", + "old": "if readout.get(\"counted\") is not True:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_counted_must_be_the_boolean_true", + "test_inferred_needs_two_direct_readout_families" + ] + }, + { + "id": "DE14", + "origin": "RF-DE", + "label": "ceiling: other owner counts", + "old": "if owner is None or readout.get(\"owner\") != owner:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_inferred_needs_two_direct_readout_families" + ] + }, + { + "id": "DE15", + "origin": "RF-DE", + "label": "missing-name-evidence", + "old": "reasons.append(\"missing-name-evidence\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_missing_owner_and_name_evidence_fail" + ] + }, + { + "id": "DE16", + "origin": "RF-DE", + "label": "missing-evidence-owner", + "old": "reasons.append(\"missing-evidence-owner\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_missing_owner_and_name_evidence_fail" + ] + }, + { + "id": "DE17", + "origin": "RF-DE", + "label": "unresolved-record-carries-owner", + "old": "reasons.append(\"unresolved-record-carries-owner\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_probable_needs_a_readout_and_unresolved_carries_no_owner" + ] + }, + { + "id": "DE18", + "origin": "RF-DE", + "label": "definer-disagrees-with-evidence-owner", + "old": "and definers[0][0] != owner:", + "new": "and False:", + "retarget": null, + "killers": [ + "test_definer_must_be_the_evidence_owner" + ] + }, + { + "id": "DE19", + "origin": "RF-DE", + "label": "owner-violates-pool-order", + "old": "if owner_index < last_owner_index:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_owner_pool_order_can_refute" + ] + }, + { + "id": "DE20", + "origin": "RF-DE", + "label": "no-ledger-entry", + "old": "reasons.append(\"no-ledger-entry\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_record_without_a_ledger_entry_fails_closed" + ] + }, + { + "id": "DE21", + "origin": "RF-DE", + "label": "ledger-rva-mismatch", + "old": "if rva != record[\"rva\"]:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_ledger_rva_and_unknown_entries" + ] + }, + { + "id": "DE22", + "origin": "RF-DE", + "label": "linker-record-in-ledger", + "old": "global_failures.append(f\"linker-record-in-ledger: {name}\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_linker_record_in_the_ledger_is_rejected_and_never_counted" + ] + }, + { + "id": "DE23", + "origin": "RF-DE", + "label": "ledger-entry-not-in-pool", + "old": "global_failures.append(f\"ledger-entry-not-in-pool: {name}\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_ledger_rva_and_unknown_entries" + ] + }, + { + "id": "DE24", + "origin": "RF-DE", + "label": "surplus-common", + "old": "global_failures.append(f\"surplus-common: {name} in {[w[0] for w in where]}\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_surplus_common_is_a_global_failure" + ] + }, + { + "id": "DE25", + "origin": "RF-DE", + "label": "linker rows counted", + "old": "if record[\"kind\"] != \"bss\":\n excluded", + "new": "if False:\n excluded", + "retarget": null, + "killers": [ + "test_ambiguous_classification_fails_closed_without_accounting", + "test_consistent_world_passes_with_separate_accounting", + "test_duplicate_january_name_fails_closed", + "test_duplicate_ledger_entry_fails_closed", + "test_every_linked_member_kind_is_scanned_for_halo_names", + "test_every_run_writes_a_receipt", + "test_halo_record_after_vendor_records_conflicts", + "test_linker_record_in_the_ledger_is_rejected_and_never_counted", + "test_missing_evidence_tag_fails", + "test_missing_owner_and_name_evidence_fail", + "test_overlapping_january_records_break_conservation", + "test_record_without_a_ledger_entry_fails_closed", + "test_report_carries_no_credit_and_writes_nothing", + "test_surplus_common_is_a_global_failure", + "test_tree_side_definer_facts_never_move_a_record_out_of_its_segment", + "test_unreadable_member_of_a_linked_library_fails_closed", + "test_unreproduced_vendor_readout_fails_closed", + "test_vendor_category_needs_a_linked_or_declared_library", + "test_vendor_category_outside_config_is_ambiguous", + "test_vendor_evidence_is_checked_against_library_and_january", + "test_vendor_evidence_must_be_recorded", + "test_vendor_label_needs_a_library_readout_and_order_is_symmetric", + "test_vendor_library_refutes_a_halo_label_without_readouts", + "test_vendor_readout_must_name_its_category_library", + "test_vendor_readout_reverified_against_the_library", + "test_vendor_record_cannot_enter_the_halo_tally", + "test_writable_pool_contribution_is_not_excluded_as_linker", + "test_xdk_libraries_are_required_no_ledger_only_mode" + ] + }, + { + "id": "DE26", + "origin": "RF-DE", + "label": "tally accepts linker rows", + "old": "raise ValueError(f\"linker record {row['name']} must not enter any tally\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_tally_refuses_mixed_linker_or_unclassified_rows" + ] + }, + { + "id": "DE27", + "origin": "RF-DE", + "label": "tally accepts mixed rows", + "old": "raise ValueError(f\"{row['name']}: segment {segment!r} and category \"", + "new": "print(f\"{row['name']}: segment {segment!r} and category \"", + "retarget": null, + "killers": [ + "test_tally_refuses_mixed_linker_or_unclassified_rows" + ] + }, + { + "id": "DE28", + "origin": "RF-DE", + "label": "segment conflicts still tallied", + "old": "accounted = segment if valid and not conflicted else None", + "new": "accounted = segment if valid else None", + "retarget": null, + "killers": [ + "test_duplicate_january_name_fails_closed", + "test_duplicate_ledger_entry_fails_closed", + "test_every_linked_member_kind_is_scanned_for_halo_names", + "test_halo_record_after_vendor_records_conflicts", + "test_unreproduced_vendor_readout_fails_closed", + "test_vendor_evidence_is_checked_against_library_and_january", + "test_vendor_label_needs_a_library_readout_and_order_is_symmetric", + "test_vendor_library_refutes_a_halo_label_without_readouts", + "test_vendor_readout_must_name_its_category_library", + "test_vendor_readout_reverified_against_the_library", + "test_vendor_record_cannot_enter_the_halo_tally" + ] + }, + { + "id": "DE29", + "origin": "RF-DE", + "label": "readout-channel-not-valid-for-segment", + "old": "elif segment in SEGMENTS and channel not in SEGMENT_CHANNELS[segment]:", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_vendor_record_cannot_enter_the_halo_tally" + ] + }, + { + "id": "DE30", + "origin": "RF-DE", + "label": "owner-category-mismatch", + "old": "elif config_objects[owner][\"category\"] != category:", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_vendor_record_cannot_enter_the_halo_tally" + ] + }, + { + "id": "DE31", + "origin": "RF-DE", + "label": "definer-category-mismatch", + "old": "elif category and obj_category != category:", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_tree_side_definer_facts_never_move_a_record_out_of_its_segment", + "test_vendor_record_cannot_enter_the_halo_tally" + ] + }, + { + "id": "DE32", + "origin": "RF-DE", + "label": "definer-category-unknown", + "old": "if obj_category is None:\n reasons.append(f\"definer-category-unknown", + "new": "if False:\n reasons.append(f\"definer-category-unknown", + "retarget": null, + "killers": [ + "test_object_outside_config_fails_closed", + "test_tree_side_definer_facts_never_move_a_record_out_of_its_segment" + ] + }, + { + "id": "DE33", + "origin": "RF-DE", + "label": "halo-record-defined-by-vendor-library", + "old": "elif segment == \"halo\" and library is not None and library.get(name):", + "new": "elif False:", + "retarget": null, + "killers": [ + "test_every_linked_member_kind_is_scanned_for_halo_names", + "test_vendor_library_refutes_a_halo_label_without_readouts" + ] + }, + { + "id": "DE34", + "origin": "RF-DE", + "label": "vendor-readout-not-reproduced", + "old": "reasons.append(f\"vendor-readout-not-reproduced: {lib} gives {in_lib}\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_unreproduced_vendor_readout_fails_closed", + "test_vendor_readout_reverified_against_the_library" + ] + }, + { + "id": "DE35", + "origin": "RF-DE", + "label": "vendor-readout-library-not-category", + "old": "if lib[:-4] != str(category).lower() or not lib.endswith(\".lib\"):", + "new": "if False:", + "retarget": null, + "killers": [ + "test_vendor_readout_must_name_its_category_library" + ] + }, + { + "id": "DE36", + "origin": "RF-DE", + "label": "segment-order-conflict", + "old": "if order_conflict and order_conflict[0] <= record[\"pool_index\"]", + "new": "if False and order_conflict[0] <= record[\"pool_index\"]", + "retarget": null, + "killers": [ + "test_halo_record_after_vendor_records_conflicts", + "test_vendor_label_needs_a_library_readout_and_order_is_symmetric" + ] + }, + { + "id": "DE37", + "origin": "RF-DE", + "label": "january-alignment-law", + "old": "if alignment != law_alignment(size):", + "new": "if False:", + "retarget": null, + "killers": [ + "test_january_alignment_that_breaks_the_layout_law_fails" + ] + }, + { + "id": "DE38", + "origin": "RF-DE", + "label": "january-misaligned", + "old": "if not alignment or rva % alignment:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_misaligned_january_record_fails" + ] + }, + { + "id": "DE39", + "origin": "RF-DE", + "label": "january-slot-inconsistent", + "old": "if rva != expected:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_january_slot_that_disagrees_with_the_pool_fails", + "test_misaligned_january_record_fails", + "test_overlapping_january_records_break_conservation" + ] + }, + { + "id": "DE40", + "origin": "RF-DE", + "label": "january static flag", + "old": "reasons.append(\"symbols.json marks a pooled record static\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_january_static_flag_on_a_pooled_record_fails" + ] + }, + { + "id": "DE41", + "origin": "RF-DE", + "label": "split size check", + "old": "if section[\"size\"] != size:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_split_pool_that_disagrees_with_contributions_fails" + ] + }, + { + "id": "DE42", + "origin": "RF-DE", + "label": "law: no 32 cap", + "old": "return min(32, power)", + "new": "return power", + "retarget": null, + "killers": [ + "test_layout_law_and_flag_alignment" + ] + }, + { + "id": "DE43", + "origin": "RF-DE", + "label": "conservation always true", + "old": "\"holds\": span == counted,", + "new": "\"holds\": True,", + "retarget": null, + "killers": [ + "test_overlapping_january_records_break_conservation" + ] + }, + { + "id": "DH01", + "origin": "RF-DH", + "label": "F1 tree reasons back in SEGMENT_CONFLICTS", + "old": "\"segment-order-conflict\", \"duplicate-january-name\",", + "new": "\"segment-order-conflict\", \"duplicate-january-name\", \"definer-category-mismatch\", \"definer-category-unknown\",", + "retarget": null, + "killers": [ + "test_tree_side_definer_facts_never_move_a_record_out_of_its_segment" + ] + }, + { + "id": "DH02", + "origin": "RF-DH", + "label": "F2 vendor needs library readout", + "old": "if segment == \"vendor\" and not any(r.get(\"channel\") == \"XDK\" for r in readouts):", + "new": "if False:", + "retarget": null, + "killers": [ + "test_vendor_label_needs_a_library_readout_and_order_is_symmetric" + ] + }, + { + "id": "DH03", + "origin": "RF-DH", + "label": "F2 unreproduced readout not a conflict", + "old": "\"vendor-readout-library-not-category\", \"vendor-readout-not-reproduced\",", + "new": "\"vendor-readout-library-not-category\",", + "retarget": null, + "killers": [ + "test_unreproduced_vendor_readout_fails_closed", + "test_vendor_readout_reverified_against_the_library" + ] + }, + { + "id": "DH04", + "origin": "RF-DH", + "label": "F2 order check one-sided", + "old": "order_conflict = (min(vendor_at), max(halo_at))", + "new": "order_conflict = (max(halo_at), max(halo_at))", + "retarget": null, + "killers": [ + "test_vendor_label_needs_a_library_readout_and_order_is_symmetric" + ] + }, + { + "id": "DH05", + "origin": "RF-DH", + "label": "F2 ledger-only fallback restored", + "old": " raise LibraryVerifyError(\"--xdk-lib-dir is required for every accounting run \"", + "new": " return {}, {\"linked_libraries_not_in_extract\": []}, {}\n raise LibraryVerifyError(\"--xdk-lib-dir is required for every accounting run \"", + "retarget": "RF-DH \"F2 segment evidence silent\" mutated the \"segments are LEDGER-ONLY\" disclosure; the owner ruling removed the ledger-only mode, so the guarantee now lives in the --xdk-lib-dir requirement: the mutant restores a ledger-only run (no libraries) instead of refusing it", + "killers": [ + "test_xdk_libraries_are_required_no_ledger_only_mode", + "test_ledger_only_run_refused_even_when_every_vendor_record_is_relabelled" + ] + }, + { + "id": "DH06", + "origin": "RF-DH", + "label": "F3 code definitions skipped", + "old": " if storage == IMAGE_SYM_CLASS_EXTERNAL:\n reals", + "new": " if False:\n reals", + "retarget": null, + "killers": [ + "test_function_or_weak_alias_named_like_a_record_fails" + ] + }, + { + "id": "DH07", + "origin": "RF-DH", + "label": "F3 weak externals skipped", + "old": "if storage == IMAGE_SYM_CLASS_WEAK_EXTERNAL:\n # an alias", + "new": "if False:\n # an alias", + "retarget": "the bare line now also occurs in library_definers; the target keeps its scan_objects context line", + "killers": [ + "test_function_or_weak_alias_named_like_a_record_fails" + ] + }, + { + "id": "DH08", + "origin": "RF-DH", + "label": "F4 counted type unchecked", + "old": " if kind == \"bool\":\n return type(value) is bool", + "new": " if kind == \"bool\":\n return True", + "retarget": "the per-readout isinstance(counted, bool) check moved into the schema (_kind_ok \"bool\"); a non-boolean counted is now a malformed type (exit 4)", + "killers": [ + "test_counted_must_be_the_boolean_true", + "test_malformed_ledger_types_fail_closed", + "test_malformed_manifest_fails_closed" + ] + }, + { + "id": "DH09", + "origin": "RF-DH", + "label": "F5 duplicates tallied", + "old": "reasons.append(\"ledger-duplicate-entry: more than one ledger entry names this record\")", + "new": "pass", + "retarget": null, + "killers": [ + "test_duplicate_ledger_entry_fails_closed" + ] + }, + { + "id": "DH10", + "origin": "RF-DH", + "label": "F6 readouts shape unchecked", + "old": " _check_object(f\"{where} readout #{number}\", readout, READOUT, READOUT_OPTIONAL)", + "new": " pass", + "retarget": "the ledger-readouts-invalid per-record reason moved into the schema: every readout must be an object with the readout keys and types (exit 4)", + "killers": [ + "test_counted_must_be_the_boolean_true", + "test_malformed_ledger_types_fail_closed", + "test_malformed_ledger_values_fail_closed" + ] + }, + { + "id": "DH11", + "origin": "RF-DH", + "label": "F6 generic malformed input no longer fails closed", + "old": " except (ValueError, TypeError, KeyError, AttributeError, struct.error) as caught:", + "new": " except ZeroDivisionError as caught:", + "retarget": "same except clause (variable renamed); it now maps to exit 4 (malformed types), previously exit 2", + "killers": [ + "test_unexpected_type_errors_fail_closed_as_malformed" + ] + }, + { + "id": "DH12", + "origin": "RF-DH", + "label": "F6 duplicate January name", + "old": "if counts.get(record[\"name\"], 0) > 1:", + "new": "if False:", + "retarget": null, + "killers": [ + "test_duplicate_january_name_fails_closed" + ] + }, + { + "id": "DH13", + "origin": "RF-DH", + "label": "F7 writable data excluded as linker", + "old": "kind = \"bss\" if bss else (\"linker\" if read_only_data else \"unexpected\")", + "new": "kind = \"bss\" if bss else \"linker\"", + "retarget": null, + "killers": [ + "test_writable_pool_contribution_is_not_excluded_as_linker" + ] + }, + { + "id": "DH14", + "origin": "RF-DH", + "label": "F8 names unchecked", + "old": "if not isinstance(raw, str) or _stem(raw) != _stem(readout[\"owner\"]):", + "new": "if False:", + "retarget": null, + "killers": [ + "test_direct_readout_must_name_its_owner" + ] + }, + { + "id": "DH15", + "origin": "RF-DH", + "label": "F9 caveat ignored", + "old": "if tag == \"inferred\" and entry.get(\"caveats\"):", + "new": "if False:", + "retarget": null, + "killers": [ + "test_inferred_record_carries_no_caveat" + ] + }, + { + "id": "DH16", + "origin": "RF-DH", + "label": "F9 referencer ignored", + "old": "and owner not in referencers[name]:", + "new": "and False:", + "retarget": null, + "killers": [ + "test_inferred_owner_must_be_a_january_referencer" + ] + }, + { + "id": "DM01", + "origin": "RF-DM", + "label": "manifest not required", + "old": " if manifest_path is None:\n raise LibraryVerifyError(", + "new": " if False:\n raise LibraryVerifyError(", + "retarget": null, + "killers": [ + "test_xdk_libraries_are_required_no_ledger_only_mode" + ] + }, + { + "id": "DM02", + "origin": "RF-DM", + "label": "library sha256/size not compared", + "old": "verified=actual == entry[\"sha256\"] and len(data) == entry[\"size\"])", + "new": "verified=True)", + "retarget": null, + "killers": [ + "test_every_run_writes_a_receipt", + "test_library_hash_mismatch_fails_closed_and_is_receipted", + "test_library_size_mismatch_fails_closed" + ] + }, + { + "id": "DM03", + "origin": "RF-DM", + "label": "library size not compared", + "old": "verified=actual == entry[\"sha256\"] and len(data) == entry[\"size\"])", + "new": "verified=actual == entry[\"sha256\"])", + "retarget": null, + "killers": [ + "test_library_size_mismatch_fails_closed" + ] + }, + { + "id": "DM04", + "origin": "RF-DM", + "label": "missing library accepted", + "old": " problems.append(f\"missing library {entry['file']}\")", + "new": " pass", + "retarget": null, + "killers": [ + "test_missing_recorded_library_fails_closed" + ] + }, + { + "id": "DM05", + "origin": "RF-DM", + "label": "unlisted library accepted", + "old": " problems.append(f\"unlisted library {present[key].name}: no recorded sha256\")", + "new": " pass", + "retarget": null, + "killers": [ + "test_unlisted_library_fails_closed" + ] + }, + { + "id": "DM06", + "origin": "RF-DM", + "label": "vendor category without library accepted", + "old": " if category.lower() not in linked_stems and category not in absent:", + "new": " if False:", + "retarget": null, + "killers": [ + "test_vendor_category_needs_a_linked_or_declared_library" + ] + }, + { + "id": "DM07", + "origin": "RF-DM", + "label": "vendor records of an absent library accepted", + "old": " if unknown_vendor:\n raise LibraryVerifyError(", + "new": " if False:\n raise LibraryVerifyError(", + "retarget": null, + "killers": [ + "test_vendor_records_of_a_library_not_in_the_extract_fail_closed" + ] + }, + { + "id": "DM08", + "origin": "RF-DM", + "label": "anonymous member skipped", + "old": " raise LibraryVerifyError(f\"{where}: anonymous object version {version}: symbols unreadable\")", + "new": " return \"anonymous\", []", + "retarget": null, + "killers": [ + "test_unreadable_member_of_a_linked_library_fails_closed" + ] + }, + { + "id": "DM09", + "origin": "RF-DM", + "label": "non-i386 members skipped (the RF-DE/RF-DH reader)", + "old": " kind, symbols = member_symbols(body, f\"{library}({member})\")", + "new": " kind, symbols = member_symbols(body, f\"{library}({member})\") if body[:2] == b\"\\x4c\\x01\" else (\"skipped\", [])", + "retarget": null, + "killers": [ + "test_every_linked_member_kind_is_scanned_for_halo_names", + "test_unreadable_member_of_a_linked_library_fails_closed" + ] + }, + { + "id": "DM10", + "origin": "RF-DM", + "label": "CVTRES zero-length string table rejected", + "old": " elif length != 0:", + "new": " elif True:", + "retarget": null, + "killers": [ + "test_every_linked_member_kind_is_scanned_for_halo_names" + ] + }, + { + "id": "DM11", + "origin": "RF-DM", + "label": "schema: unknown keys accepted", + "old": " unknown = sorted(set(value) - set(required) - set(optional))", + "new": " unknown = []", + "retarget": null, + "killers": [ + "test_malformed_ledger_types_fail_closed" + ] + }, + { + "id": "DM12", + "origin": "RF-DM", + "label": "schema: types unchecked", + "old": " if key in value and not _kind_ok(value[key], kind):", + "new": " if False:", + "retarget": null, + "killers": [ + "test_counted_must_be_the_boolean_true", + "test_malformed_ledger_types_fail_closed", + "test_malformed_ledger_values_fail_closed", + "test_malformed_manifest_fails_closed" + ] + }, + { + "id": "DM13", + "origin": "RF-DM", + "label": "schema: missing keys accepted", + "old": " if missing:\n raise MalformedInputError", + "new": " if False:\n raise MalformedInputError", + "retarget": null, + "killers": [ + "test_malformed_ledger_types_fail_closed", + "test_malformed_manifest_fails_closed" + ] + }, + { + "id": "DM14", + "origin": "RF-DM", + "label": "schema: ledger version unchecked", + "old": " if ledger[\"schema\"] != LEDGER_SCHEMA:", + "new": " if False:", + "retarget": null, + "killers": [ + "test_malformed_ledger_types_fail_closed" + ] + }, + { + "id": "DM15", + "origin": "RF-DM", + "label": "ambiguous classification tallied", + "old": " if ambiguous or unexpected:", + "new": " if unexpected:", + "retarget": null, + "killers": [ + "test_ambiguous_classification_fails_closed_without_accounting", + "test_duplicate_january_name_fails_closed", + "test_duplicate_ledger_entry_fails_closed", + "test_every_linked_member_kind_is_scanned_for_halo_names", + "test_halo_record_after_vendor_records_conflicts", + "test_record_without_a_ledger_entry_fails_closed", + "test_unreproduced_vendor_readout_fails_closed", + "test_vendor_category_outside_config_is_ambiguous", + "test_vendor_evidence_is_checked_against_library_and_january", + "test_vendor_label_needs_a_library_readout_and_order_is_symmetric", + "test_vendor_library_refutes_a_halo_label_without_readouts", + "test_vendor_readout_must_name_its_category_library", + "test_vendor_readout_reverified_against_the_library", + "test_vendor_record_cannot_enter_the_halo_tally", + "test_vendor_record_supported_only_by_a_library_member_stays_probable" + ] + }, + { + "id": "DM16", + "origin": "RF-DM", + "label": "unexpected contribution not fail-closed", + "old": " if ambiguous or unexpected:", + "new": " if ambiguous:", + "retarget": null, + "killers": [ + "test_writable_pool_contribution_is_not_excluded_as_linker" + ] + }, + { + "id": "DM17", + "origin": "RF-DM", + "label": "tally accepts unclassified rows", + "old": " raise ValueError(f\"{row['name']} is unclassified; an ambiguous classification \"", + "new": " print(f\"{row['name']} is unclassified; an ambiguous classification \"", + "retarget": null, + "killers": [ + "test_tally_refuses_mixed_linker_or_unclassified_rows" + ] + }, + { + "id": "DM18", + "origin": "RF-DM", + "label": "containment counted as a definer readout", + "old": " for readout in _readouts(entry):\n if readout.get(\"counted\") is not True:", + "new": " for readout in _readouts(entry) + [dict(channel=\"D\", owner=c[\"candidate_owner\"], mapping=\"direct\", counted=True) for c in entry.get(\"containment_evidence\", [])]:\n if readout.get(\"counted\") is not True:", + "retarget": null, + "killers": [ + "test_containment_cannot_be_smuggled_in_as_a_readout", + "test_containment_is_recorded_but_never_raises_a_tag", + "test_research_ledger_records" + ] + }, + { + "id": "DM19", + "origin": "RF-DM", + "label": "candidate owner reported as owner", + "old": "\"tag\": tag, \"tag_label\": TAG_LABELS.get(tag), \"owner\": owner,", + "new": "\"tag\": tag, \"tag_label\": TAG_LABELS.get(tag), \"owner\": owner or entry.get(\"candidate_owner\"),", + "retarget": null, + "killers": [ + "test_containment_is_recorded_but_never_raises_a_tag", + "test_unresolved_record_passes_only_as_owner_unresolved" + ] + }, + { + "id": "DM20", + "origin": "RF-DM", + "label": "containment candidate unchecked", + "old": " if item[\"candidate_owner\"] != entry.get(\"candidate_owner\"):", + "new": " if False:", + "retarget": null, + "killers": [ + "test_containment_evidence_must_name_the_record_candidate" + ] + }, + { + "id": "DM21", + "origin": "RF-DM", + "label": "vendor evidence missing accepted", + "old": " return [\"vendor-evidence-missing: the XDK library member evidence must be recorded\"]", + "new": " return []", + "retarget": null, + "killers": [ + "test_vendor_evidence_must_be_recorded" + ] + }, + { + "id": "DM22", + "origin": "RF-DM", + "label": "vendor evidence hash unchecked", + "old": " if recorded != evidence[\"library_sha256\"]:", + "new": " if False:", + "retarget": null, + "killers": [ + "test_vendor_evidence_is_checked_against_library_and_january" + ] + }, + { + "id": "DM23", + "origin": "RF-DM", + "label": "vendor evidence hash mismatch not a conflict", + "old": " \"vendor-evidence-disagrees-with-readout\", \"vendor-evidence-library-hash-mismatch\",", + "new": " \"vendor-evidence-disagrees-with-readout\",", + "retarget": null, + "killers": [ + "test_vendor_evidence_is_checked_against_library_and_january" + ] + }, + { + "id": "DM24", + "origin": "RF-DM", + "label": "vendor record raised to inferred", + "old": " elif entry.get(\"tag\") == \"inferred\":", + "new": " elif False:", + "retarget": null, + "killers": [ + "test_vendor_record_supported_only_by_a_library_member_stays_probable" + ] + }, + { + "id": "DM25", + "origin": "RF-DM", + "label": "vendor evidence on a Halo record accepted", + "old": " return [\"vendor-evidence-on-halo-record: only vendor records carry library evidence\"] \\", + "new": " return [] \\", + "retarget": null, + "killers": [ + "test_vendor_record_cannot_enter_the_halo_tally" + ] + }, + { + "id": "DM26", + "origin": "RF-DM", + "label": "receipt: wrong verifier hash", + "old": " return {\"path\": \"tools/common_pool_verify.py\", \"sha256\": sha256_file(own),", + "new": " return {\"path\": \"tools/common_pool_verify.py\", \"sha256\": sha256_file(reader),", + "retarget": null, + "killers": [ + "test_every_run_writes_a_receipt" + ] + }, + { + "id": "DM27", + "origin": "RF-DM", + "label": "receipt: not written on fail-closed runs", + "old": " receipt = build_receipt(argv, trace, exit_code, report, error)", + "new": " if report is None:\n return exit_code\n receipt = build_receipt(argv, trace, exit_code, report, error)", + "retarget": null, + "killers": [ + "test_every_run_writes_a_receipt", + "test_library_hash_mismatch_fails_closed_and_is_receipted", + "test_malformed_ledger_values_fail_closed", + "test_unexpected_type_errors_fail_closed_as_malformed", + "test_unusable_january_input_fails_closed" + ] + }, + { + "id": "DM28", + "origin": "RF-DM", + "label": "receipt: ledger hash depends on line endings", + "old": " \"sha256_lf\": sha256_bytes(lf_normalised(data)), \"size\": len(data)}", + "new": " \"sha256_lf\": sha256_bytes(data), \"size\": len(data)}", + "retarget": null, + "killers": [ + "test_ledger_hash_is_line_ending_independent" + ] + }, + { + "id": "DM29", + "origin": "RF-DM", + "label": "receipt: build snapshot not recursive", + "old": " for path in sorted(root.rglob(pattern), key=lambda p: p.relative_to(root).as_posix()):", + "new": " for path in sorted(root.glob(pattern), key=lambda p: p.relative_to(root).as_posix()):", + "retarget": null, + "killers": [ + "test_every_run_writes_a_receipt" + ] + }, + { + "id": "DM30", + "origin": "RF-DM", + "label": "truncated archive member accepted", + "old": " if offset + 60 + size > len(data):", + "new": " if False:", + "retarget": null, + "killers": [ + "test_member_reader_is_strict" + ] + }, + { + "id": "DM31", + "origin": "RF-DM", + "label": "manifest duplicate library accepted", + "old": " if key in seen:\n raise MalformedInputError", + "new": " if False:\n raise MalformedInputError", + "retarget": null, + "killers": [ + "test_malformed_manifest_fails_closed" + ] + }, + { + "id": "DM32", + "origin": "RF-DM", + "label": "manifest sha256 format unchecked", + "old": " if not SHA256_RE.match(entry[\"sha256\"]):", + "new": " if False:", + "retarget": null, + "killers": [ + "test_malformed_manifest_fails_closed" + ] + }, + { + "id": "DM33", + "origin": "RF-DM", + "label": "unlinked library satisfies a category", + "old": " linked_stems = {entry[\"file\"].lower()[:-4] for entry in manifest[\"libraries\"]\n if entry[\"linked_by_january\"]}", + "new": " linked_stems = {entry[\"file\"].lower()[:-4] for entry in manifest[\"libraries\"]\n if True}", + "retarget": null, + "killers": [ + "test_vendor_category_needs_a_linked_or_declared_library" + ] + }, + { + "id": "DM34", + "origin": "RF-DM", + "label": "unlinked libraries scanned", + "old": " elif entry[\"linked_by_january\"]:\n linked[", + "new": " else:\n linked[", + "retarget": null, + "killers": [ + "test_unreadable_member_of_a_linked_library_fails_closed" + ] + }, + { + "id": "DM35", + "origin": "RF-DM", + "label": "absent linked libraries not disclosed", + "old": "f\"{[e['library'] for e in manifest['linked_libraries_not_in_extract']] or 'none'}\")", + "new": "f\"{'none'}\")", + "retarget": null, + "killers": [ + "test_vendor_category_needs_a_linked_or_declared_library" + ] + }, + { + "id": "DM36", + "origin": "RF-DM", + "label": "malformed generic errors reported as failures", + "old": " error, exit_code = caught, EXIT_MALFORMED", + "new": " error, exit_code = caught, EXIT_FAILURES", + "retarget": null, + "killers": [ + "test_unexpected_type_errors_fail_closed_as_malformed" + ] + }, + { + "id": "DP01", + "origin": "RF-DP", + "label": "D3 duplicate JSON keys accepted again", + "old": " return json.loads(text, object_pairs_hook=_no_duplicate_keys)", + "new": " return json.loads(text)", + "killers": [ + "test_duplicate_caveats_key_cannot_hide_a_caveat", + "test_duplicate_json_keys_fail_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP02", + "origin": "RF-DP", + "label": "D2 linked flag no longer tied to the January module count", + "old": " if type(linked) is bool and type(modules) is int and (linked != (modules > 0) or modules < 0):", + "new": " if False:", + "killers": [ + "test_manifest_linked_flags_must_match_january_module_counts" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP03", + "origin": "RF-DP", + "label": "D2 absent library may claim 0 January modules", + "old": " if entry[\"january_pdb_modules\"] <= 0:", + "new": " if False:", + "killers": [ + "test_manifest_linked_flags_must_match_january_module_counts" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP04", + "origin": "RF-DP", + "label": "D2 config vendor category's listed library may be unlinked", + "old": " if category.lower() in listed_stems and category.lower() not in linked_stems:", + "new": " if False:", + "killers": [ + "test_manifest_cannot_hide_a_present_library" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP05", + "origin": "RF-DP", + "label": "D2 a present library may be declared absent", + "old": " if entry[\"library\"].lower() in present:\n problems.append(f\"library {entry['library']} is declared", + "new": " if False:\n problems.append(f\"library {entry['library']} is declared", + "killers": [ + "test_manifest_cannot_hide_a_present_library" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP06", + "origin": "RF-DP", + "label": "D2 a listed library's category may be declared absent", + "old": " if entry[\"category\"] and entry[\"category\"].lower() in listed_stems:", + "new": " if False:", + "killers": [ + "test_manifest_cannot_hide_a_present_library" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP07", + "origin": "RF-DP", + "label": "D10 library names differing only in case accepted", + "old": " if path.name.lower() in present:", + "new": " if False:", + "killers": [ + "test_library_names_differing_only_in_case_fail_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP08", + "origin": "RF-DP", + "label": "D8 absent object of a built unit skipped again", + "old": " if info[\"status\"] != \"MISSING\":\n absent.append(name)", + "new": " if False:\n absent.append(name)", + "killers": [ + "test_absent_object_of_a_built_unit_fails_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP09", + "origin": "RF-DP", + "label": "D6 section number no longer bounded", + "old": " if section_no > len(obj[\"sections\"]):", + "new": " if False:", + "killers": [ + "test_bad_section_number_in_an_object_is_receipted_not_a_crash" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP10", + "origin": "RF-DP", + "label": "D7 missing January split object skipped again", + "old": " unreadable.append(f\"{name}: no January split object {path}\")\n continue", + "new": " continue", + "killers": [ + "test_missing_or_unreadable_january_split_object_fails_closed", + "test_split_pool_outside_its_split_tree_fails_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP11", + "origin": "RF-DP", + "label": "D7 missing/unreadable split objects no longer fail closed", + "old": " if unreadable:\n raise PoolVerifyError(f\"{len(unreadable)} January split object(s)", + "new": " if False:\n raise PoolVerifyError(f\"{len(unreadable)} January split object(s)", + "killers": [ + "test_missing_or_unreadable_january_split_object_fails_closed", + "test_split_pool_outside_its_split_tree_fails_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP12", + "origin": "RF-DP", + "label": "D5 inputs changed during the run accepted", + "old": " if changed:\n raise PoolVerifyError(f\"inputs changed during the run", + "new": " if False:\n raise PoolVerifyError(f\"inputs changed during the run", + "killers": [ + "test_inputs_changed_during_the_run_fail_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP13", + "origin": "RF-DP", + "label": "D6 OSError escapes as a traceback (exit 1, no receipt)", + "old": " except OSError as caught:\n # a file that vanished", + "new": " except ZeroDivisionError as caught:\n # a file that vanished", + "killers": [ + "test_unreadable_files_are_receipted_not_a_crash" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP14", + "origin": "RF-DP", + "label": "D6 unreadable recorded library no longer a library failure", + "old": " try:\n data = path.read_bytes()\n except OSError as error:\n raise LibraryVerifyError(f\"cannot read library {path}: {error}\") from error", + "new": " data = path.read_bytes()", + "killers": [ + "test_unreadable_files_are_receipted_not_a_crash" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP15", + "origin": "RF-DP", + "label": "D9 excluded-record inconsistency ignored again", + "old": " if record[\"kind\"] != \"bss\" and record[\"january_reasons\"]:", + "new": " if False:", + "killers": [ + "test_excluded_record_inconsistency_is_a_global_failure" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP16", + "origin": "RF-DP", + "label": "P10 vendor readout reproduced from any library", + "old": "in_lib = [h for h in hits if h[0] == lib]", + "new": "in_lib = [h for h in hits]", + "killers": [ + "test_vendor_readout_is_reproduced_only_from_its_own_library" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP17", + "origin": "RF-DP", + "label": "P15 manifest may declare a present library absent", + "old": " raise MalformedInputError(f\"XDK manifest: {entry['library']} is both present and absent\")", + "new": " pass", + "killers": [ + "test_manifest_may_not_declare_a_listed_library_absent" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP18", + "origin": "RF-DP", + "label": "P39 split section count vs contributions unchecked", + "old": " if len(split[\"sections\"]) != len(pool):", + "new": " if False:", + "killers": [ + "test_extra_split_section_is_a_global_failure" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DP19", + "origin": "RF-DP", + "label": "P47 upper-case .LIB invisible to the unlisted check", + "old": " if path.is_file() and path.suffix.lower() == \".lib\":", + "new": " if path.is_file() and path.suffix == \".lib\":", + "killers": [ + "test_upper_case_unlisted_library_fails_closed" + ], + "retarget": "RF-DP independent re-review: guards a fail-closed gap found after integration" + }, + { + "id": "DX01", + "origin": "RF-DX", + "label": "D6 unanticipated exception escapes as status 1 again (catch-all narrowed)", + "old": " except Exception as caught: # deliberately total (RF-DX, D6)", + "new": " except ArithmeticError as caught: # deliberately total (RF-DX, D6)", + "retarget": null, + "killers": [ + "test_unanticipated_exception_is_receipted_never_status_1" + ] + }, + { + "id": "DX02", + "origin": "RF-DX", + "label": "D6 a report that cannot be written escapes as status 1 again", + "old": " except Exception as unwritable: # deliberately total (RF-DX, D6)", + "new": " except ArithmeticError as unwritable: # deliberately total (RF-DX, D6)", + "retarget": null, + "killers": [ + "test_unwritable_report_fails_closed_and_the_receipt_says_so" + ] + }, + { + "id": "DX03", + "origin": "RF-DX", + "label": "D6 an exit-2 run leaves the reports it already wrote (accounting) behind", + "old": " for path in paths:\n try:\n path.unlink()", + "new": " for path in []:\n try:\n path.unlink()", + "retarget": null, + "killers": [ + "test_unwritable_receipt_leaves_no_report_behind", + "test_unwritable_report_fails_closed_and_the_receipt_says_so" + ] + }, + { + "id": "DX04", + "origin": "RF-DX", + "label": "D6 an unlistable library directory is exit 2 instead of a library failure (3)", + "old": " except OSError as error:\n # listing the library directory", + "new": " except ArithmeticError as error:\n # listing the library directory", + "retarget": null, + "killers": [ + "test_unlistable_library_directory_is_a_library_failure" + ] + }, + { + "id": "DX05", + "origin": "RF-DX", + "label": "D11 another linked library defining a vendor name is ignored", + "old": " if others:", + "new": " if False:", + "retarget": null, + "killers": [ + "test_vendor_record_defined_by_another_linked_library_fails_closed" + ] + }, + { + "id": "DX06", + "origin": "RF-DX", + "label": "D11 another linked library defining a vendor name is only a record FAIL (no fail-closed)", + "old": " \"vendor-record-defined-by-another-library\",\n})", + "new": "})", + "retarget": null, + "killers": [ + "test_vendor_record_defined_by_another_linked_library_fails_closed" + ] + }, + { + "id": "DX07", + "origin": "RF-DX", + "label": "D6 IndexError no longer malformed input (falls through to the catch-all, exit 2)", + "old": " except IndexError as caught:", + "new": " except ArithmeticError as caught:", + "retarget": null, + "killers": [ + "test_index_error_is_malformed_input_and_receipted" + ] + }, + { + "id": "DX08", + "origin": "RF-DX", + "label": "D6 a run whose receipt cannot be written keeps its reports", + "old": " _remove_outputs(written) # no report outlives a run whose receipt could not be written (RF-DX)", + "new": " pass", + "retarget": null, + "killers": [ + "test_unwritable_receipt_leaves_no_report_behind" + ] + }, + { + "id": "DX09", + "origin": "RF-DX", + "label": "D2 (optional pin) a manifest other than the reviewed one accepted", + "old": " if pinned is not None and actual != pinned:", + "new": " if False:", + "retarget": null, + "killers": [ + "test_manifest_pin_refuses_any_other_manifest" + ] + } + ] +} diff --git a/research/remaining_frontier_20260926/q10/mutation/q10_mutate.py b/research/remaining_frontier_20260926/q10/mutation/q10_mutate.py new file mode 100644 index 00000000..220f5cc0 --- /dev/null +++ b/research/remaining_frontier_20260926/q10/mutation/q10_mutate.py @@ -0,0 +1,113 @@ +"""Mutation harness for the Q10 COMMON-pool verifier draft (research only; Q10 held; zero credit). + +Every mutation in mutations.json is applied, alone, to a copy of tools/common_pool_verify.py inside an +isolated work tree (tools/ + this q10 directory); its named killer tests are then run. A mutation is +KILLED only if pytest exits 1, reports no collection/setup error, and EVERY named killer test fails. + +usage: + python q10_mutate.py --repo --work [--out kills.txt] # check the catalogue + python q10_mutate.py --repo --work --discover [--write] # find failing tests + (--discover runs the whole test file per mutant and lists every failing test; --write stores them + as the killers of each mutation) +Exit status 0 only if every mutation is KILLED (check mode) or killed by at least one test (discover). +""" +import argparse +import json +import os +import re +import shutil +import subprocess +import sys +from pathlib import Path + +Q10 = Path("research") / "remaining_frontier_20260926" / "q10" +TARGET = Path("tools") / "common_pool_verify.py" +TESTS = "tools/test_common_pool_verify.py" +FAILED = re.compile(r"^(FAILED|ERROR) tools/test_common_pool_verify\.py::([A-Za-z0-9_]+)") + + +def work_tree(repo, work): + if work.exists(): + shutil.rmtree(work) + shutil.copytree(repo / "tools", work / "tools", ignore=shutil.ignore_patterns("__pycache__")) + shutil.copytree(repo / Q10, work / Q10, ignore=shutil.ignore_patterns("__pycache__")) + return work + + +def run_tests(tree, selectors, basetemp): + env = dict(os.environ, PYTHONDONTWRITEBYTECODE="1") + result = subprocess.run([sys.executable, "-m", "pytest", *selectors, "-q", "-rfE", "-p", "no:cacheprovider", + "--basetemp", str(basetemp)], cwd=tree, capture_output=True, text=True, env=env) + failed, errors = set(), set() + for line in result.stdout.splitlines(): + match = FAILED.match(line) + if match: + (failed if match.group(1) == "FAILED" else errors).add(match.group(2)) + tail = (result.stdout.strip().splitlines() or [result.stderr[-200:]])[-1] + return result.returncode, failed, errors, tail + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--repo", required=True) + parser.add_argument("--work", required=True) + parser.add_argument("--catalogue", default=None) + parser.add_argument("--discover", action="store_true") + parser.add_argument("--write", action="store_true") + parser.add_argument("--only", nargs="*") + parser.add_argument("--out") + args = parser.parse_args() + repo, work = Path(args.repo).resolve(), Path(args.work).resolve() + catalogue_path = Path(args.catalogue) if args.catalogue else repo / Q10 / "mutation" / "mutations.json" + catalogue = json.loads(catalogue_path.read_text(encoding="utf-8")) + source = (repo / TARGET).read_bytes().decode("utf-8").replace("\r\n", "\n") + lines, bad = [], 0 + baseline = work_tree(repo, work / "baseline") + code, failed, errors, tail = run_tests(baseline, [TESTS], work / "tmp_baseline") + lines.append(f"BASELINE (unmutated) exit {code}: {tail}") + if code != 0: + print("\n".join(lines)) + return 2 + for mutation in catalogue["mutations"]: + if args.only and mutation["id"] not in args.only: + continue + count = source.count(mutation["old"]) + label = f"{mutation['id']} {mutation['origin']:<5} {mutation['label']}" + if count != 1: + lines.append(f"BAD-MUTATION ({count} matches) {label}") + bad += 1 + continue + tree = work_tree(repo, work / "mut") + (tree / TARGET).write_bytes(source.replace(mutation["old"], mutation["new"]).encode("utf-8")) + if args.discover: + code, failed, errors, tail = run_tests(tree, [TESTS], work / "tmp_mut") + killed = code == 1 and failed and not errors + if args.write and killed: + mutation["killers"] = sorted(failed) + lines.append(f"{'KILLED' if killed else 'SURVIVED':<8} {label}: {sorted(failed)} {tail}") + else: + killers = mutation["killers"] + if not killers: + lines.append(f"NO-KILLERS {label}") + bad += 1 + continue + code, failed, errors, tail = run_tests(tree, [f"{TESTS}::{k}" for k in killers], work / "tmp_mut") + missing = sorted(set(killers) - failed) + killed = code == 1 and not errors and not missing + lines.append(f"{'KILLED' if killed else 'SURVIVED':<8} {label}: killers {len(killers)} failed " + f"{len(set(killers) & failed)}{' missing ' + str(missing) if missing else ''} | {tail}") + if not killed: + bad += 1 + total = len([m for m in catalogue["mutations"] if not args.only or m["id"] in args.only]) + lines.append(f"mutations {total}, not killed {bad}") + text = "\n".join(lines) + "\n" + sys.stdout.write(text) + if args.out: + Path(args.out).write_text(text, encoding="utf-8", newline="\n") # LF on every platform (RF-DP D1) + if args.discover and args.write: + catalogue_path.write_text(json.dumps(catalogue, indent=1) + "\n", encoding="utf-8", newline="\n") + return 0 if bad == 0 else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/research/remaining_frontier_20260926/q10/xdk3911_lib_manifest.json b/research/remaining_frontier_20260926/q10/xdk3911_lib_manifest.json new file mode 100644 index 00000000..f1d9f4f2 --- /dev/null +++ b/research/remaining_frontier_20260926/q10/xdk3911_lib_manifest.json @@ -0,0 +1,295 @@ +{ + "schema": "xdk-lib-manifest/1", + "status": "research only; Q10 held; zero credit; library bytes recorded as data, never credit", + "recorded_by": "RF-DM 2026-09-28 (research/remaining_frontier_20260926/workers/RF-DM/tools/build_xdk_manifest.py)", + "source_dir": "C:/tmp/xdk3911_extract/XDK/xbox/lib", + "evidence": [ + "sha256 and size of every .lib file in source_dir (XDK 3911 extract, read as data)", + "linked_by_january / january_pdb_modules: January cachebeta.pdb DBI module table (848 modules) read with RF-DI tools/pdb_mods.py; count of modules whose object path names the library", + "RF-DH C09: the release libraries reproduce all 27 vendor pool records (COMMON of January's size, each member a January PDB module); debug variants differ (e.g. xapilibd powerdwn COMMON 88)" + ], + "libraries": [ + { + "file": "d3d8.lib", + "sha256": "41ab837028d00015016040593890c57d54201c4c046835aca500ef7c6e4ac4d7", + "size": 1736410, + "linked_by_january": true, + "january_pdb_modules": 29 + }, + { + "file": "d3d8d.lib", + "sha256": "7e12dfc95d4fc45c818f5756112d3da7b418f0cd0a0e90c37395d91156b317cb", + "size": 2894726, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "d3d8i.lib", + "sha256": "e64a7cb16e71a057d1bfdc619d7cfcd7b358553a2f3b0d526c6c930522bc10f2", + "size": 2144034, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "d3d8ltcg.lib", + "sha256": "1083af7aba33eee8d2a5f4c63aa134d1951ccd40a6a0c316540679ffec85b2ba", + "size": 16642874, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "d3dx8.lib", + "sha256": "2ed9b746e9e169a6b70ef41d48554f492285ed71b749f4c64782a6c5ee9eca64", + "size": 5079110, + "linked_by_january": true, + "january_pdb_modules": 8 + }, + { + "file": "d3dx8d.lib", + "sha256": "7fdc20d92d7257ccb9950e58fbdcb3f031172266c766e5a457bd571eea745f36", + "size": 5449862, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "dmusic.lib", + "sha256": "fbb30d11953b9853030b84bfbf7eb7d083223d75ab3e73203e6b622892861f58", + "size": 16545856, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "dmusicd.lib", + "sha256": "d234444be4ed4c2b44703c7f5e7fe33c9ba2b8714a06ab2d3a79d9a505765f59", + "size": 18152686, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "dmusici.lib", + "sha256": "ce7daeca0537670854c162f735738854e6482f837ff93a010b7b04cef5db52ef", + "size": 16627550, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "dsound.lib", + "sha256": "0a07e97bdef6f18f5ec3b74aa4996d1bfe5cdbcdf561ceef22c0b671021ea136", + "size": 3777324, + "linked_by_january": true, + "january_pdb_modules": 17 + }, + { + "file": "dsoundd.lib", + "sha256": "44c19396005b5ea8a5c2b5039878dcedadc7676401394df4b2d1ed0d0c7a5213", + "size": 4494588, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libc.lib", + "sha256": "08c82866294658ce5b670a2dce0a73d9f614bedf6f1e13b73bdbe1bd923afa6a", + "size": 4278254, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcd.lib", + "sha256": "26c100ce13369ec00c4fb2e0b423b1d5b1524de892d78767138419d06a01be5a", + "size": 5629060, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libci.lib", + "sha256": "e220066f189cffe7df1e20452b9f261372ea1f16a82fcb3308cffa9a7c6b9878", + "size": 960090, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcid.lib", + "sha256": "7ebc7c439290e2ae533a1ef531286d537ca369ed1ed6df32dba350aa1af36633", + "size": 1011350, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcimt.lib", + "sha256": "56b3f89a5c140815047b6b7ca082b95ffcc1071a9d95d060129e2927cc794852", + "size": 1080092, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcimtd.lib", + "sha256": "a36525115dd6eb9ab05f48752789125c246e9a64fff467382734acdc5798c5a0", + "size": 1126694, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcmt.lib", + "sha256": "60aa4c87c97eeb6662b31d9d37cf3caba1afabaec72c47b090e7a0ce8b632f55", + "size": 4372210, + "linked_by_january": true, + "january_pdb_modules": 212 + }, + { + "file": "libcmtd.lib", + "sha256": "6248684cd7b1b49918b5ae23967688e2f53ffdc4f01d443796a6f00fee23949d", + "size": 5595180, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcp.lib", + "sha256": "8e4a362e1d3325357461234cabb20f1545afbcc1ef3d03075eeca1213f80d56a", + "size": 5231580, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcpd.lib", + "sha256": "db142d1d866c14a65ffd26eaa269a3c855e0aef649a9fa4109b4c87afc721266", + "size": 6694966, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcpmt.lib", + "sha256": "9bb9462c7ef9fea61d9fe5818551cb5d9adda3ed58545acc3147eb5f3ccd6bd0", + "size": 5244330, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "libcpmtd.lib", + "sha256": "d58d58d1ec531306116b4faa8b26ad16b7f8c66fde56da38f3db3a2ed15e4453", + "size": 6682978, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "oldnames.lib", + "sha256": "348a220e94f90bd9f530514ae59ff9b044b76e2056f52b45df406c12d2156afb", + "size": 65372, + "linked_by_january": true, + "january_pdb_modules": 11 + }, + { + "file": "uuid.lib", + "sha256": "96f671edc10e80961473e15b7553f1675e5f3d6d7d2fc7bf5941e525a821ec2b", + "size": 158540, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "VTuneAPI_XBOX.lib", + "sha256": "e2728298ee7beec4fd1f29bdd92ef714c31d8e9840adbca9360ff70ba897bea9", + "size": 11020, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xapilib.lib", + "sha256": "56122745988d7d1f031b1cc3a06b1b11347f6bc2f92e53a081a01a59e1e64d53", + "size": 2432912, + "linked_by_january": true, + "january_pdb_modules": 61 + }, + { + "file": "xapilibd.lib", + "sha256": "e16b4c04826f2747a62011a67f85d7765b8fdb96240ecfb03d910dd6b84d42b0", + "size": 2751612, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xbdm.lib", + "sha256": "34236c2e8007d62a853ea8580896719ec178aa8e2d9bab265205c4334a3a8b7b", + "size": 13574, + "linked_by_january": true, + "january_pdb_modules": 1 + }, + { + "file": "xboxkrnl.lib", + "sha256": "41a8bfa7ab1382c4d18e31c1881c93540d90573b1973f0a4eb3625a750c7df90", + "size": 88658, + "linked_by_january": true, + "january_pdb_modules": 2 + }, + { + "file": "xgraphics.lib", + "sha256": "f700d69d2fc57fd6e85c68804aed20e4f000648b56ec8e17b91e19f04e5f823c", + "size": 1674906, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xgraphicsd.lib", + "sha256": "dd32bb80e36cf267d1c8374a5b9574a9c64b07982e777477c8f2251d6ca38e84", + "size": 1829206, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xkbd.lib", + "sha256": "36b3283fc8e84e635a0c541fab056529f5de4fbae3b37adfc76b771e5a45e21b", + "size": 92182, + "linked_by_january": true, + "january_pdb_modules": 1 + }, + { + "file": "xkbdd.lib", + "sha256": "553e241d41e045e4401d997d79b6b4a70b5d85daa47cffafef477e195855f754", + "size": 93096, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xnet.lib", + "sha256": "368d7a9a7eec6df4d906d946ba2998272374432e93ef5b59ad91de6324a5ebe4", + "size": 1009062, + "linked_by_january": true, + "january_pdb_modules": 13 + }, + { + "file": "xnetd.lib", + "sha256": "823af0fa5bc91f8fd603abccbe650961fc36ca80bf8df19d5ada38c3f59d4a23", + "size": 1664632, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xnets.lib", + "sha256": "972e3720f3bed795f373719d0add882fa7f109f9b85b6dd55abc3d33240fc94c", + "size": 921344, + "linked_by_january": false, + "january_pdb_modules": 0 + }, + { + "file": "xnetsd.lib", + "sha256": "2aa08940bdb6ce0f1ec8740ad79445340e959f16c34e8759b7be3d434c77e961", + "size": 1474614, + "linked_by_january": false, + "january_pdb_modules": 0 + } + ], + "linked_libraries_not_in_extract": [ + { + "library": "binkxbox.lib", + "category": "binkxbox", + "january_path": "c:\\binkxbox\\binkxbox.lib", + "january_pdb_modules": 24, + "reason": "linked by January (cachebeta.pdb module table) but not in the XDK 3911 extract; its members cannot be scanned, so the Halo-record-defined-by-a-library check does not cover it" + }, + { + "library": "dsstrmh.lib", + "category": "dsstrmh", + "january_path": "C:\\Program Files\\Microsoft Xbox SDK\\Xbox\\Lib\\dsstrmh.lib", + "january_pdb_modules": 1, + "reason": "linked by January (cachebeta.pdb module table) but not in the XDK 3911 extract; its members cannot be scanned, so the Halo-record-defined-by-a-library check does not cover it" + } + ] +} diff --git a/source/ai/action_charge.c b/source/ai/action_charge.c index 272c6bca..31928588 100644 --- a/source/ai/action_charge.c +++ b/source/ai/action_charge.c @@ -679,15 +679,15 @@ boolean action_charge_perform( if (state_data->leap_pending || (melee && !state_data->melee_suicide)) { - real_vector2d facing_direction; + real_vector2d target_alignment_vector; - facing_direction.i = direction.i; - facing_direction.j = direction.j; - if (normalize2d(&facing_direction) > 0.f) + target_alignment_vector.i = direction.i; + target_alignment_vector.j = direction.j; + if (normalize2d(&target_alignment_vector) > 0.f) { real minimum_alignment = state_data->launched_leap ? 0.f : 0.8660254f; - if (dot_product2d(&facing_direction, (real_vector2d *)&actor->input.facing_vector) < minimum_alignment) + if (dot_product2d(&target_alignment_vector, (real_vector2d *)&actor->input.facing_vector) < minimum_alignment) { melee = FALSE; state_data->leap_pending = FALSE; @@ -701,17 +701,17 @@ boolean action_charge_perform( if (melee) { - real_vector2d melee_direction; + real_vector2d alignment_vector; - melee_direction.i = direction.i; - melee_direction.j = direction.j; - if (normalize2d(&melee_direction) == 0.f) + alignment_vector.i = direction.i; + alignment_vector.j = direction.j; + if (normalize2d(&alignment_vector) == 0.f) { - melee_direction.i = actor->input.facing_vector.i; - melee_direction.j = actor->input.facing_vector.j; + alignment_vector.i = actor->input.facing_vector.i; + alignment_vector.j = actor->input.facing_vector.j; } - if (unit_melee_attack_begin(actor->meta.unit_index, FALSE, &melee_direction)) + if (unit_melee_attack_begin(actor->meta.unit_index, FALSE, &alignment_vector)) { ai_communication_event( _ai_communication_melee, diff --git a/source/ai/action_converse.c b/source/ai/action_converse.c index 57d97fac..462d17a1 100644 --- a/source/ai/action_converse.c +++ b/source/ai/action_converse.c @@ -30,6 +30,7 @@ symbols in this file: #include "actions.h" #include "actors.h" +#include "ai/ai_scenario_definitions.h" #include "ai_communication.h" #include "props.h" #include "scenario/scenario.h" @@ -42,15 +43,8 @@ symbols in this file: /* ---------- structures */ -struct scenario_conversation_definition -{ - byte __unknown0[0x28]; - real run_to_distance; - byte __unknown2c[0x48]; -}; - typedef char scenario_conversation_definition_size_assert[ - sizeof(struct scenario_conversation_definition) == 0x74 ? 1 : -1]; + sizeof(struct ai_conversation) == 0x74 ? 1 : -1]; /* ---------- prototypes */ @@ -63,20 +57,20 @@ boolean action_converse_setup( long conversation_index, struct converse_state_data *state_data) { - struct ai_conversation_datum_header *conversation; - struct scenario_conversation_definition *definition; + struct conversation_datum *conversation; + struct ai_conversation *definition; actor_get(actor_index); conversation = ai_conversation_header_get(conversation_index); definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, conversation->scenario_conversation_index, - struct scenario_conversation_definition); + struct ai_conversation); match_assert("c:\\halo\\SOURCE\\ai\\action_converse.c", 33, state_data); csmemset(state_data, 0, sizeof(*state_data)); state_data->conversation_index = conversation_index; - state_data->run_to_distance = definition->run_to_distance; + state_data->run_to_distance = definition->run_to_player_dist; state_data->run_to_unit_index = state_data->run_to_distance == 0.0f ? NONE : conversation->triggering_player_unit_index; @@ -161,7 +155,7 @@ void action_converse_control( { struct actor_datum *actor = actor_get(actor_index); struct converse_state_data *state_data = &actor->state.action_data.converse; - struct ai_conversation_datum_header *conversation = NULL; + struct conversation_datum *conversation = NULL; long prop_index = NONE; if (state_data->conversation_index != NONE) diff --git a/source/ai/actions.c b/source/ai/actions.c index 0488e6ca..8d8e32f7 100644 --- a/source/ai/actions.c +++ b/source/ai/actions.c @@ -234,6 +234,8 @@ symbols in this file: #include "actor_definitions.h" #include "actor_types.h" #include "ai.h" +#include "ai/ai_globals.h" +#include "ai/ai_scenario_definitions.h" #include "ai_communication.h" #include "ai_debug.h" #include "ai_profile.h" @@ -322,37 +324,8 @@ enum /* ---------- structures */ -/* The fields used here from the 0x74-byte scenario conversation record. */ -struct scenario_conversation_action_definition -{ - char name[TAG_STRING_LENGTH + 1]; - word flags; - byte __unknown22[0x52]; -}; - typedef char scenario_conversation_action_definition_size_assert[ - sizeof(struct scenario_conversation_action_definition) == 0x74 ? 1 : -1]; - -/* Only the January-proven field consumed by this translation unit is named. */ -struct ai_vehicle_enterable -{ - long vehicle_index; - real radius; - short team_bitmask; - short actor_type_bitmask; - short ai_indices_count; - word __pad0E; - long ai_indices[6]; -}; - -struct ai_globals_action_data -{ - byte __unknown0[0x3B4]; - boolean grenades_enabled; - byte __unknown3B5; - short enterable_vehicle_count; - struct ai_vehicle_enterable enterable_vehicles[32]; -}; + sizeof(struct ai_conversation) == 0x74 ? 1 : -1]; /* The January iterator is exactly three datum indices; callers consume the * current actor index after encounter_actor_iterator_next advances it. */ @@ -383,11 +356,9 @@ struct vehicle_definition typedef char ai_globals_action_vehicle_size_assert[ sizeof(struct ai_vehicle_enterable) == 0x28 ? 1 : -1]; typedef char ai_globals_action_grenades_enabled_offset_assert[ - offsetof(struct ai_globals_action_data, grenades_enabled) == 0x3B4 ? 1 : -1]; + offsetof(struct ai_globals, grenades_enabled) == 0x3B4 ? 1 : -1]; typedef char ai_globals_action_enterable_vehicles_offset_assert[ - offsetof(struct ai_globals_action_data, enterable_vehicles) == 0x3B8 ? 1 : -1]; -typedef char ai_globals_action_data_size_assert[ - sizeof(struct ai_globals_action_data) == 0x8B8 ? 1 : -1]; + offsetof(struct ai_globals, enterable_vehicles) == 0x3B8 ? 1 : -1]; typedef char actions_prop_enemy_offset_assert[ offsetof(struct prop_datum, enemy) == 0x60 ? 1 : -1]; typedef char actions_prop_dead_offset_assert[ @@ -468,8 +439,6 @@ static boolean actor_action_allowed_to_enter_vehicle( /* ---------- globals */ -extern struct ai_globals_action_data *ai_globals; - real_argb_color global_temporary_render_color; struct action_specification const global_action_functions[NUMBER_OF_ACTOR_ACTIONS] = @@ -1536,13 +1505,13 @@ boolean actor_action_can_stop_conversing( if (conversation_index != NONE) { word flags; - struct ai_conversation_datum_header *conversation = + struct conversation_datum *conversation = ai_conversation_header_get(conversation_index); - struct scenario_conversation_action_definition *definition = + struct ai_conversation *definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, conversation->scenario_conversation_index, - struct scenario_conversation_action_definition); + struct ai_conversation); flags = definition->flags; @@ -3827,7 +3796,7 @@ boolean actor_action_handle_vehicle_entry( long best_vehicle_index; real attempt_distance; real continue_distance; - struct action_state_data state; + struct action_state_data new_state_data; if (actor->state.action == _actor_action_flee && actor->state.action_data.flee.panic_type > _actor_panic_none) @@ -3877,13 +3846,13 @@ boolean actor_action_handle_vehicle_entry( if (vehicle && vehicle->unit.driver_object_index == prop->unit_index) { - real_point3d origin; + real_point3d vehicle_origin; real distance_squared; - object_get_origin(prop->vehicle_index, &origin); + object_get_origin(prop->vehicle_index, &vehicle_origin); distance_squared = distance_squared3d( &actor->input.position.body_position, - &origin); + &vehicle_origin); if (distance_squared < 100.0f && distance_squared < best_distance_squared) @@ -3918,7 +3887,7 @@ boolean actor_action_handle_vehicle_entry( { struct ai_vehicle_enterable *enterable = &ai_globals->enterable_vehicles[(short)slot]; - real_point3d origin; + real_point3d position; real distance_squared; short team_bitmask; short actor_type_bitmask; @@ -3929,9 +3898,9 @@ boolean actor_action_handle_vehicle_entry( continue; } - object_get_origin(enterable->vehicle_index, &origin); + object_get_origin(enterable->vehicle_index, &position); distance_squared = distance_squared3d( - &origin, + &position, &actor->input.position.body_position); if (!(distance_squared < best_distance_squared) || @@ -4013,9 +3982,9 @@ setup_entry: best_vehicle_index, attempt_distance, continue_distance, - &state.vehicle)) + &new_state_data.vehicle)) { - actor_action_change(actor_index, _actor_action_vehicle, &state); + actor_action_change(actor_index, _actor_action_vehicle, &new_state_data); result = TRUE; } else diff --git a/source/ai/actor_combat.c b/source/ai/actor_combat.c index f176660b..674af1b2 100644 --- a/source/ai/actor_combat.c +++ b/source/ai/actor_combat.c @@ -1006,9 +1006,9 @@ boolean actor_combat_plan_grenade_trajectory( struct actor_datum *actor = actor_get(actor_index); struct actor_variant_definition *variant_definition = actor_variant_definition_get(actor->meta.variant_definition_index); - real_point3d grenade_origin = actor->input.position.head_position; + real_point3d origin = actor->input.position.head_position; real_vector3d aim_vector; - real_vector3d aim_velocity; + real_vector3d arc_initial_velocity; real aim_speed; real aim_ticks; real aim_gravity; @@ -1016,7 +1016,7 @@ boolean actor_combat_plan_grenade_trajectory( if (actor_combat_build_grenade_trajectory( variant_definition->grenade_combat.grenade_type, - &grenade_origin, + &origin, variant_definition->grenade_combat.grenade_maximum_velocity, grenade_target, NULL, @@ -1024,13 +1024,13 @@ boolean actor_combat_plan_grenade_trajectory( &aim_vector, &aim_speed, &aim_ticks, - &aim_velocity, + &arc_initial_velocity, &aim_gravity) && ai_test_ballistic_line_of_fire( actor_index, - &grenade_origin, + &origin, aim_ticks, - &aim_velocity, + &arc_initial_velocity, aim_gravity, grenade_ignore_object_index, actor->input.vehicle_index != NONE)) diff --git a/source/ai/actor_looking.c b/source/ai/actor_looking.c index c657235f..6b3f6dcc 100644 --- a/source/ai/actor_looking.c +++ b/source/ai/actor_looking.c @@ -1431,10 +1431,10 @@ void actor_look_update( if (actor_combat_currently_firing_burst(actor_index) && !actor->orders.combat.abort_burst) { - struct direction_specification burst_specification; + struct direction_specification temporary_direction; - burst_specification.type = _direction_specification_target; - if (actor_look_decode_direction(actor_index, &burst_specification, &primary_vector)) + temporary_direction.type = _direction_specification_target; + if (actor_look_decode_direction(actor_index, &temporary_direction, &primary_vector)) { primary_priority = _primary_priority_locked_aiming; aiming_at_target = TRUE; @@ -1896,22 +1896,22 @@ update_facing: } else { - real_vector2d facing2d; - real_vector2d aiming2d; - real_vector2d fixed2d; + real_vector2d desired_facing; + real_vector2d desired_aiming; + real_vector2d stationary_facing; - facing2d.i = actor->control.desired_facing_vector.i; - facing2d.j = actor->control.desired_facing_vector.j; - aiming2d.i = actor->control.desired_aiming_vector.i; - aiming2d.j = actor->control.desired_aiming_vector.j; - fixed2d.i = actor->control.fixed_stationary_facing_vector.i; - fixed2d.j = actor->control.fixed_stationary_facing_vector.j; + desired_facing.i = actor->control.desired_facing_vector.i; + desired_facing.j = actor->control.desired_facing_vector.j; + desired_aiming.i = actor->control.desired_aiming_vector.i; + desired_aiming.j = actor->control.desired_aiming_vector.j; + stationary_facing.i = actor->control.fixed_stationary_facing_vector.i; + stationary_facing.j = actor->control.fixed_stationary_facing_vector.j; - valid = normalize2d(&facing2d) != 0.0f && - normalize2d(&aiming2d) != 0.0f && - normalize2d(&fixed2d) != 0.0f && - dot_product2d(&fixed2d, &facing2d) > stationary_cosine && - dot_product2d(&aiming2d, &fixed2d) > stationary_cosine; + valid = normalize2d(&desired_facing) != 0.0f && + normalize2d(&desired_aiming) != 0.0f && + normalize2d(&stationary_facing) != 0.0f && + dot_product2d(&stationary_facing, &desired_facing) > stationary_cosine && + dot_product2d(&desired_aiming, &stationary_facing) > stationary_cosine; } if (!valid) diff --git a/source/ai/actor_moving.c b/source/ai/actor_moving.c index 24ff6f7a..1bf85b23 100644 --- a/source/ai/actor_moving.c +++ b/source/ai/actor_moving.c @@ -458,9 +458,9 @@ real const avoid_ray_adjacent_fractions[2] = }; real const avoid_ray_fully_obstructed_t = 0.5f; -extern struct vector_avoidance_ray avoidance_rays[VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS][2]; -extern real_vector3d avoidance_directions[VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS]; -extern struct vector_avoidance_ray sense_rays[9]; +struct vector_avoidance_ray avoidance_rays[VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS][2]; +real_vector3d avoidance_directions[VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS]; +struct vector_avoidance_ray sense_rays[9]; /* ---------- public code */ @@ -830,7 +830,7 @@ static short actor_move_test_avoidance_vector( real *collision_t, byte *collision_timer) { - struct collision_bsp_test_vector_result collision; + struct collision_bsp_test_vector_result collision_result; real_vector3d offset; real_vector3d divergence; real scale; @@ -874,7 +874,7 @@ static short actor_move_test_avoidance_vector( &avoidance_data->origin, &offset, 1.f, - &collision)) + &collision_result)) { result = _actor_vector_avoidance_obstructed_structure; *collision_t = 0.f; @@ -888,10 +888,10 @@ static short actor_move_test_avoidance_vector( ray_origin, ray_direction, 1.f, - &collision)) + &collision_result)) { result = _actor_vector_avoidance_obstructed_structure; - *collision_t = collision.t; + *collision_t = collision_result.t; } for (object_index = 0; @@ -1419,7 +1419,7 @@ static void actor_move_vector_avoidance( struct actor_debug_info *debug_info = &actor_debug_array[DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)]; struct vector_avoidance_data avoidance_data; - real weights[VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS]; + real avoidance_weights[VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS]; real_vector3d movement_vector; real_vector3d local_movement_direction; real maximum_sense_emergency; @@ -1448,7 +1448,7 @@ static void actor_move_vector_avoidance( actor_move_avoidance_setup(&avoidance_data); maximum_sense_emergency = 0.f; - csmemset(weights, 0, sizeof(weights)); + csmemset(avoidance_weights, 0, sizeof(avoidance_weights)); { short current_direction = actor->control.vector_avoidance_current_direction; @@ -1460,11 +1460,11 @@ static void actor_move_vector_avoidance( short previous_direction = (current_direction + VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS - 1) % VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; short second_previous_direction = (current_direction + VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS - 2) % VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; - weights[current_direction] += 0.4f; - weights[next_direction] += avoid_ray_adjacent_fractions[0]*0.4f; - weights[second_next_direction] += avoid_ray_adjacent_fractions[1]*0.4f; - weights[previous_direction] += avoid_ray_adjacent_fractions[0]*0.4f; - weights[second_previous_direction] += avoid_ray_adjacent_fractions[1]*0.4f; + avoidance_weights[current_direction] += 0.4f; + avoidance_weights[next_direction] += avoid_ray_adjacent_fractions[0]*0.4f; + avoidance_weights[second_next_direction] += avoid_ray_adjacent_fractions[1]*0.4f; + avoidance_weights[previous_direction] += avoid_ray_adjacent_fractions[0]*0.4f; + avoidance_weights[second_previous_direction] += avoid_ray_adjacent_fractions[1]*0.4f; } } @@ -1494,7 +1494,7 @@ static void actor_move_vector_avoidance( direction_index < VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; direction_index++) { - weights[direction_index] += + avoidance_weights[direction_index] += sense_ray_avoidance_weights[ray_index][direction_index]*MIN(sense_weight, 1.f); } maximum_sense_emergency = MAX(maximum_sense_emergency, sense_emergency); @@ -1505,8 +1505,8 @@ static void actor_move_vector_avoidance( direction_index < VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; direction_index++) { - short avoidance_types[NUMBEROF(avoid_ray_avoidance_weights)]; - real avoidance_t[NUMBEROF(avoid_ray_avoidance_weights)]; + short avoid_ray_result[NUMBEROF(avoid_ray_avoidance_weights)]; + real avoid_ray_t[NUMBEROF(avoid_ray_avoidance_weights)]; real direction_weight; boolean obstructed; @@ -1515,17 +1515,17 @@ static void actor_move_vector_avoidance( real_point3d ray_origin; real_vector3d ray_direction; - avoidance_types[ray_index] = actor_move_test_avoidance_vector( + avoid_ray_result[ray_index] = actor_move_test_avoidance_vector( &avoidance_data, &avoidance_rays[direction_index][ray_index], &ray_origin, &ray_direction, - &avoidance_t[ray_index], + &avoid_ray_t[ray_index], &actor->control.vector_avoidance_clear_times[direction_index][ray_index]); debug_info->field_6358[direction_index][ray_index] = ray_origin; debug_info->field_6418[direction_index][ray_index] = ray_direction; - debug_info->field_62F8[direction_index][ray_index] = avoidance_types[ray_index]; - debug_info->avoid_t[direction_index][ray_index] = avoidance_t[ray_index]; + debug_info->field_62F8[direction_index][ray_index] = avoid_ray_result[ray_index]; + debug_info->avoid_t[direction_index][ray_index] = avoid_ray_t[ray_index]; } direction_weight = 0.f; @@ -1533,7 +1533,7 @@ static void actor_move_vector_avoidance( for (ray_index = NUMBEROF(avoid_ray_avoidance_weights) - 1; ray_index >= 0; ray_index--) { - if (avoidance_types[ray_index] == _actor_vector_avoidance_clear) + if (avoid_ray_result[ray_index] == _actor_vector_avoidance_clear) { real clear_fraction = 1.f; @@ -1558,7 +1558,7 @@ static void actor_move_vector_avoidance( else { direction_weight -= - avoid_ray_avoidance_weights[ray_index]*MIN(2.f*(1.f - avoidance_t[ray_index]), 1.f); + avoid_ray_avoidance_weights[ray_index]*MIN(2.f*(1.f - avoid_ray_t[ray_index]), 1.f); obstructed = TRUE; } } @@ -1569,11 +1569,11 @@ static void actor_move_vector_avoidance( short previous_direction = (direction_index + VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS - 1) % VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; short second_previous_direction = (direction_index + VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS - 2) % VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; - weights[direction_index] += direction_weight; - weights[next_direction] += avoid_ray_adjacent_fractions[0]*direction_weight; - weights[second_next_direction] += avoid_ray_adjacent_fractions[1]*direction_weight; - weights[previous_direction] += avoid_ray_adjacent_fractions[0]*direction_weight; - weights[second_previous_direction] += avoid_ray_adjacent_fractions[1]*direction_weight; + avoidance_weights[direction_index] += direction_weight; + avoidance_weights[next_direction] += avoid_ray_adjacent_fractions[0]*direction_weight; + avoidance_weights[second_next_direction] += avoid_ray_adjacent_fractions[1]*direction_weight; + avoidance_weights[previous_direction] += avoid_ray_adjacent_fractions[0]*direction_weight; + avoidance_weights[second_previous_direction] += avoid_ray_adjacent_fractions[1]*direction_weight; } } @@ -1593,7 +1593,7 @@ static void actor_move_vector_avoidance( actor_move_vector_avoidance_find_direction( VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS, avoidance_directions, - weights, + avoidance_weights, &velocity_direction, &velocity_approximate_direction, &velocity_approximate_weight) && @@ -1607,7 +1607,7 @@ static void actor_move_vector_avoidance( dot_product3d(&avoidance_directions[direction_index], &velocity_direction); if (velocity_dot < 0.f) - weights[direction_index] += velocity_dot*velocity_weight; + avoidance_weights[direction_index] += velocity_dot*velocity_weight; } } else @@ -1628,9 +1628,9 @@ static void actor_move_vector_avoidance( direction_index < VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS; direction_index++) { - if (weights[direction_index] > best_weight) + if (avoidance_weights[direction_index] > best_weight) { - best_weight = weights[direction_index]; + best_weight = avoidance_weights[direction_index]; best_avoidance_direction = direction_index; } } @@ -1638,7 +1638,7 @@ static void actor_move_vector_avoidance( "c:\\halo\\SOURCE\\ai\\actor_moving.c", 2435, (best_avoidance_direction >= 0) && (best_avoidance_direction < VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS)); - csmemcpy(debug_info->field_64D8, weights, sizeof(weights)); + csmemcpy(debug_info->field_64D8, avoidance_weights, sizeof(avoidance_weights)); movement_vector = *movement_direction; forward_dot = 1.f; @@ -1656,7 +1656,7 @@ static void actor_move_vector_avoidance( actor_move_vector_avoidance_find_direction( VECTOR_AVOIDANCE_NUMBER_OF_DIRECTIONS, avoidance_directions, - weights, + avoidance_weights, &local_movement_direction, &movement_direction_approximation, &movement_approximate_weight); @@ -3055,8 +3055,8 @@ void actor_move_update( else if (actor->input.vehicle_driver_type == _actor_vehicle_driver_directional_flying) { - real_vector3d scaled_facing; - real_vector3d avoidance_rotation; + real_vector3d fake_movement_vector; + real_vector3d instantaneous_rotation_vector; real_vector3d const *movement_direction; real emergency_amount; real rotation_magnitude_squared; @@ -3072,17 +3072,17 @@ void actor_move_update( scale_vector3d( &actor->input.facing_vector, 3.f, - &scaled_facing); - movement_direction = &scaled_facing; + &fake_movement_vector); + movement_direction = &fake_movement_vector; } actor_move_vector_avoidance( actor_index, movement_direction, - &avoidance_rotation, + &instantaneous_rotation_vector, &emergency_amount); - rotation_magnitude_squared = magnitude_squared3d(&avoidance_rotation); + rotation_magnitude_squared = magnitude_squared3d(&instantaneous_rotation_vector); previous_magnitude_squared = magnitude_squared3d(&actor->control.vector_avoidance_rotation); blend = rotation_magnitude_squared > previous_magnitude_squared @@ -3093,9 +3093,9 @@ void actor_move_update( &actor->control.vector_avoidance_rotation, 1.f - blend, &actor->control.vector_avoidance_rotation); - actor->control.vector_avoidance_rotation.i += avoidance_rotation.i * blend; - actor->control.vector_avoidance_rotation.j += avoidance_rotation.j * blend; - actor->control.vector_avoidance_rotation.k += avoidance_rotation.k * blend; + actor->control.vector_avoidance_rotation.i += instantaneous_rotation_vector.i * blend; + actor->control.vector_avoidance_rotation.j += instantaneous_rotation_vector.j * blend; + actor->control.vector_avoidance_rotation.k += instantaneous_rotation_vector.k * blend; if (magnitude_squared3d(&actor->control.vector_avoidance_rotation) < _real_epsilon) @@ -3113,19 +3113,19 @@ void actor_move_update( if (actor->control.moving) { - real_vector3d rotation = + real_vector3d rotation_vector = actor->control.vector_avoidance_rotation; - real angle_squared = magnitude_squared3d(&rotation); + real angle_squared = magnitude_squared3d(&rotation_vector); if (angle_squared > _real_epsilon) { real angle = square_root(angle_squared); real inverse_angle = 1.f / angle; - scale_vector3d(&rotation, inverse_angle, &rotation); + scale_vector3d(&rotation_vector, inverse_angle, &rotation_vector); rotate_vector_about_axis( &actor->control.moving_towards_vector, - &rotation, + &rotation_vector, sine(angle), cosine(angle)); } @@ -3215,15 +3215,15 @@ void actor_move_update( allow_jump = TRUE; if (vehicle->object.up.k < 0.8f) { - real_vector3d escape_direction; + real_vector3d movement_vector; - escape_direction = vehicle->object.up; - escape_direction.k = 0.f; - if (normalize3d(&escape_direction) > 0.f) + movement_vector = vehicle->object.up; + movement_vector.k = 0.f; + if (normalize3d(&movement_vector) > 0.f) { actor->control.moving = TRUE; scale_vector3d( - &escape_direction, + &movement_vector, 3.f, &actor->control.moving_towards_vector); } @@ -3455,26 +3455,26 @@ void actor_move_update( !actor->emotions.played_berserk_sound) { long cause_unit_index = NONE; - real_vector2d alignment; + real_vector2d alignment_vector; - alignment.i = actor->input.facing_vector.i; - alignment.j = actor->input.facing_vector.j; + alignment_vector.i = actor->input.facing_vector.i; + alignment_vector.j = actor->input.facing_vector.j; if (actor->target.target_prop_index != NONE) { struct prop_datum *prop = prop_get(actor->target.target_prop_index); cause_unit_index = prop->unit_index; - alignment.i = prop->actor_to_prop.i; - alignment.j = prop->actor_to_prop.j; - if (normalize2d(&alignment) == 0.f) + alignment_vector.i = prop->actor_to_prop.i; + alignment_vector.j = prop->actor_to_prop.j; + if (normalize2d(&alignment_vector) == 0.f) { - alignment.i = actor->input.facing_vector.i; - alignment.j = actor->input.facing_vector.j; + alignment_vector.i = actor->input.facing_vector.i; + alignment_vector.j = actor->input.facing_vector.j; } } - actor_move_animation_impulse(actor_index, 0, &alignment); + actor_move_animation_impulse(actor_index, 0, &alignment_vector); ai_communication_event( _ai_communication_berserk, actor->meta.unit_index, @@ -3501,23 +3501,23 @@ void actor_move_update( if (actor->orders.move.jump_leap) { - real_vector2d alignment; + real_vector2d alignment_vector; if (actor->orders.move.jump_targeted) { - alignment = actor->orders.move.jump_alignment_vector; + alignment_vector = actor->orders.move.jump_alignment_vector; } else { - alignment.i = actor->input.facing_vector.i; - alignment.j = actor->input.facing_vector.j; - if (normalize2d(&alignment) == 0.f) - alignment = *global_forward2d; + alignment_vector.i = actor->input.facing_vector.i; + alignment_vector.j = actor->input.facing_vector.j; + if (normalize2d(&alignment_vector) == 0.f) + alignment_vector = *global_forward2d; } leaped = unit_leap_begin( actor->meta.unit_index, - &alignment); + &alignment_vector); } if (leaped) diff --git a/source/ai/actor_perception.c b/source/ai/actor_perception.c index c176e2af..f3a583a8 100644 --- a/source/ai/actor_perception.c +++ b/source/ai/actor_perception.c @@ -1935,12 +1935,12 @@ boolean actor_perception_friend_prop_is_attacking( } short actor_perception_aiming_vector_test_blockage( - real_point3d const *origin, - real_vector3d const *aiming_vector, - real_point3d const *point, - real_vector3d *error) + real_point3d const *source_position, + real_vector3d const *source_vector, + real_point3d const *friend_position, + real_vector3d *friend_direction_to_aiming_vector) { - real_vector2d horizontal_aiming; + real_vector2d source_planar_direction; real_vector3d friend_vector; real_vector3d blockage_vector; real horizontal_aiming_magnitude; @@ -1949,15 +1949,15 @@ short actor_perception_aiming_vector_test_blockage( real horizontal_error_squared; short blockage = 0; - horizontal_aiming.i = aiming_vector->i; - horizontal_aiming.j = aiming_vector->j; - horizontal_aiming_magnitude = magnitude2d(&horizontal_aiming); + source_planar_direction.i = source_vector->i; + source_planar_direction.j = source_vector->j; + horizontal_aiming_magnitude = magnitude2d(&source_planar_direction); if (!(_real_epsilon > fabs(horizontal_aiming_magnitude))) { real inverse_magnitude = 1.0f / horizontal_aiming_magnitude; - horizontal_aiming.i *= inverse_magnitude; - horizontal_aiming.j *= inverse_magnitude; + source_planar_direction.i *= inverse_magnitude; + source_planar_direction.j *= inverse_magnitude; } else { @@ -1967,10 +1967,10 @@ short actor_perception_aiming_vector_test_blockage( if (!(horizontal_aiming_magnitude > 0.0f)) goto done; - vector_from_points3d(origin, point, &friend_vector); + vector_from_points3d(source_position, friend_position, &friend_vector); projection = - friend_vector.i * horizontal_aiming.i + - friend_vector.j * horizontal_aiming.j; + friend_vector.i * source_planar_direction.i + + friend_vector.j * source_planar_direction.j; friend_distance = square_root( friend_vector.i * friend_vector.i + friend_vector.j * friend_vector.j); @@ -1981,17 +1981,17 @@ short actor_perception_aiming_vector_test_blockage( projection = -projection; blockage_vector.i = - friend_vector.i + projection * aiming_vector->i; + friend_vector.i + projection * source_vector->i; blockage_vector.j = - friend_vector.j + projection * aiming_vector->j; + friend_vector.j + projection * source_vector->j; blockage_vector.k = - friend_vector.k + projection * aiming_vector->k; + friend_vector.k + projection * source_vector->k; - if (error != NULL) + if (friend_direction_to_aiming_vector != NULL) { - error->i = -blockage_vector.i; - error->j = -blockage_vector.j; - error->k = -blockage_vector.k; + friend_direction_to_aiming_vector->i = -blockage_vector.i; + friend_direction_to_aiming_vector->j = -blockage_vector.j; + friend_direction_to_aiming_vector->k = -blockage_vector.k; } if (blockage_vector.k > -0.5f && blockage_vector.k < 0.9f) diff --git a/source/ai/actors.c b/source/ai/actors.c index 732b059b..da4ec393 100644 --- a/source/ai/actors.c +++ b/source/ai/actors.c @@ -289,6 +289,7 @@ symbols in this file: #include "props.h" #include "ai.h" +#include "ai/ai_globals.h" #include "math/real_math.h" #include "ai_communication.h" #include "ai_debug.h" @@ -528,27 +529,12 @@ typedef char vehicle_definition_flags_offset_assert[ typedef char vehicle_definition_ai_destination_radius_offset_assert[ offsetof(struct vehicle_definition, ai_destination_radius) == 0x384 ? 1 : -1]; -/* ai.h does not yet declare the ai globals; actors touches only the - * January-authenticated service-timer prefix, so model that view locally - * (the leading flags follow the ai.c prefix). */ -struct ai_globals_service_data -{ - boolean ai_active; - boolean ai_initialized_for_map; - byte reserved002; - boolean time_given_this_frame; - short last_highest_service_timer; - short current_highest_service_timer; - byte reserved008[0x3AC]; - boolean grenades_enabled; -}; - typedef char ai_globals_service_data_time_given_offset_assert[ - offsetof(struct ai_globals_service_data, time_given_this_frame) == 0x3 ? 1 : -1]; + offsetof(struct ai_globals, time_given_this_frame) == 0x3 ? 1 : -1]; typedef char ai_globals_service_data_current_highest_offset_assert[ - offsetof(struct ai_globals_service_data, current_highest_service_timer) == 0x6 ? 1 : -1]; + offsetof(struct ai_globals, current_highest_service_timer) == 0x6 ? 1 : -1]; typedef char ai_globals_service_data_grenades_enabled_offset_assert[ - offsetof(struct ai_globals_service_data, grenades_enabled) == 0x3B4 ? 1 : -1]; + offsetof(struct ai_globals, grenades_enabled) == 0x3B4 ? 1 : -1]; /* ---------- prototypes */ @@ -572,8 +558,6 @@ short const global_movement_animation_states[NUMBER_OF_ACTOR_MOVEMENT_TYPES] = _unit_animation_state_flaming, }; -extern struct ai_globals_service_data *ai_globals; - /* ---------- public code */ void actors_initialize( diff --git a/source/ai/ai.c b/source/ai/ai.c index 9b178624..bee7eaa7 100644 --- a/source/ai/ai.c +++ b/source/ai/ai.c @@ -215,6 +215,7 @@ symbols in this file: #include "ai/actions.h" #include "ai/actors.h" +#include "ai/ai_globals.h" #include "ai/encounters.h" #include "ai/path.h" #include "ai/props.h" @@ -330,38 +331,6 @@ enum /* ---------- structures */ -struct ai_spatial_effect -{ - short type; - short count; - real_point3d position; - long last_tick; -}; - -struct ai_globals_data -{ - boolean ai_active; - boolean ai_initialized_for_map; - boolean ai_has_control_data; - byte reserved003[0x5]; - long first_encounterless_actor_index; - real major_upgrade_error; - boolean dialogue_triggers_enabled; - byte reserved011[0x3]; - long last_chatter_time[NUMBER_OF_AI_SPEECH_TIMERS]; - long last_talk_time[NUMBER_OF_AI_SPEECH_TIMERS]; - long last_shout_time[NUMBER_OF_AI_SPEECH_TIMERS]; - byte reserved02C[0x104]; - short spatial_effect_first_index; - short spatial_effect_last_index; - struct ai_spatial_effect spatial_effects[MAXIMUM_AI_SPATIAL_EFFECTS]; - boolean grenades_enabled; - byte reserved3B5[0x503]; - short mounted_weapon_unit_count; - byte reserved8BA[0x2]; - long mounted_weapon_unit_indices[MAXIMUM_NUMBER_OF_MOUNTED_WEAPON_UNITS]; -}; - struct potentially_releasable_entity { boolean is_actor; @@ -414,25 +383,25 @@ struct encounter_iterator }; typedef char ai_globals_active_offset_assert[ - offsetof(struct ai_globals_data, ai_active) == 0x0 ? 1 : -1]; + offsetof(struct ai_globals, ai_active) == 0x0 ? 1 : -1]; typedef char ai_globals_initialized_offset_assert[ - offsetof(struct ai_globals_data, ai_initialized_for_map) == 0x1 ? 1 : -1]; + offsetof(struct ai_globals, ai_initialized_for_map) == 0x1 ? 1 : -1]; typedef char ai_globals_first_encounterless_actor_offset_assert[ - offsetof(struct ai_globals_data, first_encounterless_actor_index) == 0x8 ? 1 : -1]; + offsetof(struct ai_globals, first_encounterless_actor_index) == 0x8 ? 1 : -1]; typedef char ai_globals_dialogue_offset_assert[ - offsetof(struct ai_globals_data, dialogue_triggers_enabled) == 0x10 ? 1 : -1]; + offsetof(struct ai_globals, dialogue_triggers_enabled) == 0x10 ? 1 : -1]; typedef char ai_globals_last_chatter_time_offset_assert[ - offsetof(struct ai_globals_data, last_chatter_time) == 0x14 ? 1 : -1]; + offsetof(struct ai_globals, last_chatter_time) == 0x14 ? 1 : -1]; typedef char ai_globals_spatial_effects_offset_assert[ - offsetof(struct ai_globals_data, spatial_effects) == 0x134 ? 1 : -1]; + offsetof(struct ai_globals, spatial_effects) == 0x134 ? 1 : -1]; typedef char ai_spatial_effect_size_assert[ sizeof(struct ai_spatial_effect) == 0x14 ? 1 : -1]; typedef char ai_globals_grenades_offset_assert[ - offsetof(struct ai_globals_data, grenades_enabled) == 0x3B4 ? 1 : -1]; + offsetof(struct ai_globals, grenades_enabled) == 0x3B4 ? 1 : -1]; typedef char ai_globals_mounted_weapon_count_offset_assert[ - offsetof(struct ai_globals_data, mounted_weapon_unit_count) == 0x8B8 ? 1 : -1]; + offsetof(struct ai_globals, mounted_weapon_unit_count) == 0x8B8 ? 1 : -1]; typedef char ai_globals_size_assert[ - sizeof(struct ai_globals_data) == 0x8DC ? 1 : -1]; + sizeof(struct ai_globals) == 0x8DC ? 1 : -1]; typedef char ai_potentially_releasable_storage_size_assert[ sizeof(struct potentially_releasable_storage) == 0xC04 ? 1 : -1]; typedef char ai_unit_actor_index_offset_assert[ @@ -502,8 +471,6 @@ static void ai_flush_spatial_effects( /* ---------- globals */ -extern struct ai_globals_data *ai_globals; - static struct profile_section ai_update_section = { "ai_update", NONE, TRUE }; static char *ai_sound_volume_enum_strings[NUMBER_OF_AI_SOUND_VOLUMES] = @@ -527,10 +494,10 @@ struct tag_enum_definition ai_sound_volume_enum = void ai_initialize( void) { - ai_globals = game_state_malloc("ai globals", NULL, sizeof(struct ai_globals_data)); + ai_globals = game_state_malloc("ai globals", NULL, sizeof(struct ai_globals)); match_assert("c:\\halo\\SOURCE\\ai\\ai.c", 0x8C, ai_globals); - csmemset(ai_globals, 0, sizeof(struct ai_globals_data)); + csmemset(ai_globals, 0, sizeof(struct ai_globals)); ai_debug_initialize(); ai_profile_initialize(); @@ -1581,8 +1548,8 @@ void ai_handle_exit_vehicle( static void ai_flush_spatial_effects( void) { - ai_globals->spatial_effect_last_index = 0; - ai_globals->spatial_effect_first_index = 0; + ai_globals->spatial_effects_last_index = 0; + ai_globals->spatial_effects_first_index = 0; csmemset( ai_globals->spatial_effects, 0, @@ -1929,7 +1896,7 @@ boolean ai_consider_major_upgrade( void ai_initialize_for_new_map( void) { - csmemset(ai_globals, 0, sizeof(struct ai_globals_data)); + csmemset(ai_globals, 0, sizeof(struct ai_globals)); ai_globals->ai_active = TRUE; ai_globals->ai_has_control_data = TRUE; @@ -2546,16 +2513,16 @@ finish: boolean ai_test_ballistic_line_of_fire( long actor_index, real_point3d const *origin, - real ticks, - real_vector3d const *velocity, - real gravity, + real arc_time, + real_vector3d const *arc_initial_velocity, + real arc_acceleration, long ignore_object_index, - boolean in_vehicle) + boolean ignore_vehicles) { - struct line_of_fire_pill pills[MAXIMUM_LINE_OF_FIRE_PILLS]; + struct line_of_fire_pill friend_pills[MAXIMUM_LINE_OF_FIRE_PILLS]; struct collision_result collision; struct actor_datum *actor = actor_get(actor_index); - real_point3d point; + real_point3d current_point; real_point3d end_point; real_vector3d arc_velocity; real segment_start_time; @@ -2572,13 +2539,13 @@ boolean ai_test_ballistic_line_of_fire( pill_count = ai_find_line_of_fire_friend_pills( actor_index, MAXIMUM_LINE_OF_FIRE_PILLS, - pills); + friend_pills); if (!ai_debug.ballistic_lineoffire_freeze) { ai_debug.ballistic_lineoffire_valid = TRUE; ai_debug.ballistic_lineoffire_start = *origin; - ai_debug.ballistic_lineoffire_vector = *velocity; + ai_debug.ballistic_lineoffire_vector = *arc_initial_velocity; ai_debug.ballistic_lineoffire_point_count = 0; ai_debug.ballistic_lineoffire_pill_count = MIN( pill_count, @@ -2588,9 +2555,9 @@ boolean ai_test_ballistic_line_of_fire( pill_index < ai_debug.ballistic_lineoffire_pill_count; pill_index++) { - ai_debug.ballistic_lineoffire_pill_start[pill_index] = pills[pill_index].base; - ai_debug.ballistic_lineoffire_pill_end[pill_index] = pills[pill_index].directed_height; - ai_debug.ballistic_lineoffire_pill_radius[pill_index] = pills[pill_index].width; + ai_debug.ballistic_lineoffire_pill_start[pill_index] = friend_pills[pill_index].base; + ai_debug.ballistic_lineoffire_pill_end[pill_index] = friend_pills[pill_index].directed_height; + ai_debug.ballistic_lineoffire_pill_radius[pill_index] = friend_pills[pill_index].width; } } @@ -2602,39 +2569,39 @@ boolean ai_test_ballistic_line_of_fire( FLAG(_collision_test_objects_bit) | _collision_test_objects_sight_blocking_flags; - if (in_vehicle) + if (ignore_vehicles) collision_flags &= ~FLAG(_collision_test_objects_vehicles_bit); - point = *origin; - arc_velocity = *velocity; + current_point = *origin; + arc_velocity = *arc_initial_velocity; segment_start_time = 0.0f; - segment_end_time = MIN(6.0f, ticks); + segment_end_time = MIN(6.0f, arc_time); do { if (!ai_debug.ballistic_lineoffire_freeze && ai_debug.ballistic_lineoffire_point_count < MAXIMUM_AI_DEBUG_BALLISTIC_POINTS) { - ai_debug.ballistic_lineoffire_point[ai_debug.ballistic_lineoffire_point_count] = point; + ai_debug.ballistic_lineoffire_point[ai_debug.ballistic_lineoffire_point_count] = current_point; ai_debug.ballistic_lineoffire_point_count++; } { real segment_time = segment_end_time - segment_start_time; - end_point.x = arc_velocity.i * segment_time + point.x; - end_point.y = arc_velocity.j * segment_time + point.y; - end_point.z = (segment_time * arc_velocity.k + point.z) + - (segment_time * segment_time) * gravity * 0.5f; + end_point.x = arc_velocity.i * segment_time + current_point.x; + end_point.y = arc_velocity.j * segment_time + current_point.y; + end_point.z = (segment_time * arc_velocity.k + current_point.z) + + (segment_time * segment_time) * arc_acceleration * 0.5f; } { real_vector3d segment_vector; - vector_from_points3d(&point, &end_point, &segment_vector); + vector_from_points3d(¤t_point, &end_point, &segment_vector); line_of_fire = !collision_test_vector( collision_flags, - &point, + ¤t_point, &segment_vector, ignore_object_index, &collision); @@ -2646,16 +2613,16 @@ boolean ai_test_ballistic_line_of_fire( { real_vector3d segment_vector; - vector_from_points3d(&point, &end_point, &segment_vector); + vector_from_points3d(¤t_point, &end_point, &segment_vector); for (pill_index = 0; pill_index < pill_count; pill_index++) { boolean intersected = vector_intersects_pill3d( - &point, + ¤t_point, &segment_vector, - &pills[pill_index].base, - &pills[pill_index].directed_height, - pills[pill_index].width); + &friend_pills[pill_index].base, + &friend_pills[pill_index].directed_height, + friend_pills[pill_index].width); if (intersected) { @@ -2668,15 +2635,15 @@ boolean ai_test_ballistic_line_of_fire( if (!line_of_fire) break; - point = end_point; - arc_velocity.k = (segment_end_time - segment_start_time) * gravity + arc_velocity.k; + current_point = end_point; + arc_velocity.k = (segment_end_time - segment_start_time) * arc_acceleration + arc_velocity.k; segment_start_time = segment_end_time; segment_end_time += 6.0f; - if (segment_end_time > ticks) - segment_end_time = ticks; + if (segment_end_time > arc_time) + segment_end_time = arc_time; } - while (segment_start_time < ticks); + while (segment_start_time < arc_time); if (!ai_debug.ballistic_lineoffire_freeze && ai_debug.ballistic_lineoffire_point_count < MAXIMUM_AI_DEBUG_BALLISTIC_POINTS) @@ -2937,8 +2904,8 @@ void ai_handle_spatial_effect( submit = TRUE; available_effect_index = NONE; - for (i = ai_globals->spatial_effect_first_index; - i != ai_globals->spatial_effect_last_index; + for (i = ai_globals->spatial_effects_first_index; + i != ai_globals->spatial_effects_last_index; i = AI_SPATIAL_EFFECT_NEXT_INDEX(i)) { boolean matches = FALSE; @@ -2955,9 +2922,9 @@ void ai_handle_spatial_effect( { ai_globals->spatial_effects[i].type = NONE; - if (i == ai_globals->spatial_effect_first_index) + if (i == ai_globals->spatial_effects_first_index) { - ai_globals->spatial_effect_first_index = + ai_globals->spatial_effects_first_index = AI_SPATIAL_EFFECT_NEXT_INDEX(i); } else @@ -2994,15 +2961,15 @@ void ai_handle_spatial_effect( { if (available_effect_index == NONE) { - i = ai_globals->spatial_effect_last_index; - ai_globals->spatial_effect_last_index = - AI_SPATIAL_EFFECT_NEXT_INDEX(ai_globals->spatial_effect_last_index); + i = ai_globals->spatial_effects_last_index; + ai_globals->spatial_effects_last_index = + AI_SPATIAL_EFFECT_NEXT_INDEX(ai_globals->spatial_effects_last_index); - if (ai_globals->spatial_effect_last_index == - ai_globals->spatial_effect_first_index) + if (ai_globals->spatial_effects_last_index == + ai_globals->spatial_effects_first_index) { - ai_globals->spatial_effect_first_index = - AI_SPATIAL_EFFECT_NEXT_INDEX(ai_globals->spatial_effect_first_index); + ai_globals->spatial_effects_first_index = + AI_SPATIAL_EFFECT_NEXT_INDEX(ai_globals->spatial_effects_first_index); } } else @@ -3012,10 +2979,10 @@ void ai_handle_spatial_effect( { short distance_to_effect = - (i - ai_globals->spatial_effect_first_index + MAXIMUM_AI_SPATIAL_EFFECTS) & + (i - ai_globals->spatial_effects_first_index + MAXIMUM_AI_SPATIAL_EFFECTS) & (MAXIMUM_AI_SPATIAL_EFFECTS - 1); short distance_to_end_of_queue = - (ai_globals->spatial_effect_last_index - ai_globals->spatial_effect_first_index + + (ai_globals->spatial_effects_last_index - ai_globals->spatial_effects_first_index + MAXIMUM_AI_SPATIAL_EFFECTS) & (MAXIMUM_AI_SPATIAL_EFFECTS - 1); diff --git a/source/ai/ai.h b/source/ai/ai.h index 924cccd3..be7cdfa1 100644 --- a/source/ai/ai.h +++ b/source/ai/ai.h @@ -172,11 +172,11 @@ void ai_handle_allegiance_broken_notification( boolean ai_test_ballistic_line_of_fire( long actor_index, union real_point3d const *origin, - real ticks, - union real_vector3d const *velocity, - real gravity, + real arc_time, + union real_vector3d const *arc_initial_velocity, + real arc_acceleration, long ignore_object_index, - boolean in_vehicle); + boolean ignore_vehicles); boolean ai_test_line_of_fire( long actor_index, long ignore_unit_index, diff --git a/source/ai/ai_communication.c b/source/ai/ai_communication.c index 54692247..4947c6f4 100644 --- a/source/ai/ai_communication.c +++ b/source/ai/ai_communication.c @@ -552,6 +552,7 @@ symbols in this file: #include "actor_definitions.h" #include "actors.h" #include "actor_types.h" +#include "ai/ai_globals.h" #include "ai_scenario_definitions.h" #include "cseries/errors.h" #include "encounters.h" @@ -669,7 +670,7 @@ enum #define ai_print_conversations (ai_debug.print_conversations) #define ai_conversation_driver_get(index) \ - ((struct ai_conversation_driver_datum_view *)datum_get(conversation_data, (index))) + ((struct conversation_datum *)datum_get(conversation_data, (index))) /* ---------- structures */ @@ -720,78 +721,8 @@ typedef char dialogue_usage_size_assert[ typedef char reply_usage_size_assert[ sizeof(struct reply_usage) == 0x24 ? 1 : -1]; -struct ai_conversation_line_view -{ - struct ai_conversation_datum_header header; - byte __unknown14[0x34]; - short current_line; -}; - typedef char ai_conversation_line_view_current_line_offset_assert[ - offsetof(struct ai_conversation_line_view, current_line) == 0x48 ? 1 : -1]; - -struct ai_conversation_driver_datum_view -{ - struct ai_conversation_datum_header header; - unsigned long participant_bitmask; - short dialogue_indices[MAXIMUM_PARTICIPANTS_PER_CONVERSATION]; - long actor_indices[MAXIMUM_PARTICIPANTS_PER_CONVERSATION]; - short current_line; - short line_participant_index; - short line_delay_timer; - word line_flags; - long line_actor_index; - long line_unit_index; - long line_address_unit_index; - long line_sound_index; - boolean line_unspatialized; - boolean line_spoken; - boolean line_finished; - boolean line_advance; -}; - -struct ai_conversation_datum_view -{ - short identifier; - short scenario_conversation_index; - boolean scripted; - boolean any_line_spoken; - boolean begun; - boolean finished; - boolean waiting_to_advance; - boolean told_to_advance; - byte reserved0A[2]; - long creation_time; - long triggering_player_unit_index; - unsigned long participant_bitmask; - short dialogue_indices[MAXIMUM_PARTICIPANTS_PER_CONVERSATION]; - long actor_indices[MAXIMUM_PARTICIPANTS_PER_CONVERSATION]; - short line_index; - short line_participant_index; - short line_delay_timer; - word line_flags; - long line_actor_index; - long line_unit_index; - long line_address_unit_index; - long line_sound_index; - boolean line_unspatialized; - boolean line_spoken; - boolean line_finished; - boolean line_advance; -}; - -struct scenario_conversation_definition_view -{ - char name[32]; - word flags; - word pad22; - real trigger_distance; - real run_to_player_distance; - byte __unknown2C[0x24]; - struct tag_block participants; - struct tag_block lines; - struct tag_block unused; -}; + offsetof(struct conversation_datum, line_index) == 0x48 ? 1 : -1]; struct scenario_conversation_participant_view { @@ -820,15 +751,6 @@ struct scenario_conversation_line_view struct tag_reference dialogue[MAXIMUM_DIALOGUE_VARIANTS_PER_CONVERSATION_PARTICIPANT]; }; -struct recent_conversation_view -{ - short scenario_conversation_index; - boolean unable_to_begin; - boolean finished_successfully; - long finish_time; - byte __unknown08[8]; -}; - struct dialogue_event_status { long last_time_spoken; @@ -867,20 +789,6 @@ struct ai_communication_possibility typedef char ai_communication_possibility_size_assert[ sizeof(struct ai_communication_possibility) == 0x38 ? 1 : -1]; -struct ai_communication_globals_view -{ - byte __unknown00[0x10]; - boolean dialogue_triggers_enabled; - byte __unknown11[3]; - long last_chatter_time[2]; - long last_talk_time[2]; - long last_shout_time[2]; - short recent_conversation_count; - short recent_conversation_next_index; - struct recent_conversation_view - recent_conversations[MAXIMUM_RECENT_CONVERSATIONS]; -}; - struct actor_iterator { struct data_iterator encounter_iterator; @@ -891,46 +799,44 @@ struct actor_iterator long next_index; }; -typedef char ai_conversation_datum_header_size_assert[ - sizeof(struct ai_conversation_datum_header) == 0x14 ? 1 : -1]; typedef char ai_conversation_datum_view_size_assert[ - sizeof(struct ai_conversation_datum_view) == 0x64 ? 1 : -1]; + sizeof(struct conversation_datum) == 0x64 ? 1 : -1]; typedef char ai_conversation_datum_view_line_index_offset_assert[ - offsetof(struct ai_conversation_datum_view, line_index) == 0x48 ? 1 : -1]; + offsetof(struct conversation_datum, line_index) == 0x48 ? 1 : -1]; typedef char ai_conversation_datum_view_line_advance_offset_assert[ - offsetof(struct ai_conversation_datum_view, line_advance) == 0x63 ? 1 : -1]; + offsetof(struct conversation_datum, line_advance) == 0x63 ? 1 : -1]; typedef char ai_conversation_datum_header_any_line_spoken_offset_assert[ - offsetof(struct ai_conversation_datum_header, any_line_spoken) == 0x5 ? 1 : -1]; + offsetof(struct conversation_datum, any_line_spoken) == 0x5 ? 1 : -1]; typedef char ai_conversation_datum_header_begun_offset_assert[ - offsetof(struct ai_conversation_datum_header, begun) == 0x6 ? 1 : -1]; + offsetof(struct conversation_datum, begun) == 0x6 ? 1 : -1]; typedef char ai_conversation_datum_header_waiting_to_advance_offset_assert[ - offsetof(struct ai_conversation_datum_header, waiting_to_advance) == 0x8 ? 1 : -1]; + offsetof(struct conversation_datum, waiting_to_advance) == 0x8 ? 1 : -1]; typedef char ai_conversation_datum_header_told_to_advance_offset_assert[ - offsetof(struct ai_conversation_datum_header, told_to_advance) == 0x9 ? 1 : -1]; + offsetof(struct conversation_datum, told_to_advance) == 0x9 ? 1 : -1]; typedef char scenario_conversation_definition_view_size_assert[ - sizeof(struct scenario_conversation_definition_view) == 0x74 ? 1 : -1]; + sizeof(struct ai_conversation) == 0x74 ? 1 : -1]; typedef char scenario_conversation_definition_participants_offset_assert[ - offsetof(struct scenario_conversation_definition_view, participants) == 0x50 ? 1 : -1]; + offsetof(struct ai_conversation, participants) == 0x50 ? 1 : -1]; typedef char scenario_conversation_definition_lines_offset_assert[ - offsetof(struct scenario_conversation_definition_view, lines) == 0x5C ? 1 : -1]; + offsetof(struct ai_conversation, lines) == 0x5C ? 1 : -1]; typedef char scenario_conversation_participant_view_size_assert[ sizeof(struct scenario_conversation_participant_view) == 0x54 ? 1 : -1]; typedef char scenario_conversation_line_view_size_assert[ sizeof(struct scenario_conversation_line_view) == 0x7C ? 1 : -1]; typedef char ai_conversation_driver_datum_view_size_assert[ - sizeof(struct ai_conversation_driver_datum_view) == 0x64 ? 1 : -1]; + sizeof(struct conversation_datum) == 0x64 ? 1 : -1]; typedef char ai_conversation_driver_participant_bitmask_offset_assert[ - offsetof(struct ai_conversation_driver_datum_view, participant_bitmask) == 0x14 ? 1 : -1]; + offsetof(struct conversation_datum, participant_bitmask) == 0x14 ? 1 : -1]; typedef char ai_conversation_driver_actor_indices_offset_assert[ - offsetof(struct ai_conversation_driver_datum_view, actor_indices) == 0x28 ? 1 : -1]; + offsetof(struct conversation_datum, actor_indices) == 0x28 ? 1 : -1]; typedef char ai_conversation_driver_line_flags_offset_assert[ - offsetof(struct ai_conversation_driver_datum_view, line_flags) == 0x4E ? 1 : -1]; + offsetof(struct conversation_datum, line_flags) == 0x4E ? 1 : -1]; typedef char ai_conversation_driver_line_unit_index_offset_assert[ - offsetof(struct ai_conversation_driver_datum_view, line_unit_index) == 0x54 ? 1 : -1]; + offsetof(struct conversation_datum, line_unit_index) == 0x54 ? 1 : -1]; typedef char ai_conversation_driver_line_address_unit_index_offset_assert[ - offsetof(struct ai_conversation_driver_datum_view, line_address_unit_index) == 0x58 ? 1 : -1]; + offsetof(struct conversation_datum, line_address_unit_index) == 0x58 ? 1 : -1]; typedef char recent_conversation_view_size_assert[ - sizeof(struct recent_conversation_view) == 0x10 ? 1 : -1]; + sizeof(struct recent_conversation) == 0x10 ? 1 : -1]; typedef char ai_print_conversations_offset_assert[ offsetof(struct ai_debug_state, print_conversations) == 0x9F ? 1 : -1]; typedef char ai_communication_unit_speech_item_size_assert[ @@ -1006,9 +912,9 @@ static real ai_communication_actor_talk_weight( long cause_unit_index, real_point3d const *cause_point, real stimulus_range, - short communication_type, - short communication_priority, - short speech_priority, + short ai_communication_type, + short ai_communication_priority, + short unit_speech_priority, short vocalization_type, short animation_type, short flags); @@ -1083,8 +989,6 @@ static long ai_communication_find_actor_to_reply_to_player( short damage_category, real *reply_rating_reference); -extern short global_communication_table_indices[NUMBER_OF_COMMUNICATION_TYPES]; -extern struct ai_communication_globals_view *ai_globals; static long ai_conversation_new( short scenario_conversation_index, boolean scripted); @@ -1625,6 +1529,7 @@ short global_dialogue_event_count = 0; struct dialogue_event_status *global_dialogue_events = NULL; short global_reply_event_count = 0; struct dialogue_event_status *global_reply_events = NULL; +short global_communication_table_indices[NUMBER_OF_COMMUNICATION_TYPES]; /* ---------- public code */ @@ -2146,9 +2051,9 @@ static real ai_communication_actor_talk_weight( long cause_unit_index, real_point3d const *cause_point, real stimulus_range, - short communication_type, - short communication_priority, - short speech_priority, + short ai_communication_type, + short ai_communication_priority, + short unit_speech_priority, short vocalization_type, short animation_type, short flags) @@ -2251,17 +2156,17 @@ static real ai_communication_actor_talk_weight( if (vocalization_type != NONE) { - short line_vocalization_type = vocalization_type; + short vocalization_lookup_type = vocalization_type; long sound_definition_index = NONE; if (ai_communication_consider_speech( actor->meta.unit_index, - communication_priority, - speech_priority, + ai_communication_priority, + unit_speech_priority, 0, TEST_FLAG(flags, _find_actor_allow_lookup_bit), TRUE, - &line_vocalization_type, + &vocalization_lookup_type, &weight, &sound_definition_index, NULL) == _unit_play_speech_none) @@ -2316,7 +2221,7 @@ static real ai_communication_actor_talk_weight( } else if (!prop->enemy) { - if (communication_type != 0) + if (ai_communication_type != 0) { subject_matches = TRUE; } @@ -2667,11 +2572,11 @@ short ai_conversation_status( short scenario_conversation_index) { struct data_iterator iterator; - struct ai_conversation_datum_header *conversation; + struct conversation_datum *conversation; short status = 0; data_iterator_new(&iterator, conversation_data); - while ((conversation = (struct ai_conversation_datum_header *) + while ((conversation = (struct conversation_datum *) data_iterator_next(&iterator)) != NULL) { if (conversation->scenario_conversation_index == scenario_conversation_index) @@ -2697,7 +2602,7 @@ short ai_conversation_status( if (!status) { - struct recent_conversation_view *recent_conversation; + struct recent_conversation *recent_conversation; long latest_finish_time = NONE; short latest_index = NONE; short index; @@ -2788,15 +2693,15 @@ short ai_conversation_line( short scenario_conversation_index) { struct data_iterator iterator; - struct ai_conversation_line_view *conversation; + struct conversation_datum *conversation; short line = 999; data_iterator_new(&iterator, conversation_data); - while ((conversation = (struct ai_conversation_line_view *)data_iterator_next(&iterator)) != NULL) + while ((conversation = (struct conversation_datum *)data_iterator_next(&iterator)) != NULL) { - if (conversation->header.scenario_conversation_index == scenario_conversation_index) + if (conversation->scenario_conversation_index == scenario_conversation_index) { - line = conversation->current_line; + line = conversation->line_index; break; } } @@ -2808,21 +2713,21 @@ void ai_conversation_advance( short scenario_conversation_index) { struct data_iterator iterator; - struct ai_conversation_datum_header *conversation; + struct conversation_datum *conversation; data_iterator_new(&iterator, conversation_data); - while ((conversation = (struct ai_conversation_datum_header *) + while ((conversation = (struct conversation_datum *) data_iterator_next(&iterator)) != NULL) { if (conversation->scenario_conversation_index == scenario_conversation_index) { if (ai_print_conversations) { - struct scenario_conversation_definition_view *definition = + struct ai_conversation *definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view); + struct ai_conversation); console_printf( FALSE, @@ -2842,9 +2747,9 @@ void ai_conversation_finish( boolean unable_to_begin, boolean success) { - struct ai_conversation_datum_view *conversation; - struct ai_conversation_datum_view *recent_conversation; - struct scenario_conversation_definition_view *definition; + struct conversation_datum *conversation; + struct conversation_datum *recent_conversation; + struct ai_conversation *definition; struct actor_datum *actor; short recent_conversation_index; long recent_conversation_count; @@ -2854,13 +2759,13 @@ void ai_conversation_finish( if (conversation_index != NONE) { - conversation = (struct ai_conversation_datum_view *)datum_get( + conversation = (struct conversation_datum *)datum_get( conversation_data, conversation_index); definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, conversation->scenario_conversation_index, - struct scenario_conversation_definition_view); + struct ai_conversation); if (ai_print_conversations) { @@ -2872,7 +2777,7 @@ void ai_conversation_finish( unable_to_begin ? " (unable to begin)" : ""); } - recent_conversation = (struct ai_conversation_datum_view *)datum_get( + recent_conversation = (struct conversation_datum *)datum_get( conversation_data, conversation_index); recent_conversation_index = @@ -3096,21 +3001,21 @@ void ai_conversation_stop( short scenario_conversation_index) { struct data_iterator iterator; - struct ai_conversation_datum_header *conversation; + struct conversation_datum *conversation; data_iterator_new(&iterator, conversation_data); - while ((conversation = (struct ai_conversation_datum_header *) + while ((conversation = (struct conversation_datum *) data_iterator_next(&iterator)) != NULL) { if (conversation->scenario_conversation_index == scenario_conversation_index) { if (ai_print_conversations) { - struct scenario_conversation_definition_view *definition = + struct ai_conversation *definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view); + struct ai_conversation); console_printf( FALSE, @@ -3347,13 +3252,13 @@ static boolean ai_conversation_find_participant( boolean *success_with_better_player_rating_reference, real *best_distance_reference) { - struct ai_conversation_driver_datum_view *conversation = + struct conversation_datum *conversation = ai_conversation_driver_get(conversation_index); - struct scenario_conversation_definition_view *conversation_definition = + struct ai_conversation *conversation_definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, - conversation->header.scenario_conversation_index, - struct scenario_conversation_definition_view); + conversation->scenario_conversation_index, + struct ai_conversation); struct scenario_conversation_participant_view *participant = TAG_BLOCK_GET_ELEMENT( &conversation_definition->participants, @@ -3584,7 +3489,7 @@ static boolean ai_conversation_find_participant( if (first_participant && !player_selection && player_rating < 2.0f && - conversation_definition->run_to_player_distance == 0.0f) + conversation_definition->run_to_player_dist == 0.0f) { rejection_counts[5]++; better_player_rating_found = TRUE; @@ -4069,13 +3974,13 @@ static boolean ai_conversation_begin( long conversation_index, boolean *continue_trying) { - struct ai_conversation_driver_datum_view *conversation = + struct conversation_datum *conversation = ai_conversation_driver_get(conversation_index); - struct scenario_conversation_definition_view *definition = + struct ai_conversation *definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, - conversation->header.scenario_conversation_index, - struct scenario_conversation_definition_view); + conversation->scenario_conversation_index, + struct ai_conversation); unsigned long better_player_rating_mask = 0; boolean try_alternate = FALSE; boolean found_alternate = FALSE; @@ -4262,7 +4167,7 @@ static boolean ai_conversation_begin( can_begin = FALSE; } - conversation->header.triggering_player_unit_index = NONE; + conversation->triggering_player_unit_index = NONE; if (can_begin && TEST_FLAG(definition->flags, _ai_conversation_player_must_be_visible_bit)) { @@ -4312,14 +4217,14 @@ static boolean ai_conversation_begin( if (nearest_prop_distance < nearest_player_distance) { - conversation->header.triggering_player_unit_index = + conversation->triggering_player_unit_index = player->unit_index; nearest_player_distance = nearest_prop_distance; } } } - if (conversation->header.triggering_player_unit_index == NONE) + if (conversation->triggering_player_unit_index == NONE) { if (ai_print_conversations) { @@ -4461,7 +4366,7 @@ static boolean ai_conversation_begin( } } - conversation->header.begun = TRUE; + conversation->begun = TRUE; } else { @@ -5082,19 +4987,19 @@ void ai_conversation_actor_deleted( long actor_index) { struct data_iterator iterator; - struct ai_conversation_datum_view *conversation; - struct scenario_conversation_definition_view *definition; + struct conversation_datum *conversation; + struct ai_conversation *definition; short participant_index; data_iterator_new(&iterator, conversation_data); - conversation = (struct ai_conversation_datum_view *) + conversation = (struct conversation_datum *) data_iterator_next(&iterator); while (conversation != NULL) { definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, conversation->scenario_conversation_index, - struct scenario_conversation_definition_view); + struct ai_conversation); participant_index = 0; while ((long)participant_index < definition->participants.count) { @@ -5121,7 +5026,7 @@ void ai_conversation_actor_deleted( participant_index = (short)(participant_index + 1); } - conversation = (struct ai_conversation_datum_view *) + conversation = (struct conversation_datum *) data_iterator_next(&iterator); } @@ -5134,13 +5039,13 @@ void ai_conversation_unit_died( { struct data_iterator iterator; short participant_index; - struct ai_conversation_datum_view *conversation; - struct scenario_conversation_definition_view *definition; + struct conversation_datum *conversation; + struct ai_conversation *definition; struct actor_datum *actor; boolean referenced; data_iterator_new(&iterator, conversation_data); - conversation = (struct ai_conversation_datum_view *) + conversation = (struct conversation_datum *) data_iterator_next(&iterator); if (conversation == NULL) { @@ -5151,7 +5056,7 @@ void ai_conversation_unit_died( definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, conversation->scenario_conversation_index, - struct scenario_conversation_definition_view); + struct ai_conversation); referenced = FALSE; if (conversation->line_unit_index == unit_index) @@ -5218,7 +5123,7 @@ void ai_conversation_unit_died( } } - conversation = (struct ai_conversation_datum_view *) + conversation = (struct conversation_datum *) data_iterator_next(&iterator); if (conversation == NULL) { @@ -5242,7 +5147,7 @@ static long ai_conversation_new( boolean scripted) { struct data_iterator iterator; - struct ai_conversation_datum_view *conversation; + struct conversation_datum *conversation; long conversation_index = datum_new(conversation_data); if (conversation_index == NONE && scripted) @@ -5252,7 +5157,7 @@ static long ai_conversation_new( long overwrite_conversation_index = NONE; data_iterator_new(&iterator, conversation_data); - while ((conversation = (struct ai_conversation_datum_view *) + while ((conversation = (struct conversation_datum *) data_iterator_next(&iterator)) != NULL) { if (conversation->scripted < overwrite_scripted || @@ -5268,11 +5173,11 @@ static long ai_conversation_new( { if (ai_print_conversations) { - struct scenario_conversation_definition_view *definition = + struct ai_conversation *definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view); + struct ai_conversation); console_printf( FALSE, @@ -5292,7 +5197,7 @@ static long ai_conversation_new( if (conversation_index != NONE) { - conversation = (struct ai_conversation_datum_view *)datum_get( + conversation = (struct conversation_datum *)datum_get( conversation_data, conversation_index); conversation->scenario_conversation_index = scenario_conversation_index; @@ -5307,8 +5212,8 @@ static long ai_conversation_new( static boolean ai_conversation_line_begin( long conversation_index) { - struct ai_conversation_driver_datum_view *conversation; - struct scenario_conversation_definition_view *definition; + struct conversation_datum *conversation; + struct ai_conversation *definition; struct scenario_conversation_participant_view *participant; struct scenario_conversation_line_view *line; struct actor_datum *actor; @@ -5319,11 +5224,11 @@ static boolean ai_conversation_line_begin( conversation = ai_conversation_driver_get(conversation_index); definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, - conversation->header.scenario_conversation_index, - struct scenario_conversation_definition_view); + conversation->scenario_conversation_index, + struct ai_conversation); line = TAG_BLOCK_GET_ELEMENT( &definition->lines, - conversation->current_line, + conversation->line_index, struct scenario_conversation_line_view); participant_index = line->participant_index; result = FALSE; @@ -5356,7 +5261,7 @@ static boolean ai_conversation_line_begin( { case _ai_conversation_address_player: conversation->line_address_unit_index = - conversation->header.triggering_player_unit_index; + conversation->triggering_player_unit_index; break; case _ai_conversation_address_participant: @@ -5399,8 +5304,8 @@ static boolean ai_conversation_line_begin( static boolean ai_conversation_line_perform( long conversation_index) { - struct ai_conversation_driver_datum_view *conversation; - struct scenario_conversation_definition_view *definition; + struct conversation_datum *conversation; + struct ai_conversation *definition; struct actor_datum *actor; struct unit_datum *unit; long sound_definition_index; @@ -5417,8 +5322,8 @@ static boolean ai_conversation_line_perform( conversation = ai_conversation_driver_get(conversation_index); definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, - conversation->header.scenario_conversation_index, - struct scenario_conversation_definition_view); + conversation->scenario_conversation_index, + struct ai_conversation); if (!conversation->line_advance) { if (!conversation->line_spoken) @@ -5533,7 +5438,7 @@ static boolean ai_conversation_line_perform( if (!busy) { conversation->line_spoken = TRUE; - conversation->header.any_line_spoken = TRUE; + conversation->any_line_spoken = TRUE; } } @@ -5570,15 +5475,15 @@ static boolean ai_conversation_line_perform( if ((conversation->line_flags & FLAG( _ai_conversation_line_wait_after_until_told_to_advance_bit)) != 0) { - if (!conversation->header.waiting_to_advance) + if (!conversation->waiting_to_advance) { - conversation->header.waiting_to_advance = TRUE; - conversation->header.told_to_advance = FALSE; + conversation->waiting_to_advance = TRUE; + conversation->told_to_advance = FALSE; } - if (conversation->header.told_to_advance) + if (conversation->told_to_advance) { - conversation->header.waiting_to_advance = FALSE; + conversation->waiting_to_advance = FALSE; } else { @@ -5595,13 +5500,13 @@ static boolean ai_conversation_line_perform( static void ai_conversation_line_end( long conversation_index) { - struct ai_conversation_driver_datum_view *conversation; + struct conversation_datum *conversation; conversation = ai_conversation_driver_get(conversation_index); TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, - conversation->header.scenario_conversation_index, - struct scenario_conversation_definition_view); + conversation->scenario_conversation_index, + struct ai_conversation); return; } @@ -5629,7 +5534,7 @@ boolean ai_conversation( TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view)->name); + struct ai_conversation)->name); } if (conversation_index == NONE) @@ -5654,7 +5559,7 @@ boolean ai_conversation( TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view)->name); + struct ai_conversation)->name); } result = TRUE; @@ -5669,7 +5574,7 @@ boolean ai_conversation( TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view)->name); + struct ai_conversation)->name); } result = TRUE; @@ -5684,7 +5589,7 @@ boolean ai_conversation( TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, scenario_conversation_index, - struct scenario_conversation_definition_view)->name); + struct ai_conversation)->name); } ai_conversation_finish(conversation_index, TRUE, FALSE); @@ -5699,26 +5604,26 @@ void ai_conversation_update( void) { struct data_iterator iterator; - struct ai_conversation_driver_datum_view *conversation; + struct conversation_datum *conversation; long time; time = game_time_get(); data_iterator_new(&iterator, conversation_data); - conversation = (struct ai_conversation_driver_datum_view *)data_iterator_next(&iterator); + conversation = (struct conversation_datum *)data_iterator_next(&iterator); while (conversation) { - struct scenario_conversation_definition_view *definition; + struct ai_conversation *definition; definition = TAG_BLOCK_GET_ELEMENT( &global_scenario_get()->ai_conversations, - conversation->header.scenario_conversation_index, - struct scenario_conversation_definition_view); - if (!conversation->header.begun) + conversation->scenario_conversation_index, + struct ai_conversation); + if (!conversation->begun) { boolean continue_trying; continue_trying = TRUE; - if ((time - conversation->header.creation_time) % 30 == 0) + if ((time - conversation->creation_time) % 30 == 0) { if (ai_print_conversations) { @@ -5731,7 +5636,7 @@ void ai_conversation_update( ai_conversation_begin(iterator.datum_index, &continue_trying); } - if (!conversation->header.begun && !continue_trying) + if (!conversation->begun && !continue_trying) { if (ai_print_conversations) { @@ -5745,12 +5650,12 @@ void ai_conversation_update( } } - if (conversation->header.begun && !conversation->header.finished) + if (conversation->begun && !conversation->finished) { boolean perform; - perform = conversation->current_line >= 0 && - conversation->current_line < definition->lines.count; + perform = conversation->line_index >= 0 && + conversation->line_index < definition->lines.count; while (!perform || ai_conversation_line_perform(iterator.datum_index)) { if (perform) @@ -5758,8 +5663,8 @@ void ai_conversation_update( ai_conversation_line_end(iterator.datum_index); } - conversation->current_line++; - if (conversation->current_line < definition->lines.count) + conversation->line_index++; + if (conversation->line_index < definition->lines.count) { perform = ai_conversation_line_begin(iterator.datum_index); } @@ -5773,17 +5678,17 @@ void ai_conversation_update( definition->name); } - conversation->header.finished = TRUE; + conversation->finished = TRUE; break; } } } - if (conversation->header.finished) + if (conversation->finished) { ai_conversation_finish(iterator.datum_index, FALSE, TRUE); } - else if (conversation->header.begun) + else if (conversation->begun) { short participant_index; @@ -5840,7 +5745,7 @@ void ai_conversation_update( } } - conversation = (struct ai_conversation_driver_datum_view *)data_iterator_next(&iterator); + conversation = (struct conversation_datum *)data_iterator_next(&iterator); } return; @@ -5880,13 +5785,13 @@ void ai_communication_event( short cause_race = 0; boolean find_friend_actor = TRUE; boolean find_other_actor = TRUE; - boolean subject_groups[2]; - boolean cause_groups[2]; - boolean enemy_status[6]; - boolean hostility_matches[NUMBER_OF_AI_COMMUNICATION_HOSTILITIES]; - short chatter_ticks[NUMBER_OF_AI_COMMUNICATION_TEAMS]; - short talk_ticks[NUMBER_OF_AI_COMMUNICATION_TEAMS]; - short shout_ticks[NUMBER_OF_AI_COMMUNICATION_TEAMS]; + boolean subject_comm_groups_enabled[2]; + boolean cause_comm_groups_enabled[2]; + boolean enemy_status_enabled[6]; + boolean hostility_enabled[NUMBER_OF_AI_COMMUNICATION_HOSTILITIES]; + short time_since_chatter[NUMBER_OF_AI_COMMUNICATION_TEAMS]; + short time_since_talk[NUMBER_OF_AI_COMMUNICATION_TEAMS]; + short time_since_shout[NUMBER_OF_AI_COMMUNICATION_TEAMS]; real chatter_seconds[NUMBER_OF_AI_COMMUNICATION_TEAMS]; real talk_seconds[NUMBER_OF_AI_COMMUNICATION_TEAMS]; real shout_seconds[NUMBER_OF_AI_COMMUNICATION_TEAMS]; @@ -5921,8 +5826,8 @@ void ai_communication_event( for (distance_group = 0; distance_group < 2; distance_group++) { - subject_groups[distance_group] = FALSE; - cause_groups[distance_group] = FALSE; + subject_comm_groups_enabled[distance_group] = FALSE; + cause_comm_groups_enabled[distance_group] = FALSE; } if (subject_unit_index != NONE) @@ -5939,13 +5844,13 @@ void ai_communication_event( subject_race = actor_type_get_race(subject_actor->meta.type); if (subject_actor->situation.close_friends > 0) { - subject_groups[0] = TRUE; - subject_groups[1] = TRUE; + subject_comm_groups_enabled[0] = TRUE; + subject_comm_groups_enabled[1] = TRUE; } else if (subject_actor->situation.area_friends > 0) { - subject_groups[0] = TRUE; - subject_groups[1] = FALSE; + subject_comm_groups_enabled[0] = TRUE; + subject_comm_groups_enabled[1] = FALSE; } if (subject_encounter_index != NONE) @@ -5972,13 +5877,13 @@ void ai_communication_event( cause_race = actor_type_get_race(cause_actor->meta.type); if (cause_actor->situation.close_friends > 0) { - cause_groups[0] = TRUE; - cause_groups[1] = TRUE; + cause_comm_groups_enabled[0] = TRUE; + cause_comm_groups_enabled[1] = TRUE; } else if (cause_actor->situation.area_friends > 0) { - cause_groups[0] = TRUE; - cause_groups[1] = FALSE; + cause_comm_groups_enabled[0] = TRUE; + cause_comm_groups_enabled[1] = FALSE; } } else if (cause_unit->unit.player_index != NONE) @@ -6123,62 +6028,62 @@ void ai_communication_event( { short index; - for (index = 0; index < NUMBEROF(enemy_status); index++) + for (index = 0; index < NUMBEROF(enemy_status_enabled); index++) { - enemy_status[index] = TRUE; + enemy_status_enabled[index] = TRUE; } } else if (!subject_encounter) { - enemy_status[0] = !subject_actor->target.any_target_ever; - enemy_status[1] = + enemy_status_enabled[0] = !subject_actor->target.any_target_ever; + enemy_status_enabled[1] = !subject_actor->target.target_really_alive && subject_actor->target.since_any_target_visible_timer != NONE; - enemy_status[2] = + enemy_status_enabled[2] = subject_actor->target.target_prop_index == NONE || subject_actor->target.since_any_target_visible_timer == NONE || subject_actor->target.since_any_target_visible_timer >= 180; - enemy_status[3] = + enemy_status_enabled[3] = subject_actor->state.combat_status < _actor_combat_status_definite && (subject_actor->target.since_any_target_visible_timer == NONE || subject_actor->target.since_any_target_visible_timer >= 75) && (subject_actor->target.target_really_alive || subject_actor->state.combat_status > 0); - enemy_status[4] = subject_actor->state.combat_status < _actor_combat_status_dangerous; - enemy_status[5] = + enemy_status_enabled[4] = subject_actor->state.combat_status < _actor_combat_status_dangerous; + enemy_status_enabled[5] = subject_actor->target.target_type >= _actor_target_visible_enemy && subject_actor->target.target_really_alive; } else { - enemy_status[0] = !subject_actor->target.any_target_ever; - enemy_status[1] = + enemy_status_enabled[0] = !subject_actor->target.any_target_ever; + enemy_status_enabled[1] = subject_encounter->enemy_visible_timer != NONE && !subject_encounter->enemy_alive; - enemy_status[2] = + enemy_status_enabled[2] = (subject_encounter->enemy_visible_timer == NONE || subject_encounter->enemy_visible_timer >= 180) && subject_encounter->enemy_alive; - enemy_status[3] = + enemy_status_enabled[3] = subject_actor->state.combat_status < _actor_combat_status_definite && (subject_encounter->enemy_visible_timer == NONE || subject_encounter->enemy_visible_timer >= 75) && (subject_encounter->enemy_alive || subject_actor->state.combat_status > 0); - enemy_status[4] = + enemy_status_enabled[4] = subject_actor->state.combat_status < _actor_combat_status_dangerous && (subject_encounter->enemy_visible_timer == NONE || subject_encounter->enemy_visible_timer >= 75); - enemy_status[5] = + enemy_status_enabled[5] = subject_encounter->enemy_visible && subject_encounter->enemy_alive; } - csmemset(hostility_matches, 0, sizeof(hostility_matches)); + csmemset(hostility_enabled, 0, sizeof(hostility_enabled)); if (hostility != NONE) { - hostility_matches[hostility] = TRUE; + hostility_enabled[hostility] = TRUE; if (hostility == _comm_hostility_traitor) { - hostility_matches[_comm_hostility_enemy] = TRUE; + hostility_enabled[_comm_hostility_enemy] = TRUE; } } @@ -6190,18 +6095,18 @@ void ai_communication_event( team_index < NUMBER_OF_AI_COMMUNICATION_TEAMS; team_index++) { - shout_ticks[team_index] = (short)MAX(0, + time_since_shout[team_index] = (short)MAX(0, event_time - ai_globals->last_shout_time[team_index]); - talk_ticks[team_index] = (short)MAX(0, + time_since_talk[team_index] = (short)MAX(0, event_time - ai_globals->last_talk_time[team_index]); - chatter_ticks[team_index] = (short)MAX(0, + time_since_chatter[team_index] = (short)MAX(0, event_time - ai_globals->last_chatter_time[team_index]); shout_seconds[team_index] = - shout_ticks[team_index] * (1.0f / TICKS_PER_SECOND); + time_since_shout[team_index] * (1.0f / TICKS_PER_SECOND); talk_seconds[team_index] = - talk_ticks[team_index] * (1.0f / TICKS_PER_SECOND); + time_since_talk[team_index] * (1.0f / TICKS_PER_SECOND); chatter_seconds[team_index] = - chatter_ticks[team_index] * (1.0f / TICKS_PER_SECOND); + time_since_chatter[team_index] * (1.0f / TICKS_PER_SECOND); /* nothing may be spoken at priority none */ speech_disabled[team_index][_ai_communication_priority_none][0] = TRUE; @@ -6219,7 +6124,7 @@ void ai_communication_event( { short remaining = (short)( communication_timer_tolerances[priority][distance_group][0] * TICKS_PER_SECOND - - chatter_ticks[team_index]); + time_since_chatter[team_index]); if (remaining > 0) { @@ -6232,7 +6137,7 @@ void ai_communication_event( { short remaining = (short)( communication_timer_tolerances[priority][distance_group][1] * TICKS_PER_SECOND - - talk_ticks[team_index]); + time_since_talk[team_index]); if (remaining > 0) { @@ -6245,7 +6150,7 @@ void ai_communication_event( { short remaining = (short)( communication_timer_tolerances[priority][distance_group][3] * TICKS_PER_SECOND - - shout_ticks[team_index]); + time_since_shout[team_index]); if (remaining > 0) { @@ -6324,7 +6229,7 @@ void ai_communication_event( } if (usage->required_hostility != NONE && - !hostility_matches[usage->required_hostility]) + !hostility_enabled[usage->required_hostility]) { if (ai_debug.print_communication) { @@ -6357,11 +6262,11 @@ void ai_communication_event( continue; } else if (usage->required_enemy_status != NONE && - !enemy_status[usage->required_enemy_status]) + !enemy_status_enabled[usage->required_enemy_status]) { if (ai_debug.print_communication) { - char const *enemy_status_names[NUMBEROF(enemy_status)] = + char const *enemy_status_names[NUMBEROF(enemy_status_enabled)] = { "never", "dead", "lost", "notvis", "nodanger", "vis" }; @@ -6455,7 +6360,7 @@ void ai_communication_event( switch (usage->protagonist_type) { case _comm_protagonist_subject: - protagonist_groups = subject_groups; + protagonist_groups = subject_comm_groups_enabled; protagonist_unit_index = subject_unit_index; protagonist_actor_index = subject_actor_index; protagonist_actor = subject_actor; @@ -6463,7 +6368,7 @@ void ai_communication_event( break; case _comm_protagonist_cause: - protagonist_groups = cause_groups; + protagonist_groups = cause_comm_groups_enabled; protagonist_unit_index = cause_unit_index; protagonist_actor_index = cause_actor_index; protagonist_actor = cause_actor; @@ -7086,7 +6991,7 @@ void ai_communication_event( if (possibility_count > 0) { - struct ai_information_packet information; + struct ai_information_packet ai_packet; selected_possibility = possibilities; if (any_forced_possibility) @@ -7159,26 +7064,26 @@ void ai_communication_event( } } - information.communication_type = communication_type; - information.target_unit_index = selected_possibility->recipient_unit_index; - information.damage_category = damage_type; - information.dialogue_type_index = selected_possibility->dialogue_type_index; - information.updated_dialogue_timers = TRUE; - information.look_priority = selected_possibility->recipient_look_priority; - information.look_type = selected_possibility->look_type; - information.look_data.unit.unit_index = selected_possibility->look_unit_index; - information.information_type = information_type == NONE ? + ai_packet.communication_type = communication_type; + ai_packet.target_unit_index = selected_possibility->recipient_unit_index; + ai_packet.damage_category = damage_type; + ai_packet.dialogue_type_index = selected_possibility->dialogue_type_index; + ai_packet.updated_dialogue_timers = TRUE; + ai_packet.look_priority = selected_possibility->recipient_look_priority; + ai_packet.look_type = selected_possibility->look_type; + ai_packet.look_data.unit.unit_index = selected_possibility->look_unit_index; + ai_packet.information_type = information_type == NONE ? _ai_information_none : information_type; if (!information_data) { csmemset( - &information.information_data, + &ai_packet.information_data, 0, - sizeof(information.information_data)); + sizeof(ai_packet.information_data)); } else { - information.information_data = *information_data; + ai_packet.information_data = *information_data; } if (selected_possibility->is_reply) @@ -7192,19 +7097,19 @@ void ai_communication_event( selected_possibility->protagonist_unit_index, selected_possibility->priority, selected_possibility->vocalization_type, - &information); + &ai_packet); ai_communication_notify( selected_possibility->protagonist_unit_index, selected_possibility->priority, selected_possibility->vocalization_type, - &information); + &ai_packet); ai_communication_finished( selected_possibility->protagonist_unit_index, selected_possibility->priority, selected_possibility->vocalization_type, TRUE, selected_possibility->preselected_reply_actor_index, - &information); + &ai_packet); } else { @@ -7216,7 +7121,7 @@ void ai_communication_event( speech.delay_time = selected_possibility->delay_time; speech.ai_notification_delay = selected_possibility->ai_delay_time; speech.pause_time = 24; - speech.ai = information; + speech.ai = ai_packet; unit_speak( selected_possibility->protagonist_unit_index, selected_possibility->play_type, @@ -7225,38 +7130,38 @@ void ai_communication_event( if (selected_possibility->animation_type != NONE) { struct unit_datum *speaker_unit = unit_get(selected_possibility->protagonist_unit_index); - real_vector2d alignment; + real_vector2d alignment_vector; - alignment.i = speaker_unit->object.forward.i; - alignment.j = speaker_unit->object.forward.j; + alignment_vector.i = speaker_unit->object.forward.i; + alignment_vector.j = speaker_unit->object.forward.j; if (selected_possibility->recipient_unit_index != NONE) { - real_point3d speaker_head; - real_point3d target_head; + real_point3d protagonist_head_position; + real_point3d target_head_position; real magnitude; - unit_get_head_position(selected_possibility->protagonist_unit_index, &speaker_head); - unit_get_head_position(selected_possibility->recipient_unit_index, &target_head); - alignment.i = target_head.x - speaker_head.x; - alignment.j = target_head.y - speaker_head.y; + unit_get_head_position(selected_possibility->protagonist_unit_index, &protagonist_head_position); + unit_get_head_position(selected_possibility->recipient_unit_index, &target_head_position); + alignment_vector.i = target_head_position.x - protagonist_head_position.x; + alignment_vector.j = target_head_position.y - protagonist_head_position.y; magnitude = square_root( - alignment.i * alignment.i + alignment.j * alignment.j); + alignment_vector.i * alignment_vector.i + alignment_vector.j * alignment_vector.j); if (fabs(magnitude) >= _real_epsilon && magnitude != 0.0f) { - alignment.i /= magnitude; - alignment.j /= magnitude; + alignment_vector.i /= magnitude; + alignment_vector.j /= magnitude; } else { - alignment.i = speaker_unit->object.forward.i; - alignment.j = speaker_unit->object.forward.j; + alignment_vector.i = speaker_unit->object.forward.i; + alignment_vector.j = speaker_unit->object.forward.j; } } unit_start_animation_impulse( selected_possibility->protagonist_unit_index, selected_possibility->animation_type, - &alignment); + &alignment_vector); } if (selected_possibility->protagonist_actor_index != NONE) diff --git a/source/ai/ai_communication.h b/source/ai/ai_communication.h index 9c6aaf55..a55d2ff6 100644 --- a/source/ai/ai_communication.h +++ b/source/ai/ai_communication.h @@ -89,7 +89,7 @@ enum ai_communication_hostility /* ---------- macros */ #define ai_conversation_header_get(index) \ - ((struct ai_conversation_datum_header *)datum_get(conversation_data, (index))) + ((struct conversation_datum *)datum_get(conversation_data, (index))) /* ---------- structures */ @@ -97,7 +97,7 @@ struct ai_information_data; struct ai_information_packet; /* The independently mapped prefix of the 0x64-byte conversation datum. */ -struct ai_conversation_datum_header +struct conversation_datum { short identifier; short scenario_conversation_index; @@ -110,6 +110,21 @@ struct ai_conversation_datum_header byte reserved0A[2]; long creation_time; long triggering_player_unit_index; + unsigned long participant_bitmask; + short dialogue_indices[8]; + long actor_indices[8]; + short line_index; + short line_participant_index; + short line_delay_timer; + word line_flags; + long line_actor_index; + long line_unit_index; + long line_address_unit_index; + long line_sound_index; + boolean line_unspatialized; + boolean line_spoken; + boolean line_finished; + boolean line_advance; }; /* ---------- prototypes/AI_COMMUNICATION.C */ diff --git a/source/ai/ai_debug.c b/source/ai/ai_debug.c index f12187dd..fc2f220c 100644 --- a/source/ai/ai_debug.c +++ b/source/ai/ai_debug.c @@ -13,6 +13,7 @@ AI_DEBUG.C #include "actor_definitions.h" #include "actor_types.h" #include "ai.h" +#include "ai/ai_globals.h" #include "ai_communication.h" #include "ai_profile.h" #include "ai_scenario_definitions.h" @@ -87,40 +88,6 @@ struct ai_debug_speech_list boolean all; }; -struct ai_debug_spatial_effect -{ - short type; - short field_02; - real_point3d point; - long time; -}; - -struct ai_debug_enterable_vehicle -{ - long object_index; - real distance; - short team_flags; - short actor_type_flags; - short actor_count; - word pad; - long actor_index[6]; -}; - -struct ai_debug_globals_view -{ - boolean ai_active; - boolean initialized_for_new_map; - char __unknown02[0x12E]; - short spatial_effect_head; - short spatial_effect_tail; - struct ai_debug_spatial_effect spatial_effect[32]; - boolean field_3B4; - char __unknown3B5[1]; - short enterable_vehicle_count; - struct ai_debug_enterable_vehicle enterable_vehicle[32]; - short field_8B8; - char __unknown8BA[0x22]; -}; struct encounter_actor_iterator { long encounter_index; @@ -139,13 +106,13 @@ struct actor_iterator }; typedef char ai_debug_enterable_vehicle_size_assert[ - sizeof(struct ai_debug_enterable_vehicle) == 0x28 ? 1 : -1]; + sizeof(struct ai_vehicle_enterable) == 0x28 ? 1 : -1]; typedef char ai_debug_globals_spatial_effect_offset_assert[ - offsetof(struct ai_debug_globals_view, spatial_effect) == 0x134 ? 1 : -1]; + offsetof(struct ai_globals, spatial_effects) == 0x134 ? 1 : -1]; typedef char ai_debug_globals_enterable_vehicle_offset_assert[ - offsetof(struct ai_debug_globals_view, enterable_vehicle) == 0x3B8 ? 1 : -1]; + offsetof(struct ai_globals, enterable_vehicles) == 0x3B8 ? 1 : -1]; typedef char ai_debug_globals_size_assert[ - sizeof(struct ai_debug_globals_view) == 0x8DC ? 1 : -1]; + sizeof(struct ai_globals) == 0x8DC ? 1 : -1]; typedef char ai_debug_actor_iterator_size_assert[ sizeof(struct actor_iterator) == 0x1C ? 1 : -1]; @@ -236,8 +203,6 @@ static void ai_debug_render_path_nodes( struct ai_debug_state ai_debug; -extern struct ai_debug_globals_view *ai_globals; - struct actor_debug_info *actor_debug_array = NULL; struct path_debug_storage *actor_path_debug_array = NULL; static short global_ai_debug_path_render_id = 0; @@ -453,7 +418,7 @@ boolean ai_debug_highlight_cluster( void ai_debug_render( void) { - if (ai_globals->initialized_for_new_map) + if (ai_globals->ai_initialized_for_map) { global_ai_debug_string_position = rasterizer_globals.reserved04.frame_bounds.y1 - 20; @@ -1707,9 +1672,9 @@ static void ai_debug_render_actor( case 1: set_real_point3d( &origin, - ((1.f-prop->awareness)*prop_start_point.x) + (prop->awareness*prop->head_position.x), - ((1.f-prop->awareness)*prop_start_point.y) + (prop->awareness*prop->head_position.y), - ((1.f-prop->awareness)*prop_start_point.z) + (prop->awareness*prop->head_position.z) + (1.f-prop->awareness)*prop_start_point.x + prop->awareness*prop->head_position.x, + (1.f-prop->awareness)*prop_start_point.y + prop->awareness*prop->head_position.y, + (1.f-prop->awareness)*prop_start_point.z + prop->awareness*prop->head_position.z ); render_debug_line(TRUE, &prop_start_point, &origin, global_real_argb_yellow); render_debug_line(TRUE, &origin, &prop->head_position, global_real_argb_black); @@ -3679,8 +3644,7 @@ static void ai_debug_render_actor( { "", "part", - "full", - NULL + "full" }; sprintf( @@ -5282,11 +5246,11 @@ static void ai_debug_render_spatial_effects( void) { long time = game_time_get(); - short index = ai_globals->spatial_effect_head; + short index = ai_globals->spatial_effects_first_index; - while (index!=ai_globals->spatial_effect_tail) + while (index!=ai_globals->spatial_effects_last_index) { - struct ai_debug_spatial_effect *effect = &ai_globals->spatial_effect[index]; + struct ai_spatial_effect *effect = &ai_globals->spatial_effects[index]; if (effect->type!=NONE) { @@ -5305,7 +5269,7 @@ static void ai_debug_render_spatial_effects( color = *colors[effect->type]; } - effect_point = &effect->point; + effect_point = &effect->position; render_debug_sphere(TRUE, effect_point, 0.2f, color); @@ -5314,7 +5278,7 @@ static void ai_debug_render_spatial_effects( point.z = global_up3d->k*0.3f + effect_point->z; render_debug_string_at_point(TRUE, &point, - csprintf(temporary, "c%d t%d", effect->field_02, time - effect->time), + csprintf(temporary, "c%d t%d", effect->count, time - effect->last_tick), color); } @@ -5487,23 +5451,23 @@ static void ai_debug_render_vehicles_enterable( for (index = 0; indexenterable_vehicle_count; index++) { - struct ai_debug_enterable_vehicle *vehicle = &ai_globals->enterable_vehicle[index]; + struct ai_vehicle_enterable *vehicle = &ai_globals->enterable_vehicles[index]; - if (unit_try_and_get(vehicle->object_index)) + if (unit_try_and_get(vehicle->vehicle_index)) { real_point3d origin; - object_get_origin(vehicle->object_index, &origin); + object_get_origin(vehicle->vehicle_index, &origin); point_from_line3d(&origin, global_up3d, 0.5f, &origin); ai_debug_drawstack_setup(&origin); render_debug_string_at_point(TRUE, ai_debug_drawstack(), - csprintf(temporary, "enterable: dist %.1f", vehicle->distance), + csprintf(temporary, "enterable: dist %.1f", vehicle->radius), global_real_argb_pink); - if (vehicle->team_flags) + if (vehicle->team_bitmask) { char const *team_names[NUMBER_OF_SOLO_CAMPAIGN_TEAMS] = { @@ -5515,7 +5479,7 @@ static void ai_debug_render_vehicles_enterable( for (index = 0; indexteam_flags, index)) + if (TEST_FLAG(vehicle->team_bitmask, index)) { csstrcat(temporary, " "); csstrcat(temporary, team_names[index]); @@ -5526,7 +5490,7 @@ static void ai_debug_render_vehicles_enterable( global_real_argb_pink); } - if (vehicle->actor_type_flags) + if (vehicle->actor_type_bitmask) { char const *actor_type_names[NUMBER_OF_ACTOR_TYPES] = { @@ -5539,7 +5503,7 @@ static void ai_debug_render_vehicles_enterable( for (index = 0; indexactor_type_flags, index)) + if (TEST_FLAG(vehicle->actor_type_bitmask, index)) { csstrcat(temporary, " "); csstrcat(temporary, actor_type_names[index]); @@ -5550,15 +5514,15 @@ static void ai_debug_render_vehicles_enterable( global_real_argb_pink); } - if (vehicle->actor_count>0) + if (vehicle->ai_indices_count>0) { char string[256]; sprintf(temporary, "actors:"); - for (index = 0; indexactor_count; index++) + for (index = 0; indexai_indices_count; index++) { - ai_index_to_string(vehicle->actor_index[index], global_scenario_get(), + ai_index_to_string(vehicle->ai_indices[index], global_scenario_get(), string, 256); csstrcat(temporary, " "); diff --git a/source/ai/ai_globals.h b/source/ai/ai_globals.h index 57c21129..706231ea 100644 --- a/source/ai/ai_globals.h +++ b/source/ai/ai_globals.h @@ -14,10 +14,70 @@ header included in hcex build. /* ---------- structures */ +struct ai_spatial_effect +{ + short type; + short count; + real_point3d position; + long last_tick; +}; + +struct recent_conversation +{ + short scenario_conversation_index; + boolean unable_to_begin; + boolean finished_successfully; + long finish_time; + byte __unknown08[8]; +}; + +struct ai_vehicle_enterable +{ + long vehicle_index; + real radius; + short team_bitmask; + short actor_type_bitmask; + short ai_indices_count; + word __pad0E; + long ai_indices[6]; +}; + +struct ai_globals +{ + boolean ai_active; + boolean ai_initialized_for_map; + boolean ai_has_control_data; + boolean time_given_this_frame; + short last_highest_service_timer; + short current_highest_service_timer; + long first_encounterless_actor_index; + real major_upgrade_error; + boolean dialogue_triggers_enabled; + byte reserved011[0x3]; + long last_chatter_time[2]; + long last_talk_time[2]; + long last_shout_time[2]; + short recent_conversation_count; + short recent_conversation_next_index; + struct recent_conversation recent_conversations[16]; + short spatial_effects_first_index; + short spatial_effects_last_index; + struct ai_spatial_effect spatial_effects[32]; + boolean grenades_enabled; + byte reserved3B5; + short enterable_vehicle_count; + struct ai_vehicle_enterable enterable_vehicles[32]; + short mounted_weapon_unit_count; + byte reserved8BA[0x2]; + long mounted_weapon_unit_indices[8]; +}; + /* ---------- prototypes/EXAMPLE.C */ /* ---------- globals */ +extern struct ai_globals *ai_globals; + /* ---------- public code */ #endif // __AI_GLOBALS_H diff --git a/source/ai/ai_scenario_definitions.h b/source/ai/ai_scenario_definitions.h index 99defeb6..1af327bd 100644 --- a/source/ai/ai_scenario_definitions.h +++ b/source/ai/ai_scenario_definitions.h @@ -434,6 +434,19 @@ struct ai_command_list_definition struct tag_block unused_blocks[2]; }; +struct ai_conversation +{ + char name[32]; + word flags; + word pad22; + real trigger_distance; + real run_to_player_dist; + byte __unknown2C[0x24]; + struct tag_block participants; + struct tag_block lines; + struct tag_block unused; +}; + /* ---------- prototypes/AI_SCENARIO_DEFINITIONS.C */ /* ---------- globals */ diff --git a/source/ai/ai_script.c b/source/ai/ai_script.c index 4a176731..5017c4db 100644 --- a/source/ai/ai_script.c +++ b/source/ai/ai_script.c @@ -452,6 +452,7 @@ symbols in this file: #include "ai/actors.h" #include "ai/ai_communication.h" #include "ai/ai_debug.h" +#include "ai/ai_globals.h" #include "ai/ai_scenario_definitions.h" #include "ai/encounters.h" #include "ai/props.h" @@ -559,26 +560,6 @@ enum /* ---------- structures */ -struct ai_script_vehicle_enterable_data -{ - long vehicle_index; - real radius; - short team_bitmask; - short actor_type_bitmask; - short ai_indices_count; - word __pad0E; - long ai_indices[MAXIMUM_AI_INDICES_PER_ENTERABLE_VEHICLE]; -}; - -struct ai_script_globals_data -{ - boolean ai_active; - boolean ai_initialized_for_map; - byte __unknown2[0x3B4]; - short enterable_vehicle_count; - struct ai_script_vehicle_enterable_data enterable_vehicles[MAXIMUM_AI_ENTERABLE_VEHICLES]; -}; - typedef char ai_script_squad_iterator_size_assert[ sizeof(struct ai_script_squad_iterator) == 0x14 ? 1 : -1]; @@ -607,32 +588,24 @@ struct ai_script_vehicle_candidate byte pad[3]; }; -struct ai_script_conversation_definition -{ - char name[32]; - byte unknown[84]; -}; - typedef char ai_script_actor_iterator_size_assert[ sizeof(struct actor_iterator) == 0x1C ? 1 : -1]; typedef char ai_script_actor_reference_iterator_size_assert[ sizeof(struct ai_script_actor_reference_iterator) == 0x18 ? 1 : -1]; typedef char ai_script_actor_reference_iterator_actor_index_offset_assert[ offsetof(struct ai_script_actor_reference_iterator, actor_index) == 0x10 ? 1 : -1]; -typedef char ai_script_vehicle_enterable_size_assert[ - sizeof(struct ai_script_vehicle_enterable) == 0xC ? 1 : -1]; typedef char ai_script_vehicle_enterable_radius_offset_assert[ - offsetof(struct ai_script_vehicle_enterable, radius) == 0x4 ? 1 : -1]; + offsetof(struct ai_vehicle_enterable, radius) == 0x4 ? 1 : -1]; typedef char ai_script_vehicle_enterable_team_offset_assert[ - offsetof(struct ai_script_vehicle_enterable, team_bitmask) == 0x8 ? 1 : -1]; + offsetof(struct ai_vehicle_enterable, team_bitmask) == 0x8 ? 1 : -1]; typedef char ai_script_vehicle_enterable_actor_type_offset_assert[ - offsetof(struct ai_script_vehicle_enterable, actor_type_bitmask) == 0xA ? 1 : -1]; + offsetof(struct ai_vehicle_enterable, actor_type_bitmask) == 0xA ? 1 : -1]; typedef char ai_script_vehicle_enterable_data_size_assert[ - sizeof(struct ai_script_vehicle_enterable_data) == 0x28 ? 1 : -1]; + sizeof(struct ai_vehicle_enterable) == 0x28 ? 1 : -1]; typedef char ai_script_globals_enterable_vehicle_count_offset_assert[ - offsetof(struct ai_script_globals_data, enterable_vehicle_count) == 0x3B6 ? 1 : -1]; + offsetof(struct ai_globals, enterable_vehicle_count) == 0x3B6 ? 1 : -1]; typedef char ai_script_globals_enterable_vehicles_offset_assert[ - offsetof(struct ai_script_globals_data, enterable_vehicles) == 0x3B8 ? 1 : -1]; + offsetof(struct ai_globals, enterable_vehicles) == 0x3B8 ? 1 : -1]; typedef char ai_script_platoon_iterator_size_assert[ sizeof(struct ai_script_platoon_iterator) == 0xC ? 1 : -1]; typedef char ai_script_vehicle_candidate_size_assert[ @@ -691,8 +664,6 @@ static short ai_scripting_command_list_status_internal( /* ---------- globals */ -extern struct ai_script_globals_data *ai_globals; - char const ai_script_squad_separator = '/'; /* ---------- public code */ @@ -1763,10 +1734,10 @@ void ai_scripting_set_blind( return; } -struct ai_script_vehicle_enterable *ai_scripting_find_vehicle_enterable( +struct ai_vehicle_enterable *ai_scripting_find_vehicle_enterable( long vehicle_index) { - struct ai_script_vehicle_enterable_data *vehicle_enterable = NULL; + struct ai_vehicle_enterable *vehicle_enterable = NULL; if (vehicle_index != NONE) { @@ -1801,7 +1772,7 @@ struct ai_script_vehicle_enterable *ai_scripting_find_vehicle_enterable( } } - return (struct ai_script_vehicle_enterable *)vehicle_enterable; + return (struct ai_vehicle_enterable *)vehicle_enterable; } void ai_scripting_vehicle_enterable_distance( @@ -1818,7 +1789,7 @@ void ai_scripting_vehicle_enterable_distance( if (unit_index != NONE) { - struct ai_script_vehicle_enterable *vehicle_enterable = + struct ai_vehicle_enterable *vehicle_enterable = ai_scripting_find_vehicle_enterable(unit_index); if (vehicle_enterable) vehicle_enterable->radius = distance; @@ -1842,7 +1813,7 @@ void ai_scripting_vehicle_enterable_team( if (unit_index != NONE) { - struct ai_script_vehicle_enterable *vehicle_enterable = + struct ai_vehicle_enterable *vehicle_enterable = ai_scripting_find_vehicle_enterable(unit_index); if (vehicle_enterable) vehicle_enterable->team_bitmask |= 1 << team_index; @@ -1866,7 +1837,7 @@ void ai_scripting_vehicle_enterable_actor_type( if (unit_index != NONE) { - struct ai_script_vehicle_enterable *vehicle_enterable = + struct ai_vehicle_enterable *vehicle_enterable = ai_scripting_find_vehicle_enterable(unit_index); if (vehicle_enterable) vehicle_enterable->actor_type_bitmask |= 1 << actor_type; @@ -1897,8 +1868,8 @@ void ai_scripting_vehicle_enterable_actors( if (unit_index != NONE && ai_reference != NONE) { - struct ai_script_vehicle_enterable_data *vehicle_enterable = - (struct ai_script_vehicle_enterable_data *)ai_scripting_find_vehicle_enterable(unit_index); + struct ai_vehicle_enterable *vehicle_enterable = + (struct ai_vehicle_enterable *)ai_scripting_find_vehicle_enterable(unit_index); if (vehicle_enterable) { @@ -2854,7 +2825,7 @@ boolean ai_scripting_conversation( conversation_name = TAG_BLOCK_GET_ELEMENT( &scenario->ai_conversations, conversation_index, - struct ai_script_conversation_definition)->name; + struct ai_conversation)->name; } error( @@ -2882,7 +2853,7 @@ void ai_scripting_conversation_stop( conversation_name = TAG_BLOCK_GET_ELEMENT( &scenario->ai_conversations, conversation_index, - struct ai_script_conversation_definition)->name; + struct ai_conversation)->name; } error( @@ -2912,7 +2883,7 @@ void ai_scripting_conversation_advance( conversation_name = TAG_BLOCK_GET_ELEMENT( &scenario->ai_conversations, conversation_index, - struct ai_script_conversation_definition)->name; + struct ai_conversation)->name; } error( diff --git a/source/ai/ai_script.h b/source/ai/ai_script.h index cd4cdd30..36c8a709 100644 --- a/source/ai/ai_script.h +++ b/source/ai/ai_script.h @@ -22,14 +22,6 @@ struct platoon_datum; struct scenario; struct squad_datum; -struct ai_script_vehicle_enterable -{ - long vehicle_index; - real radius; - short team_bitmask; - short actor_type_bitmask; -}; - struct ai_script_platoon_iterator { long encounter_index; @@ -97,7 +89,7 @@ struct platoon_datum *ai_index_platoon_iterator_next( struct ai_script_platoon_iterator *iterator); long object_list_from_ai_reference( long ai_reference); -struct ai_script_vehicle_enterable *ai_scripting_find_vehicle_enterable( +struct ai_vehicle_enterable *ai_scripting_find_vehicle_enterable( long vehicle_index); void ai_scripting_vehicle_enterable_distance( long ai_reference, diff --git a/source/ai/encounters.c b/source/ai/encounters.c index fb7d7cf6..e41f47e0 100644 --- a/source/ai/encounters.c +++ b/source/ai/encounters.c @@ -289,6 +289,7 @@ symbols in this file: #include "actor_placement.h" #include "actor_types.h" #include "ai.h" +#include "ai/ai_globals.h" #include "ai_debug.h" #include "ai_communication.h" #include "ai_profile.h" @@ -471,17 +472,6 @@ struct actor_iterator long next_index; }; -struct encounter_ai_globals_prefix -{ - boolean ai_active; - boolean ai_initialized_for_map; - boolean ai_has_control_data; - boolean time_given_this_frame; - short last_highest_service_timer; - short current_highest_service_timer; - long first_encounterless_actor_index; -}; - typedef char encounter_iterator_size_assert[ sizeof(struct encounter_iterator) == 0x18 ? 1 : -1]; typedef char encounter_iterator_index_offset_assert[ @@ -505,9 +495,9 @@ typedef char actor_iterator_index_offset_assert[ typedef char actor_iterator_next_index_offset_assert[ offsetof(struct actor_iterator, next_index) == 0x18 ? 1 : -1]; typedef char encounter_ai_globals_initialized_offset_assert[ - offsetof(struct encounter_ai_globals_prefix, ai_initialized_for_map) == 0x1 ? 1 : -1]; + offsetof(struct ai_globals, ai_initialized_for_map) == 0x1 ? 1 : -1]; typedef char encounter_ai_globals_encounterless_actor_offset_assert[ - offsetof(struct encounter_ai_globals_prefix, first_encounterless_actor_index) == 0x8 ? 1 : -1]; + offsetof(struct ai_globals, first_encounterless_actor_index) == 0x8 ? 1 : -1]; typedef char encounter_datum_active_offset_assert[ offsetof(struct encounter_datum, active) == 0xD ? 1 : -1]; typedef char encounter_datum_status_dirty_offset_assert[ @@ -578,8 +568,6 @@ static short squad_get_actor_type( /* ---------- globals */ -extern struct encounter_ai_globals_prefix *ai_globals; - struct data_array *encounter_data; struct platoon_datum *platoon_array; struct squad_datum *squad_array; diff --git a/source/bitmaps/bitmap_group.c b/source/bitmaps/bitmap_group.c index f0c462f0..8df2c7b9 100644 --- a/source/bitmaps/bitmap_group.c +++ b/source/bitmaps/bitmap_group.c @@ -809,30 +809,30 @@ short bitmap_group_add_bitmap( short format, short mipmap_count) { - struct bitmap_data new_bitmap_data; + struct bitmap_data fake_bitmap; long pixels_end = 0; long previous_count; long pixel_data_size; match_assert("c:\\halo\\SOURCE\\bitmaps\\bitmap_group.c", 0x2DB, group); - new_bitmap_data.type = type; - new_bitmap_data.flags = 0; - new_bitmap_data.registration_point.y = 0; - new_bitmap_data.registration_point.x = 0; - new_bitmap_data.mipmap_count = mipmap_count; - new_bitmap_data.pixels_offset = 0; - new_bitmap_data.hardware_format = NULL; - new_bitmap_data.base_address = NULL; - new_bitmap_data.signature = BITMAP_GROUP_TAG; - new_bitmap_data.width = width; - new_bitmap_data.height = height; - new_bitmap_data.depth = depth; - new_bitmap_data.format = format; + fake_bitmap.type = type; + fake_bitmap.flags = 0; + fake_bitmap.registration_point.y = 0; + fake_bitmap.registration_point.x = 0; + fake_bitmap.mipmap_count = mipmap_count; + fake_bitmap.pixels_offset = 0; + fake_bitmap.hardware_format = NULL; + fake_bitmap.base_address = NULL; + fake_bitmap.signature = BITMAP_GROUP_TAG; + fake_bitmap.width = width; + fake_bitmap.height = height; + fake_bitmap.depth = depth; + fake_bitmap.format = format; if (group->type == _bitmap_group_type_interface_bitmaps) { - SET_FLAG(new_bitmap_data.flags, _bitmap_linear_bit, TRUE); + SET_FLAG(fake_bitmap.flags, _bitmap_linear_bit, TRUE); } else if ((width & (width - 1)) || (height & (height - 1)) || @@ -860,18 +860,18 @@ short bitmap_group_add_bitmap( else { SET_FLAG( - new_bitmap_data.flags, + fake_bitmap.flags, _bitmap_has_power_of_two_dimensions_bit, TRUE); } if (format >= _bitmap_format_dxt1 && format <= _bitmap_format_dxt5) { - SET_FLAG(new_bitmap_data.flags, _bitmap_compressed_bit, TRUE); + SET_FLAG(fake_bitmap.flags, _bitmap_compressed_bit, TRUE); } if (format == _bitmap_format_p8_bump) { - SET_FLAG(new_bitmap_data.flags, _bitmap_palettized_bit, TRUE); + SET_FLAG(fake_bitmap.flags, _bitmap_palettized_bit, TRUE); } /* January repeats these validation guards after assigning format flags. */ @@ -886,7 +886,7 @@ short bitmap_group_add_bitmap( return NONE; } if (!TEST_FLAG( - new_bitmap_data.flags, + fake_bitmap.flags, _bitmap_has_power_of_two_dimensions_bit) && group->type != _bitmap_group_type_interface_bitmaps) { @@ -900,7 +900,7 @@ short bitmap_group_add_bitmap( } previous_count = group->bitmaps.count; - pixel_data_size = bitmap_get_pixel_data_size(&new_bitmap_data); + pixel_data_size = bitmap_get_pixel_data_size(&fake_bitmap); if (tag_block_resize(&group->bitmaps, group->bitmaps.count + 1) && tag_data_resize(&group->pixel_data, group->pixel_data.size + pixel_data_size)) { @@ -968,7 +968,7 @@ short bitmap_group_add_bitmap( "c:\\halo\\SOURCE\\bitmaps\\bitmap_group.c", 0x371, new_bitmap); - csmemcpy(new_bitmap, &new_bitmap_data, sizeof(new_bitmap_data)); + csmemcpy(new_bitmap, &fake_bitmap, sizeof(fake_bitmap)); new_bitmap->pixels_offset = pixels_end; new_bitmap->base_address = (byte *)group->pixel_data.address + pixels_end; csmemset(new_bitmap->base_address, 0, pixel_data_size); diff --git a/source/bitmaps/s3tc/s3tc.c b/source/bitmaps/s3tc/s3tc.c index 9ebc2603..ac22649f 100644 --- a/source/bitmaps/s3tc/s3tc.c +++ b/source/bitmaps/s3tc/s3tc.c @@ -314,9 +314,9 @@ static void AllSame( /* ---------- public code */ void EncodeBlockRGBColorKey( - struct s3tc_color colors[S3TC_BLOCK_PIXELS], - struct s3tc_block_rgb *block, - byte alpha_key) + struct s3tc_color colorSrc[S3TC_BLOCK_PIXELS], + struct s3tc_block_rgb *pblockDst, + byte alphaKey) { struct s3tc_fcolor fcolors[S3TC_BLOCK_PIXELS]; struct s3tc_fcolor mean; @@ -349,7 +349,7 @@ void EncodeBlockRGBColorKey( long column; long i; - if (block == NULL) + if (pblockDst == NULL) { return; } @@ -357,7 +357,7 @@ void EncodeBlockRGBColorKey( for (i = S3TC_BLOCK_PIXELS - 1; i >= 0; --i) { wAlpha <<= 1; - if (colors[i].rgba[S3TC_ALPHA] >= alpha_key) + if (colorSrc[i].rgba[S3TC_ALPHA] >= alphaKey) { wAlpha |= 1; cOpaque++; @@ -370,9 +370,9 @@ void EncodeBlockRGBColorKey( if (cOpaque == 0) { - block->color0 = 0; - block->color1 = UNSIGNED_SHORT_MAX; - block->bitmap = UNSIGNED_LONG_MAX; + pblockDst->color0 = 0; + pblockDst->color1 = UNSIGNED_SHORT_MAX; + pblockDst->bitmap = UNSIGNED_LONG_MAX; return; } @@ -380,22 +380,22 @@ void EncodeBlockRGBColorKey( for (i = 0; i < S3TC_BLOCK_PIXELS; ++i) { if (same && i > 0 && - (colors[i].rgba[2] != colors[i - 1].rgba[2] || - colors[i].rgba[1] != colors[i - 1].rgba[1] || - colors[i].rgba[0] != colors[i - 1].rgba[0])) + (colorSrc[i].rgba[2] != colorSrc[i - 1].rgba[2] || + colorSrc[i].rgba[1] != colorSrc[i - 1].rgba[1] || + colorSrc[i].rgba[0] != colorSrc[i - 1].rgba[0])) { same = FALSE; } } if (same) { - AllSame(colors, block, wAlpha); + AllSame(colorSrc, pblockDst, wAlpha); return; } for (i = 0; i < S3TC_BLOCK_PIXELS; ++i) { - ColorToFcolor(&colors[i], &fcolors[i]); + ColorToFcolor(&colorSrc[i], &fcolors[i]); } scale = 1.0f / cOpaque; @@ -446,7 +446,7 @@ void EncodeBlockRGBColorKey( trace = m[2][2] + m[1][1] + m[0][0]; if (trace == 0.0f) { - AllSame(colors, block, wAlpha); + AllSame(colorSrc, pblockDst, wAlpha); return; } scale = 3.0f / trace; @@ -487,7 +487,7 @@ void EncodeBlockRGBColorKey( len2 = x * x + y * y + z * z; if (len2 == 0.0f) { - AllSame(colors, block, wAlpha); + AllSame(colorSrc, pblockDst, wAlpha); return; } @@ -519,7 +519,7 @@ void EncodeBlockRGBColorKey( upper.rgba[2] = z * max + mean.rgba[2]; ClipExtrema(&lower, &upper); - Quantize(&lower, &upper, block, cOpaque); + Quantize(&lower, &upper, pblockDst, cOpaque); dr = upper.rgba[0] - lower.rgba[0]; dg = upper.rgba[1] - lower.rgba[1]; @@ -527,11 +527,11 @@ void EncodeBlockRGBColorKey( len2 = dr * dr + dg * dg + db * db; if (len2 == 0.0f) { - AllSame(colors, block, wAlpha); + AllSame(colorSrc, pblockDst, wAlpha); return; } - block->bitmap = 0; + pblockDst->bitmap = 0; bit = 0x8000; for (i = S3TC_BLOCK_PIXELS - 1; i >= 0; --i) { @@ -554,8 +554,8 @@ void EncodeBlockRGBColorKey( { t = 3.0f; } - block->bitmap <<= 2; - block->bitmap |= mapRGB4[(long)t]; + pblockDst->bitmap <<= 2; + pblockDst->bitmap |= mapRGB4[(long)t]; } else { @@ -568,14 +568,14 @@ void EncodeBlockRGBColorKey( { t = 2.0f; } - block->bitmap <<= 2; - block->bitmap |= mapRGB3[(long)t]; + pblockDst->bitmap <<= 2; + pblockDst->bitmap |= mapRGB3[(long)t]; } } else { - block->bitmap <<= 2; - block->bitmap |= 3; + pblockDst->bitmap <<= 2; + pblockDst->bitmap |= 3; } bit >>= 1; } @@ -645,25 +645,25 @@ void DecodeBlockRGB( } void DecodeBlockRGB__single_pixel( - struct s3tc_block_rgb const *source, - struct s3tc_color *color, + struct s3tc_block_rgb const *pblockSrc, + struct s3tc_color *colorDst, short u, short v) { struct s3tc_color colors[4]; long channel; - if (source == NULL) + if (pblockSrc == NULL) { - memset(color, 0, sizeof(*color)); + memset(colorDst, 0, sizeof(*colorDst)); return; } - RGBToColor(&source->color0, &colors[0]); - RGBToColor(&source->color1, &colors[1]); + RGBToColor(&pblockSrc->color0, &colors[0]); + RGBToColor(&pblockSrc->color1, &colors[1]); colors[0].rgba[S3TC_ALPHA] = colors[1].rgba[S3TC_ALPHA] = colors[2].rgba[S3TC_ALPHA] = 0xFF; - if (source->color0 > source->color1) + if (pblockSrc->color0 > pblockSrc->color1) { word c0; word c1; @@ -695,7 +695,7 @@ void DecodeBlockRGB__single_pixel( match_assert("c:\\halo\\SOURCE\\bitmaps\\s3tc\\s3tc.c", 773, u >= 0 && u < 4); match_assert("c:\\halo\\SOURCE\\bitmaps\\s3tc\\s3tc.c", 774, v >= 0 && v < 4); - *color = colors[(source->bitmap >> (2 * (4 * v + u))) & 3]; + *colorDst = colors[(pblockSrc->bitmap >> (2 * (4 * v + u))) & 3]; return; } diff --git a/source/bitmaps/s3tc/s3tc.h b/source/bitmaps/s3tc/s3tc.h index ed6130e5..290b8264 100644 --- a/source/bitmaps/s3tc/s3tc.h +++ b/source/bitmaps/s3tc/s3tc.h @@ -73,8 +73,8 @@ void DecodeBlockAlpha3( struct s3tc_block_alpha3 *source, struct s3tc_color colors[S3TC_BLOCK_PIXELS]); void DecodeBlockRGB__single_pixel( - struct s3tc_block_rgb const *source, - struct s3tc_color *color, + struct s3tc_block_rgb const *pblockSrc, + struct s3tc_color *colorDst, short u, short v); void DecodeBlockAlpha3__single_pixel( @@ -89,9 +89,9 @@ void DecodeBlockAlpha4__single_pixel( short v); void EncodeBlockRGBColorKey( - struct s3tc_color colors[S3TC_BLOCK_PIXELS], - struct s3tc_block_rgb *block, - byte alpha_key); + struct s3tc_color colorSrc[S3TC_BLOCK_PIXELS], + struct s3tc_block_rgb *pblockDst, + byte alphaKey); void EncodeBlockRGB( struct s3tc_color colors[S3TC_BLOCK_PIXELS], struct s3tc_block_rgb *block); diff --git a/source/bungie_net/network/transport_endpoint.h b/source/bungie_net/network/transport_endpoint.h index 1be87380..b15f68b9 100644 --- a/source/bungie_net/network/transport_endpoint.h +++ b/source/bungie_net/network/transport_endpoint.h @@ -99,7 +99,7 @@ void disconnect_endpoint( struct transport_endpoint *endpoint); short poll_endpoint_set( struct transport_endpoint_set *set, - word timeout); + word millisec_timeout); void rewind_endpoint_set( struct transport_endpoint_set *set); struct transport_endpoint *get_next_endpoint_from_set( diff --git a/source/bungie_net/network/transport_endpoint_set_winsock.c b/source/bungie_net/network/transport_endpoint_set_winsock.c index 211687be..25509740 100644 --- a/source/bungie_net/network/transport_endpoint_set_winsock.c +++ b/source/bungie_net/network/transport_endpoint_set_winsock.c @@ -263,7 +263,7 @@ short transport_initialize( { if (!transport_initialized) { - WSADATA wsa_data = { 0 }; + WSADATA info = { 0 }; XNetStartupParams startup_params = { 0 }; DWORD link_status; DWORD address_status; @@ -301,7 +301,7 @@ short transport_initialize( if (XNetStartup(&startup_params) != 0) return _transport_error_not_initialized; - wsa_error = WSAStartup(MAKEWORD(2, 0), &wsa_data); + wsa_error = WSAStartup(MAKEWORD(2, 0), &info); if (wsa_error != 0) { XNetCleanup(); @@ -495,7 +495,7 @@ static int __cdecl poll_ep_array_compare_proc( short poll_endpoint_set( struct transport_endpoint_set *set, - word timeout) + word millisec_timeout) { short result = _transport_error_none; struct timeval timeout_value; @@ -512,7 +512,7 @@ short poll_endpoint_set( 0x1DE, transport_initialized); - timeout_value.tv_usec = timeout * MILLISECONDS_PER_SECOND; + timeout_value.tv_usec = millisec_timeout * MILLISECONDS_PER_SECOND; timeout_value.tv_sec = 0; if (set->needs_compaction) diff --git a/source/cache/xbox_sound_cache.c b/source/cache/xbox_sound_cache.c index a7ec2126..6a897214 100644 --- a/source/cache/xbox_sound_cache.c +++ b/source/cache/xbox_sound_cache.c @@ -191,9 +191,9 @@ static void sound_cache_delete_block_proc( /* ---------- globals */ -extern short assertion_count; -extern boolean debug_sound_cache; -extern boolean debug_sound_reference_counts; +short assertion_count; +boolean debug_sound_cache; +boolean debug_sound_reference_counts; static struct xbox_sound_cache_globals xbox_sound_cache_globals = { 0 }; /* ---------- public code */ @@ -633,34 +633,39 @@ static void render_inverse_transform_screen_point( { real screen_x; real screen_y; - real_vector3d delta0; - real_vector3d delta1; - real_point3d point; + real_vector3d top_edge; + real_vector3d left_edge; + real_point3d temp_point; - screen_x = screen_position->x * (1.0f / 640.0f); - screen_y = 1.0f - screen_position->y * (1.0f / 480.0f); - add_vectors3d( - (real_vector3d const *)&render.frustum.world_vertices[4], + screen_x = screen_position->x / 640.0f; + screen_y = 1.0f - screen_position->y / 480.0f; + point_from_line3d( + &render.frustum.world_vertices[4], global_zero_vector3d, - (real_vector3d *)world_position); - - delta0.i = render.frustum.world_vertices[1].n[0] - render.frustum.world_vertices[0].n[0]; - delta0.j = render.frustum.world_vertices[1].n[1] - render.frustum.world_vertices[0].n[1]; - delta0.k = render.frustum.world_vertices[1].n[2] - render.frustum.world_vertices[0].n[2]; - delta1.i = render.frustum.world_vertices[2].n[0] - render.frustum.world_vertices[0].n[0]; - delta1.j = render.frustum.world_vertices[2].n[1] - render.frustum.world_vertices[0].n[1]; - delta1.k = render.frustum.world_vertices[2].n[2] - render.frustum.world_vertices[0].n[2]; - - point.x = delta0.i * screen_x + render.frustum.world_vertices[0].n[0]; - point.y = delta0.j * screen_x + render.frustum.world_vertices[0].n[1]; - point.z = delta0.k * screen_x + render.frustum.world_vertices[0].n[2]; - point.x = delta1.i * screen_y + point.x; - point.y = delta1.j * screen_y + point.y; - point.z = delta1.k * screen_y + point.z; - - world_vector->i = point.x - world_position->x; - world_vector->j = point.y - world_position->y; - world_vector->k = point.z - world_position->z; + 1.0f, + world_position); + vector_from_points3d( + &render.frustum.world_vertices[0], + &render.frustum.world_vertices[1], + &top_edge); + vector_from_points3d( + &render.frustum.world_vertices[0], + &render.frustum.world_vertices[2], + &left_edge); + point_from_line3d( + &render.frustum.world_vertices[0], + &top_edge, + screen_x, + &temp_point); + point_from_line3d( + &temp_point, + &left_edge, + screen_y, + &temp_point); + vector_from_points3d( + world_position, + &temp_point, + world_vector); return; } @@ -668,59 +673,55 @@ static void render_inverse_transform_screen_point( void sound_cache_debug_render( void) { - byte page_usage[1024]; - real_point3d world_positions[2]; - real_point2d screen_positions[2]; - real_argb_color const *colors[4]; - real_vector3d world_vector; - long page_index; - long state_index; - if (debug_sound_cache) { + short rows = 1024 / 640; + byte page_usage[1024]; + long x; + real_argb_color const *colors[4]; + colors[0] = global_real_argb_red; colors[1] = global_real_argb_green; colors[2] = global_real_argb_blue; colors[3] = global_real_argb_yellow; - lruv_cache_get_page_usage(xbox_sound_cache_globals.cache, page_usage); - for (page_index = 0; page_index < 640; page_index++) + for (x = 0; x < 640; x++) { - for (state_index = 0; state_index < 4; state_index++) + short page_index = rows * x; + long bit; + + for (bit = 0; bit < 4; bit++) { - if (page_usage[(short)page_index] & FLAG(state_index)) + if (TEST_FLAG(page_usage[page_index], bit)) { - long row; - long point_index; - real distance; - real scale; + real_point3d extent[2]; + real_point2d line_pt[2]; + long i; + real_vector3d vec; - row = (state_index + (page_index / 640) * 4) * 10; - screen_positions[0].x = - screen_positions[1].x = (real)(page_index % 640); - screen_positions[0].y = (real)row; - screen_positions[1].y = (real)(row + 10); - distance = render.camera.z_near + 0.001f; - - for (point_index = 0; point_index < 2; point_index++) + line_pt[0].x = (real)(x % 640); + line_pt[0].y = (real)((bit + (x / 640) * 4) * 10); + line_pt[1].x = (real)(x % 640); + line_pt[1].y = (real)((bit + (x / 640) * 4 + 1) * 10); + for (i = 0; i < 2; i++) { render_inverse_transform_screen_point( - &screen_positions[point_index], - &world_positions[point_index], - &world_vector); - scale = distance / - dot_product3d(&render.camera.forward, &world_vector); - world_positions[point_index].x += world_vector.i * scale; - world_positions[point_index].y += world_vector.j * scale; - world_positions[point_index].z += world_vector.k * scale; + &line_pt[i], + &extent[i], + &vec); + point_from_line3d( + &extent[i], + &vec, + (render.camera.z_near + 0.001f) / dot_product3d(&vec, &render.camera.forward), + &extent[i]); } render_debug_line( TRUE, - &world_positions[0], - &world_positions[1], - colors[state_index]); + &extent[0], + &extent[1], + colors[bit]); } } } diff --git a/source/camera/director.c b/source/camera/director.c index b835a2f3..0106c1af 100644 --- a/source/camera/director.c +++ b/source/camera/director.c @@ -224,6 +224,7 @@ static struct director_variable_definition variables[NUMBER_OF_DIRECTOR_VARIABLE static struct director_globals director_globals = {0}; boolean director_camera_switch_fast = FALSE; static boolean hyper_key_down = FALSE; +boolean *director_camera_scripted; /* ---------- public code */ @@ -237,8 +238,8 @@ static struct director *director_get( void director_initialize( void) { - director_camera_scripted = game_state_malloc("director scripting", NULL, sizeof(*director_camera_scripted)); - director_camera_scripted->camera_scripted = FALSE; + director_camera_scripted = game_state_malloc("director scripting", NULL, 4); + *director_camera_scripted = FALSE; return; } @@ -262,7 +263,7 @@ void director_dispose_from_old_map( director->debug_controls = FALSE; } - director_camera_scripted->camera_scripted = FALSE; + *director_camera_scripted = FALSE; return; } @@ -653,7 +654,7 @@ void director_script_camera( { short local_player_index; - director_camera_scripted->camera_scripted = scripted; + *director_camera_scripted = scripted; for (local_player_index = 0; local_player_index < MAXIMUM_NUMBER_OF_LOCAL_PLAYERS; local_player_index++) @@ -701,7 +702,7 @@ static void director_choose_camera_game( if (key) director_rotate_cameras(local_player_index, director_game_camera_modes, 3); - if (!director_camera_scripted->camera_scripted) + if (!*director_camera_scripted) { director_choose_game_perspective(local_player_index, initialize); if (use_dead_camera) @@ -1039,7 +1040,7 @@ void director_initialize_for_saved_game( void) { director_initialize_for_new_map(); - director_script_camera(director_camera_scripted->camera_scripted); + director_script_camera(*director_camera_scripted); return; } diff --git a/source/camera/director.h b/source/camera/director.h index 9d872f08..7c8f4292 100644 --- a/source/camera/director.h +++ b/source/camera/director.h @@ -66,12 +66,6 @@ typedef void (*director_camera_update_proc)( void *command, void *result); -struct director_scripting_globals -{ - boolean camera_scripted; - byte pad[3]; -}; - struct director_variable_instance { real value; @@ -165,7 +159,7 @@ void director_update( /* ---------- globals */ -extern struct director_scripting_globals *director_camera_scripted; +extern boolean *director_camera_scripted; extern boolean director_camera_switch_fast; /* ---------- public code */ diff --git a/source/cutscene/cinematics.c b/source/cutscene/cinematics.c index 0184ff1e..f2d13e18 100644 --- a/source/cutscene/cinematics.c +++ b/source/cutscene/cinematics.c @@ -424,21 +424,21 @@ void cinematic_render( } { - real_argb_color color; + real_argb_color text_color; long shadow_alpha; pixel32_to_real_argb_color( title->foreground_color, - &color); - color.alpha *= fade_amount; + &text_color); + text_color.alpha *= fade_amount; - if (fabs(color.red - 1.0f) < _real_epsilon && - fabs(color.green - 1.0f) < _real_epsilon && - fabs(color.blue - 1.0f) < _real_epsilon) + if (fabs(text_color.red - 1.0f) < _real_epsilon && + fabs(text_color.green - 1.0f) < _real_epsilon && + fabs(text_color.blue - 1.0f) < _real_epsilon) { - color.red = MIN(color.red, 0.8f); - color.green = MIN(color.green, 0.8f); - color.blue = MIN(color.blue, 0.8f); + text_color.red = MIN(text_color.red, 0.8f); + text_color.green = MIN(text_color.green, 0.8f); + text_color.blue = MIN(text_color.blue, 0.8f); } draw_string_set_draw_mode( @@ -446,7 +446,7 @@ void cinematic_render( title->style - 1, title->justification, title->text_flags, - &color); + &text_color); shadow_alpha = PIN( fast_ftol( diff --git a/source/effects/decals.c b/source/effects/decals.c index 9071b9ad..b5b626d1 100644 --- a/source/effects/decals.c +++ b/source/effects/decals.c @@ -483,6 +483,7 @@ struct decal_wrap_parameters const decal_wrap_parameters[NUMBER_OF_DECAL_TYPES] /* SECONDS_PER_TICK: name from the 2003 PC demo PDB and the HCEX PDB (decals file static const float) */ static real const SECONDS_PER_TICK = 1.0f / TICKS_PER_SECOND; +boolean debug_decals; /* ---------- public code */ @@ -1836,13 +1837,13 @@ void decal_new_from_collision( &collision_bsp->surfaces, deviant_surface, struct collision_surface); - real_plane3d surface_plane; + real_plane3d surface_plane1; short next_deviant_surface_index; bsp3d_get_plane_from_designator( &collision_bsp->bsp3d, surface->plane_designator, - &surface_plane); + &surface_plane1); match_assert("c:\\halo\\SOURCE\\effects\\decals.c", 2399, deviant_surface_bunch_sizesurfaces, next_deviant_surface, struct collision_surface); - real_plane3d next_surface_plane; + real_plane3d surface_plane2; real angle; bsp3d_get_plane_from_designator( &collision_bsp->bsp3d, next_surface->plane_designator, - &next_surface_plane); + &surface_plane2); - angle = angle_between_normals3d(&surface_plane.n, &next_surface_plane.n); + angle = angle_between_normals3d(&surface_plane1.n, &surface_plane2.n); if (angle<=DEGREES_TO_RADIANS(decal_wrap_parameters[definition->type].minimum_wrap_angle)) { match_assert("c:\\halo\\SOURCE\\effects\\decals.c", 2422, @@ -1884,9 +1885,9 @@ void decal_new_from_collision( long closest_surface_index = NONE; real closest_minimum_distance; real closest_maximum_distance; - real_plane3d closest_surface_plane; - real_point3d closest_edge_start; - real_point3d closest_edge_end; + real_plane3d closest_plane; + real_point3d closest_vertex1; + real_point3d closest_vertex2; short bunch_index; for (bunch_index = 0; @@ -1933,11 +1934,11 @@ void decal_new_from_collision( bsp3d_get_plane_from_designator( &collision_bsp->bsp3d, bunch_surface->plane_designator, - &closest_surface_plane); + &closest_plane); closest_minimum_distance = minimum_distance; closest_maximum_distance = maximum_distance; - closest_edge_start = edge_start->point; - closest_edge_end = edge_end->point; + closest_vertex1 = edge_start->point; + closest_vertex2 = edge_end->point; closest_surface_index = bunch_surface_index; } @@ -1953,46 +1954,46 @@ void decal_new_from_collision( struct decal_projection wrapped_projection; real_vector3d edge_axis; - vector_from_points3d(&closest_edge_start, &closest_edge_end, &edge_axis); + vector_from_points3d(&closest_vertex1, &closest_vertex2, &edge_axis); if (normalize3d(&edge_axis) > 0.0f) { real sign = triple_product3d( - &closest_surface_plane.n, + &closest_plane.n, &projection.plane.n, &edge_axis) < 0.0f ? 1.0f : -1.0f; real angle; - real_matrix4x3 rotation; - real_matrix4x3 wrapped_basis; + real_matrix4x3 wrap_rotation; + real_matrix4x3 wrap_basis; angle = angle_between_normals3d( - &closest_surface_plane.n, + &closest_plane.n, &projection.plane.n) * sign; matrix4x3_rotation_from_axis_and_angle( - &rotation, + &wrap_rotation, &edge_axis, (real)sin(angle), (real)cos(angle)); - wrapped_basis.position.x = basis.position.x - closest_edge_start.x; - wrapped_basis.position.y = basis.position.y - closest_edge_start.y; - wrapped_basis.position.z = basis.position.z - closest_edge_start.z; - matrix4x3_transform_point(&rotation, &wrapped_basis.position, &wrapped_basis.position); - matrix4x3_transform_normal(&rotation, &basis.forward, &wrapped_basis.forward); - matrix4x3_transform_normal(&rotation, &basis.left, &wrapped_basis.left); - matrix4x3_transform_normal(&rotation, &basis.up, &wrapped_basis.up); - wrapped_basis.scale = 1.0f; - wrapped_basis.position.x += closest_edge_start.x; - wrapped_basis.position.y += closest_edge_start.y; - wrapped_basis.position.z += closest_edge_start.z; + wrap_basis.position.x = basis.position.x - closest_vertex1.x; + wrap_basis.position.y = basis.position.y - closest_vertex1.y; + wrap_basis.position.z = basis.position.z - closest_vertex1.z; + matrix4x3_transform_point(&wrap_rotation, &wrap_basis.position, &wrap_basis.position); + matrix4x3_transform_normal(&wrap_rotation, &basis.forward, &wrap_basis.forward); + matrix4x3_transform_normal(&wrap_rotation, &basis.left, &wrap_basis.left); + matrix4x3_transform_normal(&wrap_rotation, &basis.up, &wrap_basis.up); + wrap_basis.scale = 1.0f; + wrap_basis.position.x += closest_vertex1.x; + wrap_basis.position.y += closest_vertex1.y; + wrap_basis.position.z += closest_vertex1.z; - decal_projection_create(&wrapped_basis, &extent, &wrapped_projection); - normal_bounds.x0 = MIN(wrapped_basis.up.i, normal_bounds.x0); - normal_bounds.x1 = MAX(wrapped_basis.up.i, normal_bounds.x1); - normal_bounds.y0 = MIN(wrapped_basis.up.j, normal_bounds.y0); - normal_bounds.y1 = MAX(wrapped_basis.up.j, normal_bounds.y1); - normal_bounds.z0 = MIN(wrapped_basis.up.k, normal_bounds.z0); - normal_bounds.z1 = MAX(wrapped_basis.up.k, normal_bounds.z1); + decal_projection_create(&wrap_basis, &extent, &wrapped_projection); + normal_bounds.x0 = MIN(wrap_basis.up.i, normal_bounds.x0); + normal_bounds.x1 = MAX(wrap_basis.up.i, normal_bounds.x1); + normal_bounds.y0 = MIN(wrap_basis.up.j, normal_bounds.y0); + normal_bounds.y1 = MAX(wrap_basis.up.j, normal_bounds.y1); + normal_bounds.z0 = MIN(wrap_basis.up.k, normal_bounds.z0); + normal_bounds.z1 = MAX(wrap_basis.up.k, normal_bounds.z1); } else { @@ -2124,16 +2125,16 @@ void decal_new_from_collision( real intensity = real_local_random_range( definition->intensity_lower_bound, definition->intensity_upper_bound); - real_rgb_color color; + real_rgb_color decal_color; real interpolation = real_local_random_range(0.0f, 1.0f); rgb_colors_interpolate( - &color, + &decal_color, (definition->flags >> _decal_definition_color_interpolate_in_hsv_bit) & 3, &definition->color_lower_bound, &definition->color_upper_bound, interpolation); - decal->color = real_a_rgb_color_to_pixel32(intensity, &color); + decal->color = real_a_rgb_color_to_pixel32(intensity, &decal_color); decal->intensity = 255; } diff --git a/source/effects/effects.c b/source/effects/effects.c index 6b5232ce..26a2a2f8 100644 --- a/source/effects/effects.c +++ b/source/effects/effects.c @@ -546,7 +546,7 @@ static void impulse_effect_initialize( // effect_generate_part: the part definition and the location instance are passed in registers static void effect_generate_part( struct effect_datum const *effect, - struct effect_part_definition const *part, + struct effect_part_definition const *part_definition, struct effect_location_datum const *instance, real_point3d const *world_point, real_vector3d const *world_forward, @@ -651,7 +651,7 @@ static void effect_set_event( /* ---------- globals */ extern struct data_array *effect_data; -extern struct data_array *effect_location_data; +struct data_array *effect_location_data; boolean effects_corpse_nonviolent = TRUE; @@ -1605,7 +1605,7 @@ static void impulse_effect_initialize( static void effect_generate_part( struct effect_datum const *effect, - struct effect_part_definition const *part, + struct effect_part_definition const *part_definition, struct effect_location_datum const *instance, real_point3d const *world_point, real_vector3d const *world_forward, @@ -1615,14 +1615,14 @@ static void effect_generate_part( real_vector3d direction; real_vector3d velocity; - switch (part->runtime_base_class_tag) + switch (part_definition->runtime_base_class_tag) { case PARTICLE_SYSTEM_DEFINITION_TAG: { - real_argb_color color; + real_argb_color tint; - color.alpha = 1.0f; - color.rgb = effect->color; + tint.alpha = 1.0f; + tint.rgb = effect->color; effect_random_translational_velocity( get_global_local_random_seed_address(), @@ -1630,21 +1630,21 @@ static void effect_generate_part( world_forward, &direction, &velocity, - part->velocity_lower_bound, - part->velocity_upper_bound, - part->velocity_cone_angle, - part->scale_a_flags, - part->scale_b_flags); + part_definition->velocity_lower_bound, + part_definition->velocity_upper_bound, + part_definition->velocity_cone_angle, + part_definition->scale_a_flags, + part_definition->scale_b_flags); velocity.i += effect->velocity.i; velocity.j += effect->velocity.j; velocity.k += effect->velocity.k; particle_system_new_unattached( - part->reference.index, + part_definition->reference.index, world_point, &velocity, - &color, + &tint, scale); break; } @@ -1659,7 +1659,7 @@ static void effect_generate_part( object_impulse_sound_new( effect->object_index, - part->reference.index, + part_definition->reference.index, node_index, &instance->matrix.position, &instance->matrix.forward, @@ -1675,7 +1675,7 @@ static void effect_generate_part( location.game_location = effect->location; unattached_impulse_sound_new( - part->reference.index, + part_definition->reference.index, &location, scale); } @@ -1683,45 +1683,45 @@ static void effect_generate_part( case OBJECT_DEFINITION_TAG: { - struct object_placement_data placement; + struct object_placement_data data; unsigned long *seed; object_placement_data_new( - &placement, - part->reference.index, + &data, + part_definition->reference.index, effect->owner_object_index); - placement.position = *world_point; - placement.forward = *world_forward; - placement.up = *world_up; + data.position = *world_point; + data.forward = *world_forward; + data.up = *world_up; effect_random_translational_velocity( get_global_random_seed_address(), effect, world_forward, &direction, - &placement.translational_velocity, - part->velocity_lower_bound, - part->velocity_upper_bound, - part->velocity_cone_angle, - part->scale_a_flags, - part->scale_b_flags); + &data.translational_velocity, + part_definition->velocity_lower_bound, + part_definition->velocity_upper_bound, + part_definition->velocity_cone_angle, + part_definition->scale_a_flags, + part_definition->scale_b_flags); - placement.translational_velocity.i += effect->velocity.i; - placement.translational_velocity.j += effect->velocity.j; - placement.translational_velocity.k += effect->velocity.k; + data.translational_velocity.i += effect->velocity.i; + data.translational_velocity.j += effect->velocity.j; + data.translational_velocity.k += effect->velocity.k; seed = get_global_random_seed_address(); effect_random_angular_velocity( seed, effect, - &placement.angular_velocity, - part->angular_velocity_lower_bound, - part->angular_velocity_upper_bound, - part->scale_a_flags, - part->scale_b_flags); + &data.angular_velocity, + part_definition->angular_velocity_lower_bound, + part_definition->angular_velocity_upper_bound, + part_definition->scale_a_flags, + part_definition->scale_b_flags); - object_new(&placement); + object_new(&data); break; } @@ -1735,19 +1735,19 @@ static void effect_generate_part( world_forward, &direction, &velocity, - part->velocity_lower_bound, - part->velocity_upper_bound, - part->velocity_cone_angle, - part->scale_a_flags, - part->scale_b_flags); + part_definition->velocity_lower_bound, + part_definition->velocity_upper_bound, + part_definition->velocity_cone_angle, + part_definition->scale_a_flags, + part_definition->scale_b_flags); radius_modifier = real_seed_random_range( get_global_local_random_seed_address(), - part->radius_modifier_lower_bound, - part->radius_modifier_upper_bound); + part_definition->radius_modifier_lower_bound, + part_definition->radius_modifier_upper_bound); decal_new( - part->reference.index, + part_definition->reference.index, world_point, &velocity, radius_modifier, @@ -1763,7 +1763,7 @@ static void effect_generate_part( struct object_datum *owner = object_try_and_get(effect->owner_object_index); - damage_data_new(&damage, part->reference.index); + damage_data_new(&damage, part_definition->reference.index); if (owner) { @@ -1790,7 +1790,7 @@ static void effect_generate_part( node_index &= (short)(FLAG(_effect_location_first_person_bit) - 1); light_new_unattached( - part->reference.index, + part_definition->reference.index, effect->object_index, node_index, &instance->matrix.position, @@ -1808,7 +1808,7 @@ static void effect_generate_part( temporary, "effect %s has a bad part %s", tag_get_name(effect->definition_index), - part->reference.name)); + part_definition->reference.name)); break; } @@ -1995,9 +1995,9 @@ static void effect_generate_particles( instance_particle_index++) { struct new_particle_data data; - real_vector3d random_direction; - real_vector3d emission_offset; - real_point3d world_position; + real_vector3d random_offset; + real_vector3d relative_offset; + real_point3d world_point; real_vector3d world_direction; real_vector3d world_velocity; real emission_radius = effect_real_random_range( @@ -2009,18 +2009,18 @@ static void effect_generate_particles( particles->scale_b_flags, _effect_particle_distribution_radius_bit); - local_random_direction3d(&random_direction); + local_random_direction3d(&random_offset); matrix4x3_transform_vector( &instance->matrix, &particles->offset, - &emission_offset); + &relative_offset); data.position.x = instance->matrix.position.x + - random_direction.i * emission_radius + emission_offset.i; + random_offset.i * emission_radius + relative_offset.i; data.position.y = instance->matrix.position.y + - random_direction.j * emission_radius + emission_offset.j; + random_offset.j * emission_radius + relative_offset.j; data.position.z = instance->matrix.position.z + - random_direction.k * emission_radius + emission_offset.k; + random_offset.k * emission_radius + relative_offset.k; effect_random_translational_velocity( get_global_local_random_seed_address(), @@ -2052,7 +2052,7 @@ static void effect_generate_particles( matrix4x3_transform_point( node_matrix, &data.position, - &world_position); + &world_point); matrix4x3_transform_normal( node_matrix, &data.direction, @@ -2064,7 +2064,7 @@ static void effect_generate_particles( } else { - world_position = data.position; + world_point = data.position; world_direction = data.direction; world_velocity = data.velocity; } @@ -2072,7 +2072,7 @@ static void effect_generate_particles( if (effect_allowed_by_environment( particles->environment, &effect->location, - &world_position)) + &world_point)) { data.definition_index = particles->particle.index; @@ -2093,7 +2093,7 @@ static void effect_generate_particles( { effect->impulse_field.translational_function( &data.initial_impulse, - &world_position, + &world_point, effect->impulse_field.user_data); } else @@ -2102,7 +2102,7 @@ static void effect_generate_particles( } data.object_index = NONE; - data.position = world_position; + data.position = world_point; data.direction = world_direction; data.velocity.i = world_velocity.i + effect->velocity.i * 30.0f; data.velocity.j = world_velocity.j + effect->velocity.j * 30.0f; diff --git a/source/effects/particle_systems.c b/source/effects/particle_systems.c index 98a47e6d..0a914701 100644 --- a/source/effects/particle_systems.c +++ b/source/effects/particle_systems.c @@ -194,6 +194,8 @@ static particle_system_particle_update_proc const particle_update_functions[] = real const ground_error = 0.05f; static real const seconds_per_tick = 1.0f/TICKS_PER_SECOND; +struct data_array *particle_systems; +struct data_array *system_particles; /* ---------- public code */ diff --git a/source/effects/player_effects.c b/source/effects/player_effects.c index 2c00b34a..90ebc724 100644 --- a/source/effects/player_effects.c +++ b/source/effects/player_effects.c @@ -356,11 +356,11 @@ void player_effect_dispose_from_old_map( void player_effect_add_continuous_effect( short local_player_index, - long definition_index, + long effect_index, real distance) { struct continuous_damage_effect_definition *definition = - continuous_damage_effect_definition_get(definition_index); + continuous_damage_effect_definition_get(effect_index); if (distance < definition->cutoff_radius) { diff --git a/source/effects/player_effects.h b/source/effects/player_effects.h index 1dbd70a8..4f96a772 100644 --- a/source/effects/player_effects.h +++ b/source/effects/player_effects.h @@ -39,7 +39,7 @@ void player_effect_dispose_from_old_map( void); void player_effect_add_continuous_effect( short local_player_index, - long definition_index, + long effect_index, real distance); void player_effect_update( void); diff --git a/source/effects/weather_particle_systems.c b/source/effects/weather_particle_systems.c index a5be718e..3bfe15fb 100644 --- a/source/effects/weather_particle_systems.c +++ b/source/effects/weather_particle_systems.c @@ -311,6 +311,7 @@ real const one_over_char_max = 1.f/255.f; boolean weather = TRUE; static struct weather_particle_system_globals weather_particle_system_globals = { 0 }; +struct data_array *weather_particle_data; /* ---------- public code */ @@ -547,7 +548,7 @@ static void weather_particle_system_render( { struct weather_particle_system *system = weather_particle_system_get(local_player_index); struct weather_particle_system_definition *definition = weather_particle_system_definition_get(system->definition_index); - struct structure_bsp *structure_bsp = global_structure_bsp_get(); + struct structure_bsp *structure = global_structure_bsp_get(); short type_index; weather_particle_system_update(local_player_index); @@ -562,11 +563,11 @@ static void weather_particle_system_render( if (type->particle_count) { - real_plane3d clipping_planes[NUMBER_OF_WEATHER_PARTICLE_CLIPPING_PLANES]; + real_plane3d clip_planes[NUMBER_OF_WEATHER_PARTICLE_CLIPPING_PLANES]; real_point3d box_positions[MAXIMUM_NUMBER_OF_VISIBLE_WEATHER_PARTICLE_BOXES]; - real box_plane_distances[MAXIMUM_NUMBER_OF_VISIBLE_WEATHER_PARTICLE_BOXES][NUMBER_OF_WEATHER_PARTICLE_CLIPPING_PLANES]; - short visible_polyhedron_indices[MAXIMUM_NUMBER_OF_VISIBLE_WEATHER_POLYHEDRA]; - short visible_polyhedron_count = weather_polyhedra_find(visible_polyhedron_indices, type->box_width); + real clip_plane_d_transforms[MAXIMUM_NUMBER_OF_VISIBLE_WEATHER_PARTICLE_BOXES][NUMBER_OF_WEATHER_PARTICLE_CLIPPING_PLANES]; + short weather_polyhedra_indices[MAXIMUM_NUMBER_OF_VISIBLE_WEATHER_POLYHEDRA]; + short visible_polyhedron_count = weather_polyhedra_find(weather_polyhedra_indices, type->box_width); struct build_sprite_data sprite_data; struct weather_particle *particle; real box_offsets[3]; @@ -575,9 +576,9 @@ static void weather_particle_system_render( short i, j, k; long particle_index; - weather_particle_system_build_clipping_planes(clipping_planes, type->box_width); + weather_particle_system_build_clipping_planes(clip_planes, type->box_width); weather_particle_system_box_offset_from_point3d(type->box_width, &render.camera.position, &box_positions[0]); - weather_particle_system_transform_clip_planes_to_box(box_plane_distances[0], clipping_planes, &box_positions[0]); + weather_particle_system_transform_clip_planes_to_box(clip_plane_d_transforms[0], clip_planes, &box_positions[0]); bounds.x0 = box_positions[0].x; bounds.x1 = box_positions[0].x + type->box_width; @@ -614,7 +615,7 @@ static void weather_particle_system_render( box_positions[box_count].x = box_bounds.x0; box_positions[box_count].y = box_bounds.y0; box_positions[box_count].z = box_bounds.z0; - weather_particle_system_transform_clip_planes_to_box(box_plane_distances[box_count], clipping_planes, &box_positions[box_count]); + weather_particle_system_transform_clip_planes_to_box(clip_plane_d_transforms[box_count], clip_planes, &box_positions[box_count]); box_count++; } } @@ -626,7 +627,7 @@ static void weather_particle_system_render( for (particle_index = type->first_particle_index; particle_index!=NONE; particle_index = particle->next_particle_index) { - real particle_plane_distances[NUMBER_OF_WEATHER_PARTICLE_CLIPPING_PLANES]; + real plane_evaluations[NUMBER_OF_WEATHER_PARTICLE_CLIPPING_PLANES]; short plane_index; short box_index; @@ -634,7 +635,7 @@ static void weather_particle_system_render( for (plane_index = 0; plane_indexposition); + plane_evaluations[plane_index] = plane3d_distance_to_point(&clip_planes[plane_index], &particle->position); } for (box_index = 0; box_indexweather_polyhedra, - visible_polyhedron_indices[polyhedron_index], + &structure->weather_polyhedra, + weather_polyhedra_indices[polyhedron_index], struct structure_weather_polyhedron); short polyhedron_plane_index; diff --git a/source/game/game.c b/source/game/game.c index 4adf61a3..b046f922 100644 --- a/source/game/game.c +++ b/source/game/game.c @@ -119,9 +119,7 @@ struct game_options; /* ---------- headers */ #include "cseries/cseries.h" -#define set_random_seed set_random_seed_inline #include "game/game.h" -#undef set_random_seed #include "ai/ai.h" #include "bink/bink_playback.h" #include "bungie_net/network/transport.h" @@ -525,14 +523,6 @@ boolean game_is_cooperative( return player_spawn_count > 1; } -void set_random_seed( - unsigned long seed) -{ - *get_global_random_seed_address() = seed; - - return; -} - boolean game_load( struct game_options *options) { @@ -562,8 +552,6 @@ boolean game_load( void game_initialize_for_new_map( void) { - unsigned long random_seed; - match_assert( "c:\\halo\\SOURCE\\game\\game.c", 0x1D1, @@ -573,8 +561,7 @@ void game_initialize_for_new_map( 0x1D2, !game_globals->active); - random_seed = game_globals->options.random_seed; - *get_global_random_seed_address() = random_seed; + set_random_seed(game_globals->options.random_seed); game_engine_dispose(); game_engine_initialize(&game_variant_global); real_math_reset_precision(); diff --git a/source/game/game_engine_king.c b/source/game/game_engine_king.c index 561c1a4f..82005f18 100644 --- a/source/game/game_engine_king.c +++ b/source/game/game_engine_king.c @@ -90,6 +90,7 @@ symbols in this file: #include "math/geometry.h" #include "rasterizer/rasterizer.h" #include "rasterizer/rasterizer_geometry.h" +#include "rasterizer/rasterizer_model_types.h" #include "rasterizer/rasterizer_models.h" #include "render/render.h" #include "scenario/scenario.h" @@ -145,56 +146,11 @@ enum /* ---------- structures */ -/* Target-proven vertex layouts used by this translation unit's quad helper. */ -struct model_vertex_uncompressed -{ - real_point3d position; - real_vector3d normal; - real_vector3d binormal; - real_vector3d tangent; - real_point2d texcoord; - short nodes[2]; - real node_weights[2]; -}; - -struct model_vertex_compressed -{ - real_point3d position; - unsigned long normal; - unsigned long binormal; - unsigned long tangent; - point2d texcoord; - byte nodes[2]; - short node_weight; -}; - typedef char verify_model_vertex_uncompressed_size[ sizeof(struct model_vertex_uncompressed) == 0x44 ? 1 : -1]; typedef char verify_model_vertex_compressed_size[ sizeof(struct model_vertex_compressed) == 0x20 ? 1 : -1]; -/* January-local render packet layouts used by render_dynamic_quad. */ -struct render_model_effect -{ - short type; - word pad; - real intensity; - byte reserved[0x20]; -}; - -struct rasterizer_model_begin_parameters -{ - unsigned long geometry_flags; - long unique_identifier; - struct render_skinning skinning; - struct render_lighting lighting; - struct render_animation animation; - struct render_model_effect effect; - real_point3d centroid; - real radius; - real_vector2d base_map_scale; -}; - typedef char verify_rasterizer_model_begin_parameters_size[ sizeof(struct rasterizer_model_begin_parameters) == 0xCC ? 1 : -1]; @@ -222,8 +178,8 @@ static void king_calculate_hill_state( /* ---------- globals */ /* Shared rasterizer defaults, named by the January image. */ -extern real_rgb_color global_default_animation_colors[4]; -extern real global_default_animation_values[4]; +real_rgb_color global_default_animation_colors[4]; +real global_default_animation_values[4]; static struct king_globals king_globals = { 0 }; /* king_engine_num_hills: name from the 2003 PC demo PDB (file static short at king_globals+0x1AC), diff --git a/source/game/players.c b/source/game/players.c index 59118c93..1f79229f 100644 --- a/source/game/players.c +++ b/source/game/players.c @@ -309,15 +309,6 @@ struct scenario_bsp_switch_trigger_volume short cutscene_flag_index; }; -struct scenario_cutscene_flag -{ - long runtime_unused; - char name[TAG_STRING_LENGTH]; - real_point3d position; - real_euler_angles2d facing; - byte unused[0x24]; -}; - struct unit_control_data { char animation_state; @@ -2981,18 +2972,18 @@ static void player_examine_nearby_device( struct player_datum *player; struct unit_datum *unit; struct device_datum *device; - real_point3d camera_position; + real_point3d camera; player = player_get(player_index); unit = unit_get(player->unit_index); device = device_get(device_index); - unit_get_camera_position(player->unit_index, &camera_position); + unit_get_camera_position(player->unit_index, &camera); if (fast_vector_intersects_sphere( - &camera_position, + &camera, &unit->unit.aiming_vector, &device->object.bounding_sphere_center, device->object.bounding_sphere_radius) && - device_frontfacing(device_index, &camera_position, &unit->unit.aiming_vector) && + device_frontfacing(device_index, &camera, &unit->unit.aiming_vector) && device_can_change_position(device_index)) { player_set_action_result( diff --git a/source/hs/hs_compile.c b/source/hs/hs_compile.c index 5171a3be..b77588b2 100644 --- a/source/hs/hs_compile.c +++ b/source/hs/hs_compile.c @@ -2424,8 +2424,8 @@ static boolean hs_parse_nonprimitive( } boolean hs_compile_postprocess( - char const **error_message, - char const **error_source) + char const **error_message_pointer, + char const **error_source_pointer) { boolean success = TRUE; long expression_index; @@ -2437,8 +2437,8 @@ boolean hs_compile_postprocess( global_scenario_get()->hs_string_constants.size - HS_MAXIMUM_DYNAMIC_SOURCE_DATA_BYTES; hs_compile_globals.error = NULL; hs_compile_globals.variables_predetermined = TRUE; - *error_message = NULL; - *error_source = NULL; + *error_message_pointer = NULL; + *error_source_pointer = NULL; for (expression_index = data_next_index(hs_syntax_data, NONE); success && expression_index != NONE; @@ -2537,9 +2537,9 @@ boolean hs_compile_postprocess( if (!success) { - *error_message = hs_compile_globals.error; + *error_message_pointer = hs_compile_globals.error; if (hs_compile_globals.error_offset != NONE) - *error_source = hs_compile_globals.compiled_source + hs_compile_globals.error_offset; + *error_source_pointer = hs_compile_globals.compiled_source + hs_compile_globals.error_offset; } hs_compile_globals.compiled_source = NULL; diff --git a/source/hs/hs_library_external.c b/source/hs/hs_library_external.c index e9c465a6..bee90038 100644 --- a/source/hs/hs_library_external.c +++ b/source/hs/hs_library_external.c @@ -118,15 +118,6 @@ symbols in this file: /* ---------- structures */ -struct scenario_cutscene_flag -{ - long runtime_unused; - char name[TAG_STRING_LENGTH]; - real_point3d position; - real_euler_angles2d facing; - byte unused[0x24]; -}; - struct hs_sound_definition { byte unused00[0x28]; diff --git a/source/hs/hs_runtime.c b/source/hs/hs_runtime.c index 2fb40de0..51e5b910 100644 --- a/source/hs/hs_runtime.c +++ b/source/hs/hs_runtime.c @@ -527,13 +527,14 @@ static void hs_global_reconcile_write( /* ---------- globals */ -extern struct data_array *hs_global_data; -extern struct data_array *hs_thread_data; +struct data_array *hs_global_data; +struct data_array *hs_thread_data; extern struct data_array *hs_syntax_data; extern short const hs_external_global_count; extern short const hs_type_sizes[NUMBER_OF_HS_TYPES]; -extern boolean debug_scripting; -extern unsigned long hs_debug_data[]; +boolean debug_scripting; +unsigned long hs_debug_data[BIT_VECTOR_SIZE_IN_LONGS(MAXIMUM_TRIGGER_VOLUMES_PER_SCENARIO)]; +typedef char verify_hs_debug_data_size[sizeof(hs_debug_data) == 0x20 ? 1 : -1]; static hs_inspection_procedure hs_type_inspectors[NUMBER_OF_HS_TYPES] = { NULL, @@ -715,6 +716,7 @@ extern long const _hs_type_weapon_default; extern long const _hs_type_device_default; extern long const _hs_type_scenery_default; extern short const _hs_type_object_name_default; +boolean debug_trigger_volumes; /* ---------- public code */ diff --git a/source/interface/first_person_weapons.c b/source/interface/first_person_weapons.c index 06b0a72c..e6ca320e 100644 --- a/source/interface/first_person_weapons.c +++ b/source/interface/first_person_weapons.c @@ -117,6 +117,7 @@ symbols in this file: #include "models/models.h" #include "networking/network_connection.h" #include "objects/objects.h" +#include "rasterizer/rasterizer_model_types.h" #include "render/render.h" #include "saved games/game_state.h" #include "scenario/scenario.h" @@ -229,19 +230,6 @@ struct animation_graph_node typedef char verify_animation_graph_node_size[ sizeof(struct animation_graph_node) == 0x40 ? 1 : -1]; -/* TU-private rendering packet layout, also recovered independently by the rendering owners. */ -struct render_model_effect -{ - short type; - word pad; - real intensity; - real parameter; - long source_object_index; - real_point3d source_object_centroid; - struct shader const *modifier_shader; - byte reserved0020[8]; /* render_animation modifier_animation */ -}; - typedef char verify_render_model_effect_size[ sizeof(struct render_model_effect) == 0x28 ? 1 : -1]; diff --git a/source/interface/hud.c b/source/interface/hud.c index 2eedfe4e..935a70d8 100644 --- a/source/interface/hud.c +++ b/source/interface/hud.c @@ -203,7 +203,7 @@ static void temporary_hud_draw( struct hud_globals_definition *hud_globals = NULL; struct hud_scripted_globals_definition *hud_scripted_globals = NULL; -extern boolean temporary_hud; +boolean temporary_hud; static wchar_t const *default_string = L""; diff --git a/source/interface/hud_messaging.c b/source/interface/hud_messaging.c index 20a816c9..1413e765 100644 --- a/source/interface/hud_messaging.c +++ b/source/interface/hud_messaging.c @@ -473,7 +473,7 @@ static void render_state_bitmap( /* ---------- globals */ static struct hud_messaging_globals_definition *hud_messaging_globals; -extern struct hud_messaging_parameters_definition *hud_msg_def; +struct hud_messaging_parameters_definition *hud_msg_def; static char button_mappings[_icon_custom_1 - _icon_action] = { 2, diff --git a/source/interface/hud_nav_points.c b/source/interface/hud_nav_points.c index e4d21d01..c0718e75 100644 --- a/source/interface/hud_nav_points.c +++ b/source/interface/hud_nav_points.c @@ -201,15 +201,6 @@ struct hud_nav_point_player_datum struct hud_nav_point_datum nav_points[MAXIMUM_NUMBER_OF_NAV_POINTS]; }; -struct scenario_cutscene_flag -{ - long runtime_unused; - char name[TAG_STRING_LENGTH]; - real_point3d position; - real_euler_angles2d facing; - byte unused[0x24]; -}; - struct hud_nav_object_datum { byte unused[0xB6]; @@ -687,7 +678,7 @@ void custom_render_nav_point( real_point3d view_point; real distance; real arrow_scale; - real_point2d screen_point; + real_point2d screen_position; real horizontal_radius; real vertical_radius; real vertical_component; @@ -707,16 +698,16 @@ void custom_render_nav_point( long unit_index = local_player_get_player_index(local_player_index)==NONE ? NONE : player_get(local_player_get_player_index(local_player_index))->unit_index; - real_point3d camera_position; + real_point3d cam_pos; real delta_x; real delta_y; real delta_z; - unit_get_camera_position(unit_index, &camera_position); + unit_get_camera_position(unit_index, &cam_pos); - delta_x = position->x-camera_position.x; - delta_y = position->y-camera_position.y; - delta_z = position->z-camera_position.z; + delta_x = position->x-cam_pos.x; + delta_y = position->y-cam_pos.y; + delta_z = position->z-cam_pos.z; distance = square_root( delta_x*delta_x + (delta_y*delta_y + delta_z*delta_z)); } @@ -742,18 +733,18 @@ void custom_render_nav_point( &render.camera, &render.frustum, &view_point, - &screen_point)) + &screen_position)) { - screen_point.x = view_point.x; - screen_point.y = -view_point.y; + screen_position.x = view_point.x; + screen_position.y = -view_point.y; waypoint_type = _waypoint_off_screen; } else { - screen_point.x -= (real)( + screen_position.x -= (real)( ((render.camera.viewport_bounds.x1-render.camera.viewport_bounds.x0)/2) + render.camera.viewport_bounds.x0); - screen_point.y -= (real)( + screen_position.y -= (real)( ((render.camera.viewport_bounds.y1-render.camera.viewport_bounds.y0)/2) + render.camera.viewport_bounds.y0); } @@ -765,8 +756,8 @@ void custom_render_nav_point( ((real)(render.camera.window_bounds.y1-render.camera.window_bounds.y0) - (hud_globals->waypoint.bottom_offset+hud_globals->waypoint.top_offset))*0.5f; radius_product = vertical_radius*horizontal_radius; - vertical_component = vertical_radius*screen_point.x; - horizontal_component = horizontal_radius*screen_point.y; + vertical_component = vertical_radius*screen_position.x; + horizontal_component = horizontal_radius*screen_position.y; theta = 0.0f; if (waypoint_type==_waypoint_off_screen || @@ -778,18 +769,18 @@ void custom_render_nav_point( (vertical_component*vertical_component + horizontal_component*horizontal_component)); waypoint_type = _waypoint_off_screen; - screen_point.x *= scale; - screen_point.y *= scale; + screen_position.x *= scale; + screen_position.y *= scale; if (!TEST_FLAG(arrow->flags, _hud_waypoint_dont_rotate_offscreen_bit)) { - theta = -arctangent(screen_point.x, screen_point.y); + theta = -arctangent(screen_position.x, screen_position.y); } } - screen_point.x += (real)( + screen_position.x += (real)( (render.camera.viewport_bounds.x1-render.camera.viewport_bounds.x0)/2); - screen_point.y += (real)( + screen_position.y += (real)( (render.camera.viewport_bounds.y1-render.camera.viewport_bounds.y0)/2); match_assert( @@ -813,18 +804,18 @@ void custom_render_nav_point( (struct bitmap_data *)bitmap, FALSE, TRUE)) { point2d point; - real_rgb_color color; + real_rgb_color rgb_temp; byte alpha; real fade; - point.x = (short)(long)screen_point.x; - point.y = (short)(long)screen_point.y; + point.x = (short)(long)screen_position.x; + point.y = (short)(long)screen_position.y; alpha = (byte)PIN(fast_ftol_C(arrow->opacity)*255, 0, 255); - pixel32_to_real_rgb_color(arrow->color, &color); + pixel32_to_real_rgb_color(arrow->color, &rgb_temp); fade = 1.0f-arrow->fade; - color.red *= PIN(fade, 0.0f, 1.0f); - color.green *= PIN(fade, 0.0f, 1.0f); - color.blue *= PIN(fade, 0.0f, 1.0f); + rgb_temp.red *= PIN(fade, 0.0f, 1.0f); + rgb_temp.green *= PIN(fade, 0.0f, 1.0f); + rgb_temp.blue *= PIN(fade, 0.0f, 1.0f); hud_draw_bitmap_direct( bitmap, @@ -833,7 +824,7 @@ void custom_render_nav_point( clip, arrow_scale, theta, - ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&color), + ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&rgb_temp), FALSE); if (waypoint_type!=_waypoint_off_screen) @@ -849,9 +840,9 @@ void custom_render_nav_point( placement.corner = _hud_anchor_top_left; numbers.colors.color = - ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&color); + ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&rgb_temp); numbers.colors.flash_color = - ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&color); + ((pixel32)alpha<<24) | real_rgb_color_to_pixel32(&rgb_temp); numbers.digits = 3; numbers.fractional_digits = 1; numbers.number_flags = diff --git a/source/interface/hud_weapon.c b/source/interface/hud_weapon.c index 8795f64a..de03b538 100644 --- a/source/interface/hud_weapon.c +++ b/source/interface/hud_weapon.c @@ -692,7 +692,7 @@ static void hud_update_weapon_local_player( { root_definition }; long weapon_hud_indices[MAXIMUM_WEAPON_HUD_DEFINITION_DEPTH] = { hud_index }; unsigned long valid_crosshair_types = weapon_hud_hierarchy[0]->valid_crosshair_types_flags; - unsigned long render_flags = 0; + long render_flags = 0; short definition_count = 1; short crosshair_index; @@ -954,18 +954,18 @@ static void crosshairs_draw( struct weapon_definition *weapon_definition = weapon_index == NONE ? NULL : weapon_definition_get(weapon_get(weapon_index)->definition_index); - struct weapon_hud_interface_definition *definitions[MAXIMUM_WEAPON_HUD_DEFINITION_DEPTH] = { root_definition }; + struct weapon_hud_interface_definition *weapon_hud_hierarchy[MAXIMUM_WEAPON_HUD_DEFINITION_DEPTH] = { root_definition }; long definition_indices[MAXIMUM_WEAPON_HUD_DEFINITION_DEPTH] = { hud_index }; - unsigned long render_flags = crosshair->render_flags; + long render_flags = crosshair->render_flags; short definition_count = 1; short definition_index; do { - if (definitions[definition_count - 1]->parent_hud.index == NONE) + if (weapon_hud_hierarchy[definition_count - 1]->parent_hud.index == NONE) break; - definition_indices[definition_count] = definitions[definition_count - 1]->parent_hud.index; - definitions[definition_count] = weapon_hud_interface_definition_get(definition_indices[definition_count]); + definition_indices[definition_count] = weapon_hud_hierarchy[definition_count - 1]->parent_hud.index; + weapon_hud_hierarchy[definition_count] = weapon_hud_interface_definition_get(definition_indices[definition_count]); definition_count++; } while (definition_count < MAXIMUM_WEAPON_HUD_DEFINITION_DEPTH); @@ -981,7 +981,7 @@ static void crosshairs_draw( definition_index < definition_count; definition_index++) { - struct weapon_hud_interface_definition *definition = definitions[definition_index]; + struct weapon_hud_interface_definition *definition = weapon_hud_hierarchy[definition_index]; struct hud_absolute_placement_definition absolute_placement = { _hud_anchor_center }; boolean in_multiplayer = local_player_count() > 1; short crosshair_index; @@ -1259,7 +1259,7 @@ static void render_weapon_hud( short state_flags[NUMBER_OF_WEAPON_HUD_FLASH_REFERENCES] = { 0 }; short overlay_flags[NUMBER_OF_WEAPON_HUD_FLASH_REFERENCES] = { 0 }; short number_values[NUMBER_OF_WEAPON_HUD_FLASH_REFERENCES] = { 0 }; - real number_fractions[NUMBER_OF_WEAPON_HUD_FLASH_REFERENCES] = { 0.0f }; + real numbers_real[NUMBER_OF_WEAPON_HUD_FLASH_REFERENCES] = { 0.0f }; short state_index; short map_type_flags; short element_index; @@ -1549,23 +1549,23 @@ static void render_weapon_hud( long unit_index = player_index == NONE ? NONE : player_get(local_player_get_player_index(local_player_index))->unit_index; - real_point3d camera_position; + real_point3d position; real_point3d target_position; real delta_x; real delta_y; real delta_z; - unit_get_camera_position(unit_index, &camera_position); + unit_get_camera_position(unit_index, &position); object_get_origin(target_object_index, &target_position); - delta_x = camera_position.x - target_position.x; - delta_y = camera_position.y - target_position.y; - delta_z = camera_position.z - target_position.z; - number_fractions[6] = square_root( + delta_x = position.x - target_position.x; + delta_y = position.y - target_position.y; + delta_z = position.z - target_position.z; + numbers_real[6] = square_root( delta_x * delta_x + delta_y * delta_y + delta_z * delta_z) * 3.0480001f; - number_fractions[7] = - (target_position.z - camera_position.z) * 3.0480001f; + numbers_real[7] = + (target_position.z - position.z) * 3.0480001f; } else { @@ -1576,8 +1576,8 @@ static void render_weapon_hud( } no_target_value; no_target_value.bits = 0xFFC00000; - number_fractions[6] = no_target_value.value; - number_fractions[7] = no_target_value.value; + numbers_real[6] = no_target_value.value; + numbers_real[7] = no_target_value.value; } } } @@ -1687,15 +1687,15 @@ static void render_weapon_hud( } fraction; real scale; - fraction.value = number_fractions[state_index]; + fraction.value = numbers_real[state_index]; if (fraction.bits == 0xFFC00000) continue; scale = power(10.0f, 4.0f); decimal_value = (short)fmod( - fabs(number_fractions[state_index] * scale), + fabs(numbers_real[state_index] * scale), scale); value = (short)fast_ftol_C( - number_fractions[state_index] / magazine_size); + numbers_real[state_index] / magazine_size); } else { diff --git a/source/interface/motion_sensor.c b/source/interface/motion_sensor.c index 5aec1662..08254d62 100644 --- a/source/interface/motion_sensor.c +++ b/source/interface/motion_sensor.c @@ -265,8 +265,8 @@ static struct motion_sensor_globals_definition *motion_sensor_globals = NULL; static real sweep_theta = 0.f; boolean debug_motion_sensor_draw_all_units= {0}; -extern short blip_player_index; -extern real_point2d center_point; +short blip_player_index; +real_point2d center_point; /* ---------- private code */ @@ -332,7 +332,7 @@ static void motion_sensor_update( short local_player_slots[4] = { 0 }; short player_count = local_player_count(); short local_player_index = local_player_get_next(NONE); - struct object_iterator iterator; + struct object_iterator iter; real_point3d camera_positions[2]; boolean done = FALSE; short player_scan_index; @@ -374,19 +374,19 @@ static void motion_sensor_update( local_player_index = local_player_get_next(local_player_index); } - object_iterator_new(&iterator, _object_mask_unit, TRUE); - while (object_iterator_next(&iterator) && !done) + object_iterator_new(&iter, _object_mask_unit, TRUE); + while (object_iterator_next(&iter) && !done) { - if (should_track_object(iterator.index) && - should_draw_object(iterator.index)) + if (should_track_object(iter.index) && + should_draw_object(iter.index)) { - real_point3d object_position; + real_point3d center; real object_radius; short players_full = 0; object_get_bounding_sphere( - iterator.index, - &object_position, + iter.index, + ¢er, &object_radius); for (player_scan_index = 0; @@ -414,13 +414,13 @@ static void motion_sensor_update( real_vector3d displacement; displacement.i = - object_position.x - + center.x - camera_positions[scan_player_index].x; displacement.j = - object_position.y - + center.y - camera_positions[scan_player_index].y; displacement.k = - object_position.z - + center.z - camera_positions[scan_player_index].z; if (game_engine_running() || @@ -437,10 +437,10 @@ static void motion_sensor_update( motion_sensor_blip_set_type_and_size( blip, - iterator.index, + iter.index, scan_player_index); - player->unit_indices[blip_index] = iterator.index; + player->unit_indices[blip_index] = iter.index; sensor->blip_count++; local_player_slots[scan_player_index] = (short)(blip_index + 1); @@ -625,7 +625,7 @@ static void render_motion_sensor( director_perspective perspective; struct motion_sensor_player *player; real relative_scale; - real_point2d center; + real_point2d corner; short history_index; csmemset(stack_buffer, 0x62, sizeof(stack_buffer)); @@ -640,9 +640,9 @@ static void render_motion_sensor( relative_scale = hud_globals->defaults.motion_sensor_scale / hud_globals->defaults.motion_sensor_range; - center.x = (real)reference->x; - center.y = (real)reference->y; - blip_begin(¢er, 0, in_multiplayer, local_player_index); + corner.x = (real)reference->x; + corner.y = (real)reference->y; + blip_begin(&corner, 0, in_multiplayer, local_player_index); for (history_index = 0; history_index < MOTION_SENSOR_HISTORY_COUNT; @@ -669,14 +669,14 @@ static void render_motion_sensor( if (blip->type != _blip_type_none) { - real_point2d point; + real_point2d blip_pos; - tiny_point2d_get(&blip->position, &point); + tiny_point2d_get(&blip->position, &blip_pos); render_blip( sensor, blip->type, blip->size, - &point, + &blip_pos, relative_scale, fade, radius); @@ -695,14 +695,14 @@ static void render_motion_sensor( if (game_engine_get_goal_in_use( (short)sensor->custom_blip_goal_indices[blip_index])) { - real_point2d point; + real_point2d blip_pos; - tiny_point2d_get(&sensor->custom_blips[blip_index], &point); + tiny_point2d_get(&sensor->custom_blips[blip_index], &blip_pos); render_blip( sensor, _blip_type_custom, _hud_blip_type_medium, - &point, + &blip_pos, relative_scale, fade, radius); diff --git a/source/interface/ui_widget.c b/source/interface/ui_widget.c index e2f41181..7ce40232 100644 --- a/source/interface/ui_widget.c +++ b/source/interface/ui_widget.c @@ -1314,7 +1314,7 @@ static void ui_widget_delete_children_recursive( struct widget_instance *widget); static struct widget_instance *ui_widget_launch_widget( struct widget_instance *widget, - long widget_tag_index); + long new_widget_tag_index); static __inline boolean widget_instance_can_handle_events( struct widget_instance *widget); static struct widget_instance *widget_instance_find_by_tag_index_recursive( @@ -1427,8 +1427,8 @@ static struct ui_widget_bss_prefix ui_widget_globals_storage; #define widget_globals ui_widget_globals_storage.widget_globals #define we_are_at_the_main_menu ui_widget_globals_storage.we_are_at_the_main_menu #define dpad_event_times ui_widget_globals_storage.dpad_event_times -extern real_argb_color ui_plasma_effect_color; -extern short local_player_index_for_draw_string_and_hack_in_icons; +real_argb_color ui_plasma_effect_color; +short local_player_index_for_draw_string_and_hack_in_icons; /* January defines this and never references it, as we do not */ real const _one_over_255 = 1.0f / 255.0f; @@ -1627,8 +1627,8 @@ void draw_bitmap_in_rect( real_argb_color plasma_fade = ui_plasma_effect_color; real_rgb_color map_tint = { 0.9f, 0.9f, 0.9f }; real map_fade = 0.9f; - rectangle2d default_bitmap_rect; - real_point2d positions[NUMBER_OF_POINTS_PER_RECTANGLE]; + rectangle2d temp; + real_point2d points[NUMBER_OF_POINTS_PER_RECTANGLE]; struct dynamic_screen_vertex vertices[NUMBER_OF_POINTS_PER_RECTANGLE]; struct rasterizer_dynamic_screen_geometry_parameters parameters; real bitmap_width; @@ -1647,11 +1647,11 @@ void draw_bitmap_in_rect( if (!bitmap_rect) { - default_bitmap_rect.x0 = 0; - default_bitmap_rect.y0 = 0; - default_bitmap_rect.x1 = bitmap->width; - default_bitmap_rect.y1 = bitmap->height; - bitmap_rect = &default_bitmap_rect; + temp.x0 = 0; + temp.y0 = 0; + temp.x1 = bitmap->width; + temp.y1 = bitmap->height; + bitmap_rect = &temp; } rectangle_width = rect->x1 - rect->x0; @@ -1660,32 +1660,32 @@ void draw_bitmap_in_rect( rectangle_y0 = rect->y0; source_width = bitmap_rect->x1 - bitmap_rect->x0; source_height = bitmap_rect->y1 - bitmap_rect->y0; - positions[0].x = (real)rectangle_x0; - positions[0].y = (real)rectangle_y0; - positions[1].x = (real)(rectangle_x0 + rectangle_width); - positions[1].y = (real)rectangle_y0; - positions[2].x = (real)(rectangle_x0 + rectangle_width); - positions[2].y = (real)(rectangle_y0 + rectangle_height); - positions[3].x = (real)rectangle_x0; - positions[3].y = (real)(rectangle_y0 + rectangle_height); + points[0].x = (real)rectangle_x0; + points[0].y = (real)rectangle_y0; + points[1].x = (real)(rectangle_x0 + rectangle_width); + points[1].y = (real)rectangle_y0; + points[2].x = (real)(rectangle_x0 + rectangle_width); + points[2].y = (real)(rectangle_y0 + rectangle_height); + points[3].x = (real)rectangle_x0; + points[3].y = (real)(rectangle_y0 + rectangle_height); if (clip_rect) { if (clip_rect->x0 > rect->x0) { - positions[0].x = positions[3].x = (real)clip_rect->x0; + points[0].x = points[3].x = (real)clip_rect->x0; } if (clip_rect->x1 < rect->x1) { - positions[1].x = positions[2].x = (real)clip_rect->x1; + points[1].x = points[2].x = (real)clip_rect->x1; } if (clip_rect->y0 > rect->y0) { - positions[0].y = positions[1].y = (real)clip_rect->y0; + points[0].y = points[1].y = (real)clip_rect->y0; } if (clip_rect->y1 < rect->y1) { - positions[2].y = positions[3].y = (real)clip_rect->y1; + points[2].y = points[3].y = (real)clip_rect->y1; } } @@ -1707,7 +1707,7 @@ void draw_bitmap_in_rect( (vertex_index % 3) ? texture_width : 0.0f; vertices[vertex_index].texture_coordinates.y = (vertex_index > 1) ? texture_height : 0.0f; - vertices[vertex_index].position = positions[vertex_index]; + vertices[vertex_index].position = points[vertex_index]; } csmemset(¶meters, 0, sizeof(parameters)); @@ -2304,9 +2304,9 @@ static void ui_widget_delete_children_recursive( static struct widget_instance *ui_widget_launch_widget( struct widget_instance *widget, - long widget_tag_index) + long new_widget_tag_index) { - struct ui_widget_definition *definition = ui_widget_definition_get(widget_tag_index); + struct ui_widget_definition *definition = ui_widget_definition_get(new_widget_tag_index); struct widget_instance *root; struct widget_instance *new_widget; short local_player_index; @@ -2370,7 +2370,7 @@ static struct widget_instance *ui_widget_launch_widget( root = widget_instance_get_topmost_parent(widget); new_widget = ui_widget_load_by_name_or_tag( NULL, - widget_tag_index, + new_widget_tag_index, NULL, local_player_index, root->definition_tag_index, @@ -6180,6 +6180,7 @@ static boolean ui_check_for_pause_game( { boolean pause_pressed = FALSE; boolean network_game = network_game_is_active(); + short controller_index = NONE; if (game_in_progress() && !cinematic_in_progress() && @@ -6187,185 +6188,175 @@ static boolean ui_check_for_pause_game( !we_are_at_the_main_menu && widget_globals.pause_disabled_ticks == 0) { - short controller_index; + long gamepad_index; - for (controller_index = 0; - controller_index < MAXIMUM_NUMBER_OF_LOCAL_PLAYERS; - controller_index++) + for (gamepad_index = 0; + gamepad_index < MAXIMUM_NUMBER_OF_LOCAL_PLAYERS; + gamepad_index++) { - if (input_has_gamepad(controller_index) && - local_player_exists(controller_index) && - input_get_gamepad_state(controller_index)-> + if (input_has_gamepad(gamepad_index) && + local_player_exists(gamepad_index) && + input_get_gamepad_state(gamepad_index)-> buttons[_gamepad_binary_button_start] == 1) { - boolean pressed_by_first_local_player = TRUE; - short local_player_count = 0; - short pressing_local_player_index = NONE; - short local_player_index; - pause_pressed = TRUE; - for (local_player_index = local_player_get_next(NONE); - local_player_index != NONE; - local_player_index = local_player_get_next(local_player_index)) - { - if (local_player_index == controller_index) - { - pressing_local_player_index = controller_index; - if (local_player_count >= 1) - pressed_by_first_local_player = FALSE; - } - local_player_count++; - } - if (network_game) - { - if (game_engine_allow_pause() && - pressing_local_player_index == controller_index) - { - if (!widget_globals.active_widgets[controller_index]) - { - struct network_game_client *client = global_network_game_client_get(); - struct network_game *network_game_data = - network_game_client_get_game(client); - short machine_index = - network_game_client_get_machine_index(client); - char const *widget_name; + controller_index = gamepad_index; + break; + } + } + } + if (pause_pressed) + { + boolean pressed_by_first_local_player = TRUE; + short local_player_count = 0; + short pressing_local_player_index = NONE; + short local_player_index; - switch (local_player_count) - { - case 1: - widget_name = - "ui\\shell\\multiplayer_game\\pause_game\\1p_pause_game"; - break; - case 2: - widget_name = - "ui\\shell\\multiplayer_game\\pause_game\\2p_pause_game"; - break; - case 3: - widget_name = pressed_by_first_local_player == TRUE - ? "ui\\shell\\multiplayer_game\\pause_game\\2p_pause_game" - : "ui\\shell\\multiplayer_game\\pause_game\\4p_pause_game"; - break; - case 4: - widget_name = - "ui\\shell\\multiplayer_game\\pause_game\\4p_pause_game"; - break; - default: - error( - _error_silent, - "invalid local player count for multiplayer game"); - widget_name = NULL; - break; - } - if (widget_name && - !ui_widget_load_by_name_or_tag( - widget_name, - NONE, - NULL, - controller_index, - NONE, - NONE, - NONE)) - { - error( - _error_silent, - "failed to load multiplayer pause game window"); - } - } - else - { - ui_widget_delete(widget_globals.active_widgets[controller_index]); - } - } - } - else + for (local_player_index = local_player_get_next(NONE); + local_player_index != NONE; + local_player_index = local_player_get_next(local_player_index)) + { + if (local_player_index == controller_index) + { + pressing_local_player_index = controller_index; + if (local_player_count >= 1) + pressed_by_first_local_player = FALSE; + } + local_player_count++; + } + if (network_game) + { + if (game_engine_allow_pause() && + pressing_local_player_index == controller_index) + { + if (!widget_globals.active_widgets[controller_index]) { + struct network_game_client *client = global_network_game_client_get(); + struct network_game *network_game_data = + network_game_client_get_game(client); + short machine_index = + network_game_client_get_machine_index(client); + char const *widget_name; + switch (local_player_count) { - case 0: case 1: - if (widget_globals.active_widgets[controller_index]) - { - if (game_time_get_paused() == TRUE) - ui_widgets_close_all(); - } - else if (!ui_widget_load_by_name_or_tag( - "ui\\shell\\solo_game\\pause_game\\pause_game", - NONE, - NULL, - controller_index, - NONE, - NONE, - NONE)) - { - error( - _error_silent, - "failed to load full screen pause game window"); - } + widget_name = + "ui\\shell\\multiplayer_game\\pause_game\\1p_pause_game"; break; case 2: - if (widget_globals.active_widgets[controller_index]) - { - if (game_time_get_paused() == TRUE) - ui_widgets_close_all(); - } - else if (!game_time_get_paused()) - { - if (!ui_widget_load_by_name_or_tag( - "ui\\shell\\solo_game\\pause_game\\pause_game_split_screen", - NONE, - NULL, - controller_index, - NONE, - NONE, - NONE)) - { - error( - _error_silent, - "failed to load split screen pause game window"); - } - } + widget_name = + "ui\\shell\\multiplayer_game\\pause_game\\2p_pause_game"; + break; + case 3: + widget_name = pressed_by_first_local_player == TRUE + ? "ui\\shell\\multiplayer_game\\pause_game\\2p_pause_game" + : "ui\\shell\\multiplayer_game\\pause_game\\4p_pause_game"; + break; + case 4: + widget_name = + "ui\\shell\\multiplayer_game\\pause_game\\4p_pause_game"; break; default: error( _error_silent, - "the ui seems to be confused... assuming you are playing full-screen single player?"); - if (widget_globals.initialized) - { - boolean widgets_active = FALSE; - long widget_index; - - for (widget_index = 0; - widget_index < MAXIMUM_NUMBER_OF_LOCAL_PLAYERS; - widget_index++) - { - if (widget_globals.active_widgets[widget_index]) - { - widgets_active = TRUE; - break; - } - } - if (widgets_active) - { - ui_widgets_close_all(); - break; - } - } - if (!ui_widget_load_by_name_or_tag( - "ui\\shell\\solo_game\\pause_game\\pause_game", + "invalid local player count for multiplayer game"); + widget_name = NULL; + break; + } + if (widget_name && + !ui_widget_load_by_name_or_tag( + widget_name, NONE, NULL, controller_index, NONE, NONE, NONE)) - { - error( - _error_silent, - "failed to load full screen pause game window"); - } - break; + { + error( + _error_silent, + "failed to load multiplayer pause game window"); } } + else + { + ui_widget_delete(widget_globals.active_widgets[controller_index]); + } + } + } + else + { + switch (local_player_count) + { + case 0: + case 1: + if (widget_globals.active_widgets[controller_index]) + { + if (game_time_get_paused() == TRUE) + ui_widgets_close_all(); + } + else if (!ui_widget_load_by_name_or_tag( + "ui\\shell\\solo_game\\pause_game\\pause_game", + NONE, + NULL, + controller_index, + NONE, + NONE, + NONE)) + { + error( + _error_silent, + "failed to load full screen pause game window"); + } + break; + case 2: + if (widget_globals.active_widgets[controller_index]) + { + if (game_time_get_paused() == TRUE) + ui_widgets_close_all(); + } + else if (!game_time_get_paused()) + { + if (!ui_widget_load_by_name_or_tag( + "ui\\shell\\solo_game\\pause_game\\pause_game_split_screen", + NONE, + NULL, + controller_index, + NONE, + NONE, + NONE)) + { + error( + _error_silent, + "failed to load split screen pause game window"); + } + } + break; + default: + error( + _error_silent, + "the ui seems to be confused... assuming you are playing full-screen single player?"); + if (!ui_widgets_active()) + { + if (!ui_widget_load_by_name_or_tag( + "ui\\shell\\solo_game\\pause_game\\pause_game", + NONE, + NULL, + controller_index, + NONE, + NONE, + NONE)) + { + error( + _error_silent, + "failed to load full screen pause game window"); + } + } + else + { + ui_widgets_close_all(); + } break; } } diff --git a/source/main/main.c b/source/main/main.c index c0c64ca6..590aa130 100644 --- a/source/main/main.c +++ b/source/main/main.c @@ -706,6 +706,7 @@ boolean display_framerate = FALSE; boolean display_vblank_deltas = FALSE; boolean display_precache_progress = FALSE; struct _screenshot_and_framerate_globals global_screenshot_count = { 0 }; +boolean debug_render_freeze; /* ---------- public code */ diff --git a/source/math/geometry.c b/source/math/geometry.c index 470d6e44..d6df49e5 100644 --- a/source/math/geometry.c +++ b/source/math/geometry.c @@ -1128,14 +1128,14 @@ short convex_polygon2d_clip_to_plane( real_plane2d const *plane, short maximum_count, real_point2d *result, - long *clip_flags, + unsigned long *clip_flags, boolean *clipped, real epsilon) { - real_point2d local_points[CLIP_BUFFER_SIZE]; + real_point2d storage[CLIP_BUFFER_SIZE]; boolean any_in_front = FALSE; boolean any_behind = FALSE; - long result_clip_flags = 0; + unsigned long result_clip_flags = 0; short result_count = 0; real_point2d const *previous_point; boolean previous_in_front; @@ -1154,8 +1154,8 @@ short convex_polygon2d_clip_to_plane( if (points == result) { match_assert("c:\\halo\\SOURCE\\math\\geometry.c", 1357, count<=CLIP_BUFFER_SIZE); - csmemcpy(local_points, points, sizeof(real_point2d)*count); - points = local_points; + csmemcpy(storage, points, sizeof(real_point2d)*count); + points = storage; } previous_point = points + count - 1; @@ -1296,9 +1296,9 @@ short convex_polygon3d_clip_to_plane( real_point3d *result, boolean *clipped, real epsilon, - boolean keep_degenerate) + boolean keep_coplanar) { - real_point3d local_points[CLIP_BUFFER_SIZE]; + real_point3d storage[CLIP_BUFFER_SIZE]; boolean any_in_front = FALSE; boolean any_behind = FALSE; short result_count = 0; @@ -1319,8 +1319,8 @@ short convex_polygon3d_clip_to_plane( if (points == result) { match_assert("c:\\halo\\SOURCE\\math\\geometry.c", 1500, count<=CLIP_BUFFER_SIZE); - csmemcpy(local_points, points, sizeof(real_point3d)*count); - points = local_points; + csmemcpy(storage, points, sizeof(real_point3d)*count); + points = storage; } previous_point = points + count - 1; @@ -1417,7 +1417,7 @@ short convex_polygon3d_clip_to_plane( if (!any_in_front) { - if (any_behind || !keep_degenerate) + if (any_behind || !keep_coplanar) { return 0; } diff --git a/source/math/geometry.h b/source/math/geometry.h index a9a92d44..0edee02e 100644 --- a/source/math/geometry.h +++ b/source/math/geometry.h @@ -117,7 +117,7 @@ short convex_polygon2d_clip_to_plane( real_plane2d const *plane, short maximum_count, real_point2d *result, - long *clip_flags, + unsigned long *clip_flags, boolean *clipped, real epsilon); short convex_polygon3d_clip_to_plane( @@ -128,7 +128,7 @@ short convex_polygon3d_clip_to_plane( real_point3d *result, boolean *clipped, real epsilon, - boolean keep_degenerate); + boolean keep_coplanar); short convex_hull2d_intersect( short p_count, real_point2d const *p, diff --git a/source/math/periodic_functions.c b/source/math/periodic_functions.c index e9b378de..a95d0fbe 100644 --- a/source/math/periodic_functions.c +++ b/source/math/periodic_functions.c @@ -506,7 +506,7 @@ void periodic_functions_initialize( 67, !function_tables_initialized); function_tables_initialized = TRUE; - *get_global_random_seed_address() = 0x20F3F660; + set_random_seed(0x20F3F660); for (function_index = 0; function_index < NUMBER_OF_PERIODIC_FUNCTIONS; function_index++) { diff --git a/source/models/models.c b/source/models/models.c index 29757d3a..39d17db1 100644 --- a/source/models/models.c +++ b/source/models/models.c @@ -81,6 +81,7 @@ symbols in this file: #include "shaders/shader_definitions.h" #include "shaders/shaders.h" #include "rasterizer/rasterizer_console_vars.h" +#include "rasterizer/rasterizer_model_types.h" /* ---------- constants */ @@ -220,27 +221,6 @@ struct render_sort_filth word pad; }; -struct render_model_effect -{ - short type; - word pad; - real intensity; - byte reserved[0x20]; -}; - -struct rasterizer_model_begin_parameters -{ - unsigned long geometry_flags; - long unique_identifier; - struct render_skinning skinning; - struct render_lighting lighting; - struct render_animation animation; - struct render_model_effect effect; - real_point3d centroid; - real radius; - real_vector2d base_map_scale; -}; - typedef char verify_render_model_effect_size[sizeof(struct render_model_effect) == 0x28 ? 1 : -1]; typedef char verify_rasterizer_model_begin_parameters_size[sizeof(struct rasterizer_model_begin_parameters) == 0xCC ? 1 : -1]; diff --git a/source/objects/damage.c b/source/objects/damage.c index 293ed0d4..f53195d7 100644 --- a/source/objects/damage.c +++ b/source/objects/damage.c @@ -351,7 +351,7 @@ static void object_destroy_region( /* ---------- globals */ -extern boolean debug_damage; +boolean debug_damage; /* Name and type from the 2003 PC demo PDB ONLY (file static long); HCEX has no such static, so the name is singly attested. January corroborates the storage: .bss +0x48, after @@ -2206,7 +2206,7 @@ static void area_of_effect_cause_damage_to_object( real_vector3d collision_vector; real_vector3d offset_vector; real_vector3d direct_vector; - real_point3d collision_point; + real_point3d offset_point; struct collision_result spread_collision; struct collision_result direct_collision; boolean can_damage; @@ -2284,13 +2284,13 @@ static void area_of_effect_cause_damage_to_object( &collision_vector, object_get_ultimate_parent(object_index), &spread_collision); - collision_point = spread_collision.point; + offset_point = spread_collision.point; ultimate_parent_index = object_get_ultimate_parent(object_index); if (!collision_test_vector( _damage_area_of_effect_collision_flags, - &collision_point, + &offset_point, vector_from_points3d( - &collision_point, + &offset_point, &object->object.bounding_sphere_center, &offset_vector), ultimate_parent_index, diff --git a/source/objects/object_lights.c b/source/objects/object_lights.c index b5cacc88..f4ba4d79 100644 --- a/source/objects/object_lights.c +++ b/source/objects/object_lights.c @@ -492,12 +492,12 @@ real object_light_ambient_scale = 0.4f; real object_light_secondary_scale = 1.0f; boolean object_light_interpolate = TRUE; -extern boolean debug_lights; -extern boolean debug_object_lights; -extern struct data_array *light_data; -extern struct cluster_partition light_cluster_partition; +boolean debug_lights; +boolean debug_object_lights; +struct data_array *light_data; +struct cluster_partition light_cluster_partition; struct lights_game_globals *lights_game_globals = NULL; -extern short debug_rasterizer_light_count; +short debug_rasterizer_light_count; struct lights_globals lights_globals; /* ---------- public code */ diff --git a/source/objects/object_types.c b/source/objects/object_types.c index fcff21ab..1a08f1e4 100644 --- a/source/objects/object_types.c +++ b/source/objects/object_types.c @@ -470,7 +470,7 @@ struct object_type_definition *object_type_definitions[NUMBER_OF_OBJECT_TYPES] = &sound_scenery_data_definition }; -extern struct object_type_definition *first_object_type_definition; +struct object_type_definition *first_object_type_definition; /* VC7 otherwise emits this tentative definition as a common symbol. */ #pragma bss_seg(".bss") static word processed_bsp_flags; diff --git a/source/objects/widgets/antenna.c b/source/objects/widgets/antenna.c index 1277a395..cedf6d2b 100644 --- a/source/objects/widgets/antenna.c +++ b/source/objects/widgets/antenna.c @@ -73,6 +73,8 @@ static void antenna_update( /* ---------- globals */ +struct data_array *antenna_data; + /* ---------- public code */ void antennas_initialize( diff --git a/source/objects/widgets/glow.c b/source/objects/widgets/glow.c index 0d606263..f441e6de 100644 --- a/source/objects/widgets/glow.c +++ b/source/objects/widgets/glow.c @@ -326,6 +326,12 @@ static void glow_update( /* ---------- globals */ +struct +{ + struct data_array *glow_data; + struct data_array *glow_particle_data; +} glow_globals; + /* ---------- public code */ void glow_initialize( @@ -810,10 +816,10 @@ static void get_particle_world_position( real_vector3d side; real_vector3d ups[4]; real_vector3d up; - real_point3d positions[4]; + real_point3d traversal_points[4]; real_vector3d position_vectors[4]; real_vector3d position; - real knots[4]; + real traversal_time_indices[4]; real angle; short marker_index; short first_marker_index; @@ -836,8 +842,8 @@ static void get_particle_world_position( switch (glow->number_of_markers) { case 2: - positions[0] = glow->markers[0].matrix.position; - positions[3] = glow->markers[1].matrix.position; + traversal_points[0] = glow->markers[0].matrix.position; + traversal_points[3] = glow->markers[1].matrix.position; ups[0] = glow->markers[0].matrix.up; ups[3] = glow->markers[1].matrix.up; cross_product3d( @@ -848,15 +854,15 @@ static void get_particle_world_position( &glow->markers[1].matrix.up, &glow->markers[1].matrix.forward, &sides[3]); - knots[0] = glow->marker_time_index[0]; - knots[3] = glow->marker_time_index[1]; + traversal_time_indices[0] = glow->marker_time_index[0]; + traversal_time_indices[3] = glow->marker_time_index[1]; - positions[1].x = (positions[3].x - positions[0].x) * 0.25f + positions[0].x; - positions[1].y = (positions[3].y - positions[0].y) * 0.25f + positions[0].y; - positions[1].z = (positions[3].z - positions[0].z) * 0.25f + positions[0].y; - positions[2].x = (positions[3].x - positions[0].x) * 0.75f + positions[0].x; - positions[2].y = (positions[3].y - positions[0].y) * 0.75f + positions[0].y; - positions[2].z = (positions[3].z - positions[0].z) * 0.75f + positions[0].y; + traversal_points[1].x = (traversal_points[3].x - traversal_points[0].x) * 0.25f + traversal_points[0].x; + traversal_points[1].y = (traversal_points[3].y - traversal_points[0].y) * 0.25f + traversal_points[0].y; + traversal_points[1].z = (traversal_points[3].z - traversal_points[0].z) * 0.25f + traversal_points[0].y; + traversal_points[2].x = (traversal_points[3].x - traversal_points[0].x) * 0.75f + traversal_points[0].x; + traversal_points[2].y = (traversal_points[3].y - traversal_points[0].y) * 0.75f + traversal_points[0].y; + traversal_points[2].z = (traversal_points[3].z - traversal_points[0].z) * 0.75f + traversal_points[0].y; ups[1].i = (ups[3].i - ups[0].i) * 0.25f + ups[0].i; ups[1].j = (ups[3].j - ups[0].j) * 0.25f + ups[0].j; @@ -871,13 +877,13 @@ static void get_particle_world_position( sides[2].j = (sides[3].j - sides[0].j) * 0.75f + sides[0].j; sides[2].k = (sides[3].k - sides[0].k) * 0.75f + sides[0].k; - knots[1] = (knots[3] - knots[0]) * 0.25f + knots[0]; - knots[2] = (knots[3] - knots[0]) * 0.75f + knots[0]; + traversal_time_indices[1] = (traversal_time_indices[3] - traversal_time_indices[0]) * 0.25f + traversal_time_indices[0]; + traversal_time_indices[2] = (traversal_time_indices[3] - traversal_time_indices[0]) * 0.75f + traversal_time_indices[0]; break; case 3: - positions[0] = glow->markers[0].matrix.position; - positions[3] = glow->markers[2].matrix.position; + traversal_points[0] = glow->markers[0].matrix.position; + traversal_points[3] = glow->markers[2].matrix.position; ups[0] = glow->markers[0].matrix.up; ups[3] = glow->markers[2].matrix.up; cross_product3d( @@ -888,23 +894,23 @@ static void get_particle_world_position( &glow->markers[2].matrix.up, &glow->markers[2].matrix.forward, &sides[3]); - knots[0] = glow->marker_time_index[0]; - knots[3] = glow->marker_time_index[2]; + traversal_time_indices[0] = glow->marker_time_index[0]; + traversal_time_indices[3] = glow->marker_time_index[2]; switch (particle->parent_marker_index) { case 0: - positions[1] = glow->markers[1].matrix.position; + traversal_points[1] = glow->markers[1].matrix.position; ups[1] = glow->markers[1].matrix.up; cross_product3d( &glow->markers[1].matrix.up, &glow->markers[1].matrix.forward, &sides[1]); - knots[1] = glow->marker_time_index[1]; + traversal_time_indices[1] = glow->marker_time_index[1]; - positions[2].x = (positions[3].x - positions[1].x) * 0.5f + positions[1].x; - positions[2].y = (positions[3].y - positions[1].y) * 0.5f + positions[1].y; - positions[2].z = (positions[3].z - positions[1].z) * 0.5f + positions[1].y; + traversal_points[2].x = (traversal_points[3].x - traversal_points[1].x) * 0.5f + traversal_points[1].x; + traversal_points[2].y = (traversal_points[3].y - traversal_points[1].y) * 0.5f + traversal_points[1].y; + traversal_points[2].z = (traversal_points[3].z - traversal_points[1].z) * 0.5f + traversal_points[1].y; ups[2].i = (ups[3].i - ups[1].i) * 0.5f + ups[1].i; ups[2].j = (ups[3].j - ups[1].j) * 0.5f + ups[1].j; @@ -913,20 +919,20 @@ static void get_particle_world_position( sides[2].j = (sides[3].j - sides[1].j) * 0.5f + sides[1].j; sides[2].k = (sides[3].k - sides[1].k) * 0.5f + sides[1].k; - knots[2] = (knots[3] - knots[1]) * 0.5f + knots[1]; + traversal_time_indices[2] = (traversal_time_indices[3] - traversal_time_indices[1]) * 0.5f + traversal_time_indices[1]; break; case 1: - positions[2] = glow->markers[1].matrix.position; + traversal_points[2] = glow->markers[1].matrix.position; ups[2] = glow->markers[1].matrix.up; cross_product3d( &glow->markers[1].matrix.up, &glow->markers[1].matrix.forward, &sides[2]); - positions[1].x = (positions[2].x - positions[0].x) * 0.5f + positions[0].x; - positions[1].y = (positions[2].y - positions[0].y) * 0.5f + positions[0].y; - positions[1].z = (positions[2].z - positions[0].z) * 0.5f + positions[0].y; + traversal_points[1].x = (traversal_points[2].x - traversal_points[0].x) * 0.5f + traversal_points[0].x; + traversal_points[1].y = (traversal_points[2].y - traversal_points[0].y) * 0.5f + traversal_points[0].y; + traversal_points[1].z = (traversal_points[2].z - traversal_points[0].z) * 0.5f + traversal_points[0].y; ups[1].i = (ups[2].i - ups[0].i) * 0.5f + ups[0].i; ups[1].j = (ups[2].j - ups[0].j) * 0.5f + ups[0].j; @@ -935,8 +941,8 @@ static void get_particle_world_position( sides[1].j = (sides[2].j - sides[0].j) * 0.5f + sides[0].j; sides[1].k = (sides[2].k - sides[0].k) * 0.5f + sides[0].k; - knots[1] = (glow->marker_time_index[1] - knots[0]) * 0.5f + knots[0]; - knots[2] = glow->marker_time_index[1]; + traversal_time_indices[1] = (glow->marker_time_index[1] - traversal_time_indices[0]) * 0.5f + traversal_time_indices[0]; + traversal_time_indices[2] = glow->marker_time_index[1]; break; } break; @@ -963,16 +969,16 @@ static void get_particle_world_position( last_marker_index++; } - knots[0] = glow->marker_time_index[first_marker_index]; - knots[1] = glow->marker_time_index[first_marker_index + 1]; - knots[2] = glow->marker_time_index[first_marker_index + 2]; - knots[3] = glow->marker_time_index[first_marker_index + 3]; + traversal_time_indices[0] = glow->marker_time_index[first_marker_index]; + traversal_time_indices[1] = glow->marker_time_index[first_marker_index + 1]; + traversal_time_indices[2] = glow->marker_time_index[first_marker_index + 2]; + traversal_time_indices[3] = glow->marker_time_index[first_marker_index + 3]; for (index = 0; index < 4; index++) { struct object_marker *marker = &glow->markers[glow->marker_order[first_marker_index + index]]; - positions[index] = marker->matrix.position; + traversal_points[index] = marker->matrix.position; ups[index] = marker->matrix.up; cross_product3d(&marker->matrix.up, &marker->matrix.forward, &sides[index]); } @@ -981,9 +987,9 @@ static void get_particle_world_position( for (index = 0; index < NUMBEROF(position_vectors); index++) { - position_vectors[index].i = positions[index].x; - position_vectors[index].j = positions[index].y; - position_vectors[index].k = positions[index].z; + position_vectors[index].i = traversal_points[index].x; + position_vectors[index].j = traversal_points[index].y; + position_vectors[index].k = traversal_points[index].z; } nonuniform_cubic_spline_vector3d( @@ -992,10 +998,10 @@ static void get_particle_world_position( &position_vectors[1], &position_vectors[2], &position_vectors[3], - knots[0], - knots[1], - knots[2], - knots[3], + traversal_time_indices[0], + traversal_time_indices[1], + traversal_time_indices[2], + traversal_time_indices[3], particle->t); nonuniform_cubic_spline_vector3d( &up, @@ -1003,10 +1009,10 @@ static void get_particle_world_position( &ups[1], &ups[2], &ups[3], - knots[0], - knots[1], - knots[2], - knots[3], + traversal_time_indices[0], + traversal_time_indices[1], + traversal_time_indices[2], + traversal_time_indices[3], particle->t); nonuniform_cubic_spline_vector3d( &side, @@ -1014,10 +1020,10 @@ static void get_particle_world_position( &sides[1], &sides[2], &sides[3], - knots[0], - knots[1], - knots[2], - knots[3], + traversal_time_indices[0], + traversal_time_indices[1], + traversal_time_indices[2], + traversal_time_indices[3], particle->t); particle->position.x = position.i; diff --git a/source/objects/widgets/glow.h b/source/objects/widgets/glow.h index 305eac97..41b8988d 100644 --- a/source/objects/widgets/glow.h +++ b/source/objects/widgets/glow.h @@ -18,12 +18,6 @@ header included in hcex build. /* ---------- structures */ -struct glow_globals -{ - struct data_array *glow_data; - struct data_array *glow_particle_data; -}; - /* ---------- prototypes/EXAMPLE.C */ void glow_initialize( @@ -46,8 +40,6 @@ void glow_submit( /* ---------- globals */ -extern struct glow_globals glow_globals; - /* ---------- public code */ #endif // __GLOW_H diff --git a/source/objects/widgets/lightning.c b/source/objects/widgets/lightning.c index 57322e9b..f8ec91ea 100644 --- a/source/objects/widgets/lightning.c +++ b/source/objects/widgets/lightning.c @@ -262,14 +262,14 @@ static void lightning_offset_marker_position( void lightning_submit( long object_index, - long lightning_index, + long widget_index, struct render_lighting const *lighting, struct render_animation const *animation) { (void)lighting; - if (object_index != NONE && lightning_index != NONE) + if (object_index != NONE && widget_index != NONE) { - struct lightning_datum *lightning = lightning_get(lightning_index); + struct lightning_datum *lightning = lightning_get(widget_index); struct lightning_definition *definition = lightning_definition_get(lightning->definition_index); struct object_marker marker; diff --git a/source/objects/widgets/lightning.h b/source/objects/widgets/lightning.h index a0fdda19..11dd86a4 100644 --- a/source/objects/widgets/lightning.h +++ b/source/objects/widgets/lightning.h @@ -60,7 +60,7 @@ void lightning_delete( void lightning_submit( long object_index, - long lightning_index, + long widget_index, struct render_lighting const *lighting, struct render_animation const *animation); diff --git a/source/objects/widgets/widgets.c b/source/objects/widgets/widgets.c index 76ba0d0a..3fd0caf0 100644 --- a/source/objects/widgets/widgets.c +++ b/source/objects/widgets/widgets.c @@ -145,6 +145,7 @@ static struct widget_type_definition data_0030b2b0[NUMBER_OF_WIDGET_TYPES] = lightning_submit } }; +struct data_array *widget_data; /* ---------- public code */ diff --git a/source/physics/bsp3d.c b/source/physics/bsp3d.c index 053d3c7b..fc89cf7a 100644 --- a/source/physics/bsp3d.c +++ b/source/physics/bsp3d.c @@ -86,7 +86,7 @@ static __inline real bsp3d_polygon_plane_distance_to_point( /* ---------- globals */ -extern long node_count; +long node_count; /* ---------- public code */ diff --git a/source/physics/collision_bsp.c b/source/physics/collision_bsp.c index 49456e37..299760c5 100644 --- a/source/physics/collision_bsp.c +++ b/source/physics/collision_bsp.c @@ -140,7 +140,7 @@ struct collision_bsp_test_pill_new_context typedef char collision_bsp_test_pill_new_context_size_assert[ sizeof(struct collision_bsp_test_pill_new_context) == 0x2C ? 1 : -1]; -struct collision_bsp_test_pill_context +struct test_pill_data { struct collision_bsp const *bsp; real_point3d const *point; @@ -157,9 +157,9 @@ struct collision_bsp_test_pill_context }; typedef char collision_bsp_test_pill_context_size_assert[ - sizeof(struct collision_bsp_test_pill_context) == 0x22C ? 1 : -1]; + sizeof(struct test_pill_data) == 0x22C ? 1 : -1]; -struct collision_bsp_test_sphere_context +struct test_sphere_data { struct collision_bsp const *bsp; short breakable_surface_count; @@ -177,13 +177,13 @@ struct collision_bsp_test_sphere_context }; typedef char collision_bsp_test_sphere_context_size_assert[ - sizeof(struct collision_bsp_test_sphere_context) == 0x228 ? 1 : -1]; + sizeof(struct test_sphere_data) == 0x228 ? 1 : -1]; typedef char collision_bsp_test_sphere_context_plane_stack_offset_assert[ - offsetof(struct collision_bsp_test_sphere_context, plane_stack) == 0x1C ? 1 : -1]; + offsetof(struct test_sphere_data, plane_stack) == 0x1C ? 1 : -1]; typedef char collision_bsp_test_sphere_context_projection_axis_offset_assert[ - offsetof(struct collision_bsp_test_sphere_context, projection_axis) == 0x21C ? 1 : -1]; + offsetof(struct test_sphere_data, projection_axis) == 0x21C ? 1 : -1]; typedef char collision_bsp_test_sphere_context_center2d_offset_assert[ - offsetof(struct collision_bsp_test_sphere_context, center2d) == 0x220 ? 1 : -1]; + offsetof(struct test_sphere_data, center2d) == 0x220 ? 1 : -1]; struct collision_leaf { @@ -273,26 +273,26 @@ static boolean pill_test_vector( real *t, real *edge_t); static boolean collision_surface_test_pill( - struct collision_bsp_test_pill_context *data, + struct test_pill_data *data, long surface_index); static boolean bsp2d_test_pill_recursive( - struct collision_bsp_test_pill_context *data, + struct test_pill_data *data, long child_index); static boolean bsp3d_test_pill_recursive( - struct collision_bsp_test_pill_context *data, - long node_index); + struct test_pill_data *data, + long child_index); static void add_feature( long *count, long *indices, long index); static void collision_surface_test_sphere( - struct collision_bsp_test_sphere_context *data, + struct test_sphere_data *data, long surface_index); static void bsp2d_test_sphere_recursive( - struct collision_bsp_test_sphere_context *data, + struct test_sphere_data *data, long child_index); static void bsp3d_test_sphere_recursive( - struct collision_bsp_test_sphere_context *data, + struct test_sphere_data *data, long node_index); void render_debug_collision_edge( struct collision_bsp *bsp, @@ -955,7 +955,7 @@ boolean collision_bsp_test_pill( real maximum_t, struct collision_bsp_test_pill_result *result) { - struct collision_bsp_test_pill_context context; + struct test_pill_data context; context.bsp = bsp; context.point = point; @@ -977,7 +977,7 @@ boolean collision_bsp_test_sphere( real radius, struct collision_bsp_test_sphere_result *result) { - struct collision_bsp_test_sphere_context context; + struct test_sphere_data context; short collision_function = 6 + (bsp == global_collision_bsp); collision_log_usage(collision_function); @@ -1068,7 +1068,7 @@ static void add_feature( } static void collision_surface_test_sphere( - struct collision_bsp_test_sphere_context *data, + struct test_sphere_data *data, long surface_index) { struct collision_surface const *surface = TAG_BLOCK_GET_ELEMENT( @@ -1423,7 +1423,7 @@ static boolean collision_bsp_test_pill_new_recursive( } static void bsp2d_test_sphere_recursive( - struct collision_bsp_test_sphere_context *data, + struct test_sphere_data *data, long child_index) { while (!(child_index & LONG_MIN)) @@ -1616,7 +1616,7 @@ static boolean pill_test_vector( } static void bsp3d_test_sphere_recursive( - struct collision_bsp_test_sphere_context *data, + struct test_sphere_data *data, long node_index) { while (!(node_index & LONG_MIN)) @@ -1695,17 +1695,17 @@ static void bsp3d_test_sphere_recursive( reference->plane_designator & LONG_MAX, real_plane3d); real plane_distance = -plane3d_distance_to_point(plane, data->center); - real_point3d projected_center; + real_point3d center_projected_on_plane; real absolute_i; real absolute_j; real absolute_k; short projection; - projected_center.x = + center_projected_on_plane.x = plane->n.i * plane_distance + data->center->x; - projected_center.y = + center_projected_on_plane.y = plane->n.j * plane_distance + data->center->y; - projected_center.z = + center_projected_on_plane.z = plane->n.k * plane_distance + data->center->z; absolute_i = fabs(plane->n.i); absolute_j = fabs(plane->n.j); @@ -1719,7 +1719,7 @@ static void bsp3d_test_sphere_recursive( projection_sign_from_vector3d(&plane->n, projection) != (reference->plane_designator & LONG_MIN ? TRUE : FALSE); project_point3d( - &projected_center, + ¢er_projected_on_plane, data->projection_axis, data->projection_sign, &data->center2d); @@ -1900,7 +1900,7 @@ static boolean collision_bsp_test_vector_recursive( } static boolean collision_surface_test_pill( - struct collision_bsp_test_pill_context *data, + struct test_pill_data *data, long surface_index) { boolean hit = FALSE; @@ -1981,7 +1981,7 @@ static boolean collision_surface_test_pill( } static boolean bsp2d_test_pill_recursive( - struct collision_bsp_test_pill_context *data, + struct test_pill_data *data, long child_index) { boolean hit = FALSE; @@ -2021,16 +2021,16 @@ static boolean bsp2d_test_pill_recursive( } static boolean bsp3d_test_pill_recursive( - struct collision_bsp_test_pill_context *data, - long node_index) + struct test_pill_data *data, + long child_index) { boolean hit = FALSE; - if (!(node_index & LONG_MIN)) + if (!(child_index & LONG_MIN)) { struct bsp3d_node const *node = TAG_BLOCK_GET_ELEMENT( &data->bsp->bsp3d.nodes, - node_index, + child_index, struct bsp3d_node); real_plane3d const *plane = TAG_BLOCK_GET_ELEMENT( &data->bsp->bsp3d.planes, @@ -2072,9 +2072,9 @@ static boolean bsp3d_test_pill_recursive( hit = TRUE; } } - else if (node_index != NONE) + else if (child_index != NONE) { - long leaf_index = node_index & LONG_MAX; + long leaf_index = child_index & LONG_MAX; struct collision_leaf const *leaf = TAG_BLOCK_GET_ELEMENT( &data->bsp->leaves, leaf_index, @@ -2121,7 +2121,7 @@ static boolean bsp3d_test_pill_recursive( short projection; real_point3d pill_point; real plane_distance; - real_point2d point2d; + real_point2d p2d; long surface_index; real_point3d start_point; real_point3d sweep_point; @@ -2147,10 +2147,10 @@ static boolean bsp3d_test_pill_recursive( &pill_point, data->projection_axis, data->projection_sign, - &point2d); + &p2d); surface_index = bsp2d_test_point( &data->bsp->bsp2d.nodes, - &point2d, + &p2d, reference->root_index); if (collision_surface_test_point( data->bsp, @@ -2159,7 +2159,7 @@ static boolean bsp3d_test_pill_recursive( surface_index, data->projection_axis, data->projection_sign, - &point2d)) + &p2d)) { struct collision_surface const *surface = TAG_BLOCK_GET_ELEMENT( &data->bsp->surfaces, diff --git a/source/physics/physics.c b/source/physics/physics.c index 17bdcc47..d11635c2 100644 --- a/source/physics/physics.c +++ b/source/physics/physics.c @@ -713,11 +713,11 @@ void physics_compute_new( &mass_point->position); if (powered_mass_point) { - real_matrix4x3 powered_matrix; + real_matrix4x3 powered_world_matrix; - matrix4x3_multiply(&instance->world_matrix, &powered_mass_point->rotation_matrix, &powered_matrix); - matrix4x3_transform_normal(&powered_matrix, &mass_point_definition->forward, &mass_point->forward); - matrix4x3_transform_normal(&powered_matrix, &mass_point_definition->up, &mass_point->up); + matrix4x3_multiply(&instance->world_matrix, &powered_mass_point->rotation_matrix, &powered_world_matrix); + matrix4x3_transform_normal(&powered_world_matrix, &mass_point_definition->forward, &mass_point->forward); + matrix4x3_transform_normal(&powered_world_matrix, &mass_point_definition->up, &mass_point->up); } else { @@ -897,7 +897,7 @@ void physics_compute_new( if (TEST_FLAG(powered_mass_point_definition->flags, _powered_mass_point_antigrav_bit)) { real probe_length = mass_point_definition->radius + powered_mass_point_definition->antigrav_height; - real_point3d probe_point = mass_point->position; + real_point3d point = mass_point->position; real_vector3d probe_vector; struct collision_result collision; @@ -905,7 +905,7 @@ void physics_compute_new( if (collision_test_vector( _collision_test_for_bipeds_dead_flags, - &probe_point, + &point, &probe_vector, instance->object_index, &collision)) @@ -1636,18 +1636,18 @@ static void physics_update_old( if (powered_mass_point) { - real_matrix4x3 powered_matrix; + real_matrix4x3 powered_world_matrix; matrix4x3_multiply( &world_matrix, &powered_mass_point->rotation_matrix, - &powered_matrix); + &powered_world_matrix); matrix4x3_transform_normal( - &powered_matrix, + &powered_world_matrix, &mass_point_definition->forward, &mass_point->forward); matrix4x3_transform_normal( - &powered_matrix, + &powered_world_matrix, &mass_point_definition->up, &mass_point->up); } @@ -1916,14 +1916,14 @@ static void physics_update_old( { real probe_length = mass_point_definition->radius + powered_mass_point_definition->antigrav_height; - real_point3d probe_point = mass_point->position; + real_point3d point = mass_point->position; real_vector3d probe_vector; struct collision_result collision; scale_vector3d(global_down3d, probe_length, &probe_vector); if (collision_test_vector( _collision_test_for_bipeds_dead_flags, - &probe_point, + &point, &probe_vector, object_index, &collision)) diff --git a/source/physics/point_physics.c b/source/physics/point_physics.c index 77a82f4f..86cac3aa 100644 --- a/source/physics/point_physics.c +++ b/source/physics/point_physics.c @@ -34,6 +34,7 @@ struct tag_reference_definition global_point_physics_reference = { 0, POINT_PHYS static real global_water_mass_over_radius_cubed = 0.0f; static real global_air_mass_over_radius_cubed = 0.0f; +boolean debug_point_physics; /* ---------- public code */ diff --git a/source/rasterizer/rasterizer_frame_statistics.c b/source/rasterizer/rasterizer_frame_statistics.c index 531aa45b..ff1a3bb7 100644 --- a/source/rasterizer/rasterizer_frame_statistics.c +++ b/source/rasterizer/rasterizer_frame_statistics.c @@ -460,15 +460,15 @@ void rasterizer_frame_statistics_draw( { if (rasterizer_debug_options.statistics_mode) { - char string[STATISTICS_TEXT_BUFFER_SIZE]; + char frame_statistics_string[STATISTICS_TEXT_BUFFER_SIZE]; point2d cursor = { 0, 0 }; short height_adjust = -4; short line_advance = -1; short left = rasterizer_globals.reserved04.frame_bounds.x0; short tab_stops[NUMBER_OF_STATISTICS_TAB_STOPS] = { 100, 200, 300, 400, 500, 600 }; - real_argb_color data_color = { 1.0f, 0.66f, 1.0f, 0.66f }; - real_argb_color header_color = { 1.0f, 1.0f, 1.0f, 1.0f }; - real_argb_color default_color = { 1.0f, 1.0f, 1.0f, 1.0f }; + real_argb_color statistics_color_plain = { 1.0f, 0.66f, 1.0f, 0.66f }; + real_argb_color statistics_color_bold = { 1.0f, 1.0f, 1.0f, 1.0f }; + real_argb_color white = { 1.0f, 1.0f, 1.0f, 1.0f }; long environment_vertices = rasterizer_frame_statistics.lightmap_dynamic_vertex_count + rasterizer_frame_statistics.shadow_vertex_count + @@ -532,12 +532,12 @@ void rasterizer_frame_statistics_draw( offset_rectangle2d(&bounds, 0, 32); interface_set_bitmap_text_draw_mode(_interface_font_terminal, NONE, 0, 0, 5, 0); - sprintf(string, "|n|tframerate|taverage (of %d)|tmin|tmax", + sprintf(frame_statistics_string, "|n|tframerate|taverage (of %d)|tmin|tmax", rasterizer_frame_statistics.fps_sample_count); tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - draw_string_set_color(&header_color); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + draw_string_set_color(&statistics_color_bold); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; if (rasterizer_debug_options.fps_accumulation) @@ -549,7 +549,7 @@ void rasterizer_frame_statistics_draw( system_milliseconds() - rasterizer_frame_statistics_private_globals.fps_accumulation_time; - sprintf(string, "|t%.0f|t%.0f/%.0f|t%.0f|t%.0f|n", + sprintf(frame_statistics_string, "|t%.0f|t%.0f/%.0f|t%.0f|t%.0f|n", rasterizer_frame_statistics.frames_per_second, rasterizer_frame_statistics.average_frames_per_second, accumulated_frames * 1000.0f / accumulated_time, @@ -558,7 +558,7 @@ void rasterizer_frame_statistics_draw( } else { - sprintf(string, "|t%.0f|t%.0f|t%.0f|t%.0f|n", + sprintf(frame_statistics_string, "|t%.0f|t%.0f|t%.0f|t%.0f|n", rasterizer_frame_statistics.frames_per_second, rasterizer_frame_statistics.average_frames_per_second, rasterizer_frame_statistics.minimum_frames_per_second, @@ -567,66 +567,66 @@ void rasterizer_frame_statistics_draw( tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - draw_string_set_color(&data_color); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + draw_string_set_color(&statistics_color_plain); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; if (rasterizer_debug_options.statistics_mode == _rasterizer_statistics_mode_objects) { tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - draw_string_set_color(&data_color); + draw_string_set_color(&statistics_color_plain); - sprintf(string, "|tfogged|t%d|n|tnormal|t%d|n|tfast|t%d|n|tscenery|t%d|n", + sprintf(frame_statistics_string, "|tfogged|t%d|n|tnormal|t%d|n|tfast|t%d|n|tscenery|t%d|n", rasterizer_frame_statistics.vertices_by_permutation[0], rasterizer_frame_statistics.vertices_by_permutation[1], rasterizer_frame_statistics.vertices_by_permutation[2], rasterizer_frame_statistics.vertices_by_permutation[3]); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tskinning|t%d|n|tlighting|t%d|n|tvertex shaders|t%d|n", + sprintf(frame_statistics_string, "|tskinning|t%d|n|tlighting|t%d|n|tvertex shaders|t%d|n", rasterizer_frame_statistics.model_skinning_constant_bytes, rasterizer_frame_statistics.model_lighting_constant_bytes, rasterizer_frame_statistics.model_vertex_shader_work_accumulated); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tlocal_player_count|t%d|n|tmain_get_window_count|t%d|n", + sprintf(frame_statistics_string, "|tlocal_player_count|t%d|n|tmain_get_window_count|t%d|n", local_player_count(), main_get_window_count()); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; } else if (rasterizer_debug_options.statistics_mode == _rasterizer_statistics_mode_geometry) { - sprintf(string, "|t|tvertices|ttriangles|tprimitives"); + sprintf(frame_statistics_string, "|t|tvertices|ttriangles|tprimitives"); tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - draw_string_set_color(&header_color); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + draw_string_set_color(&statistics_color_bold); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|ttotal|t%d|t%d|t%d|n", + sprintf(frame_statistics_string, "|ttotal|t%d|t%d|t%d|n", total_vertices, total_triangles, total_primitives); tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - draw_string_set_color(&data_color); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + draw_string_set_color(&statistics_color_plain); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tenvironment|t%d|t%d|t%d", + sprintf(frame_statistics_string, "|tenvironment|t%d|t%d|t%d", environment_vertices, environment_triangles, environment_primitives); tab_stops[0] = left + 25; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tlightmaps|t%d|t%d|t%d|n|tshadows (%d)|t%d|t%d|t%d|n|tlights|t%d|t%d|t%d|n|ttextures|t%d|t%d|t%d|n|tlights specular|t%d|t%d|t%d|n|tlightmaps specular|t%d|t%d|t%d|n|tlightmaps ref.mask|t%d|t%d|t%d|n|treflections|t%d|t%d|t%d|n|ttransparent|t%d|t%d/%d|t%d|n|tfog|t%d|t%d|t%d|n", + sprintf(frame_statistics_string, "|tlightmaps|t%d|t%d|t%d|n|tshadows (%d)|t%d|t%d|t%d|n|tlights|t%d|t%d|t%d|n|ttextures|t%d|t%d|t%d|n|tlights specular|t%d|t%d|t%d|n|tlightmaps specular|t%d|t%d|t%d|n|tlightmaps ref.mask|t%d|t%d|t%d|n|treflections|t%d|t%d|t%d|n|ttransparent|t%d|t%d/%d|t%d|n|tfog|t%d|t%d|t%d|n", rasterizer_frame_statistics.lightmap_dynamic_vertex_count, rasterizer_frame_statistics.lightmap_dynamic_triangle_count, rasterizer_frame_statistics.lightmap_dynamic_draw_count, @@ -661,30 +661,30 @@ void rasterizer_frame_statistics_draw( rasterizer_frame_statistics.environment_fog_dynamic_draw_count); tab_stops[0] = left + 50; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tmodel shadows (%d)|t%d|t%d|t%d", + sprintf(frame_statistics_string, "|tmodel shadows (%d)|t%d|t%d|t%d", rasterizer_frame_statistics.model_shadow_count, rasterizer_frame_statistics.model_shadow_vertex_count, rasterizer_frame_statistics.model_shadow_triangle_count, rasterizer_frame_statistics.model_shadow_draw_count); tab_stops[0] = left + 25; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tmodels (%d)|t%d|t%d|t%d", + sprintf(frame_statistics_string, "|tmodels (%d)|t%d|t%d|t%d", rasterizer_frame_statistics.model_count, model_vertices, model_triangles, model_primitives); tab_stops[0] = left + 25; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tsolid|t%d|t%d|t%d|n|ttransparent|t%d|t%d/%d|t%d|n", + sprintf(frame_statistics_string, "|tsolid|t%d|t%d|t%d|n|ttransparent|t%d|t%d/%d|t%d|n", rasterizer_frame_statistics.model_vertex_count, rasterizer_frame_statistics.model_triangle_count, rasterizer_frame_statistics.model_draw_count, @@ -694,34 +694,34 @@ void rasterizer_frame_statistics_draw( rasterizer_frame_statistics.transparent_model_submit_count); tab_stops[0] = left + 50; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tdecals|t%d|t%d|t%d|n", + sprintf(frame_statistics_string, "|tdecals|t%d|t%d|t%d|n", rasterizer_frame_statistics.decal_vertex_count, rasterizer_frame_statistics.decal_triangle_count, rasterizer_frame_statistics.decal_draw_count); tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tdynamic geometry|t%d/%d|t%d/%d|n", + sprintf(frame_statistics_string, "|tdynamic geometry|t%d/%d|t%d/%d|n", rasterizer_frame_statistics.dynamic_vertex_count, rasterizer_frame_statistics.dynamic_vertex_buffer_count, rasterizer_frame_statistics.dynamic_triangle_count, rasterizer_frame_statistics.dynamic_triangle_buffer_count); tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|t%d dynamic lights|n|t%d lens flares|n", + sprintf(frame_statistics_string, "|t%d dynamic lights|n|t%d lens flares|n", rasterizer_frame_statistics.dynamic_light_count, rasterizer_frame_statistics.lens_flare_count); tab_stops[0] = left; draw_string_set_tab_stops(tab_stops, NUMBER_OF_STATISTICS_TAB_STOPS); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; } else if (rasterizer_debug_options.statistics_mode == _rasterizer_statistics_mode_profile) @@ -733,13 +733,13 @@ void rasterizer_frame_statistics_draw( tab_stops[2] = left + 300; tab_stops[3] = 600; - sprintf(string, "|tGPU profile|ttime (msecs)|tdata (bytes)"); + sprintf(frame_statistics_string, "|tGPU profile|ttime (msecs)|tdata (bytes)"); draw_string_set_tab_stops(tab_stops, 4); - draw_string_set_color(&header_color); + draw_string_set_color(&statistics_color_bold); cursor.y -= 30; - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - draw_string_set_color(&data_color); + draw_string_set_color(&statistics_color_plain); for (profile = 0; profile < NUMBER_OF_RASTERIZER_PROFILES; profile++) { @@ -747,27 +747,27 @@ void rasterizer_frame_statistics_draw( if (profile_time >= 0.0f) { - sprintf(string, "|t%s|t%.2f|t%d", + sprintf(frame_statistics_string, "|t%s|t%.2f|t%d", rasterizer_profile_get_string(profile), profile_time * 1000.0f, rasterizer_profile_query_pushbuffer(profile)); } else { - sprintf(string, "|t%s|t----|t0", + sprintf(frame_statistics_string, "|t%s|t----|t0", rasterizer_profile_get_string(profile)); } - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; } - sprintf(string, "|ttotal|t%.2f|t%d|n", + sprintf(frame_statistics_string, "|ttotal|t%.2f|t%d|n", rasterizer_profile_query(NUMBER_OF_RASTERIZER_PROFILES) * 1000.0f, rasterizer_profile_query_pushbuffer(NUMBER_OF_RASTERIZER_PROFILES)); draw_string_set_color(global_real_argb_yellow); bounds.y0 += 4; - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; } else if (rasterizer_debug_options.statistics_mode == _rasterizer_statistics_mode_memory) @@ -801,45 +801,45 @@ void rasterizer_frame_statistics_draw( tab_stops[0] = left; tab_stops[1] = left + 300; tab_stops[2] = 600; - sprintf(string, "|tallocation|tmemory usage (bytes)"); + sprintf(frame_statistics_string, "|tallocation|tmemory usage (bytes)"); draw_string_set_tab_stops(tab_stops, 3); - draw_string_set_color(&header_color); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + draw_string_set_color(&statistics_color_bold); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - draw_string_set_color(&data_color); + draw_string_set_color(&statistics_color_plain); for (report_index = 0; report_index < NUMBER_OF_MEMORY_USAGE_REPORTS; report_index++) { - sprintf(string, "|t%s|t%d", + sprintf(frame_statistics_string, "|t%s|t%d", memory_usage[report_index].name, memory_usage[report_index].allocation); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; total_allocation += memory_usage[report_index].allocation; total_unique_allocation += memory_usage[report_index].allocation - memory_usage[report_index].shared; } - sprintf(string, "|n|ttotal|t%d (%d)", total_allocation, total_unique_allocation); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + sprintf(frame_statistics_string, "|n|ttotal|t%d (%d)", total_allocation, total_unique_allocation); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; GlobalMemoryStatus(&memory_status); - draw_string_set_color(&header_color); + draw_string_set_color(&statistics_color_bold); - sprintf(string, "|n|tsystem total|t%dKb", memory_status.dwTotalPhys >> 10); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + sprintf(frame_statistics_string, "|n|tsystem total|t%dKb", memory_status.dwTotalPhys >> 10); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - sprintf(string, "|tsystem available|t%dKb", memory_status.dwAvailPhys >> 10); - rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, string); + sprintf(frame_statistics_string, "|tsystem available|t%dKb", memory_status.dwAvailPhys >> 10); + rasterizer_draw_string(&bounds, NULL, &cursor, height_adjust, frame_statistics_string); bounds.y0 = cursor.y + line_advance; - draw_string_set_color(&data_color); + draw_string_set_color(&statistics_color_plain); } draw_string_set_tab_stops(NULL, 0); - draw_string_set_color(&default_color); + draw_string_set_color(&white); } if (rasterizer_debug_options.profile_log_enabled) diff --git a/source/rasterizer/rasterizer_geometry.c b/source/rasterizer/rasterizer_geometry.c index 1b2eaf17..73da8ba8 100644 --- a/source/rasterizer/rasterizer_geometry.c +++ b/source/rasterizer/rasterizer_geometry.c @@ -97,6 +97,7 @@ symbols in this file: #include "cseries.h" #include "cseries/errors.h" #include "math/real_math.h" +#include "rasterizer/rasterizer_model_types.h" #include "rasterizer_geometry.h" #include "rasterizer_geometry_compression.h" @@ -137,28 +138,6 @@ struct environment_lightmap_vertex_compressed short lightmap_v; }; -struct model_vertex_uncompressed -{ - real_point3d position; - real_vector3d normal; - real_vector3d binormal; - real_vector3d tangent; - real_point2d texcoord; - short nodes[2]; - real node_weights[2]; -}; - -struct model_vertex_compressed -{ - real_point3d position; - unsigned long normal; - unsigned long binormal; - unsigned long tangent; - point2d texcoord; - byte nodes[2]; - short node_weight; -}; - /* ---------- globals */ static short const rasterizer_vertex_type_sizes[]= diff --git a/source/rasterizer/rasterizer_lights.c b/source/rasterizer/rasterizer_lights.c index 0f881bbd..c1bef69a 100644 --- a/source/rasterizer/rasterizer_lights.c +++ b/source/rasterizer/rasterizer_lights.c @@ -869,9 +869,9 @@ void rasterizer_lens_flares_draw( LENS_FLARE_LIGHT_COLOR_ALPHA(lens_flare_parameters->compressed_light_color) > 0 && definition->reflections.count > 0) { - real_point3d position = lens_flare_parameters->position; - real_vector3d camera_offset; - real_vector3d mirror; + real_point3d corona_position = lens_flare_parameters->position; + real_vector3d eye_to_corona_vector; + real_vector3d corona_axis; real depth; real occlusion_fraction; real light_brightness; @@ -885,13 +885,13 @@ void rasterizer_lens_flares_draw( vector_from_points3d( &global_window_parameters.camera.position, - &position, - &camera_offset); - depth = dot_product3d(&global_window_parameters.camera.forward, &camera_offset); + &corona_position, + &eye_to_corona_vector); + depth = dot_product3d(&global_window_parameters.camera.forward, &eye_to_corona_vector); - scale_vector3d(&global_window_parameters.camera.forward, depth, &mirror); - subtract_vectors3d(&mirror, &camera_offset, &mirror); - scale_vector3d(&mirror, 2.0f, &mirror); + scale_vector3d(&global_window_parameters.camera.forward, depth, &corona_axis); + subtract_vectors3d(&corona_axis, &eye_to_corona_vector, &corona_axis); + scale_vector3d(&corona_axis, 2.0f, &corona_axis); occlusion_fraction = *occlusion_test_result*(1.0f/255.0f); @@ -915,14 +915,14 @@ void rasterizer_lens_flares_draw( definition->corona_rotation_function, lens_flare_parameters)*definition->corona_rotation_function_scale; screen_rotation = (real)atan2( - dot_product3d(&global_window_parameters.frustum.view_to_world.forward, &camera_offset), - dot_product3d(&global_window_parameters.frustum.view_to_world.left, &camera_offset))*(180.0f/((real)M_PI)); + dot_product3d(&global_window_parameters.frustum.view_to_world.forward, &eye_to_corona_vector), + dot_product3d(&global_window_parameters.frustum.view_to_world.left, &eye_to_corona_vector))*(180.0f/((real)M_PI)); cosine_scale = 1.0f/ (definition->runtime_cosine_falloff_angle-definition->runtime_cosine_cutoff_angle); cosine_offset = -(definition->runtime_cosine_cutoff_angle*cosine_scale); - normalize3d(&camera_offset); + normalize3d(&eye_to_corona_vector); scale_functions[_lens_flare_reflection_scale_function_none] = 1.0f; scale_functions[_lens_flare_reflection_scale_function_light_direction] = PIN( @@ -930,11 +930,11 @@ void rasterizer_lens_flares_draw( 0.0f, 1.0f); scale_functions[_lens_flare_reflection_scale_function_light_to_camera] = PIN( - -dot_product3d(&direction, &camera_offset)*cosine_scale+cosine_offset, + -dot_product3d(&direction, &eye_to_corona_vector)*cosine_scale+cosine_offset, 0.0f, 1.0f); scale_functions[_lens_flare_reflection_scale_function_camera_direction] = PIN( - dot_product3d(&global_window_parameters.camera.forward, &camera_offset)*cosine_scale+cosine_offset, + dot_product3d(&global_window_parameters.camera.forward, &eye_to_corona_vector)*cosine_scale+cosine_offset, 0.0f, 1.0f); @@ -964,7 +964,7 @@ void rasterizer_lens_flares_draw( real radius = radius_lower_bound+ (reflection->radius_upper_bounds-radius_lower_bound)*light_scale; real_argb_color color; - real_vector2d radius_scale; + real_vector2d scale; real rotation; pixel32 pixel; real tint_factor; @@ -1042,12 +1042,12 @@ void rasterizer_lens_flares_draw( if (reflection_index == 0) { rotation = corona_rotation+reflection->rotation_offset; - radius_scale = definition->corona_radius_scale; + scale = definition->corona_radius_scale; } else { rotation = reflection->rotation_offset; - radius_scale.i = radius_scale.j = 1.0f; + scale.i = scale.j = 1.0f; } if (TEST_FLAG(reflection->flags, _lens_flare_reflection_rotate_from_center_of_screen_bit)) @@ -1067,9 +1067,9 @@ void rasterizer_lens_flares_draw( real offset = reflection->offset; real_point3d point; - point.x = offset*mirror.i + position.x; - point.y = offset*mirror.j + position.y; - point.z = offset*mirror.k + position.z; + point.x = offset*corona_axis.i + corona_position.x; + point.y = offset*corona_axis.j + corona_position.y; + point.z = offset*corona_axis.k + corona_position.z; if (rasterizer_widget_set_texture( 0, @@ -1092,7 +1092,7 @@ void rasterizer_lens_flares_draw( rasterizer_widget_draw_sprite3d( &point, radius, - &radius_scale, + &scale, rotation*(_pi/180.0f), pixel); } diff --git a/source/rasterizer/rasterizer_lights.h b/source/rasterizer/rasterizer_lights.h index 3ded0c2b..116e7ae7 100644 --- a/source/rasterizer/rasterizer_lights.h +++ b/source/rasterizer/rasterizer_lights.h @@ -41,7 +41,7 @@ void rasterizer_lens_flares_submit_occlusion_tests( void rasterizer_lens_flares_draw( void); void rasterizer_sun_glow_draw( - struct rasterizer_lens_flare_submit_parameters const *parameters); + struct rasterizer_lens_flare_submit_parameters const *flare); /* ---------- globals */ diff --git a/source/rasterizer/rasterizer_model_types.h b/source/rasterizer/rasterizer_model_types.h index 03e6e67a..58ba9104 100644 --- a/source/rasterizer/rasterizer_model_types.h +++ b/source/rasterizer/rasterizer_model_types.h @@ -48,7 +48,7 @@ struct render_model_effect real parameter; long source_object_index; real_point3d source_object_centroid; - struct shader const *modifier_shader; + struct shader *modifier_shader; struct render_animation modifier_animation; }; diff --git a/source/rasterizer/xbox/rasterizer_xbox_environment.c b/source/rasterizer/xbox/rasterizer_xbox_environment.c index 6b8961cf..4df20253 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_environment.c +++ b/source/rasterizer/xbox/rasterizer_xbox_environment.c @@ -139,7 +139,6 @@ symbols in this file: /* ---------- headers */ #define REAL_MATH_EXTERNAL_POINT_FROM_LINE3D -#define REAL_MATH_EXTERNAL_SCALE_VECTOR3D #include "cseries.h" #include "bitmaps/bitmaps.h" #include "cseries/errors.h" @@ -150,7 +149,6 @@ symbols in this file: #include "math/periodic_functions.h" #include "math/real_math.h" #undef REAL_MATH_EXTERNAL_POINT_FROM_LINE3D -#undef REAL_MATH_EXTERNAL_SCALE_VECTOR3D #include "rasterizer/rasterizer.h" #include "rasterizer/rasterizer_console_vars.h" #include "rasterizer/rasterizer_environment.h" @@ -3255,13 +3253,12 @@ static void rasterizer_environment_specular_spot_light_begin( rasterizer_debug_options.draw_environment_specular_lights) { struct rasterizer_light_submit_parameters *light; + real_matrix4x3 light_matrix; long gel_bitmap_index; - real_vector3d forward; - real_vector3d side; - real_vector3d up; - real_vector4d vertex_constants[5]; real radius; + real inner_radius; real cone_scale; + real_vector4d vertex_constants[5]; match_assert( "c:\\halo\\SOURCE\\rasterizer\\xbox\\rasterizer_xbox_environment.c", @@ -3277,32 +3274,34 @@ static void rasterizer_environment_specular_spot_light_begin( if (gel_bitmap_index == NONE) gel_bitmap_index = light->definition->gel.secondary_map.index; - forward = light->forward; - up = light->up; - normalize3d(cross_product3d(&forward, &up, &side)); + light_matrix.forward = light->forward; + light_matrix.up = light->up; + cross_product3d(&light->forward, &light->up, &light_matrix.left); + normalize3d(&light_matrix.left); radius = light->definition->geometry.specular_radius_multiplier * light->radius; - cone_scale = 1.0f / (radius - radius * 0.5f); + inner_radius = radius * 0.5f; + cone_scale = 1.0f / (radius - inner_radius); vertex_constants[0].i = light->position.x; vertex_constants[0].j = light->position.y; vertex_constants[0].k = light->position.z; vertex_constants[0].l = 0.5f / radius; - vertex_constants[1].i = -forward.i; - vertex_constants[1].j = -forward.j; - vertex_constants[1].k = -forward.k; + vertex_constants[1].i = -light_matrix.forward.i; + vertex_constants[1].j = -light_matrix.forward.j; + vertex_constants[1].k = -light_matrix.forward.k; vertex_constants[1].l = 1.0f; - vertex_constants[2].i = -side.i; - vertex_constants[2].j = -side.j; - vertex_constants[2].k = -side.k; + vertex_constants[2].i = -light_matrix.left.i; + vertex_constants[2].j = -light_matrix.left.j; + vertex_constants[2].k = -light_matrix.left.k; vertex_constants[2].l = 1.0f; - vertex_constants[3].i = -up.i; - vertex_constants[3].j = -up.j; - vertex_constants[3].k = -up.k; + vertex_constants[3].i = -light_matrix.up.i; + vertex_constants[3].j = -light_matrix.up.j; + vertex_constants[3].k = -light_matrix.up.k; vertex_constants[3].l = 1.0f; - vertex_constants[4].i = forward.i * cone_scale; - vertex_constants[4].j = forward.j * cone_scale; - vertex_constants[4].k = forward.k * cone_scale; - vertex_constants[4].l = -(cone_scale * (radius * 0.5f)); + vertex_constants[4].i = light_matrix.forward.i * cone_scale; + vertex_constants[4].j = light_matrix.forward.j * cone_scale; + vertex_constants[4].k = light_matrix.forward.k * cone_scale; + vertex_constants[4].l = -cone_scale * inner_radius; D3DDevice_SetVertexShaderConstant(-81, vertex_constants, 5); rasterizer_set_texture(1, 2, 1, gel_bitmap_index, 0); diff --git a/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c b/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c index 2c2b68fb..386be1a3 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c +++ b/source/rasterizer/xbox/rasterizer_xbox_environment_fog.c @@ -134,6 +134,7 @@ symbols in this file: #include "rasterizer/rasterizer_console_vars.h" #include "rasterizer/common/rasterizer_common.h" #include "rasterizer/rasterizer_geometry.h" +#include "rasterizer/rasterizer_model_types.h" #include "rasterizer/rasterizer_transparent_geometry.h" #include "render/render.h" #include "shaders/shader_definitions.h" @@ -299,31 +300,6 @@ struct shader_transparent_chicago_definition struct tag_reference map; }; -struct rasterizer_model_effect_parameters -{ - short type; - word pad02; - real intensity; - byte reserved08[4]; - long source_object_index; - real_point3d centroid; - struct shader *shader; - struct render_animation animation; -}; - -struct rasterizer_model_begin_parameters -{ - unsigned long geometry_flags; - long unique_identifier; - struct render_skinning skinning; - struct render_lighting lighting; - struct render_animation animation; - struct rasterizer_model_effect_parameters effect; - real_point3d centroid; - real radius; - real_vector2d base_map_scale; -}; - struct transparent_geometry_group { unsigned long geometry_flags; @@ -332,7 +308,7 @@ struct transparent_geometry_group struct shader *shader; short shader_permutation_index; word pad12; - struct rasterizer_model_effect_parameters effect; + struct render_model_effect effect; real_vector2d model_base_map_scale; long dynamic_triangle_buffer_index; struct triangle_buffer const *triangle_buffer; diff --git a/source/rasterizer/xbox/rasterizer_xbox_lights.c b/source/rasterizer/xbox/rasterizer_xbox_lights.c index 1ae95b0c..2cfc3f9b 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_lights.c +++ b/source/rasterizer/xbox/rasterizer_xbox_lights.c @@ -155,7 +155,7 @@ extern struct pixel_shader_definition pixel_shader; /* ---------- public code */ void rasterizer_sun_glow_draw( - struct rasterizer_lens_flare_submit_parameters const *parameters) + struct rasterizer_lens_flare_submit_parameters const *flare) { real vertex_constants[5][4]; real_point3d occlusion_point; @@ -163,8 +163,8 @@ void rasterizer_sun_glow_draw( real_rectangle2d screen_bounds; real brightness; real_rectangle2d bounds; - real_vector2d projected_axes; - real_point3d projected_center; + real_vector2d axes; + real_point3d center; real_vector3d direction; real intensity; short viewport_width; @@ -180,9 +180,9 @@ void rasterizer_sun_glow_draw( 583, global_d3d_device); - direction.i = parameters->position.x - global_window_parameters.camera.position.x; - direction.j = parameters->position.y - global_window_parameters.camera.position.y; - direction.k = parameters->position.z - global_window_parameters.camera.position.z; + direction.i = flare->position.x - global_window_parameters.camera.position.x; + direction.j = flare->position.y - global_window_parameters.camera.position.y; + direction.k = flare->position.z - global_window_parameters.camera.position.z; normalize3d(&direction); intensity = @@ -235,22 +235,22 @@ void rasterizer_sun_glow_draw( vertex_constants, 5); - direction = uncompress_int32_to_real_vector3d(parameters->compressed_direction); - occlusion_point.x = parameters->definition->occlusion_radius * direction.i + - parameters->position.x; - occlusion_point.y = parameters->definition->occlusion_radius * direction.j + - parameters->position.y; - occlusion_point.z = parameters->definition->occlusion_radius * direction.k + - parameters->position.z; + direction = uncompress_int32_to_real_vector3d(flare->compressed_direction); + occlusion_point.x = flare->definition->occlusion_radius * direction.i + + flare->position.x; + occlusion_point.y = flare->definition->occlusion_radius * direction.j + + flare->position.y; + occlusion_point.z = flare->definition->occlusion_radius * direction.k + + flare->position.z; if (rasterizer_project_billboard( &occlusion_point, - parameters->definition->occlusion_radius, - &projected_center, - &projected_axes)) + flare->definition->occlusion_radius, + ¢er, + &axes)) { - center_x = (real)floor(projected_center.x + 0.5f); - center_y = (real)floor(projected_center.y + 0.5f); + center_x = (real)floor(center.x + 0.5f); + center_y = (real)floor(center.y + 0.5f); bounds.x0 = center_x - 32.0f; bounds.y0 = center_y - 32.0f; @@ -398,7 +398,7 @@ void rasterizer_sun_glow_draw( 0, bounds.x0, bounds.y0, - projected_center.z, + center.z, 1.0f); IDirect3DDevice8_SetVertexData2s(global_d3d_device, 4, 1, 0); IDirect3DDevice8_SetVertexData4f( @@ -406,7 +406,7 @@ void rasterizer_sun_glow_draw( 0, bounds.x1, bounds.y0, - projected_center.z, + center.z, 1.0f); IDirect3DDevice8_SetVertexData2s(global_d3d_device, 4, 1, 1); IDirect3DDevice8_SetVertexData4f( @@ -414,7 +414,7 @@ void rasterizer_sun_glow_draw( 0, bounds.x1, bounds.y1, - projected_center.z, + center.z, 1.0f); IDirect3DDevice8_SetVertexData2s(global_d3d_device, 4, 0, 1); IDirect3DDevice8_SetVertexData4f( @@ -422,7 +422,7 @@ void rasterizer_sun_glow_draw( 0, bounds.x0, bounds.y1, - projected_center.z, + center.z, 1.0f); IDirect3DDevice8_End(global_d3d_device); diff --git a/source/rasterizer/xbox/rasterizer_xbox_models.c b/source/rasterizer/xbox/rasterizer_xbox_models.c index ae5b6e5a..b7eecb48 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_models.c +++ b/source/rasterizer/xbox/rasterizer_xbox_models.c @@ -117,6 +117,7 @@ symbols in this file: #include #include "interface/progress_bar_internal.h" +#include "rasterizer/rasterizer_model_types.h" #include "rasterizer/xbox/rasterizer_xbox.h" #include "rasterizer/xbox/rasterizer_xbox_pixel_shader.h" #include "rasterizer/xbox/rasterizer_xbox_draw_primitives.h" @@ -209,31 +210,6 @@ enum /* ---------- structures */ -struct rasterizer_model_effect_parameters -{ - short type; - word pad02; - real intensity; - byte reserved08[4]; - long source_object_index; - real_point3d centroid; - struct shader *shader; - struct render_animation animation; -}; - -struct rasterizer_model_begin_parameters -{ - unsigned long geometry_flags; - long unique_identifier; - struct render_skinning skinning; - struct render_lighting lighting; - struct render_animation animation; - struct rasterizer_model_effect_parameters effect; - real_point3d centroid; - real radius; - real_vector2d base_map_scale; -}; - struct shader_model_properties { word flags; @@ -305,7 +281,7 @@ struct transparent_geometry_group struct shader *shader; short shader_permutation_index; word pad12; - struct rasterizer_model_effect_parameters effect; + struct render_model_effect effect; real_vector2d model_base_map_scale; long dynamic_triangle_buffer_index; struct triangle_buffer const *triangle_buffer; @@ -468,10 +444,10 @@ typedef char verify_shader_environment_cube_map_offset[ environment.reflection.cube_map) == 0x324 ? 1 : -1]; typedef char verify_rasterizer_model_parameters_effect_shader_offset[ - offsetof(struct rasterizer_model_begin_parameters, effect.shader) == 0xA8 + offsetof(struct rasterizer_model_begin_parameters, effect.modifier_shader) == 0xA8 ? 1 : -1]; typedef char verify_rasterizer_model_parameters_effect_animation_offset[ - offsetof(struct rasterizer_model_begin_parameters, effect.animation) == 0xAC + offsetof(struct rasterizer_model_begin_parameters, effect.modifier_animation) == 0xAC ? 1 : -1]; typedef char verify_rasterizer_models_statistics_vertex_shader_work_offset[ offsetof( @@ -1665,16 +1641,16 @@ void _rasterizer_model_draw( 676, shader); - if (local_parameters->effect.shader) + if (local_parameters->effect.modifier_shader) { intensity_exponent_source = NONE; - if (local_parameters->effect.shader->base.type == + if (local_parameters->effect.modifier_shader->base.type == _shader_type_transparent_plasma) { plasma = (struct shader_transparent_plasma_definition const *) shader_get_and_verify_type( - local_parameters->effect.shader, + local_parameters->effect.modifier_shader, _shader_type_transparent_plasma); intensity_exponent_source = plasma->intensity_exponent_source; } @@ -1682,12 +1658,12 @@ void _rasterizer_model_draw( if (intensity_exponent_source < 1 || intensity_exponent_source > NUMBER_OF_SHADER_ANIMATION_FUNCTIONS || - !local_parameters->effect.animation.values || - local_parameters->effect.animation.values[ + !local_parameters->effect.modifier_animation.values || + local_parameters->effect.modifier_animation.values[ intensity_exponent_source-1] != 0.0f) { group = _rasterizer_model_transparent_geometry_submit( - local_parameters->effect.shader, + local_parameters->effect.modifier_shader, shader_permutation_index, triangle_buffer, dynamic_triangle_buffer_index, @@ -1700,7 +1676,7 @@ void _rasterizer_model_draw( if (group) { group->animation = rasterizer_memory_alloc( - &local_parameters->effect.animation, + &local_parameters->effect.modifier_animation, sizeof(struct render_animation)); } } @@ -2474,7 +2450,7 @@ struct transparent_geometry_group *_rasterizer_model_transparent_geometry_submit struct transparent_geometry_group *group; unsigned long geometry_flags; real_vector3d relative_centroid; - real_plane3d plane; + real_plane3d zero_plane; boolean alpha_blended_decal; boolean submit_decals; @@ -2578,10 +2554,10 @@ struct transparent_geometry_group *_rasterizer_model_transparent_geometry_submit if (group) { - plane.n.i = 0.0f; - plane.n.j = 0.0f; - plane.n.k = 0.0f; - plane.d = 0.0f; + zero_plane.n.i = 0.0f; + zero_plane.n.j = 0.0f; + zero_plane.n.k = 0.0f; + zero_plane.d = 0.0f; group->geometry_flags = geometry_flags; group->object_index = local_parameters->unique_identifier; @@ -2598,7 +2574,7 @@ struct transparent_geometry_group *_rasterizer_model_transparent_geometry_submit local_parameters->effect.source_object_index!=0); group->source_object_index = local_parameters->effect.source_object_index; - group->centroid = local_parameters->effect.centroid; + group->centroid = local_parameters->effect.source_object_centroid; } group->shader = shader; group->shader_permutation_index = shader_permutation_index; @@ -2617,7 +2593,7 @@ struct transparent_geometry_group *_rasterizer_model_transparent_geometry_submit group->z_sort = -dot_product3d( &global_window_parameters.camera.forward, &relative_centroid); - group->plane = plane; + group->plane = zero_plane; group->model_base_map_scale.i = local_parameters->base_map_scale.i; group->model_base_map_scale.j = local_parameters->base_map_scale.j; group->previous_group_presorted_index = NONE; diff --git a/source/rasterizer/xbox/rasterizer_xbox_shadows.c b/source/rasterizer/xbox/rasterizer_xbox_shadows.c index 1e44ba6f..80c3ac8d 100644 --- a/source/rasterizer/xbox/rasterizer_xbox_shadows.c +++ b/source/rasterizer/xbox/rasterizer_xbox_shadows.c @@ -84,6 +84,7 @@ symbols in this file: * replace these wrappers with handwritten bodies. */ #include "rasterizer/rasterizer.h" #include "rasterizer/rasterizer_console_vars.h" +#include "rasterizer/rasterizer_model_types.h" #include #include "rasterizer/xbox/rasterizer_xbox.h" #include "rasterizer/xbox/rasterizer_xbox_pixel_shader.h" @@ -133,32 +134,6 @@ enum /* ---------- structures */ -struct rasterizer_model_lighting_parameters -{ - byte data[0x74]; -}; - -struct rasterizer_model_effect_parameters -{ - short type; - word pad02; - real intensity; - byte reserved08[0x20]; -}; - -struct rasterizer_model_begin_parameters -{ - unsigned long geometry_flags; - long unique_identifier; - struct render_skinning skinning; - struct rasterizer_model_lighting_parameters lighting; - struct render_animation animation; - struct rasterizer_model_effect_parameters effect; - real_point3d centroid; - real radius; - real_vector2d base_map_scale; -}; - struct shader_model_definition { struct shader shader; diff --git a/source/render/render_cameras.c b/source/render/render_cameras.c index 9e415372..bcd26cd0 100644 --- a/source/render/render_cameras.c +++ b/source/render/render_cameras.c @@ -1123,10 +1123,10 @@ void render_camera_build_frustum( real field_of_view_tangent; real projection_x_scale; real projection_y_scale; - real_vector3d view_left; - real_vector3d view_up; - real_vector3d view_backward; - real_vector3d plane_normal; + real_vector3d x_axis; + real_vector3d y_axis; + real_vector3d z_axis; + real_vector3d viewspace_normal; real_plane3d view_plane; real left_plane_z; real bottom_plane_z; @@ -1209,15 +1209,15 @@ void render_camera_build_frustum( 436, camera->viewport_bounds.y0viewport_bounds.y1); - cross_product3d(&camera->forward, &camera->up, &view_left); - cross_product3d(&view_left, &camera->forward, &view_up); - negate_vector3d(&camera->forward, &view_backward); - normalize3d(&view_left); - normalize3d(&view_up); - normalize3d(&view_backward); - frustum->view_to_world.forward = view_left; - frustum->view_to_world.left = view_up; - frustum->view_to_world.up = view_backward; + cross_product3d(&camera->forward, &camera->up, &x_axis); + cross_product3d(&x_axis, &camera->forward, &y_axis); + negate_vector3d(&camera->forward, &z_axis); + normalize3d(&x_axis); + normalize3d(&y_axis); + normalize3d(&z_axis); + frustum->view_to_world.forward = x_axis; + frustum->view_to_world.left = y_axis; + frustum->view_to_world.up = z_axis; frustum->view_to_world.position = camera->position; frustum->view_to_world.scale = 1.0f; matrix4x3_inverse(&frustum->view_to_world, &frustum->world_to_view); @@ -1230,43 +1230,43 @@ void render_camera_build_frustum( 459, valid_real_matrix4x3(&frustum->view_to_world)); - plane_normal.i = -projection_x_scale; - plane_normal.j = 0.0f; + viewspace_normal.i = -projection_x_scale; + viewspace_normal.j = 0.0f; left_plane_z = bounds_center_x + 1.0f; - plane_normal.k = left_plane_z; - normalize3d(&plane_normal); - plane3d_from_point_and_normal(&view_plane, global_origin3d, &plane_normal); + viewspace_normal.k = left_plane_z; + normalize3d(&viewspace_normal); + plane3d_from_point_and_normal(&view_plane, global_origin3d, &viewspace_normal); matrix4x3_transform_plane( &frustum->view_to_world, &view_plane, &frustum->world_planes[_render_frustum_plane_left]); - plane_normal.i = projection_x_scale; - plane_normal.j = 0.0f; - plane_normal.k = 1.0f - bounds_center_x; - normalize3d(&plane_normal); - plane3d_from_point_and_normal(&view_plane, global_origin3d, &plane_normal); + viewspace_normal.i = projection_x_scale; + viewspace_normal.j = 0.0f; + viewspace_normal.k = 1.0f - bounds_center_x; + normalize3d(&viewspace_normal); + plane3d_from_point_and_normal(&view_plane, global_origin3d, &viewspace_normal); matrix4x3_transform_plane( &frustum->view_to_world, &view_plane, &frustum->world_planes[_render_frustum_plane_right]); - plane_normal.i = 0.0f; - plane_normal.j = -projection_y_scale; + viewspace_normal.i = 0.0f; + viewspace_normal.j = -projection_y_scale; bottom_plane_z = bounds_center_y + 1.0f; - plane_normal.k = bottom_plane_z; - normalize3d(&plane_normal); - plane3d_from_point_and_normal(&view_plane, global_origin3d, &plane_normal); + viewspace_normal.k = bottom_plane_z; + normalize3d(&viewspace_normal); + plane3d_from_point_and_normal(&view_plane, global_origin3d, &viewspace_normal); matrix4x3_transform_plane( &frustum->view_to_world, &view_plane, &frustum->world_planes[_render_frustum_plane_bottom]); - plane_normal.i = 0.0f; - plane_normal.j = projection_y_scale; - plane_normal.k = 1.0f - bounds_center_y; - normalize3d(&plane_normal); - plane3d_from_point_and_normal(&view_plane, global_origin3d, &plane_normal); + viewspace_normal.i = 0.0f; + viewspace_normal.j = projection_y_scale; + viewspace_normal.k = 1.0f - bounds_center_y; + normalize3d(&viewspace_normal); + plane3d_from_point_and_normal(&view_plane, global_origin3d, &viewspace_normal); matrix4x3_transform_plane( &frustum->view_to_world, &view_plane, diff --git a/source/render/render_objects.c b/source/render/render_objects.c index 7e5f7074..066d96e7 100644 --- a/source/render/render_objects.c +++ b/source/render/render_objects.c @@ -111,6 +111,7 @@ symbols in this file: #include "tag_files/tag_files.h" #include "saved games/game_state.h" #include "rasterizer/rasterizer_console_vars.h" +#include "rasterizer/rasterizer_model_types.h" /* ---------- constants */ @@ -157,18 +158,6 @@ enum /* ---------- structures */ -struct render_model_effect -{ - short type; - word pad; - real intensity; - real parameter; - long source_object_index; - real_point3d source_object_centroid; - struct shader const *modifier_shader; - struct render_animation modifier_animation; -}; - struct object_render_data { long object_index; diff --git a/source/render/render_sprite.c b/source/render/render_sprite.c index 952ed427..963ad649 100644 --- a/source/render/render_sprite.c +++ b/source/render/render_sprite.c @@ -135,22 +135,6 @@ struct build_sprite_vertex typedef char build_sprite_vertex_size_assert[ sizeof(struct build_sprite_vertex) == 0x18 ? 1 : -1]; -struct build_sprite_globals_data -{ - boolean initialized; - boolean debug_flag; - word pad02; - real screen_coverage; - short big_sprite_count; - word pad0A; - real screen_area_scale; - real_vector3d viewer_space_world_up; - real_vector3d viewer_space_world_forward; -}; - -typedef char build_sprite_globals_data_size_assert[ - sizeof(struct build_sprite_globals_data) == 0x28 ? 1 : -1]; - /* ---------- prototypes */ static void build_sprite_transform_origin_and_direction( @@ -180,8 +164,20 @@ static void build_sprite_compute_basis( /* ---------- globals */ -extern boolean debug_sprites; -extern struct build_sprite_globals_data build_sprite_globals; +boolean debug_sprites; +struct +{ + boolean initialized; + boolean debug_flag; + real screen_coverage; + short big_sprite_count; + real screen_area_scale; + real_vector3d viewer_space_world_up; + real_vector3d viewer_space_world_forward; +} build_sprite_globals; + +typedef char build_sprite_globals_data_size_assert[ + sizeof(build_sprite_globals) == 0x28 ? 1 : -1]; /* name from the 2003 PC demo PDB and the HCEX PDB (file static char *[3]); January's three pointers * name the same strings in the same order, followed by the enum definition at +0xC as in the demo */ @@ -404,9 +400,9 @@ void build_sprite( short vertex_index = NUMBER_OF_VERTICES_PER_QUADRILATERAL*group->sprite_count; real rotation_sine = 0.f; real rotation_cosine = 1.f; - real_rectangle3d bounds = *global_null_rectangle3d; + real_rectangle3d bounding_rectangle = *global_null_rectangle3d; real_point3d transformed_origin; - real_vector3d transformed_direction; + real_vector3d direction; real_matrix4x3 basis; pixel32 pixel; real alpha; @@ -424,13 +420,13 @@ void build_sprite( untransformed_origin, untransformed_direction, &transformed_origin, - &transformed_direction); + &direction); build_sprite_compute_basis( data, mode, flags, &transformed_origin, - &transformed_direction, + &direction, &basis); build_sprite_compute_scale(data, mode, flags, &transformed_origin, bitmap, &scale); @@ -499,18 +495,18 @@ void build_sprite( transformed_origin.y; point.z = (basis.forward.k*x + basis.left.k*y)*scale + transformed_origin.z; - if (point.xbounds.x1) - bounds.x1 = point.x; - if (point.ybounds.y1) - bounds.y1 = point.y; - if (point.zbounds.z1) - bounds.z1 = point.z; + if (point.xbounding_rectangle.x1) + bounding_rectangle.x1 = point.x; + if (point.ybounding_rectangle.y1) + bounding_rectangle.y1 = point.y; + if (point.zbounding_rectangle.z1) + bounding_rectangle.z1 = point.z; sprite_vertex->point = point; sprite_vertex->texture_coordinates.x = u; sprite_vertex->texture_coordinates.y = v; @@ -527,7 +523,7 @@ void build_sprite( if (!TEST_FLAG(data->flags, _build_sprites_screen_space_bit)) { - real coverage = render_frustum_cube_view_fraction(&render.frustum, &bounds); + real coverage = render_frustum_cube_view_fraction(&render.frustum, &bounding_rectangle); build_sprite_globals.screen_coverage += coverage; if (coverage>0.5f && build_sprite_globals.big_sprite_count++>10) @@ -582,7 +578,7 @@ void build_sprite( void build_sprite_rotational( struct build_sprite_data *data, unsigned long flags, - short sequence_index, + short first_sequence_index, short sprite_index, real_point3d const *untransformed_origin, real_vector3d const *untransformed_axis_of_rotation, @@ -591,8 +587,8 @@ void build_sprite_rotational( real_argb_color const *color, real fade) { - real_point3d transformed_origin; - real_vector3d transformed_axis_of_rotation; + real_point3d origin; + real_vector3d axis_of_rotation; real const quarter_circle = _pi/2; real fraction; real angle; @@ -613,12 +609,12 @@ void build_sprite_rotational( flags & FLAG(_build_sprite_rotational_viewer_space_bit), untransformed_origin, untransformed_axis_of_rotation, - &transformed_origin, - &transformed_axis_of_rotation); + &origin, + &axis_of_rotation); angle = angle_between_vectors3d( - (real_vector3d const *)&transformed_origin, - &transformed_axis_of_rotation) - quarter_circle; + (real_vector3d const *)&origin, + &axis_of_rotation) - quarter_circle; fraction = angle*angle/(quarter_circle*quarter_circle); fraction = PIN(fraction, 0.f, 1.f); @@ -626,7 +622,7 @@ void build_sprite_rotational( { struct bitmap_group_sequence *sequence = TAG_BLOCK_GET_ELEMENT( &bitmap_group_get(data->bitmap_group_index)->sequences, - sequence_index+1, + first_sequence_index+1, struct bitmap_group_sequence); short sprite_count = (short)sequence->sprites.count; unsigned long edge_flags = FLAG(_build_sprite_viewer_space_bit); @@ -652,9 +648,9 @@ void build_sprite_rotational( build_sprite( data, _build_sprite_normal, - sequence_index+1, + first_sequence_index+1, edge_sprite_index, - &transformed_origin, + &origin, NULL, sprite_rotation, scale, @@ -668,22 +664,22 @@ void build_sprite_rotational( { struct bitmap_group_sequence *sequence = TAG_BLOCK_GET_ELEMENT( &bitmap_group_get(data->bitmap_group_index)->sequences, - sequence_index, + first_sequence_index, struct bitmap_group_sequence); short sprite_count = (short)sequence->sprites.count; build_sprite( data, _build_sprite_normal, - sequence_index, + first_sequence_index, (short)fmod( sprite_count*one_over_full_circle*rotation + 0.5f, (real)sprite_count), - &transformed_origin, + &origin, NULL, arctangent( - transformed_axis_of_rotation.j, - transformed_axis_of_rotation.i), + axis_of_rotation.j, + axis_of_rotation.i), scale, color, fraction*fade, diff --git a/source/render/render_sprite.h b/source/render/render_sprite.h index 4116a032..413f2a7e 100644 --- a/source/render/render_sprite.h +++ b/source/render/render_sprite.h @@ -110,7 +110,7 @@ real build_sprite_compute_vertex_fade( void build_sprite_rotational( struct build_sprite_data *data, unsigned long flags, - short sequence_index, + short first_sequence_index, short sprite_index, real_point3d const *untransformed_origin, real_vector3d const *untransformed_axis_of_rotation, diff --git a/source/saved games/player_profile.c b/source/saved games/player_profile.c index 03d78309..ac64044e 100644 --- a/source/saved games/player_profile.c +++ b/source/saved games/player_profile.c @@ -395,7 +395,7 @@ long player_profile_new( short local_player_index, wchar_t *name) { - struct file_reference file; + struct file_reference profile_file; long player_profile_index = create_enumerated_saved_game_file( _saved_game_file_type_player_profile, local_player_index, @@ -403,7 +403,7 @@ long player_profile_new( if (player_profile_index != NONE) { - if (saved_game_file_open(&file, player_profile_index)) + if (saved_game_file_open(&profile_file, player_profile_index)) { struct player_profile_file_block block = {0}; struct player_profile *profile = &block.profile; @@ -441,9 +441,9 @@ long player_profile_new( saved_game_file_generate_checksum(&block.profile, sizeof(block.profile), &block.checksum); - succeeded = file_set_position(&file, 0) && - file_write(&file, sizeof(block), &block); - saved_game_file_close(&file, player_profile_index); + succeeded = file_set_position(&profile_file, 0) && + file_write(&profile_file, sizeof(block), &block); + saved_game_file_close(&profile_file, player_profile_index); if (!succeeded) { @@ -848,15 +848,15 @@ static void player_profile_create_default_profiles_on_disk( for (i = 0; i < NUMBER_OF_DEFAULT_PROFILES; i++) { struct player_profile_file_block block = {0}; - char path[MAXIMUM_FILENAME_LENGTH+1]; + char full_path[MAXIMUM_FILENAME_LENGTH+1]; struct file_reference file; boolean succeeded = FALSE; build_default_profile(&block.profile, i); - _snprintf(path, MAXIMUM_FILENAME_LENGTH, "z:\\saved\\player_profiles\\default_profile\\%02d.sav", i); + _snprintf(full_path, MAXIMUM_FILENAME_LENGTH, "z:\\saved\\player_profiles\\default_profile\\%02d.sav", i); - if (file_reference_create_from_path(&file, path, FALSE)) + if (file_reference_create_from_path(&file, full_path, FALSE)) { saved_game_file_generate_checksum(&block.profile, sizeof(block.profile), &block.checksum); @@ -872,7 +872,7 @@ static void player_profile_create_default_profiles_on_disk( error( _error_silent, "failed to close default player profile file '%s'", - path); + full_path); } } } @@ -882,7 +882,7 @@ static void player_profile_create_default_profiles_on_disk( error( _error_silent, "failed to create/update default player profile file '%s' on disk", - path); + full_path); } } diff --git a/source/scenario/scenario_definitions.h b/source/scenario/scenario_definitions.h index 700d3822..d37c4a66 100644 --- a/source/scenario/scenario_definitions.h +++ b/source/scenario/scenario_definitions.h @@ -315,6 +315,15 @@ struct scenario struct tag_block structure_bsp_references; // scenario_structure_bsp_reference }; +struct scenario_cutscene_flag +{ + long runtime_unused; + char name[TAG_STRING_LENGTH]; + real_point3d position; + real_euler_angles2d facing; + byte unused[0x24]; +}; + /* ---------- prototypes/EXAMPLE.C */ /* ---------- globals */ diff --git a/source/scenario/wind.c b/source/scenario/wind.c index 638c7e88..a9438523 100644 --- a/source/scenario/wind.c +++ b/source/scenario/wind.c @@ -59,7 +59,6 @@ symbols in this file: struct wind_state { boolean valid; - byte pad[3]; real velocity_variance; real_euler_angles2d angular_variance; real velocity; @@ -69,20 +68,6 @@ struct wind_state typedef char wind_state_size_assert[ sizeof(struct wind_state) == 0x20 ? 1 : -1]; -struct wind_globals -{ - boolean initialized; - byte pad[3]; - real_vector3d variance[3][64]; - short count; - word pad2; - struct wind_state states[32]; - long time; -}; - -typedef char wind_globals_size_assert[ - sizeof(struct wind_globals) == 0xD0C ? 1 : -1]; - struct structure_weather_palette_entry { char name[32]; @@ -128,7 +113,18 @@ void uniform_cubic_spline_vector3d( /* ---------- globals */ -extern struct wind_globals wind_globals; +struct +{ + boolean initialized; + real_vector3d variance[3][64]; + short count; + struct wind_state wind_states[32]; + long time; +} wind_globals; + +typedef char wind_globals_size_assert[ + sizeof(wind_globals) == 0xD0C ? 1 : -1]; + long global_environment_index = NONE; /* ---------- public code */ @@ -209,7 +205,7 @@ void wind_update( weather_palette_block, weather_palette_index, struct structure_weather_palette_entry); - struct wind_state *state = &wind_globals.states[weather_palette_index]; + struct wind_state *state = &wind_globals.wind_states[weather_palette_index]; if (weather_palette->wind.index != NONE) { @@ -282,7 +278,7 @@ void scenario_get_current_from_weather_palette( if (VALID_INDEX(weather_palette_index, wind_globals.count)) { - state = &wind_globals.states[weather_palette_index]; + state = &wind_globals.wind_states[weather_palette_index]; if (state->valid) { struct structure_weather_palette_entry *weather_palette = diff --git a/source/sound/sound_classes.c b/source/sound/sound_classes.c index f519b788..4787103a 100644 --- a/source/sound/sound_classes.c +++ b/source/sound/sound_classes.c @@ -125,12 +125,11 @@ enum /* ---------- structures */ -struct sound_class_runtime +struct sound_class_datum { - real target_gain; - real current_gain; - short interpolation_ticks; - short pad; + real desired_gain; + real gain; + short ticks; }; typedef char verify_sound_class_definition_size[ @@ -140,7 +139,7 @@ typedef char verify_sound_class_definition_size[ /* ---------- globals */ -extern struct sound_class_runtime *sound_class_data; +struct sound_class_datum *sound_class_data; struct sound_class_definition sound_classes[NUMBER_OF_SOUND_CLASSES] = { SOUND_CLASS_DEFINITION(6, 4, 100, 0, 4, 0, 0.5f, 1.4f, 8.f, 1.f, 1.f, 0), @@ -264,7 +263,7 @@ void sound_classes_dispose( return; } -static struct sound_class_runtime *sound_class_datum_get( +static struct sound_class_datum *sound_class_datum_get( short index) { match_assert( @@ -282,7 +281,7 @@ static struct sound_class_runtime *sound_class_datum_get( real sound_class_get_gain( short index) { - return sound_class_datum_get(index)->current_gain; + return sound_class_datum_get(index)->gain; } void debug_sound_classes_enable( @@ -340,11 +339,11 @@ void sound_classes_initialize_for_new_map( for (class_index = 0; class_index < NUMBER_OF_SOUND_CLASSES; class_index++) { - struct sound_class_runtime *sound_class = sound_class_datum_get(class_index); + struct sound_class_datum *sound_class = sound_class_datum_get(class_index); - sound_class->current_gain = 1.f; - sound_class->target_gain = 1.f; - sound_class->interpolation_ticks = 0; + sound_class->gain = 1.f; + sound_class->desired_gain = 1.f; + sound_class->ticks = 0; } return; @@ -359,19 +358,19 @@ void sound_classes_update( for (class_index = 0; class_index < NUMBER_OF_SOUND_CLASSES; class_index++) { - struct sound_class_runtime *sound_class = sound_class_datum_get(class_index); - if (sound_class->interpolation_ticks > ticks) + struct sound_class_datum *sound_class = sound_class_datum_get(class_index); + if (sound_class->ticks > ticks) { - sound_class->current_gain = - (real)ticks / sound_class->interpolation_ticks * - (sound_class->target_gain - sound_class->current_gain) + - sound_class->current_gain; - sound_class->interpolation_ticks -= ticks; + sound_class->gain = + (real)ticks / sound_class->ticks * + (sound_class->desired_gain - sound_class->gain) + + sound_class->gain; + sound_class->ticks -= ticks; } else { - sound_class->current_gain = sound_class->target_gain; - sound_class->interpolation_ticks = 0; + sound_class->gain = sound_class->desired_gain; + sound_class->ticks = 0; } } } @@ -418,10 +417,10 @@ void sound_class_set_gain( { if ((*sound_class_name)[0] && strstr(*sound_class_name, name)) { - struct sound_class_runtime *sound_class = sound_class_datum_get(class_index); + struct sound_class_datum *sound_class = sound_class_datum_get(class_index); - sound_class->target_gain = PIN(gain, 0.f, 1.f); - sound_class->interpolation_ticks = + sound_class->desired_gain = PIN(gain, 0.f, 1.f); + sound_class->ticks = interpolation_ticks < 0 ? 0 : interpolation_ticks; } class_index++; diff --git a/source/sound/sound_manager.c b/source/sound/sound_manager.c index b7f00fa2..3f132bc7 100644 --- a/source/sound/sound_manager.c +++ b/source/sound/sound_manager.c @@ -705,11 +705,11 @@ static void prioritize_sounds( /* ---------- globals */ -extern struct data_array *looping_sound_data; -extern struct data_array *sound_data; -extern struct sound_channel_datum sound_channels[MAXIMUM_SOUND_CHANNELS]; -extern boolean loud_dialog_hack; -extern boolean debug_looping_sound; +struct data_array *looping_sound_data; +struct data_array *sound_data; +struct sound_channel_datum sound_channels[MAXIMUM_SOUND_CHANNELS]; +boolean loud_dialog_hack; +boolean debug_looping_sound; static real const sound_pitch_range_fade_time = 0.5f; static real const sound_inaudible_fade_out_time = 2.f; @@ -729,6 +729,8 @@ static struct profile_section sound_render_section = {"sound_render", NONE, TRUE}; real sound_fade_exponent = 2.5f; static struct sound_manager_globals sound_manager_globals = { 0 }; +boolean debug_sound; +boolean debug_sound_channels; /* ---------- public code */ diff --git a/source/structures/structure_render.c b/source/structures/structure_render.c index 1c5e6634..0db163b8 100644 --- a/source/structures/structure_render.c +++ b/source/structures/structure_render.c @@ -224,6 +224,7 @@ static struct profile_section render_structure_shadows_draw_section = { "render_structure_shadows_draw", NONE, TRUE }; static short report_dynamic_structure_triangle_failure = TRUE; +boolean debug_leaf_portals; /* ---------- public code */ diff --git a/source/structures/structures.c b/source/structures/structures.c index 780e17e3..c18a0176 100644 --- a/source/structures/structures.c +++ b/source/structures/structures.c @@ -227,7 +227,7 @@ typedef char verify_structure_runtime_globals_size[ static struct structure_runtime_globals structure_globals; -extern boolean debug_fog_planes; +boolean debug_fog_planes; /* ---------- public code */ @@ -327,7 +327,7 @@ boolean structure_cluster_mark( boolean sphere_intersects_cluster_portal( struct structure_bsp *structure, short portal_index, - real_point3d const *position, + real_point3d const *point, real radius) { struct structure_cluster_portal *portal = TAG_BLOCK_GET_ELEMENT( @@ -341,17 +341,17 @@ boolean sphere_intersects_cluster_portal( struct collision_bsp)->bsp3d.planes, portal->plane_index, real_plane3d); - real plane_distance = plane3d_distance_to_point(collision_plane, position); - real_point2d projected_vertices[MAXIMUM_VERTICES_PER_CLUSTER_PORTAL]; - real_point3d projected_position; - real_point2d projected_position2d; + real plane_distance = plane3d_distance_to_point(collision_plane, point); + real_point2d projected_points[MAXIMUM_VERTICES_PER_CLUSTER_PORTAL]; + real_point3d projected_centroid3d; + real_point2d projected_centroid2d; real_vector3d const *plane_normal; short projection; boolean projection_sign; short vertex_index; if (fabs(plane_distance) < radius && - distance_squared3d(position, &portal->centroid) < + distance_squared3d(point, &portal->centroid) < (portal->bounding_radius + radius) * (portal->bounding_radius + radius)) { plane_normal = &TAG_BLOCK_GET_ELEMENT( @@ -361,15 +361,15 @@ boolean sphere_intersects_cluster_portal( projection = projection_from_vector3d(plane_normal); projection_sign = projection_sign_from_vector3d(plane_normal, projection); point_from_line3d( - position, + point, plane_normal, -plane_distance, - &projected_position); + &projected_centroid3d); project_point3d( - &projected_position, + &projected_centroid3d, projection, projection_sign, - &projected_position2d); + &projected_centroid2d); for (vertex_index = 0; vertex_index < portal->vertices.count; @@ -382,13 +382,13 @@ boolean sphere_intersects_cluster_portal( real_point3d), projection, projection_sign, - &projected_vertices[vertex_index]); + &projected_points[vertex_index]); } if (convex_hull2d_test_circle( (short)portal->vertices.count, - projected_vertices, - &projected_position2d, + projected_points, + &projected_centroid2d, square_root(radius * radius - plane_distance * plane_distance))) { return TRUE; diff --git a/source/text/draw_string.c b/source/text/draw_string.c index 984f239a..8c96b00c 100644 --- a/source/text/draw_string.c +++ b/source/text/draw_string.c @@ -1471,8 +1471,8 @@ void bitmap_draw_string( rectangle2d const *clip, char const *string) { - rectangle2d bitmap_bounds; - rectangle2d bitmap_clip; + rectangle2d adjusted_bounds; + rectangle2d adjusted_clip; rectangle2d const *effective_bounds = bounds; short format = bitmap->format; @@ -1494,23 +1494,23 @@ void bitmap_draw_string( if (!effective_bounds) { set_rectangle2d( - &bitmap_bounds, + &adjusted_bounds, 0, 0, bitmap->width, bitmap->height); - effective_bounds = &bitmap_bounds; + effective_bounds = &adjusted_bounds; } if (clip) { set_rectangle2d( - &bitmap_clip, + &adjusted_clip, MAX(clip->x0, 0), MAX(clip->y0, 0), MIN(clip->x1, bitmap->width), MIN(clip->y1, bitmap->height)); - clip = &bitmap_clip; + clip = &adjusted_clip; } draw_string( diff --git a/source/units/bipeds.c b/source/units/bipeds.c index caee40c6..11960a70 100644 --- a/source/units/bipeds.c +++ b/source/units/bipeds.c @@ -914,10 +914,10 @@ static void biped_start_landing( } void biped_adjust_placement( - long biped_index, + long object_index, struct object_placement_data *data) { - struct biped_datum *biped = biped_get(biped_index); + struct biped_datum *biped = biped_get(object_index); struct biped_definition *definition = biped_definition_get(biped->definition_index); unsigned long flags = definition->biped.flags; @@ -1650,24 +1650,24 @@ void biped_accelerate( TEST_FLAG(definition->biped.flags, _biped_flying_bit) || TEST_FLAG(definition->biped.flags, _biped_climbs_anything_bit)) { - real_vector3d axis; + real_vector3d angular_acceleration_axis; real scale; - cross_product3d(global_up3d, acceleration, &axis); - normalize3d(&axis); + cross_product3d(global_up3d, acceleration, &angular_acceleration_axis); + normalize3d(&angular_acceleration_axis); scale = real_random()*magnitude3d(acceleration)*(_pi/2); - biped->object.angular_velocity.i += axis.i*scale; - biped->object.angular_velocity.j += axis.j*scale; - biped->object.angular_velocity.k += axis.k*scale; + biped->object.angular_velocity.i += angular_acceleration_axis.i*scale; + biped->object.angular_velocity.j += angular_acceleration_axis.j*scale; + biped->object.angular_velocity.k += angular_acceleration_axis.k*scale; } if (biped->object.parent_object_index==NONE) { - real_vector3d forward = *acceleration; + real_vector3d new_forward = *acceleration; - if (normalize3d(&forward)>0.f) + if (normalize3d(&new_forward)>0.f) { - biped->object.forward = forward; + biped->object.forward = new_forward; biped_snap_facing(biped_index); biped_verify_object_vectors(biped_index, "post-accel"); } @@ -3190,7 +3190,7 @@ static void biped_update_turning( real target_bank; real bank_blend; real bank_time; - real_rectangle2d aiming_bounds; + real_rectangle2d facing_bounds; real angular_velocity_limit; real angular_acceleration_limit; @@ -3259,10 +3259,10 @@ static void biped_update_turning( biped->biped.bank = target_bank; } - aiming_bounds.x0 = -_pi; - aiming_bounds.x1 = _pi; - aiming_bounds.y0 = -_pi/2.f; - aiming_bounds.y1 = _pi/2.f; + facing_bounds.x0 = -_pi; + facing_bounds.x1 = _pi; + facing_bounds.y0 = -_pi/2.f; + facing_bounds.y1 = _pi/2.f; angular_velocity_limit = definition->biped.flying_angular_velocity/TICKS_PER_SECOND; angular_acceleration_limit = @@ -3279,7 +3279,7 @@ static void biped_update_turning( &biped->object.forward, &target_facing, &biped->object.angular_velocity, - &aiming_bounds, + &facing_bounds, angular_velocity_limit, angular_acceleration_limit); } @@ -3706,7 +3706,7 @@ static void biped_update_moving( &scenario_get_game_globals()->player_information, 0, struct game_globals_player_information); - struct game_globals_player_information old_player_information; + struct game_globals_player_information player_information_block; real body_stun_scale = 1.f; real crouch; real uncrouch; @@ -3720,13 +3720,13 @@ static void biped_update_moving( definition->biped.flags, _biped_uses_old_player_physics_bit)) { - old_player_information = *player_information; - player_information = &old_player_information; - old_player_information.walking_speed = 0.51200002f; - old_player_information.run_forward_speed = 2.25f; - old_player_information.run_backward_speed = 2.f; - old_player_information.run_sideways_speed = 2.f; - old_player_information.run_acceleration = 0.31999999f; + player_information_block = *player_information; + player_information = &player_information_block; + player_information_block.walking_speed = 0.51200002f; + player_information_block.run_forward_speed = 2.25f; + player_information_block.run_backward_speed = 2.f; + player_information_block.run_sideways_speed = 2.f; + player_information_block.run_acceleration = 0.31999999f; } if (biped->unit.player_index != NONE) @@ -3944,19 +3944,19 @@ static void biped_update_moving( } { - real_point3d new_position = physics.new_position; + real_point3d new_biped_position = physics.new_position; word out_flags = physics.out_flags; if (!TEST_FLAG( definition->biped.flags, _biped_pill_centered_at_origin_bit)) { - new_position.z -= physics.width; + new_biped_position.z -= physics.width; } - object_translate(biped_index, &new_position, NULL); + object_translate(biped_index, &new_biped_position, NULL); biped->biped.support_surface_index = physics.support_surface_index; - biped->biped.pathfinding_point = new_position; + biped->biped.pathfinding_point = new_biped_position; biped->biped.pathfinding_surface_index = NONE; biped->object.translational_velocity = physics.new_velocity; if (!animation->crouching && @@ -4012,8 +4012,8 @@ static void biped_update_moving( target->object.bounding_sphere_radius)) { struct collision_model_instance instance; - struct collision_model_test_vector_result model_result; - struct collision_result world_collision; + struct collision_model_test_vector_result vector_result; + struct collision_result collision; if (collision_model_instance_new( &instance, @@ -4024,37 +4024,37 @@ static void biped_update_moving( FLAG(_collision_test_back_facing_surfaces_bit), &physics.position, &melee_vector, - &model_result) && + &vector_result) && !collision_test_vector( _collision_test_for_bipeds_passthrough_living_flags, &physics.position, &melee_vector, biped_index, - &world_collision)) + &collision)) { - real_point3d impact_point; - real_plane3d impact_plane; + real_point3d collision_point; + real_plane3d collision_plane; point_from_line3d( &physics.position, &melee_vector, - model_result.bsp_result.t, - &impact_point); + vector_result.bsp_result.t, + &collision_point); matrix4x3_transform_plane( - &instance.matrices[model_result.node_index], - model_result.bsp_result.plane, - &impact_plane); - if (model_result.bsp_result.plane_designator < 0) - plane3d_negate(&impact_plane, &impact_plane); + &instance.matrices[vector_result.node_index], + vector_result.bsp_result.plane, + &collision_plane); + if (vector_result.bsp_result.plane_designator < 0) + plane3d_negate(&collision_plane, &collision_plane); unit_impact_melee_damage( biped_index, biped->biped.impact_target_object_index, - model_result.node_index, - model_result.region_index, - model_result.bsp_result.material_index, - &impact_point, - &impact_plane.n, - &world_collision.location); + vector_result.node_index, + vector_result.region_index, + vector_result.bsp_result.material_index, + &collision_point, + &collision_plane.n, + &collision.location); } } diff --git a/source/units/bipeds.h b/source/units/bipeds.h index 3b64300b..3c171d2a 100644 --- a/source/units/bipeds.h +++ b/source/units/bipeds.h @@ -101,7 +101,7 @@ void biped_reset( boolean biped_flying_through_air( long biped_index); void biped_adjust_placement( - long biped_index, + long object_index, struct object_placement_data *data); void biped_export_function_values( long biped_index); diff --git a/source/units/vehicles.c b/source/units/vehicles.c index 86877966..0b6aeb80 100644 --- a/source/units/vehicles.c +++ b/source/units/vehicles.c @@ -2099,7 +2099,7 @@ static void update_alien_scout_physics( vehicle->definition_index); struct physics_definition *physics = physics_definition_get( definition->unit.object.physics.index); - real_matrix4x3 matrix; + real_matrix4x3 vehicle_matrix; real_vector3d local_velocity; real_vector3d magic_force; real_vector3d magic_torque; @@ -2131,9 +2131,9 @@ static void update_alien_scout_physics( real_vector3d const *object_up = &vehicle->object.up; real_vector3d const *object_angular_velocity = &vehicle->object.angular_velocity; - matrix4x3_from_point_and_vectors(&matrix, &vehicle->object.position, + matrix4x3_from_point_and_vectors(&vehicle_matrix, &vehicle->object.position, object_forward, object_up); - matrix4x3_inverse_transform_vector(&matrix, + matrix4x3_inverse_transform_vector(&vehicle_matrix, &vehicle->object.translational_velocity, &local_velocity); if (vehicle->vehicle.hover>0.0f) @@ -2162,7 +2162,7 @@ static void update_alien_scout_physics( } limit3d(&acceleration, maximum_acceleration); - matrix4x3_transform_vector(&matrix, &acceleration, &acceleration); + matrix4x3_transform_vector(&vehicle_matrix, &acceleration, &acceleration); scale = physics->mass*vehicle->vehicle.hover; magic_force.i += acceleration.i*scale; diff --git a/tools/common_pool_verify.py b/tools/common_pool_verify.py new file mode 100644 index 00000000..d6d359dc --- /dev/null +++ b/tools/common_pool_verify.py @@ -0,0 +1,1613 @@ +#!/usr/bin/env python3 +"""Report-only per-record verifier for January's pooled COMMON block. + +REPORT ONLY (owner rulings "Q10 mechanism", "Q10 fixes", "Q10 ledger home" and +"Q10 FINAL"): this tool itself never credits anything or writes progress. The +progress hook (semantic_progress.apply_common_pool_credit) runs it on every run +and credits only the reviewed allowlist in config/common_pool_credit.json. + +January's linker gathered every uninitialised, non-static file-scope global +(a *tentative* definition, COFF "COMMON") into one pool, which csplit exposes as +``source/linker_common``. For every pooled record this tool checks the tree +under test against January, against a reviewed provenance ledger (a research +record, passed explicitly) and against the XDK libraries January linked: + +* name - csplit symbol == symbols.json name at the RVA == ledger name; the + record is public (no ``"static": true``); name evidence recorded; +* size - every COMMON definer requests exactly January's extent; +* slot - January's alignment/slot obey the pool layout law, and the + alignment our size would request equals January's; +* class - the name exists in our objects only as COMMON (tentative) and + UNDEF; any real (initialised/const/.bss), code, weak or static + definition fails; +* definer - exactly one COMMON definer object, in the record's category; +* provenance - the ledger's tag (inferred / probable / unresolved) is carried + verbatim and may never exceed the recorded definer readouts; + containment evidence and candidate owners never raise a tag; for + inferred/probable records the definer must be the evidence owner + and owners must respect January's pool order (a constraint that can + refute, never prove); +* segment - Halo / vendor classification is re-verified against the XDK + libraries, whose bytes must match a recorded manifest. + +Accounting keeps Halo (halobetacache) and each vendor category separate +(house rule 5) and excludes linker-generated records from every denominator. +Nothing here proves January's owner: "inferred" means "owner inferred from +later first-party builds (>=2 readouts), consistent with January". + +Fail closed (owner ruling 2026-09-27, "Q10 fixes"): there is no ledger-only +mode. Exit status: 0 complete, no failing record; 1 complete, failing records +or global failures; 2 unreadable input or usage error; 3 XDK libraries missing +or unverifiable; 4 malformed types; 5 ambiguous classification. Runs 2-5 +carry no accounting. Every run writes a receipt (--receipt). Independent +review RF-DP added: a repeated JSON key is malformed (4); a manifest whose +linked flags disagree with its January module counts, or that declares a +present library (or a listed library's category) absent, fails closed (4/3); +a missing or unreadable January split object, an absent object of a built +(non-MISSING) unit, an unreadable file anywhere, and inputs that change during +the run are unreadable input (2). Independent review RF-DX added: any other +exception, and a report that cannot be written, end in exit 2 with a receipt +(the receipt is written last and always states the process exit status); an +unlistable library directory is exit 3; a vendor record whose name another +linked library also defines is ambiguous (5). The XDK manifest is pinned +(XDK_MANIFEST_SHA256_LF): any other manifest is exit 3. +""" + +import argparse +import datetime +import hashlib +import json +import re +import struct +import sys +from collections import Counter, OrderedDict +from pathlib import Path + +try: # package use (python -m tools.common_pool_verify, pytest) + from .coff_compare import CoffError, load +except ImportError: # pragma: no cover - direct script use + sys.path.insert(0, str(Path(__file__).resolve().parent)) + from coff_compare import CoffError, load # type: ignore + + +STATUS = ("report only; credits nothing itself (progress credits only the reviewed Q10 allowlist); " + "provenance is inferred or weaker, never January-proven") + +LEDGER_SCHEMA = "common-pool-ledger/2" +MANIFEST_SCHEMA = "xdk-lib-manifest/1" +RECEIPT_SCHEMA = "common-pool-verify-receipt/1" + +EXIT_OK = 0 +EXIT_FAILURES = 1 +EXIT_UNREADABLE = 2 +EXIT_LIBRARIES = 3 +EXIT_MALFORMED = 4 +EXIT_AMBIGUOUS = 5 +FAIL_CLASSES = OrderedDict(( + (EXIT_UNREADABLE, "unreadable-input"), + (EXIT_LIBRARIES, "libraries-missing-or-unverifiable"), + (EXIT_MALFORMED, "malformed-types"), + (EXIT_AMBIGUOUS, "ambiguous-classification"), +)) + +IMAGE_SCN_CNT_CODE = 0x00000020 +IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 +IMAGE_SYM_CLASS_EXTERNAL = 2 +IMAGE_SYM_CLASS_STATIC = 3 + +LINKER_SOURCE = "source/linker_common.c" +HALO_CATEGORY = "halobetacache" +SEGMENTS = ("halo", "vendor") + +TAG_RANK = OrderedDict((("unresolved", 0), ("probable", 1), ("inferred", 2))) +TAG_LABELS = { + "inferred": ("owner inferred from later first-party builds (>=2 readouts), " + "consistent with January; not January-proven"), + "probable": ("one definer readout, or readouts with a recorded caveat; " + "not January-proven"), + "unresolved": ("no usable definer readout, or readouts disagree; " + "ownership not established"), +} +# Readout channels and the evidence family each belongs to. Two readouts from +# one family (HCEX GlobalRefs singleton X and HCEX real definition XD) are one +# observation. XDK = the vendor library member that defines the COMMON. +# Pool containment (house rule 48) is NOT a channel: it is recorded separately +# ("containment_evidence") and never counts toward a tag. +CHANNEL_FAMILY = {"D": "D", "X": "X", "XD": "X", "OD": "OD", "L": "L", + "XDK": "XDK"} +SEGMENT_CHANNELS = {"halo": {"D", "X", "XD", "OD", "L"}, "vendor": {"XDK"}} +MAPPINGS = ("direct", "sibling") +VENDOR_SUPPORT = ("xdk-library-member-only",) +CONTAINMENT_KIND = "pool-containment" + +# Failure reasons that contradict the ledger's Halo/vendor segment: such a +# record cannot be classified, and the whole run fails closed (exit 5). Only +# January-side, library-side or ledger-side evidence can contradict a segment: +# facts about the tree under test (e.g. a definer in the wrong project or +# outside config.json) fail the record inside its segment and never move it +# out of a denominator. +SEGMENT_CONFLICTS = frozenset({ + "ledger-segment-invalid", "ledger-category-invalid", "ledger-duplicate-entry", + "readout-channel-not-valid-for-segment", "owner-category-mismatch", + "vendor-readout-library-not-category", "vendor-readout-not-reproduced", + "vendor-segment-without-library-readout", "halo-record-defined-by-vendor-library", + "segment-order-conflict", "duplicate-january-name", + "vendor-evidence-disagrees-with-readout", "vendor-evidence-library-hash-mismatch", + "vendor-evidence-on-halo-record", + "vendor-record-defined-by-another-library", +}) +IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105 +IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 +IMAGE_SCN_MEM_EXECUTE = 0x20000000 +IMAGE_SCN_MEM_WRITE = 0x80000000 + +VERDICT_PASS = "PASS" +VERDICT_PASS_UNRESOLVED = "PASS-OWNER-UNRESOLVED" +VERDICT_FAIL = "FAIL" + +SHA256_RE = re.compile(r"^[0-9a-f]{64}$") + +# The reviewed XDK manifest (RF-DM C02; recomputed 38/38 by RF-DP C02) records fixed facts: the XDK 3911 +# extract's library hashes and January's PDB module table. Its linked flags and absent declarations decide +# which libraries are scanned for Halo names and which vendor categories may lack a library, so a consistent +# edit could move the Halo/vendor boundary (RF-DX C05 T05/T06). Its content is therefore pinned here: any +# other manifest is unverifiable library evidence (exit 3), and changing it is a verifier change (RF-DX, D2). +XDK_MANIFEST_SHA256_LF = "1b8a8350bd456bd61efea345970b793ca7ae8b554f9f63d5a0111571a47ebe3b" + + +class PoolVerifyError(RuntimeError): + """Input that cannot be read (exit 2).""" + exit_code = EXIT_UNREADABLE + + +class LibraryVerifyError(PoolVerifyError): + """XDK libraries missing, unlisted, or not matching the recorded manifest (exit 3).""" + exit_code = EXIT_LIBRARIES + + +class MalformedInputError(PoolVerifyError): + """A JSON input with a wrong type, a missing required key or an unknown key (exit 4).""" + exit_code = EXIT_MALFORMED + + +# -- small helpers ----------------------------------------------------------- + +def alignment_from_flags(flags): + """COFF section alignment (IMAGE_SCN_ALIGN_*) in bytes; 0 if unspecified.""" + code = (int(flags) >> 20) & 0xF + return 1 << (code - 1) if code else 0 + + +def law_alignment(size): + """Alignment VC7's linker gives a COMMON of *size* bytes in January's pool. + + min(32, smallest power of two >= size); holds for all 240 January records. + """ + size = int(size) + if size <= 0: + raise ValueError("COMMON size must be positive") + power = 1 + while power < size: + power <<= 1 + return min(32, power) + + +def align_up(value, alignment): + return (value + alignment - 1) // alignment * alignment if alignment else value + + +def sha256_bytes(data): + return hashlib.sha256(data).hexdigest() + + +def sha256_file(path): + return sha256_bytes(Path(path).read_bytes()) + + +def lf_normalised(data): + return data.replace(b"\r\n", b"\n") + + +def sha256_file_lf(path): + """sha256 of the file with CRLF normalised to LF (checkout-independent).""" + return sha256_bytes(lf_normalised(Path(path).read_bytes())) + + +def _stem(path): + return Path(str(path).replace("\\", "/")).stem.lower() + + +class DuplicateKeyError(ValueError): + """A JSON object names the same key twice (Python would keep the last value silently).""" + + +def _no_duplicate_keys(pairs): + seen = set() + for key, _value in pairs: + if key in seen: + raise DuplicateKeyError(f"duplicate JSON key {key!r}") + seen.add(key) + return dict(pairs) + + +def _loads(text, description): + """json.loads that fails closed on a repeated key (exit 4): a reviewer, another parser and + this verifier must all read the same value (RF-DP D3).""" + try: + return json.loads(text, object_pairs_hook=_no_duplicate_keys) + except DuplicateKeyError as exc: + raise MalformedInputError(f"{description}: {exc}") from exc + + +def _read_json(path, description, error=PoolVerifyError): + try: + text = Path(path).read_text(encoding="utf-8") + except (OSError, ValueError) as exc: + raise error(f"cannot read {description} {path}: {exc}") from exc + try: + return _loads(text, f"{description} {path}") + except MalformedInputError: + raise + except ValueError as exc: + raise error(f"cannot read {description} {path}: {exc}") from exc + + +def file_fingerprint(path): + """{path, sha256, sha256_lf, size} of a file, or {path, missing: true}.""" + path = Path(path) + try: + data = path.read_bytes() + except OSError: + return {"path": str(path), "missing": True} + return {"path": str(path), "sha256": sha256_bytes(data), + "sha256_lf": sha256_bytes(lf_normalised(data)), "size": len(data)} + + +def tree_manifest(root, pattern="*.obj"): + """sha256sum-style manifest of every *pattern* file under *root* (sorted by + relative POSIX path) and the sha256 of that manifest text.""" + root = Path(root) + if not root.is_dir(): + return {"root": str(root), "missing": True} + lines = [] + for path in sorted(root.rglob(pattern), key=lambda p: p.relative_to(root).as_posix()): + if path.is_file(): + lines.append(f"{sha256_file(path)} *{path.relative_to(root).as_posix()}\n") + text = "".join(lines).encode("utf-8") + return {"root": str(root), "files": len(lines), "manifest_sha256": sha256_bytes(text), + "format": "sha256sum lines ' *', sorted by relative path"} + + +# -- JSON schema (keys + JSON types; fail closed) ----------------------------- + +def _kind_ok(value, kind): + if kind == "str": + return isinstance(value, str) + if kind == "str?": + return value is None or isinstance(value, str) + if kind == "bool": + return type(value) is bool + if kind == "int": + return type(value) is int + if kind == "list": + return isinstance(value, list) + if kind == "list[str]": + return isinstance(value, list) and all(isinstance(v, str) for v in value) + if kind == "obj": + return isinstance(value, dict) + raise AssertionError(kind) + + +def _check_object(where, value, required, optional=None): + """Keys and JSON types of one object: missing, unknown or mistyped keys are malformed.""" + optional = optional or {} + if not isinstance(value, dict): + raise MalformedInputError(f"{where}: expected an object, got {type(value).__name__}") + missing = [key for key in required if key not in value] + if missing: + raise MalformedInputError(f"{where}: missing key(s) {missing}") + unknown = sorted(set(value) - set(required) - set(optional)) + if unknown: + raise MalformedInputError(f"{where}: unknown key(s) {unknown}") + for key, kind in list(required.items()) + list(optional.items()): + if key in value and not _kind_ok(value[key], kind): + raise MalformedInputError(f"{where}: {key} must be {kind}, got " + f"{type(value[key]).__name__} {value[key]!r:.60}") + + +LEDGER_TOP = {"schema": "str", "status": "str", "vocabulary": "obj", "derivation": "list[str]", + "rulings": "list[str]", "records": "list"} +LEDGER_RECORD = {"name": "str", "rva": "str", "segment": "str", "category": "str", + "name_evidence": "str?", "tag": "str?", "owner": "str?", + "candidate_owner": "str?", "readouts": "list", "basis": "str", + "caveats": "list[str]", "sources": "list[str]"} +LEDGER_RECORD_OPTIONAL = {"containment_evidence": "list", "vendor_evidence": "obj"} +READOUT = {"channel": "str", "owner": "str", "mapping": "str", "counted": "bool", "source": "str"} +READOUT_OPTIONAL = {"names": "str", "library": "str", "member": "str", "note": "str"} +CONTAINMENT = {"kind": "str", "candidate_owner": "str", "lower_neighbours": "list[str]", + "upper_neighbours": "list[str]", "neighbour_owner_evidence": "str", + "ordering_model": "str", "veto_check": "str", "ruling": "str", + "sources": "list[str]"} +VENDOR_EVIDENCE = {"support": "str", "library": "str", "library_sha256": "str", "member": "str", + "definition": "str", "size": "int", "january_public": "bool", + "january_pdb_module": "str?", "statement": "str"} +MANIFEST_TOP = {"schema": "str", "status": "str", "recorded_by": "str", "source_dir": "str", + "evidence": "list[str]", "libraries": "list", + "linked_libraries_not_in_extract": "list"} +MANIFEST_LIBRARY = {"file": "str", "sha256": "str", "size": "int", "linked_by_january": "bool", + "january_pdb_modules": "int"} +MANIFEST_ABSENT = {"library": "str", "category": "str?", "january_path": "str", + "january_pdb_modules": "int", "reason": "str"} + + +def validate_ledger(ledger): + """Keys and JSON types of the whole ledger (MalformedInputError on the first defect). + + Vocabulary (tag / channel / mapping values, segment names) is NOT checked + here: a value outside the vocabulary is a per-record failure reason. + """ + _check_object("ledger", ledger, LEDGER_TOP) + if ledger["schema"] != LEDGER_SCHEMA: + raise MalformedInputError(f"ledger schema {ledger['schema']!r} != {LEDGER_SCHEMA!r}") + for index, entry in enumerate(ledger["records"]): + where = f"ledger record #{index}" + _check_object(where, entry, LEDGER_RECORD, LEDGER_RECORD_OPTIONAL) + where = f"ledger record #{index} ({entry['name']})" + if not entry["name"]: + raise MalformedInputError(f"{where}: empty name") + for number, readout in enumerate(entry["readouts"]): + _check_object(f"{where} readout #{number}", readout, READOUT, READOUT_OPTIONAL) + if readout["channel"] == "XDK": + if "library" not in readout or "member" not in readout or "names" in readout: + raise MalformedInputError(f"{where} readout #{number}: an XDK readout has " + f"library + member and no names") + elif readout["channel"] in CHANNEL_FAMILY: + if "names" not in readout or "library" in readout or "member" in readout: + raise MalformedInputError(f"{where} readout #{number}: a {readout['channel']} " + f"readout has names and no library/member") + for number, item in enumerate(entry.get("containment_evidence", [])): + _check_object(f"{where} containment #{number}", item, CONTAINMENT) + if "vendor_evidence" in entry: + _check_object(f"{where} vendor_evidence", entry["vendor_evidence"], VENDOR_EVIDENCE) + + +def validate_manifest(manifest): + _check_object("XDK manifest", manifest, MANIFEST_TOP) + if manifest["schema"] != MANIFEST_SCHEMA: + raise MalformedInputError(f"XDK manifest schema {manifest['schema']!r} != {MANIFEST_SCHEMA!r}") + seen = set() + for index, entry in enumerate(manifest["libraries"]): + _check_object(f"XDK manifest library #{index}", entry, MANIFEST_LIBRARY) + if not SHA256_RE.match(entry["sha256"]): + raise MalformedInputError(f"XDK manifest library {entry['file']}: sha256 must be 64 " + f"lowercase hex digits") + key = entry["file"].lower() + if not key.endswith(".lib") or "/" in key or "\\" in key: + raise MalformedInputError(f"XDK manifest library {entry['file']!r}: a bare .lib file name") + if key in seen: + raise MalformedInputError(f"XDK manifest lists {entry['file']} twice") + seen.add(key) + # the linked flag is January's PDB module table in another form (RF-DP D2): a library is + # linked exactly when January's PDB lists modules from it + # (types are the schema's job above; this compares values only) + linked, modules = entry["linked_by_january"], entry["january_pdb_modules"] + if type(linked) is bool and type(modules) is int and (linked != (modules > 0) or modules < 0): + raise MalformedInputError(f"XDK manifest library {entry['file']}: linked_by_january " + f"{entry['linked_by_january']} disagrees with january_pdb_modules " + f"{entry['january_pdb_modules']}") + for index, entry in enumerate(manifest["linked_libraries_not_in_extract"]): + _check_object(f"XDK manifest absent library #{index}", entry, MANIFEST_ABSENT) + if entry["library"].lower() in seen: + raise MalformedInputError(f"XDK manifest: {entry['library']} is both present and absent") + if entry["january_pdb_modules"] <= 0: + raise MalformedInputError(f"XDK manifest: absent library {entry['library']} is declared linked by " + f"January with {entry['january_pdb_modules']} PDB modules") + + +# -- configuration ------------------------------------------------------------- + +def load_config(config_path): + """Map every config.json object to (project, January module index, status).""" + config = _read_json(config_path, "config") + objects = {} + if not isinstance(config, dict) or not isinstance(config.get("projects"), list): + raise MalformedInputError("config: 'projects' must be a list") + for project in config["projects"]: + if not isinstance(project, dict) or not isinstance(project.get("name"), str) \ + or not isinstance(project.get("objects"), list): + raise MalformedInputError("config: every project needs a name and an objects list") + for entry in project["objects"]: + if not isinstance(entry, dict) or not isinstance(entry.get("name"), str) \ + or type(entry.get("index")) is not int: + raise MalformedInputError(f"config: malformed object entry in {project['name']}") + name = entry["name"] + if name in objects: + raise MalformedInputError(f"config lists {name} twice") + objects[name] = {"category": project["name"], + "index": entry["index"], + "status": entry.get("status")} + linker = objects.get(LINKER_SOURCE) + if linker is None: + raise MalformedInputError(f"config does not list {LINKER_SOURCE}") + return objects, linker["index"] + + +# -- January side ---------------------------------------------------------------- + +def _int_field(item, key, where): + value = item.get(key) if isinstance(item, dict) else None + if type(value) is not int: + raise MalformedInputError(f"{where}: {key} must be an integer, got {value!r:.40}") + return value + + +def january_pool(contribs_path, symbols_path, split_path, pool_module): + """Read January's pool from contribs.json and cross-check csplit + symbols.json. + + Returns (records, global_failures). Every record carries its own January + self-consistency failures in ``january_reasons``. + """ + contribs = _read_json(contribs_path, "contribs") + symbols = _read_json(symbols_path, "symbols") + if not isinstance(contribs, list) or not isinstance(symbols, list): + raise MalformedInputError("contribs.json and symbols.json must be lists") + by_offset = {} + for item in symbols: + offset = _int_field(item, "file_offset", "symbols.json") + if not isinstance(item.get("name"), str): + raise MalformedInputError(f"symbols.json entry at {offset:#x} has no string name") + by_offset.setdefault(offset, []).append(item) + for item in contribs: + for key in ("file_offset", "size", "flags", "module_index"): + _int_field(item, key, "contribs.json") + pool = sorted((c for c in contribs if c["module_index"] == pool_module), + key=lambda c: c["file_offset"]) + if not pool: + raise MalformedInputError(f"no contributions for the pool module {pool_module}") + + try: + split = load(Path(split_path).read_bytes()) + except (OSError, CoffError) as error: + raise PoolVerifyError(f"cannot read the split pool {split_path}: {error}") from error + split_names = {} + for item in split["symbols"]: + if item["section"] > 0 and item["storage"] == IMAGE_SYM_CLASS_EXTERNAL: + split_names.setdefault(item["section"], []).append(item["name"]) + + failures = [] + if len(split["sections"]) != len(pool): + failures.append(f"split pool has {len(split['sections'])} sections, " + f"January contributions {len(pool)}") + records = [] + previous_bss = None + for index, contribution in enumerate(pool): + rva = contribution["file_offset"] + size = contribution["size"] + flags = contribution["flags"] + reasons = [] + entries = by_offset.get(rva, []) + names = [entry["name"] for entry in entries] + if len(names) != 1: + reasons.append(f"symbols.json names at rva: {names}") + name = names[0] if names else None + static = any(entry.get("static") for entry in entries) + section = split["sections"][index] if index < len(split["sections"]) else None + if section is None: + reasons.append("no split section") + else: + if section["size"] != size: + reasons.append(f"split size {section['size']} != contribution {size}") + if section["flags"] != flags: + reasons.append(f"split flags {section['flags']:#x} != contribution {flags:#x}") + if split_names.get(section["index"]) != [name]: + reasons.append(f"split symbol {split_names.get(section['index'])} != symbols.json {name}") + bss = bool(flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) + alignment = alignment_from_flags(flags) + # Only read-only initialised data (January: the PE debug directory and + # its CodeView record) is excluded as linker-generated; any other + # non-.bss pool contribution cannot be classified and fails the run + # closed instead of being silently dropped from every denominator. + read_only_data = (flags & IMAGE_SCN_CNT_INITIALIZED_DATA + and not flags & (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE + | IMAGE_SCN_CNT_CODE)) + kind = "bss" if bss else ("linker" if read_only_data else "unexpected") + if kind == "unexpected": + failures.append(f"unexpected-non-bss-pool-contribution: {name} rva {rva:#x} " + f"flags {flags:#x}") + record = {"pool_index": index, "rva": rva, "size": size, "flags": flags, + "alignment": alignment, "name": name, "static_in_symbols": static, + "kind": kind, "gap_before": 0, + "january_reasons": reasons} + if bss: + if static: + reasons.append("symbols.json marks a pooled record static") + if size <= 0: + reasons.append("non-positive size") + else: + if alignment != law_alignment(size): + reasons.append(f"january-alignment-law: flags align {alignment} " + f"!= law {law_alignment(size)}") + if not alignment or rva % alignment: + reasons.append(f"january-misaligned: rva {rva:#x} align {alignment}") + if previous_bss is not None: + end = previous_bss["rva"] + previous_bss["size"] + expected = align_up(end, alignment) + if rva != expected: + reasons.append(f"january-slot-inconsistent: rva {rva:#x} != " + f"align_up(previous end {end:#x}, {alignment}) {expected:#x}") + record["gap_before"] = max(0, rva - end) + previous_bss = record + records.append(record) + counts = Counter(r["name"] for r in records if r["name"]) + for record in records: + if counts.get(record["name"], 0) > 1: + record["january_reasons"].append( + f"duplicate-january-name: {record['name']} names {counts[record['name']]} pool records") + # an excluded (linker) record is in no tally, but a csplit/contribs disagreement about it is + # still a January-side inconsistency and must not pass silently (RF-DP D9) + for record in records: + if record["kind"] != "bss" and record["january_reasons"]: + failures.append(f"january-excluded-record-inconsistent: {record['name']}: " + f"{'; '.join(record['january_reasons'])}") + return records, failures + + +# -- our build --------------------------------------------------------------------- + +def _object_path(objects_root, name): + return Path(objects_root) / Path(name).with_suffix(".obj") + + +def scan_objects(objects_root, config_objects, pool_names): + """Collect every appearance of a pooled name, and every COMMON, in our objects.""" + objects_root = Path(objects_root) + if not objects_root.is_dir(): + raise PoolVerifyError(f"objects root {objects_root} is not a directory") + known = {} + stale, stale_paths = [], set() + absent = [] + for name, info in sorted(config_objects.items()): + path = _object_path(objects_root, name) + if not path.is_file(): + # a unit that is not MISSING must have been built: its absent object could hide a + # duplicate or real definition of a pooled name (RF-DP D8) + if info["status"] != "MISSING": + absent.append(name) + continue + if info["status"] == "MISSING": + stale.append(name) + stale_paths.add(path.resolve()) + continue + known[path.resolve()] = (name, info["category"]) + if absent: + raise PoolVerifyError(f"{len(absent)} built (non-MISSING) config unit(s) have no object under " + f"{objects_root}: {absent[:8]}{' ...' if len(absent) > 8 else ''}; an incomplete " + f"build cannot be verified") + for path in sorted(objects_root.rglob("*.obj")): + resolved = path.resolve() + if resolved in known or resolved in stale_paths: + continue + rel = path.relative_to(objects_root).as_posix() + known[resolved] = (rel, None) # unknown category: fails closed if it defines + + commons, reals, statics, undefs = {}, {}, {}, {} + all_commons = {} + scanned = 0 + for path, (name, category) in sorted(known.items(), key=lambda kv: kv[1][0]): + try: + obj = load(path.read_bytes()) + except (OSError, CoffError) as error: + raise PoolVerifyError(f"cannot read our object {path}: {error}") from error + scanned += 1 + for item in obj["symbols"]: + symbol_name = item["name"] + section_no = item["section"] + storage = item["storage"] + if section_no == 0 and storage == IMAGE_SYM_CLASS_EXTERNAL: + if item["value"] > 0: + all_commons.setdefault(symbol_name, []).append((name, category, item["value"])) + if symbol_name in pool_names: + commons.setdefault(symbol_name, []).append((name, category, item["value"])) + elif symbol_name in pool_names: + undefs.setdefault(symbol_name, set()).add(name) + continue + if symbol_name not in pool_names: + continue + if storage == IMAGE_SYM_CLASS_WEAK_EXTERNAL: + # an alias the linker may bind the pooled name to: never tentative storage + reals.setdefault(symbol_name, []).append((name, category, "weak external")) + continue + if section_no <= 0: + continue + if section_no > len(obj["sections"]): + raise PoolVerifyError(f"cannot read our object {path}: symbol {symbol_name} names section " + f"{section_no} of {len(obj['sections'])}") + section = obj["sections"][section_no - 1] + where = (name, category, section["name"]) + if section["flags"] & IMAGE_SCN_CNT_CODE: + # an EXTERNAL function of the pooled name is a real definition the + # link would bind the name to; a static function is TU-private + if storage == IMAGE_SYM_CLASS_EXTERNAL: + reals.setdefault(symbol_name, []).append(where) + continue + if storage == IMAGE_SYM_CLASS_EXTERNAL: + reals.setdefault(symbol_name, []).append(where) + elif storage == IMAGE_SYM_CLASS_STATIC: + statics.setdefault(symbol_name, []).append(where) + return {"commons": commons, "reals": reals, "statics": statics, + "undefs": undefs, "all_commons": all_commons, "scanned": scanned, + "stale_missing_units": stale} + + +def january_referencers(split_root, config_objects, pool_names): + """{pooled name: set(config object)} of January TUs whose csplit object relocates to it. + + January-internal evidence (like pool order): it can refute an "inferred" + owner that never references its own record, never prove one. csplit writes + one object per config unit, so a missing or unreadable one is unreadable + January input (PoolVerifyError, exit 2): skipping it would silently drop the + refutation it carries (RF-DP D7). + """ + split_root = Path(split_root) + found, unreadable = {}, [] + for name in sorted(config_objects): + if name == LINKER_SOURCE: + continue + path = _object_path(split_root, name) + if not path.is_file(): + unreadable.append(f"{name}: no January split object {path}") + continue + try: + obj = load(path.read_bytes()) + except (OSError, CoffError) as error: + unreadable.append(f"{name}: {error}") + continue + data = obj["data"] + for section in obj["sections"]: + for index in range(section["reloc_count"]): + _address, target, _type = struct.unpack_from( + " 5 else ''}") + return found, unreadable + + +# -- XDK libraries (required; bytes pinned by the recorded manifest) ------------ + +def read_lib_members(path_or_bytes, library="archive"): + """Yield (member name, bytes) of every member of a COFF archive (strict).""" + data = path_or_bytes if isinstance(path_or_bytes, (bytes, bytearray)) \ + else Path(path_or_bytes).read_bytes() + if data[:8] != b"!\n": + raise LibraryVerifyError(f"{library} is not a COFF archive") + offset, longnames = 8, b"" + while offset < len(data): + if offset + 60 > len(data) or data[offset + 58:offset + 60] != b"`\n": + raise LibraryVerifyError(f"{library}: truncated or corrupt member header at {offset:#x}") + header = data[offset:offset + 60] + raw_name = header[:16].decode("latin-1").rstrip() + try: + size = int(header[48:58].decode("ascii").strip()) + except ValueError as error: + raise LibraryVerifyError(f"{library}: bad member size at {offset:#x}") from error + if offset + 60 + size > len(data): + raise LibraryVerifyError(f"{library}: member at {offset:#x} extends past the archive end") + body = data[offset + 60:offset + 60 + size] + offset += 60 + size + (size & 1) + if raw_name == "//": + longnames = body + continue + if raw_name == "/" or raw_name == "/SYM64/": + continue + if raw_name.startswith("/") and raw_name[1:].isdigit(): + start = int(raw_name[1:]) + if start >= len(longnames): + raise LibraryVerifyError(f"{library}: long member name offset {start} out of range") + end = start + while end < len(longnames) and longnames[end] not in (0, 10): + end += 1 + member = longnames[start:end].decode("latin-1") + else: + member = raw_name.rstrip("/") + yield member, body + + +def member_symbols(body, where="member"): + """(kind, [(name, section, value, storage)]) of one archive member. + + Reads i386 and machine-independent (IMAGE_FILE_MACHINE_UNKNOWN, e.g. + OLDNAMES aliases) COFF objects and short import descriptors. A string + table whose length field is 0 (CVTRES resource objects) is read as empty. + Anything else (e.g. an anonymous LTCG object) is unreadable: LibraryVerifyError. + """ + if len(body) >= 20 and body[:4] == b"\x00\x00\xff\xff": + version = struct.unpack_from(" len(body): + raise LibraryVerifyError(f"{where}: symbol table truncated") + strtab = b"" + if string_offset + 4 <= len(body): + length = struct.unpack_from("= 4: + if string_offset + length > len(body): + raise LibraryVerifyError(f"{where}: string table truncated") + strtab = body[string_offset:string_offset + length] + elif length != 0: + raise LibraryVerifyError(f"{where}: invalid string table length {length}") + elif string_offset != len(body): + raise LibraryVerifyError(f"{where}: string table length field truncated") + symbols = [] + index = 0 + while index < symbol_count: + entry = symbol_offset + index * 18 + zeroes, name_offset = struct.unpack_from("= len(strtab): + raise LibraryVerifyError(f"{where}: symbol {index} long name offset out of range") + end = strtab.find(b"\0", name_offset) + if end < 0: + raise LibraryVerifyError(f"{where}: symbol {index} name not terminated") + name = strtab[name_offset:end].decode("latin-1") + else: + name = body[entry:entry + 8].rstrip(b"\0").decode("latin-1") + value, section, _type, storage, aux = struct.unpack_from(" 0: + found.setdefault(name, []).append((lib, member, "COMMON", value)) + elif section > 0 or section in (-1, -3): # section, absolute, import + found.setdefault(name, []).append((lib, member, "DEFINED", None)) + members[library] = dict(sorted(count.items())) + return found, members + + +# -- ledger -------------------------------------------------------------------- + +def load_ledger(ledger_path): + if ledger_path is None: + raise PoolVerifyError("--ledger is required (the research ledger is passed explicitly)") + ledger = _read_json(ledger_path, "ledger") + validate_ledger(ledger) + by_name, failures = {}, [] + duplicates = Counter() + for entry in ledger["records"]: + name = entry["name"] + if name in by_name: + # every entry of a duplicated name is distrusted: the record is + # failed and cannot be classified (the run fails closed) + failures.append(f"ledger lists {name} twice") + duplicates[name] += 1 + continue + by_name[name] = entry + return ledger, by_name, failures, set(duplicates) + + +def _readouts(entry): + """The entry's readouts (validated as a list of objects by validate_ledger).""" + return entry.get("readouts") or [] + + +def tag_ceiling(entry, segment): + """Highest tag the recorded readouts can carry (never used to raise a tag). + + Only definer readouts count. containment_evidence and candidate_owner are + never read here: pool containment supports a candidate, never a tag. + """ + owner = entry.get("owner") + direct, any_family = set(), set() + for readout in _readouts(entry): + if readout.get("counted") is not True: # the boolean true only + continue + channel = readout.get("channel") + if not isinstance(channel, str) or channel not in SEGMENT_CHANNELS.get(segment, set()): + continue + if owner is None or readout.get("owner") != owner: + continue + family = CHANNEL_FAMILY[channel] + any_family.add(family) + if readout.get("mapping") == "direct": + direct.add(family) + if len(direct) >= 2: + return "inferred" + if any_family: + return "probable" + return "unresolved" + + +def _ledger_reasons(entry, record, config_objects, vendor_categories): + reasons = [] + segment = entry.get("segment") + category = entry.get("category") + if segment not in SEGMENTS: + reasons.append(f"ledger-segment-invalid: {segment!r}") + elif segment == "halo" and category != HALO_CATEGORY: + reasons.append(f"ledger-category-invalid: halo record in {category!r}") + elif segment == "vendor" and category not in vendor_categories: + reasons.append(f"ledger-category-invalid: vendor record in {category!r}") + try: + rva = int(entry.get("rva"), 0) + except ValueError: + rva = None + if rva != record["rva"]: + reasons.append(f"ledger-rva-mismatch: {entry.get('rva')} != {record['rva']:#x}") + if not entry.get("name_evidence"): + reasons.append("missing-name-evidence") + tag = entry.get("tag") + if tag is None: + reasons.append("missing-provenance-tag") + elif not isinstance(tag, str) or tag not in TAG_RANK: + reasons.append(f"invalid-provenance-tag: {tag!r}") + tag = None + readouts = _readouts(entry) + for readout in readouts: + channel = readout.get("channel") + if channel not in CHANNEL_FAMILY: + reasons.append(f"readout-channel-unknown: {channel!r}") + channel = None + elif segment in SEGMENTS and channel not in SEGMENT_CHANNELS[segment]: + reasons.append(f"readout-channel-not-valid-for-segment: {channel} on {segment}") + mapping = readout.get("mapping") + if mapping not in MAPPINGS: + reasons.append(f"readout-mapping-invalid: {mapping!r}") + # a direct readout names its owner itself: the raw name (Halo channels) or + # the library member (XDK) must be the owner's own file + if mapping == "direct" and channel and readout.get("owner"): + raw = readout.get("member") if channel == "XDK" else readout.get("names") + if not isinstance(raw, str) or _stem(raw) != _stem(readout["owner"]): + reasons.append(f"readout-names-disagree-with-owner: {channel} {raw!r} " + f"-> {readout.get('owner')}") + if segment == "vendor" and not any(r.get("channel") == "XDK" for r in readouts): + reasons.append("vendor-segment-without-library-readout: a vendor record needs the library " + "member that defines it") + if tag == "inferred" and entry.get("caveats"): + reasons.append("tag-exceeds-evidence: an inferred record carries caveats") + owner = entry.get("owner") + if tag in ("inferred", "probable"): + if not owner: + reasons.append("missing-evidence-owner") + elif owner not in config_objects: + reasons.append(f"owner-not-in-config: {owner}") + elif config_objects[owner]["category"] != category: + reasons.append(f"owner-category-mismatch: {owner} is " + f"{config_objects[owner]['category']}, record {category}") + if tag == "unresolved" and owner: + reasons.append("unresolved-record-carries-owner") + if tag in TAG_RANK and segment in SEGMENTS: + ceiling = tag_ceiling(entry, segment) + if TAG_RANK[tag] > TAG_RANK[ceiling]: + reasons.append(f"tag-exceeds-evidence: {tag} > {ceiling}" + + (" (containment evidence never raises a tag)" + if entry.get("containment_evidence") else "")) + for item in entry.get("containment_evidence", []): + if item["kind"] != CONTAINMENT_KIND: + reasons.append(f"containment-evidence-invalid: kind {item['kind']!r}") + if item["candidate_owner"] != entry.get("candidate_owner"): + reasons.append(f"containment-evidence-invalid: candidate {item['candidate_owner']} != " + f"record candidate {entry.get('candidate_owner')}") + return reasons + + +def _vendor_evidence_reasons(entry, record, library_hashes): + """Vendor records must record their library-member evidence explicitly + (owner ruling 2026-09-27, "Q10 ledger home"); a Halo record carries none.""" + evidence = entry.get("vendor_evidence") + if entry.get("segment") != "vendor": + return ["vendor-evidence-on-halo-record: only vendor records carry library evidence"] \ + if evidence is not None else [] + if evidence is None: + return ["vendor-evidence-missing: the XDK library member evidence must be recorded"] + reasons = [] + if evidence["support"] not in VENDOR_SUPPORT: + reasons.append(f"vendor-evidence-invalid: support {evidence['support']!r}") + elif entry.get("tag") == "inferred": + reasons.append("tag-exceeds-evidence: a vendor record supported only by an XDK library " + "member remains probable") + xdk = [(str(r.get("library")).lower(), r.get("member")) + for r in _readouts(entry) if r.get("channel") == "XDK"] + if xdk != [(evidence["library"].lower(), evidence["member"])]: + reasons.append(f"vendor-evidence-disagrees-with-readout: {evidence['library']} " + f"{evidence['member']} vs readouts {xdk}") + recorded = library_hashes.get(evidence["library"].lower()) + if recorded != evidence["library_sha256"]: + reasons.append(f"vendor-evidence-library-hash-mismatch: evidence {evidence['library_sha256'][:16]}.. " + f"verified {str(recorded)[:16]}..") + if evidence["definition"] != "COMMON" or evidence["size"] != record["size"]: + reasons.append(f"vendor-evidence-size-mismatch: {evidence['definition']}({evidence['size']}) " + f"!= January COMMON({record['size']})") + return reasons + + +# -- verification ------------------------------------------------------------------ + +def _trace_inputs(trace, config_dir, split_path, ledger_path, manifest_path, objects_root): + trace["inputs"] = { + "config": file_fingerprint(config_dir / "config.json"), + "contribs": file_fingerprint(config_dir / "contribs.json"), + "symbols": file_fingerprint(config_dir / "symbols.json"), + "split_pool": file_fingerprint(split_path), + "ledger": file_fingerprint(ledger_path) if ledger_path else None, + "xdk_manifest": file_fingerprint(manifest_path) if manifest_path else None, + } + trace["build_snapshot"] = {"objects": tree_manifest(objects_root), + "split": tree_manifest(split_path.parent.parent)} + + +def verify(root=".", objects_root=None, ledger_path=None, split_path=None, + config_dir=None, xdk_lib_dir=None, xdk_manifest_path=None, trace=None): + """Verify the tree against January, the ledger and the XDK libraries. + + Returns the report (result COMPLETE or FAIL-CLOSED for ambiguous + classification). Raises PoolVerifyError subclasses for unreadable input + (exit 2), missing/unverifiable libraries (3) and malformed types (4). + *trace* (a dict) receives the input fingerprints even when it raises. + """ + trace = {} if trace is None else trace + root = Path(root) + config_dir = Path(config_dir) if config_dir else root / "config" + objects_root = Path(objects_root) if objects_root else root / "build" / "base" + split_path = Path(split_path) if split_path else root / "build" / "split" / "source" / "linker_common.obj" + _trace_inputs(trace, config_dir, split_path, ledger_path, xdk_manifest_path, objects_root) + + config_objects, pool_module = load_config(config_dir / "config.json") + vendor_categories = {info["category"] for info in config_objects.values()} - {HALO_CATEGORY} + ledger, ledger_by_name, ledger_failures, ledger_duplicates = load_ledger(ledger_path) + linked, manifest, library_hashes = verify_libraries(xdk_lib_dir, xdk_manifest_path, + vendor_categories, trace) + records, global_failures = january_pool(config_dir / "contribs.json", + config_dir / "symbols.json", + split_path, pool_module) + global_failures.extend(ledger_failures) + + pool_names = {r["name"] for r in records if r["name"]} + bss_names = {r["name"] for r in records if r["kind"] == "bss" and r["name"]} + linker_names = {r["name"] for r in records if r["kind"] == "linker" and r["name"]} + for name in sorted(set(ledger_by_name) & linker_names): + global_failures.append(f"linker-record-in-ledger: {name}") + for name in sorted(set(ledger_by_name) - pool_names): + global_failures.append(f"ledger-entry-not-in-pool: {name}") + unknown_vendor = sorted({e["category"] for e in ledger_by_name.values() + if e["segment"] == "vendor" and e["category"] in vendor_categories + and e["category"].lower() + ".lib" not in {f.lower() for f in linked}}) + if unknown_vendor: + raise LibraryVerifyError(f"ledger vendor records of {unknown_vendor} need a linked library " + f"present in the XDK extract") + + ours = scan_objects(objects_root, config_objects, pool_names) + for name, where in sorted(ours["all_commons"].items()): + if name not in bss_names: + global_failures.append(f"surplus-common: {name} in {[w[0] for w in where]}") + + library, library_members = library_definers(linked, bss_names) + + # January referencers (csplit relocations) refute an "inferred" owner that + # never references its own record (RF-CP's PROVEN condition); they never prove one. + # A missing or unreadable split object raises (exit 2) instead of becoming a global failure. + referencers, _unreadable = january_referencers(split_path.parent.parent, config_objects, bss_names) + + # January links Halo objects before the vendor libraries, so its pool holds + # every Halo record before the first vendor record. Checked symmetrically: + # every record between the first vendor label and the last Halo label is in + # conflict, whichever of the two labels is wrong. + labels = {} + for record in records: + if record["kind"] == "bss" and isinstance(ledger_by_name.get(record["name"]), dict): + labels[record["pool_index"]] = ledger_by_name[record["name"]].get("segment") + halo_at = [i for i, s in labels.items() if s == "halo"] + vendor_at = [i for i, s in labels.items() if s == "vendor"] + order_conflict = (min(vendor_at), max(halo_at)) \ + if halo_at and vendor_at and min(vendor_at) < max(halo_at) else None + + rows, excluded = [], [] + last_owner_index, last_owner_name = -1, None + for record in records: + if record["kind"] != "bss": + excluded.append({"pool_index": record["pool_index"], "name": record["name"], + "rva": f"{record['rva']:#x}", "size": record["size"], + "reason": ("linker-generated (not a COMMON record); excluded " + "from every denominator" if record["kind"] == "linker" else + "UNEXPECTED non-.bss pool contribution (cannot be classified)"), + "january_reasons": record["january_reasons"]}) + continue + name = record["name"] + entry = ledger_by_name.get(name) + reasons = list(record["january_reasons"]) + notes = [] + if entry is None: + reasons.append("no-ledger-entry") + entry = {} + segment, category, tag, owner = None, None, None, None + else: + segment, category = entry["segment"], entry["category"] + tag, owner = entry["tag"], entry["owner"] + reasons.extend(_ledger_reasons(entry, record, config_objects, vendor_categories)) + reasons.extend(_vendor_evidence_reasons(entry, record, library_hashes)) + if name in ledger_duplicates: + reasons.append("ledger-duplicate-entry: more than one ledger entry names this record") + if segment == "halo" and tag == "inferred" and owner and referencers.get(name) \ + and owner not in referencers[name]: + reasons.append(f"tag-exceeds-evidence: inferred owner {owner} is not a January referencer " + f"({len(referencers[name])} referencing TUs)") + + definers = ours["commons"].get(name, []) + real = ours["reals"].get(name, []) + static = ours["statics"].get(name, []) + undef = sorted(ours["undefs"].get(name, set())) + for obj, obj_category, section in real: + reasons.append(f"real-definition: {obj} ({section}); an initialised or real " + f"definition is not tentative storage") + for obj, obj_category, section in static: + reasons.append(f"static-definition: {obj} ({section})") + if len(definers) == 0: + reasons.append("no-definer:extern-only" if undef else "no-definer:absent") + elif len(definers) > 1: + reasons.append(f"duplicate-definers: {[d[0] for d in definers]}") + for obj, obj_category, size in definers: + if size != record["size"]: + reasons.append(f"size-mismatch: {obj} COMMON({size}) != January {record['size']}") + if law_alignment(size) != record["alignment"]: + reasons.append(f"alignment-class-differs: {obj} would align " + f"{law_alignment(size)}, January {record['alignment']}") + if obj_category is None: + reasons.append(f"definer-category-unknown: {obj}") + elif category and obj_category != category: + reasons.append(f"definer-category-mismatch: {obj} is {obj_category}, " + f"record {category}") + if tag in ("inferred", "probable") and owner and len(definers) == 1 \ + and definers[0][0] != owner: + reasons.append(f"definer-disagrees-with-evidence-owner: {definers[0][0]} != {owner}") + + # pool order may refute an owner, never prove one (house rule 48) + if segment == "halo" and tag in ("inferred", "probable") and owner in config_objects: + owner_index = config_objects[owner]["index"] + if owner_index < last_owner_index: + reasons.append(f"owner-violates-pool-order: {owner} (module {owner_index}) after " + f"{last_owner_name} (module {last_owner_index})") + else: + last_owner_index, last_owner_name = owner_index, owner + + if segment == "vendor": + xdk = [r for r in _readouts(entry) if r.get("channel") == "XDK"] + for readout in xdk: + lib = str(readout.get("library", "")).lower() + if lib[:-4] != str(category).lower() or not lib.endswith(".lib"): + reasons.append(f"vendor-readout-library-not-category: {readout.get('library')} " + f"for {category}") + hits = library.get(name, []) + for readout in xdk: + lib = str(readout.get("library", "")).lower() + in_lib = [h for h in hits if h[0] == lib] + if [(h[1], h[2], h[3]) for h in in_lib] != [(readout.get("member"), "COMMON", record["size"])]: + reasons.append(f"vendor-readout-not-reproduced: {lib} gives {in_lib}") + # another linked library that also defines the name (COMMON, real or weak) makes the + # record's library - its vendor category - ambiguous (RF-DX D11) + own = {str(readout.get("library", "")).lower() for readout in xdk} + others = [h for h in hits if h[0] not in own] + if others: + reasons.append(f"vendor-record-defined-by-another-library: {others}") + notes.append("vendor readout re-verified against the manifest-verified library") + elif segment == "halo" and library is not None and library.get(name): + reasons.append(f"halo-record-defined-by-vendor-library: {library[name]}") + + if order_conflict and order_conflict[0] <= record["pool_index"] <= order_conflict[1]: + reasons.append(f"segment-order-conflict: Halo and vendor labels interleave in January's " + f"pool (pool {order_conflict[0]}..{order_conflict[1]})") + + candidate = entry.get("candidate_owner") + if tag == "unresolved" and candidate: + notes.append(f"candidate owner {candidate} (not established; the tag stays unresolved); " + f"sole definer {'is' if [d[0] for d in definers] == [candidate] else 'is not'} " + f"the candidate") + + if reasons: + verdict = VERDICT_FAIL + elif tag == "unresolved": + verdict = VERDICT_PASS_UNRESOLVED + else: + verdict = VERDICT_PASS + # A record whose segment is invalid or contradicted by evidence cannot + # be classified: it enters no tally and the run fails closed (exit 5). + conflicted = any(reason.split(":")[0] in SEGMENT_CONFLICTS for reason in reasons) + valid = ((segment == "halo" and category == HALO_CATEGORY) + or (segment == "vendor" and category in vendor_categories)) + accounted = segment if valid and not conflicted else None + rows.append({ + "pool_index": record["pool_index"], "name": name, "rva": f"{record['rva']:#x}", + "size": record["size"], "alignment": record["alignment"], + "gap_before": record["gap_before"], "segment": accounted, + "ledger_segment": segment, "category": category if accounted else None, + "ledger_category": category, + "tag": tag, "tag_label": TAG_LABELS.get(tag), "owner": owner, + "candidate_owner": entry.get("candidate_owner"), + "containment_evidence": len(entry.get("containment_evidence", [])), + "verdict": verdict, "reasons": reasons, "notes": notes, + "definers": [d[0] for d in definers], "referencers": len(undef), + }) + + ambiguous = [{"pool_index": row["pool_index"], "name": row["name"], "reasons": row["reasons"]} + for row in rows if row["segment"] is None] + unexpected = [item for item in excluded if item["reason"].startswith("UNEXPECTED")] + report = { + "tool": "tools/common_pool_verify.py", "schema": 2, "status": STATUS, + "inputs": { + "config": str(config_dir / "config.json"), + "contribs_sha256": trace["inputs"]["contribs"].get("sha256"), + "symbols_sha256": trace["inputs"]["symbols"].get("sha256"), + "split_pool": str(split_path), "split_pool_sha256": trace["inputs"]["split_pool"].get("sha256"), + "ledger": str(ledger_path), "ledger_sha256": trace["inputs"]["ledger"]["sha256"], + "ledger_sha256_lf": trace["inputs"]["ledger"]["sha256_lf"], + "ledger_schema": ledger["schema"], "ledger_status": ledger["status"], + "xdk_manifest": str(xdk_manifest_path), + "xdk_manifest_sha256_lf": trace["inputs"]["xdk_manifest"]["sha256_lf"], + "objects_root": str(objects_root), "objects_scanned": ours["scanned"], + "stale_missing_units_ignored": ours["stale_missing_units"], + "vendor_libraries_reverified": True, + }, + "libraries": { + "scanned_linked": library_members, + "linked_not_in_extract": [ + {"library": e["library"], "category": e["category"], "reason": e["reason"]} + for e in manifest["linked_libraries_not_in_extract"]], + }, + "january": { + "pool_module_index": pool_module, "records": len(records), + "bss_records": sum(1 for r in records if r["kind"] == "bss"), + "linker_records": sum(1 for r in records if r["kind"] == "linker"), + "unexpected_records": sum(1 for r in records if r["kind"] == "unexpected"), + "layout_reasons": sum(1 for r in records if r["january_reasons"]), + }, + "excluded_linker_records": excluded, + "global_failures": global_failures, + "records": rows, + } + # the receipt fingerprints the inputs before they are parsed; a file replaced meanwhile (e.g. by + # a concurrent build) would leave a receipt that does not describe the data used (RF-DP D5) + again = {} + _trace_inputs(again, config_dir, split_path, ledger_path, xdk_manifest_path, objects_root) + changed = [key for key in ("inputs", "build_snapshot") if again[key] != trace[key]] + if changed: + raise PoolVerifyError(f"inputs changed during the run ({', '.join(changed)}); rerun on a quiet tree") + if ambiguous or unexpected: + report["result"] = "FAIL-CLOSED" + report["exit_code"] = EXIT_AMBIGUOUS + report["fail_closed"] = {"class": FAIL_CLASSES[EXIT_AMBIGUOUS], "exit_code": EXIT_AMBIGUOUS, + "records": ambiguous, "unexpected_contributions": unexpected} + report["accounting"] = None + return report + report["result"] = "COMPLETE" + report["fail_closed"] = None + report["accounting"] = tally(rows, records) + report["accounting"]["segment_evidence"] = ( + "Halo/vendor segments re-verified against the XDK libraries January linked (bytes == recorded " + f"manifest); linked libraries not in the extract: " + f"{[e['library'] for e in manifest['linked_libraries_not_in_extract']] or 'none'}") + failed = global_failures or any(r["verdict"] == VERDICT_FAIL for r in rows) + report["exit_code"] = EXIT_FAILURES if failed else EXIT_OK + return report + + +# -- accounting (house rule 5; linker records never counted) ------------------- + +def _bucket(): + return {"records": 0, "bytes": 0, "gap_bytes": 0, + "by_tag": {tag: {"records": 0, "bytes": 0, "verdicts": {}} for tag in + list(TAG_RANK) + ["missing"]}, + "by_verdict": {}, "failure_reasons": {}} + + +def _add(bucket, row): + bucket["records"] += 1 + bucket["bytes"] += row["size"] + bucket["gap_bytes"] += row["gap_before"] + tag = row["tag"] if isinstance(row["tag"], str) and row["tag"] in TAG_RANK else "missing" + by_tag = bucket["by_tag"][tag] + by_tag["records"] += 1 + by_tag["bytes"] += row["size"] + verdict = by_tag["verdicts"].setdefault(row["verdict"], {"records": 0, "bytes": 0}) + verdict["records"] += 1 + verdict["bytes"] += row["size"] + overall = bucket["by_verdict"].setdefault(row["verdict"], {"records": 0, "bytes": 0}) + overall["records"] += 1 + overall["bytes"] += row["size"] + for reason in row["reasons"]: + key = reason.split(":")[0] + bucket["failure_reasons"][key] = bucket["failure_reasons"].get(key, 0) + 1 + + +def tally(rows, january_records=None): + """Separate Halo / vendor-category tallies. + + Raises ValueError if a linker record, an unclassified row, or a row whose + segment and category disagree would enter a tally: such a row can never be + counted anywhere (the run fails closed instead). + """ + halo, vendor = _bucket(), {} + seen = set() + for row in rows: + if row.get("kind") == "linker" or row.get("segment") == "linker": + raise ValueError(f"linker record {row['name']} must not enter any tally") + # one January pool record = one row (two records may share a name only + # in a corrupt symbols.json, which fails them as duplicate-january-name) + key = row.get("pool_index", row["name"]) + if key in seen: + raise ValueError(f"{row['name']} would be counted twice") + seen.add(key) + segment, category = row.get("segment"), row.get("category") + if segment == "halo" and category == HALO_CATEGORY: + _add(halo, row) + elif segment == "vendor" and category and category != HALO_CATEGORY: + _add(vendor.setdefault(category, _bucket()), row) + elif segment is None: + raise ValueError(f"{row['name']} is unclassified; an ambiguous classification " + f"fails the run closed and is never tallied") + else: + raise ValueError(f"{row['name']}: segment {segment!r} and category " + f"{category!r} disagree; refusing to count it") + accounting = {"halo": halo, "vendor": dict(sorted(vendor.items())), + "note": "bytes = January COMMON extents; gap_bytes = alignment padding " + "before each record; no credit, no progress percentage"} + if january_records is not None: + bss = [r for r in january_records if r["kind"] == "bss"] + span = (bss[-1]["rva"] + bss[-1]["size"] - bss[0]["rva"]) if bss else 0 + counted = (halo["bytes"] + halo["gap_bytes"] + + sum(b["bytes"] + b["gap_bytes"] for b in vendor.values())) + accounting["conservation"] = { + "january_bss_span": span, "counted_bytes_plus_gaps": counted, + "holds": span == counted, + "linker_bytes_excluded": sum(r["size"] for r in january_records + if r["kind"] == "linker"), + } + return accounting + + +# -- receipts ---------------------------------------------------------------------- + +def verifier_version(): + """sha256 of this verifier's source (raw and LF-normalised) and of its COFF reader.""" + own = Path(__file__).resolve() + reader = own.parent / "coff_compare.py" + return {"path": "tools/common_pool_verify.py", "sha256": sha256_file(own), + "sha256_lf": sha256_file_lf(own), + "coff_compare_sha256_lf": sha256_file_lf(reader) if reader.is_file() else None} + + +def summary(report): + """Per-segment verdict counts of a complete report (records / January bytes).""" + acc = report.get("accounting") + if not acc: + return None + + def verdicts(bucket): + return {v: [d["records"], d["bytes"]] for v, d in sorted(bucket["by_verdict"].items())} + + return {"halo": {"records": acc["halo"]["records"], "bytes": acc["halo"]["bytes"], + "verdicts": verdicts(acc["halo"])}, + "vendor": {c: {"records": b["records"], "bytes": b["bytes"], "verdicts": verdicts(b)} + for c, b in acc["vendor"].items()}, + "linker_excluded": [[x["name"], x["size"]] for x in report["excluded_linker_records"]], + "global_failures": len(report["global_failures"]), + "conservation_holds": acc["conservation"]["holds"]} + + +def build_receipt(argv, trace, exit_code, report=None, error=None): + fail = None + if exit_code in FAIL_CLASSES: + fail = {"class": FAIL_CLASSES[exit_code], "exit_code": exit_code, + "message": str(error) if error is not None else None} + if report is not None and report.get("fail_closed"): + fail["records"] = [[r["name"], r["reasons"]] for r in report["fail_closed"]["records"]] + return { + "schema": RECEIPT_SCHEMA, "status": STATUS, + "utc": datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds"), + "verifier": verifier_version(), + "python": sys.version.split()[0], + "argv": list(argv), + "result": "COMPLETE" if exit_code in (EXIT_OK, EXIT_FAILURES) else "FAIL-CLOSED", + "exit_code": exit_code, + "fail_closed": fail, + "inputs": trace.get("inputs"), + "build_snapshot": trace.get("build_snapshot"), + "xdk_libraries": trace.get("xdk_libraries"), + "summary": summary(report) if report is not None else None, + } + + +# -- text rendering ---------------------------------------------------------------- + +def _block_lines(title, bucket): + lines = [f"{title}: {bucket['records']} records, {bucket['bytes']:,} B " + f"(+{bucket['gap_bytes']:,} gap B)"] + for tag, info in bucket["by_tag"].items(): + if not info["records"]: + continue + verdicts = ", ".join(f"{v} {d['records']}/{d['bytes']:,} B" + for v, d in sorted(info["verdicts"].items())) + lines.append(f" {tag:<10} {info['records']:>3} records {info['bytes']:>10,} B : {verdicts}") + if bucket["failure_reasons"]: + reasons = ", ".join(f"{k} {v}" for k, v in sorted(bucket["failure_reasons"].items())) + lines.append(f" failure reasons: {reasons}") + return lines + + +def render_text(report, show_records=True): + lines = [f"common_pool_verify - {report['status']}", + f"result: {report['result']} (exit {report['exit_code']})", + f"pool module {report['january']['pool_module_index']}: " + f"{report['january']['records']} contributions = {report['january']['bss_records']} " + f"COMMON records + {report['january']['linker_records']} linker records (excluded)", + f"objects scanned {report['inputs']['objects_scanned']} under " + f"{report['inputs']['objects_root']}; vendor libraries re-verified: " + f"{report['inputs']['vendor_libraries_reverified']}"] + acc = report["accounting"] + if report["fail_closed"]: + fail = report["fail_closed"] + lines.append(f"FAIL-CLOSED ({fail['class']}): {len(fail['records'])} record(s) cannot be " + f"classified, {len(fail['unexpected_contributions'])} unexpected contribution(s); " + f"no accounting") + lines += [f" {r['name']}: {'; '.join(r['reasons'])}" for r in fail["records"]] + else: + lines.append(f"segment evidence: {acc.get('segment_evidence')}") + lines += _block_lines("HALO (halobetacache)", acc["halo"]) + for category, bucket in acc["vendor"].items(): + lines += _block_lines(f"VENDOR {category}", bucket) + c = acc["conservation"] + lines.append(f"conservation: January .bss pool span {c['january_bss_span']:,} B == counted " + f"{c['counted_bytes_plus_gaps']:,} B: {c['holds']}; linker bytes excluded " + f"{c['linker_bytes_excluded']}") + for item in report["excluded_linker_records"]: + lines.append(f"EXCLUDED {item['name']} {item['rva']} {item['size']} B: {item['reason']}") + lines.append(f"global failures: {len(report['global_failures'])}") + lines += [f" {g}" for g in report["global_failures"]] + if show_records: + for row in report["records"]: + lines.append(f"{row['pool_index']:>3} {row['name']:<48} {row['size']:>7} " + f"{str(row['segment']):<6} {str(row['category']):<13} " + f"{str(row['tag']):<10} {row['verdict']:<21} " + f"{'; '.join(row['reasons'])}") + return "\n".join(lines) + "\n" + + +def _remove_outputs(paths): + """Best effort: a run that ends in exit 2 leaves no report (no accounting) behind.""" + for path in paths: + try: + path.unlink() + except OSError: + pass + + +def _write_reports(report, args, written): + """Write the JSON report (receipt embedded) and the text report (or stdout); *written* + collects every path this run has written.""" + if args.json: + Path(args.json).write_text(json.dumps(report, indent=1) + "\n", encoding="utf-8") + written.append(Path(args.json)) + text = render_text(report) + if args.text: + Path(args.text).write_text(text, encoding="utf-8") + written.append(Path(args.text)) + else: + sys.stdout.write(text) + + +def main(argv=None): + argv = list(sys.argv[1:] if argv is None else argv) + parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0]) + parser.add_argument("--root", default=".") + parser.add_argument("--objects", help="object root under test (default /build/base)") + # --ledger, --xdk-lib-dir and --xdk-lib-manifest are required, but checked by + # verify() rather than argparse so that a run without them still writes its + # receipt and exits with its own fail-closed code (2 ledger, 3 libraries). + parser.add_argument("--ledger", + help="REQUIRED: research provenance ledger (e.g. research/" + "remaining_frontier_20260926/q10/common_pool_ledger.json)") + parser.add_argument("--split-pool", help="January split pool object") + parser.add_argument("--config-dir", help="config directory (default /config)") + parser.add_argument("--xdk-lib-dir", + help="REQUIRED: XDK 3911 xbox/lib directory (no ledger-only mode)") + parser.add_argument("--xdk-lib-manifest", + help="REQUIRED: recorded sha256/size manifest of that directory") + parser.add_argument("--receipt", required=True, help="write the run receipt (JSON) here") + parser.add_argument("--json", help="write the JSON report here") + parser.add_argument("--text", help="write the text report here (default stdout)") + args = parser.parse_args(argv) + trace, report, error = {}, None, None + try: + report = verify(args.root, args.objects, args.ledger, args.split_pool, + args.config_dir, args.xdk_lib_dir, args.xdk_lib_manifest, trace=trace) + exit_code = report["exit_code"] + except PoolVerifyError as caught: + error, exit_code = caught, caught.exit_code + except (ValueError, TypeError, KeyError, AttributeError, struct.error) as caught: + # malformed input must never pass for "failures found" (1) or be half-reported + error, exit_code = caught, EXIT_MALFORMED + except IndexError as caught: + # a malformed structure indexed out of range: malformed input, receipted (RF-DP D6) + exit_code, error = EXIT_MALFORMED, caught + except OSError as caught: + # a file that vanished, is locked or unreadable outside an explicit wrapper: unreadable + # input (2), never the uncaught traceback exit status 1 = "complete, failing records" (RF-DP D6) + error, exit_code = caught, EXIT_UNREADABLE + except Exception as caught: # deliberately total (RF-DX, D6) + # any other exception (a verifier defect or an input shape nobody anticipated) is not a + # complete run either: fail closed (2) with a receipt that names the type + error = PoolVerifyError(f"unexpected {type(caught).__name__}: {caught}") + exit_code = EXIT_UNREADABLE + receipt = build_receipt(argv, trace, exit_code, report, error) + written = [] + if report is not None: + report["receipt"] = receipt + try: + _write_reports(report, args, written) + except Exception as unwritable: # deliberately total (RF-DX, D6) + # a report that cannot be written (missing directory, unencodable text, ...) leaves the + # run unreported: fail closed (2), drop what this run wrote (an exit-2 run carries no + # accounting) and let the receipt, written last, say so + _remove_outputs(written) + error = PoolVerifyError(f"cannot write the report: {type(unwritable).__name__}: {unwritable}") + exit_code, report = EXIT_UNREADABLE, None + receipt = build_receipt(argv, trace, exit_code, None, error) + if error is not None: + print(f"common_pool_verify: FAIL-CLOSED ({FAIL_CLASSES[exit_code]}): " + f"{type(error).__name__}: {error}", file=sys.stderr) + try: + Path(args.receipt).write_text(json.dumps(receipt, indent=1) + "\n", encoding="utf-8") + except OSError as caught: + _remove_outputs(written) # no report outlives a run whose receipt could not be written (RF-DX) + print(f"common_pool_verify: cannot write the receipt {args.receipt}: {caught}", file=sys.stderr) + return EXIT_UNREADABLE + return exit_code + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/project_x86.py b/tools/project_x86.py index 5a6749e6..86a4c4e9 100644 --- a/tools/project_x86.py +++ b/tools/project_x86.py @@ -28,10 +28,13 @@ from . import ninja_syntax from .ninja_syntax import serialize_path from .semantic_progress import ( SemanticProgressError, + apply_common_pool_credit, + apply_data_category_reassignments, apply_semantic_accepted_ledger, apply_semantic_data_matches, apply_semantic_matches, apply_semantic_rejections, + clear_common_pool_outputs, require_symbol_ownership_snapshots, revoke_incomplete_units, ) @@ -467,6 +470,11 @@ def generate_build_ninja(sln: SolutionConfig) -> None: sln.config_dir / "symbols.json", sln.config_dir / "symbol_ownership.json", sln.config_dir / "parked.json", + sln.config_dir / "data_category_reassignments.json", + # The COMMON pool credit entry, its verifier and the Q10 ledger + # and manifest are deliberately not inputs: this edge always runs, + # and a ninja "missing input" error would pre-empt the credit's + # fail-closed receipt (owner ruling Q10). sln.tools_dir / "coff_compare.py", sln.tools_dir / "parked_functions.py", sln.tools_dir / "semantic_progress.py", @@ -668,6 +676,12 @@ def generate_solution(sln: SolutionConfig) -> None: # Print progress information from objdiff report def calculate_progress(sln: SolutionConfig) -> None: sln.validate() + try: + # No receipt of an earlier COMMON pool credit run may outlive a + # progress run that fails before (or without reaching) that step. + clear_common_pool_outputs(sln.build_dir, Path.cwd()) + except SemanticProgressError as error: + sys.exit(f"Semantic progress verification failed: {error}") report_path = sln.build_dir / "report.json" if not report_path.is_file(): sys.exit(f"Report file {report_path} does not exist") @@ -714,6 +728,21 @@ def calculate_progress(sln: SolutionConfig) -> None: Path("objdiff.json"), ) incomplete_units = revoke_incomplete_units(report_data) + data_category_reassignments = apply_data_category_reassignments( + report_data, + Path.cwd(), + sln.config_dir / "data_category_reassignments.json", + Path("objdiff.json"), + ) + common_pool_credits = apply_common_pool_credit( + report_data, + Path.cwd(), + sln.config_dir / "common_pool_credit.json", + Path("objdiff.json"), + sln.config_dir / "semantic_data_matches.json", + sln.config_dir / "data_category_reassignments.json", + sln.build_dir, + ) parked = require_valid_parked_functions( Path.cwd(), report_path, @@ -754,6 +783,13 @@ def calculate_progress(sln: SolutionConfig) -> None: for incomplete_unit in incomplete_units: progress_print( f" Revoked premature complete unit: {incomplete_unit}") + for reassignment in data_category_reassignments: + progress_print( + f" Reassigned data denominator (accounting only): {reassignment}") + for common_pool_credit in common_pool_credits: + progress_print( + f" Verified COMMON pool record credit (data only): " + f"{common_pool_credit}") progress_print( f" Validated parked compiler ties: {parked['summary']['active']}" ) diff --git a/tools/semantic_progress.py b/tools/semantic_progress.py index 17842121..5f44c71b 100644 --- a/tools/semantic_progress.py +++ b/tools/semantic_progress.py @@ -10,10 +10,13 @@ semantic relocation comparison proves exact equality. """ import copy +import datetime import hashlib import json +import re import struct import subprocess +import sys import tempfile from collections import Counter from pathlib import Path @@ -681,6 +684,16 @@ _IMAGE_SYM_CLASS_EXTERNAL = 2 # selections depend on auxiliary fields (checksum, associated section) that the # executable split does not reproduce and the member checks do not compare. _MODEL_ALLOWED_SELECTIONS = frozenset({None, 0, _IMAGE_COMDAT_SELECT_ANY}) +_IMAGE_SCN_MEM_WRITE = 0x80000000 +_IMAGE_COMDAT_SELECT_NODUPLICATES = 1 +# A surplus helper function (see _verify_helper_reached_constant): csplit +# writes every January function COMDAT as select-noduplicates, so the January +# provider's copy may carry either selection; the rebuilt copies must be +# select-any so that the linker can fold ours into the provider's. +_HELPER_JANUARY_SELECTIONS = frozenset({ + _IMAGE_COMDAT_SELECT_NODUPLICATES, _IMAGE_COMDAT_SELECT_ANY}) +_HELPER_REBUILT_SELECTIONS = frozenset({_IMAGE_COMDAT_SELECT_ANY}) +_IMAGE_SYM_CLASS_WEAK_EXTERNAL = 105 def _objdiff_data_section(section): @@ -1151,8 +1164,299 @@ def _january_definers(project_root, config_units, symbol_names): return definers +def _relocation_rows(obj, section_number): + """(address, type, target symbol) of every relocation, in table order.""" + section = obj["sections"][section_number - 1] + rows = [] + for index in range(section["reloc_count"]): + address, symbol_index, kind = struct.unpack_from( + " 0 + for entry in target["symbols"]): + raise SemanticProgressError( + f"it is reached from {helper!r}, which January's unit defines") + _, ours_section = _single_function_comdat( + base, helper, "rebuilt surplus helper", _HELPER_REBUILT_SELECTIONS) + references = [entry for entry in target["symbols"] + if entry["name"] == helper] + if not references or any( + int(entry["section"]) != 0 + or int(entry["storage"]) != _IMAGE_SYM_CLASS_EXTERNAL + for entry in references): + raise SemanticProgressError( + f"helper {helper!r} is not a January undefined reference of this " + f"unit") + if not any(destination["name"] == helper + for number in range(1, len(target["sections"]) + 1) + for _, _, destination in _relocation_rows(target, number)): + raise SemanticProgressError( + f"January's unit never relocates to helper {helper!r}") + definers = _january_definers(project_root, config_units, [helper])[helper] + if definers != [provider]: + raise SemanticProgressError( + f"helper {helper!r} provider {provider!r} is not January's unique " + f"definer (definers {definers})") + provider_config = config_units[provider] + try: + january_provider = load( + Path(project_root) / provider_config["target_path"]) + rebuilt_provider = load( + Path(project_root) / provider_config["base_path"]) + ours_info = section_info_by_number(base, helper_number) + ours_resolved = section_info_resolved(base, helper, symbol_addresses) + except (CoffError, KeyError, OSError) as error: + raise SemanticProgressError( + f"cannot read helper {helper!r} or its provider {provider}: " + f"{error}") from error + ours_rows = _relocation_rows(base, helper_number) + january_rows = None + for obj, description, selections in ( + (january_provider, f"January provider {provider}", + _HELPER_JANUARY_SELECTIONS), + (rebuilt_provider, f"rebuilt provider {provider}", + _HELPER_REBUILT_SELECTIONS)): + owner, theirs_section = _single_function_comdat( + obj, helper, f"{description} helper", selections) + try: + info = section_info_by_number(obj, int(owner["section"])) + resolved = section_info_resolved(obj, helper, symbol_addresses) + except (CoffError, KeyError) as error: + raise SemanticProgressError( + f"cannot resolve helper {helper!r} in {description}: {error}" + ) from error + if int(theirs_section["flags"]) != int(ours_section["flags"]) \ + or theirs_section["size"] != ours_section["size"] \ + or not section_infos_equal(info, ours_info): + raise SemanticProgressError( + f"helper {helper!r} bytes or relocations differ from " + f"{description}") + if _defined_section_symbols(obj, int(owner["section"])) \ + != _defined_section_symbols(base, helper_number): + raise SemanticProgressError( + f"helper {helper!r} section symbol table differs from " + f"{description}") + for measured in (resolved, ours_resolved): + if any(relocation["target"][0] != "address" + for relocation in measured["relocations"]): + raise SemanticProgressError( + f"helper {helper!r} relocation has no image address") + if resolved != ours_resolved: + raise SemanticProgressError( + f"helper {helper!r} resolved relocations differ from " + f"{description}") + rows = _relocation_rows(obj, int(owner["section"])) + for side in (rows, ours_rows): + if any(int(destination["storage"]) != _IMAGE_SYM_CLASS_EXTERNAL + for _, _, destination in side): + raise SemanticProgressError( + f"helper {helper!r} relocates through a non-external " + f"symbol") + if [(address, kind, destination["name"]) + for address, kind, destination in rows] \ + != [(address, kind, destination["name"]) + for address, kind, destination in ours_rows]: + raise SemanticProgressError( + f"helper {helper!r} relocation targets differ from " + f"{description}") + if january_rows is None: + january_rows = rows + constants = set() + for (address, _, ours_target), (_, _, january_target) in zip( + ours_rows, january_rows): + number = int(ours_target["section"]) + if number == 0: + continue + name = ours_target["name"] + if not 0 < number <= len(base["sections"]) \ + or int(base["sections"][number - 1]["flags"]) \ + & (IMAGE_SCN_CNT_CODE | _IMAGE_SCN_MEM_EXECUTE): + raise SemanticProgressError( + f"helper {helper!r} relocates to {name!r}, which is not a " + f"data constant") + if int(january_target["section"]) <= 0: + raise SemanticProgressError( + f"helper {helper!r} constant {name!r} is not defined by the " + f"January provider {provider}") + ours_constant = _select_any_definition( + base, name, "rebuilt helper constant") + # The identity proved below covers the constant's own bytes, so the + # relocation must address one of them (all three copies carry the + # same addend: the strict comparator compared it). + addend = struct.unpack_from( + "= 0: + return value + raise SemanticProgressError(f"malformed {description}: {value!r}") + + +def _objdiff_named_sections(obj, unit_name): + """The object's sections under the names objdiff reports them by. + + A long section name is stored in the section header as '/' into the string table. objdiff's object reader resolves it (the + split's '/20' reports as '.rdata$debug'), so it is resolved here too; a + malformed or dangling reference fails closed. + """ + data = obj["data"] + symbol_offset, symbol_count = struct.unpack_from("> 20) & 0xF + if code > 14: + raise SemanticProgressError( + f"invalid COFF section alignment code {code} in section " + f"{section['index']}") + alignment = max(1 << (code - 1) if code else 16, 4) + advanced = (offset + int(section["size"]) + alignment - 1) \ + & ~(alignment - 1) + shares[int(section["index"])] = advanced - offset + offset = advanced + if sum(shares.values()) != _objdiff_report_extent(sections): + raise SemanticProgressError( + "objdiff extent shares do not sum to the report extent") + return shares + + +def _move_total_data(measures, delta, category_id): + total = int(measures.get("total_data", 0)) + delta + matched = int(measures.get("matched_data", 0)) + complete = int(measures.get("complete_data", 0)) + if total < matched or total < complete: + raise SemanticProgressError( + f"data reassignment would leave category {category_id} below its " + f"matched or complete data") + measures["total_data"] = total + measures["matched_data_percent"] = _percent(matched, total) + measures["complete_data_percent"] = _percent(complete, total) + + +def _unit_categories(unit, description): + categories = unit.get("metadata", {}).get("progress_categories", []) + if isinstance(categories, str): + categories = [categories] + if not isinstance(categories, list): + raise SemanticProgressError( + f"malformed progress categories for {description}") + return categories + + +def _plan_data_category_reassignment(entry, report_units, config_units, + categories, project_root, seen_units): + """Verify one manifest entry; return (unit, from, {to: bytes}, rows).""" + if not isinstance(entry, dict) or set(entry) != _REASSIGNMENT_ENTRY_KEYS: + keys = sorted(entry) if isinstance(entry, dict) else entry + raise SemanticProgressError( + f"data category reassignment entry must have exactly the keys " + f"{sorted(_REASSIGNMENT_ENTRY_KEYS)}: {keys!r}") + unit_name = entry["unit"] + if not _nonempty_string(unit_name): + raise SemanticProgressError( + f"malformed data category reassignment unit: {unit_name!r}") + if unit_name in seen_units: + raise SemanticProgressError( + f"data category reassignment unit listed twice: {unit_name}") + seen_units.add(unit_name) + if unit_name not in report_units or unit_name not in config_units: + raise SemanticProgressError( + f"data category reassignment unit not found: {unit_name}") + if entry["extent_model"] not in DATA_CATEGORY_REASSIGNMENT_MODELS: + raise SemanticProgressError( + f"unknown data category reassignment extent model " + f"{entry['extent_model']!r}: {unit_name}") + if not _nonempty_string(entry["reason"]): + raise SemanticProgressError( + f"data category reassignment needs a reason: {unit_name}") + from_category = entry["from_category"] + report_unit = report_units[unit_name] + config_unit = config_units[unit_name] + for unit, side in ((report_unit, "report"), (config_unit, "objdiff.json")): + if _unit_categories(unit, f"{unit_name} ({side})") != [from_category]: + raise SemanticProgressError( + f"data category reassignment unit is not solely in " + f"{from_category!r} ({side}): {unit_name}") + if from_category not in categories: + raise SemanticProgressError( + f"progress category not found: {from_category}") + measures = report_unit.get("measures", {}) + if config_unit.get("metadata", {}).get("complete") \ + or report_unit.get("metadata", {}).get("complete") \ + or _report_count(measures.get("matched_data", 0), + f"matched_data for {unit_name}") \ + or _report_count(measures.get("complete_data", 0), + f"complete_data for {unit_name}") \ + or _report_count(measures.get("complete_units", 0), + f"complete_units for {unit_name}"): + raise SemanticProgressError( + f"data category reassignment needs a unit with no matched or " + f"complete data: {unit_name}") + + target = load(project_root / config_unit["target_path"]) + named = _objdiff_named_sections(target, unit_name) + _require_report_binding( + named, report_unit, unit_name, "data-category-reassignment") + unit_total = _report_count( + measures.get("total_data", 0), f"total_data for {unit_name}") + if unit_total != _manifest_count( + entry["unit_total_data"], f"unit_total_data for {unit_name}"): + raise SemanticProgressError( + f"data category reassignment unit total changed: {unit_name} " + f"(report {unit_total}, manifest {entry['unit_total_data']})") + shares = {} + for sections in _objdiff_report_data_groups(named).values(): + shares.update(_objdiff_report_shares(sections)) + sections = {int(section["index"]): section for section in named["sections"]} + externals = {} + for item in target["symbols"]: + if int(item["section"]) > 0 \ + and int(item["storage"]) == _IMAGE_SYM_CLASS_EXTERNAL: + externals.setdefault(item["name"], []).append(item) + externals.setdefault(("section", int(item["section"])), []) \ + .append(item) + + records = entry["records"] + if not isinstance(records, list) or not records: + raise SemanticProgressError( + f"data category reassignment needs records: {unit_name}") + moved, rows, seen_symbols, seen_sections = {}, [], set(), set() + for record in records: + if not isinstance(record, dict) \ + or set(record) != _REASSIGNMENT_RECORD_KEYS: + raise SemanticProgressError( + f"data category reassignment record must have exactly the " + f"keys {sorted(_REASSIGNMENT_RECORD_KEYS)}: {unit_name}: " + f"{record!r}") + symbol = record["symbol"] + label = f"{unit_name}:{symbol}" + if not _nonempty_string(symbol) or not _nonempty_string( + record["evidence"]) or not _nonempty_string(record["section"]): + raise SemanticProgressError( + f"malformed data category reassignment record: {label}") + if symbol in seen_symbols: + raise SemanticProgressError( + f"data category reassignment record listed twice: {label}") + seen_symbols.add(symbol) + definitions = externals.get(symbol, []) + if len(definitions) != 1: + raise SemanticProgressError( + f"data category reassignment record is not one defined " + f"external symbol of the target: {label} " + f"({len(definitions)} definitions)") + number = int(definitions[0]["section"]) + if int(definitions[0]["value"]) != 0 \ + or len(externals[("section", number)]) != 1: + raise SemanticProgressError( + f"data category reassignment record does not own its whole " + f"section: {label}") + if number in seen_sections or number not in shares: + raise SemanticProgressError( + f"data category reassignment record is not a distinct " + f"reported data section: {label}") + seen_sections.add(number) + section = sections[number] + size = _manifest_count(record["size"], f"size for {label}") + if section["name"] != record["section"] \ + or int(section["size"]) != size: + raise SemanticProgressError( + f"data category reassignment record does not match the " + f"target: {label} (target {section['name']} " + f"{section['size']} B, manifest {record['section']} {size} B)") + to_category = record["to_category"] + if to_category == from_category or to_category not in categories: + raise SemanticProgressError( + f"invalid data category reassignment target " + f"{to_category!r}: {label}") + moved[to_category] = moved.get(to_category, 0) + shares[number] + rows.append((size, shares[number])) + pinned = entry["moved"] + if not isinstance(pinned, dict) or { + key: _manifest_count(value, f"moved {key} for {unit_name}") + for key, value in pinned.items()} != moved: + raise SemanticProgressError( + f"data category reassignment totals changed: {unit_name} " + f"(computed {dict(sorted(moved.items()))}, manifest {pinned!r})") + return unit_name, from_category, moved, rows + + +def apply_data_category_reassignments(report, project_root, manifest_path, + objdiff_config_path): + """Move proven foreign records' data denominators between categories. + + Accounting only: see the comment above DATA_CATEGORY_REASSIGNMENT_MODELS. + Every entry is verified before any measure changes; any failure raises. + """ + if not manifest_path.is_file(): + return [] + manifest = json.loads(manifest_path.read_text(encoding="utf-8")) + if not isinstance(manifest, dict) \ + or not set(manifest) <= _REASSIGNMENT_MANIFEST_KEYS \ + or not isinstance(manifest.get("entries"), list) \ + or not isinstance(manifest.get("categories", []), list): + raise SemanticProgressError( + "data category reassignment manifest must be an object with an " + "entries list and an optional categories list") + objdiff = json.loads(objdiff_config_path.read_text(encoding="utf-8")) + report_units = {unit["name"]: unit for unit in report.get("units", [])} + config_units = {unit["name"]: unit for unit in objdiff.get("units", [])} + categories = {item["id"]: item for item in report.get("categories", [])} + declared = [] + for item in manifest.get("categories", []): + if not isinstance(item, dict) \ + or set(item) != _REASSIGNMENT_CATEGORY_KEYS \ + or not _nonempty_string(item["id"]) \ + or not _nonempty_string(item["name"]): + raise SemanticProgressError( + f"malformed declared progress category: {item!r}") + if item["id"] in categories: + raise SemanticProgressError( + f"declared progress category already exists: {item['id']}") + categories[item["id"]] = { + "id": item["id"], "name": item["name"], + "measures": { + "fuzzy_match_percent": 100.0, "matched_code_percent": 100.0, + "matched_functions_percent": 100.0, + "complete_code_percent": 100.0, "total_data": 0, + "matched_data": 0, "matched_data_percent": 0.0, + "complete_data": 0, "complete_data_percent": 0.0, + "total_units": 0, "complete_units": 0}} + declared.append(item["id"]) + + plans, seen_units = [], set() + for entry in manifest["entries"]: + plans.append(_plan_data_category_reassignment( + entry, report_units, config_units, categories, + Path(project_root), seen_units)) + used = {to for _, _, moved, _ in plans for to in moved} + unused = sorted(set(declared) - used) + if unused: + raise SemanticProgressError( + f"declared progress category receives no data: {unused}") + + for category_id in declared: + report.setdefault("categories", []).append(categories[category_id]) + notes = [] + for unit_name, from_category, moved, rows in plans: + total = sum(moved.values()) + _move_total_data( + categories[from_category]["measures"], -total, from_category) + for to_category, share in sorted(moved.items()): + _move_total_data( + categories[to_category]["measures"], share, to_category) + raw = sum(size for size, _ in rows) + notes.append( + f"{unit_name}: {from_category} -{total} -> " + + ", ".join(f"{to} +{share}" for to, share in sorted(moved.items())) + + f" ({len(rows)} records: {raw} raw + {total - raw} objdiff " + f"padding bytes)") + return notes + + +# Pooled COMMON record credit (owner ruling Q10, 2026-09-28): data credit only. +# +# January's linker pools every COMMON (tentative) record into one '* Linker *' +# contribution, which the executable split turns into the single unit +# source/linker_common. objdiff has no rebuilt object for that unit, so it can +# never match any of its data. config/common_pool_credit.json pins the reviewed +# per-record verifier (tools/common_pool_verify.py), its provenance ledger and +# its XDK library manifest by LF sha256, names the XDK library directory, and +# lists the Halo records to credit with each record's objdiff-3.3.1-combined +# extent share (the 38f82c59 model: size plus the padding the model inserts +# after it). Every progress run re-runs the verifier as its reviewed command +# line (with --xdk-lib-dir and the manifest its own pin requires) and credits +# exactly the listed shares, and only while each listed record is still a +# qualifying PASS: verdict PASS (tag inferred or probable), Halo segment, in a +# complete run with no global failure. PASS-OWNER-UNRESOLVED, FAIL, vendor +# and linker records earn nothing, and a PASS record that is not listed earns +# nothing either. Only matched data moves (overall, the unit's category and +# the unit): denominators, functions, units, completion and the unit's MISSING +# status are untouched, so there is no whole-pool Matching claim. Any failure +# - a pin mismatch, a missing or unreadable input, malformed evidence, a +# verifier run that fails closed, or a listed record that no longer qualifies - +# raises SemanticProgressError, so progress fails exactly as it does for every +# other semantic data verification. Every attempt writes a receipt first. +# The COFF reader (tools/coff_compare.py) is pinned too (Q10 addition): the +# file, the reader this process loaded (by content) and the reader the +# verifier's receipt names must all equal the pin; changing the reader needs +# an explicit reviewed re-pin. Pins bind files, not the interpreter that runs +# them. Pinning prevents unnoticed changes to reviewed assumptions; it does +# not prove those assumptions or January ownership (limitation L1). +COMMON_POOL_CREDIT_SCHEMA = "common-pool-credit/1" +COMMON_POOL_CREDIT_RECEIPT_SCHEMA = "common-pool-credit-receipt/1" +COMMON_POOL_VERIFY_RECEIPT_SCHEMA = "common-pool-verify-receipt/1" +COMMON_POOL_VERIFIER_PATH = "tools/common_pool_verify.py" +COMMON_POOL_VERIFIER_MODULE = "tools.common_pool_verify" +COMMON_POOL_READER_PATH = "tools/coff_compare.py" +COMMON_POOL_OUTPUT_DIR = "common_pool" +COMMON_POOL_QUALIFYING_VERDICT = "PASS" +COMMON_POOL_QUALIFYING_TAGS = frozenset({"inferred", "probable"}) +COMMON_POOL_HALO_SEGMENT = "halo" +COMMON_POOL_L1 = ("L1: pinning prevents unnoticed changes to reviewed " + "assumptions; it does not prove those assumptions or " + "January ownership.") +# L1 trust root 8 (owner, Q10 additions), carried by every receipt +COMMON_POOL_ENVIRONMENT = ( + "Pins are not protection against a compromised execution environment. " + "The Python interpreter, its module search path and bytecode cache, the " + "unpinned progress code and the generated build outputs are trusted, not " + "pinned (L1 trust root 8).") +# 0 = complete, no failing record; 1 = complete, failing records (FAIL rows +# earn nothing) or global failures (refused below). 2-5 are the verifier's +# fail-closed classes and carry no accounting. +COMMON_POOL_COMPLETE_EXITS = frozenset({0, 1}) +# credit_receipt.json first: once it is gone, no earlier run's outcome can +# stand in for this run, even when removing a verifier output fails next +# (that failure is then receipted). +_POOL_OUTPUT_FILES = ("credit_receipt.json", "verify_receipt.json", + "verify_report.json", "verify_report.txt") +_POOL_ENTRY_KEYS = frozenset({ + "schema", "reason", "scope", "limitation", "unit", "category", + "extent_model", "unit_total_data", "verifier", "reader", "ledger", + "xdk_manifest", "xdk_lib_dir", "linked_libraries_not_in_extract", "credit", + "records"}) +_POOL_PIN_KEYS = frozenset({"path", "sha256_lf"}) +# pins whose path is fixed: the verifier the hook runs and its COFF reader +_POOL_FIXED_PIN_PATHS = {"verifier": COMMON_POOL_VERIFIER_PATH, + "reader": COMMON_POOL_READER_PATH} +_POOL_CREDIT_KEYS = frozenset({"records", "raw", "padding", "total"}) +_POOL_RECORD_KEYS = frozenset({"symbol", "rva", "size", "share", "tag", "owner"}) +_SHA256_HEX = re.compile(r"[0-9a-f]{64}") +_RVA_HEX = re.compile(r"0x[0-9a-f]+") + + +def _strict_json_file(path, description): + """Read JSON that must not repeat a key; any defect fails closed.""" + def no_duplicates(pairs): + keys = [key for key, _ in pairs] + repeated = sorted({key for key in keys if keys.count(key) > 1}) + if repeated: + raise SemanticProgressError( + f"{description} repeats JSON key(s) {repeated}: {path}") + return dict(pairs) + + try: + text = Path(path).read_text(encoding="utf-8") + except (OSError, ValueError) as error: + raise SemanticProgressError( + f"cannot read {description} {path}: {error}") from error + try: + return json.loads(text, object_pairs_hook=no_duplicates) + except ValueError as error: + raise SemanticProgressError( + f"malformed {description} {path}: {error}") from error + + +def _lf_sha256(path, description): + try: + data = Path(path).read_bytes() + except OSError as error: + raise SemanticProgressError( + f"cannot read {description} {path}: {error}") from error + return hashlib.sha256(data.replace(b"\r\n", b"\n")).hexdigest() + + +def _pool_count(value, description, positive=False): + if isinstance(value, int) and not isinstance(value, bool) \ + and value >= (1 if positive else 0): + return value + raise SemanticProgressError( + f"malformed COMMON pool credit {description}: {value!r}") + + +def _pool_relative_path(value, description): + """A repository-relative POSIX path (never absolute, never '..').""" + if not _nonempty_string(value) or "\\" in value or value.startswith("/") \ + or ":" in value or ".." in value.split("/"): + raise SemanticProgressError( + f"COMMON pool credit {description} must be a repository-relative " + f"path: {value!r}") + return value + + +def _pool_pin(entry, key, fixed_path=None): + pin = entry[key] + if not isinstance(pin, dict) or set(pin) != _POOL_PIN_KEYS \ + or not isinstance(pin["sha256_lf"], str) \ + or not _SHA256_HEX.fullmatch(pin["sha256_lf"]): + raise SemanticProgressError( + f"COMMON pool credit {key} pin must be {{path, sha256_lf}} with a " + f"64-digit lowercase sha256: {pin!r}") + path = _pool_relative_path(pin["path"], f"{key} path") + if fixed_path is not None and path != fixed_path: + raise SemanticProgressError( + f"COMMON pool credit {key} path must be {fixed_path}: {path}") + return path, pin["sha256_lf"] + + +def _validate_pool_entry(entry): + if not isinstance(entry, dict) or set(entry) != _POOL_ENTRY_KEYS: + keys = sorted(entry) if isinstance(entry, dict) else entry + raise SemanticProgressError( + f"COMMON pool credit entry must have exactly the keys " + f"{sorted(_POOL_ENTRY_KEYS)}: {keys!r}") + if entry["schema"] != COMMON_POOL_CREDIT_SCHEMA: + raise SemanticProgressError( + f"COMMON pool credit schema {entry['schema']!r} != " + f"{COMMON_POOL_CREDIT_SCHEMA!r}") + for key in ("reason", "scope", "limitation", "unit", "category", + "xdk_lib_dir"): + if not _nonempty_string(entry[key]): + raise SemanticProgressError( + f"COMMON pool credit {key} must be a non-empty string") + if entry["extent_model"] != OBJDIFF_331_COMBINED_EXTENT: + raise SemanticProgressError( + f"unknown COMMON pool credit extent model " + f"{entry['extent_model']!r}") + _pool_count(entry["unit_total_data"], "unit_total_data") + for key in ("verifier", "reader", "ledger", "xdk_manifest"): + _pool_pin(entry, key, _POOL_FIXED_PIN_PATHS.get(key)) + absent = entry["linked_libraries_not_in_extract"] + if not isinstance(absent, list) or not all( + _nonempty_string(item) for item in absent): + raise SemanticProgressError( + "COMMON pool credit linked_libraries_not_in_extract must be a " + "list of library names") + credit = entry["credit"] + if not isinstance(credit, dict) or set(credit) != _POOL_CREDIT_KEYS: + raise SemanticProgressError( + f"COMMON pool credit totals must have exactly the keys " + f"{sorted(_POOL_CREDIT_KEYS)}: {credit!r}") + for key in sorted(_POOL_CREDIT_KEYS): + _pool_count(credit[key], f"credit {key}") + records = entry["records"] + if not isinstance(records, list) or not records: + raise SemanticProgressError("COMMON pool credit needs records") + symbols, rvas = set(), set() + for record in records: + if not isinstance(record, dict) or set(record) != _POOL_RECORD_KEYS: + raise SemanticProgressError( + f"COMMON pool credit record must have exactly the keys " + f"{sorted(_POOL_RECORD_KEYS)}: {record!r}") + symbol = record["symbol"] + if not _nonempty_string(symbol) or not isinstance(record["rva"], str) \ + or not _RVA_HEX.fullmatch(record["rva"]) \ + or not _nonempty_string(record["owner"]) \ + or not isinstance(record["tag"], str) \ + or record["tag"] not in COMMON_POOL_QUALIFYING_TAGS: + raise SemanticProgressError( + f"malformed COMMON pool credit record: {record!r}") + size = _pool_count(record["size"], f"size of {symbol}", positive=True) + if _pool_count(record["share"], f"share of {symbol}") < size: + raise SemanticProgressError( + f"COMMON pool credit share of {symbol} is below its size") + if symbol in symbols or record["rva"] in rvas: + raise SemanticProgressError( + f"COMMON pool credit lists a record twice: {symbol}") + symbols.add(symbol) + rvas.add(record["rva"]) + raw = sum(record["size"] for record in records) + total = sum(record["share"] for record in records) + if credit != {"records": len(records), "raw": raw, + "padding": total - raw, "total": total}: + raise SemanticProgressError( + f"COMMON pool credit totals do not add up: {credit!r} (records " + f"{len(records)}, raw {raw}, padding {total - raw}, total {total})") + + +def run_common_pool_verifier(project_root, argv, timeout=600): + """Run the reviewed verifier command line; return (status, stdout, stderr).""" + try: + process = subprocess.run( + [sys.executable, "-B", "-m", COMMON_POOL_VERIFIER_MODULE, *argv], + cwd=str(project_root), capture_output=True, text=True, + timeout=timeout, check=False) + except (OSError, subprocess.SubprocessError) as error: + raise SemanticProgressError( + f"COMMON pool verifier could not run: {error}") from error + return process.returncode, process.stdout, process.stderr + + +def _pool_side_symbols(path): + """Every unit and symbol that a semantic data entry names.""" + entries = _strict_json_file(path, "semantic data manifest") + if not isinstance(entries, list): + raise SemanticProgressError( + "semantic data manifest must be a list of entries") + units, symbols = set(), set() + for entry in entries: + if not isinstance(entry, dict): + raise SemanticProgressError( + "semantic data manifest entry must be an object") + units.add(entry.get("unit")) + if isinstance(entry.get("symbol"), str): + symbols.add(entry["symbol"]) + for key in ("members", "surplus"): + for item in entry.get(key) or []: + if isinstance(item, dict): + for name in ("symbol", "base_symbol"): + if isinstance(item.get(name), str): + symbols.add(item[name]) + return units, symbols + + +def _pool_reassigned_symbols(path, unit_name): + if not Path(path).is_file(): + return set() + manifest = _strict_json_file(path, "data category reassignment manifest") + if not isinstance(manifest, dict) \ + or not isinstance(manifest.get("entries"), list): + raise SemanticProgressError( + "data category reassignment manifest must have an entries list") + symbols = set() + for entry in manifest["entries"]: + if isinstance(entry, dict) and entry.get("unit") == unit_name: + for record in entry.get("records") or []: + if not isinstance(record, dict) \ + or not _nonempty_string(record.get("symbol")): + raise SemanticProgressError( + f"malformed data category reassignment record for " + f"{unit_name}") + symbols.add(record["symbol"]) + return symbols + + +def _pool_resolve(project_root, path): + path = Path(path) + return path if path.is_absolute() else Path(project_root) / path + + +def _loaded_reader_file(): + """The source file of the COFF reader this process computes the shares with. + + That is the file that defines the ``load`` this module calls (a reader + loaded from another place on sys.path names that place). It names the + source file even when Python ran a cached bytecode copy of it: pins bind + files, not the interpreter (limitation L1, trust root 8). + """ + filename = getattr(getattr(load, "__code__", None), "co_filename", None) + if not _nonempty_string(filename): + raise SemanticProgressError( + "cannot identify the COFF reader this process loaded") + return Path(filename) + + +def _plan_common_pool_credit(report, project_root, entry_path, + objdiff_config_path, semantic_data_matches_path, + reassignments_path, out_dir, run_verifier, + receipt): + """Verify everything; return the credit plan. Changes no measure.""" + entry = _strict_json_file(entry_path, "COMMON pool credit entry") + _validate_pool_entry(entry) + unit_name, category_id = entry["unit"], entry["category"] + receipt["entry"]["unit"] = unit_name + receipt["entry"]["category"] = category_id + # disclosures every receipt of a valid entry carries (OQ-DM1, the scope) + receipt["linked_libraries_not_in_extract"] = list( + entry["linked_libraries_not_in_extract"]) + receipt["scope"] = entry["scope"] + + # -- the unit: one MISSING split unit that objdiff cannot match -- + objdiff = _strict_json_file(objdiff_config_path, "objdiff configuration") + config_units = [unit for unit in objdiff.get("units", []) + if isinstance(unit, dict) and unit.get("name") == unit_name] + report_units = [unit for unit in report.get("units", []) + if unit.get("name") == unit_name] + if len(config_units) != 1 or len(report_units) != 1: + raise SemanticProgressError( + f"COMMON pool credit unit is not one objdiff and one report unit: " + f"{unit_name}") + config_unit, report_unit = config_units[0], report_units[0] + if "base_path" in config_unit or not _nonempty_string( + config_unit.get("target_path")): + raise SemanticProgressError( + f"COMMON pool credit unit must have a target and no rebuilt " + f"object: {unit_name}") + for unit, side in ((report_unit, "report"), (config_unit, "objdiff.json")): + if _unit_categories(unit, f"{unit_name} ({side})") != [category_id]: + raise SemanticProgressError( + f"COMMON pool credit unit is not solely in {category_id!r} " + f"({side}): {unit_name}") + if unit.get("metadata", {}).get("complete"): + raise SemanticProgressError( + f"COMMON pool credit unit is marked complete ({side}); a " + f"whole-pool Matching claim is not allowed: {unit_name}") + build_config = _strict_json_file( + Path(entry_path).parent / "config.json", "build configuration") + statuses = [obj.get("status") + for project in build_config.get("projects", []) + for obj in project.get("objects", []) + if isinstance(obj, dict) and isinstance(obj.get("name"), str) + and obj["name"].rsplit(".", 1)[0] == unit_name] + if statuses != ["MISSING"]: + raise SemanticProgressError( + f"COMMON pool credit unit must be one MISSING config object (no " + f"whole-pool Matching claim): {unit_name} {statuses}") + categories = {item["id"]: item for item in report.get("categories", [])} + if category_id not in categories: + raise SemanticProgressError( + f"progress category not found: {category_id}") + measures = report_unit.get("measures", {}) + unit_total = _report_count(measures.get("total_data", 0), + f"total_data for {unit_name}") + if unit_total != entry["unit_total_data"]: + raise SemanticProgressError( + f"COMMON pool credit unit total changed: {unit_name} (report " + f"{unit_total}, entry {entry['unit_total_data']})") + for key in ("matched_data", "complete_data", "complete_units"): + if _report_count(measures.get(key, 0), f"{key} for {unit_name}"): + raise SemanticProgressError( + f"COMMON pool credit needs a unit with no matched or complete " + f"data ({key}): {unit_name}") + + # -- no double counting with the other data entries -- + pinned = {record["symbol"]: record for record in entry["records"]} + if Path(semantic_data_matches_path).is_file(): + units, symbols = _pool_side_symbols(semantic_data_matches_path) + if unit_name in units: + raise SemanticProgressError( + f"COMMON pool credit unit also has a semantic data entry: " + f"{unit_name}") + both = sorted(set(pinned) & symbols) + if both: + raise SemanticProgressError( + f"COMMON pool credit record also named by a semantic data " + f"entry: {both[:8]}") + reassigned = _pool_reassigned_symbols(reassignments_path, unit_name) + both = sorted(set(pinned) & reassigned) + if both: + raise SemanticProgressError( + f"COMMON pool credit record was reassigned to another category: " + f"{both[:8]}") + + # -- pins, checked before the verifier runs -- + _, verifier_pin = _pool_pin(entry, "verifier", COMMON_POOL_VERIFIER_PATH) + _, reader_pin = _pool_pin(entry, "reader", COMMON_POOL_READER_PATH) + ledger_path, ledger_pin = _pool_pin(entry, "ledger") + manifest_path, manifest_pin = _pool_pin(entry, "xdk_manifest") + for key, path, pin in (("verifier", COMMON_POOL_VERIFIER_PATH, verifier_pin), + ("reader", COMMON_POOL_READER_PATH, reader_pin), + ("ledger", ledger_path, ledger_pin), + ("xdk_manifest", manifest_path, manifest_pin)): + actual = _lf_sha256(_pool_resolve(project_root, path), f"pinned {key}") + receipt["pins"][key] = {"path": path, "expected": pin, "actual": actual} + if actual != pin: + raise SemanticProgressError( + f"COMMON pool credit pin mismatch: {key} {path} LF sha256 " + f"{actual} != pinned {pin}") + # the reader this process loaded computes the shares: it must be the + # pinned reader too (by content; a copy elsewhere on sys.path that differs + # is refused) + loaded_reader = _loaded_reader_file() + loaded_sha = _lf_sha256(loaded_reader, "COFF reader this process loaded") + receipt["pins"]["reader"]["loaded_by_hook"] = { + "path": str(loaded_reader), "actual": loaded_sha} + if loaded_sha != reader_pin: + raise SemanticProgressError( + f"COMMON pool credit pin mismatch: the COFF reader this process " + f"loaded ({loaded_reader}) has LF sha256 {loaded_sha} != pinned " + f"{reader_pin}") + + # -- the reviewed verifier, run as its command line -- + target_path = _pool_resolve(project_root, config_unit["target_path"]) + names = {name: out_dir / name for name in _POOL_OUTPUT_FILES} + argv = ["--root", str(project_root), + "--config-dir", str(Path(entry_path).parent), + "--objects", str(out_dir.parent / "base"), + "--split-pool", str(target_path), + "--ledger", str(_pool_resolve(project_root, ledger_path)), + "--xdk-lib-dir", entry["xdk_lib_dir"], + "--xdk-lib-manifest", + str(_pool_resolve(project_root, manifest_path)), + "--receipt", str(names["verify_receipt.json"]), + "--json", str(names["verify_report.json"]), + "--text", str(names["verify_report.txt"])] + out_dir.mkdir(parents=True, exist_ok=True) + status, _stdout, stderr = run_verifier(project_root, argv) + receipt["verifier_run"] = {"argv": argv, "exit_code": status, + "stderr_tail": (stderr or "")[-2000:]} + verify_receipt = None + if names["verify_receipt.json"].is_file(): + verify_receipt = _strict_json_file( + names["verify_receipt.json"], "COMMON pool verifier receipt") + receipt["verifier_run"]["receipt_sha256"] = hashlib.sha256( + names["verify_receipt.json"].read_bytes()).hexdigest() + if status not in COMMON_POOL_COMPLETE_EXITS: + fail = verify_receipt.get("fail_closed") \ + if isinstance(verify_receipt, dict) else None + fail = fail if isinstance(fail, dict) else {} + raise SemanticProgressError( + f"COMMON pool verifier failed closed: exit {status} " + f"({fail.get('class', 'no receipt')}): " + f"{fail.get('message') or (stderr or '').strip()[-400:]}") + if verify_receipt is None or not names["verify_report.json"].is_file(): + raise SemanticProgressError( + f"COMMON pool verifier exited {status} without its receipt and " + f"report") + verify_report = _strict_json_file( + names["verify_report.json"], "COMMON pool verifier report") + receipt["verifier_run"]["report_sha256"] = hashlib.sha256( + names["verify_report.json"].read_bytes()).hexdigest() + + # -- the receipt binds the run to the pins and to this split pool -- + try: + target_bytes = target_path.read_bytes() + except OSError as error: + raise SemanticProgressError( + f"cannot read the COMMON pool split object {target_path}: {error}" + ) from error + target_sha = hashlib.sha256(target_bytes).hexdigest() + receipt["split_pool"] = {"path": config_unit["target_path"], + "sha256": target_sha} + try: + inputs = verify_receipt["inputs"] + libraries = verify_receipt["xdk_libraries"] + # the reader beside the verifier file that ran (None: it found none) + verifier_reader = verify_receipt["verifier"]["coff_compare_sha256_lf"] + receipt["pins"]["reader"]["verifier_receipt"] = verifier_reader + bound = { + "receipt schema": (verify_receipt["schema"], + COMMON_POOL_VERIFY_RECEIPT_SCHEMA), + "receipt exit code": (verify_receipt["exit_code"], status), + "receipt result": (verify_receipt["result"], "COMPLETE"), + "receipt fail_closed": (verify_receipt["fail_closed"], None), + "report exit code": (verify_report["exit_code"], status), + "report result": (verify_report["result"], "COMPLETE"), + "report receipt": (verify_report["receipt"], verify_receipt), + "verifier sha256_lf": (verify_receipt["verifier"]["sha256_lf"], + verifier_pin), + "reader sha256_lf": (verifier_reader, reader_pin), + "ledger sha256_lf": (inputs["ledger"]["sha256_lf"], ledger_pin), + "manifest sha256_lf": (inputs["xdk_manifest"]["sha256_lf"], + manifest_pin), + "split pool sha256": (inputs["split_pool"]["sha256"], target_sha), + "libraries not in the extract": ( + libraries["linked_not_in_extract"], + entry["linked_libraries_not_in_extract"]), + "global failures": (verify_report["global_failures"], []), + "conservation": ( + verify_report["accounting"]["conservation"]["holds"], True), + } + library_rows = libraries["libraries"] + unverified = sorted(name for name, row in library_rows.items() + if row.get("verified") is not True) + rows = verify_report["records"] + excluded = verify_report["excluded_linker_records"] + if not isinstance(rows, list) or not isinstance(excluded, list): + raise TypeError("records and excluded_linker_records must be lists") + except (KeyError, TypeError, AttributeError) as error: + raise SemanticProgressError( + f"malformed COMMON pool verifier receipt or report: " + f"{type(error).__name__}: {error}") from error + for name, (actual, expected) in bound.items(): + if actual != expected: + raise SemanticProgressError( + f"COMMON pool verifier run is not bound to the pins: {name} " + f"{str(actual)[:120]!r} != {str(expected)[:120]!r}") + if unverified or not library_rows: + raise SemanticProgressError( + f"COMMON pool verifier receipt has unverified libraries: " + f"{unverified[:8]}") + + # -- qualifying PASS records -- + by_name = {} + for row in rows: + if not isinstance(row, dict) or not _nonempty_string(row.get("name")) \ + or row["name"] in by_name: + raise SemanticProgressError( + "COMMON pool verifier report rows must name distinct records") + by_name[row["name"]] = row + + def qualifies(row): + return (row.get("verdict") == COMMON_POOL_QUALIFYING_VERDICT + and row.get("segment") == COMMON_POOL_HALO_SEGMENT + and row.get("category") == category_id + and row.get("tag") in COMMON_POOL_QUALIFYING_TAGS + and row.get("reasons") == []) + + for symbol, record in pinned.items(): + row = by_name.get(symbol) + if row is None or not qualifies(row): + raise SemanticProgressError( + f"COMMON pool credit record is not a qualifying PASS: {symbol} " + f"(verdict {None if row is None else row.get('verdict')}, " + f"segment {None if row is None else row.get('segment')}, " + f"reasons {None if row is None else row.get('reasons')})") + actual = {"rva": row.get("rva"), "size": row.get("size"), + "tag": row.get("tag"), "owner": row.get("owner")} + expected = {key: record[key] for key in actual} + if actual != expected: + raise SemanticProgressError( + f"COMMON pool credit record changed: {symbol} (verifier " + f"{actual}, entry {expected})") + unpinned = sorted(row["name"] for row in rows + if qualifies(row) and row["name"] not in pinned) + + # -- each record's objdiff-3.3.1-combined extent share -- + try: + target = load(target_bytes) + except CoffError as error: + raise SemanticProgressError( + f"cannot read the COMMON pool split object {target_path}: {error}" + ) from error + named = _objdiff_named_sections(target, unit_name) + _require_report_binding(named, report_unit, unit_name, "common-pool-credit") + shares = {} + for sections in _objdiff_report_data_groups(named).values(): + shares.update(_objdiff_report_shares(sections)) + sections = {int(section["index"]): section + for section in named["sections"]} + externals = {} + for item in target["symbols"]: + if int(item["section"]) > 0 \ + and int(item["storage"]) == _IMAGE_SYM_CLASS_EXTERNAL: + externals.setdefault(item["name"], []).append(item) + externals.setdefault(("section", int(item["section"])), []) \ + .append(item) + + def share_of(symbol): + definitions = externals.get(symbol, []) + if len(definitions) != 1 or int(definitions[0]["value"]) != 0: + raise SemanticProgressError( + f"COMMON pool record is not one external symbol at the start " + f"of its section: {symbol}") + number = int(definitions[0]["section"]) + if len(externals[("section", number)]) != 1 or number not in shares: + raise SemanticProgressError( + f"COMMON pool record does not own one reported data section: " + f"{symbol}") + return number, sections[number], shares[number] + + credited, seen_sections = [], set() + for symbol, record in pinned.items(): + number, section, share = share_of(symbol) + if number in seen_sections: + raise SemanticProgressError( + f"COMMON pool credit counts a section twice: {symbol}") + seen_sections.add(number) + if not int(section["flags"]) & IMAGE_SCN_CNT_UNINITIALIZED_DATA \ + or int(section["size"]) != record["size"] \ + or share != record["share"]: + raise SemanticProgressError( + f"COMMON pool credit record does not match the split object: " + f"{symbol} (section {section['name']} {section['size']} B, " + f"share {share}; entry {record['size']} B, share " + f"{record['share']})") + credited.append((symbol, record["tag"], record["size"], share)) + reassigned_share = sum(share_of(symbol)[2] for symbol in sorted(reassigned)) + total = sum(share for _, _, _, share in credited) + raw = sum(size for _, _, size, _ in credited) + if total != entry["credit"]["total"] or raw != entry["credit"]["raw"]: + raise SemanticProgressError( + f"COMMON pool credit totals changed: {total} ({raw} raw), entry " + f"{entry['credit']}") + if total > unit_total - reassigned_share: + raise SemanticProgressError( + f"COMMON pool credit {total} exceeds the unit's {category_id} " + f"share {unit_total - reassigned_share}") + for description, target_measures in ( + ("overall", report.get("measures", {})), + (category_id, categories[category_id]["measures"])): + matched = _report_count(target_measures.get("matched_data", 0), + f"{description} matched_data") + whole = _report_count(target_measures.get("total_data", 0), + f"{description} total_data") + if matched + total > whole: + raise SemanticProgressError( + f"COMMON pool credit would exceed the {description} data total") + + def tally(selected): + return [len(selected), sum(int(row.get("size", 0)) for row in selected)] + + halo_rows = [row for row in rows + if row.get("segment") == COMMON_POOL_HALO_SEGMENT] + by_tag = {} + for _, tag, size, share in credited: + item = by_tag.setdefault( + tag, {"records": 0, "raw": 0, "padding": 0, "share": 0}) + item["records"] += 1 + item["raw"] += size + item["padding"] += share - size + item["share"] += share + # the record that carries most of the credit, disclosed by name (Q10 + # additions: today _render, 643,744 of the 657,556 bytes) + symbol, tag, size, share = max(credited, key=lambda row: row[3]) + largest = {"symbol": symbol, "tag": tag, "raw": size, + "padding": share - size, "share": share} + return { + "unit": unit_name, "category": category_id, "report_unit": report_unit, + "credited": credited, "total": total, "raw": raw, "by_tag": by_tag, + "largest": largest, "unpinned": unpinned, + "uncredited": { + "halo_pass_owner_unresolved": tally( + [row for row in halo_rows + if row.get("verdict") == "PASS-OWNER-UNRESOLVED"]), + "halo_fail": tally([row for row in halo_rows + if row.get("verdict") == "FAIL"]), + "halo_pass_not_listed": tally( + [by_name[name] for name in unpinned]), + "vendor": tally([row for row in rows + if row.get("segment") == "vendor"]), + "linker_excluded": [len(excluded), sum( + int(item.get("size", 0)) for item in excluded)], + }, + } + + +def clear_common_pool_outputs(build_dir=Path("build"), project_root=None): + """Remove every output of an earlier COMMON pool credit run. + + calculate_progress calls this before its first step, so a progress run + that fails before apply_common_pool_credit (or never reaches it) leaves + no receipt that could be read as its own. Returns the output directory. + An output that cannot be removed fails closed: once the earlier receipt + is gone (it goes first) a FAIL-CLOSED receipt records the failure; + SemanticProgressError names the output either way. + """ + root = Path.cwd() if project_root is None else Path(project_root) + out_dir = _pool_resolve(root, build_dir) / COMMON_POOL_OUTPUT_DIR + receipt_path = out_dir / "credit_receipt.json" + for name in _POOL_OUTPUT_FILES: + try: + (out_dir / name).unlink() + except FileNotFoundError: + pass + except OSError as error: + message = (f"cannot remove the stale COMMON pool output {name}: " + f"{error}; it does not describe this run") + if name != "credit_receipt.json": + try: + _write_pool_receipt(receipt_path, { + "schema": COMMON_POOL_CREDIT_RECEIPT_SCHEMA, + "utc": datetime.datetime.now( + datetime.timezone.utc).isoformat( + timespec="seconds"), + "outcome": "FAIL-CLOSED", "reason": message, + "entry": None, "pins": {}, "verifier_run": None, + "split_pool": None, "credit": None, + "linked_libraries_not_in_extract": None, + "scope": None, "limitation": COMMON_POOL_L1, + "environment": COMMON_POOL_ENVIRONMENT}) + except SemanticProgressError as unwritable: + message = f"{message}; and {unwritable}" + raise SemanticProgressError(message) from error + return out_dir + + +def _write_pool_receipt(path, receipt): + try: + Path(path).parent.mkdir(parents=True, exist_ok=True) + Path(path).write_text(json.dumps(receipt, indent=1) + "\n", + encoding="utf-8") + except (OSError, ValueError) as error: + raise SemanticProgressError( + f"cannot write the COMMON pool credit receipt {path}: {error}" + ) from error + + +def apply_common_pool_credit(report, project_root, entry_path, + objdiff_config_path, semantic_data_matches_path, + reassignments_path, build_dir=Path("build"), + run_verifier=None): + """Credit the listed qualifying PASS Halo COMMON records (see above). + + Runs after apply_data_category_reassignments, which refuses a unit that + already has matched data. Returns note lines; raises + SemanticProgressError, with a FAIL-CLOSED receipt written, on any failure. + """ + project_root = Path(project_root) + entry_path = _pool_resolve(project_root, entry_path) + out_dir = _pool_resolve(project_root, build_dir) / COMMON_POOL_OUTPUT_DIR + receipt_path = out_dir / "credit_receipt.json" + # a previous run's receipt or report must never stand in for this one; a + # removal failure is receipted below whenever the receipt itself could be + # removed (it goes first), and the absent-entry path raises it too + try: + clear_common_pool_outputs(build_dir, project_root) + stale = None + except SemanticProgressError as error: + stale = error + if not entry_path.is_file(): + if stale is not None: + raise stale + return [] + receipt = { + "schema": COMMON_POOL_CREDIT_RECEIPT_SCHEMA, + "utc": datetime.datetime.now(datetime.timezone.utc).isoformat( + timespec="seconds"), + "outcome": None, "reason": None, + "entry": {"path": str(entry_path), "sha256_lf": None}, + "pins": {}, "verifier_run": None, "split_pool": None, "credit": None, + "linked_libraries_not_in_extract": None, "scope": None, + "limitation": COMMON_POOL_L1, "environment": COMMON_POOL_ENVIRONMENT, + } + try: + if stale is not None: + raise stale + receipt["entry"]["sha256_lf"] = _lf_sha256( + entry_path, "COMMON pool credit entry") + plan = _plan_common_pool_credit( + report, project_root, entry_path, + _pool_resolve(project_root, objdiff_config_path), + _pool_resolve(project_root, semantic_data_matches_path), + _pool_resolve(project_root, reassignments_path), out_dir, + run_verifier or run_common_pool_verifier, receipt) + except Exception as error: # deliberately total: every failure is receipted + message = (str(error) if isinstance(error, SemanticProgressError) + else f"unexpected {type(error).__name__}: {error}") + receipt.update(outcome="FAIL-CLOSED", reason=message) + try: + _write_pool_receipt(receipt_path, receipt) + except SemanticProgressError as unwritable: + # the failure itself must not be lost with its receipt + raise SemanticProgressError( + f"COMMON pool credit failed closed: {message}; and {unwritable}" + ) from error + raise SemanticProgressError( + f"COMMON pool credit failed closed: {message} (receipt " + f"{receipt_path})") from error + + total, raw = plan["total"], plan["raw"] + overall = report["measures"] + category = {item["id"]: item for item in report["categories"]}[ + plan["category"]]["measures"] + unit_measures = plan["report_unit"]["measures"] + before = {name: _report_count(measures.get("matched_data", 0), + f"{name} matched_data") + for name, measures in (("overall", overall), + ("category", category), + ("unit", unit_measures))} + receipt.update(outcome="CREDITED", credit={ + "records": len(plan["credited"]), "raw": raw, "padding": total - raw, + "total": total, "by_tag": plan["by_tag"], + "largest_record": plan["largest"], + "rows": [list(row) for row in plan["credited"]], + "uncredited": plan["uncredited"], "not_listed": plan["unpinned"], + "matched_data_before": before, + "matched_data_after": {name: value + total + for name, value in before.items()}, + }) + _write_pool_receipt(receipt_path, receipt) + _credit_data(overall, total) + _credit_data(category, total) + _credit_data(unit_measures, total) + # bytes by tag, raw versus padding, and the largest record's share + # (owner, Q10 additions) + tags = ", ".join( + f"{tag} {item['records']} records +{item['share']} ({item['raw']} raw " + f"+ {item['padding']} padding)" + for tag, item in sorted(plan["by_tag"].items())) + largest = plan["largest"] + uncredited = plan["uncredited"] + return [ + f"{plan['unit']}: +{total} {plan['category']} data bytes " + f"({len(plan['credited'])} PASS Halo records: {raw} raw + " + f"{total - raw} objdiff padding bytes); uncredited: " + f"{uncredited['halo_pass_owner_unresolved'][0]} " + f"PASS-OWNER-UNRESOLVED, {uncredited['halo_fail'][0]} FAIL, " + f"{uncredited['halo_pass_not_listed'][0]} unlisted PASS, " + f"{uncredited['vendor'][0]} vendor and " + f"{uncredited['linker_excluded'][0]} linker records; the unit stays " + f"MISSING (no Matching claim); receipt {receipt_path}", + f"{plan['unit']} by tag: {tags}; largest record {largest['symbol']} " + f"({largest['tag']}) +{largest['share']} ({largest['raw']} raw + " + f"{largest['padding']} padding) = " + f"{100.0 * largest['share'] / total:.1f}% of the credit"] diff --git a/tools/test_common_pool_credit.py b/tools/test_common_pool_credit.py new file mode 100644 index 00000000..dbbf708f --- /dev/null +++ b/tools/test_common_pool_credit.py @@ -0,0 +1,1237 @@ +"""Tests for apply_common_pool_credit (owner ruling Q10: pooled COMMON record data credit). + +Two groups: +- CommonPoolCreditTests: a synthetic pool unit and a fake verifier run (the verifier's own behaviour is covered by + tools/test_common_pool_verify.py); they cover the hook's pins, receipts, qualifying set, extent shares, the + no-double-counting guards and the no-Matching-claim guards. +- RealPoolCreditTests: the real verifier as its command line (a subprocess) on a copy of this tree's build, the pinned + entry and the XDK libraries it names; skipped when the build or the libraries are absent. They cover the credit the + entry pins and the verifier's fail-closed classes as progress sees them (pin mismatch, missing library directory, + a manifest other than the reviewed one, an unreadable object, a malformed ledger). +The reader-pin tests (Q10 addition a) cover a changed, missing or CR-damaged tools/coff_compare.py, a reader loaded +from elsewhere by this process, and (real tree) a reader substituted through sys.path in the verifier's process. +The disclosure tests (Q10 addition b) cover bytes by tag, raw versus padding and the largest record in progress, the +missing-library list, scope and environment sentence in every receipt, and (CommonPoolAllowlistTests) the frozen +Q10 FINAL allowlist and amount, and the EXT1 allowlist extension after it, in the real entry. +""" + +import copy +import hashlib +import importlib.util +import inspect +import json +import os +import shutil +import tempfile +import unittest +from pathlib import Path +from unittest import mock + +from tools import project_x86, semantic_progress +from tools.coff_compare import build_coff +from tools.semantic_progress import ( + COMMON_POOL_CREDIT_SCHEMA, + OBJDIFF_331_COMBINED_EXTENT, + SemanticProgressError, + apply_common_pool_credit, + apply_data_category_reassignments, + clear_common_pool_outputs, +) + +BSS_ALIGN1 = 0xC0100080 +BSS_ALIGN2 = 0xC0200080 +BSS_ALIGN4 = 0xC0300080 +BSS_ALIGN8 = 0xC0400080 +RDATA_DEFAULT = 0x40000040 + +VERIFIER = "tools/common_pool_verify.py" +READER = "tools/coff_compare.py" +LEDGER = "research/q10/ledger.json" +MANIFEST = "research/q10/manifest.json" +ENTRY = "config/common_pool_credit.json" +OUT = "build/common_pool" +ABSENT = ["binkxbox.lib", "dsstrmh.lib"] +# the reader this test process loaded, LF (the hook checks the reader it loaded by content, CRLF -> LF) +READER_BYTES = Path(semantic_progress.load.__code__.co_filename).read_bytes().replace(b"\r\n", b"\n") + + +def _lf_sha(data): + return hashlib.sha256(data.replace(b"\r\n", b"\n")).hexdigest() + + +def _load_reader_copy(path, data, name): + """Load *data* as a COFF reader module from *path* (a reader found elsewhere on sys.path).""" + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def _pool_object(section_changes=None, symbol_changes=None, extra_symbols=()): + """Five .bss records (shares 8/4/4/4/4 under the objdiff 3.3.1 model) and one .rdata linker record (28). + + The optional arguments change fields of a section (by 1-based number) or of a symbol (by name), or add symbols, + for the split-object shape checks.""" + sections = [ + {"name": ".bss", "size": 6, "flags": BSS_ALIGN8}, + {"name": ".bss", "size": 4, "flags": BSS_ALIGN4}, + {"name": ".bss", "size": 2, "flags": BSS_ALIGN2}, + {"name": ".bss", "size": 1, "flags": BSS_ALIGN1}, + {"name": ".bss", "size": 4, "flags": BSS_ALIGN4}, + {"name": ".rdata", "size": 28, "flags": RDATA_DEFAULT}, + ] + symbols = [ + {"name": "_halo_a", "section": 1}, + {"name": "_halo_b", "section": 2}, + {"name": "_halo_c", "section": 3}, + {"name": "_halo_d", "section": 4}, + {"name": "_vend_v", "section": 5}, + {"name": "_rd_l", "section": 6}, + {"name": "_undef", "section": 0}, + ] + for number, changes in (section_changes or {}).items(): + sections[number - 1].update(changes) + for symbol in symbols: + symbol.update((symbol_changes or {}).get(symbol["name"], {})) + symbols[-1:-1] = list(extra_symbols) + return build_coff(sections=sections, symbols=symbols) + + +def _row(index, name, rva, size, segment, category, tag, owner, verdict, reasons=()): + return {"pool_index": index, "name": name, "rva": rva, "size": size, "segment": segment, + "category": category, "tag": tag, "owner": owner, "verdict": verdict, + "reasons": list(reasons)} + + +def _report(): + """The progress report as the hook sees it: after the 38f82c59-style reassignment of _vend_v and _rd_l.""" + return { + "measures": {"total_data": 1000, "matched_data": 400, "complete_data": 100, + "matched_data_percent": 40.0}, + "categories": [ + {"id": "halo", "name": "halo", + "measures": {"total_data": 900, "matched_data": 300, "matched_data_percent": 100 / 3, + "complete_data": 100}}, + {"id": "vend", "name": "vend", + "measures": {"total_data": 72, "matched_data": 100 - 30, "matched_data_percent": 70 / 0.72}}, + {"id": "linker", "name": "linker", + "measures": {"total_data": 28, "matched_data": 0, "matched_data_percent": 0.0}}, + ], + "units": [ + {"name": "pool", "measures": {"total_data": "52"}, + "sections": [{"name": ".bss", "size": "24"}, {"name": ".rdata", "size": "28"}], + "metadata": {"progress_categories": ["halo"]}}, + {"name": "other", "measures": {"total_data": "8", "matched_data": "8"}, + "sections": [{"name": ".data", "size": "8"}], + "metadata": {"progress_categories": ["halo"]}}, + ], + } + + +class CommonPoolCreditTests(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.root = Path(self.tmp.name) + self._write(VERIFIER, b"# fixture verifier\n") + self._write(READER, READER_BYTES) + self._write(LEDGER, b'{"fixture": "ledger"}\n') + self._write(MANIFEST, b'{"fixture": "manifest"}\n') + self.target = _pool_object() + self._write("build/split/pool.obj", self.target) + self._json("objdiff.json", {"units": [ + {"name": "pool", "target_path": "build/split/pool.obj", + "metadata": {"progress_categories": ["halo"]}}, + {"name": "other", "target_path": "build/split/other.obj", "base_path": "build/base/other.obj", + "metadata": {"progress_categories": ["halo"]}}]}) + self._json("config/config.json", {"projects": [{"name": "halo", "objects": [ + {"name": "pool.c", "index": 1, "status": "MISSING"}, + {"name": "other.c", "index": 0, "status": "Matching"}]}]}) + self._json("config/semantic_data_matches.json", [ + {"unit": "other", "symbol": "_other_data", "measurements": {}}]) + self._json("config/data_category_reassignments.json", {"entries": [{"unit": "pool", "records": [ + {"symbol": "_vend_v", "section": ".bss", "size": 4, "to_category": "vend", "evidence": "fixture"}, + {"symbol": "_rd_l", "section": ".rdata", "size": 28, "to_category": "linker", + "evidence": "fixture"}]}]}) + self.entry = self._entry() + self.calls = [] + self.mutate = None + self.status = 1 + + def tearDown(self): + self.tmp.cleanup() + + # -- fixture helpers -------------------------------------------------------------------------------------- + + def _write(self, relative, data): + path = self.root / relative + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(data) + return path + + def _json(self, relative, value): + return self._write(relative, (json.dumps(value, indent=1) + "\n").encode("utf-8")) + + def _pin(self, relative): + return _lf_sha((self.root / relative).read_bytes()) + + def _entry(self): + return { + "schema": COMMON_POOL_CREDIT_SCHEMA, "unit": "pool", "category": "halo", + "extent_model": OBJDIFF_331_COMBINED_EXTENT, "unit_total_data": 52, + "verifier": {"path": VERIFIER, "sha256_lf": self._pin(VERIFIER)}, + "reader": {"path": READER, "sha256_lf": self._pin(READER)}, + "ledger": {"path": LEDGER, "sha256_lf": self._pin(LEDGER)}, + "xdk_manifest": {"path": MANIFEST, "sha256_lf": self._pin(MANIFEST)}, + "xdk_lib_dir": "C:/fixture/lib", "linked_libraries_not_in_extract": list(ABSENT), + "credit": {"records": 2, "raw": 10, "padding": 2, "total": 12}, + "reason": "fixture", "scope": "fixture scope", "limitation": "fixture L1", + "records": [ + {"symbol": "_halo_a", "rva": "0x100", "size": 6, "share": 8, "tag": "inferred", + "owner": "src/a.c"}, + {"symbol": "_halo_b", "rva": "0x108", "size": 4, "share": 4, "tag": "probable", + "owner": "src/b.c"}, + ], + } + + def _outputs(self, status): + receipt = { + "schema": "common-pool-verify-receipt/1", "exit_code": status, + "result": "COMPLETE" if status in (0, 1) else "FAIL-CLOSED", + "fail_closed": None if status in (0, 1) else { + "class": {2: "unreadable-input", 3: "libraries-missing-or-unverifiable", 4: "malformed-types", + 5: "ambiguous-classification"}[status], + "exit_code": status, "message": "fixture failure"}, + "verifier": {"path": VERIFIER, "sha256_lf": self._pin(VERIFIER), + "coff_compare_sha256_lf": self._pin(READER)}, + "inputs": {"ledger": {"sha256_lf": self._pin(LEDGER)}, + "xdk_manifest": {"sha256_lf": self._pin(MANIFEST)}, + "split_pool": {"sha256": hashlib.sha256( + (self.root / "build/split/pool.obj").read_bytes()).hexdigest()}}, + "xdk_libraries": {"libraries": {"a.lib": {"verified": True}, "b.lib": {"verified": True}}, + "linked_not_in_extract": list(ABSENT)}, + } + report = { + "result": receipt["result"], "exit_code": status, "global_failures": [], + "accounting": {"conservation": {"holds": True}}, + "records": [ + _row(0, "_halo_a", "0x100", 6, "halo", "halo", "inferred", "src/a.c", "PASS"), + _row(1, "_halo_b", "0x108", 4, "halo", "halo", "probable", "src/b.c", "PASS"), + _row(2, "_halo_c", "0x10c", 2, "halo", "halo", "unresolved", None, "PASS-OWNER-UNRESOLVED"), + _row(3, "_halo_d", "0x10e", 1, "halo", "halo", "probable", "src/d.c", "FAIL", + ["no-definer:absent"]), + _row(4, "_vend_v", "0x110", 4, "vendor", "vend", "probable", "vend/pool.obj", "FAIL", + ["no-definer:absent"]), + ], + "excluded_linker_records": [{"name": "_rd_l", "size": 28}], + } + return receipt, report + + def _runner(self, project_root, argv): + self.calls.append(list(argv)) + args = dict(zip(argv[::2], argv[1::2])) + receipt, report = self._outputs(self.status) + if self.mutate: + self.mutate(receipt, report) + report.setdefault("receipt", receipt) + if report.get("write", True) is not False: + report.pop("write", None) + Path(args["--json"]).write_text(json.dumps(report), encoding="utf-8") + if receipt.pop("write", True) is not False: + Path(args["--receipt"]).write_text(json.dumps(receipt), encoding="utf-8") + Path(args["--text"]).write_text("fixture text report\n", encoding="utf-8") + return self.status, "", "fixture stderr" + + def _run(self, report=None, entry=None, runner=None): + report = _report() if report is None else report + if entry is not False: + self._json(ENTRY, self.entry if entry is None else entry) + notes = apply_common_pool_credit( + report, self.root, ENTRY, "objdiff.json", "config/semantic_data_matches.json", + "config/data_category_reassignments.json", Path("build"), runner or self._runner) + return report, notes + + def _receipt(self): + return json.loads((self.root / OUT / "credit_receipt.json").read_text(encoding="utf-8")) + + def _fails(self, pattern, report=None, entry=None, runner=None): + report = _report() if report is None else report + before = copy.deepcopy(report) + with self.assertRaisesRegex(SemanticProgressError, pattern): + self._run(report, entry, runner) + self.assertEqual(report, before, "a failure must not change any measure") + receipt = self._receipt() + self.assertEqual(receipt["outcome"], "FAIL-CLOSED") + self.assertRegex(receipt["reason"], pattern) + self.assertIsNone(receipt["credit"]) + return receipt + + # -- the credit ------------------------------------------------------------------------------------------- + + def test_credits_exactly_the_listed_pass_shares(self): + report, notes = self._run() + before = _report() + self.assertEqual(report["measures"]["matched_data"], 400 + 12) + categories = {c["id"]: c["measures"] for c in report["categories"]} + self.assertEqual(categories["halo"]["matched_data"], 300 + 12) + self.assertAlmostEqual(categories["halo"]["matched_data_percent"], 100.0 * 312 / 900) + unit = report["units"][0]["measures"] + self.assertEqual(unit["matched_data"], 12) + # denominators, completion, vendor and linker categories, other units: untouched + self.assertEqual(report["measures"]["total_data"], 1000) + self.assertEqual(report["measures"]["complete_data"], 100) + self.assertEqual(categories["halo"]["total_data"], 900) + self.assertEqual(categories["halo"]["complete_data"], 100) + self.assertEqual(report["categories"][1:], before["categories"][1:]) + self.assertEqual(report["units"][1], before["units"][1]) + self.assertEqual(report["units"][0]["sections"], before["units"][0]["sections"]) + self.assertNotIn("complete_data", unit) + self.assertEqual(len(notes), 2) + self.assertIn("pool: +12 halo data bytes (2 PASS Halo records: 10 raw + 2 objdiff padding bytes); " + "uncredited: ", notes[0]) + self.assertIn("1 PASS-OWNER-UNRESOLVED, 1 FAIL, 0 unlisted PASS, 1 vendor and 1 linker records", + notes[0]) + self.assertIn("stays MISSING (no Matching claim)", notes[0]) + + def test_progress_shows_bytes_by_tag_raw_padding_and_the_largest_record(self): + # owner, Q10 additions: inferred/probable bytes, raw versus padding, and the largest record's share + _, notes = self._run() + self.assertEqual(notes[1], "pool by tag: inferred 1 records +8 (6 raw + 2 padding), probable 1 records +4 " + "(4 raw + 0 padding); largest record _halo_a (inferred) +8 (6 raw + 2 padding) " + "= 66.7% of the credit") + + def test_receipt_records_raw_padding_and_every_uncredited_class(self): + self._run() + receipt = self._receipt() + self.assertEqual(receipt["outcome"], "CREDITED") + credit = receipt["credit"] + self.assertEqual((credit["records"], credit["raw"], credit["padding"], credit["total"]), (2, 10, 2, 12)) + self.assertEqual(credit["by_tag"], {"inferred": {"records": 1, "raw": 6, "padding": 2, "share": 8}, + "probable": {"records": 1, "raw": 4, "padding": 0, "share": 4}}) + self.assertEqual(credit["largest_record"], {"symbol": "_halo_a", "tag": "inferred", "raw": 6, + "padding": 2, "share": 8}) + self.assertEqual(receipt["linked_libraries_not_in_extract"], ABSENT) + self.assertEqual(receipt["scope"], "fixture scope") + self.assertEqual(receipt["environment"], semantic_progress.COMMON_POOL_ENVIRONMENT) + self.assertTrue(receipt["environment"].startswith( + "Pins are not protection against a compromised execution environment.")) + self.assertEqual(credit["rows"], [["_halo_a", "inferred", 6, 8], ["_halo_b", "probable", 4, 4]]) + self.assertEqual(credit["uncredited"], { + "halo_pass_owner_unresolved": [1, 2], "halo_fail": [1, 1], "halo_pass_not_listed": [0, 0], + "vendor": [1, 4], "linker_excluded": [1, 28]}) + self.assertEqual(credit["matched_data_before"], {"overall": 400, "category": 300, "unit": 0}) + self.assertEqual(credit["matched_data_after"], {"overall": 412, "category": 312, "unit": 12}) + self.assertEqual(set(receipt["pins"]), {"verifier", "reader", "ledger", "xdk_manifest"}) + for pin in receipt["pins"].values(): + self.assertEqual(pin["expected"], pin["actual"]) + reader = receipt["pins"]["reader"] + self.assertEqual(reader["path"], READER) + self.assertEqual(reader["expected"], _lf_sha(READER_BYTES)) + self.assertEqual(reader["loaded_by_hook"]["actual"], reader["expected"]) + self.assertEqual(Path(reader["loaded_by_hook"]["path"]), Path(semantic_progress.load.__code__.co_filename)) + self.assertEqual(reader["verifier_receipt"], reader["expected"]) + self.assertEqual(receipt["verifier_run"]["exit_code"], 1) + self.assertIn("L1", receipt["limitation"]) + self.assertEqual(receipt["split_pool"]["sha256"], hashlib.sha256(self.target).hexdigest()) + + def test_runs_the_verifier_with_the_lib_dir_and_the_pinned_manifest(self): + self._run() + self.assertEqual(len(self.calls), 1) + args = dict(zip(self.calls[0][::2], self.calls[0][1::2])) + self.assertEqual(args["--xdk-lib-dir"], "C:/fixture/lib") + self.assertEqual(Path(args["--xdk-lib-manifest"]), self.root / MANIFEST) + self.assertEqual(Path(args["--ledger"]), self.root / LEDGER) + self.assertEqual(Path(args["--split-pool"]), self.root / "build/split/pool.obj") + self.assertEqual(Path(args["--objects"]), self.root / "build/base") + for key in ("--receipt", "--json", "--text"): + self.assertEqual(Path(args[key]).parent, self.root / OUT) + + def test_an_exit_0_run_credits_too(self): + self.status = 0 + report, _ = self._run() + self.assertEqual(report["measures"]["matched_data"], 412) + + def test_an_unlisted_pass_record_earns_nothing(self): + self.entry["records"] = self.entry["records"][:1] + self.entry["credit"] = {"records": 1, "raw": 6, "padding": 2, "total": 8} + report, notes = self._run() + self.assertEqual(report["measures"]["matched_data"], 408) + self.assertIn("1 unlisted PASS", notes[0]) + self.assertEqual(self._receipt()["credit"]["not_listed"], ["_halo_b"]) + + def test_a_vendor_pass_record_is_never_halo_credit(self): + def vendor_passes(receipt, report): + report["records"][4].update(verdict="PASS", reasons=[]) + self.mutate = vendor_passes + report, notes = self._run() + self.assertEqual(report["measures"]["matched_data"], 412) + self.assertIn("0 unlisted PASS, 1 vendor", notes[0]) + + def test_absent_entry_is_a_no_op_and_clears_stale_outputs(self): + self._write(OUT + "/credit_receipt.json", b'{"outcome": "CREDITED"}') + self._write(OUT + "/verify_receipt.json", b"{}") + report = _report() + report_out, notes = self._run(report=report, entry=False) + self.assertEqual(notes, []) + self.assertEqual(report_out, _report()) + self.assertFalse((self.root / OUT / "credit_receipt.json").exists()) + self.assertFalse((self.root / OUT / "verify_receipt.json").exists()) + self.assertEqual(self.calls, []) + + # -- fail closed: pins ---------------------------------------------------------------------------------- + + def test_verifier_pin_mismatch_fails_before_the_run(self): + self._write(VERIFIER, b"# a changed verifier\n") + receipt = self._fails(r"pin mismatch: verifier") + self.assertEqual(self.calls, []) + self.assertNotEqual(receipt["pins"]["verifier"]["expected"], receipt["pins"]["verifier"]["actual"]) + + def test_ledger_pin_mismatch_fails_before_the_run(self): + self._write(LEDGER, b'{"fixture": "edited ledger"}\n') + self._fails(r"pin mismatch: ledger") + self.assertEqual(self.calls, []) + + def test_manifest_pin_mismatch_fails_before_the_run(self): + self._write(MANIFEST, b'{"fixture": "another manifest"}\n') + self._fails(r"pin mismatch: xdk_manifest") + self.assertEqual(self.calls, []) + + # -- fail closed: the reader pin (Q10 addition a) ----------------------------------------------------------- + + def test_reader_pin_mismatch_fails_before_the_run(self): + self._write(READER, READER_BYTES + b"\n# a changed reader\n") + receipt = self._fails(r"pin mismatch: reader tools/coff_compare\.py") + self.assertEqual(self.calls, []) + self.assertNotEqual(receipt["pins"]["reader"]["expected"], receipt["pins"]["reader"]["actual"]) + self.assertIsNone(receipt["verifier_run"]) + + def test_a_missing_reader_fails_before_the_run(self): + (self.root / READER).unlink() + receipt = self._fails(r"cannot read pinned reader") + self.assertEqual(self.calls, []) + self.assertIsNone(receipt["verifier_run"]) + + def test_a_lone_cr_in_the_reader_is_a_pin_mismatch(self): + self._write(READER, READER_BYTES.replace(b"\n", b"\r", 1)) + self._fails(r"pin mismatch: reader") + self.assertEqual(self.calls, []) + + def test_a_changed_reader_loaded_by_this_process_fails_before_the_run(self): + # the tree's file is the pinned one, but the reader this process computes the shares with came from + # elsewhere (a regular 'tools' package earlier on sys.path, say) and differs + module = _load_reader_copy(self.root / "elsewhere" / "coff_compare.py", + READER_BYTES + b"\n# a changed reader\n", "q10_changed_reader") + with mock.patch.object(semantic_progress, "load", module.load): + receipt = self._fails(r"pin mismatch: the COFF reader this process loaded") + self.assertEqual(self.calls, []) + loaded = receipt["pins"]["reader"]["loaded_by_hook"] + self.assertEqual(Path(loaded["path"]), self.root / "elsewhere" / "coff_compare.py") + self.assertNotEqual(loaded["actual"], receipt["pins"]["reader"]["expected"]) + self.assertEqual(receipt["pins"]["reader"]["actual"], receipt["pins"]["reader"]["expected"]) + + def test_the_loaded_reader_is_checked_by_content_not_location(self): + module = _load_reader_copy(self.root / "elsewhere" / "coff_compare.py", READER_BYTES, + "q10_identical_reader") + with mock.patch.object(semantic_progress, "load", module.load): + report, _ = self._run() + self.assertEqual(report["measures"]["matched_data"], 412) + + def test_an_unidentifiable_loaded_reader_fails_closed(self): + with mock.patch.object(semantic_progress, "load", len): # a builtin names no source file + self._fails(r"cannot identify the COFF reader this process loaded") + self.assertEqual(self.calls, []) + + def test_receipt_must_name_the_pinned_reader(self): + receipt = self._bound_fails(r"not bound to the pins: reader sha256_lf", + lambda r, p: r["verifier"].update(coff_compare_sha256_lf="4" * 64)) + self.assertEqual(receipt["pins"]["reader"]["verifier_receipt"], "4" * 64) + + def test_a_verifier_that_found_no_reader_fails_closed(self): + self._bound_fails(r"not bound to the pins: reader sha256_lf", + lambda r, p: r["verifier"].update(coff_compare_sha256_lf=None)) + + def test_a_verifier_receipt_without_a_reader_hash_is_malformed(self): + self._bound_fails(r"malformed COMMON pool verifier receipt or report: KeyError", + lambda r, p: r["verifier"].pop("coff_compare_sha256_lf")) + + def test_a_crlf_checkout_of_the_pinned_files_passes(self): + for relative in (VERIFIER, READER, LEDGER, MANIFEST): + path = self.root / relative + path.write_bytes(path.read_bytes().replace(b"\n", b"\r\n")) + report, _ = self._run() + self.assertEqual(report["measures"]["matched_data"], 412) + + def test_missing_pinned_file_fails_closed(self): + (self.root / LEDGER).unlink() + self._fails(r"cannot read pinned ledger") + self.assertEqual(self.calls, []) + + # -- disclosures every receipt carries (Q10 addition b) ------------------------------------------------- + + def test_a_fail_closed_receipt_of_a_valid_entry_carries_the_disclosures(self): + self._write(LEDGER, b'{"fixture": "edited ledger"}\n') + receipt = self._fails(r"pin mismatch: ledger") + self.assertEqual(receipt["linked_libraries_not_in_extract"], ABSENT) + self.assertEqual(receipt["scope"], "fixture scope") + self.assertEqual(receipt["limitation"], semantic_progress.COMMON_POOL_L1) + self.assertEqual(receipt["environment"], semantic_progress.COMMON_POOL_ENVIRONMENT) + + def test_a_malformed_entry_leaves_the_entry_disclosures_empty(self): + self._write(ENTRY, b"{") + with self.assertRaisesRegex(SemanticProgressError, r"malformed COMMON pool credit entry"): + self._run(entry=False) + receipt = self._receipt() + self.assertEqual(receipt["outcome"], "FAIL-CLOSED") + self.assertIsNone(receipt["linked_libraries_not_in_extract"]) + self.assertIsNone(receipt["scope"]) + self.assertEqual(receipt["environment"], semantic_progress.COMMON_POOL_ENVIRONMENT) + + # -- fail closed: the verifier's own classes ------------------------------------------------------------ + + def test_every_fail_closed_verifier_exit_fails_progress(self): + for status, name in ((2, "unreadable-input"), (3, "libraries-missing-or-unverifiable"), + (4, "malformed-types"), (5, "ambiguous-classification")): + with self.subTest(status=status): + self.status = status + receipt = self._fails(rf"verifier failed closed: exit {status} \({name}\): fixture failure") + self.assertEqual(receipt["verifier_run"]["exit_code"], status) + + def test_a_crash_without_a_receipt_fails_closed(self): + self.status = 1 + + def crash(project_root, argv): + return 1, "", "Traceback (most recent call last): boom" + self._fails(r"exited 1 without its receipt and report", runner=crash) + + def test_an_unknown_exit_code_fails_closed(self): + # an exit status outside the verifier's contract, with a receipt that carries no class + def runner(project_root, argv): + args = dict(zip(argv[::2], argv[1::2])) + Path(args["--receipt"]).write_text("{}", encoding="utf-8") + return 7, "", "odd" + self._fails(r"verifier failed closed: exit 7 \(no receipt\)", runner=runner) + + def test_a_runner_exception_is_receipted(self): + def runner(project_root, argv): + raise RuntimeError("the interpreter vanished") + self._fails(r"unexpected RuntimeError: the interpreter vanished", runner=runner) + + # -- fail closed: the run must be bound to the pins and complete ---------------------------------------- + + def _bound_fails(self, pattern, mutate): + self.mutate = mutate + return self._fails(pattern) + + def test_receipt_exit_code_must_equal_the_process_status(self): + self._bound_fails(r"receipt exit code", lambda r, p: r.update(exit_code=0)) + + def test_receipt_must_name_the_pinned_verifier(self): + self._bound_fails(r"verifier sha256_lf", lambda r, p: r["verifier"].update(sha256_lf="0" * 64)) + + def test_receipt_must_name_the_pinned_ledger_and_manifest(self): + self._bound_fails(r"ledger sha256_lf", lambda r, p: r["inputs"]["ledger"].update(sha256_lf="1" * 64)) + self._bound_fails(r"manifest sha256_lf", + lambda r, p: r["inputs"]["xdk_manifest"].update(sha256_lf="2" * 64)) + + def test_receipt_must_name_the_split_pool_the_hook_reads(self): + self._bound_fails(r"split pool sha256", lambda r, p: r["inputs"]["split_pool"].update(sha256="3" * 64)) + + def test_report_must_embed_the_same_receipt(self): + self._bound_fails(r"report receipt", lambda r, p: p.update(receipt={"other": True})) + + def test_undisclosed_library_gap_fails_closed(self): + self._bound_fails(r"libraries not in the extract", + lambda r, p: r["xdk_libraries"].update(linked_not_in_extract=["binkxbox.lib"])) + + def test_unverified_library_fails_closed(self): + self._bound_fails(r"unverified libraries", + lambda r, p: r["xdk_libraries"]["libraries"]["b.lib"].update(verified=False)) + + def test_global_failures_fail_closed(self): + self._bound_fails(r"global failures", lambda r, p: p.update(global_failures=["surplus-common: _x"])) + + def test_broken_conservation_fails_closed(self): + self._bound_fails(r"conservation", lambda r, p: p["accounting"]["conservation"].update(holds=False)) + + def test_malformed_verifier_report_fails_closed(self): + self._bound_fails(r"malformed COMMON pool verifier receipt or report", + lambda r, p: p.pop("excluded_linker_records")) + + def test_verifier_report_that_is_not_json_fails_closed(self): + def runner(project_root, argv): + self._runner(project_root, argv) + args = dict(zip(argv[::2], argv[1::2])) + Path(args["--json"]).write_text("{not json", encoding="utf-8") + return 1, "", "" + self._fails(r"malformed COMMON pool verifier report", runner=runner) + + def test_duplicate_keys_in_the_verifier_receipt_fail_closed(self): + def runner(project_root, argv): + self._runner(project_root, argv) + args = dict(zip(argv[::2], argv[1::2])) + text = Path(args["--receipt"]).read_text(encoding="utf-8") + Path(args["--receipt"]).write_text(text[:-1] + ', "exit_code": 1}', encoding="utf-8") + return 1, "", "" + self._fails(r"repeats JSON key", runner=runner) + + # -- fail closed: the listed records -------------------------------------------------------------------- + + def test_listed_record_that_fails_now_fails_closed(self): + self._bound_fails(r"not a qualifying PASS: _halo_b", + lambda r, p: p["records"][1].update(verdict="FAIL", reasons=["no-definer:absent"])) + + def test_listed_record_that_became_owner_unresolved_fails_closed(self): + self._bound_fails(r"not a qualifying PASS: _halo_a", lambda r, p: p["records"][0].update( + verdict="PASS-OWNER-UNRESOLVED", tag="unresolved")) + + def test_a_non_pass_verdict_is_refused_even_without_reasons(self): + # an inconsistent report (verdict FAIL, no reasons, a qualifying tag) must not qualify + self._bound_fails(r"not a qualifying PASS: _halo_b", + lambda r, p: p["records"][1].update(verdict="FAIL", reasons=[])) + + def test_a_non_halo_segment_is_refused_even_in_the_halo_category(self): + # an inconsistent report (vendor segment, Halo category) must not qualify + self._bound_fails(r"not a qualifying PASS: _halo_b", + lambda r, p: p["records"][1].update(segment="vendor")) + + def test_listed_record_missing_from_the_run_fails_closed(self): + self._bound_fails(r"not a qualifying PASS: _halo_a", lambda r, p: p["records"].pop(0)) + + def test_listed_record_with_another_tag_owner_size_or_rva_fails_closed(self): + for key, value in (("tag", "inferred"), ("owner", "src/z.c"), ("size", 5), ("rva", "0x104")): + with self.subTest(key=key): + self._bound_fails(r"record changed: _halo_b", + lambda r, p, key=key, value=value: p["records"][1].update({key: value})) + + def test_a_pinned_unresolved_or_fail_record_is_rejected(self): + entry = self._entry() + entry["records"][1]["tag"] = "unresolved" + self._fails(r"malformed COMMON pool credit record", entry=entry) + entry = self._entry() + entry["records"].append({"symbol": "_halo_d", "rva": "0x10e", "size": 1, "share": 4, + "tag": "probable", "owner": "src/d.c"}) + entry["credit"] = {"records": 3, "raw": 11, "padding": 5, "total": 16} + self._fails(r"not a qualifying PASS: _halo_d", entry=entry) + + def test_a_wrong_share_fails_closed(self): + entry = self._entry() + entry["records"][0]["share"] = 6 + entry["credit"] = {"records": 2, "raw": 10, "padding": 0, "total": 10} + self._fails(r"does not match the split object: _halo_a", entry=entry) + + def test_a_record_the_split_object_does_not_define_fails_closed(self): + def ghost(receipt, report): + report["records"].append(_row(9, "_ghost", "0x200", 4, "halo", "halo", "inferred", "src/g.c", + "PASS")) + self.mutate = ghost + entry = self._entry() + entry["records"].append({"symbol": "_ghost", "rva": "0x200", "size": 4, "share": 4, "tag": "inferred", + "owner": "src/g.c"}) + entry["credit"] = {"records": 3, "raw": 14, "padding": 2, "total": 16} + self._fails(r"not one external symbol at the start of its section: _ghost", entry=entry) + + # -- fail closed: malformed entry ---------------------------------------------------------------------- + + def test_malformed_entries_fail_closed(self): + cases = [ + ("unknown key", lambda e: e.update(extra=1), r"exactly the keys"), + ("missing key", lambda e: e.pop("limitation"), r"exactly the keys"), + ("schema", lambda e: e.update(schema="common-pool-credit/0"), r"schema"), + ("model", lambda e: e.update(extent_model="objdiff-3.6.0"), r"extent model"), + ("empty reason", lambda e: e.update(reason=" "), r"reason must be"), + ("bool total", lambda e: e.update(unit_total_data=True), r"unit_total_data"), + ("short sha", lambda e: e["ledger"].update(sha256_lf="abc"), r"ledger pin"), + ("upper sha", lambda e: e["ledger"].update(sha256_lf="A" * 64), r"ledger pin"), + ("sha + newline", lambda e: e["ledger"].update(sha256_lf="a" * 64 + "\n"), r"ledger pin"), + ("rva + newline", lambda e: e["records"][0].update(rva="0x100\n"), + r"malformed COMMON pool credit record"), + ("absolute ledger", lambda e: e["ledger"].update(path="C:/ledger.json"), r"repository-relative"), + ("dotdot ledger", lambda e: e["ledger"].update(path="../ledger.json"), r"repository-relative"), + ("backslash", lambda e: e["xdk_manifest"].update(path="research\\q10\\manifest.json"), + r"repository-relative"), + ("verifier path", lambda e: e["verifier"].update(path="tools/other_verify.py"), + r"verifier path must be"), + ("reader path", lambda e: e["reader"].update(path="tools/other_reader.py"), + r"reader path must be tools/coff_compare\.py"), + ("no reader pin", lambda e: e.pop("reader"), r"exactly the keys"), + ("reader sha", lambda e: e["reader"].update(sha256_lf="B" * 64), r"reader pin"), + ("reader pin keys", lambda e: e["reader"].update(size=1), r"reader pin"), + ("empty scope", lambda e: e.update(scope=" "), r"scope must be"), + ("no scope", lambda e: e.pop("scope"), r"exactly the keys"), + ("absent not list", lambda e: e.update(linked_libraries_not_in_extract="binkxbox.lib"), + r"linked_libraries_not_in_extract"), + ("no records", lambda e: e.update(records=[]), r"needs records"), + ("record key", lambda e: e["records"][0].update(section=".bss"), r"record must have exactly"), + ("zero size", lambda e: e["records"][0].update(size=0), r"size of _halo_a"), + ("share < size", lambda e: e["records"][0].update(share=5), r"below its size"), + ("rva", lambda e: e["records"][0].update(rva="256"), r"malformed COMMON pool credit record"), + ("duplicate record", lambda e: e["records"].append(dict(e["records"][0])), r"lists a record twice"), + ("totals", lambda e: e["credit"].update(total=13), r"totals do not add up"), + ] + for name, change, pattern in cases: + with self.subTest(name=name): + entry = self._entry() + change(entry) + self._fails(pattern, entry=entry) + self.assertEqual(self.calls, [], "a malformed entry must stop before the verifier runs") + + def test_duplicate_keys_in_the_entry_fail_closed(self): + text = json.dumps(self.entry) + self._write(ENTRY, (text[:-1] + ', "unit": "pool"}').encode("utf-8")) + with self.assertRaisesRegex(SemanticProgressError, r"repeats JSON key"): + self._run(entry=False) + self.assertEqual(self._receipt()["outcome"], "FAIL-CLOSED") + + def test_entry_that_is_not_json_fails_closed(self): + self._write(ENTRY, b"{") + with self.assertRaisesRegex(SemanticProgressError, r"malformed COMMON pool credit entry"): + self._run(entry=False) + + # -- no double counting -------------------------------------------------------------------------------- + + def test_a_reassigned_vendor_record_can_never_be_listed(self): + entry = self._entry() + entry["records"].append({"symbol": "_vend_v", "rva": "0x110", "size": 4, "share": 4, + "tag": "probable", "owner": "vend/pool.obj"}) + entry["credit"] = {"records": 3, "raw": 14, "padding": 2, "total": 16} + self._fails(r"reassigned to another category: \['_vend_v'\]", entry=entry) + self.assertEqual(self.calls, []) + + def test_a_semantic_data_entry_for_the_unit_fails_closed(self): + self._json("config/semantic_data_matches.json", [{"unit": "pool", "symbol": "_other"}]) + self._fails(r"also has a semantic data entry: pool") + + def test_a_record_named_by_a_semantic_data_entry_fails_closed(self): + self._json("config/semantic_data_matches.json", [ + {"unit": "other", "group": "g", "members": [{"symbol": "_halo_b", "measurements": {}}]}]) + self._fails(r"also named by a semantic data entry: \['_halo_b'\]") + + def test_a_unit_with_matched_data_fails_closed(self): + report = _report() + report["units"][0]["measures"]["matched_data"] = "4" + self._fails(r"no matched or complete data \(matched_data\)", report=report) + + def test_the_hook_never_credits_twice(self): + report, _ = self._run() + credited = copy.deepcopy(report) + with self.assertRaisesRegex(SemanticProgressError, r"no matched or complete data"): + self._run(report=report) + self.assertEqual(report, credited) + self.assertEqual(report["measures"]["matched_data"], 412) + + def test_credit_beyond_the_category_total_fails_closed(self): + report = _report() + report["categories"][0]["measures"]["matched_data"] = 895 + self._fails(r"exceed the halo data total", report=report) + + def test_a_listed_record_later_reassigned_to_another_category_fails_closed(self): + # a record moved out of the Halo denominator can no longer earn Halo credit + self._json("config/data_category_reassignments.json", {"entries": [{"unit": "pool", "records": [ + {"symbol": "_halo_c"}, {"symbol": "_halo_d"}, {"symbol": "_vend_v"}, {"symbol": "_rd_l"}, + {"symbol": "_halo_b"}]}]}) + self._fails(r"reassigned to another category: \['_halo_b'\]") + + # -- no whole-pool Matching claim ---------------------------------------------------------------------- + + def test_a_complete_unit_is_refused(self): + report = _report() + report["units"][0]["metadata"]["complete"] = True + self._fails(r"marked complete \(report\)", report=report) + + def test_a_matching_config_status_is_refused(self): + self._json("config/config.json", {"projects": [{"name": "halo", "objects": [ + {"name": "pool.c", "index": 1, "status": "Matching"}]}]}) + self._fails(r"one MISSING config object") + + def test_a_rebuilt_object_for_the_unit_is_refused(self): + objdiff = json.loads((self.root / "objdiff.json").read_text(encoding="utf-8")) + objdiff["units"][0]["base_path"] = "build/base/pool.obj" + self._json("objdiff.json", objdiff) + self._fails(r"no rebuilt object") + + def test_a_unit_in_two_categories_is_refused(self): + report = _report() + report["units"][0]["metadata"]["progress_categories"] = ["halo", "vend"] + self._fails(r"not solely in 'halo'", report=report) + + def test_a_changed_unit_total_fails_closed(self): + entry = self._entry() + entry["unit_total_data"] = 53 + self._fails(r"unit total changed", entry=entry) + + def test_a_report_not_bound_to_the_split_object_fails_closed(self): + report = _report() + report["units"][0]["sections"][0]["size"] = "20" + self._fails(r"not the target's modelled extent", report=report) + + def test_a_credit_never_moves_completion_or_denominators(self): + report, _ = self._run() + before = _report() + for key in ("total_data", "complete_data"): + self.assertEqual(report["measures"][key], before["measures"][key]) + self.assertEqual(report["categories"][0]["measures"][key], before["categories"][0]["measures"][key]) + self.assertNotIn("complete", report["units"][0]["metadata"]) + + # -- receipts ------------------------------------------------------------------------------------------ + + def test_an_unwritable_receipt_fails_closed_without_credit(self): + self._write("build/common_pool", b"a file where the output directory should be") + report = _report() + before = copy.deepcopy(report) + with self.assertRaisesRegex(SemanticProgressError, + r"failed closed: unexpected FileExistsError.*; and cannot write the " + r"COMMON pool credit receipt"): + self._run(report=report) + self.assertEqual(report, before) + + def test_a_stale_receipt_never_survives_a_failed_run(self): + self._run() + self.assertEqual(self._receipt()["outcome"], "CREDITED") + self._write(LEDGER, b'{"fixture": "edited"}\n') + self._fails(r"pin mismatch: ledger") + self.assertFalse((self.root / OUT / "verify_receipt.json").exists()) + self.assertFalse((self.root / OUT / "verify_report.json").exists()) + + # -- RF-EI v1.4: stale outputs (D1) -------------------------------------------------------------------- + + def _block(self, name): + """Replace an output of the previous (credited) run by a directory, which no unlink can remove.""" + blocker = self.root / OUT / name + blocker.unlink() + blocker.mkdir() + return blocker + + def test_an_unremovable_verifier_output_is_receipted_and_the_old_receipt_is_gone(self): + self._run() + self._block("verify_receipt.json") + receipt = self._fails(r"cannot remove the stale COMMON pool output verify_receipt\.json") + self.assertIsNone(receipt["verifier_run"]) + self.assertEqual(len(self.calls), 1, "the verifier must not run after a stale-output failure") + + def test_an_unremovable_receipt_fails_closed_and_says_it_is_stale(self): + self._run() + self._block("credit_receipt.json") + report = _report() + before = copy.deepcopy(report) + with self.assertRaisesRegex(SemanticProgressError, + r"cannot remove the stale COMMON pool output credit_receipt\.json: .*does not " + r"describe this run; and cannot write the COMMON pool credit receipt"): + self._run(report=report) + self.assertEqual(report, before) + self.assertEqual(len(self.calls), 1) + + def test_the_absent_entry_path_still_fails_on_an_unremovable_output(self): + self._run() + (self.root / ENTRY).unlink() + self._block("verify_report.json") + with self.assertRaisesRegex(SemanticProgressError, + r"cannot remove the stale COMMON pool output verify_report\.json"): + self._run(entry=False) + receipt = self._receipt() + self.assertEqual(receipt["outcome"], "FAIL-CLOSED") + self.assertRegex(receipt["reason"], r"verify_report\.json: .*does not describe this run") + + def test_clear_records_an_unremovable_verifier_output_in_a_fail_closed_receipt(self): + self._run() + self._block("verify_report.txt") + with self.assertRaisesRegex(SemanticProgressError, + r"cannot remove the stale COMMON pool output verify_report\.txt: .*does not " + r"describe this run"): + clear_common_pool_outputs(Path("build"), self.root) + receipt = self._receipt() + self.assertEqual(receipt["outcome"], "FAIL-CLOSED") + self.assertIsNone(receipt["credit"]) + self.assertEqual(receipt["limitation"], "L1: pinning prevents unnoticed changes to reviewed assumptions; it " + "does not prove those assumptions or January ownership.") + # the same receipt schema as the hook's own (Q10 addition b) + self.assertEqual(receipt["environment"], semantic_progress.COMMON_POOL_ENVIRONMENT) + self.assertIsNone(receipt["scope"]) + self.assertIsNone(receipt["linked_libraries_not_in_extract"]) + + def test_clear_common_pool_outputs_removes_exactly_the_four_outputs(self): + out = self.root / OUT + out.mkdir(parents=True) + for name in ("credit_receipt.json", "verify_receipt.json", "verify_report.json", "verify_report.txt", + "unrelated.txt"): + (out / name).write_text("x", encoding="utf-8") + self.assertEqual(clear_common_pool_outputs(Path("build"), self.root), out) + self.assertEqual(sorted(path.name for path in out.iterdir()), ["unrelated.txt"]) + + def test_the_credit_receipt_is_written_before_any_measure_changes(self): + from tools import semantic_progress + original = semantic_progress._write_pool_receipt + + def refuse_credited(path, receipt): + if receipt.get("outcome") == "CREDITED": + raise SemanticProgressError("cannot write the COMMON pool credit receipt (fixture)") + original(path, receipt) + report = _report() + before = copy.deepcopy(report) + with mock.patch.object(semantic_progress, "_write_pool_receipt", refuse_credited): + with self.assertRaisesRegex(SemanticProgressError, r"credit receipt \(fixture\)"): + self._run(report=report) + self.assertEqual(report, before) + + # -- RF-EI v1.4: pins, inconsistent verifier output and split-object shape (D2) ------------------------ + + def test_a_lone_cr_in_a_pinned_file_is_a_pin_mismatch(self): + # only CRLF -> LF is normalised; a CR that is not a line end changes the pinned content + self._write(LEDGER, b'{\r"fixture": "ledger"}\n') + self._fails(r"pin mismatch: ledger") + self.assertEqual(self.calls, []) + + def test_inconsistent_receipt_or_report_fields_are_refused(self): + cases = ( + (r"receipt result", lambda r, p: r.update(result="FAIL-CLOSED")), + (r"receipt fail_closed", lambda r, p: r.update(fail_closed={"class": "unreadable-input"})), + (r"receipt schema", lambda r, p: r.update(schema="common-pool-verify-receipt/2")), + (r"report result", lambda r, p: p.update(result="FAIL-CLOSED")), + (r"report exit code", lambda r, p: p.update(exit_code=0)), + (r"unverified libraries", lambda r, p: r["xdk_libraries"].update(libraries={})), + (r"rows must name distinct records", lambda r, p: p["records"].append(dict(p["records"][0]))), + (r"not a qualifying PASS: _halo_a", lambda r, p: p["records"][0].update(reasons=["no-definer:absent"])), + (r"not a qualifying PASS: _halo_a", lambda r, p: p["records"][0].update(category="vend")), + ) + for pattern, mutate in cases: + with self.subTest(pattern=pattern): + self._bound_fails(pattern, mutate) + + def test_split_objects_outside_the_one_record_per_section_shape_are_refused(self): + cases = ( + ("symbol not at offset 0", {"symbol_changes": {"_halo_a": {"value": 4}}}, + r"not one external symbol at the start of its section: _halo_a"), + ("two externals in one section", {"extra_symbols": [{"name": "_halo_x", "section": 1, "value": 2}]}, + r"does not own one reported data section: _halo_a"), + ("initialised data section", {"section_changes": {1: {"flags": 0xC0400040}}}, + r"does not match the split object: _halo_a"), + ("split size differs, same share", {"section_changes": {1: {"size": 5}}}, + r"does not match the split object: _halo_a"), + ) + for name, variant, pattern in cases: + with self.subTest(name=name): + self._write("build/split/pool.obj", _pool_object(**variant)) + self._fails(pattern) + self._write("build/split/pool.obj", self.target) + + +class CommonPoolWiringTests(unittest.TestCase): + """RF-EI v1.4: the progress wiring (tools/project_x86.py) that the hook tests cannot see.""" + + def test_progress_clears_first_and_credits_once_after_the_reassignment(self): + source = inspect.getsource(project_x86.calculate_progress) + order = [source.index(name + "(") for name in ( + "clear_common_pool_outputs", "apply_data_category_reassignments", "apply_common_pool_credit")] + self.assertEqual(order, sorted(order)) + self.assertEqual(source.count("apply_common_pool_credit("), 1) + + def test_the_progress_edge_does_not_depend_on_the_entry_or_the_verifier(self): + source = inspect.getsource(project_x86.generate_build_ninja) + edge = source[source.index('outputs="progress"'):] + edge = edge[:edge.index("n.newline()")] + for name in ('"common_pool_credit.json"', '"common_pool_verify.py"'): + self.assertNotIn(name, edge) + + def test_progress_prints_every_credit_note(self): + # Q10 addition b: the credit is two notes (the total, then bytes by tag and the largest record); progress + # must print each one (RF-EK mutation K20: printing only the first survived every other test) + source = inspect.getsource(project_x86.calculate_progress) + self.assertIn(" for common_pool_credit in common_pool_credits:\n", source) + + +ROOT = Path(__file__).resolve().parents[1] +REAL_ENTRY = ROOT / ENTRY + +# Owner ruling Q10 FINAL (2026-09-28): the reviewed 85-record allowlist is frozen. Records that pass later earn nothing +# until a separate approval lists them; changing the list or the amount is a reviewed change to this test as well as to +# the entry. The frozen 85 stay the first 85 entry records, unchanged. +Q10_FINAL_ALLOWLIST_SHA256 = "62b51a00121e7445f836c4b453f15d9feb50f6b728beb09d657b487c639a943f" +# Allowlist extension EXT1 (separate owner approval; RF-EV PACKET_ALLOWLIST_EXT.md): exactly these records follow the +# frozen 85, in pool order, and nothing else is listed. +Q10_EXT1_SYMBOLS = ("_sound_class_data", "_debug_sound_cache", "_assertion_count", "_debug_sound_reference_counts", + "_wind_globals", "_build_sprite_globals", "_light_data", "_glow_globals") +Q10_EXT1_RECORDS_SHA256 = "9d7655b062d93139a91fae1402e217cb3df999ef9b9c1b0d89f5de684027828f" +# Qualifying PASS records that stay unlisted by their own rulings: +# - _debug_sound_channels (Q-B2: "Keep it outside Q10's credit allowlist") +# - _director_camera_scripted (B7: "remain outside the Q10 allowlist") +Q10_UNLISTED_BY_RULING = ("_debug_sound_channels", "_director_camera_scripted") + + +def _canonical_sha256(records): + return hashlib.sha256(json.dumps(records, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest() + + +def _by_tag(records): + by_tag = {} + for record in records: + item = by_tag.setdefault(record["tag"], [0, 0, 0]) + item[0] += 1 + item[1] += record["size"] + item[2] += record["share"] + return by_tag + + +@unittest.skipIf(not REAL_ENTRY.is_file(), "no config/common_pool_credit.json") +class CommonPoolAllowlistTests(unittest.TestCase): + """The entry lists exactly the approved allowlist and amount (Q10 FINAL, then EXT1); no build is needed.""" + + def setUp(self): + self.entry = json.loads(REAL_ENTRY.read_text(encoding="utf-8")) + self.records = self.entry["records"] + + def test_the_first_85_records_are_the_frozen_q10_final_allowlist(self): + final = self.records[:85] + self.assertEqual(_canonical_sha256(final), Q10_FINAL_ALLOWLIST_SHA256) + self.assertEqual(_by_tag(final), {"inferred": [60, 8220, 8444], "probable": [25, 649025, 649112]}) + self.assertEqual((len(final), sum(r["size"] for r in final), sum(r["share"] for r in final)), + (85, 657245, 657556)) + + def test_ext1_lists_exactly_the_approved_records_after_them(self): + extension = self.records[85:] + self.assertEqual(tuple(record["symbol"] for record in extension), Q10_EXT1_SYMBOLS) + self.assertEqual(_canonical_sha256(extension), Q10_EXT1_RECORDS_SHA256) + self.assertEqual(_by_tag(extension), {"inferred": [4, 3392, 3440], "probable": [4, 8, 16]}) + + def test_the_entry_amount_and_disclosures(self): + entry, records = self.entry, self.records + self.assertEqual(entry["credit"], {"records": 93, "raw": 660645, "padding": 367, "total": 661012}) + self.assertEqual(_by_tag(records), {"inferred": [64, 11612, 11884], "probable": [29, 649033, 649128]}) + largest = max(records, key=lambda record: record["share"]) + self.assertEqual((largest["symbol"], largest["tag"], largest["size"], largest["share"]), + ("_render", "probable", 643732, 643744)) + listed = {record["symbol"] for record in records} + self.assertEqual(sorted(listed & set(Q10_UNLISTED_BY_RULING)), []) + self.assertEqual(entry["linked_libraries_not_in_extract"], ["binkxbox.lib", "dsstrmh.lib"]) + self.assertEqual(entry["scope"], "This lifts Q10 only for those 85 records and the 8 records of allowlist " + "extension EXT1 under this verification contract. It does not certify " + "January ownership, complete pool layout, or a matching executable link.") + + +def _real_prerequisites(): + if not REAL_ENTRY.is_file(): + return "no config/common_pool_credit.json" + for relative in ("build/report.json", "build/base", "build/split/source/linker_common.obj", "objdiff.json"): + if not (ROOT / relative).exists(): + return f"no {relative} (build first)" + entry = json.loads(REAL_ENTRY.read_text(encoding="utf-8")) + if not Path(entry["xdk_lib_dir"]).is_dir(): + return f"XDK library directory {entry['xdk_lib_dir']} is absent" + return None + + +def _convert_numbers(report): + for measures in [report["measures"]] + [c["measures"] for c in report.get("categories", [])]: + for key, value in list(measures.items()): + if isinstance(value, str) and value.isdigit(): + measures[key] = int(value) + return report + + +@unittest.skipIf(_real_prerequisites(), _real_prerequisites() or "") +class RealPoolCreditTests(unittest.TestCase): + """The real verifier (subprocess) on a private copy of this tree's build and pinned inputs.""" + + @classmethod + def setUpClass(cls): + cls.tmp = tempfile.TemporaryDirectory() + cls.mini = Path(cls.tmp.name) + cls.entry = json.loads(REAL_ENTRY.read_text(encoding="utf-8")) + (cls.mini / "tools").mkdir() + for name in ("common_pool_verify.py", "coff_compare.py"): + shutil.copy2(ROOT / "tools" / name, cls.mini / "tools" / name) + shutil.copytree(ROOT / "config", cls.mini / "config", + ignore=lambda d, names: [n for n in names if not n.endswith(".json")]) + for key in ("ledger", "xdk_manifest"): + target = cls.mini / cls.entry[key]["path"] + target.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(ROOT / cls.entry[key]["path"], target) + (cls.mini / "build").mkdir() + shutil.copytree(ROOT / "build" / "base", cls.mini / "build" / "base") + shutil.copytree(ROOT / "build" / "split", cls.mini / "build" / "split") + shutil.copy2(ROOT / "objdiff.json", cls.mini / "objdiff.json") + cls.report_text = (ROOT / "build" / "report.json").read_text(encoding="utf-8") + cls.pristine = {} + for relative in (ENTRY, cls.entry["ledger"]["path"], cls.entry["xdk_manifest"]["path"], READER): + cls.pristine[relative] = (cls.mini / relative).read_bytes() + + @classmethod + def tearDownClass(cls): + cls.tmp.cleanup() + + def setUp(self): + for relative, data in self.pristine.items(): + (self.mini / relative).write_bytes(data) + self.restore = [] + + def tearDown(self): + for path, data in self.restore: + path.write_bytes(data) + + def _report(self): + report = _convert_numbers(json.loads(self.report_text)) + apply_data_category_reassignments(report, self.mini, self.mini / "config/data_category_reassignments.json", + self.mini / "objdiff.json") + return report + + def _run(self, report): + return apply_common_pool_credit( + report, self.mini, ENTRY, "objdiff.json", "config/semantic_data_matches.json", + "config/data_category_reassignments.json", Path("build")) + + def _write_entry(self, entry): + (self.mini / ENTRY).write_text(json.dumps(entry, indent=2) + "\n", encoding="utf-8") + + def _receipts(self): + out = self.mini / OUT + credit = json.loads((out / "credit_receipt.json").read_text(encoding="utf-8")) + verify = out / "verify_receipt.json" + return credit, (json.loads(verify.read_text(encoding="utf-8")) if verify.is_file() else None) + + def _fails(self, pattern): + report = self._report() + before = copy.deepcopy(report) + with self.assertRaisesRegex(SemanticProgressError, pattern): + self._run(report) + self.assertEqual(report, before) + credit, verify = self._receipts() + self.assertEqual(credit["outcome"], "FAIL-CLOSED") + return credit, verify + + def test_real_pool_credit_equals_the_entry(self): + report = self._report() + before = copy.deepcopy(report) + notes = self._run(report) + total = self.entry["credit"]["total"] + self.assertEqual(report["measures"]["matched_data"], before["measures"]["matched_data"] + total) + self.assertEqual(report["measures"]["total_data"], before["measures"]["total_data"]) + after = {c["id"]: c["measures"] for c in report["categories"]} + prior = {c["id"]: c["measures"] for c in before["categories"]} + halo = self.entry["category"] + self.assertEqual(after[halo]["matched_data"], prior[halo]["matched_data"] + total) + for category_id in after: + self.assertEqual(after[category_id]["total_data"], prior[category_id]["total_data"]) + if category_id != halo: + self.assertEqual(after[category_id], prior[category_id]) + credit, verify = self._receipts() + self.assertEqual(credit["outcome"], "CREDITED") + self.assertEqual([credit["credit"][k] for k in ("records", "raw", "padding", "total")], + [self.entry["credit"][k] for k in ("records", "raw", "padding", "total")]) + self.assertIn(verify["exit_code"], (0, 1)) + self.assertEqual(verify["result"], "COMPLETE") + self.assertIn(f"+{total} {halo} data bytes", notes[0]) + # the reader pin: the tree's file, the reader this process loaded and the verifier's reader agree + pin = self.entry["reader"]["sha256_lf"] + reader = credit["pins"]["reader"] + self.assertEqual((reader["expected"], reader["actual"], reader["loaded_by_hook"]["actual"], + reader["verifier_receipt"]), (pin, pin, pin, pin)) + self.assertEqual(verify["verifier"]["coff_compare_sha256_lf"], pin) + self.assertEqual(_lf_sha((ROOT / READER).read_bytes()), pin) + # bytes by tag and the largest record, as the entry lists them (Q10 addition b) + by_tag = {} + for record in self.entry["records"]: + item = by_tag.setdefault(record["tag"], [0, 0, 0]) + item[0] += 1 + item[1] += record["share"] + item[2] += record["size"] + tags = ", ".join(f"{tag} {n} records +{share} ({raw} raw + {share - raw} padding)" + for tag, (n, share, raw) in sorted(by_tag.items())) + largest = max(self.entry["records"], key=lambda record: record["share"]) + self.assertEqual(notes[1], f"{self.entry['unit']} by tag: {tags}; largest record {largest['symbol']} " + f"({largest['tag']}) +{largest['share']} ({largest['size']} raw + " + f"{largest['share'] - largest['size']} padding) = " + f"{100.0 * largest['share'] / total:.1f}% of the credit") + self.assertEqual(credit["linked_libraries_not_in_extract"], self.entry["linked_libraries_not_in_extract"]) + self.assertEqual(credit["linked_libraries_not_in_extract"], verify["xdk_libraries"]["linked_not_in_extract"]) + self.assertEqual(credit["linked_libraries_not_in_extract"], ["binkxbox.lib", "dsstrmh.lib"]) + self.assertEqual(credit["scope"], self.entry["scope"]) + + def test_hook_pin_mismatch_stops_before_the_verifier(self): + path = self.mini / self.entry["ledger"]["path"] + path.write_bytes(path.read_bytes() + b" ") + credit, verify = self._fails(r"pin mismatch: ledger") + self.assertIsNone(verify) + self.assertIsNone(credit["verifier_run"]) + + def test_a_changed_reader_stops_before_the_verifier(self): + path = self.mini / READER + path.write_bytes(path.read_bytes() + b"\n# a changed reader\n") + credit, verify = self._fails(r"pin mismatch: reader tools/coff_compare\.py") + self.assertIsNone(verify) + self.assertIsNone(credit["verifier_run"]) + + def test_a_missing_reader_stops_before_the_verifier(self): + (self.mini / READER).unlink() + credit, verify = self._fails(r"cannot read pinned reader") + self.assertIsNone(verify) + self.assertIsNone(credit["verifier_run"]) + + def test_a_reader_substituted_through_sys_path_in_the_verifier_fails_closed(self): + # A regular 'tools' package anywhere on the search path takes precedence over the tree's namespace package + # for `python -B -m tools.common_pool_verify`. Here it holds a byte-identical verifier and a changed reader: + # every file the hook hashes is the pinned one, and only the verifier receipt's reader hash shows the swap. + substitute = self.mini / "substitute" + package = substitute / "tools" + package.mkdir(parents=True) + (package / "__init__.py").write_bytes(b"") + shutil.copy2(self.mini / VERIFIER, package / "common_pool_verify.py") + changed = (self.mini / READER).read_bytes() + b"\n# a substituted reader\n" + (package / "coff_compare.py").write_bytes(changed) + try: + with mock.patch.dict(os.environ, {"PYTHONPATH": str(substitute)}): + credit, verify = self._fails(r"not bound to the pins: reader sha256_lf") + finally: + shutil.rmtree(substitute) + self.assertEqual(verify["verifier"]["coff_compare_sha256_lf"], _lf_sha(changed)) + self.assertEqual(verify["verifier"]["sha256_lf"], self.entry["verifier"]["sha256_lf"]) + self.assertEqual(credit["pins"]["reader"]["verifier_receipt"], _lf_sha(changed)) + self.assertEqual(credit["pins"]["reader"]["actual"], self.entry["reader"]["sha256_lf"]) + + def test_missing_xdk_lib_dir_fails_closed(self): + entry = copy.deepcopy(self.entry) + entry["xdk_lib_dir"] = str(self.mini / "no_such_xdk_lib_dir") + self._write_entry(entry) + credit, verify = self._fails(r"exit 3 \(libraries-missing-or-unverifiable\)") + self.assertEqual(verify["exit_code"], 3) + self.assertEqual(credit["verifier_run"]["exit_code"], 3) + + def test_a_manifest_other_than_the_reviewed_one_fails_closed(self): + # the entry's pin follows the edited manifest, so only the verifier's own mandatory pin can stop it + path = self.mini / self.entry["xdk_manifest"]["path"] + manifest = json.loads(path.read_text(encoding="utf-8")) + manifest["status"] += " (edited)" + path.write_text(json.dumps(manifest, indent=1) + "\n", encoding="utf-8") + entry = copy.deepcopy(self.entry) + entry["xdk_manifest"]["sha256_lf"] = _lf_sha(path.read_bytes()) + self._write_entry(entry) + credit, verify = self._fails(r"exit 3 \(libraries-missing-or-unverifiable\).*not the reviewed manifest") + self.assertEqual(verify["exit_code"], 3) + + def test_an_unreadable_object_fails_closed(self): + victim = sorted((self.mini / "build" / "base").rglob("*.obj"))[0] + self.restore.append((victim, victim.read_bytes())) + victim.write_bytes(b"\x4c\x01\x01") + credit, verify = self._fails(r"exit 2 \(unreadable-input\)") + self.assertEqual(verify["exit_code"], 2) + + def test_a_malformed_ledger_fails_closed(self): + path = self.mini / self.entry["ledger"]["path"] + ledger = json.loads(path.read_text(encoding="utf-8")) + ledger["records"][0]["tag"] = 5 + path.write_text(json.dumps(ledger, indent=1) + "\n", encoding="utf-8") + entry = copy.deepcopy(self.entry) + entry["ledger"]["sha256_lf"] = _lf_sha(path.read_bytes()) + self._write_entry(entry) + credit, verify = self._fails(r"exit 4 \(malformed-types\)") + self.assertEqual(verify["exit_code"], 4) + + def test_real_pool_is_never_credited_twice(self): + report = self._report() + self._run(report) + credited = copy.deepcopy(report) + with self.assertRaisesRegex(SemanticProgressError, r"no matched or complete data"): + self._run(report) + self.assertEqual(report, credited) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/test_common_pool_verify.py b/tools/test_common_pool_verify.py new file mode 100644 index 00000000..24444d29 --- /dev/null +++ b/tools/test_common_pool_verify.py @@ -0,0 +1,1652 @@ +"""Tests for tools/common_pool_verify.py (report-only COMMON-pool verifier; it credits nothing itself). + +A small synthetic world (January pool + csplit object + symbols/contribs/config ++ our objects + research ledger + XDK library directory with its recorded +manifest) exercises every failure reason and every fail-closed class; the +positive world must pass, and the real January pool (when present) must +reproduce the reviewed accounting. Nothing here credits anything. + +Every mutation of the RF-DE/RF-DH/RF-DM mutation catalogue +(research/remaining_frontier_20260926/q10/mutation/mutations.json) names the +regression tests below that fail when that mutation is applied. +""" + +import copy +import hashlib +import json +import os +import struct +from pathlib import Path + +import pytest + +from tools.coff_compare import build_coff +from tools.common_pool_verify import ( + EXIT_AMBIGUOUS, + EXIT_FAILURES, + EXIT_LIBRARIES, + EXIT_MALFORMED, + EXIT_OK, + EXIT_UNREADABLE, + LibraryVerifyError, + MalformedInputError, + PoolVerifyError, + TAG_RANK, + VERDICT_FAIL, + VERDICT_PASS, + VERDICT_PASS_UNRESOLVED, + XDK_MANIFEST_SHA256_LF as PINNED_MANIFEST, + alignment_from_flags, + law_alignment, + main, + member_symbols, + read_lib_members, + render_text, + tag_ceiling, + tally, + verify, +) + + +REPO = Path(__file__).resolve().parents[1] +Q10 = Path("research") / "remaining_frontier_20260926" / "q10" +REPO_LEDGER = REPO / Q10 / "common_pool_ledger.json" +REPO_MANIFEST = REPO / Q10 / "xdk3911_lib_manifest.json" +MUTATIONS = REPO / Q10 / "mutation" / "mutations.json" +ALIGN_CODE = {1: 1, 2: 2, 4: 3, 8: 4, 16: 5, 32: 6} +LINKER_MODULE = 99 +SHA_PLACEHOLDER = "@library-sha256@" + + +@pytest.fixture(autouse=True) +def _synthetic_manifests_are_not_pinned(): + """Synthetic worlds write their own XDK manifests: the verifier's manifest pin is switched off here and + tested explicitly (test_*manifest_pin*, test_real_january_pool_accounting). Not done with the monkeypatch + fixture, whose undo() inside a test would switch the pin back on.""" + import tools.common_pool_verify as module + saved, module.XDK_MANIFEST_SHA256_LF = module.XDK_MANIFEST_SHA256_LF, None + yield + module.XDK_MANIFEST_SHA256_LF = saved + + +def bss_flags(alignment): + return 0xC0000080 | (ALIGN_CODE[alignment] << 20) + + +RDATA_FLAGS = 0x40000040 + +# January pool: one linker record, three Halo records, one vendor record. +POOL = [ + # name, rva, size, flags + ("_rdata_00001000", 0x1000, 28, RDATA_FLAGS), + ("_alpha", 0x2000, 4, bss_flags(4)), + ("_beta", 0x2004, 1, bss_flags(1)), + ("_gamma", 0x2010, 16, bss_flags(16)), + ("_delta", 0x2020, 4, bss_flags(4)), +] + +CONFIG = { + "projects": [ + {"name": "halobetacache", "objects": [ + {"name": "source/a.c", "index": 10, "status": "NonMatching"}, + {"name": "source/b.c", "index": 20, "status": "NonMatching"}, + {"name": "source/c.c", "index": 30, "status": "Matching"}, + {"name": "source/linker_common.c", "index": LINKER_MODULE, "status": "MISSING"}, + ]}, + {"name": "libcmt", "objects": [ + {"name": "libs/libcmt/crt0dat.c", "index": 50, "status": "Matching"}, + ]}, + ] +} + + +def readout(channel, owner, names, mapping="direct", counted=True): + return {"channel": channel, "names": names, "owner": owner, "mapping": mapping, + "counted": counted, "source": "test"} + + +def record(name, rva, segment, category, tag, owner, readouts, **extra): + entry = {"name": name, "rva": rva, "segment": segment, "category": category, + "name_evidence": "test public", "tag": tag, "owner": owner, "candidate_owner": None, + "readouts": readouts, "basis": "test", "caveats": [], "sources": ["test"]} + entry.update(extra) + return entry + + +VENDOR_EVIDENCE = {"support": "xdk-library-member-only", "library": "libcmt.lib", + "library_sha256": SHA_PLACEHOLDER, "member": "obj\\i386\\crt0dat.obj", + "definition": "COMMON", "size": 4, "january_public": False, + "january_pdb_module": "test module", "statement": "test"} +XDK_READOUT = {"channel": "XDK", "library": "libcmt.lib", "member": "obj\\i386\\crt0dat.obj", + "owner": "libs/libcmt/crt0dat.c", "mapping": "direct", "counted": True, + "source": "test"} +CONTAINMENT = {"kind": "pool-containment", "candidate_owner": "source/c.c", + "lower_neighbours": ["_beta"], "upper_neighbours": ["_delta"], + "neighbour_owner_evidence": "test", "ordering_model": "test", "veto_check": "test", + "ruling": "test", "sources": ["test"]} + +LEDGER = { + "schema": "common-pool-ledger/2", + "status": "test", + "vocabulary": {}, + "derivation": ["test"], + "rulings": [], + "records": [ + record("_alpha", "0x2000", "halo", "halobetacache", "inferred", "source/a.c", + [readout("D", "source/a.c", "a"), readout("X", "source/a.c", "a")]), + record("_beta", "0x2004", "halo", "halobetacache", "probable", "source/b.c", + [readout("D", "source/b.c", "b")]), + record("_gamma", "0x2010", "halo", "halobetacache", "unresolved", None, [], + candidate_owner="source/c.c"), + record("_delta", "0x2020", "vendor", "libcmt", "probable", "libs/libcmt/crt0dat.c", + [XDK_READOUT], name_evidence="test lib", vendor_evidence=VENDOR_EVIDENCE), + ], +} + + +def common(name, size): + return {"name": name, "value": size, "section": 0, "storage": 2} + + +def undef(name): + return {"name": name, "value": 0, "section": 0, "storage": 2} + + +def defined(name, storage=2): + return {"name": name, "value": 0, "section": 1, "storage": storage} + + +BSS_SECTION = {"name": ".bss", "size": 4, "flags": bss_flags(4)} +DATA_SECTION = {"name": ".data", "size": 4, "flags": 0xC0300040} +TEXT_SECTION = {"name": ".text", "size": 4, "flags": 0x60500020} + +OURS = { + "source/a.obj": ([], [common("_alpha", 4), undef("_beta")]), + "source/b.obj": ([], [common("_beta", 1)]), + "source/c.obj": ([], [common("_gamma", 16)]), + "libs/libcmt/crt0dat.obj": ([], [common("_delta", 4)]), +} + + +def write_lib(path, members): + """Minimal COFF archive: empty first linker member, longnames, members.""" + def header(name, size): + return (name.ljust(16) + "0".ljust(12) + "".ljust(6) + "".ljust(6) + "0".ljust(8) + + str(size).ljust(10) + "`\n").encode("latin-1") + + longnames = b"" + offsets = [] + for name, _ in members: + offsets.append(len(longnames)) + longnames += name.encode("latin-1") + b"\0" + out = bytearray(b"!\n") + for name, body in [("/", b"\0\0\0\0"), ("//", longnames)]: + out += header(name, len(body)) + body + if len(body) & 1: + out += b"\n" + for (name, body), offset in zip(members, offsets): + out += header(f"/{offset}", len(body)) + body + if len(body) & 1: + out += b"\n" + path.write_bytes(bytes(out)) + + +def delta_member(size=4, extra=()): + return build_coff(sections=[], symbols=[common("_delta", size)] + list(extra)) + + +def default_libs(delta_size=4, extra=()): + return {"libcmt.lib": [("obj\\i386\\crt0dat.obj", delta_member(delta_size, extra))]} + + +def import_member(name): + """Short import descriptor (sig1 0, sig2 0xFFFF, version 0) for *name*.""" + strings = name.encode("latin-1") + b"\0" + b"test.dll\0" + return struct.pack(" unresolved (containment evidence never " + f"raises a tag)") for r in reasons) + assert rows_by_name(report)["_gamma"]["verdict"] == VERDICT_FAIL + + +def test_containment_cannot_be_smuggled_in_as_a_readout(tmp_path): + smuggled = dict(readout("D", "source/c.c", "c"), channel="CONTAINMENT") + ledger = ledger_with(_gamma=dict(HS_LIKE, tag="probable", owner="source/c.c", readouts=[smuggled])) + row = rows_by_name(run(tmp_path, ledger=ledger))["_gamma"] + assert {"readout-channel-unknown", "tag-exceeds-evidence"} <= reason_keys(row) + + +def test_containment_evidence_must_name_the_record_candidate(tmp_path): + bad = [dict(CONTAINMENT, candidate_owner="source/a.c"), dict(CONTAINMENT, kind="adjacency")] + row = rows_by_name(run(tmp_path, ledger=ledger_with(_gamma=dict(HS_LIKE, containment_evidence=bad))))["_gamma"] + assert len([r for r in row["reasons"] if r.startswith("containment-evidence-invalid")]) == 2 + + +# -- integration (RF-DM): vendor evidence is explicit --------------------------------- + +def test_vendor_evidence_must_be_recorded(tmp_path): + report = run(tmp_path, ledger=ledger_with(_delta={"vendor_evidence": KeyError})) + row = rows_by_name(report)["_delta"] + assert reason_keys(row) == {"vendor-evidence-missing"} + assert report["result"] == "COMPLETE" and row["segment"] == "vendor" + + +@pytest.mark.parametrize("change,key,closed", [ + ({"library_sha256": "0" * 64}, "vendor-evidence-library-hash-mismatch", True), + ({"member": "obj\\i386\\other.obj"}, "vendor-evidence-disagrees-with-readout", True), + ({"library": "xapilib.lib"}, "vendor-evidence-disagrees-with-readout", True), + ({"size": 8}, "vendor-evidence-size-mismatch", False), + ({"definition": "DEFINED"}, "vendor-evidence-size-mismatch", False), + ({"support": "january-proven"}, "vendor-evidence-invalid", False), +]) +def test_vendor_evidence_is_checked_against_library_and_january(tmp_path, change, key, closed): + evidence = dict(VENDOR_EVIDENCE, **change) + report = run(tmp_path, ledger=ledger_with(_delta={"vendor_evidence": evidence})) + assert key in reason_keys(rows_by_name(report)["_delta"]) + assert (report["result"] == "FAIL-CLOSED") is closed + + +def test_vendor_record_supported_only_by_a_library_member_stays_probable(tmp_path): + two = [XDK_READOUT, dict(XDK_READOUT, library="libcmt.lib")] + report = run(tmp_path, ledger=ledger_with(_delta={"tag": "inferred", "readouts": two})) + reasons = rows_by_name(report)["_delta"]["reasons"] + assert any(r.startswith("tag-exceeds-evidence: a vendor record supported only by an XDK library " + "member remains probable") for r in reasons) + assert any(r.startswith("tag-exceeds-evidence: inferred > probable") for r in reasons) + + +# -- integration (RF-DM): receipts ---------------------------------------------------- + +def test_every_run_writes_a_receipt(tmp_path): + import tools.common_pool_verify as module + write_world(tmp_path) + assert cli(tmp_path, "r0.json") == EXIT_OK + receipt = receipt_of(tmp_path, "r0.json") + source = Path(module.__file__).read_bytes() + assert receipt["verifier"]["sha256"] == hashlib.sha256(source).hexdigest() + assert receipt["verifier"]["sha256_lf"] == hashlib.sha256(source.replace(b"\r\n", b"\n")).hexdigest() + ledger_bytes = (tmp_path / Q10 / "common_pool_ledger.json").read_bytes() + assert receipt["inputs"]["ledger"]["sha256_lf"] == hashlib.sha256(ledger_bytes).hexdigest() + assert receipt["inputs"]["xdk_manifest"]["sha256"] + lib = receipt["xdk_libraries"]["libraries"]["libcmt.lib"] + assert lib["verified"] and lib["actual_sha256"] == lib["recorded_sha256"] + snapshot = receipt["build_snapshot"] + assert snapshot["objects"]["files"] == 4 and len(snapshot["objects"]["manifest_sha256"]) == 64 + assert snapshot["split"]["files"] == 5 # the pool + one January object per config unit (RF-DP D7) + assert receipt["argv"][:2] == ["--root", str(tmp_path)] + assert receipt["summary"]["halo"]["verdicts"] == {"PASS": [2, 5], "PASS-OWNER-UNRESOLVED": [1, 16]} + assert receipt["summary"]["vendor"]["libcmt"]["verdicts"] == {"PASS": [1, 4]} + # fail-closed runs are receipted too, with every input fingerprint that could be taken + (tmp_path / "xdk" / "libcmt.lib").write_bytes(b"!\n") + assert cli(tmp_path, "r1.json") == EXIT_LIBRARIES + receipt = receipt_of(tmp_path, "r1.json") + assert receipt["result"] == "FAIL-CLOSED" and receipt["inputs"]["ledger"]["sha256_lf"] + assert receipt["build_snapshot"]["objects"]["files"] == 4 + report_json = json.loads((tmp_path / "out.json").read_text(encoding="utf-8")) + assert report_json["receipt"]["exit_code"] == EXIT_OK # the r0 run's report, untouched by r1 + + +def test_ledger_hash_is_line_ending_independent(tmp_path): + write_world(tmp_path) + ledger_path = tmp_path / Q10 / "common_pool_ledger.json" + ledger_path.write_bytes(json.dumps(LEDGER, indent=1).replace(SHA_PLACEHOLDER, json.loads( + (tmp_path / Q10 / "xdk_manifest.json").read_text())["libraries"][0]["sha256"]).encode()) + lf = verify(**paths(tmp_path))["inputs"] + ledger_path.write_bytes(ledger_path.read_bytes().replace(b"\n", b"\r\n")) + crlf = verify(**paths(tmp_path))["inputs"] + assert lf["ledger_sha256_lf"] == crlf["ledger_sha256_lf"] + assert lf["ledger_sha256"] != crlf["ledger_sha256"] + + +def test_ledger_path_is_explicit(tmp_path): + write_world(tmp_path) + with pytest.raises(PoolVerifyError, match="--ledger is required"): + verify(**dict(paths(tmp_path), ledger_path=None)) + assert main(cli_args(tmp_path, ledger=True)) == EXIT_UNREADABLE + assert "--ledger is required" in receipt_of(tmp_path)["fail_closed"]["message"] + with pytest.raises(SystemExit): # nowhere to write the receipt: usage error + main(cli_args(tmp_path, receipt=True)) + + +# -- the research ledger and the real January pool -------------------------------------- + +@pytest.mark.skipif(not REPO_LEDGER.is_file() or not REPO_MANIFEST.is_file(), + reason="research ledger / XDK manifest not present") +def test_research_ledger_records(): + assert not (REPO / "config" / "common_pool_ledger.json").exists() # research record, not config + ledger = json.loads(REPO_LEDGER.read_text(encoding="utf-8")) + manifest = json.loads(REPO_MANIFEST.read_text(encoding="utf-8")) + from tools.common_pool_verify import validate_ledger, validate_manifest + validate_ledger(ledger) + validate_manifest(manifest) + sha = {e["file"].lower(): e["sha256"] for e in manifest["libraries"]} + records = {r["name"]: r for r in ledger["records"]} + hs = records["_hs_debug_data"] + assert (hs["tag"], hs["owner"], hs["readouts"]) == ("unresolved", None, []) + assert hs["candidate_owner"] == "source/hs/hs_runtime.c" + assert [c["candidate_owner"] for c in hs["containment_evidence"]] == ["source/hs/hs_runtime.c"] + assert tag_ceiling(dict(hs, owner=hs["candidate_owner"]), "halo") == "unresolved" + vendor = [r for r in ledger["records"] if r["segment"] == "vendor"] + assert len(vendor) == 27 and {r["tag"] for r in vendor} == {"probable"} + for entry in vendor: + evidence = entry["vendor_evidence"] + assert evidence["support"] == "xdk-library-member-only" + assert evidence["library_sha256"] == sha[evidence["library"].lower()] + assert not any("vendor_evidence" in r for r in ledger["records"] if r["segment"] == "halo") + + +def _xdk_dir(): + candidates = [os.environ.get("HALO_Q10_XDK_LIB_DIR")] + if REPO_MANIFEST.is_file(): + candidates.append(json.loads(REPO_MANIFEST.read_text(encoding="utf-8"))["source_dir"]) + for candidate in candidates: + if candidate and Path(candidate).is_dir(): + return Path(candidate) + return None + + +@pytest.mark.skipif(not (REPO / "build/split/source/linker_common.obj").is_file() + or not REPO_LEDGER.is_file() or _xdk_dir() is None, + reason="January split pool, research ledger or XDK libraries not present") +def test_real_january_pool_accounting(tmp_path, monkeypatch): + import tools.common_pool_verify as module + monkeypatch.setattr(module, "XDK_MANIFEST_SHA256_LF", PINNED_MANIFEST) # the real run is pinned (RF-DX D2) + # a complete build in which no object defines anything: one empty object per built unit (RF-DP D8) + empty = tmp_path / "no_objects" + config = json.loads((REPO / "config" / "config.json").read_text(encoding="utf-8")) + for project in config["projects"]: + for entry in project["objects"]: + if entry.get("status") != "MISSING": + path = empty / Path(entry["name"]).with_suffix(".obj") + path.parent.mkdir(parents=True, exist_ok=True) + path.write_bytes(build_coff(sections=[], symbols=[])) + report = verify(REPO, objects_root=empty, ledger_path=REPO_LEDGER, xdk_lib_dir=_xdk_dir(), + xdk_manifest_path=REPO_MANIFEST) + assert report["result"] == "COMPLETE" + january = report["january"] + assert (january["records"], january["bss_records"], january["linker_records"]) == (242, 240, 2) + assert january["layout_reasons"] == 0 and report["global_failures"] == [] + assert sum(x["size"] for x in report["excluded_linker_records"]) == 88 + acc = report["accounting"] + assert (acc["halo"]["records"], acc["halo"]["bytes"], acc["halo"]["gap_bytes"]) == (213, 1270477, 675) + vendor = {k: (v["records"], v["bytes"]) for k, v in acc["vendor"].items()} + assert vendor == {"dsound": (1, 4), "libcmt": (17, 845), "xapilib": (9, 276)} + assert sum(v["gap_bytes"] for v in acc["vendor"].values()) == 131 + assert acc["conservation"]["holds"] and acc["conservation"]["january_bss_span"] == 1272408 + tags = {t: acc["halo"]["by_tag"][t]["records"] for t in TAG_RANK} + assert tags == {"unresolved": 83, "probable": 60, "inferred": 70} + assert sorted(report["libraries"]["scanned_linked"]) == [ + "d3d8.lib", "d3dx8.lib", "dsound.lib", "libcmt.lib", "oldnames.lib", "xapilib.lib", "xbdm.lib", + "xboxkrnl.lib", "xkbd.lib", "xnet.lib"] + # with no objects, every record fails for want of a definer - and only for that + reasons = {r.split(":")[0] for row in report["records"] for r in row["reasons"]} + assert reasons == {"no-definer", "owner-not-in-config"} + + +# -- independent re-review (RF-DP): fail-closed gaps found after integration ----------------- + +def _manifest_path(root): + return Path(root) / Q10 / "xdk_manifest.json" + + +def _edit_manifest(root, change): + manifest = json.loads(_manifest_path(root).read_text(encoding="utf-8")) + change(manifest) + _manifest_path(root).write_text(json.dumps(manifest), encoding="utf-8") + + +def test_manifest_linked_flags_must_match_january_module_counts(tmp_path): + write_world(tmp_path) + _edit_manifest(tmp_path, lambda m: m["libraries"][0].update(january_pdb_modules=0)) # linked, 0 modules + with pytest.raises(MalformedInputError, match="disagrees with january_pdb_modules"): + verify(**paths(tmp_path)) + write_world(tmp_path / "absent") + _edit_manifest(tmp_path / "absent", lambda m: m["linked_libraries_not_in_extract"].append( + {"library": "binkxbox.lib", "category": None, "january_path": "x", "january_pdb_modules": 0, + "reason": "test"})) + with pytest.raises(MalformedInputError, match="declared linked by January with 0"): + verify(**paths(tmp_path / "absent")) + + +def test_manifest_cannot_hide_a_present_library(tmp_path): + # RF-DP T02: mark the category's own library unlinked and declare the category absent, so that + # its records could be relabelled Halo without any library scan + write_world(tmp_path) + + def hide(manifest): + manifest["libraries"][0].update(linked_by_january=False, january_pdb_modules=0) + manifest["linked_libraries_not_in_extract"].append( + {"library": "libcmt_january.lib", "category": "libcmt", "january_path": "x", + "january_pdb_modules": 1, "reason": "test"}) + _edit_manifest(tmp_path, hide) + with pytest.raises(LibraryVerifyError) as caught: + verify(**paths(tmp_path)) + assert "libcmt.lib is listed but not marked linked" in str(caught.value) + assert "declared to have no library in the extract" in str(caught.value) + # a library declared absent must not be sitting in the directory + write_world(tmp_path / "present") + (tmp_path / "present" / "xdk" / "binkxbox.lib").write_bytes(b"!\n") + _edit_manifest(tmp_path / "present", lambda m: m["linked_libraries_not_in_extract"].append( + {"library": "binkxbox.lib", "category": None, "january_path": "x", "january_pdb_modules": 24, + "reason": "test"})) + with pytest.raises(LibraryVerifyError, match="declared not in the extract but is present"): + verify(**paths(tmp_path / "present")) + + +def test_manifest_may_not_declare_a_listed_library_absent(tmp_path): + write_world(tmp_path) + _edit_manifest(tmp_path, lambda m: m["linked_libraries_not_in_extract"].append( + {"library": "LIBCMT.lib", "category": None, "january_path": "x", "january_pdb_modules": 1, + "reason": "test"})) + with pytest.raises(MalformedInputError, match="both present and absent"): + verify(**paths(tmp_path)) + + +def test_upper_case_unlisted_library_fails_closed(tmp_path): + write_world(tmp_path) + (tmp_path / "xdk" / "EXTRA.LIB").write_bytes(b"!\n") + with pytest.raises(LibraryVerifyError, match="unlisted library EXTRA.LIB"): + verify(**paths(tmp_path)) + + +def test_library_names_differing_only_in_case_fail_closed(tmp_path, monkeypatch): + write_world(tmp_path) + lib_dir = tmp_path / "xdk" + variant = lib_dir / "LIBCMT.lib" + if not variant.exists(): # a case-sensitive file system: a real second file + variant.write_bytes((lib_dir / "libcmt.lib").read_bytes()) + else: # case-insensitive: list the same file under both names + real_iterdir = Path.iterdir + + def iterdir(self): + items = list(real_iterdir(self)) + if self == lib_dir: + items.append(variant) + return iter(items) + monkeypatch.setattr(Path, "iterdir", iterdir) + with pytest.raises(LibraryVerifyError, match="differ only in case"): + verify(**paths(tmp_path)) + + +def test_vendor_readout_is_reproduced_only_from_its_own_library(tmp_path): + # another linked library defines _delta in a member of the same name; libcmt.lib does not + libs = {"libcmt.lib": [("obj\\i386\\other.obj", build_coff(sections=[], symbols=[]))], + "other.lib": [("obj\\i386\\crt0dat.obj", delta_member())]} + report = run(tmp_path, libs=libs) + assert fail_closed_names(report) == {"_delta"} + assert "vendor-readout-not-reproduced" in reason_keys(rows_by_name(report)["_delta"]) + + +@pytest.mark.parametrize("which", ["ledger", "manifest", "contribs"]) +def test_duplicate_json_keys_fail_closed(tmp_path, which): + write_world(tmp_path) + path = {"ledger": tmp_path / Q10 / "common_pool_ledger.json", "manifest": _manifest_path(tmp_path), + "contribs": tmp_path / "config" / "contribs.json"}[which] + text = path.read_text(encoding="utf-8") + brace = text.index("{") # the top-level object, or the first contribution + first = '"size": 1, ' if which == "contribs" else '"schema": "x", ' + path.write_text(text[:brace + 1] + first + text[brace + 1:], encoding="utf-8") + assert main(cli_args(tmp_path)) == EXIT_MALFORMED + receipt = receipt_of(tmp_path) + assert receipt["fail_closed"]["class"] == "malformed-types" + assert "duplicate JSON key" in receipt["fail_closed"]["message"] + + +def test_duplicate_caveats_key_cannot_hide_a_caveat(tmp_path): + write_world(tmp_path) + path = tmp_path / Q10 / "common_pool_ledger.json" + text = path.read_text(encoding="utf-8") + at = text.index('"name": "_alpha"') + path.write_text(text[:at] + '"caveats": ["hidden"], ' + text[at:], encoding="utf-8") + with pytest.raises(MalformedInputError, match="duplicate JSON key 'caveats'"): + verify(**paths(tmp_path)) + + +def test_missing_or_unreadable_january_split_object_fails_closed(tmp_path): + write_world(tmp_path) + split_b = tmp_path / "build" / "split" / "source" / "b.obj" + split_b.unlink() + assert main(cli_args(tmp_path)) == EXIT_UNREADABLE + assert "no January split object" in receipt_of(tmp_path)["fail_closed"]["message"] + split_b.write_bytes(b"\x4c\x01") + assert main(cli_args(tmp_path)) == EXIT_UNREADABLE + assert "split object(s) missing or unreadable" in receipt_of(tmp_path)["fail_closed"]["message"] + + +def test_split_pool_outside_its_split_tree_fails_closed(tmp_path): + write_world(tmp_path) + alone = tmp_path / "elsewhere" / "pool" / "linker_common.obj" + alone.parent.mkdir(parents=True) + alone.write_bytes((tmp_path / "build" / "split" / "source" / "linker_common.obj").read_bytes()) + with pytest.raises(PoolVerifyError, match="no January split object"): + verify(**dict(paths(tmp_path), split_path=alone)) + + +def test_absent_object_of_a_built_unit_fails_closed(tmp_path): + ours = dict(OURS) + ours.pop("source/b.obj") + write_world(tmp_path, ours=ours) + assert main(cli_args(tmp_path)) == EXIT_UNREADABLE + assert "source/b.c" in receipt_of(tmp_path)["fail_closed"]["message"] + + +def test_bad_section_number_in_an_object_is_receipted_not_a_crash(tmp_path): + write_world(tmp_path) + stray = tmp_path / "build" / "base" / "stray" / "bad.obj" + stray.parent.mkdir(parents=True) + stray.write_bytes(build_coff(sections=[], symbols=[{"name": "_alpha", "value": 0, "section": 5, + "type": 0, "storage": 2, "aux_count": 0}])) + assert main(cli_args(tmp_path)) == EXIT_UNREADABLE + assert "names section 5 of 0" in receipt_of(tmp_path)["fail_closed"]["message"] + + +def test_unreadable_files_are_receipted_not_a_crash(tmp_path, monkeypatch): + import tools.common_pool_verify as module + write_world(tmp_path) + + def locked(*_args, **_kwargs): + raise PermissionError(13, "Permission denied (test)") + monkeypatch.setattr(module, "tree_manifest", locked) + assert main(cli_args(tmp_path)) == EXIT_UNREADABLE + receipt = receipt_of(tmp_path) + assert receipt["result"] == "FAIL-CLOSED" and "PermissionError" not in receipt["fail_closed"]["message"] + assert "Permission denied" in receipt["fail_closed"]["message"] + monkeypatch.undo() + real_read = Path.read_bytes + + def read_bytes(self): + if self.name == "libcmt.lib": + raise PermissionError(13, "Permission denied (test)") + return real_read(self) + monkeypatch.setattr(Path, "read_bytes", read_bytes) + assert main(cli_args(tmp_path, "r2.json")) == EXIT_LIBRARIES + assert "cannot read library" in receipt_of(tmp_path, "r2.json")["fail_closed"]["message"] + + +def test_inputs_changed_during_the_run_fail_closed(tmp_path, monkeypatch): + import tools.common_pool_verify as module + write_world(tmp_path) + ledger_path = tmp_path / Q10 / "common_pool_ledger.json" + real_scan = module.scan_objects + + def scan_and_touch(*args, **kwargs): + ledger_path.write_bytes(ledger_path.read_bytes() + b"\n") # a concurrent writer + return real_scan(*args, **kwargs) + monkeypatch.setattr(module, "scan_objects", scan_and_touch) + with pytest.raises(PoolVerifyError, match="inputs changed during the run"): + verify(**paths(tmp_path)) + + +def test_excluded_record_inconsistency_is_a_global_failure(tmp_path): + split = [p if p[0] != "_rdata_00001000" else ("_rdata_00001000", 0x1000, 32, RDATA_FLAGS) for p in POOL] + report = run(tmp_path, split_pool=split) + assert any(g.startswith("january-excluded-record-inconsistent: _rdata_00001000") + for g in report["global_failures"]) + assert report["exit_code"] == EXIT_FAILURES + + +def test_extra_split_section_is_a_global_failure(tmp_path): + report = run(tmp_path, split_pool=POOL + [("_extra", 0x3000, 4, bss_flags(4))]) + assert any(g.startswith("split pool has 6 sections") for g in report["global_failures"]) + assert report["exit_code"] == EXIT_FAILURES + + +def test_ledger_only_run_refused_even_when_every_vendor_record_is_relabelled(tmp_path): + # RF-DH F2 behaviourally: with no vendor record left in the ledger, only the library requirement + # stands between a relabelled vendor record and the Halo tally + relabelled = ledger_with(_delta={"segment": "halo", "category": "halobetacache", "tag": "unresolved", + "owner": None, "readouts": [], "vendor_evidence": KeyError}) + write_world(tmp_path, ledger=relabelled) + assert main(cli_args(tmp_path, xdk_lib_dir=True)) == EXIT_LIBRARIES + receipt = receipt_of(tmp_path) + assert receipt["summary"] is None and "--xdk-lib-dir is required" in receipt["fail_closed"]["message"] + + +# -- independent re-review (RF-DX): D6 completion (every exit path receipted), D11 ------------ + +def test_unanticipated_exception_is_receipted_never_status_1(tmp_path, monkeypatch): + import tools.common_pool_verify as module + write_world(tmp_path) + + def broken(*_args, **_kwargs): + raise RuntimeError("verifier defect (test)") + monkeypatch.setattr(module, "january_pool", broken) + assert main(cli_args(tmp_path)) == EXIT_UNREADABLE + receipt = receipt_of(tmp_path) + assert receipt["exit_code"] == EXIT_UNREADABLE and receipt["summary"] is None + assert receipt["fail_closed"]["class"] == "unreadable-input" + assert receipt["fail_closed"]["message"] == "unexpected RuntimeError: verifier defect (test)" + assert not (tmp_path / "out.json").exists() + + +def test_index_error_is_malformed_input_and_receipted(tmp_path, monkeypatch): + import tools.common_pool_verify as module + write_world(tmp_path) + + def broken(*_args, **_kwargs): + raise IndexError("index out of range (test)") + monkeypatch.setattr(module, "january_pool", broken) + assert main(cli_args(tmp_path)) == EXIT_MALFORMED + receipt = receipt_of(tmp_path) + assert receipt["fail_closed"]["class"] == "malformed-types" + assert receipt["fail_closed"]["message"] == "index out of range (test)" + + +@pytest.mark.parametrize("output", ["text", "json"]) +def test_unwritable_report_fails_closed_and_the_receipt_says_so(tmp_path, output): + write_world(tmp_path) + args = cli_args(tmp_path) + args[args.index("--" + output) + 1] = str(tmp_path / "no_such_dir" / f"out.{output}") + assert main(args) == EXIT_UNREADABLE + receipt = receipt_of(tmp_path) + assert receipt["exit_code"] == EXIT_UNREADABLE and receipt["result"] == "FAIL-CLOSED" + assert receipt["summary"] is None + assert receipt["fail_closed"]["message"].startswith("cannot write the report: FileNotFoundError") + # the JSON report is written before the text report: an exit-2 run leaves no accounting behind + assert not (tmp_path / "out.json").exists() + + +def test_unwritable_receipt_leaves_no_report_behind(tmp_path, capsys): + write_world(tmp_path) + args = cli_args(tmp_path) + args[args.index("--receipt") + 1] = str(tmp_path / "no_such_dir" / "receipt.json") + assert main(args) == EXIT_UNREADABLE + assert "cannot write the receipt" in capsys.readouterr().err + # the complete run's reports were written first; with no receipt they must not survive + assert not (tmp_path / "out.json").exists() and not (tmp_path / "out.txt").exists() + + +def test_unlistable_library_directory_is_a_library_failure(tmp_path, monkeypatch): + write_world(tmp_path) + lib_dir = (tmp_path / "xdk").resolve() + real_iterdir = Path.iterdir + + def iterdir(self): + if self.resolve() == lib_dir: + raise PermissionError(13, "Permission denied (test)", str(self)) + return real_iterdir(self) + monkeypatch.setattr(Path, "iterdir", iterdir) + assert main(cli_args(tmp_path)) == EXIT_LIBRARIES + receipt = receipt_of(tmp_path) + assert receipt["fail_closed"]["class"] == "libraries-missing-or-unverifiable" + assert "cannot list --xdk-lib-dir" in receipt["fail_closed"]["message"] + + +@pytest.mark.parametrize("member", [ + build_coff(sections=[], symbols=[common("_delta", 4)]), # a second COMMON definer + build_coff(machine=0, sections=[], symbols=[{"name": "_delta", "value": 0, "section": 0, + "storage": 105}]), # a weak alias +]) +def test_vendor_record_defined_by_another_linked_library_fails_closed(tmp_path, member): + libs = default_libs() + libs["other.lib"] = [("obj\\i386\\other.obj", member)] + report = run(tmp_path, libs=libs) + assert fail_closed_names(report) == {"_delta"} + assert "vendor-record-defined-by-another-library" in reason_keys(rows_by_name(report)["_delta"]) + + +# -- optional (RF-DX, D2 residual): the reviewed XDK manifest is pinned --------------------- + +@pytest.mark.skipif(not REPO_MANIFEST.is_file(), reason="research XDK manifest not present") +def test_manifest_pin_is_the_research_manifest(): + data = REPO_MANIFEST.read_bytes().replace(b"\r\n", b"\n") + assert hashlib.sha256(data).hexdigest() == PINNED_MANIFEST + + +def test_manifest_pin_refuses_any_other_manifest(tmp_path, monkeypatch): + import tools.common_pool_verify as module + write_world(tmp_path) + monkeypatch.setattr(module, "XDK_MANIFEST_SHA256_LF", PINNED_MANIFEST) # a well-formed, consistent manifest + assert main(cli_args(tmp_path)) == EXIT_LIBRARIES + receipt = receipt_of(tmp_path) + assert receipt["fail_closed"]["class"] == "libraries-missing-or-unverifiable" and receipt["summary"] is None + assert "is not the reviewed manifest" in receipt["fail_closed"]["message"] + + +def test_manifest_pin_accepts_its_own_manifest_with_either_line_end(tmp_path, monkeypatch): + import tools.common_pool_verify as module + write_world(tmp_path) + path = _manifest_path(tmp_path) + path.write_bytes(json.dumps(json.loads(path.read_text(encoding="utf-8")), indent=1).encode("utf-8")) + monkeypatch.setattr(module, "XDK_MANIFEST_SHA256_LF", hashlib.sha256(path.read_bytes()).hexdigest()) + assert verify(**paths(tmp_path))["result"] == "COMPLETE" + path.write_bytes(path.read_bytes().replace(b"\n", b"\r\n")) + assert verify(**paths(tmp_path))["result"] == "COMPLETE" + + +# -- the mutation catalogue ---------------------------------------------------------------- + +@pytest.mark.skipif(not MUTATIONS.is_file(), reason="mutation catalogue not present") +def test_every_mutation_names_existing_regression_tests(): + catalogue = json.loads(MUTATIONS.read_text(encoding="utf-8")) + tests = {name for name in globals() if name.startswith("test_")} + ids = [m["id"] for m in catalogue["mutations"]] + assert len(ids) == len(set(ids)) + origins = {} + for mutation in catalogue["mutations"]: + origins[mutation["origin"]] = origins.get(mutation["origin"], 0) + 1 + assert mutation["killers"], mutation["id"] + assert set(mutation["killers"]) <= tests, (mutation["id"], set(mutation["killers"]) - tests) + assert origins.get("RF-DE") == 43 and origins.get("RF-DH") == 16 diff --git a/tools/test_data_category_reassignments.py b/tools/test_data_category_reassignments.py new file mode 100644 index 00000000..2615c109 --- /dev/null +++ b/tools/test_data_category_reassignments.py @@ -0,0 +1,373 @@ +"""Tests for apply_data_category_reassignments (accounting only, no credit).""" + +import copy +import json +import random +import struct +import tempfile +import unittest +from pathlib import Path + +from tools import semantic_progress +from tools.coff_compare import build_coff +from tools.semantic_progress import ( + OBJDIFF_331_COMBINED_EXTENT, + SemanticProgressError, + apply_data_category_reassignments, +) + +BSS_ALIGN1 = 0xC0100080 +BSS_ALIGN4 = 0xC0300080 +BSS_ALIGN32 = 0xC0600080 +RDATA_DEFAULT = 0x40000040 +RDATA_ALIGN4 = 0x40300040 +LONG_NAME = b".rdata$debug" + + +def _pool_object(extra_symbols=(), long_name="/4"): + """Five-record pool: .bss 5/1/48, .rdata 28 and a long-named .rdata$debug 60.""" + sections = [ + {"name": ".bss", "size": 5, "flags": BSS_ALIGN4}, + {"name": ".bss", "size": 1, "flags": BSS_ALIGN1}, + {"name": ".bss", "size": 48, "flags": BSS_ALIGN32}, + {"name": ".rdata", "size": 28, "flags": RDATA_DEFAULT}, + {"name": long_name, "size": 60, "flags": RDATA_ALIGN4}, + ] + symbols = [ + {"name": ".bss", "section": 1, "storage": 3}, + {"name": "_halo_a", "section": 1}, + {"name": "_vend_b", "section": 2}, + {"name": "_halo_c", "section": 3}, + {"name": "_rd_a", "section": 4}, + {"name": "_rd_b", "section": 5}, + {"name": "_undef", "section": 0}, + ] + symbols.extend(extra_symbols) + strtab = struct.pack(" linker +96, vend +4 " + "(3 records: 89 raw + 11 objdiff padding bytes)"]) + + def test_missing_manifest_is_a_no_op(self): + report = _report() + notes = apply_data_category_reassignments( + report, self.root, self.root / "absent.json", + self.root / "objdiff.json") + self.assertEqual(notes, []) + self.assertEqual(report, _report()) + + def test_shares_sum_to_the_pinned_extent_model(self): + rng = random.Random(20260928) + for _ in range(300): + sections = [] + for index in range(1, rng.randint(1, 12)): + name = rng.choice([".bss", ".data", ".data$r", ".data$z"]) + sections.append({ + "index": index, "name": name, + "size": rng.randint(0, 300), + "flags": 0xC0000040 | (rng.randint(0, 7) << 20)}) + if not sections: + continue + shares = semantic_progress._objdiff_report_shares(sections) + self.assertEqual( + sum(shares.values()), + semantic_progress._objdiff_report_extent(sections)) + self.assertEqual(set(shares), + {s["index"] for s in sections}) + + def test_long_section_name_is_resolved(self): + named = semantic_progress._objdiff_named_sections( + semantic_progress.load(self.root / "target.obj"), "pool") + self.assertEqual([s["name"] for s in named["sections"]], + [".bss", ".bss", ".bss", ".rdata", ".rdata$debug"]) + + def test_dangling_long_section_name_fails(self): + (self.root / "target.obj").write_bytes(_pool_object(long_name="/99")) + self._fails("unresolvable long section name") + + def test_malformed_long_section_name_fails(self): + (self.root / "target.obj").write_bytes(_pool_object(long_name="/x1")) + self._fails("malformed long section name") + + def test_wrong_size_fails(self): + self.manifest["entries"][0]["records"][0]["size"] = 2 + self._fails("does not match the target") + + def test_wrong_section_name_fails(self): + self.manifest["entries"][0]["records"][2]["section"] = ".rdata" + self._fails("does not match the target") + + def test_absent_symbol_fails(self): + self.manifest["entries"][0]["records"][0]["symbol"] = "_nobody" + self._fails("not one defined external symbol") + + def test_undefined_symbol_is_not_a_record(self): + self.manifest["entries"][0]["records"][0]["symbol"] = "_undef" + self._fails("not one defined external symbol") + + def test_duplicate_record_fails(self): + records = self.manifest["entries"][0]["records"] + records.append(copy.deepcopy(records[0])) + self._fails("listed twice") + + def test_shared_section_fails(self): + (self.root / "target.obj").write_bytes(_pool_object( + extra_symbols=[{"name": "_alias", "section": 2, "value": 0}])) + self._fails("does not own its whole section") + + def test_offset_symbol_fails(self): + (self.root / "target.obj").write_bytes(_pool_object( + extra_symbols=[{"name": "_inner", "section": 3, "value": 8}])) + self.manifest["entries"][0]["records"][0] = { + "symbol": "_inner", "section": ".bss", "size": 48, + "to_category": "vend", "evidence": "fixture"} + self._fails("does not own its whole section") + + def test_moved_pin_fails(self): + self.manifest["entries"][0]["moved"] = {"linker": 96, "vend": 1} + self._fails("totals changed") + + def test_raw_size_pin_is_not_the_moved_share(self): + self.manifest["entries"][0]["moved"] = {"linker": 88, "vend": 1} + self._fails("totals changed") + + def test_unit_total_pin_fails(self): + self.manifest["entries"][0]["unit_total_data"] = 161 + self._fails("unit total changed") + + def test_report_not_bound_to_target_fails(self): + report = _report() + report["units"][0]["sections"][0]["size"] = "60" + report["units"][0]["measures"]["total_data"] = "156" + self._fails("modelled extent", report) + + def test_unit_with_matched_data_fails(self): + report = _report() + report["units"][0]["measures"]["matched_data"] = "4" + self._fails("no matched or complete data", report) + + def test_complete_unit_fails(self): + self.objdiff["units"][0]["metadata"]["complete"] = True + self._fails("no matched or complete data") + + def test_unit_in_two_categories_fails(self): + report = _report() + report["units"][0]["metadata"]["progress_categories"] = [ + "halo", "vend"] + self._fails("not solely", report) + + def test_unknown_target_category_fails(self): + self.manifest["entries"][0]["records"][0]["to_category"] = "nowhere" + self._fails("invalid data category reassignment target") + + def test_target_equal_to_source_fails(self): + self.manifest["entries"][0]["records"][0]["to_category"] = "halo" + self._fails("invalid data category reassignment target") + + def test_declared_category_may_not_shadow(self): + self.manifest["categories"].append({"id": "vend", "name": "vend"}) + self._fails("already exists") + + def test_unused_declared_category_fails(self): + self.manifest["categories"].append({"id": "spare", "name": "spare"}) + self._fails("receives no data") + + def test_unknown_keys_fail(self): + for where in ("manifest", "entry", "record", "category"): + with self.subTest(where=where): + self.manifest = _manifest() + target = {"manifest": self.manifest, + "entry": self.manifest["entries"][0], + "record": self.manifest["entries"][0]["records"][0], + "category": self.manifest["categories"][0]}[where] + target["credit"] = 1 + self._fails("") + + def test_missing_keys_fail(self): + for key in ("reason", "moved", "unit_total_data", "extent_model"): + with self.subTest(key=key): + self.manifest = _manifest() + del self.manifest["entries"][0][key] + self._fails("exactly the keys") + self.manifest = _manifest() + del self.manifest["entries"][0]["records"][1]["evidence"] + self._fails("exactly the keys") + + def test_blank_evidence_fails(self): + self.manifest["entries"][0]["records"][1]["evidence"] = " " + self._fails("malformed data category reassignment record") + + def test_unknown_extent_model_fails(self): + self.manifest["entries"][0]["extent_model"] = "objdiff-9" + self._fails("unknown data category reassignment extent model") + + def test_boolean_is_not_a_count(self): + self.manifest["entries"][0]["records"][0]["size"] = True + self._fails("malformed size") + + def test_unit_listed_twice_fails_before_any_change(self): + self.manifest["entries"].append(copy.deepcopy( + self.manifest["entries"][0])) + self._fails("listed twice") + + def test_unknown_unit_fails(self): + self.manifest["entries"][0]["unit"] = "elsewhere" + self._fails("unit not found") + + +class ProductionDataCategoryReassignmentTests(unittest.TestCase): + """The local build's manifest verifies; a verification failure FAILS. + + Missing build inputs are an explicitly reported skip. + """ + + ROOT = Path(__file__).resolve().parents[1] + + def setUp(self): + self.paths = { + "report": self.ROOT / "build" / "report.json", + "objdiff": self.ROOT / "objdiff.json", + "manifest": self.ROOT / "config" / "data_category_reassignments.json", + "target": self.ROOT / "build" / "split" / "source" / "linker_common.obj", + } + missing = [str(p) for p in self.paths.values() if not p.is_file()] + if missing: + self.skipTest("SKIPPED: local build inputs are unavailable: " + + ", ".join(missing)) + + def test_linker_common_non_halo_records_leave_the_halo_denominator(self): + report = json.loads(self.paths["report"].read_text(encoding="utf-8")) + before = copy.deepcopy(report) + notes = apply_data_category_reassignments( + report, self.ROOT, self.paths["manifest"], self.paths["objdiff"]) + self.assertEqual(notes, [ + "source/linker_common: halobetacache -1288 -> dsound +4, " + "libcmt +880, linker +96, xapilib +308 " + "(29 records: 1213 raw + 75 objdiff padding bytes)"]) + old = {c["id"]: int(c["measures"].get("total_data", 0)) + for c in before["categories"]} + new = {c["id"]: int(c["measures"].get("total_data", 0)) + for c in report["categories"]} + self.assertEqual(new["halobetacache"], old["halobetacache"] - 1288) + self.assertEqual(new["libcmt"], old["libcmt"] + 880) + self.assertEqual(new["xapilib"], old["xapilib"] + 308) + self.assertEqual(new["dsound"], old["dsound"] + 4) + self.assertEqual(new["linker"], 96) + self.assertEqual(sum(new.values()), sum(old.values())) + self.assertEqual(sum(new.values()), + int(before["measures"]["total_data"])) + self.assertEqual(report["measures"], before["measures"]) + self.assertEqual(report["units"], before["units"]) + for category in before["categories"]: + for key in ("matched_data", "complete_data", "matched_code", + "matched_functions", "total_units", "complete_units"): + self.assertEqual( + int(next(c for c in report["categories"] + if c["id"] == category["id"])["measures"] + .get(key, 0)), + int(category["measures"].get(key, 0))) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/test_semantic_progress.py b/tools/test_semantic_progress.py index d78821c3..e9ed8c77 100644 --- a/tools/test_semantic_progress.py +++ b/tools/test_semantic_progress.py @@ -1285,7 +1285,7 @@ class SemanticDataExtentModelTests(unittest.TestCase): ("negative matched", {"matched": -1}), ("non-numeric total", {"total": "13x"}), ("empty total", {"total": ""}), - ("non-ASCII digit total", {"total": "131"}), + ("non-ASCII digit total", {"total": "131"}), ("float total", {"total": 131.0}), ("boolean matched", {"matched": True})): with self.subTest(label=label): @@ -2437,6 +2437,729 @@ class SurplusProviderProofTests(unittest.TestCase): rescore_report_unit=trust_fixture_report(report)) +# Surplus-helper constants (the source/ai/actions shape). January's object for +# the unit imports a helper function; the rebuilt object carries its own +# select-any copy of the helper and of the two constants the helper loads, +# which January's object never names. The single January definer of the +# helper (the provider) holds the identical helper and the identical constants. +_HELPER = "_helper2d" +_CALLER = "_caller" +_C1 = _REAL +_C2 = "__real@3f1a36e2e0000000" +_C1_BYTES = b"\x00\x00\x80\x3f" +_C2_BYTES = bytes.fromhex("000000e0e2361a3f") +_SCN_CODE_COMDAT = _SCN_CODE_ALIGN16 | _SCN_COMDAT +# fld qword [C2]; fmul dword [C1]; ret; padding. +_HELPER_RAW = b"\xdd\x05" + bytes(4) + b"\xd8\x0d" + bytes(4) + b"\xc3" + b"\xcc" * 3 +_HELPER_RELOCS = ((2, _C2, _DIR32, 0), (8, _C1, _DIR32, 0)) +_SCN_DEBUG = 0x42100040 +_WRITE = 0x80000000 + + +def _helper_section(selection=_SELECT_ANY, relocs=_HELPER_RELOCS, + raw=_HELPER_RAW, symbols=((_HELPER, 0, 2),), + flags=_SCN_CODE_COMDAT): + return _v1_section(".text", raw, flags, symbols, relocs, selection=selection) + + +def _caller_section(extra_relocs=()): + # call _helper2d; ret; padding (bytes 6..15 can hold extra relocations). + raw = b"\xe8" + bytes(4) + b"\xc3" + b"\xcc" * 10 + return _v1_section(".text", raw, _SCN_CODE_ALIGN16, [(_CALLER, 0, 2)], + [(1, _HELPER, _REL32, -4)] + list(extra_relocs)) + + +def _c1(raw=_C1_BYTES, **options): + return _v1_literal(_C1, raw, **options) + + +def _c2(raw=_C2_BYTES, **options): + return _v1_literal(_C2, raw, code=options.pop("code", 4), **options) + + +class HelperFixture(V1Fixture): + """V1Fixture plus a surplus helper whose constants January never names. + + base: .data, xyz, C1, C2, abc, table, hello, w, .bss, caller, helper. + provider (January and rebuilt): xyz, helper, C1, C2. + """ + + SURPLUS = [_XYZ, _C1, _C2] + + def __init__(self): + super().__init__() + self.target.append(_caller_section()) + self.target_externals = self.target_externals + [_HELPER] + self.base.insert(2, _c1()) + self.base.insert(3, _c2()) + self.base.append(_caller_section()) + self.base.append(_helper_section()) + self.provider_target += [ + _helper_section(selection=_SELECT_NODUPLICATES), _c1(), _c2()] + self.provider_base += [_helper_section(), _c1(), _c2()] + self.addresses.update({_HELPER: 0x6200, _CALLER: 0x6300, _C2: 0x5108}) + self.provider_target_imports = [] + + def materialize(self, root): + # V1Fixture writes provider objects without imports; a provider that + # imports a name is written again with it (placeholders let the base + # writer resolve the name first). + if not self.provider_target_imports: + return super().materialize(root) + real = self.provider_target + self.provider_target = real + [ + _v1_literal(name, bytes(4)) for name in self.provider_target_imports] + try: + report = super().materialize(root) + finally: + self.provider_target = real + (Path(root) / "provider_target.obj").write_bytes( + _v1_coff(real, self.provider_target_imports)) + return report + + +def _retarget_relocation(data, obj, section_symbol, address, new_index): + """Byte-patch one relocation of ``section_symbol``'s section to symbol + index ``new_index`` (a spelling the fixture builder cannot express).""" + number = [item for item in obj["symbols"] + if item["name"] == section_symbol and item["section"] > 0][0]["section"] + section = obj["sections"][number - 1] + for index in range(section["reloc_count"]): + offset = section["reloc"] + 10 * index + if struct.unpack_from(" 0][0]["section"] + name = obj["sections"][number - 1]["name"] + return [item for item in obj["symbols"] + if item["section"] == number and item["name"] == name + and item["storage"] == 3][0]["index"] + + +_HELPER_PATH = (r"is not a January undefined reference of this unit: " + r"data_unit:__real@[0-9a-f]+ \(nor a verified surplus-helper " + r"constant: .*") + + +class SurplusHelperConstantTests(unittest.TestCase): + """Surplus constants reached only through a surplus helper (RF-CO). + + The controls credit exactly the fixture's report gap; every adversarial + case fails closed. ``helper_path=False`` marks a case an unchanged, + earlier check refuses before the helper path is reached. + """ + + def _rejects(self, mutate, pattern, helper_path=True, post_base=None): + fixture = HelperFixture() + mutate(fixture) + expected = (_HELPER_PATH + pattern) if helper_path else pattern + with self.assertRaisesRegex(SemanticProgressError, expected): + _run_fixture(fixture, post_base=post_base) + + # -- controls -------------------------------------------------------- + def test_control_helper_constants_credit_only_the_report_gap(self): + self.assertEqual(_run_fixture(HelperFixture()), + ["data_unit:v1-group (+56 data bytes)"]) + + def test_control_section_table_permutation(self): + # Section numbers are object-local: moving the helper and constants + # changes no name, byte or relocation, so it is not an identity change. + fixture = HelperFixture() + fixture.base.insert(1, fixture.base.pop()) + fixture.base.append(fixture.base.pop(4)) + fixture.provider_target.reverse() + self.assertEqual(_run_fixture(fixture), + ["data_unit:v1-group (+56 data bytes)"]) + + def test_january_imported_constant_skips_the_helper_path(self): + # January imports C1: the ordinary rule accepts it without the helper; + # C2 still takes the helper path, which now refuses a changed helper. + fixture = HelperFixture() + fixture.target_externals = fixture.target_externals + [_C1] + fixture.base[-1] = _helper_section(raw=b"\x90" + _HELPER_RAW[1:]) + with self.assertRaisesRegex( + SemanticProgressError, + _HELPER_PATH.replace("[0-9a-f]+", "3f1a36e2e0000000") + + "bytes or relocations differ from January provider"): + _run_fixture(fixture) + + # -- helper byte / relocation mismatch ------------------------------- + def test_helper_byte_differs_from_january_provider(self): + self._rejects(lambda f: f.provider_target.__setitem__( + 1, _helper_section(selection=_SELECT_NODUPLICATES, + raw=_HELPER_RAW[:12] + b"\xc2" + b"\xcc" * 3)), + "bytes or relocations differ from January provider") + + def test_helper_byte_differs_from_rebuilt_provider(self): + self._rejects(lambda f: f.provider_base.__setitem__( + 1, _helper_section(raw=_HELPER_RAW[:-1] + b"\x90")), + "bytes or relocations differ from rebuilt provider") + + def test_our_helper_byte_differs(self): + self._rejects(lambda f: f.base.__setitem__( + -1, _helper_section(raw=b"\xd9" + _HELPER_RAW[1:])), + "bytes or relocations differ from January provider") + + def test_helper_relocation_type_differs(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + relocs=((2, _C2, _DIR32NB, 0), (8, _C1, _DIR32, 0)))), + "bytes or relocations differ from January provider") + + def test_helper_relocation_addend_differs(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + relocs=((2, _C2, _DIR32, 0), (8, _C1, _DIR32, 4)))), + "bytes or relocations differ from January provider") + + def test_provider_helper_section_name_differs(self): + self._rejects(lambda f: f.provider_base.__setitem__(1, _v1_section( + ".text$mn", _HELPER_RAW, _SCN_CODE_COMDAT, [(_HELPER, 0, 2)], + _HELPER_RELOCS, selection=_SELECT_ANY)), + "section symbol table differs from rebuilt provider") + + def test_provider_helper_spells_the_constant_through_a_static_alias(self): + # The strict comparator and the image addresses both accept a static + # alias at the constant's offset; the relocation rows must not. + def mutate(fixture): + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, + relocs=((2, _C2, _DIR32, 0), (8, "_c1_alias", _DIR32, 0))) + fixture.provider_target[2]["symbols"].append(["_c1_alias", 0, 3]) + fixture.addresses["_c1_alias"] = 0x5100 + self._rejects(mutate, "relocates through a non-external symbol") + + def test_provider_helper_spells_the_constant_as_another_name_plus_addend(self): + # csplit-style "other external + addend" reaching the same address: + # strict comparator and image addresses agree, the names do not. + def mutate(fixture): + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, + relocs=((2, _C2, _DIR32, 0), (8, "_c1_tail", _DIR32, -4))) + fixture.provider_target[2]["symbols"].append(["_c1_tail", 4, 2]) + fixture.addresses["_c1_tail"] = 0x5104 + self._rejects(mutate, "relocation targets differ from January provider") + + def test_helper_relocation_without_image_address(self): + self._rejects(lambda f: f.addresses.pop(_C2), + "relocation has no image address") + + def test_helper_without_image_address(self): + self._rejects(lambda f: f.addresses.pop(_HELPER), + "image address unavailable") + + def test_helper_section_holds_another_symbol(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + symbols=((_HELPER, 0, 2), ("$L100", 12, 3)))), + "not a single-function helper") + + def test_helper_is_static(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + symbols=((_HELPER, 0, 3),))), "not an external at offset 0") + + def test_our_helper_is_not_select_any(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + selection=_SELECT_NODUPLICATES)), "has COMDAT selection 1") + + def test_our_helper_is_not_a_comdat(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + flags=_SCN_CODE_ALIGN16, selection=0)), "is not a code COMDAT") + + def test_rebuilt_provider_helper_is_not_select_any(self): + self._rejects(lambda f: f.provider_base.__setitem__(1, _helper_section( + selection=_SELECT_NODUPLICATES)), "has COMDAT selection 1") + + def test_january_provider_helper_other_selection(self): + self._rejects(lambda f: f.provider_target.__setitem__(1, _helper_section( + selection=5)), "has COMDAT selection 5") + + def test_provider_helper_alignment_differs(self): + self._rejects(lambda f: f.provider_base.__setitem__(1, _helper_section( + flags=0x60000020 | _align(6) | _SCN_COMDAT)), + "bytes or relocations differ from rebuilt provider") + + def test_helper_reaches_constant_through_its_section_symbol(self): + def post_base(data, obj): + _retarget_relocation(data, obj, _HELPER, 8, + _section_symbol_index(obj, _C1)) + self._rejects(lambda f: None, "relocation has no image address", + post_base=post_base) + + # -- constant mismatch (complete constant identity) ------------------ + def test_our_constant_differs(self): + def mutate(fixture): + fixture.base[2] = _c1(raw=b"\x01\x00\x80\x3f") + self._rejects(mutate, "constant '__real@3f800000' differs from " + "January provider") + + def test_january_provider_constant_differs(self): + self._rejects(lambda f: f.provider_target.__setitem__( + 2, _c1(raw=b"\x00\x00\x00\x3f")), + "constant '__real@3f800000' differs from January provider") + + def test_rebuilt_provider_constant_differs(self): + self._rejects(lambda f: f.provider_base.__setitem__( + 3, _c2(raw=bytes(8))), + "constant '__real@3f1a36e2e0000000' differs from rebuilt provider") + + def test_constant_section_name_differs(self): + self._rejects(lambda f: f.base.__setitem__(2, _v1_section( + ".rdata$r", _C1_BYTES, _SCN_RDATA | _SCN_COMDAT | _align(3), + [(_C1, 0, 2)], selection=_SELECT_ANY)), + "constant '__real@3f800000' differs from January provider") + + def test_constant_alignment_differs(self): + self._rejects(lambda f: f.base.__setitem__(3, _c2(code=5)), + "constant '__real@3f1a36e2e0000000' differs from " + "January provider") + + def test_provider_helper_imports_the_constant(self): + # The provider's January helper loads a C1 it does not define (another + # January object owns it): no identity against the provider exists. + def mutate(fixture): + del fixture.provider_target[2] + fixture.provider_target_imports = [_C1] + self._rejects(mutate, "constant '__real@3f800000' is not defined by " + "the January provider") + + def test_constant_referenced_by_another_name_in_the_provider(self): + other = "__real@3f800001" + + def mutate(fixture): + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, + relocs=((2, _C2, _DIR32, 0), (8, other, _DIR32, 0))) + fixture.provider_target.append(_v1_literal(other, _C1_BYTES)) + self._rejects(mutate, "bytes or relocations differ from January provider") + + # -- reordered sections / relocations -------------------------------- + def test_swapped_constant_references(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + relocs=((2, _C1, _DIR32, 0), (8, _C2, _DIR32, 0)))), + "bytes or relocations differ from January provider") + + def test_reordered_relocation_records(self): + self._rejects(lambda f: f.base.__setitem__(-1, _helper_section( + relocs=tuple(reversed(_HELPER_RELOCS)))), + "bytes or relocations differ from January provider") + + def test_provider_constants_exchanged_between_names(self): + # Two same-sized constants exchange values in the January provider: + # names, bytes and relocations of the helpers still agree, only the + # constant identity check can see it. + other = "__real@3f000000" + half = b"\x00\x00\x00\x3f" + + def mutate(fixture): + relocs = _HELPER_RELOCS + ((12, other, _DIR32, 0),) + raw = _HELPER_RAW[:12] + bytes(4) + fixture.base[-1] = _helper_section(relocs=relocs, raw=raw) + fixture.base.insert(4, _v1_literal(other, half)) + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, relocs=relocs, raw=raw) + fixture.provider_base[1] = _helper_section(relocs=relocs, raw=raw) + fixture.provider_target[2] = _c1(raw=half) + fixture.provider_target.append(_v1_literal(other, _C1_BYTES)) + fixture.provider_base.append(_v1_literal(other, half)) + fixture.addresses[other] = 0x5110 + fixture.SURPLUS = [_XYZ, _C1, _C2, other] + self._rejects(mutate, "constant '__real@3f800000' differs from " + "January provider") + + # -- constant also reached from non-helper sections ------------------ + def test_constant_also_referenced_by_january_defined_code(self): + self._rejects(lambda f: f.base.__setitem__(-2, _caller_section( + [(8, _C1, _DIR32, 0)])), "which January's unit defines") + + def test_constant_reached_by_section_symbol_from_other_code(self): + def post_base(data, obj): + _retarget_relocation(data, obj, _CALLER, 8, + _section_symbol_index(obj, _C1)) + self._rejects(lambda f: f.base.__setitem__(-2, _caller_section( + [(8, _C2, _DIR32, 0)])), "which January's unit defines", + post_base=post_base) + + def test_constant_referenced_from_a_debug_section(self): + self._rejects(lambda f: f.base.append(_v1_section( + ".debug$S", bytes(8), _SCN_DEBUG, [], [(4, _C1, 0x0B, 0)])), + "reached from non-code section") + + def test_constant_referenced_by_a_second_unverified_helper(self): + # A second rebuilt-only select-any helper January never imports. + self._rejects(lambda f: f.base.append(_helper_section( + symbols=(("_helper3d", 0, 2),))), + "helper '_helper3d' is not a January undefined reference") + + # -- helper not imported by January's unit --------------------------- + def test_helper_not_named_by_january_unit(self): + def mutate(fixture): + fixture.target_externals = [name for name in fixture.target_externals + if name != _HELPER] + fixture.target[-1] = _v1_section( + ".text", b"\xc3" + b"\xcc" * 15, _SCN_CODE_ALIGN16, + [(_CALLER, 0, 2)]) + self._rejects(mutate, "helper '_helper2d' is not a January undefined " + "reference of this unit\\)") + + def test_helper_named_but_never_relocated_by_january_unit(self): + self._rejects(lambda f: f.target.__setitem__(-1, _v1_section( + ".text", b"\xc3" + b"\xcc" * 15, _SCN_CODE_ALIGN16, + [(_CALLER, 0, 2)])), "never relocates to helper") + + def test_helper_defined_by_january_unit(self): + def mutate(fixture): + fixture.target_externals = [name for name in fixture.target_externals + if name != _HELPER] + fixture.target.append(_helper_section( + selection=_SELECT_NODUPLICATES, relocs=())) + self._rejects(mutate, "'_helper2d', which January's unit defines") + + # -- multiple / unauthenticated providers ---------------------------- + def test_helper_has_two_january_definers(self): + def mutate(fixture): + fixture.other_sections = [ + _v1_section(".bss", bytes(8), _SCN_BSS | _align(3), + [("_bss_var", 0, 2)]), + _helper_section(selection=_SELECT_NODUPLICATES, relocs=())] + self._rejects(mutate, "provider 'provider_unit' is not January's " + "unique definer \\(definers \\['other_unit', " + "'provider_unit'\\]\\)") + + def test_helper_has_no_january_definer(self): + self._rejects(lambda f: f.provider_target.pop(1), + "not January's unique definer \\(definers \\[\\]\\)") + + def test_constant_names_a_provider_that_does_not_define_the_helper(self): + def mutate(fixture): + entry = fixture.entry() + for item in entry["surplus"]: + if item["symbol"] == _C1: + item["provider"] = "other_unit" + fixture.entries = [entry] + self._rejects(mutate, "provider 'other_unit' is not January's unique " + "definer") + + def test_constant_names_its_own_unit_or_a_missing_unit(self): + for provider in ("data_unit", "missing_unit"): + with self.subTest(provider=provider): + def mutate(fixture, provider=provider): + entry = fixture.entry() + for item in entry["surplus"]: + if item["symbol"] == _C1: + item["provider"] = provider + fixture.entries = [entry] + self._rejects(mutate, "invalid provider") + + def test_missing_january_provider_object(self): + fixture = HelperFixture() + with tempfile.TemporaryDirectory() as root: + report, arguments = _materialize(fixture, root) + (Path(root) / "provider_target.obj").unlink() + with self.assertRaisesRegex(SemanticProgressError, + "January object missing"): + apply_semantic_data_matches( + report, *arguments, + rescore_report_unit=trust_fixture_report(report)) + + def test_constant_has_another_january_definer(self): + # The helper's provider is unique, but another January object also + # defines the constant: the unchanged provider check still refuses. + def mutate(fixture): + fixture.other_sections = [ + _v1_section(".bss", bytes(8), _SCN_BSS | _align(3), + [("_bss_var", 0, 2)]), _c1()] + self._rejects(mutate, "__real@3f800000 \\(definers " + "\\['other_unit', 'provider_unit'\\]\\)", + helper_path=False) + + # -- unrelated surplus data riding along ----------------------------- + def _extra_constant(self, fixture, extra): + fixture.base.insert(4, _v1_literal(extra, b"\x00\x00\x00\x40")) + fixture.provider_target.append(_v1_literal(extra, b"\x00\x00\x00\x40")) + fixture.provider_base.append(_v1_literal(extra, b"\x00\x00\x00\x40")) + fixture.addresses[extra] = 0x5120 + + def test_unreferenced_surplus_constant(self): + def mutate(fixture): + self._extra_constant(fixture, "__real@40000000") + fixture.SURPLUS = [_XYZ, "__real@40000000", _C1, _C2] + self._rejects(mutate, "no rebuilt section references it") + + def test_surplus_constant_used_only_by_january_defined_code(self): + def mutate(fixture): + self._extra_constant(fixture, "__real@40000000") + fixture.base[-2] = _caller_section([(8, "__real@40000000", _DIR32, 0)]) + fixture.SURPLUS = [_XYZ, "__real@40000000", _C1, _C2] + self._rejects(mutate, "which January's unit defines") + + def test_extra_constant_loaded_only_by_our_helper(self): + def mutate(fixture): + self._extra_constant(fixture, "__real@40000000") + fixture.base[-1] = _helper_section( + relocs=_HELPER_RELOCS + ((12, "__real@40000000", _DIR32, 0),), + raw=_HELPER_RAW[:12] + bytes(4)) + fixture.SURPLUS = [_XYZ, _C1, _C2, "__real@40000000"] + self._rejects(mutate, "bytes or relocations differ from January provider") + + def test_writable_data_reached_only_by_the_helper(self): + self._rejects(lambda f: f.base.__setitem__(2, _c1( + flags=_SCN_RDATA | _WRITE | _SCN_COMDAT | _align(3))), + "not a read-only constant") + + def test_relocated_constant_reached_only_by_the_helper(self): + self._rejects(lambda f: f.base.__setitem__(2, _v1_section( + ".rdata", _C1_BYTES, _SCN_RDATA | _SCN_COMDAT | _align(3), + [(_C1, 0, 2)], [(0, "_ext_function", _DIR32, 0)], + selection=_SELECT_ANY)), "not a read-only constant") + + def test_helper_loads_code_this_unit_defines(self): + def mutate(fixture): + relocs = _HELPER_RELOCS + ((12, _CALLER, _DIR32, 0),) + raw = _HELPER_RAW[:12] + bytes(4) + fixture.base[-1] = _helper_section(relocs=relocs, raw=raw) + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, relocs=relocs, raw=raw) + fixture.provider_base[1] = _helper_section(relocs=relocs, raw=raw) + fixture.provider_target.append(_caller_section()) + fixture.provider_base.append(_caller_section()) + self._rejects(mutate, "relocates to '_caller', which is not a data " + "constant") + + def test_helper_target_in_a_section_that_does_not_exist(self): + # A malformed rebuilt symbol (section number past the section table) + # is refused with the verifier's error, never an IndexError. + def mutate(fixture): + relocs = _HELPER_RELOCS + ((12, "_x_far", _DIR32, 0),) + raw = _HELPER_RAW[:12] + bytes(4) + fixture.base[-1] = _helper_section(relocs=relocs, raw=raw) + fixture.base_externals = fixture.base_externals + ["_x_far"] + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, relocs=relocs, raw=raw) + fixture.provider_base[1] = _helper_section(relocs=relocs, raw=raw) + fixture.provider_target.append(_v1_literal("_x_far", bytes(4))) + fixture.provider_base.append(_v1_literal("_x_far", bytes(4))) + fixture.addresses["_x_far"] = 0x5130 + + def post_base(data, obj): + index = [item for item in obj["symbols"] + if item["name"] == "_x_far"][0]["index"] + symbol_offset = struct.unpack_from(" 0][0] + index = _append_weak_external(data, "_w_c1", default["index"]) + _retarget_relocation(data, obj, _CALLER, 6, index) + with self.assertRaisesRegex(SemanticProgressError, + _HELPER_PATH + "has a weak external"): + _run_fixture(fixture, post_base=weak) + + def test_alternatename_directive_fails_closed(self): + fixture = HelperFixture() + fixture.base[-2] = _caller_section([(6, "_alias_c1", _DIR32, 0)]) + fixture.base_externals = fixture.base_externals + ["_alias_c1"] + fixture.base.append(_v1_section( + ".drectve", b" /ALTERNATENAME:_alias_c1=" + _C1.encode() + b" ", + 0x00100A00, [])) + with self.assertRaisesRegex( + SemanticProgressError, + _HELPER_PATH + "has an /ALTERNATENAME directive"): + _run_fixture(fixture) + + def _set_addend(self, fixture, address, addend): + relocs = [list(item) for item in _HELPER_RELOCS] + for item in relocs: + if item[0] == address: + item[3] = addend + fixture.base[-1] = _helper_section(relocs=relocs) + fixture.provider_target[1] = _helper_section( + selection=_SELECT_NODUPLICATES, relocs=relocs) + fixture.provider_base[1] = _helper_section(relocs=relocs) + + def test_helper_addressing_past_the_constant_fails_closed(self): + # all three helpers load C1+4: the four bytes after C1, whose identity + # nothing proves + fixture = HelperFixture() + self._set_addend(fixture, 8, 4) + with self.assertRaisesRegex( + SemanticProgressError, + _HELPER_PATH + "relocation at 0x8 addresses outside constant"): + _run_fixture(fixture) + + def test_control_helper_addressing_inside_the_constant(self): + # C2 is 8 bytes: C2+4 (its high dword) is inside the proved bytes + fixture = HelperFixture() + self._set_addend(fixture, 2, 4) + self.assertEqual(_run_fixture(fixture), + ["data_unit:v1-group (+56 data bytes)"]) + + def test_helper_reaching_the_constant_through_an_undefined_duplicate(self): + # ours also carries an undefined C1 entry and the helper relocates + # through it: the reach scan matches the name, the comparator and the + # image addresses agree, only "C1 is among the helper's constants" + # refuses (RF-CO's surviving mutant M18 is not implied). + fixture = HelperFixture() + fixture.base_externals = fixture.base_externals + [_C1] + + def undefined(data, obj): + index = [item for item in obj["symbols"] + if item["name"] == _C1 and item["section"] == 0][0]["index"] + _retarget_relocation(data, obj, _HELPER, 8, index) + with self.assertRaisesRegex( + SemanticProgressError, + _HELPER_PATH + "does not reference it by name"): + _run_fixture(fixture, post_base=undefined) + + +class ActionsHelperConstantProductionTests(unittest.TestCase): + """The real source/ai/actions shape on the local build (skips without it).""" + + ROOT = Path(__file__).resolve().parents[1] + UNIT = "source/ai/actions" + CONSTANTS = ("__real@3f800000", "__real@3f1a36e2e0000000") + + def setUp(self): + objdiff = self.ROOT / "objdiff.json" + symbols = self.ROOT / "config" / "symbols.json" + if not objdiff.is_file() or not symbols.is_file(): + self.skipTest("SKIPPED: local build inputs are unavailable") + self.config_units = {unit["name"]: unit for unit in json.loads( + objdiff.read_text(encoding="utf-8"))["units"]} + unit = self.config_units.get(self.UNIT) + paths = [self.ROOT / unit[key] for key in ("target_path", "base_path")] \ + if unit else [] + if not paths or not all(path.is_file() for path in paths): + self.skipTest("SKIPPED: actions objects are unavailable") + self.target, self.base = (load(path) for path in paths) + self.addresses = semantic_progress.image_symbol_addresses(json.loads( + symbols.read_text(encoding="utf-8"))) + + def _verify(self, provider, addresses=True): + items = [{"symbol": name, "provider": provider, "measurements": {}} + for name in self.CONSTANTS] + semantic_progress._verify_surplus_providers( + self.ROOT, self.config_units, self.target, self.base, self.UNIT, + items, self.addresses if addresses else None) + + def test_helper_constants_verify_against_action_charge(self): + try: + self._verify("source/ai/action_charge") + except SemanticProgressError as error: + self.fail(f"actions helper constants do not verify: {error}") + + def test_helper_constants_refuse_another_provider(self): + with self.assertRaisesRegex(SemanticProgressError, + "is not January's unique definer"): + self._verify("source/ai/action_obey") + + def test_helper_constants_refuse_without_image_addresses(self): + with self.assertRaisesRegex(SemanticProgressError, + "no image symbol addresses"): + self._verify("source/ai/action_charge", addresses=False) + + class ProductionSemanticDataManifestTests(unittest.TestCase): """The local build's manifest verifies; a verification failure FAILS.