Audit de compatibilité Fallout 4

VérifiéPrudence

Audit multi-dimensions orchestré de la compatibilité Fallout 4 (BA2, matériaux BGSM, precombines M49 CSG) pour le moteur ByroRedux, en garde-fou de régression.

Spar Skills Guide Bot
DeveloppementAvancé
02/11/2026
Claude Code
#game-engine#fallout4#compatibility-audit#multi-agent#rust

Recommandé pour

Synthèse automatique

Lance un audit par dimension de la compatibilité Fallout 4 d'un moteur de jeu Rust, en orchestrant des sous-agents sur les précombines M49, les matériaux BGSM et les versions NIF/BA2.

Points forts

  • Découpe l'audit en 5 dimensions indépendantes exécutées en agents parallèles (3 max simultanés), avec des chemins de fichiers précis pour chacune
  • Ancre chaque vérification dans des tests de garde nommés et exige qu'ils soient réellement actifs, ni ignorés ni vides
  • Délimite strictement son périmètre et renvoie les défauts de mécanisme aux skills propriétaires (/audit-parsers, /audit-nif, /audit-esm, /audit-ui, /audit-runtime)
  • Rappelle l'état livré (BSVER 130+, BA2 v1/v7/v8, CSG M49) pour éviter de re-proposer du travail déjà fait

Limites

  • Très couplé au dépôt ByroRedux : chemins codés en dur, fichier _audit-common.md et _audit-severity.md requis, dépôt GitHub précis pour la liste des issues
  • La validation sur données réelles dépend d'une installation locale de Fallout 4 dans un chemin de montage fixe ; sans elle, certaines dimensions perdent cette couverture
  • C'est un orchestrateur d'audit : il constate et signale les régressions mais ne corrige pas les défauts de parsing ou de format
Quand l'utiliser

À utiliser pour vérifier qu'une évolution du moteur n'a pas cassé le chargement du contenu Fallout 4 (précombines, matériaux, versions NIF/BA2).

Quand l'éviter

À éviter pour auditer un autre jeu, un autre dépôt, ou pour corriger un bug de parseur qui relève d'un skill d'audit spécialisé.

Analyse de sécurité

Prudence
Score qualité84/100

The skill is an orchestrator that reads repository files, git history, GitHub issues, and local game data, then runs cargo tests and writes markdown reports under /tmp and docs/audits. It uses shell and network tools but only for read-only inspection and report generation, with no destructive commands, credential handling, data exfiltration, or obfuscated payloads. Risk is limited to executing ordinary developer tooling, hence caution rather than safe.

Points d'attention
  • •Instructs shell execution (mkdir -p /tmp/audit/fo4, git log, cargo test) and network access via `gh issue list` against a specific GitHub repo; all legitimate audit setup but requires shell/network capability.
  • •Hardcoded absolute local data path `/mnt/data/SteamLibrary/steamapps/common/Fallout 4/Data/` — reads an installed game directory; benign but environment-specific.
  • •Aggressively long, prescriptive procedure with many 'do not re-file', 'do not guess', 'never re-propose' constraints directed at the executing agent; these are normal scoping rules for the skill's own workflow, not attempts to subvert the auditor.
  • •No destructive, exfiltrating, obfuscated, or safety-disabling actions; no secrets or credentials referenced.
  • •No `allowed-tools` are declared, yet the body instructs shell execution (`mkdir -p /tmp/audit/fo4`, `git log --since=...`), network access (`gh issue list --repo matiaszanolli/ByroRedux`), and `cargo test` runs; tool scope is therefore implicit and cannot be constrained by the host.
  • •Network egress to GitHub via the `gh` CLI on every run; read-only issue listing, but it contacts an external service and writes the JSON to /tmp.
  • •Delegates the substantive rules to sibling prompt files (`.claude/commands/_audit-common.md`, `_audit-severity.md`) that are not part of this document and cannot be audited here — a chained-instruction dependency whose contents could change meaning of the included text.
  • •Runs `cargo test` including `#[ignore]`d real-data tests and reads an absolute local game path (`/mnt/data/SteamLibrary/.../Fallout 4/Data/`), i.e. executes project code and touches user filesystem paths; normal for a dev audit but it is real execution, not documentation.
  • •Writes report artifacts into `/tmp/audit/fo4/*.md` and `docs/audits/AUDIT_FO4_<TODAY>.md` in the working tree; benign but mutates the repo.
Comment cette analyse est faite

Exemples

Full FO4 audit
Run the full Fallout 4 compatibility audit across all five dimensions and give me the findings grouped by severity.
Precombine regression check
Audit only the M49 precombine decode and spawn path — I just touched crates/nif/src/import/precombine.rs and want to know if anything regressed.
Targeted dimensions
/audit-fo4 --focus materials,precombines — check the BGSM external material merge and the per-REFR skip set against the shipped state.

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; 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.
  • 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. Guard: byroredux/src/asset_provider/tests/archive_precedence.rs (real-data, #[ignore]d — run it).
  • 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.
  • .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). 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).
  • 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 blob decode (PHYSAL, /audit-physics); 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. Known open, don't re-file: #5523 (SCOL CM path taken verbatim from MODL, 114 stale DLCRobot MODLs; the expansion gate is model_path emptiness only, so a set-but-absent CM is an extract_mesh miss and renders nothing — the documented absent-CM fallback does not exist). Regression guards: 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 only consumer is byroredux/src/ragdoll_pose.rs, gated to the 18-body Skyrim humanoid ragdoll (18b3d87a7) — FO4 skeletons are refused and keep the collapse, so FO4 corpses are still unposed (open #5015, forward scope; the layout is empirically derived, not sourced — do not widen the body-name gate on a count match alone).
  • 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 pose consumer for FO4 (#5015; Skyrim humanoids are posed), PKIN template-CELL instancing (skipped with a warn since #5231), BSBehaviorGraphExtraData parse-only (verify nothing pretends to drive it), 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.)

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/fallout-4-compatibility-audit-mvg6ty1i/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

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

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Le fichier ne fournit pas un en-tête name/description exploitable pour cette procédure native. Le téléchargement reste disponible pour lecture ; utilisez le mode manuel ci-dessous.

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/fallout-4-compatibility-audit-mvg6ty1i/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires