Flush waits for a save already on its way; a field removed by a redraw no longer commits on blur.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stats read 6000 scenes x 2400 triggers in under 1 s (was 2 min). Length fields show the grid value they use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A variable referencing the same other variable more than once is not a
cycle, so memoization alone still leaves the OUTPUT exponential in size
(each level's re.sub concatenates the memoized child result multiple
times). Adds a shared output-size budget, checked before using either
a cached or freshly-computed result.
Also ignore the runtime shortcuts.json data file, and fix the fan-out
test's assertion, which was checking against a vacuous condition.
A trigger->replacement library (core/shortcuts.py, a close port of v4's
apply_prompt_shortcuts/resolve_variables), a Settings section to manage it,
autocomplete on the real prompt textarea (composer.autocomplete.default, so
it outranks the Constructor modal it lives inside), and a stateless
/api/prompt/expand that combines anchor + shortcuts + $variables + postfix
at the moment a run is queued -- scene.text itself stays exactly what was
typed. Project gained anchor/postfix/variables editing UI on its own tab.
Along the way: a real layout bug in the Properties column (every composer
stack can flex-shrink below its own content, and once the Project tab grew
past a couple of rows the column started squeezing its own children's
content into each other and, at the outer level, into the sibling Generation
section below) -- fixed with flex-shrink:0 at each level that needs it,
caught by a Playwright regression test.