Quality: the checks every change passes
Balaur CI: rustfmt and clippy on three platforms, house lints, ~1,200 tests, every example run twenty ways, and determinism traces.
في هذه الصفحة
Every rule here is a script. Every script runs on every push and pull request. docs/QUALITY.md has the same list with file paths.
Workflows
One workflow owns the triggers and calls four.
| Workflow | Covers |
|---|---|
lint |
everything that reads the code without running it |
docs |
both kinds of documentation |
test |
everything that runs the engine |
build |
everything that produces a download |
A pull request runs all four. Only the release-publishing job is skipped.
The compiler
- A pinned toolchain: one linter version on every machine.
- Formatting checked and Clippy with warnings denied, on Linux, macOS and Windows.
- Once more per off-by-default feature: the windowed backend (wgpu, egui, the macOS dock icon), extensions (dlopen and the cdylib), the Apple stores.
- One example extension built outside the workspace, without the engine's build tree.
House lints
Three scripts, two severities. Error fails CI and is mechanical. Report prints only.
| Rule | Fails on |
|---|---|
| platform float math | .sin(), .powf() and the rest that differ between operating systems; sqrt, abs and floor are exact and allowed |
| nondeterministic iteration | iterating a hash map or set |
| channels outside the recorded seam | anything that could reach the outside world during a replay |
unjustified unwrap |
unwrap or expect outside tests without a justification |
allow without a reason |
an #[allow(..)] that does not say why |
| TODO without an issue | a TODO with no issue |
| function and file length | 120 lines, 1200 lines |
| naming | the mechanical half of the naming rules, a dozen checks |
| two Rune traps | shapes that compile and then misbehave |
| Also held | How |
|---|---|
| The ratchet | A per-file baseline records the violations predating each rule. Above that count fails. The baseline is never raised by hand |
| Comments | One or two lines stating a constraint, in Rust, Rune, Python, shell, YAML and TOML. A block over three lines fails, as does one that restates the line under it |
| Names | Decided once and checked mechanically. The API half boots the engine and reads what it offers |
Determinism
Two determinism breaks are compile errors:
- Wall-clock time.
Instant::nowandSystemTime::noware banned. - Entropy. Unseeded randomness is banned; a call outside the simulation carries a written reason.
Line endings are pinned in the index. CI checks four things:
- Two exports agree. Every example is exported twice in separate processes; the files must be byte-identical.
- Every platform exports the same bytes. Linux, macOS and Windows upload pack digests, and the digests are diffed.
- Every platform steps the same simulation. One digest per tick, 600 frames, five projects. The first differing line is the tick.
- The same sources build the same binary. Built twice on one runner and compared.
A change that alters a recorded digest has to say why.
Tests
About 1,200 tests across 22 crates, on three desktop platforms. Beyond the plain run:
- the extension path, off by default;
- a build with the optional subsystems switched off;
- suites that boot a full app and talk over real sockets.
A test's name is a sentence about behaviour:
freeing_a_node_frees_its_children. A test asserting from inside a script
carries one control proving the script ran.
Example passes
Six example projects, twenty passes each, on three platforms:
| Pass | What it proves |
|---|---|
| run | dev mode, from the sources |
| export, twice | the two packs match |
| play | the exported pack runs without the sources or a compiler |
| edit, sixteen times | the editor, itself a Balaur project, booted headless against every example |
The editor passes drive undo, layout, rigging, the polygon tool, plugins, the clipboard, the assets dock, picking, script properties, prefab instances, placement, the profiler, session recording and the theme switch.
Every pass needs a clean exit and a clean log. A logged error fails the run, as does an editor scene node the editor cannot resolve.
Headless covers loading, mirroring and asset rebinding. Drawing is one screenshot per editor screen, rendered offscreen and diffed against a committed catalogue before any change to the editor's shell.
Generated documentation
- Rustdoc builds with warnings denied; a dead intra-doc link fails.
- The generated docs (script API, components, assets, behaviour) are rebuilt from a booted engine on every push. Any diff fails.
- The third-party notices file is regenerated and diffed the same way.
- This site builds its reference from that data.
Performance
- Feature tests and performance tests are separate.
- Budgets assert orders of magnitude, never percentages.
- Every ceiling is ten times a measured run, written in one place.
- They catch an O(n²), a lock held across a frame, or a compile moved into the hot path. A five percent regression is for the benchmarks.
Supply chain
- Advisories, bans and sources are checked on every push with all features on.
- Yanked crates, unknown registries and git sources are denied.
- The two forks the engine uses are allowlisted by name, with the reason recorded.
Releases
SHA256SUMSand build-provenance attestations, verifiable withgh attestation verify.- Every push exports a game through the published actions a player's repository calls, against the engine that run built.
Review
Review covers what a script cannot check:
- whether the change serves the principles;
- whether the name is the right name;
- whether the test asserts on behaviour a caller can see.
One concern per pull request. Code, tests and docs land together, and the roadmap moves with the change.