- Every format parser MUST live in its own
ltk_*crate undercrates/. - Crates MUST be independently compilable and usable without the umbrella
league-toolkitcrate. - The dependency graph MUST flow upward: foundation crates (
ltk_hash,ltk_primitives) have zero internal deps; format crates depend on foundation + I/O; higher-level crates depend on format crates. - Circular dependencies between crates are prohibited.
- The umbrella
league-toolkitcrate MUST re-export sub-crates via feature flags only — it MUST NOT contain business logic.
- Every format type that supports reading MUST also support writing unless the format is documented as read-only.
- Round-trip tests (parse -> write -> parse -> assert equal) are the primary verification pattern and MUST exist for all format crates that support both reading and writing.
- Floating-point comparisons in tests MUST use the
approxcrate, never direct equality. - Snapshot tests MUST use
instawith.ronformat. Snapshot changes MUST be reviewed viacargo insta reviewbefore committing. - Tests MUST be runnable in isolation — no shared mutable state between test cases.
- All code MUST pass
cargo fmt -- --checkwith zero differences. - All code MUST pass
cargo clippy --all-targets -- -D warningswith zero warnings (CI denies all warnings). - All code MUST pass
cargo test --verbosewith zero failures. - These three checks MUST pass before any merge to
main. - No
#[allow(clippy::*)]annotations without a documented justification in an adjacent comment.
- Reading MUST be implemented via
from_reader(&mut impl Read)(orRead + Seekwhen random access is required, e.g., WAD mounting). - Writing MUST be implemented via
to_writer(&mut impl Write). - Complex types MUST use the builder pattern (e.g.,
BinTree::builder(),RigResource::builder(),WadBuilder). - All vector/matrix types MUST use
glam(Vec2, Vec3, Vec4, Mat4, Quat).
- Shared dependency versions MUST be declared in the root
Cargo.tomlunder[workspace.dependencies]. - Individual crates MUST reference workspace dependencies with
workspace = true— pinning a version locally is prohibited unless the crate genuinely needs a different version (document why). - New external dependencies MUST be added at the workspace level first.
- Dependency additions MUST be justified — avoid pulling in large dependency trees for trivial functionality.
- Each crate MUST define its own error type via
thiserrorand aResult<T>type alias inerror.rs. ltk_metaadditionally usesmiettefor diagnostic errors; other crates MUST NOT addmiettewithout justification.- Unwrap/expect calls are prohibited in library code (non-test).
Use
?propagation or explicit error variants. unsafeblocks MUST include a// SAFETY:comment explaining the invariant that makes the usage sound.
- All changes MUST go through pull requests — direct pushes to
mainare prohibited. - PRs MUST pass the CI quality gate (fmt, clippy, test) before merge.
- Commits MUST use conventional commit format (e.g.,
feat(ltk_wad):,fix(ltk_meta):,chore:,refactor:). - Features MUST be developed on feature branches.
- Hashing algorithms are fixed by the game format: WAD paths use
XXHash64 (64-bit) of lowercased paths; Bin names use FNV-1a (32-bit)
via
ltk_hash. These MUST NOT be changed without format evidence.
- This constitution supersedes conflicting practices found elsewhere in the codebase. When a conflict is discovered, the constitution takes precedence and the conflicting artifact MUST be updated.
- Amendments require: (1) a documented rationale, (2) review of downstream impact on templates and specs, and (3) a version bump following SemVer.
- Version policy: MAJOR for principle removals or redefinitions, MINOR for new principles or material expansions, PATCH for wording clarifications.
- Compliance MUST be verified during code review — reviewers SHOULD reference specific principles when requesting changes.
- Runtime development guidance lives in
CLAUDE.mdat the repository root.
Version: 2.0.0 | Ratified: 2026-03-07 | Last Amended: 2026-03-25