Repository navigation
Chantier: post-audit reliability hardening #102
Description
Context
A full audit of the codebase (read-only, commit 452596e) targeted three areas: JSON scenario
generation quality, component overflow handling, and the engine's ability to produce the
"dark premium" marketing style of the reference videos.
It found 2 critical, 8 high and 9 medium issues. The headline conclusion: the render
engine is markedly stronger than its authoring surface. Real 3D (M44 with perspective divide),
keyframed camera, multi-plane parallax, both blur kinds and the spring/cubic-bezier easing solver
all work correctly. What is broken is the chain of trust around them — the validator green-lights
scenarios that render invisible text, column-less grids, and content spilling out of its card.
Every finding below was reproduced against a release build, not inferred from reading code.
Decisions taken at kickoff
| Question | Decision | Rationale |
|---|---|---|
grid component |
Wire tracks through to taffy | taffy supports CSS Grid natively and the schema already models tracks; a KPI row is the single most common marketing layout |
| Unknown top-level attributes | Error by default, and --strict-attrs made available to render |
This is the class of failure that produces a silently wrong video; all 7 repo examples must still validate |
| Delivery cadence | Wave 1 (critical + high), review, then wave 2 (medium) | Keeps each review sitting reviewable |
| Base branch | origin/main |
All code findings exist there; the in-flight 1600-template branch lands separately |
Frozen contracts
Read-only for every workstream. Changing one requires updating this issue first.
- Colour parsing entry point —
crates/rustmotion-core/src/engine/renderer/colors.rsexposes:pub fn parse_css_color(input: &str) -> Option<(u8, u8, u8, u8)>
parse_hex_colorstays as a thin infallible wrapper for existing call sites. - The geometry validator never mutates schema types.
cli/commands/geometry.rsreads the box
tree and CSS; any schema change belongs to the schema workstream. - File ownership is disjoint. No file is written by two workstreams. Reads may overlap freely.
css/style.rsandschema/style.rsare different files owned by different workstreams.
Workstreams
Wave 1 — critical + high
- L1 · Geometry validator —
cli/commands/{geometry,validate}.rs— C1, H3, H4, H6, H7 + regression tests - L2 · Value parsing —
engine/renderer/colors.rs,engine/paint_pass.rs,css/units.rs— C2 - L3 · Grid layout —
css/taffy_bridge.rs,css/style.rs— H1 - L4 · Schema surface —
core/schema/**,cli/commands/{schema,validation}.rs— H2, H5 (fonts), deadLayerStyle - L6 · Documentation —
CLAUDE.md,.claude/skills/rustmotion/**— H8, M7
Wave 2 — medium (after review of wave 1)
- L5 · Dead features & components —
components/{box_builder,intrinsic,text}.rs,engine/animator.rs— M1, M2, M3 - L4b · Diagnostics hardening —
validate_attrs.rs,cli/lib.rs,render.rs,scenario.rs— M4, M5, M6
Findings index
| ID | Severity | Summary | Workstream |
|---|---|---|---|
| C1 | Critical | --fix writes style.wrap, a field CssStyle rejects — the component is dropped from the render and validation then reports clean |
L1 |
| C2 | Critical | #fff, #FFF, white, rgb(...) all fall back to SColor::BLACK silently; unparseable lengths fall back to 0px |
L2 |
| H1 | High | grid-template-columns never reaches taffy, yet validate_schema.rs:217 makes it mandatory |
L3 |
| H2 | High | Exported JSON Schema types children as items: true — zero component coverage, no constrained generation possible |
L4 |
| H3 | High | --fix indexes the post-filter child vector against raw JSON, patching the wrong node when a sibling fails to deserialize |
L1 |
| H4 | High | _parent_clips is computed and never read: parent overflow is never detected, clipped subtrees are false positives |
L1 |
| H5 | High | Geometry ignores static transform and scene.camera; custom fonts are never loaded before measuring |
L1 + L4 |
| H6 | High | --strict-anim samples 7 fixed points, discards t=0 via an opacity guard, and forks the renderer's effect resolution |
L1 |
| H7 | High | Deliberate frame-bleeding typography — the reference style's signature — is rejected as a viewport overflow | L1 |
| H8 | High | The authoring guide teaches a dead style model (LayerStyle); its canonical Example 1 produces a dropped component |
L4 + L6 |
Verification (applies to every workstream)
rtk cargo build --release
rtk cargo test --workspace
for f in examples/*.json; do ./target/release/rustmotion validate -f "$f"; done
All 7 example scenarios must still validate after every workstream.
Activity
LeadcodeDev commentedon Aug 1, 2026
Wave 1 integrated — PR #108
All five wave-1 workstreams are implemented, reviewed, integrated and verified.
One commit per workstream on
chantier/audit-fiabilisation.bcbec0726f5cc6de588037eeb4b9cb166a3cargo test --workspace→ 534 passed / 0 failed. Independent acceptance harness:3/11 green on the pre-fix binary, 11/11 after.
Decision log
Non-obvious choices made during this wave, with the rejected alternative.
Unresolvable colour renders opaque magenta, not black. Rejected: keeping a black
fallback. Black is a legitimate authored colour and disappears into the dark frames
this engine targets, which is precisely the silent failure C2 describes. Magenta
never blends in. A validation-time error is the better answer and is deferred to
wave 2 — this wave only makes the failure impossible to miss.
Alpha rounds in both notations. Rejected: preserving truncation for bare floats
to keep a pre-existing test passing byte-for-byte. That test asserted an artefact of
the old formula, not a behaviour anyone depends on, and the asymmetry made
0.5and50%disagree on the same value.Bare-number grid tracks now mean
fr, notpx. Rejected: preserving the oldmeaning.
[1,1,1]previously produced three 1px tracks — never a usable intent —because
GridTrack's untagged variant order madeFrandKeywordunreachable.Single
frvalues use taffy'sflex()(minmax(0, Nfr)), notfr(). Rejected:spec-exact
minmax(auto, Nfr), whose content-based minimum yields unequal columnswith uneven content. Predictable track sizing matters more in a video renderer.
Clipped content is exempt from every overflow check, including the new one.
Deliberate bleed under a clipping parent is a composition technique — it is how the
reference style gets giant type running off frame — and rejecting it made that
composition unauthorable while
validatewas mandatory.The
content_overflows_boxcheck does not fire for an unbreakable long word in anauto-width box. That is ordinary CSS
min-width: autobehaviour on a flex item, andan element escaping a non-clipping intermediate container while staying inside the
viewport is not a defect. It does fire when the author set an explicit width.
No follow-up issue filed for the font registration bug.
register_font_filediscards the
TypefacefromFontMgr::new_from_data, so declared families neverresolve by name. Rediscovered independently here, but already fixed by
208e8d1ondocs/1600-brutalist-style. Filing an issue would duplicate work in flight. See themerge-order note in PR Post-audit reliability hardening — wave 1 (critical + high) #108.
Carried into wave 2
schema::GridTrackremoval — needstraits/container.rs, outside wave 1's partition.schema::style::SpacingandGridPlacement, dead sinceLayerStylewas removed.white-spacehas no render effect), M2 (rich_textinvisible in flow), M3 (
glowis a no-op), M4 (no legibility floor), M5 (strict-attrshardening — decided at kickoff, error by default plus availability on
render),M6 (
SceneEntryuntagged diagnostics).fix(engine): stop accepting input that has no observable effect
LeadcodeDev commentedon Aug 1, 2026
Chantier complete — all 19 audit findings addressed
38596ca2ec0659Verified on merged
main: 15 test suites green, clippy clean, all 7 examplescenarios validate, and the independent acceptance harness reports 13/13 —
including wave-1 non-regression checks.
What actually changed
The audit's conclusion was that the render engine was markedly stronger than the
chain of trust around it. That chain now holds in both directions.
validatecould previously lie by saying yes — a scenario with invisibletext (
#fffresolved to black), a grid with no columns, content spilling out ofits card — and by saying no, rejecting the deliberately frame-bleeding
typography that is the signature of the reference style this project targets.
Both directions are now covered, and covered by a harness that measures rendered
pixels rather than trusting unit tests.
The worst single defect is gone:
--fixused to write a propertyCssStylerejects, which dropped the component from the render — and then reported the
result as clean. It turned text that overflowed into text that was absent, with
a green light on top.
What was deliberately left
Four follow-ups, each surfaced by a workstream that reported it rather than
reaching outside its file partition:
glow_radius/glow_intensitystill paints a black halovalidatebut blockrender*_colorfields living outsidestyleOn the third audit objective
The marketing-video goal is no longer blocked by the engine. 3D, camera,
multi-plane depth, both blur kinds and the easing solver were already there;
this chantier made
rich_textusable,glowreal, and lifted the validatorrule that made frame-bleeding typography unauthorable.
What remains for that objective is a second template in the dark-premium
register — radial blooms, product mockups in perspective, kinetic typography,
World view for continuity across shots. That is design work, not engine work.
The existing
1600-style.jsonis a coherent brutalist piece, but it is not thelanguage of the reference videos.