Found by the adversarial pass on the commit that moved it to the Project
tab: it had no persistence and no per-project sync at all. width/height/
length (project.video) get both -- a real dict field on Project, and
syncVideo() re-reading it into the controls on every project switch.
Negative got neither: it lived only in the pipeline-override controls'
own in-memory state, so it silently carried over from whichever project
was open last. Typed for project A, it was sent as project B's negative
prompt the moment someone switched -- with nothing on screen to say so,
and the Project tab's own copy ("Size and length live in the
Constructor") actively implying every field there was project-scoped.
Project.negative is now a real field (core/projects.py, round-tripped
through the existing whole-project PUT with no route changes needed),
and boot.js gained syncNegative(), wired everywhere syncVideo() already
is: onOpen, and after the pipeline changes underneath. Reproduced the
exact leak end-to-end before fixing it, and the new project_video.spec.js
test is that same reproduction, now asserting it doesn't happen.