Skip to content

Search

Documentation

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.

Pe această pagină

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::now and SystemTime::now are 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:

  1. Two exports agree. Every example is exported twice in separate processes; the files must be byte-identical.
  2. Every platform exports the same bytes. Linux, macOS and Windows upload pack digests, and the digests are diffed.
  3. Every platform steps the same simulation. One digest per tick, 600 frames, five projects. The first differing line is the tick.
  4. 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

  • SHA256SUMS and build-provenance attestations, verifiable with gh 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.