mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-28 12:16:53 -06:00
Two unbounded things in the GREP-style path. `BACKTRACK_LIMIT` bounds one search, not a scan: `find_all` was called with `usize::MAX` and pays the limit again for every match, so a pattern tuned just under it cost `200_000 x matches` per paragraph on every relayout. A scan now stops at `MAX_MATCHES_PER_PARAGRAPH` (4096) -- more styled runs than a paragraph can usefully carry -- and says which pattern reached it. The `PATTERNS` thread-local never evicted, so it grew across every pattern a session ever composed. It now holds at most 64, least recently used dropped first: a tick counter marks each use, so the entry evicted is the one longest unused rather than the one inserted earliest. The test checks that the pattern just used is still there after the cache overflows, which insertion-order eviction would not give. Left for a separate change: DC-17 also asks for a per-compose step budget, so the cost cannot add up across paragraphs. That means threading a budget from `compose_story` through `shape` into `overlays`, a compose-internal signature change that wants its own review rather than riding along here.