Tooling & Host-Contract Audit

VerifiedCaution

Structured audit of the SDK, debug server, launcher handoff and CLI tools, with per-dimension focus parameters and delta-first change detection.

Sby Skills Guide Bot
SecurityAdvanced
11/7/2026
Claude Code
#security-audit#debug-server#sdk-contract#launcher#rust

Recommended for

Automated summary

Audits the tooling and host-facing contracts of the ByroRedux Rust repo (debug server and protocol, SDK, launcher boot/settings handoff, install detection, tool CLIs), rating each finding by dimension and exposure.

Strengths

  • Clearly bounded scope: six dimensions mapped to concrete file paths, plus an explicit list of out-of-scope surfaces delegated to other audit skills.
  • Actionable triage: per-crate grep and cargo test commands, with a rule against launching the windowed engine to exercise the debug server.
  • Practical exposure rubric: unauthenticated local file write or command execution in a stock build is HIGH, developer-only tool defects are LOW–MEDIUM, crash-window data loss is MEDIUM.
  • Delta-first workflow using git log since the last AUDIT_TOOLING report, so unchanged paths are not re-audited.

Limitations

  • Heavily coupled to one repository: paths, crate names, feature flags and documentation references are ByroRedux-specific.
  • Relies on shared files (_audit-common.md, _audit-severity.md) and a history of prior audit reports that the skill does not ship with.
  • The provided excerpt cuts off mid-Dimension 1, and parts of the protocol (issue labels, dedup rules) remain outside the visible text.
When to use it

Use it to periodically re-audit, or audit after a targeted change, the tooling contracts of a Rust engine/modding project before a release or before opening up to modders.

When not to use it

Avoid it on repositories other than ByroRedux, or for auditing rendering, parsers, saves or debug-server concurrency, which belong to other skills.

Security analysis

Caution
Quality score84/100

The document is a legitimate, detailed audit protocol. It does not exfiltrate secrets, pipe remote scripts to a shell, decode obfuscated payloads, or disable safety controls. Its execution risk comes from ordinary but powerful tooling (bash, cargo, git, gh network calls) and one scoped `rm -rf` cleanup on a skill-created temp path, so it rates caution rather than safe. No embedded prompt-injection or instruction-override attempt was detected in the content.

Findings
  • •Instructs running shell commands (mkdir, grep, git log, cargo test, gh issue list) without any declared allowed-tools, so an agent would need bash/network access that the manifest does not grant.
  • •Phase 3 cleanup issues `rm -rf /tmp/audit/tooling` — a recursive delete. It is scoped to a directory the skill itself creates, but a variable-substitution or cwd mistake could widen its effect.
  • •Uses network access via `gh issue list --repo matiaszanolli/ByroRedux`, reaching an external repository; the repo slug is fixed and not attacker-controllable in the text.
  • •Declared allowed-tools is empty, but the skill instructs the agent to run shell commands (mkdir, cargo test, grep, git log, gh issue list) and delete a temporary directory.
  • •Runs `cargo test` against repository code, which compiles and executes project tests/build scripts; only appropriate in a trusted checkout.
  • •Makes an outbound network request to the GitHub API via `gh issue list --repo matiaszanolli/ByroRedux`.
  • •Contains `rm -rf /tmp/audit/tooling`, which is destructive but scoped to a fixed temporary path.
  • •Writes an audit report into the repository's `docs/audits/` directory, modifying the working tree.
How this analysis is made

Examples

Debug trust boundary only
Run the tooling audit scoped to the debug area: --area debug. Check the debug-server bind/authentication, the protocol registry and debug_load path confinement, then report findings with Dimension and Exposure fields.
SDK and launcher contract
Audit the SDK contract and the launcher boot handoff dimensions only (--focus sdk, launcher). Compare against the most recent docs/audits/AUDIT_TOOLING_*.md and list any new HIGH-exposure issues.
Delta since last audit
Run a delta-first tooling audit: check git log since the last AUDIT_TOOLING report across the tooling paths, deep-audit only the changed dimensions, and include cargo test counts for the relevant crates.

description: "Audit of tooling and host-facing contracts — SDK (Studio snapshots, typed commands, StorageUtil compat), debug server + protocol + byro-dbg, debug-ui panels, launcher/boot-request/settings-io handoff, install detection, byro-detect, texture-upscale" argument-hint: "--focus <dimensions> [--area sdk|debug|launcher|detect|tools]"

Tooling and Host-Contract Audit

Read _audit-common.md and _audit-severity.md for shared protocol.

Surfaces a modder, player or developer touches instead of the engine: a TCP command port evaluated against the live World, the renderer-independent SDK, the launcher's boot/settings handoff and the tool CLIs. Not here: crates/mod-runtime (/audit-safety Dim 8); debug-server locks/threads (/audit-concurrency Dim 7); the egui pass (/audit-renderer); VDF/ACF parsing (/audit-parsers); save schema (/audit-save).

| Area | Code (docs) | |---|---| | sdk | crates/sdk/src/ (identity, manifest, service.rs, studio.rs, compatibility/); adapters byroredux/src/studio_host.rs, byroredux/src/commands/studio.rs, byroredux/src/extensions/ (docs/engine/sdk-v0.1-development-plan.md, docs/engine/sdk-v0.1-next-action-plan.md) | | debug | crates/debug-server/src/{listener,system,evaluator,registration}.rs, crates/debug-protocol/src/{lib,wire,registry}.rs, byroredux/src/debug_load.rs, tools/byro-dbg/src/, crates/debug-ui/src/ (panels also host the player menu, inventory, HUD) (docs/engine/debug-cli.md) | | launcher | crates/boot-request/src/, crates/settings-io/src/, crates/core/src/atomic_file.rs, tools/byro-launcher/src/, byroredux/src/boot/cli.rs (expand_boot_request) (docs/engine/launcher.md) | | detect | crates/game-detect/src/{catalog,steam,profiles,validate,overrides}.rs, crates/core/src/ecs/game_profiles.rs, assets/debug_profiles.toml, tools/byro-detect/src/main.rs (docs/engine/launcher.md §3) | | tools | tools/texture-upscale/src/ (tools/nifskope is vendored, not first-party) |

Parameters (from $ARGUMENTS)

  • --focus <dimensions>: dimensions to run (default all 6). --area <name>: one area.
  • Delta-first: run each First step and git log --since=<last AUDIT_TOOLING date> -- <Paths>; deep-audit only dimensions whose Paths changed.

Extra Per-Finding Fields

  • Dimension: Debug Trust Boundary | Protocol & Registry | SDK Contract | Boot Handoff & Persistence | Install Detection | Tool CLIs
  • Exposure: who can reach it (any local process / launcher user / modder / developer only). Unauthenticated local file write or command execution in a stock build = HIGH; developer-only tool defect = LOW–MEDIUM; user data loss in a crash window = MEDIUM.

Phase 1: Setup

  1. mkdir -p /tmp/audit/tooling; gh issue list --repo matiaszanolli/ByroRedux --limit 200 --json number,title,state,labels > /tmp/audit/tooling/issues.json; dedup per _audit-common.md.
  2. Read the newest docs/audits/AUDIT_TOOLING_*.md if any.
  3. cargo test for -p byroredux-{sdk,debug-server,debug-protocol,debug-ui,boot-request,settings-io,game-detect} and -p byro-{launcher,detect,texture-upscale}; record counts. Do not launch a windowed engine to exercise the debug server (feedback_no_parallel_engine_launch).

Phase 2: Dimensions (max 3 concurrent agents)

Dimension 1: Debug-server trust boundary

Paths: crates/debug-server/src/{listener,system,evaluator}.rs, crates/debug-protocol/src/{lib,wire}.rs, byroredux/src/main.rs (start site, debug_server_allowed), byroredux/src/debug_load.rs (cell-load path confinement), byroredux/Cargo.toml. First step: grep -n 'bind\|MAX_\|fs::write\|create_new\|from_secs' crates/debug-server/src/*.rs crates/debug-protocol/src/wire.rs. Facts (re-verified 2026-10-20): bind is the literal ("127.0.0.1", port); no authentication; debug-server is a default feature of byroredux, started from main.rs on BYRO_DEBUG_PORT (default 9876). Debug builds always bind; release builds bind only with BYRO_DEBUG_SERVER=1 (debug_server_allowed, guard release_debug_server_requires_explicit_opt_in; 63c0aee3b, #4752), so the exposure is every local process on a debug build or an opted-in release. Caps: MAX_QUEUED_COMMANDS 64, MAX_CONCURRENT_CLIENTS 8 (#3449), 300 s read timeout, 16 MB frame (MAX_MESSAGE_SIZE, enforced by both encode and decode), MAX_WALK_DEPTH 64. The timeout pair lives in crates/debug-protocol/src/lib.rs: COMMAND_RESPONSE_TIMEOUT 30 s (server wait) < CLIENT_READ_TIMEOUT 35 s (byro-dbg read), ordering pinned (cc5468813, #5140). Guards: try_enqueue_rejects_when_queue_is_full, connections_past_the_cap_are_refused, occupied_port_is_reported_before_a_handle_is_returned (listener.rs); rejects_oversized_message, encode_rejects_response_payloads_over_the_protocol_limit (wire.rs); cancelled_screenshot_does_not_skip_same_frame_command_drain, cancelled_command_is_answered_without_evaluation, rejects_absolute_and_parent_paths (system.rs); walk_depth_is_capped_even_for_untrusted_requests (evaluator.rs); output_path_is_confined_to_the_dump_directory (commands/assets.rs); cell_load_paths_are_confined_to_startup_roots, confinement_rejects_a_symlink_out_of_the_root (debug_load.rs); the_listener_binds_loopback_only (listener.rs; 224180508, #5149 closed) asserts handle.local_addr().ip().is_loopback() on a port-0 spawn, so a 0.0.0.0 bind now fails a test. Regression guards, both fixed in 72a63616b (#5147 closed): the default output names self-unique under create_new (unique_default_dump_name_in → tex_dump.png, tex_dump_2.png, …; unique_screenshot_name_in → screenshot_<secs>.png, screenshot_<secs>_2.png; pinned by repeated_bare_tex_dumps_take_free_suffixes, same_second_bare_screenshots_take_free_suffixes), while an explicitly named output keeps the fail-rather-than-clobber contract; a constant default name is the regression. Checklist:

  • Capability surface = the whole console: eval_request dispatches every registered dotted command; SetField writes any registered component field. File reads are confined: LoadNif loose paths and the LoadInteriorCell/LoadExteriorCell ESM/master/archive paths all go through confine_to_roots against startup_asset_roots() (relative, normal components, canonicalised inside a startup --esm/--master/--bsa root; one rejected path rejects the whole load; 554259315, #5165). The syntactic half (relative, no ..) lives once in byroredux_core::ecs::is_root_relative_load_path, which confine_to_roots uses and eval_queue_load (evaluator.rs) applies at enqueue through PendingDebugLoad::first_non_root_relative_path, so a client sending an absolute path gets an Error naming it instead of an Ok and a silently dropped load (cff99166e, #5290); only the root-existence/canonicalisation half still resolves engine-side at drain time. File writes are confined: write_screenshot (system.rs) takes a single filename under screenshots/ with create_new (no overwrite), and tex.dump goes through safe_tex_dump_path (byroredux/src/commands/assets.rs, texture-dumps/). Archive-backed debug NIF loads (and --mesh/--tree) resolve their loose-file miss through TextureProvider::extract_mesh (last-listed-wins, BA2 dispatch, named corrupt-entry fall-through; 44219e881, #5009), and the hygiene guard no_production_code_opens_archives_outside_the_provider_layer (byroredux/src/workspace_hygiene_tests.rs) fails on a raw BsaArchive/Ba2Archive open in the bin crate. Check a new path-taking request goes through the same helpers and that no other command reads or writes a client-chosen path. Ask whether each mutating or file-writing command (tex.dump, screenshot, dumps) should be reachable unauthenticated in a player build; size by Exposure.
  • Evaluator bounds: parse_expr runs on the engine thread in the Late exclusive (depth caps in crates/papyrus/src/parser/); WalkEntity.max_depth is clamped by bounded_walk_depth; other entity/Value responses are unbounded until encode refuses them.
  • An over-limit response is replaced by an error response in handle_client (the InvalidData arm) rather than a torn frame — verify the fallback itself cannot exceed the limit and that the command's side effects already ran. A decode error (even an unknown variant) drops the connection: intended?
  • The drain system runs evaluate inline, so a slow query stalls a frame; is there a per-request cost bound? Lock order is /audit-concurrency (debug_evaluator_acquires_locks_in_canonical_order). Abandoned requests (PendingCommand.cancel, #1007) and the SCREENSHOT_OWNER_* claim must release on client timeout; the drain answers an already-cancelled command with an error instead of evaluating it, and keeps running while a native pause/settings/inventory page gates the scheduler (Scheduler::run_exclusive_named, 00115f7a5, #5141), naming the system through the shared DRAIN_SYSTEM_NAME constant (crates/debug-server/src/system.rs) with a debug_assert on the returned bool (8a9989070, #5292; source-scan guard in byroredux/src/scheduler_access_tests.rs) — a paused frame path that skips the drain, or a hand-typed copy of the name, re-creates the burst-on-unpause replay.

Dimension 2: Protocol and registry completeness, wire compat

Paths: crates/debug-protocol/src/{lib,registry}.rs, crates/debug-server/src/registration.rs, tools/byro-dbg/src/{main,display,tui}.rs, docs/engine/debug-cli.md. First step: grep -c 'register_component::<' crates/debug-server/src/registration.rs; diff against inspect-derived components (grep -rn 'cfg_attr(feature = "inspect"' crates/core/src).

  • Re-derive counts: docs/engine/debug-cli.md must report N in both the "Currently registered (N components)" heading and the byro> components example transcript (debug_cli_component_counts_match_the_registry requires ≥2 occurrences since f2d0b6ea0, #5417). N = the production-text register_component::< calls plus the hand-built register_faction_reputation descriptor: 73 + 1 = 74 (re-verified 2026-10-20) (67 → 71: the M42 Eat/Sleep trio plus EditorPlacement, #5391; 71 → 72: CreatureActor, 9bb8bc475 #5495; 72 → 74: CharacterLevel, dbe562c1f, and LevelUpPoints, f0ca6eda1). A whole-file grep -c prints 76 because the test module's own needles add lines; count production text. The same test now also requires a | Name | table row in the doc for every registered name (3ad23b3e4, #5694: the table had carried 67 of 72 rows under a passing count).
  • Completeness guards (registration.rs): every_inspectable_component_is_registered walks crates/core/src for every type carrying the inspect derive and implementing Component and fails unless each is registered (977793679, #4755, took the registry 49 → 67), plus the older every_ai_procedure_behavior_component_is_registered (#4063). Remaining gap class: components outside crates/core/src (engine-crate or other-crate components with inspect derives) the walk does not see — enumerate those and judge which hold user-visible state.
  • Wire: 4-byte BE length + JSON, serde-tagged DebugRequest; no version or handshake field, so engine and byro-dbg must come from one workspace commit. Guards: round_trip_request, round_trip_response (wire.rs). Metrics ride DebugResponse::Metrics(MetricsPayload) (f64a299ec, #5822: byro-dbg stores the payload as-is, debug-ui reads core's MetricsSnapshot directly); the one remaining cross-seam copy is eval_metrics (evaluator.rs). The metrics_response_mirrors_core_snapshot guard that the variant's doc and #5822 cite does not exist (never did, per git log -S): a field added to core's MetricsSnapshot is silently dropped from the wire. Report it until a test lands.
  • A new DebugRequest / DebugResponse variant must reach the evaluator dispatch, parse_shorthand and display.rs in byro-dbg, and handle_response / variant_name in tui.rs; a _ => arm in any of them hides a missing variant. byro-dbg sets its socket read timeout to CLIENT_READ_TIMEOUT (configure_read_timeout, guard read_timeout_exceeds_the_server_response_timeout); the TUI net thread treats a read timeout as "engine busy", not a disconnect. Its only other test is parses_common_shorthand_requests — variant coverage in display.rs / tui.rs is untested. The never-constructed DebugResponse::Screenshot variant was deleted (6f38b335d, #5150); a dead variant still matched by the client is the same class.
  • Console docs vs the dispatch table (registry.register( in byroredux/src/commands/mod.rs): every_registered_command_is_named_in_debug_cli_docs (same file) requires the doc's Current registered commands (**N**) to equal the live registry and every registered name to appear (130 after ab34039b8, #6056; re-derive). It does not check the reverse (a documented command that no longer exists), so diff that by hand. set_field never panics on bad JSON.

Dimension 3: SDK contract surface

Paths: crates/sdk/src/, byroredux/src/{studio_host.rs,commands/studio.rs}, crates/debug-ui/src/panels.rs, the two SDK plan docs. First step: cargo tree -p byroredux-sdk --depth 1 and grep -rn 'byroredux_core::' crates/sdk/src.

  • Facts (2026-09-19): #![forbid(unsafe_code)]; deps are byroredux-core (only math::Vec3 used), semver, serde, thiserror; StudioSession is pub(crate) in byroredux/src/studio_host.rs, not the SDK.
  • Plan gates: an explicit checked dependency list (no renderer/UI/platform/archive/Wasmtime), "Rust/WIT schema drift fails CI" (crates/mod-runtime/wit/host.wit), warning-free docs, and "no supported SDK value exposes an ECS ID or engine pointer". Find the test or CI step for each (none found for the dependency list, 2026-09-19). The plan is In progress: report only gates the docs call delivered.
  • API leak: a pub SDK item exposing an engine type (Entity, World, FormId, glam beyond Vec3) instead of a stable id (ObjectId, AssetId, EntityRef, FormRef); pub value-type fields are unvalidated by construction.
  • Actor-value projection: ActorValueState has no set_override slot, so extensions/capture.rs folds the #5412 layer into base (base + set_override) and a mod reads back its own routed SetBase (627149b62, #5508); a projection that drops the layer, or re-sums the layers by hand instead of ActorValue::undamaged(), is the regression (byroredux/src/extensions/tests.rs).
  • Validation lives in the host: valid_transform / valid_material in studio_host.rs reject non-finite values, while the clamps (sanitize_transform, sanitize_material) sit in the egui panel; every non-UI command path (extensions, commands/studio.rs) must reach the host validators.
  • Snapshot determinism: ids come from a sorted canonical set (plan Phase 1); check no HashMap iteration order reaches a StudioSnapshot or serialized output. Identity guards: object_ids_reserve_zero_and_assign_one_based_ordinals, namespaced_ids_reject_path_and_whitespace_spoofing, capability_sets_are_validated_and_deduplicated.
  • Every *_CAPABILITY constant in service.rs is checked at a real call site (count by grep); an unchecked one is a grant without a gate (enforcement is /audit-safety Dim 8).
  • StorageUtil / list verbs (crates/sdk/src/compatibility/storage_util/ — mod.rs scalar + codecs, list.rs, declarations.rs): bounded sizes and deterministic order per the plan's compatibility table; every provider alias maps to a route, policy and fixture; the unsupported boundary (file-backed state, JContainers JSON/Lua, menu mutation) fails explicitly, never no-ops.

Dimension 4: Launcher boot handoff and persistence

Paths: crates/boot-request/src/, crates/settings-io/src/, crates/core/src/atomic_file.rs, crates/game-detect/src/overrides.rs, tools/byro-launcher/src/, byroredux/src/boot/cli.rs, byroredux/src/cli_args.rs. First step: grep -n 'fs::write\|atomic_write\|CONTRACT_VERSION\|SETTINGS_VERSION' crates/boot-request/src crates/settings-io/src crates/game-detect/src tools/byro-launcher/src. Guards: version — an_unknown_contract_version_is_refused_by_version_not_by_field, a_missing_version_is_a_mismatch_not_a_default; precedence (docs/engine/launcher.md §2.4) — explicit_command_line_flags_suppress_their_request_counterparts (crates/boot-request/src/args.rs), boot_request_seam_tests in boot/cli.rs; settings — saving_a_partial_registry_preserves_keys_it_does_not_know, stale_and_invalid_values_do_not_block_valid_siblings, a_save_does_not_revert_another_frontends_newer_value, save_refuses_when_the_existing_file_does_not_parse, save_refuses_to_downgrade_a_newer_version_file, the_shipped_presets_apply_cleanly_to_the_real_builtin_registry; durability — atomic_file.rs::{failed_rename_removes_the_temp, clobber_guard_accepts_the_writer_shape_and_rejects_fallbacks}, save_has_no_nonatomic_clobber_fallback (boot-request, settings-io), merge_uses_the_shared_atomic_file_writer + merging_preserves_comments_and_formatting (overrides.rs); supervision — the_engine_is_invoked_with_the_boot_request_path_and_profiles_env, the_log_tail_is_bounded_and_keeps_the_most_recent_lines, and (da3f62128: EngineProcess::poll lets the stderr reader reach EOF, bounded by READER_DRAIN_TIMEOUT 250 ms, before snapshotting the crash tail) a_crash_tail_waits_for_the_stderr_reader_to_drain, a_crash_report_is_not_held_hostage_by_a_lingering_descendant (tools/byro-launcher/src/engine.rs). Checklist:

  • CLI flag reads (byroredux/src/cli_args.rs, owned here): only the space-separated --flag value form is accepted, and parse_string_arg warns on the --flag=value spelling instead of silently dropping it (the_equals_form_is_reported_rather_than_silently_dropped). Plain value lookups (--esm, --cell, --grid, --wrld, --radius, --kf, --rotation-mode, --bench-frames) and the repeatable --master collectors go through parse_string_arg / parse_all_string_args (parse_all_string_args_collects_repeats_and_skips_flag_values) and esm_discovery_root, never a hand-rolled args.iter().position(..) (d8a6e58bf, #5598). The raw-by-design flags (--swf, --bsa, --menu, --studio, --cmd, ...) error on a missing value, which parse_string_arg's None would weaken; a new flag reader should pick one deliberately.
  • atomic_write (unique hidden temp sibling -> fsync -> read-back -> rename -> parent fsync, #3472) is the durability contract, used by all three writers: BootRequest::save, RootOverrides::merge_into_file, settings-io save_to_path. The non-atomic "Windows rename" fs::write fallback is gone (2e95f0bbf, #5143) and any staging error removes the temp (69fd54fb2, #5163); each writer is pinned by the shared structural scan atomic_file::assert_no_clobber_fallback over production text only (#5164). A fallback, a second atomic_write call, or an fs::write/fs::rename reappearing in a writer is the regression. merge_into_file now edits a toml_edit::DocumentMut, touching only changed [roots] entries and skipping the write when nothing changed (7f2cee3e8, #5166).
  • Version policies: boot-request refuses a mismatch; settings-io load logs and "attempts compatible values", while save refuses a newer-version file (no silent downgrade), copies an unparseable file aside as <name>.bad and refuses, and refuses a non-NotFound read error (2e95f0bbf, #5144).
  • Lost updates: there is still no file lock, but SettingsPersistence keeps a per-frontend baseline (shared through an Arc across clones) and save_to_path writes only ids whose value moved off it; the launcher reloads on opening Settings and on engine exit (c9f95283a, #5162). Check a new save path goes through the baseline, not a full-registry write.
  • Precedence: settings path is SETTINGS_PATH_ENV, then the platform config dir, then a cwd fallback (discover_settings_path); games root is --games-root, BYROREDUX_GAMES_ROOT, then DEFAULT_GAMES_ROOT, one developer's path (crates/game-detect/src/profiles.rs) — a player's machine silently resolves to a missing directory; does anything say so? discover_settings_path's sibling for profiles is user_profiles_path() (crates/game-detect/src/profiles.rs, one per-user path shared by launcher, byro-detect and the engine); $BYRO_PROFILES redirects every per-user layer (profile merge and both [roots] passes) and the launcher exports it on the engine it spawns, so a custom --profiles file stays self-consistent (322c36626, #5294) — a private ~/.byroredux/profiles.toml copy is the regression. 61ad29da3 (#5476) finished it: the [defaults] layer (game, games_root, light_atten_*) now runs through selected_user_path() too (ordered_config_paths_with), the launcher's LauncherState::load/refresh and byro-detect build their registry with load_with_user_path(Some(&profiles_path)) (not load_default()), and a relative --profiles is made absolute before the engine spawns with current_dir(engine.parent()). A path that still reads ~/.byroredux/profiles.toml directly, or a launcher registry built from the process's own home, is the regression. The strict --profiles arm and absolutise_against_cwd live once in crates/game-detect/src/profiles.rs (parse_profiles_arg; 0f07131a8, #5739), taking OsString arguments so a non-UTF-8 path is accepted rather than panicking (b3ca11cf1, #5911; accepts_a_non_utf8_profiles_path_without_panicking, rejects_an_empty_profiles_path in both tools); an explicit profiles file also supplies the [roots] overrides (root_overrides_path; 21538a9d0, #5910; explicit_profile_file_also_supplies_root_overrides). A private flag-arm copy in a tool is the regression. boot.toml paths are absolute and never ~-expanded (docs/engine/launcher.md §2.2) while profiles.rs expands ~/ on roots — check they agree.
  • The launcher must run when the engine cannot (no Vulkan): cargo tree -p byro-launcher may show ash (pre-flight probe) but not the renderer, byroredux-ui or any wgpu (eframe runs on glow; cargo tree -p byro-launcher -i wgpu empty after the 2026-10 egui 0.36 / wgpu 30 bump, docs/engine/launcher.md); a_directory_with_the_engine_name_is_not_the_engine guards locate_engine. The preflight probe (tools/byro-launcher/src/preflight.rs) reads extension and device names through bounded from_bytes_until_nul accessors, scanned by the renderer's device_names_read_through_bounded_accessors guard (d3225bb2f, #5717).

Dimension 5: Install detection and profile registry

Paths: crates/game-detect/src/{catalog,steam,profiles,validate}.rs, crates/core/src/ecs/game_profiles.rs, byroredux/src/game_profiles.rs (re-export shim), assets/debug_profiles.toml, tools/byro-detect/src/main.rs. First step: cargo test -p byroredux-game-detect and git log --since=<last report> -- crates/game-detect assets/debug_profiles.toml.

  • Steam only today (~/.steam/*, ~/.local/share/Steam, Flatpak, macOS, Windows ProgramFiles*; the registry probe is marked "still to do"); GOG/Epic and Wine prefixes are not probed — a Wine install is reachable only via a manual [roots] entry, which byro-detect says when nothing is found. A manifest installdir must pass is_bare_install_dir (non-empty, not ./.., no /, \ or :; aad5dfd75, #5016; only_a_bare_directory_name_is_a_valid_installdir) — a Path::is_absolute-style check reappearing misses Windows \X / D:X shapes.
  • Alternate releases ([[profiles.<key>.releases]], chosen by files on disk via GameProfileEntry::for_data_dir): guards an_alternate_release_is_validated_against_its_own_archives, the_primary_release_wins_when_its_archives_are_all_present, a_release_replaces_only_the_lists_it_names. The launcher validator, the engine's expand_game_profile_args (byroredux/src/boot/cli.rs) and studio_host.rs must all go through for_data_dir, not a private copy; sibling rules come from byroredux_bsa::numeric_sibling_paths.
  • Env-var spelling: canonical is BYROREDUX_<GAME>_DATA (crates/plugin/src/esm/test_paths.rs, e.g. BYROREDUX_SKYRIMSE_DATA). 63c0aee3b (Session 91) unified the Skyrim SE split; the legacy BYROREDUX_SKYRIM_DATA survives only as a repo-variable fallback in .github/workflows/playable-smoke.yml (#4760 closed; its Rust/script readers are gone). A new reader of the old name is a regression of that unification (#3741 was the earlier same-class failure).
  • validate.rs: a zero-byte or truncated .esm / archive must fail at the right Severity, not pass and then abort the engine. esm_opens reads only a bounded 1 MiB TES4 prefix and fails closed on an over-declared header (d6b495f2a, #5145); a whole-file read on the launcher UI thread is the regression.
  • byro-detect: exit failure when nothing is found, text output only, --write records [roots] via the formatting-preserving merge (Dim 4); arguments parse strictly (the launcher's --profiles too, #5294) — an unknown flag, a missing/flag-shaped or repeated --profiles value is a usage error (exit 2, nothing written; ad6967fa9, #5167; rejects_an_unknown_flag) — check --help matches behaviour.

Dimension 6: Tool CLIs

Paths: tools/texture-upscale/src/. First step: cargo test -p byro-texture-upscale.

  • texture-upscale (MANIFEST_VERSION 1, Manifest::validate): output_png_path follows validate_asset_path (rejects absolute, ., .., empty segments); overwrite refused without --overwrite; --dry-run creates nothing (dry_run_checks_the_plan_without_creating_output_or_launching_the_model); dimensions overflow-checked (scaled_dimensions_reject_overflow); disk space checked first (insufficient_space_is_rejected_before_writes), and a read-only output or scratch volume is refused by role through the pure refuse_read_only (space.rs; e7913ec21, #5695; read_only_output_or_scratch_is_refused_by_role).
  • Trust: the upscaler is Command::new(&manifest.upscaler.program) with .args(..) (no shell), so the manifest is executable trusted input; README/--help must say so.
  • Output collisions and per-set failure are fixed (#4761/#4762): validate claims each source's output PNG across every set (manifest_rejects_sources_that_share_an_output_png); a bad set is reported, not batch-fatal (one_bad_set_does_not_abort_the_batch), while an unlaunchable upscaler still aborts (an_unlaunchable_upscaler_still_aborts_the_batch). Check: SourceStack "later overrides earlier" matches the engine's last-wins order (/audit-parsers Dim 6).

Phase 3: Merge and Cleanup

Write docs/audits/AUDIT_TOOLING_<TODAY>.md: Executive Summary (findings by severity, areas swept), deduplicated Findings, and an Exposure Matrix (surface x {reachable by, authenticated, size-capped, persistence atomic}). Cross-audit dedup: debug-server locks /audit-concurrency Dim 7; sandbox enforcement /audit-safety Dim 8; save schema /audit-save; VDF/archive parsing /audit-parsers. Then rm -rf /tmp/audit/tooling and suggest /audit-publish docs/audits/AUDIT_TOOLING_<TODAY>.md (labels: tech-debt for debug-server/launcher/tools, which have no label of their own; doc-rot, test-gap as fitting).

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/tooling-host-contract-audit-mvhm5m4e/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/tooling-host-contract-audit-mvhm5m4e' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/tooling-host-contract-audit-mvhm5m4e/download' --output '.skill-downloads/tooling-host-contract-audit-mvhm5m4e/SKILL.md.part' && mv '.skill-downloads/tooling-host-contract-audit-mvhm5m4e/SKILL.md.part' '.skill-downloads/tooling-host-contract-audit-mvhm5m4e/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/tooling-host-contract-audit-mvhm5m4e/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