DVPApplied Creative AI Engineering

Search this course

Search lesson and reference material.

↑ ↓ to choose · Enter to open · Esc to close

Case study

Adding a model to a shipped tool without betting the tool on it

Optional learned signals for CineQC, off by default, where every failure path leaves the existing heuristics exactly as they were.

Default: offAdditive onlyFallback: heuristics and human review

Problem

CineQC is a working tool people already rely on. Adding a model to it is easy; adding one that cannot make it worse is the actual engineering problem. A learned signal that overwrites a measurement, or that returns a plausible number when it has in fact failed, damages something that currently works.

Baseline

The baseline is CineQC as it stands: five heuristic scores computed in the browser, plus a human rubric. That behaviour is the floor. The integration is only acceptable if the floor is unchanged when the model is off, unavailable, slow, or unsure.

Data

The browser sends the luma timeline — one value per frame, capped at 32 frames — because that is all the CineQC pipeline retains. It is enough for a temporal signal, and it is why the service keeps semantic confidence low enough to route to human review. Nothing about the payload is logged: frames are customer footage, they may be analysed and never recorded, and a test asserts no pixel value or clip id reaches the log even at debug level.

System

A FastAPI POST /v1/analyze with its bounds in the schema rather than the handler — 2 to 32 frames, at most 256×256, pixels in 0 to 1, uniform geometry, no unknown fields. A bound checked in one code path is a bound the next code path forgets.

Evaluation

The property under test is not accuracy, it is containment. Every failure path — feature off, too few frames, no fetch, HTTP error, unknown schema version, timeout — funnels into one shape: { status: 'unavailable', fallback: 'heuristics-human-review', warning }. Learned results attach to state.learned, deliberately not inside state.analysis.scores, and a test asserts the heuristic scores object is unchanged before and after attachment on both the success and the failure path.

An unrecognised schema_version is treated as a failure rather than parsed optimistically: fields may have moved, and a score read from the wrong place is worse than no score at all.

The report carries signalOrigins mapping automated → heuristic, learned → learned, rubric → human. A measurement, a model, and a person are different kinds of claim, and a report that blends them cannot say which kind any given number is.

The failures worth showing here are the ones engineered out rather than observed:

Limitations

Next steps

Repository and reproduction

Service and adapter: cineqc-hybrid-api.

uv run --project creative-ai-engineering/capstones/cineqc-hybrid-api pytest creative-ai-engineering/capstones/cineqc-hybrid-api -qnode --test tests/cineqc-learned-adapter.test.mjsnode --test --test-concurrency=1 tests/cineqc-*.test.mjs

Defence

The question I expect is why the flag defaults to off when the whole point was to add a signal. Because the tool is already useful, and the cost of a wrong learned score reaching a delivery decision is far higher than the benefit of an extra advisory number. Off by default is what makes the integration reversible, and reversible is what makes it safe to ship at all.