Skip to content
C.W.K.
Stream
Lesson 03 of 04 · published

The Cache That Served a Three-Hour-Old Image

~12 min · caching, invalidation, digests, staleness

Level 0Cold Workshop
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Why a Render Pipeline Needs Caching at All

Stages are expensive — synthesis costs money per character, image generation costs money per image, encodes cost minutes. A person reviewing output changes one thing and re-runs, repeatedly. Without caching, every small correction pays for the entire pipeline, and review becomes expensive enough that people stop doing it. So caching here is not a performance optimization; it is what makes the quality process affordable.

Which means a wrong cache does not merely slow things down. It silently defeats the review it was built to enable.

Naming Instead of Judging

The naive cache stores an artifact at a fixed path and asks whether what is there is still good. That question has no reliable answer — timestamps lie under checkouts, and "did any input change?" is exactly the bookkeeping you were hoping to avoid.

The version that works derives the path from a digest of everything that can affect the output. Edit a scene and the address changes, so the previous artifact still exists but at a location nobody asks for. Staleness becomes structurally impossible rather than carefully avoided: the correct artifact is either present or absent, and there is no third state where something plausible-but-wrong sits at the right address.

Note that the key must include everything that changes the output. A plate depends on its scene definition. A clip depends on its scene and how long it is held on the timeline — the same picture for four seconds and for nine seconds are two different artifacts, and a key that omits duration will happily serve one for the other.

The Failure That Actually Happened

The pilot shipped an image three hours out of date into a finished render. The cause was not the absence of content-keying — it had been implemented. The cause was a hole in the key: something that could change the pixels was not part of the digest, so an edit produced the same address and the cache correctly returned what was stored there.

This is the characteristic failure of the whole approach, and it is worth naming precisely. Once you have content-keyed a cache, you stop thinking about staleness, because you have solved staleness. The remaining bug does not look like a cache bug — it looks like an edit that did not take effect, which sends you looking at your edit rather than at the key.

Every content-keyed cache should be able to state its key. Write down what goes into the digest, next to the function that computes it, as a list. Then adding a new input that affects the output puts you one line away from a question you would otherwise never ask: does this belong in the key? Most holes are inputs added long after the key was designed.

Code

The key, its documented contents, and where a hole appears·python
def scene_digest(sc: dict) -> str:
    """Digest of everything that can change this scene's pixels.

    IN THE KEY (keep this list current - it is the contract):
      - scene kind and all its content fields
      - text, labels, values, node states (struck / active)
      - palette + font selection
      - canvas geometry

    DELIBERATELY NOT IN THE KEY:
      - the scene's position in the timeline (does not change pixels)
      - the episode slug (already in the path)
    """
    payload = json.dumps(sc, sort_keys=True, ensure_ascii=False)
    return hashlib.sha256(payload.encode()).hexdigest()[:12]


def scene_clip_path(ep: Path, sc: dict, dur: float) -> Path:
    # duration MUST be in the clip key even though it is not in the
    # plate key: the same still held 4s and 9s are two artifacts.
    return ep / "clips" / f"{sc['key']}-{scene_digest(sc)}-{dur:.2f}.mp4"


# A hole is any output-affecting input missing from that list.
# Its symptom is never "stale cache" - it is "my edit did nothing",
# which sends you to debug the edit.

External links

Exercise

Find a cache in your systems keyed on something other than a full digest of its inputs — a user id, a filename, a query string. List every input that can change the cached value, then check which of them appear in the key. For each that does not, work out what a user would see when it changes: usually a change that appears not to take effect, which is the symptom nobody attributes to caching.
Hint
Configuration and templates are the usual holes, because they were not thought of as inputs when the key was designed. If changing a template requires clearing the cache manually, the template is an input missing from the key and everyone has been compensating with a ritual.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.