4.5 KiB
ADR 0029: Validation-gated build profiles and packaging
Status
Accepted
Context
Blacksite builds previously required users to know Cargo commands and manually assemble assets. That made it easy to ship broken references, editor caches, recovery data, or an executable without the settings and content that produced it. Ordinary debug binaries are also too large for practical distribution, while release LTO is too expensive for every development package.
Decision
Projects define versioned RON profiles under assets/build_profiles/. A profile selects the Cargo
package profile, optional target triple and feature set, rendering tier, default scene, and a safe
project-relative output directory. Development and QA exports use dedicated optimized non-LTO Cargo
profiles; QA retains line tables, while release exports retain thin LTO and strip symbols. The
development rendering tier forces the portable Forward GI path in the packaged project settings;
representative and shipping tiers preserve the authored rendering policy. Windows MSVC QA packages
include Cargo's PDB sidecar and record it in the content manifest.
cargo package-project is the authoritative build/package entry point for editor and CI. It runs
scene::validate_project before compiling, builds game, reads the executable path from Cargo's
JSON artifact stream, then validates again against a BLAKE3 snapshot of the runtime inputs. A profile
default scene must be a regular .scn.ron file under the fully audited assets/levels/ tree and pass
schema plus composition validation. The selected default scene and rendering tier are applied to the
packaged project.ron. Metadata records profile, target, features, rendering tier, default scene,
exact engine/project commit and
dirty state, Rust/Cargo versions, and a sorted BLAKE3 content manifest. Features that require the
development or hot-reload dynamic libraries are rejected because those libraries are not shipping
artifacts.
Runtime packaging excludes the editor asset registry, trash, thumbnails, build profiles, recovery
and autosave data, temporary/backup files, and source-authoring formats. Traversal errors and runtime
asset symlinks are blocking instead of silently omitting content. Output is restricted to a dedicated
non-symlinked dist/<name>/ tree. A non-empty existing directory must carry recognized package
metadata before it can be seeded or pruned, preventing a profile typo from replacing project source
or an unrelated user directory.
Assembly happens in a unique sibling staging directory copied from the previous package. Staging has no shared file inodes with the published output, and its complete content is rehashed before promotion, so a failed build or external output edit cannot mutate the candidate package. An OS-backed per-output lock prevents concurrent publication on Unix and Windows. Versioned ownership records authenticate lock/staging cleanup; an interrupted run removes only owned partial staging and restores a strictly validated prior backup before retrying. Only a complete, unchanged-input package is promoted; stale files and obsolete directory shapes are pruned in staging. The editor Build panel invokes the same engine-workspace Cargo alias for the active external project, streams stdout/stderr, owns and cancels its worker/process tree, and exposes Build, Build and Run, and Reveal Output. Dirty scene tabs block a build. Cross-target packages are produced but Build and Run refuses to execute a binary for a different host operating system or CPU architecture.
Consequences
- Editor and headless builds have identical validation, profile, inclusion, and metadata semantics.
- Blocking content errors fail before compiler or output work and are checked again after a long compile. Concurrent asset mutation aborts staging without replacing the previous package.
- The first build of a package profile compiles optimized intermediates; later unchanged builds reuse Cargo intermediates and avoid rewriting byte-identical files after seeding the staged copy.
- Cross-compilation still requires the selected Rust target and platform linker/toolchain to be installed; missing tools are reported by Cargo in the Build panel. The native layout currently accepts desktop Linux and Windows targets only; web, mobile, and platform-bundle formats require dedicated future packagers rather than being mislabeled as ready native packages.
--skip-buildrequires an explicit matchinggameartifact, avoiding guesses about Cargo target directories or configured default targets.