Files
intotheeast-com/docs/solutions/integration-issues/grav-deleteall-doesnt-invalidate-page-tree-index.md
T
m038andClaude Opus 4.8 e10496afe7 docs(solutions): BUG-001 part 2 — deleteAll doesn't rebuild page-tree index
Document why deleteAll() alone left a freshly-posted entry 404-ing on its
edit-prefill API lookup (regular-pages index keyed on config->checksum, which
survives a create under cache.check.method:folder) and why the fix adds
Cache::invalidateCache(). Note the H1/M8 travelling:true coverage gap as a
tracked residual. Cross-link from bugs-and-fixes.md.

Code review F8 (learnings) + F5 (residual-gap tracking).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mpdu3Dt1iVoozHwAMyjrbn
2026-07-07 08:32:20 +02:00

102 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "cache.deleteAll() doesn't rebuild the page-tree index — a freshly-posted entry 404s when opened for editing"
date: 2026-07-07
category: integration-issues
module: cache-on-save
problem_type: integration_issue
component: plugin
severity: high
symptoms:
- "A just-posted journal entry is written to disk but the API 404s on it (GET /api/v1/pages{route})"
- "Opening the entry you just created for editing shows 'This entry no longer exists — it may have been deleted'"
- "The entry DOES appear in the trip feed, but the edit prefill fetch can't find it until the next unrelated cache bump"
- "Intermittent — only bites when the page-tree index survives the create"
root_cause: incomplete_setup
resolution_type: code_fix
related_components:
- documentation
- development_workflow
tags:
- grav
- cache
- forms
- page-tree
---
# `cache.deleteAll()` doesn't rebuild the page-tree index
## Context — this is BUG-001 Part 2
[BUG-001](../../working/bugs-and-fixes.md) ("new entry not visible after form
submission") was fixed by wiring `$this->grav['cache']->deleteAll()` into the
`cache-on-save` plugin's `onFormProcessed` hook. That made new entries appear in
the trip feed immediately. It was **not the whole story**: `deleteAll()` drops
the Doctrine store (rendered-page cache, feed HTML, etc.) but does **not** force
Grav to rebuild its **regular-pages index**.
The gap only surfaced once the shared `/post` form gained an **edit mode**
(`?edit=<route>`), whose prefill does `GET /api/v1/pages{route}`. On a fresh
create that request would 404 — so the owner opening the entry they had *just*
posted saw "This entry no longer exists."
## Root cause
Grav's regular-pages index is keyed on:
```
md5(dirs + folderHash + config->checksum() + lang) // Pages::buildRegularPages
```
With `cache.check.method: folder` (our setting), the `folderHash` component does
not necessarily change when a new child folder is added inside an existing
tree — so the **index key stays the same** and the stale index (missing the new
entry) is reused. `deleteAll()` clears cache *stores* but does not change any of
the inputs to that key, so the tree is not rebuilt. The new page is on disk and
in the feed (which re-reads children), but the **API lookup by route** resolves
through the cached index and 404s.
## Fix
Add a second invalidation step alongside `deleteAll()`:
```php
use Grav\Common\Cache;
// ...
$this->grav['cache']->deleteAll();
Cache::invalidateCache(); // touch(system.yaml) → bumps config->checksum()
```
`Cache::invalidateCache()` is lightweight and idempotent — it `touch()`es
`system.yaml`, calls `clearstatcache()` and `opcache_reset()` (verified in Grav
core `Cache.php`). Touching `system.yaml` bumps `config->checksum()`, which
changes the index key, so the tree rebuilds on the next request and the new
entry becomes resolvable by route.
### Latch it — the hook fires 4× per submit
`onFormProcessed` fires once per `process:` action, and `post-form.md` has four
(`add_page`, `upload`, `message`, `reset`). Without a guard the
`deleteAll()` + `invalidateCache()` pair runs four times per post (a full store
wipe + `system.yaml` touch each time). Gate it with a once-per-request latch
(`$cacheInvalidated`), the same pattern already used for photo reconciliation
(`$photosReconciled`). See `user/plugins/cache-on-save/cache-on-save.php`.
## How to verify
1. Post a new entry via `/post`.
2. From the trip feed, click the new card's **Edit** link.
3. The form prefills with the entry's title/body — no "no longer exists" banner.
Regression test: `tests/ui/post/edit-mode.spec.js` **ES1** (create → open the
feed card's Edit link → change title + body → Save → assert on disk).
## Residual coverage gap (tracked, not fixed here)
`tests/ui/home/home.spec.js` **H1** and `tests/ui/maps/maps.spec.js` **M8**
require `site.travelling: true` to exercise the active-trip home feed + home GPX
map. The committed local `site.yaml` runs `travelling: false` (owner's testing
config, intentionally not committed as `true`), so both specs **skip loudly**
with a reason rather than fail misleadingly. They validate whenever the site is
in travelling mode. This is a known gap in this environment, not a silent hole —
provisioning `travelling: true` in a dedicated test config would close it.