matiaszanolli

Fallout 3 Compatibility Audit

"Per-game audit of Fallout 3 compatibility — NIF v20.2.0.7, BSA v104, ESM via FNV-shared parser"

matiaszanolli 28 3 Updated 1w ago
GitHub

Install

npx skillscat add matiaszanolli/byroredux/claude-commands-audit-fo3

Install via the SkillsCat registry.

SKILL.md

Fallout 3 Compatibility Audit

FO3 rides the FNV path almost end-to-end (NIF v20.2.0.7 / BSVER 34, BSA v104, one ESM parser, one cell loader, one RT pipeline). This is NOT a re-run of /audit-fnv: it hunts the divergences — where FO3 content exercises a path FNV doesn't, where shared code carries an FNV-only assumption, and where a feature is verified on FNV but only assumed on FO3. Its data goes through shared mechanisms owned elsewhere (.claude/commands/_audit-owners.md); a defect in the mechanism is filed against its owner, but tag its FO3 reach: a shared-code regression hits all four classic games (the 2026-09-19 HIGH did).

Architecture: Orchestrator. Each dimension runs as a Task agent (max 3 concurrent).

Read .claude/commands/_audit-common.md (layout, methodology, dedup, finding format) and .claude/commands/_audit-severity.md for shared protocol.

Game Context

Aspect State
NIF / BSA v20.2.0.7 BSVER 34 · BSA v104 · 7 mesh/texture archives (base + 5 DLC - Main.bsa)
Parse baselines (pull) crates/nif/tests/data/per_block_baselines/fallout_3.tsv (17 172 NIFs, 6 mesh archives, 145 types, 0 unknown — the gate walks open_all_mesh_archives, #3041), ROADMAP.md FO3 row, docs/feature-matrix.md, .claude/audit-baselines/runtime/fo3-MegatonPlayerHouse.tsv
Reference data /mnt/data/SteamLibrary/steamapps/common/Fallout 3 goty/Data/
FO3 vs FNV Both are GameKind::Fallout3NV. The only discriminator is CharacterRulesProfile (FALLOUT3 vs FALLOUT_NEW_VEGAS, #4448). A divergence branch keyed on GameKind cannot tell them apart; pins: obscript_dialect_follows_the_profile_not_the_game_kind (byroredux/src/cell_loader/references/attach.rs), fn586_condition_gate_is_profile_scoped_not_game_scoped (crates/plugin/src/consumables.rs)

Authoring census (measured — each line is a checklist premise that has already rotted once; re-measure before asserting the opposite):

  • Inline shader stack only: 0 BGSM/BGEM in the FO3 archives; 0 bump_texture; no bump-tiling field exists on any BSShader*Property.
  • 0 XATO / XTNM / XTXR in Fallout3.esm — no REFR texture overlays (#3511); byroredux/src/cell_loader/refr_texture_overlay_tests.rs fixtures are FO4-shaped and prove nothing about FO3.
  • Fallout3.esm: 718 952 records (HEDR.numrec 808 699 = records + GRUPs + the TES4 header), 1 257 SCPT, 54 SCOL bases / 389 REFRs, 244 TXST records (243 parsed — Bethesda's own NullTextureSet is skipped), 51 LTEX all carrying TNAM (the 51 landscape_texture_sets entries).
  • NIF: 1 374 BSSegmentedTriShape (#3101's "zero" measured one archive), 112 bhkConvexListShape chains, 0 bhkMultiSphereShape, B-splines are 83% of base-archive .kf — never rule them out by era.
  • Object LOD: 114 <world>.levelN.high.x<X>.y<Y>.nif quads that no code path consumes (54 in Fallout - Meshes.bsa — 28 washmontop.level8, 26 wasteland.level4; 60 in Anchorage - Main.bsa), every one with a plain sibling — censused-not-consumed by design (#4468, closed; probe_lod_corpus).
  • Known-open, do not re-file (gh issue view first): #4772 (a copied-save restore's first ragdoll solve throws the root to ~1e12 BU on FO3; the recovery masks it, Dim 5), #5642 (force-greet pass 2 opens every in-radius greeter against a stale open_partner snapshot, Dim 2/5), #5669 (the #5400 header census gates only Oblivion textures\menus\, not FO3/FNV textures\interface\, Dim 4). Every FO3 finding of the 2026-10-08/09 audits is fixed — verify, don't re-file: #5428 (kill-script provenance follows the load order's last-writer table, 335a0179c, Dim 2), #5429 (FO3 dialogue real-data floor + declared dt1 SKIP, c6e48cbc6, Dim 2/5), #5433 (the FO3 profile mounts Fallout - Sound.bsa + Fallout - Voices.bsa + Fallout - MenuVoices.bsa, 4ef386a1e, Dim 2), #5521 (voice names truncate only over 25, 4d6294bb1, Dim 2), #5494 (an override's PNAM-less INFO heads fold in authored file order, 5356c8780, Dim 2), #5499 (package selection continues past a fail-open Dialogue decline, f7ca4a60f, Dim 5), #5500 (Eat/Sleep Near-Linked-Reference / In-Cell anchors, bcaf63aa8, Dim 5), #5496 (LOD rings key on the PNAM "Use LOD Data" ancestor, 2ca57c4bc, Dim 3), #5518 (legacy quad-index scan keys on either family table, 5a549e664, Dim 3), #5520 (prune tie-break on authored-cell coverage, a9577fd69, Dim 3), #5073 (empty compressed BSA placeholders extract as empty files, fa2af0e89, Dim 4). Fixed 2026-10-08..09: #5387 (same-level LOD leftovers pruned, fbf1bed74, Dim 3), #5393 + #5395 (voice owner + file name, 5b68792b7, Dim 2), #5390 (legacy sleep = sit fallback, 9bdfdd1c6, Dim 5), #5423 (LOD rings + climate on the layout table, b3e679dba, Dim 3). Fixed 2026-09-29..10-05: #4469 (INFO DATA decoded, cc9353043), #5005 + #5223 + #5248 + #5304 (corpses, Dim 2), #5222 (legacy LOD quad index, b7987d813, Dim 3), #5224 (DIAL Top-level flag, 305363122), #5225 (LOD census, 4e9cf87b9), #5226 (unmatched --wrld errors, c6cbbe9f9), #5238 (NPC Health curve, c71eeed80), #5271 (per-INFO QSTI quest gate, dbc07e8f0). Older guards: #4398 (emitter orientation), #4401 (clamp/parallax re-latch), #4468 (.high. quads), #4122 (SPT tail desync, /audit-speedtree).

Parameters (from $ARGUMENTS)

--focus <dimensions>: comma-separated numbers (e.g. 1,4). Default: all 5.

Phase 1: Setup

  1. Parse $ARGUMENTS; mkdir -p /tmp/audit/fo3.
  2. Dedup baseline: gh issue list --repo matiaszanolli/ByroRedux --limit 200 --json number,title,state,labels > /tmp/audit/issues.json.
  3. Confirm Fallout 3 goty/Data/ exists; if not, name the dimensions that lose real-data validation.
  4. Run the real-data lane first — it is the only guard for shared-code regressions on FO3 and no CI lane runs it: cargo test -p byroredux-nif --release --test parse_real_nifs --test per_block_baselines --test block_coverage_baselines -- --ignored fallout_3 real_archive_torch. A red gate is the headline finding; dimension agents then explain it.
  5. Reconcile every count against the tables above and the ROADMAP/feature-matrix rows. Measure across all archives (base + DLC), never the base archive alone.
  6. Scope by delta: git log --since=<last AUDIT_FO3 date> --format='%h %cs %s' -- <dimension Paths>.
  7. Toolchain: the byroredux bin crate needs rustc >= 1.96 (wasmtime 49, 15a6b1d2d) — rustup cargo per docs/contributing.md § Toolchain note (#4466).

Phase 2: Launch Dimension Agents (parallel)

Dimension 1: NIF, Inline-Shader Material & Collision — FO3 Authoring

Subagent: legacy-specialist
Routing: block decode /audit-nif; single-boundary / no-fabrication / particle + collision translation /audit-nifal; Disney-BSDF gate (MAT_FLAG_PBR_BSDF must be 0, FO3 authors no BGSM) /audit-renderer; solver + phantoms /audit-physics.
Paths: crates/nif/src/blocks/shader/, crates/nif/src/blocks/particle.rs, crates/nif/src/shader_flags.rs, crates/nif/src/import/material/, crates/nif/src/import/collision/, crates/nif/src/import/walk/emitter.rs, byroredux/src/material_translate.rs
First step: the Phase 1 lane, plus git log --since=<date> -- crates/nif/src/import crates/nif/src/blocks/shader

  • FO3 shader properties use the BSShaderFlags F1 + BSShaderFlags2 F2 pair (fo3nv_f1 / fo3nv_f2 in shader_flags.rs) — never the Skyrim/FO4 vocabularies (same numeric bits, different meaning). Both properties are field-for-field with nif.xml on every BSVER gate (14/24/26/34).
  • Texture precedence: a BSShaderTextureSet outranks NiTexturingProperty for base + normal (#4235; census: 3 703 NoLighting base co-binds all name the identical path). Clamp mode + parallax pair re-latch with it (#4401; displacing_the_base_path_re_latches_the_clamp_mode, legacy_property_precedence_tests.rs).
  • BSShaderNoLightingProperty -> MATERIAL_KIND_NO_LIGHTING (102) fullbright with no distance term (crates/renderer/shaders/triangle.frag); decal bits honored on both properties; two-sided comes from NiStencilProperty (no FO3 flag bit); legacy emissive is EmissiveSource::Material only.
  • BSSegmentedTriShape decodes the nif.xml 9-byte segment layout and feeds the plain NiTriShape geometry arm; segment (dismemberment) metadata is consumed-and-discarded by design — route to /audit-nifal + /audit-character when a consumer exists.
  • Emitter birth rate: FO3's leg of real_archive_torch_meshes_surface_particle_emitters (crates/nif/tests/parse_real_nifs.rs, --ignored) must hold its per-game floor. #4261 broke it on every game from 2026-09-12 to 2026-09-19 (#4467) because the fix ran only the default lane — any change under walk/ or blocks/particle.rs needs this lane. Spawn cones follow the emitter's composed orientation (#4398; flat_walker_composes_the_emitter_rotation).
  • Collision: all FO3 chains classify CollisionAuthoring::Classic; havok_motion_type keeps BOX_INERTIA crates Dynamic (1 612 in FO3); every FO3-authored bhk shape kind has a resolve_shape arm (a new dispatch arm needs a resolve arm).
    Output: /tmp/audit/fo3/dim_1.md

Dimension 2: ESM Data Slice (Fallout3.esm)

Subagent: general-purpose
Routing: GRUP walk, SubReader accounting, dispatch, remap /audit-esm. This dimension owns FO3-only authoring and its counts.
Paths: crates/plugin/src/esm/records/, crates/plugin/src/esm/cell/, crates/plugin/tests/parse_real_esm.rs
First step: cargo test -p byroredux-plugin --release --test parse_real_esm -- --ignored parse_rate_fo3_esm (one test at a time; whole-file --ignored runs can spike >20 GB).

  • Baseline (#3756): index.total() >= FO3_TOTAL_FLOOR (44 000) is an index-sum over ~95 typed maps that double-counts by design — NOT a file record count. Also floor the cell tier index.total() cannot see: placed refs >= 573 000 (REFR 568 107 + ACHR 2 154 + ACRE 3 349 + PGRE 350) and exterior cells >= 41 900; 0 walker errors on the master and all 5 DLCs. Never cite "44 657" or "13 684".
  • FO3 is a strict subset of FNV's NPC_/DIAL/INFO subforms (sole FO3-only subform INFO.SNDD, 1 record) and shares CELL.XCLL (XCLL_SIZES_FALLOUT_ERA, FO3 {36,40}); the SCOL gate is_scol_era must keep FO3 dispatching (54 bases / 389 REFRs). SCHR u16 tail: see /audit-fnv Dim 2.
  • The one FO3 TXST consumer is LTEX.TNAM -> TXST -> TX00 -> EsmCellIndex.landscape_texture_sets (terrain splat diffuse); the other ~192 parsed TXST have no live consumer on this title.
  • Dialogue decode (consumer: byroredux/src/systems/npc_dialogue.rs, /audit-gameplay): INFO DATA stores the type byte + raw u16 flags on all 22 327 INFOs, the per-game reading left to the consumer (#4469, cc9353043; parse_info_data_header_decodes_type_and_flags); DIAL DATA byte 1 is the Rumors 0x01 / Top-level 0x02 flags — only 844 of 5 130 Topic DIALs are top-level, the rest link-only (#5224, 305363122). INFO QSTI is decoded into InfoRecord.quest (all 23 247 measured FNV INFOs author it) and gates each INFO on its own quest's running state, ordered by quest priority via DialogueQuestPriorities (#5271, dbc07e8f0; a_stopped_quests_info_does_not_speak_through_a_running_sibling, byroredux/src/systems/npc_dialogue.rs). INFO-side SNAM, NEXT and the script family are still undecoded (none consumer-blocking).
  • #5367 runtime on FO3 (shared path; the only live gate, docs/smoke-tests/dt1-dialogue-layers.sh, is FNV — dt1 fo3 is a declared SKIP, exit 77, never a pass, #5429, c6e48cbc6; FO3's data premises are floored instead by the --ignored dialogue_greeting_and_forcegreet_fo3_floor in crates/plugin/tests/parse_real_esm.rs: literal GREETING >= 2 500 INFOs + HELLO, >= 380 Dialogue-procedure PACKs (386 measured), >= 22 000 INFOs (22 327) with 0 quest-less; a measured FO3 cell / NPC / PACK live pin is the open work): the generic GREETING fallback (one GREETING/HELLO DIAL per FO3 plugin, resolved once per load order as EsmIndex::generic_greeting_form, #5426); the positional Random stack, closed by a passing plain line or Random End (Flags1 bit 5 on TES4/FO3/FNV; #5397, 0436bea5c; pins in crates/scripting/src/dialogue.rs); DLC DIAL overrides fold their INFOs into the master topic by FormID instead of replacing it (#5375, 168b81322; dialogue_override_folds_infos_into_the_master_topic), an override's PNAM-less head run composing in authored file order behind a per-override contribution cursor (#5494, 5356c8780 — The Pitt's 93 heads no longer let "Go away." outrank 92 greetings). Voice (byroredux/src/systems/dialogue_voice.rs): the owning plugin resolves through GlobalFormIdResolver (#5393), the name cuts the quest EDID to 10 and the topic to a 25-char total only when quest + topic exceed 25, otherwise full EDIDs, one candidate (#5521, 4d6294bb1), writes the plugin-local id and each segment's authored response number (19 FO3 INFOs skip 1..k) (#5395, 5b68792b7; 11 955 / 11 955 joinable Fallout3.esm lines resolve, 2026-10-09; pins voice_path_candidates_truncate_only_over_the_length_limit, voice_owner_resolves_masters_before_the_esm); a topic change or conversation close cuts the playing line (#5432, 40b77828b). The FO3 profile (assets/debug_profiles.toml, [profiles.fo3]) mounts Fallout - Sound.bsa, Fallout - Voices.bsa and Fallout - MenuVoices.bsa as default_sounds_bsas (#5433, 4ef386a1e; pin fo3_profile_declares_sound_and_voice_archives in crates/game-detect/src/lib.rs); fo3.env still passes only Fallout - Sound.bsa. PKDD Dialogue Type is the u32 at offset 16 (19 FO3 Say-To packages), so the #5376 Say-To decline gate fires (#5492, dae08000d).
  • Authored corpses (mechanism /audit-gameplay): base DATA health <= 0 marks 498 FO3 placements (#5005, fo3_corpses_key_on_base_health_not_xrgd), and the 85 dismember-trigger XLKR targets + 3 self-killing bases are recognised at load because no FO3 object script runs (#5223, 717f39a82; fo3_fnv_script_killed_corpses_match_the_measured_census). The set is computed once per load order over every cell (interior, grid, worldspace-persistent) as the ScriptKilledCorpseForms resource, because a trigger and its persistent target never share a load_references_budgeted call (#5248, d4e8c31be; the union-over-all-cells census cannot see locality, so a per-call regression passes it). Recognition needs one of the 11 exact shipped GenericBiped*DismembermentSCRIPT EDIDs **and** a winning SCPT that resolves to a vanilla master, so name-alikes decline (#5304, 2d47bf7f1; kill_on_load_recognition_requires_exact_edid_and_vanilla_master). A true override patch keeps the master's FormID, so script_is_vanilla consults the LoadOrder script_winners last-writer table (SCPT FormID -> position of the last plugin that wrote it) rather than the FormID's slot byte, and declines it (#5428, 335a0179c; kill_on_load_recognition_declines_a_true_override_of_a_vanilla_script, both passes); the slot owner is only the fallback for hand-built orders with no writer table. The whole-load-order scan returns the empty set up front off FO3/FNV (#5450, eaac75911). NPC Health seeds from the authored NPC curve (#5238; Nova = 40.0, Three Dog 25); a non-auto-calc NPC (ACBS bit 4 clear; ~712 FO3 actors) seeds its authored DATA SPECIAL (NpcRecord::data_attributes) instead of the class ATTR (#5338, 4957536ba).
    Output: /tmp/audit/fo3/dim_2.md

Dimension 3: Cell Loading — Interior + Exterior

Subagent: general-purpose
Routing: terrain / WTHR / water / LOD mechanism /audit-exterior; unload hygiene /audit-safety Dim 3.
Paths: byroredux/src/cell_loader/ (load, unload, exterior, references/, spawn), byroredux/src/scene/, byroredux/src/cell_loader/legacy_lod_index.rs, crates/plugin/src/esm/cell/wrld.rs, docs/engine/exterior-readiness-plan.md
First step: git log --since=<date> --format='%h %cs %s' -- byroredux/src/cell_loader byroredux/src/scene crates/plugin/src/esm/cell

  • Interior MegatonPlayerHouse: 929 REFRs parse-side (never the stale 1609); fixture cell MegatonMoriartysSaloon 458 REFRs. GPU entity/FPS numbers come only from a Vulkan run — record "not measured" otherwise.
  • Exterior (Capital Wasteland): worldspace selection is data-driven (select_worldspace_key, deterministic tie-break; --wrld overrides #444's heuristic, and an unmatched --wrld now errors naming the loaded EDIDs instead of silently loading Wasteland's copy of the cell — #5226, c6cbbe9f9) — FO3 data has no wastelandnv EDID, so an FNV-first preference can never mis-pick; wrld.rs must hold no hardcoded worldspace name, origin or grid. Every GameKind use on the load path is asset-family classification, not a behavior branch. Gate: docs/smoke-tests/m-exteriors.sh fo3 (MegatonWorld); last measured figures in exterior-readiness-plan.md (no FO3 scene is in the ROADMAP bench-of-record table). Default land texture is DirtWasteland01.dds (DefaultLandTexture::for_game).
  • Object LOD is ObjectLodScheme::FalloutLegacyBlocks (placement_lod_supported is Oblivion-only). It is not a flat ring (#3502): 7 of FO3's 15 worldspaces bake level-8 object quads with no level-4 sibling (93 of the 366 plain quads in Fallout - Meshes.bsa — its 422 blocks\ entries also carry 54 .high. variants and 2 …postapocalypse.nif, variant files not quads; 366 base + 331 DLC = 697 plain corpus-wide: dcworld01/03/06/12/17, paradisefalls, washmontop); LodBandSelection::coarsen_to_available must stay **object-only** (terrain keeps subdividing — object_lod.rs true / terrain_lod.rs false) and those worldspaces must show distant buildings inside 16 cells — the legacy family no longer derives a grid origin (#5222, b7987d813): 26 of 29 worldspace/level sets sit off (0,0) with no single origin, so LegacyLodQuadIndex (byroredux/src/cell_loader/legacy_lod_index.rs) scans the archive name tables once per streaming state and select_authored_lod_quads (lod_bands.rs) picks quads by footprint (objects from the mesh BSAs, terrain from the diffuse DDS names, .high. variants riding their plain sibling; terrain tops up uncovered ring ground with level-4 synth tiles). Selection first keeps each level's majority lattice residue (prune_same_level_overlaps): six FO3 worldspaces ship same-level quads from different LOD generations whose footprints and geometry overlap — washmontop 65 overlapping pairs among 37 level-8 quads (#5387, fbf1bed74; same_level_leftover_generation_quads_are_pruned; a count tie in the residue vote goes to the class whose footprints cover more of the LOD source worldspace's authored exterior cells, residue order only on a coverage tie (#5520, a9577fd69; lod_source_cell_exists threads through select_authored_lod_quads from both ring call sites; exal.md keeps open which lattice the shipped game loads). The terrain ring gates on terrain_lod_layout (FalloutLegacy), not GameKind::Fallout3NV (#5423, b3e679dba); the quad-index scan (should_scan_legacy_lod_quads, byroredux/src/streaming_helpers.rs) fires when either the terrain-layout or the object-scheme table selects the legacy family (#5518, 5a549e664). **LOD-inheriting children**: WRLD PNAM bit 0x02 ("Use LOD Data") children — all four FO3 roof / vista worldspaces (StatesmanRoofWorld, GNRroofWorld, …) author zero quads — resolve every distant-ring key (legacy quad index, object archive paths, .btr paths, generated distant textures + worldspace form id, band bounds) on ExteriorWorldContext::lod_worldspace_key(), the nearest WNAM ancestor that does not set the bit (lod_source_worldspace, byroredux/src/env_translate/lod.rs); full-detail residency stays on the child (#5496, 2ca57c4bc; installed-FO3 pin walks StatesmanRoofWorld -> Wasteland). worldspace_lod_grid_origin (byroredux/src/cell_loader/lod_support.rs) still returns (0,0) for non-combined-LOD games but only the synth/placement grids consume it. Real-data pins (--ignored, byroredux/src/cell_loader/legacy_lod_index_tests.rs): dcworld03_level8_quads_select_near_the_worldspace_centre, washmontop_level8_spans_multiple_residues_and_all_select (name predates #5387 — it now pins the majority-generation selection and that no two selected same-level quads overlap).
  • CachedNifImport Arc cache: no re-parse and no leak across FO3 unload/load cycles.
    Output: /tmp/audit/fo3/dim_3.md

Dimension 4: BSA v104 & Real-Data Validation

Subagent: general-purpose
Routing: reader discipline /audit-parsers. FO3's BSA is byte-identical in format to FNV's — a divergence here is a v104 regression, not a format gap.
Paths: crates/bsa/src/archive/, crates/facegen/, crates/spt/, crates/nif/examples/nif_stats.rs
First step: cargo test -p byroredux-bsa --release --test ba2_real -- --ignored fo3_bsa_corpus_opens_and_lists (#4665 — FO3's only committed BSA guard, in ba2_real.rs; it opens and lists every FO3 .bsa but extracts nothing, so extraction is still checked by sweep) and --test bsa_real -- --ignored fnv_meshes_bsa_v104.

  • Sweep every FO3 archive: Fallout - Textures.bsa extracts fully to valid DDS headers (12 261 / 12 261 at last measure), folder-hash census has 0 collisions over 1 810 folders, no game-conditional branch in the v104 path. The 1 vanilla zero-byte compressed .txt placeholder extracts as an empty file — BsaArchive::extract decides the empty-stream edge before any decoder, so a flate2 bump cannot reopen it (#5073, fa2af0e89).
  • Pick one deathclaw-class creature (skinned via BSDismemberSkinInstance, crates/nif/src/import/mesh/skin.rs), one UI BSShaderNoLightingProperty element (fullbright route), one FaceGen head (crates/facegen/; EGM morph deltas are scaled int16, not half-floats — #4653, real-data pin parse_vanilla_headhuman_egm in crates/facegen/tests/parse_real_facegen.rs; may not render fully — note the gap), one .spt (parse_rate_fo3_spt: placeholder-billboard fallback, not a hard error).
  • Runtime telemetry diff: /audit-runtime --game fo3.
    Output: /tmp/audit/fo3/dim_4.md

Dimension 5: Animation, NPC Spawn, Gameplay Data & the Scripting Gap

Subagent: legacy-specialist
Routing: gameplay mechanism /audit-gameplay; MenuXml /audit-ui; scripting runtime /audit-scripting; clip registry /audit-ecs. The classic-era M41 guards (B-spline FLT_MAX pose fallback, clip-registry dedup, NPC hand meshes) and the spawn-time skin seam blend (tuned on Moriarty's Saloon) are listed in /audit-fnv Dim 4 — verify them on FO3 data here.
Paths: crates/nif/src/anim/, byroredux/src/npc_spawn.rs, byroredux/src/npc_spawn/seam_blend.rs, byroredux/src/hud.rs, crates/menuxml/, crates/plugin/src/consumables.rs, docs/smoke-tests/fixtures/fo3.env
First step: git log --since=<date> --format='%h %cs %s' -- crates/nif/src/anim byroredux/src/npc_spawn byroredux/src/hud.rs crates/menuxml

  • FO3 kf-era spawn works because its skeleton.nif resolves (unlike FO4); Megaton dwellers with no hands = the hand-mesh regression; the three mtforward.kf body-class walk clips (humanoid_walk_kf_path) exist in FO3's archive.
  • HUD: HudGameProfile::fallout3 — menu art from Fallout - Textures.bsa (the shared anchor; FNV's Textures2 rides in as its numeric sibling), 8 font slots (FNV: 9), 2 bars keyed on AVIF editor ids resolved through PlayerVitals (#4675). FO3 vs FNV is picked from the load order by fallout_profile (#4718), falling back to FO3 when neither base ESM is listed or beside the corpus. Guards: crates/menuxml/tests/fo3_corpus.rs (BYROREDUX_FO3_DATA) and docs/smoke-tests/m48-5-fo3-hud.sh.
  • Consumables: Stimpak restores health + the seven body-condition AVIFs on FO3 as on FNV; FO3 has no Hardcore — CTDA fn 586 must be rejected under the FO3 profile (fn586_condition_gate_is_profile_scoped_not_game_scoped). Real-master guard: real_stimpaks_restore_scaled_health_and_limbs_but_hardcore_only_health in byroredux/src/inventory.rs (--ignored).
  • Playable gates declared in fo3.env (FIXTURE_GATES): p0-door-interaction, p5-save-restart, p5-f5-f9-quicksave, p2-melee-core (Moriarty's Saloon, target Nova; green at HEAD per 273692be5). An undeclared gate exits 2 — that is unmeasured, not covered.
  • Eat / Sleep (M42, byroredux/src/systems/eat_sleep.rs, mechanism /audit-gameplay): PKDT procedures 3 / 4 walk to the authored PLDT anchor (#5391, 42aab4c09); Near-Linked-Reference resolves through the actor's own XLKR edge, In-Cell searches the whole resident cell (radius is not authored), and an unresolved Near-Reference target retries on a coarse clock instead of caching the actor's position (#5500, bcaf63aa8; #5527); creatures never take furniture (#5495). Legacy furniture markers author animation_type 0, so every marker reads Sit and on FO3 the sit fallback IS the sleep path — sleepers take the nearest sit marker, chairs included (documented contract, #5390, 9bdfdd1c6; legacy_sleep_actor_seats_at_the_sit_fallback). docs/smoke-tests/m42-eat-sleep.sh runs FNV only; FO3 posture is unmeasured.
  • Scripting gap (known, owned by /audit-scripting): 1 257 SCPT parse; there is no general executing runtime for FO3 script logic. M47.3 ticks compiled quest scripts game-agnostically (101 / 192 QUSTs carry script refs, 403 / 1 257 scripts have executable GameMode blocks; FO3's SetStage/GetStage ids match the Oblivion-derived table). The narrow obscript_runtime.rs load-order-idiom interpreter does not reach FO3: obscript_dialect_for gives FALLOUT3 no compiled dialect. Object-script effects the slice depends on are recognised at load instead (the #5223 kill-on-load corpse idiom, Dim 2).
    Output: /tmp/audit/fo3/dim_5.md

Phase 3: Merge

  1. Read all /tmp/audit/fo3/dim_*.md.
  2. Combine into docs/audits/AUDIT_FO3_<TODAY>.md:
    • Executive Summary — compatibility level + delta vs FNV (what is shared, what diverges); state the real-data lane result first.
    • Dimension Findings — grouped by severity per dimension.
    • FNV-Shared Surface — record/block/shader paths FO3 inherits, plus any FO3-only gap inside them.
    • FO3-Distinctive Gaps — inline-shader-only material universe, Capital Wasteland worldspace, the SCPT runtime gap.
    • Validation Status — interior (Megaton 929 REFRs), exterior (population + image-health gates per exterior-readiness-plan.md; no FO3 scene in the ROADMAP bench-of-record), creature/NPC.
    • Cross-Audit Routing — shared-mechanism findings handed to their owner.
  3. Remove cross-dimension duplicates.

Suggest: /audit-publish docs/audits/AUDIT_FO3_<TODAY>.md
(label every finding game:fo3 + legacy-compat, plus its own domain label.)