Skip to content

fix(render): clear asset caches between watch renders - #242

Merged
LeadcodeDev merged 1 commit into
chantier/audit-2026-09from
fix/watch-cache-invalidation
Sep 22, 2026
Merged

LeadcodeDev merged 1 commit into
chantier/audit-2026-09from
fix/watch-cache-invalidation

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Severity Low, category coherence. Location: crates/rustmotion/src/cli/commands/render.rs:452

Impact

Triggering scenario: rustmotion render deck.json -o out.mp4 --watch left open for an afternoon, with an image component pointing at logo.png. The author re-exports logo.png. ASSET_CACHE is keyed on the path alone (image.rs:41-54) with no mtime or size component, and in the incremental branch clear_asset_cache() only runs when the video config hash changes (resolution/fps) — editing scene content never clears it. Every subsequent re-render silently re-uses the stale decoded bitmap; the author sees the old logo indefinitely with nothing on stderr. The adjacent audio path solved exactly this and documents why (encode/audio_analysis.rs:29-39: fingerprint on len+mtime because 'someone re-exports a mix while the studio is open') — the image/GIF/video caches never got the same treatment. Memory side: clear_asset_cache touches only ASSET_CACHE; GIF_CACHE, VIDEO_FRAME_CACHE and AUDIO_ANALYSIS_CACHE have no clear function at all, so a long --watch session that touches several asset variants accumulates every decode for the process lifetime.

Fix

Key ASSET_CACHE/GIF_CACHE/VIDEO_FRAME_CACHE on (path, len, mtime) the way source_fingerprint already does for audio, or add a clear_all_caches() invoked at the top of every watch iteration. The first is strictly better: it keeps incremental reuse for untouched assets.

Evidence the audit read

let use_prev = if prev_config_hash == Some(config_hash) {
    prev_segments.as_deref()
} else {
    engine::clear_asset_cache();
    None
};
// assets.rs:24
pub fn clear_asset_cache() {
    if let Some(cache) = ASSET_CACHE.get() { cache.clear(); }
}

Stacked on fix/gif-decode-bomb, which carries the previous finding of this workstream. GitHub shows only this finding's diff; merge in order.

Part of the September 2026 audit remediation chantier. Refs #220 (RM-25).

@LeadcodeDev LeadcodeDev added the bug Something isn't working label Sep 21, 2026
@LeadcodeDev LeadcodeDev self-assigned this Sep 21, 2026
@LeadcodeDev
LeadcodeDev force-pushed the fix/watch-cache-invalidation branch from 408d3e4 to a7a75fa Compare September 22, 2026 06:10
@LeadcodeDev
LeadcodeDev force-pushed the fix/watch-cache-invalidation branch from a7a75fa to 581d1ad Compare September 22, 2026 08:34
@LeadcodeDev
LeadcodeDev force-pushed the fix/watch-cache-invalidation branch from 581d1ad to b02296e Compare September 22, 2026 08:44
@LeadcodeDev
LeadcodeDev changed the base branch from fix/gif-decode-bomb to chantier/audit-2026-09 September 22, 2026 08:53
Triggering scenario: `rustmotion render deck.json -o out.mp4 --watch` left open for an afternoon, with an `image` component pointing at `logo.png`. The author re-exports `logo.png`. `ASSET_CACHE` is keyed on the path alone (image.rs:41-54) with no mtime or size component, and in the incremental branch `clear_asset_cache()` only runs when the video config hash changes (resolution/fps) — editing scene content never clears it. Every subsequent re-render silently re-uses the stale decoded bitmap; the author sees the old logo indefinitely with nothing on stderr. The adjacent audio path solved exactly this and documents why (`encode/audio_analysis.rs:29-39`: fingerprint on len+mtime because 'someone re-exports a mix while the studio is open') — the image/GIF/video caches never got the same treatment. Memory side: `clear_asset_cache` touches only `ASSET_CACHE`; `GIF_CACHE`, `VIDEO_FRAME_CACHE` and `AUDIO_ANALYSIS_CACHE` have no clear function at all, so a long `--watch` session that touches several asset variants accumulates every decode for the process lifetime.

Refs #220
@LeadcodeDev
LeadcodeDev force-pushed the fix/watch-cache-invalidation branch from b02296e to 523f995 Compare September 22, 2026 09:00
@LeadcodeDev
LeadcodeDev merged commit c029b9f into chantier/audit-2026-09 Sep 22, 2026
LeadcodeDev added a commit that referenced this pull request Sep 22, 2026
Triggering scenario: `rustmotion render deck.json -o out.mp4 --watch` left open for an afternoon, with an `image` component pointing at `logo.png`. The author re-exports `logo.png`. `ASSET_CACHE` is keyed on the path alone (image.rs:41-54) with no mtime or size component, and in the incremental branch `clear_asset_cache()` only runs when the video config hash changes (resolution/fps) — editing scene content never clears it. Every subsequent re-render silently re-uses the stale decoded bitmap; the author sees the old logo indefinitely with nothing on stderr. The adjacent audio path solved exactly this and documents why (`encode/audio_analysis.rs:29-39`: fingerprint on len+mtime because 'someone re-exports a mix while the studio is open') — the image/GIF/video caches never got the same treatment. Memory side: `clear_asset_cache` touches only `ASSET_CACHE`; `GIF_CACHE`, `VIDEO_FRAME_CACHE` and `AUDIO_ANALYSIS_CACHE` have no clear function at all, so a long `--watch` session that touches several asset variants accumulates every decode for the process lifetime.

Refs #220
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant