Skip to content

[6.x] Fix stache:refresh flattening structured collection trees - #15003

Merged
jasonvarga merged 1 commit into
statamic:6.xfrom
mynetx:fix/stache-refresh-flattens-tree
Jul 14, 2026
Merged

[6.x] Fix stache:refresh flattening structured collection trees#15003
jasonvarga merged 1 commit into
statamic:6.xfrom
mynetx:fix/stache-refresh-flattens-tree

Conversation

@mynetx

@mynetx mynetx commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Running php please stache:refresh on a structured collection (structure.root: true) can flatten the tree in the warmed Stache cache: entries end up at the root level and whichever one sorts first becomes the site root, even though the on-disk tree file is untouched. Running stache:clear then stache:warm as separate commands is always correct.

Stache::clear() never invalidated the Blink caches that hold a collection's structured tree. Since stache:refresh runs clear() and warm() in one process, warm() could see stale, already-computed tree data from before the clear. Two Blink keys were involved:

  • the tree object cached in CollectionStructure::in()
  • the validateTree() result memoized in Tree::tree(), which is content-addressed only on the raw tree array, but validateTree() also reads queryEntries(), so the same cache key can go stale as entries are created without the key itself changing

This PR makes clear() forget both, mirroring the existing forget already done on tree save/delete (Tree::save()/Tree::delete()).

I couldn't reproduce the exact flattening with an explicit, already-ordered tree in an isolated repro, but I found the existing ColdStacheUriTest had a manual Blink::flush() worked into its cold-stache simulation specifically to paper over this same gap. I removed that manual flush and confirmed the production fix makes the test pass on its own, which is direct proof Stache::clear() was leaving this stale.

Fixes #14996

🤖 Generated with Claude Code

Stache::clear() never invalidated the Blink caches that hold a
collection's structured tree, so the single-process clear()+warm()
inside stache:refresh could serve a stale, unvalidated tree state
computed moments earlier. With structure.root: true, this flattens
the whole tree and lets the first entry become the site root.

Two Blink key patterns were involved: the tree object cached in
CollectionStructure::in(), and the validateTree() memo in
Tree::tree(), which is content-addressed on the raw tree array but
also depends on the mutable result of queryEntries() - so the same
cache key can silently go stale as entries are created.

Forget both on clear(), mirroring the existing forget already done
on tree save/delete. Also drops the now-redundant manual Blink flush
from ColdStacheUriTest, since the production code now does it.

Fixes statamic#14996

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@jasonvarga
jasonvarga merged commit 49a3630 into statamic:6.x Jul 14, 2026
20 checks passed
@mynetx
mynetx deleted the fix/stache-refresh-flattens-tree branch July 14, 2026 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stache:refresh flattens a collection tree

2 participants