Repository navigation
chantier: September 25 audit remediation #315
Description
An exhaustive audit of the five crates on main @ 97b122d produced 217 findings: 62 High, 105 Medium, 45 Low, 3 Info, no Critical. Report: https://claude.ai/artifact/V7ttBMi4SbqxDQmKt9A8XH
Four of them were not found by reading the code. They came out of porting a real promotional animation to a scenario and watching it fail, which is why they sit first in the order below: they block the most ordinary thing a promo asks for, several elements entering and leaving in turn inside one continuous scene.
Work happens on chantier/audit-2026-09-25. One branch per fix, pulled from the chantier, squash-merged into it once CI is green. The chantier lands on main as a single pull request, and only with an explicit go.
Frozen before any dispatch
ConversionContext::for_viewport(w, h) is the single constructor the validator and the renderer share. Do not reintroduce ConversionContext::default() on a path that knows the real viewport.
The Painter trait signature does not change. Defaulted methods may be added; paint_content may not.
Seventeen fields deserialize, pass validation, appear in the exported schema and do nothing. Each is either implemented or removed so the unknown-attribute error catches it. Leaving one inert is the only option that contradicts the strictness contract the schema is sold on.
Order
- A timeline step acts before its
atwhen several steps exist — b9cf23a -
start_atopens the visibility window without rebasing the animation clock — 83f7ca6 - A card lays its children out in a row while the documentation says column — 8afc4c1
- Closing the detection hole
8afc4c1opens in the geometry validator — 3ba6f76 - A filled SVG cannot be revealed by progressive fill — 5bda143
- The geometric validator, which the entry document declares mandatory, is bypassed five ways
- Encoding does not produce what the flags asked for
- Two arbitrary file reads reachable from a scenario
- Seventeen inert fields
- The render loop caps at 2x on twelve cores
- Documentation teaches a schema the binary rejects
- The suite is silent where it matters most
- The studio writes files its own validator rejects
Write partition
Each workstream owns a disjoint set of files. Cargo.toml, Cargo.lock, the module-registration lib.rs files, README.md, CLAUDE.md, .github/ and crates/rustmotion/skills/ are not written by a workstream: a line needed there is reported and applied in one pass at integration.
Resolved
Closed by 3ba6f76. Six of the seven red tests were real detection losses and are fixed; the seventh was a genuine reclassification, and its fixture moved back inside the frame to restore the invariant its own docstring claims rather than have the assertion relaxed. The audit's reproduction errors again with the message it gave before 8afc4c1. Full suite on a quiet tree: 1437 passed, 0 failed.
What the hold was
8afc4c1 is correct and stays, but it must not ship alone. Defaulting a container to column removes the cross-axis clamp a fixed-height card used to impose on an oversized child, so the child grows to its natural size and the layout box then matches its own grown content. check_content_overflows_box stops firing. Where the grown box crosses the frame edge check_viewport still catches it, reclassified; where it stays inside, or where the node carries bleed: true, the overflow is no longer reported at all.
A 300x80 card holding a 44px paragraph reports text (wrapped content exceeds its own box) before the change and Valid scenario after. The pattern covers 45 of the 98 card instances in examples/. Seven tests in geometry.rs fail, some of them legitimate reclassifications and some genuine losses; they are being sorted one by one rather than relaxed.
Activity
docs(skills): teach the schema the binary actually accepts
fix(encode): keep the incremental encoder's slot indices aligned
fix(render): refuse flags the bundled encoder cannot honour
fix(encode): make the ffmpeg path produce what the flags asked for
fix(security): close the file reads a scenario could reach
feat(cli): validate in still the way render already does
fix(studio): stop writing scenarios the engine refuses
fix(components): paint inside the box layout assigned, not a self-com…
fix(geometry): measure against the real viewport and the real camera
feat(css): make mix-blend-mode, clip-path and visibility do something
fix(schema): describe the shapes the parser actually accepts
fix(cli,studio): drop the references text-decoration left behind
fix(badge): stop overriding the alignment its parent asked for
11 remaining items
fix(engine): make the scroll wrap, the camera stack and the world clo…
fix(core,studio): let the paint pass and the studio use what the engi…
style(expand): reflow the type-mismatch error construction
fix(ci): gate publishing on main, and take the fixes that were alread…
fix(html): refuse what the dialect cannot express, and reach what it …
docs(skills): update the dialect reference to what it now does
fix(chart): stop the charts from drawing a plausible wrong answer
docs(skills): document the radial bar's explicit maximum
fix(security): guard every ffmpeg input, not one of four
fix(paint): stop the paint pass from clipping, dropping and double-pa…
fix(studio,cli): make the editor and the validator report what they see
fix(components): spend the typewriter budget in characters, and stop …
fix(cli): keep key order through --fix, and refuse transparency befor…
LeadcodeDev commentedon Sep 29, 2026
Closing the tracker.
Note before anyone acts on this: PR #325 is still open, carrying 43 commits on
chantier/audit-2026-09-25that are not onmain. Closing this issue does notclose that PR and does not discard that branch — it is left exactly as it is.
Decide on #325 separately.
Several findings from this audit were fixed directly on
mainin the meantimerather than through the chantier: #155, #159, #162, #318, #320, #321, #322, #323,
#324 all carried
Refs #315and are closed.