Repository navigation
animaEngine 0.9.0 — the stability freeze
animaEngine 0.9.0 — the stability freeze
The release before 1.0 deliberately ships no new features. Its job
is to prove the 1.0 contract before promising it: measure what the
0.6–0.8 cycles built, harden the edges, and make the docs tell the
truth. Feature work stopped the day this phase opened; everything here
is migration safety, leak hunting, fuzzing, and audit.
Config that survives its own future
A top-level version key now records the config schema generation.
Files written before 0.9 have no key, are treated as schema v1, and
migrate on load — but the original is copied to config.toml.bak-v<n>
before any migration runs, so a migration bug can never be why you
lose a config. A malformed version is treated as current rather than
risking the wrong migration, and unknown [section] tables (e.g. from
a newer build) survive a load → save round-trip instead of being
dropped. v1→v2 is an honest identity migration — every change so far
was additive — but the chain, backup, and forward-compat are in place
and tested for the first change that isn't.
Proving memory is bounded
- Soak harness (
scripts/soak.sh): a 16-entity synthetic scene
under Xvfb, RSS least-squares-regressed against time to catch slow
leaks. The regression fits the steady state only — a cold start
legitimately steps memory once as the cache fills, and fitting across
that step would cry "leak" on a flat run. - Leak audit: every pre-registered suspect came back bounded with a
cited mechanism. The one real growth was the on-disk decode cache
(content-addressed keying orphans a file on every asset edit, never
reclaimed);cache::sweepnow evicts oldest-first past a 1 GiB cap at
startup, off-thread. - Perf HUD GPU block: the overlay (`Ctrl+Shift+``) shows a VRAM
estimate, live texture count + uploads/frame, and draw calls — the
same numbers the soak harness regresses, live.
Hardening
- GPU surface-loss recovery. A lost surface reconfigures in place
for the transient cases (resize, occlusion, the first frames after
suspend); a loss that persists past a threshold — driver reset, GPU
hot-unplug, device lost across S3 resume — rebuilds the whole renderer
from the retained window, and exits cleanly for a restart if even that
fails, rather than spinning on a dead device. - Expanded fuzzing. Three new cargo-fuzz targets over the
hand-written parsers closest to untrusted bytes: the on-disk cache
codec, the MP4 NALU length-prefix walk, and the Shimejiactions.xml
reader, with committed seeds and a nightly CI run. - XWayland fractional-scaling click-through is now detected and
warned about at startup instead of leaving misaligned clicks a
mystery — an inherent XWayland limitation, documented with the
workarounds. - Forward-compat with the upcoming rustc float-literal inference
change (caught by the weekly beta-toolchain canary before it became a
hard error).
Docs that match the code
- Reality audit: every
docs/*.mddiffed against the code.
config.mdnow documents every field (it was missing themes,
locale, monitor mode, the per-state animation sets, the windows /
groups / keybindings sections, and several env vars); the architecture
diagrams were reconciled with the post-0.6 module layout; the threat
model's stale claims were corrected (the AccessKit bridge is a live
flag, hotkeys are rebindable, release artefacts carry Sigstore
provenance, and the native-Wayland path is now near-parity through the
same drag-drop validation boundary). - Cross-locale audit: 194 keys × 10 locales came back clean on key
parity and placeholder parity — and the placeholder guarantee is now
a test, so a translator dropping a{ $var }fails CI. The sweep
fixed six corrupted strings from an earlier batch. - Freeze rules published.
CONTRIBUTING.mddeclares the bugfix-only
window to 1.0: what qualifies (crash, data loss, regression, security,
doc error, translation), what waits, and how exceptions get decided.
Audit notes (1.0-grade)
A full-tree re-audit, treated like the 0.5.0 pass. The panic surface is
clean: three unsafe blocks (two getuid, one wgpu surface handle, all
justified), and every production .unwrap() is either bounds-guarded
(the cache codec, also fuzzed) or a set-then-read invariant. The D-Bus
surface is five parameterless methods — no untrusted IPC input. Env
vars parse with fallbacks; size math is checked/saturating
throughout, gated by the decoded-bytes budget. Findings were fixed or
formally accepted in docs/threat-model.md.
Known limitations (accepted for 1.0)
- openh264 runs in-process, unsandboxed. MP4/H.264 playback reaches
Cisco's C decoder; we bound the input (caps, a pure-Rust demuxer that
pre-validates, a fuzzed NALU walk) but don't isolate the decoder.
A seccomp-confined decode thread is the right fix and is deferred past
1.0. If you don't play video, nothing reaches it. - A native-Wayland device-loss rework and an
Appstruct split are
deliberately deferred — both are out of scope under the freeze. - The visual a11y matrix and a screen-reader walkthrough still want a
human at a real session (tracked indocs/ux-audit-0.8.md).
# Debian / Ubuntu
sudo apt install ./anima-engine_0.9.0-1_amd64.deb
# AppImage
chmod +x animaEngine-0.9.0-x86_64.AppImage
./animaEngine-0.9.0-x86_64.AppImage