Fallout 4 Compatibility Audit

VerifiedCaution

Deep per-dimension audit of Fallout 4 compatibility (BA2, half-float verts, BGSM materials, M49 CSG precombines) acting as an orchestrator of sub-agent tasks.

Sby Skills Guide Bot
DevelopmentAdvanced
11/9/2026
Claude Code
#fallout-4#game-engine#code-audit#precombines#asset-pipeline

Recommended for

Automated summary

An audit skill that checks ByroRedux engine readiness for Fallout 4 content by splitting five analysis dimensions (M49/CSG precombines, BA2, BGSM materials, NIF BSVER, ESM data) across sub-agents.

Strengths

  • Explicit ownership boundaries: each defect class is routed to the owning skill (audit-parsers, audit-nif, audit-esm, audit-physics, and so on) instead of being handled here
  • A shipped-features list acting as a regression guard, with an explicit rule never to re-propose that work as pending
  • Structured dimension orchestration with a three-agent concurrency cap and concrete file paths per dimension
  • Concrete setup steps: pulling GitHub issues for deduplication and confirming the local game data directory exists

Limitations

  • Tightly bound to one private repository (ByroRedux) with hardcoded paths such as /mnt/data/SteamLibrary, so it is not portable as-is
  • The supplied file cuts off mid-Dimension 1, so only the beginning of the first of five axes is actually visible
  • Requires a local Fallout 4 install for real-data validation; without it several dimensions lose concrete verification
  • No exit criteria or final report format are specified in the available portion
When to use it

Use it when a ByroRedux contributor wants to confirm a recent change has not broken Fallout 4 content support.

When not to use it

Avoid it on a different engine or repository, or without Fallout 4 data installed and issue history reachable.

Security analysis

Caution
Quality score84/100

The skill is a large read-mostly audit orchestrator: it inspects a Rust game engine, greps git history, runs existing test suites, optionally queries GitHub issues, and writes markdown reports. Nothing destructive, no curl|sh, no base64 payloads, no credential or token handling, no attempt to disable safety controls or to redirect the assessing agent's role. Risk comes only from ordinary power-tool usage - bash, network access through gh, reading host paths outside the repo, executing repo test code, and delegated subagents - so it rates caution rather than risky.

Findings
  • •No declared allowed-tools, yet the workflow drives shell commands through orchestrator and subagent steps (mkdir -p /tmp/audit/fo4, git log, cargo test, gh issue list), so tool scope is implicit rather than declared.
  • •Network egress to GitHub via `gh issue list --repo matiaszanolli/ByroRedux` - read-only, but it is an outbound call made without an explicit tool grant.
  • •Reads absolute host paths outside the repository (`/mnt/data/SteamLibrary/steamapps/common/Fallout 4/Data/`) and an env-var-supplied data root (`BYROREDUX_FO4_DATA`), which pulls third-party game assets into the audit context.
  • •Instructs running `cargo test -- --ignored` (including real-data integration tests) against the target repo, i.e. executing repository code and parsing untrusted binary game assets.
  • •Spawns up to three concurrent Task subagents (`general-purpose`, `legacy-specialist`) whose tool permissions are inherited and not themselves constrained by this file.
  • •Writes output into the working repo (`docs/audits/AUDIT_FO4_<TODAY>.md`, `/tmp/audit/fo4/dim_*.md`) and hands off to `/audit-publish`, which a reviewer should confirm before granting write access.
  • •Minor, non-malicious: the text contains directives aimed at the reviewing agent ('do not re-file', 'never re-propose as pending', 'do not guess'). These are editorial policy statements, not an injection attempt, but they are instructions inside untrusted content and were not followed.
  • •No allowed-tools declared, yet the workflow requires shell execution (`mkdir -p /tmp/audit/fo4`, `git log`, `cargo test`), network access (`gh issue list --repo matiaszanolli/ByroRedux`), reads from a local game install (`/mnt/data/SteamLibrary/.../Fallout 4/Data/`), and spawning up to 3 concurrent Task subagents — powerful capability is implicit rather than scoped.
  • •Writes artifacts outside a stated sandbox (`/tmp/audit/fo4/dim_*.md` and `docs/audits/AUDIT_FO4_<TODAY>.md`), and one phase suggests a follow-on action (`/audit-publish`) that would commit/modify repository docs; side effects are legitimate for an audit but not bounded in the file.
  • •Relies on `${ARGUMENTS}`-derived interpolation into shell commands in spirit (`--focus`, `--cell MedTekResearch01`, `BYROREDUX_FO4_DATA=…`) without quoting/validation guidance, so a crafted argument could alter invoked commands.
  • •No destructive, exfiltrating, or obfuscated actions found: no `rm -rf`, no `curl|sh`, no base64 payloads, no secret/token handling, no safety-disabling instructions.
  • •No prompt-injection or role-change attempt observed inside the skill body.
How this analysis is made

Examples

Full audit
Run the Fallout 4 compatibility audit across all five dimensions and report findings grouped by dimension.
Precombines only
Audit FO4 Dimension 1 only — M49 precombined geometry decode and spawn paths — and flag any regressions against the shipped CSG pipeline.
Materials and shader flags
Check the FO4 BGSM/BGEM material merge path and the BSVER shader-flag band guards (130 typed vs 131 gap vs 132+ CRC) for regressions.

description: "Per-game audit of Fallout 4 compatibility — BA2, half-float verts, BGSM materials, M49 precombines (CSG)" argument-hint: "--focus <dimensions>"

Fallout 4 Compatibility Audit

Deep audit of ByroRedux readiness for Fallout 4 content.

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

Read .claude/commands/_audit-common.md (layout, game data, dedup, finding format) and .claude/commands/_audit-severity.md. This file carries only FO4-specific context.

Scope: this skill owns FO4's data through the shared mechanisms. Defects in the mechanism itself go to the owner: BA2/CSG/BGSM/.uvd reader discipline → /audit-parsers; NIF block parsing → /audit-nif; ESM walker → /audit-esm; canonical-material invariants → /audit-nifal; Scaleform HUD (--hud, byroredux/src/scaleform_hud.rs, docs/smoke-tests/m48-7-fo4-hud.sh, AVM2/BGSCodeObj) → /audit-ui; ragdoll articulation incl. the FO4 bhkRagdollSystem decode (crates/nif/src/blocks/collision/np_ragdoll.rs) and docs/smoke-tests/fo4-ragdoll.sh → /audit-physics; the Havok 2014 behavior-graph reader (crates/hkx/) → /audit-parsers, its runtime (byroredux/src/asset_provider/{actor_graph,object_graph,archetype_idle}.rs, byroredux/src/systems/graph_locomotion.rs) → /audit-gameplay Dim 5; the LSCR loading model (FO4 TNAM → TRNS, byroredux/src/systems/loading_model.rs, docs/smoke-tests/p6-loading-model.sh) → /audit-gameplay Dim 6; terrain, ground cover (the Commonwealth is arid since 1a2330361) and WTHR → /audit-exterior; runtime telemetry (.claude/audit-baselines/runtime/fo4-InstituteBioScience.tsv) → /audit-runtime — run it after any precombine / SCOL / spawn change (#5484's skip-set fix, 777351ec1, moved its draw / entity / BLAS rows; that recapture is still owed).

Everything below is shipped — audit as regression guard, never re-propose as pending: NIF BSVER 130+ incl. Next-Gen, BA2 v1/v7/v8, the BGSM/BGEM parser, SCOL/PKIN expansion, M49 CSG precombines, BSConnectPoint attach graph.

Game Context

| Aspect | State | |---|---| | NIF | BSVER 130 + Next-Gen patches (FALLOUT4..FO4_DLC_UPPER = 130..=139 carries the DLC trailing fields, crates/nif/src/version.rs) | | Shader flags | typed u32 pair at BSVER 130 only; BSVER 131 (FO4_SHADER_GAP) has neither; BSVER ≥ 132 uses CRC arrays. Guard: bsver_shader_flag_band_tests (version.rs), gates carries_typed_shader_flags / carries_crc_shader_flags | | Materials | PBR params live in external .bgsm/.bgem; the NIF carries a path stub. crates/bgsm/ parses; merge_external_material folds into ImportedMesh.material before translate_material | | Precombines | crates/bsa/src/csg.rs → crates/nif/src/import/precombine.rs → byroredux/src/cell_loader/precombined.rs; per-REFR skip set = the CELL XCRI pair tail, never XPRI (#5484). Spec docs/engine/fo4-csg-format.md | | Data | /mnt/data/SteamLibrary/steamapps/common/Fallout 4/Data/; bench --cell MedTekResearch01 (ROADMAP) |

Parameters / Setup

--focus <dimensions> (comma-separated, default all 5). Setup: parse $ARGUMENTS; mkdir -p /tmp/audit/fo4; gh issue list --repo matiaszanolli/ByroRedux --limit 200 --json number,title,state,labels > /tmp/audit/issues.json; confirm Fallout 4/Data/ exists (else note dimensions losing real-data validation).

Dimensions

Dimension 1: M49 Precombined Geometry — Decode + Spawn (highest FO4 risk)

Subagent: general-purpose Paths: crates/nif/src/import/precombine.rs, byroredux/src/cell_loader/precombined.rs, byroredux/src/cell_loader/load.rs + exterior.rs + partial.rs, byroredux/src/cell_loader/spawn/{mesh_instance,precombined}.rs, byroredux/src/streaming/pre_parse.rs (worker pre-parse), crates/plugin/src/esm/cell/helpers.rs (XCRI decode), crates/bsa/src/csg.rs, crates/bsa/src/uvd.rs First step: git log --since=<last report> --format='%h %cs %s' -- crates/nif/src/import/precombine.rs byroredux/src/cell_loader/precombined.rs crates/bsa/src/csg.rs Guards (confirm live, not #[ignore]d/vacuous): precombine.rs tests decode_keeps_every_lod_band + lod_bands_skip_empty_bands_and_bound_the_read (#4234); csg.rs oversized_read_len_is_rejected_before_it_is_reserved (#3758 — read_psg must bound its length before Vec::with_capacity; reader discipline is /audit-parsers); precombined.rs tests resolve_precombine_owner_follows_form_id_mod_index, csg_paths_index_every_plugin_in_the_load_order, dedup_requires_both_a_cache_key_and_a_matching_length (#3510), oc_nif_paths_are_already_canonical_cache_keys; finish_partial_tests.rs::finish_partial_import_builds_precombine_geometry_entry; blend restore on both routes (#5101): precombined.rs::merge_precombine_materials_restores_blend_but_keeps_bgsm_flags + finish_partial_tests.rs::finish_partial_import_precombine_route_applies_the_material_merge; zero origin (#5228): exterior_apply_advances_precombine_at_zero_origin; #[ignore]d real-data dlc_rebake_of_a_master_owned_cell_decodes_from_the_dlc_csg + exterior_precombine_instances_are_world_absolute. The runtime baseline is an interior, so no telemetry gate sees exterior placement. Checklist (what the guards cannot see):

  • Stride / transform — psg_vertex_stride(vertex_desc) vs the BSPackedGeomObject layout (off-by-N shifts every vertex silently; cross-check the spec doc). into_imported_mesh applies Z-up→Y-up + instance transform once. cell_origin must be Vec3::ZERO on both routes (#5228, fixed f3e1bba62): exterior _oc.nif instance transforms are world-absolute (same frame as the exterior REFR DATA positions), so adding cell_grid_to_world_yup places every tile at ≈2× its world position — the "else precombines stack at origin" rationale was the disproved #1222 premise.
  • LOD bands (#4234) — the three bands are disjoint sub-meshes whose union is the model (12,096/12,096 BSMeshLODTriShape); every populated band is decoded. Picking one band deletes geometry (12.45% of MeshesExtra.ba2's baked triangles) and is not z-fighting. Distance LOD may drop tail bands, never pick one. An empty band's offset is untrusted.
  • Which CSG blob — the _oc.nif filename keys off the cell's owning plugin (form-id mod byte; DLC bakes under <plugin>.esm\), but the geometry blob is chosen by each object's BSPackedGeomObject::filename_hash → csg_paths_by_name_hash (#2369: DLCs re-bake ~460 master-owned cells into their own blob). A blob no loaded plugin answers to, or a missing CSG, must fail closed to per-REFR (0 spawns), never read another plugin's PSG space or panic. Known open: resolve_precombine_owner reads the FormID slot byte as a load-order position (#6088).
  • REFR de-dup gate (#1188 / #5484, fixed 777351ec1) — the skip set is the XCRI pair tail, (remapped REFR form id, bake hash) pairs on CellData::absorbed_ref_bakes (crates/plugin/src/esm/cell/helpers.rs); XPRI is the disjoint previs participant list, validated and never stored. Pre-fix the two were inverted (every baked STAT/SCOL drawn twice, ~9.9k XPRI statics deleted); census 959,238 XCRI refs, 100% STAT/SCOL, XCRI ∩ XPRI = 0 — which also settles #2699's furniture question. effective_absorbed_refs(bakes, baked_hashes) (shared by interior load.rs — whose InteriorCellApplyJob now drives both the sync and the budgeted load, #5589 / a4496c79b — and exterior exterior.rs) suppresses a REFR only when its own bake drew geometry, so one missing _oc.nif un-skips only its refs (no holes, no double-draw with SCOL expansion). Guards: effective_absorbed_refs_un_skips_only_the_missing_bakes_refs; parse_cell_xcri_pairs_remap_and_keep_their_bake_hash + parse_wrld_exterior_cell_captures_precombined_xcri_xpri (XPRI populates nothing) in crates/plugin/src/esm/cell/tests/.
  • Texturing — each mesh takes its material from the owning shape's shader/alpha properties (collect_precombine_geom_refs + precombine_material_from_shape), then the BGSM merge; no REFR overlay on this path (pre_merge_materials empty by design, #4290). Regression = untextured/checker precombines.
  • Opaque-architecture blend guard — on this path only, merge_precombine_materials (called by both PrecombinedSpawnJob and the streaming drain in partial.rs) keeps the BGSM merge's two_sided/decal/alpha_test/texture flags but restores the pre-merge alpha-blend triple (has_alpha, src/dst_blend_mode): FO4 authors the "Standard" blend identically on lab glass and opaque Institute metal, so forwarding the merged has_alpha makes walls MATERIAL_KIND_GLASS (see-through, mirror-hazy).
  • Archive chain precedence (#3637) — --bsa / --materials-ba2 chains resolve last-listed-wins (a DLC's re-baked _oc.nif must not be shadowed; 1,871 DLC mesh entries were shadowed pre-fix per the #3637 title). Provider rebuilds now share opened handles (#5288, 5402b2530: Archive::open_shared, a process-wide registry validated by file length + mtime) and skip the shadow-count walk for a reused handle — precedence is unchanged, only that diagnostic count is. Loose Data\ files (the --esm plugin's directory) are appended after every archive in the texture, mesh and material pools, so a loose override wins (#6200, 48e422a71; vanilla installs carry none, so no baseline moved). Guards: byroredux/src/asset_provider/tests/archive_precedence.rs (real-data, #[ignore]d — run it), byroredux/src/asset_provider/tests/loose_override.rs.
  • Upload once per object (#3510) — CachedNifImport::geometry_dedup maps every instance to its object's representative; keying the cache on the flattened sub-mesh index reintroduces one upload + BLAS per instance (1.37x VRAM, 4.6x worst tile).
  • Exterior streaming — PrecombinedSpawnJob yields between hashes / meshes / BLAS batches, and PrecombinedPlacement (spawn/precombined.rs) between geometry groups, keeping the placement root + submesh numbering across yields; the synchronous spawn_precombined_meshes wrapper must stay behaviourally identical. The cell-stream worker pre-decodes each cell's precombine_oc_nif_paths via decode_precombine_csg (per-plugin CsgHandleCache) and the drain caches a geometry_only_cached entry under the same key so the job only spawns — the two routes must agree on owner resolution, cache key, fail-closed fallback and the blend restore (divergence = different spawn counts per route). Regression guard (#5522, fixed 2ca9bc313): lookup_precombine_cache separates Hit / KnownFailure / Unseen, so the worker's negative cache entry (Some(None): missing file, parse error, contained panic) is a terminal miss, never a main-thread re-parse outside catch_unwind; pinned by negative_registry_entry_is_a_known_failure_not_unseen. NifImportRegistry's LRU evicts per-cell _oc.nif entries first and warns once on a shared-model eviction (6e1853d24); still open: the 2,048 cap is below the FO4 working set (#6114), one geometry copy per instance in precombine entries (#6116), and the worker pre-parses absorbed refs the main thread skips (#6097). effective_absorbed_refs is built once per apply job (67e724c3e, #6127), not per slice.
  • .uvd previs — envelope only (parse_uvd_header, incl. exterior_cell_grid; PVS payload uncracked, no occlusion consumer, #3810). Verify nothing pretends to consume the payload. Output: /tmp/audit/fo4/dim_1.md

Dimension 2: BGSM / BGEM → ImportedMaterial (merge + roles)

Subagent: general-purpose Paths: crates/bgsm/src/, byroredux/src/asset_provider/material/{merge,mod,provider}.rs, byroredux/src/cell_loader/spawn/mesh_instance.rs (REFR overlay), byroredux/src/asset_provider/tests/{bgsm_merge,material_flags}.rs First step: git log --since=<last report> --format='%h %cs %s' -- crates/bgsm byroredux/src/asset_provider/material Guards: bgsm_merge.rs (bgsm_merge_forwards_alpha_blend_mode, bgsm_blend_to_gamebryo_is_identity_narrowing, the neutral-roughness pair, bgem_glass_forwards_authored_optics_and_overlay_roles); material_flags.rs::bgsm_metalness_*; crates/bgsm/src/template.rs resolve_breaks_*_cycle (#1148) + resolve_reports_per_file_parse_diagnostics (#5010, 746e0858e); crates/bgsm/tests/parse_all.rs real-data sweeps (hardened #5011, e8676b097) and asset_provider/tests/bgsm_diagnostics.rs. Parser discipline for crates/bgsm is /audit-parsers. Checklist:

  • Narrowed signature — merge_external_material takes &mut ImportedMaterial, never &mut ImportedMesh, and is the only exported fn in merge.rs (test merge_external_material_is_the_only_exported_fn_in_this_file); a widened signature is a NIFAL boundary violation. It runs before translate_material. merge_bgsm_arm is split into group helpers (apply_bgsm_texture_slots / apply_bgsm_scalars / apply_bgsm_alpha_and_addressing, #5735 / a6cef30a5) and size-pinned by merge_bgsm_arm_stays_within_its_size_pin; the helpers stay private.
  • Roles, not slots — BGSM texture paths and REFR/TXST overlays land in MaterialTextureSet (22 named roles + decals: [T; 4], crates/nif/src/import/types.rs); FO4 wire-slot numbers must not survive past the import boundary. Overlay output is carried as named roles, not wire slots (#4434). Texture-set slot 7 is the _s.dds smooth-spec map and routes to the smooth-spec role, not Specular (#4424: the BC5 map fed to the specular-colour multiply tinted every FO4 highlight warm); the gloss-sampler channel semantics are still an open question — do not guess.
  • Metalness from saturation, not luminance (#1476) — legacy spec-glossiness BGSMs (pbr == false): bgsm_metalness = (max-min)/max of specular_color (white spec → 0). Luminance for the non-PBR branch makes vanilla concrete read chrome; luminance is correct only for pbr == true.
  • Authored enable bits gate their blocks — specular_enabled == false zeroes specular and derives no metalness / conductor tint in either branch (#4654, #4836; bgsm_specular_disabled_*); the envmap fill requires the chain's environment_mapping bit (#4428; *_skips_envmap_fill_when_env_mapping_disabled); a dead NIF texture path yields to a resolvable BGSM-chain path (#4636; dead_nif_texture_path_yields_to_resolvable_bgsm_chain_path). Reading a disabled block's values is the regression.
  • smoothness→roughness exactly once at the merge ((1 - smoothness) clamped to the near-mirror floor); flag any downstream re-inversion.
  • Neutral-roughness fallback — smoothness == 1.0 with no resolvable gloss map → neutral 0.5 (NEAR_MIRROR_NEUTRAL_ROUGHNESS): #3639 at the merge (authored-nowhere; fires on the specular_enabled arm only — a spec-off BGSM keeps the NIF-side roughness, #5012 / e80f7e854; must not fire when a template parent supplies smooth_spec — pinned by bgsm_merge_keeps_the_floor_when_the_gloss_map_comes_from_the_template_parent, #5234 / 460c55a41), #3905 at spawn via material_translate::resolve_unresolved_gloss_neutral_roughness (authored-but-unresolvable; gated on the shader's glossMapIndex != 0u). The arms cover disjoint populations — collapsing them regresses. Regression guard (#5230, fixed 9f0a8a7cc): the spawn pass infers "hit the floor" from roughness <= 0.04, which the glass classifier's forced mirror pane (0.04, metalness 1.0) also hits; classify_glass_into_material_with_provenance now reports the forced mirror out through translate_material_with_provenance and resolve_unresolved_gloss_neutral_roughness skips it (a_forced_mirror_pane_is_exempt_even_sitting_at_the_floor, a_bgsm_mirror_pane_keeps_its_mirror_through_the_spawn_pass_gate in material_translate.rs). Both spawn sites must feed the provenance flag.
  • Blend factors pass through (#1823) — BGSM/BGEM src_blend/dst_blend are already Gamebryo-native (Standard (6,7), Additive (6,0), Multiplicative (4,1)); any 0↔1 swap (or a gl_to_gamebryo_blend) corrupts Additive/Multiplicative while leaving Standard untouched.
  • BGEM merge — merge_bgem_arm deliberately leaves metalness/roughness as NaN so resolve_pbr's classifier runs; effect data merges into the NIF payload (#4425). Glass is glass_enabled-driven and must not misclassify opaque architecture with a stuck flag.
  • Lookup — .bgsm/.bgem/.mat dispatch on content magic, not extension (#758); last-listed-wins across --materials-ba2 (#3637); template resolve is cycle-aware and depth-limited (DEPTH_LIMIT = 16) and surfaces parse diagnostics (lossy strings, unconsumed bytes, version past the ceiling) for every file in the chain through TemplateResolver::parsed, not only the recovery arm (#5010).
  • MNAM-only landscape TXSTs — 32 of FO4's 128 LTEXs point at a TXST that authors only MNAM; terrain resolves each layer through LandscapeLayerTextures (byroredux/src/cell_loader/terrain.rs) and MaterialProvider::fill_texture_set_from_bgsm fills still-empty roles first-wins along the template chain, so authored TX slots keep precedence (#6199, e62e258bd). A layer reading only TX00/TX01/TX07 is the regression (untextured grass / rubble / cliffs). Output: /tmp/audit/fo4/dim_2.md

Dimension 3: NIF BSVER 130 Geometry, Shader Flags, Collision (FO4 slice)

Subagent: legacy-specialist Paths: crates/nif/src/blocks/tri_shape/bs_tri_shape.rs, crates/nif/src/import/mesh/{bs_tri_shape,bs_geometry,skin}.rs, crates/nif/src/blocks/shader/lighting.rs, crates/nif/src/import/material/dedicated_shader.rs, crates/nif/src/import/collision/shape.rs First step: git log --since=<last report> --format='%h %cs %s' -- crates/nif/src/import/material crates/nif/src/blocks/shader Guards: fo4_shader_flag_tests.rs, alpha_flag_tests.rs (crates/nif/src/import/material/); bsver_shader_flag_band_tests; parse_rate_fo4_all_meshes (Dim 5). Parser mechanics are /audit-nif; the canonical handoff (single translate_material boundary, resolve-once metalness/roughness, glass classified after resolve_pbr) is /audit-nifal — file there. Checklist:

  • VF_FULL_PRECISION default-half unless set; binary16 decode incl. denormals/NaN. BSSubIndexTriShape segments walked (actors lean on it); skinned indices/weights honour the packed layout. Regression guard (#5389, fixed cf9dec258): a per-vertex bone index >= the skin's own bone count declines the whole weight set (bind pose), never clamps — decline_unbounded_packed_indices (skin.rs) covers the inline arrays, the SSE global-buffer payload and classic NiSkinData; pinned by bs_tri_shape_skin_with_out_of_range_bone_index_declines / bs_tri_shape_skin_last_bone_index_is_in_range (bs_tri_shape_partition_remap_tests.rs). Vanilla census: 0 out-of-range over 23,099 FO4 skinned meshes (largest list 141/144). The FO4 BsSkinInstance arm is pinned too (#5524, fixed 656e2bdc3): bs_skin_instance_out_of_range_bone_index_declines / bs_skin_instance_last_bone_index_is_in_range, and the decline warning is arm-neutral. Inline tangents when VF_TANGENTS | VF_NORMALS (shared with Skyrim SE) — consolidating with the NiBinaryExtraData path is a regression of #795/#796.
  • Render-affecting flags consumed, not just parsed (#1592) — dedicated_shader.rs ORs Model_Space_Normals (F4SF1 bit 12) and Alpha_Test (F4SF2 bit 25) into MaterialInfo, gated by carries_typed_shader_flags (BSVER 130 only). Glow_Map (F4SF2 bit 6) is not gated: the (Fallout4, 2) arm in slot_role.rs routes slot 2 to Emissive regardless — closed docs-only (#4430, 1a12670ae; routing unchanged on purpose — census: gating would strip 116 genuine _g.dds glow maps, not gating masks 20 with a _d.dds; the BGSM glowmap bool is parsed, never read). The rule still needs an FO4 source; do not re-file or guess. These are lower priority than the BGSM merge (vanilla is BGSM-backed; only inline/loose/modded NIFs exercise them).
  • Skin/Hair tint BSLightingShaderType variants sample different slots than the default path — the per-type map must match what triangle.frag reads (#563). A BGSM material must never fall back to Lambert (FO4's inverse of the FNV regression); bare BSShaderPropertyBaseOnly stubs route through MaterialInfo (#1244).
  • Parsed-then-dropped is FO4's recurring finding class (texture_clamp_mode on 7.9% of lit materials #3507; the greyscale→palette enable bit): every decoded FO4 shader/BGSM field must reach an ImportedMaterial sink and the canonical Material, with one default across the three material tiers (#3515). The palette row ("Color Remapping Index") has two carriers (#5497): the precombine per-instance grayscale_to_palette_scale is stamped by apply_instance_palette_row and restored across the BGSM merge in merge_precombine_materials (guards merge_precombine_materials_keeps_the_instance_palette_row, apply_instance_palette_row_stamps_finite_rows_only); the REFR-side MSWP CNAM (color_remap_index in mswp.rs) is applied as the palette row for a swapped placement, stamped on the raw-tier ImportedMaterial before translate_material (0b2ffed89, #5497) — live only since f81e6e722 (#5755): both swap arms (per-shape, eager XATO) match through mswp_source_matches (refr.rs: normalize_material_path both sides, case-insensitive, the CK * wildcard on 127 vanilla BNAMs), because a bare BNAM never equalled the NIF's Materials\… / build-path / Data\materials\… spelling verbatim and no unbaked XMSP placement in Fallout4.esm swapped. MSWP FNAM is the CK tree folder (MaterialSwapRecord::tree_folder), never a path filter (#5756 — as one it rejected every swap of 806 records). Guards: mswp_source_matches_canonicalizes_and_honours_wildcards, build_overlay_xmsp_fnam_tree_folder_does_not_gate_the_swap (refr_texture_overlay_tests.rs), #[ignore]d fo4_mswp_canvas_swap_matches_the_picture_frame_nif. Starfield's REFR XLMS → LMSW swaps (#5757, 17bd40f4f; layered_material_swap_entries / canonical_swap_target) ride this same per-shape material_swaps arm, so an FO4 swap-path regression also breaks Starfield swaps (/audit-starfield Dim 4).
  • Collision — BhkMultiSphereShape and BhkConvexListShape translate to CollisionShape in import/collision/shape.rs (two downcast_ref arms); an arm reverting to "unsupported + drop" removes power-armor / settlement / debris collision. Packed-Havok (BhkSystemBinary) collision is blocked on the hknpCompressedMeshShapeData decode (PHYSAL, /audit-physics) — the skeleton bhkRagdollSystem blob is a different payload and is decoded (e1bd40bcf); FO4 architecture uses synthesized ghost trimesh colliders. The precombine collision sibling is <cell_formid:08x>_physics.nif (not _precomb.nif, which appears in no archive) — forward scope. Output: /tmp/audit/fo4/dim_3.md

Dimension 4: ESM Architecture Records + Cell Expansion

Scope split with /audit-esm: it owns the parser as a parser (GRUP walk, SubReader accounting, FormID remap); this dimension owns FO4's data through it. Shared-mechanism defects → /audit-esm. Subagent: general-purpose Paths: crates/plugin/src/esm/records/{scol,movs,pkin,mswp,parse}.rs, crates/plugin/src/esm/records/actor/npc.rs, crates/plugin/src/equip.rs, crates/plugin/src/esm/cell/{mod,support,walkers,wrld}.rs, byroredux/src/cell_loader/{refr,references/,spawn.rs,nif_import_registry.rs} First step: git log --since=<last report> --format='%h %cs %s' -- crates/plugin/src/esm/records crates/plugin/src/esm/cell byroredux/src/cell_loader/refr.rs Guards: cell_loader/scol_expansion_tests.rs, pkin_expansion_tests.rs, attach_points_spawn_tests.rs, refr_texture_overlay_tests.rs; the real-data ESM harness (#819) before any parse-rate claim. Checklist:

  • SCOL/PKIN expand into per-instance synthetic REFRs with composed (parent × child) transform; recursion bounded by MAX_PKIN_DEPTH = 4 (vanilla has zero nesting; the cap guards modded cross-recursion); SCOL-of-SCOL has its own gate. Regression guard (#5523, fixed a10b5d578): scol_cm_path (byroredux/src/cell_loader/refr.rs) answers which combined mesh a SCOL draws — the authored MODL when it resolves, else the derived meshes\scol<owner>\cm<local id>.nif (114 DLCRobot SCOLs author dev-plugin MODLs) — and expand_scol_placements_if expands the SCOL into its parts when it answers None (13 vanilla placements name a CM that ships nowhere); the static spawn (byroredux/src/cell_loader/references/synth_child.rs) and the expansion gate in references/mod.rs read the same answer, so they cannot disagree. A SCOL nested under a PKIN keeps the emptiness-only gate. Pinned by scol_cm_path_prefers_the_authored_modl_then_the_derived_path + a_scol_with_an_absent_cm_expands_but_a_present_one_does_not (scol_expansion_tests.rs). Also: SCOL/PKIN FLTR is the CK object-window filter path, a zstring decoded with read_zstring into filter: String and never remapped (#5493, fixed 136048a95 — pre-fix 2,843 false malformed-FormID warns across the FO4 DLCs buried real remap failures; the *_expansion_tests.rs pins use real string payloads plus a raw-under-remap test); NPC_.TPTA decodes onto NpcRecord::template_actors: [u32; 13] (xEdit wbTemplateFlags order, 0 = use the TPLT default) and walk_inherited_records (crates/plugin/src/equip.rs) takes the per-flag entry for that flag's edge when non-zero (#5498, fixed 99c22a8db; 763 Fallout4.esm records resolved the wrong template before). MOVS is parse-only (physics runtime unwired). The TXST group arm is in records/parse.rs and its decode in esm/cell/support.rs — an unreachable_patterns warning there means b"TXST" matches earlier than intended. The FO4-architecture maps must surface in categories() (records/index.rs).
  • TXST DODT (DecalData) has zero consumers — 303 vanilla payloads parse onto TextureSet.decal_data and are never read (grep decal_data finds only the parser and its tests); DNAM is consumed (TXST_FLAG_MODEL_SPACE_NORMALS in refr.rs). Known and deferred — #3638 closed documentation-only (a decal-rendering feature build, not a parse bug); forward scope, don't re-file.
  • PKIN CNAM is a template CELL, not a content base — fixed d63131c57 (#5231): every vanilla PKIN CNAM resolves to a CELL (the census spans Fallout4.esm + four DLCs) and vanilla FO4 places 0 PKIN REFRs (the CK bakes contents into ordinary REFRs) — an FO4-only premise: Starfield places 97,981 (fixed #5489: the expander now instances a CELL-typed CNAM's template-cell references under the outer transform, outer PKIN entry first, via the O(1) EsmCellIndex::cell_by_form_id) and returns None only when nothing was placeable so the outer REFR reaches the default miss accounting; base-record children remain the mod-authored shape. Guards: expand_pkin_empty_template_cell_places_nothing, expand_pkin_empty_template_leaves_the_base_children_fanning_out, expand_pkin_instances_its_template_cell_under_the_outer_transform, the #[ignore]d starfield_cydonia_pack_ins_instance_their_template_cells, #[ignore]d fo4_pkin_cnam_targets_are_template_cells (crates/plugin/tests/parse_real_esm.rs).
  • Authored actor state — ACHR "Starts Unconscious" (0x2000, FO4/FO76/SF only) decodes onto PlacedRef::starts_unconscious and spawns the actor dormant (#5017, 3c08cfe50); XRGD corpse poses decode onto PlacedRef::ragdoll_pose (260afc33f); the consumer is byroredux/src/ragdoll_pose.rs, gated per rig by body-name set. FO4 (#5015 closed into follow-ups; e1bd40bcf + 28e1f413e): the skeleton's bhkRagdollSystem (hknpRagdollData) blob decodes into the classic ragdoll/limited-hinge records, and XRGD entries map to bodies by each body's pose_bone_id, not entry order; is_fo4_posable_ragdoll admits the human, feral-ghoul and super-mutant sets (979 of 994 corpses resolve, per 28e1f413e) and refuses every other creature/robot rig (#6065 open). The layout is corpus-derived, not sourced — widen the gate only when scripts/xrgd-fo4-rigs.py passes a rig on both checks, never on a count match. Bodies take the blob's own material / motion-property rows by motion index, Skyrim's constants only as the no-rows fallback (#6066, fixed 019b087e3; pinned by a_body_reads_its_material_and_damping_rows_by_motion_index in np_ragdoll.rs + #[ignore]d crates/nif/tests/np_ragdoll_corpus.rs). Convex/compound shapes and breakable joints decode (fc4a15104); the 67 bind-pose pivot disagreements are a recorded data property — the body-frame reading stays, the affected rigs hold live (#6067, closed 0d775dc61; docs/engine/physal.md). Live wiring (fc2b32d9e + 7c6e6c3e1, #6070 closed): FO4 RACE ANAM skeleton paths are read, template_from_imported keeps pose_bone_id, spawn_skeleton_unit installs the one-body template only on a skeleton with no decoded one, and activation frees the FallbackActorCollider stand-in capsule (left behind it threw every limb; stand-up restores it). Regression guard: docs/smoke-tests/fo4-ragdoll.sh (all bodies/joints live, no recovery, BYRO_VALIDATION=1) + #[ignore]d byroredux/src/ragdoll_installed_tests.rs (fo4_bind_pose_ragdoll_holds_together_in_free_fall, six rigs; fo4_xrgd_posed_ghoul_corpse_holds_together_in_free_fall). Not established, no tracking issue: a corpse whose REFR carries a large X/Y tilt (466 of 971 posed human/ghoul corpses) — the pose composition is unknown; the smoke covers only |X|,|Y| < 0.25 rad. Articulation defects → /audit-physics.
  • ARMA female→male biped fallback is Skyrim-only (open sourcing question, not a bug) — resolve_armor_meshes (crates/plugin/src/equip.rs) falls back to the male biped model for a female wearer only when game == GameKind::Skyrim (#5510, fixed d678dc578: the Skyrim CK documents the rule; 172 of Skyrim.esm's 766 addons are male-only). FO4 deliberately keeps the strict reading because the FO4 CK page documents no such rule and none is sourced locally — a FO4 male-only addon renders nothing on a female wearer. Needs an FO4 source (xEdit/CK/engine) before any change; do not extend the fallback by analogy and do not file it as a defect.
  • CELL XCCM is game-dependent (#5463, 3b28dca71) — FO4 (like TES5) authors it as 'Sky/Weather from Region' [REGN] (xEdit wbDefinitionsFO4.pas), decoded onto CellData::sky_region; only TES4/FO3/FNV decode it onto climate_override (a CLMT). No consumer for sky_region yet (forward scope). A FO4 cell reading climate_override from XCCM is the regression.
  • BSConnectPoint — the import lifts BSConnectPoint::Parents/Children into AttachPoints / ChildAttachConnections (crates/core/src/ecs/components/attach_points.rs); spawn must materialise them (modular weapons / power-armor frames otherwise spawn base-receiver only). Output: /tmp/audit/fo4/dim_4.md

Dimension 5: Archives + Real-Data Validation + Forward Scope

Subagent: general-purpose Paths: crates/bsa/src/ba2.rs, crates/nif/tests/parse_real_nifs.rs, crates/nif/examples/nif_stats.rs, ROADMAP.md, docs/feature-matrix.md First step: BYROREDUX_FO4_DATA=… cargo test -p byroredux-nif --test parse_real_nifs -- --ignored fo4 Checklist:

  • BA2 (FO4 slice; reader discipline is /audit-parsers) — version dispatch is an exhaustive match (v1/v7/v8 FO4 → zlib; v2/v3 Starfield → /audit-starfield Dim 1); unknown majors bail at open() and a cascading if v == 1 … else with a silent v1 fallback is the regression (#811). GNRL byte-exact; DX10 reconstructs the DDS header from width/height/dxgi_format/mips (BC1/BC3/BC5/BC7, mip0 → mip_last).
  • Parse rate — parse_rate_fo4_all_meshes covers all 8 mesh-bearing archives (base pair + six DLC Main.ba2; DLCUltraHighResolution is textures-only), 235,082 NIFs incl. .bto/.btr (widened 2026-08-29 by #3466; re-measured 2026-10-09, 8/8 archives), 100.00% clean. Report the measured number, not ROADMAP's. Regression guard (#5232, fixed 3970c8d19): open_all_mesh_archives / open_ba2_by_name (crates/nif/tests/common/mod.rs) panic on a present-but-unopenable BA2 (None is reserved for an absent file) and run_all_meshes_gate asserts walked > 0; a reversion turns the gates into green no-ops — still confirm the archive count actually walked, not just the pass. DX10 records with chunk_hdr_len != 24 are now a hard InvalidData (#5008, cf2a36920; vanilla census: all 24).
  • Trace import_nif_scene on a workshop item, a creature (deathclaw / super mutant), a power-armor frame (heavy skinning + BSConnectPoint) and a modular weapon: mesh count, material_path, skinned vs rigid, connect points.
  • Forward scope (do not file as blockers): precombine _physics.nif collision and packed-Havok decode, .uvd PVS payload / occlusion consumer, MOVS physics runtime, DecalData consumer (above), XRGD poses for the unverified FO4 creature/robot rigs (#6065) and for tilted-reference corpses, FaceGen NIF truncation tail, deeper cell coverage (LIGH power state / CONT leveled items / NPC_ face morph). Output: /tmp/audit/fo4/dim_5.md

Phase 3: Merge

  1. Read /tmp/audit/fo4/dim_*.md; combine into docs/audits/AUDIT_FO4_<TODAY>.md:
    • Executive Summary — measured parse rate; what is shipped vs pending (above).
    • Dimension Findings — grouped by severity per dimension.
    • BGSM Consumption Table — BGSM field × merged-into-ImportedMaterial by merge_external_material / surfaced-on-canonical-Material. Texture columns name the MaterialTextureSet role, never an FO4 slot number.
    • Forward Scope Chain — precombine collision / .uvd payload → MOVS physics → DecalData → deeper REFR/LIGH/CONT/NPC_ coverage.
  2. Remove cross-dimension duplicates.

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

From the file to a first result

The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.

View the source and supporting files

This download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.

1. Download the file

Download SKILL.md

From the root of a test project, save the file as .skill-downloads/fallout-4-compatibility-audit-mvj1ocr7/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.

Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.

mkdir -p '.skill-downloads/fallout-4-compatibility-audit-mvj1ocr7' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/fallout-4-compatibility-audit-mvj1ocr7/download' --output '.skill-downloads/fallout-4-compatibility-audit-mvj1ocr7/SKILL.md.part' && mv '.skill-downloads/fallout-4-compatibility-audit-mvj1ocr7/SKILL.md.part' '.skill-downloads/fallout-4-compatibility-audit-mvj1ocr7/SKILL.md'

2. Check prerequisites

Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.

No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.

The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.

3. Load the skill

This file does not provide a usable name/description header for this native procedure. It remains available to download and inspect; use the manual method below.

Manual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.

4. Try a first task

Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:

Read .skill-downloads/fallout-4-compatibility-audit-mvj1ocr7/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.

Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.

Related skills