The bug the verification found: a card that showed nothing it had not fetched itself
`NearbyExperiencesCard` held its list in `useState<NearbyPlace[] | null>(null)` and learned it ONLY
from its own action's return value. Every page load rendered _"Find nearby places"_ and an empty card
— with eight places saved in the profile and rendering on the live Experiences page. Its own doc
comment, _"the host reviews the list here"_, stopped being true the moment the host reloaded.
🚨 **Not merely cosmetic.** The only route back to the list was to press the button, which spends a
real Overpass round-trip — a free, rate-limited, frequently-overloaded community service — to
redisplay rows the database already held, **and overwrites the saved selection while doing it**.
🔑 **Found by disagreement, not by reading the component.** While verifying the cap, the card said
_"Find nearby places"_ while the database said `nearby=9`. The empty card on its own looked like a
perfectly ordinary empty state; only the two sources contradicting each other made it a bug. It also
nearly cost the cap its verification — the blank card read as "my change broke the fetch."
- `loadOverviewData` already read `content_profile` for the Rewrite card, so the profile is parsed
ONCE and both cards read it — no extra query for the fix.
- The `saved` prop is **required on purpose**. Optional would type-check at a mount that forgot it,
which is exactly how `turnstileSitekey` was threaded through five layers and passed at none
(savepoint §2.6).
- Verified as a render, both directions, on the real dashboard: 8 saved → _"Refresh"_ plus all eight
chips; cleared → the CTA returns with no phantom list; restored → the list is back. The eight
objects were snapshotted to a file before the control cleared them — real host data, and a negative
control is not worth losing it to.
- Corrected in passing: a comment naming `refreshNearbyPlacesAction`, which does not exist.
⚠️ Correcting the SEO-title advice from the entry below
That entry says to compare the **SEO title** across wizard runs as the canary for "the AI actually
ran". **That is wrong, and the fifth run disproved it.** Page SEO is never written by the wizard —
`regeneratePageSeoAction` says so outright (_"THIS IS NOT HOW A PAGE GETS SEO"_): every page is
written once, free, by `/api/seo-ai-worker`, driven by a `*/10 * * * *` pg_cron job that lives in the
live cloud database and posts to production, so it sweeps rows a LOCAL wizard creates.
Measured: site built `12:55:08Z`, `seo_ai = {}` at `12:59`, written at `13:00:15Z` — the sweep, to
the second. So run four's AI titles and run five's stock titles were the same behaviour at different
points in a ten-minute cycle.
🚨 **And it is worse than merely timing-dependent.** Run five's home title came back
_character-for-character identical_ to run four's, because the generation is hash-bounded off the
same business facts. Following that advice would have compared two identical strings and concluded
the AI was serving from a cache — **a false negative on the exact question the canary exists to
answer.** The canary is the BODY copy, and several slots at once rather than the headline alone.
Runs five and six, and the purge behind them
**Run five** (`d50e6171…`) is the one that caught the SEO-title mistake above; it is otherwise
unremarkable — 8 rows, 15 pages, both new pages in draft and published, 9 places (it predates the
cap).
**Run six** (`9200aa27-028e-470a-995d-5e7da5ecb3d4`) is the first run that exercises **both** of
today's changes from a clean start, and that is why it was worth doing:
- 🔑 **The cap on a genuinely FIRST fetch.** The earlier proof was a _refresh_ over an existing nine,
which only shows the cap applied to a re-fetch. Run six started at `nearby: 0`, the card offered
_"Find nearby places"_, and one press produced **8** — stored 8, rendered 8, Albasini ruins absent,
8 Directions links, no sample note. The category filters are still all four groups, so the
round-robin spans the set at the lower cap rather than collapsing toward restaurants.
- 🔑 **The card fix on a real fresh load.** Navigating away and back shows _"Refresh"_ and _"8 places
saved"_ with the chips. Before today the identical navigation showed the empty CTA with eight
places sitting in the database.
- Sixth distinct headline: _"Where the Fence Used to Be"_ — differing in structure, not only wording,
from the five before it. (Body copy, not the SEO title — see the retraction above.)
**The purge.** `d50e6171…` (15 pages) and `b5f952cd…` (15 pages), both hard-deleted, **not
recoverable** — wizard-built verification artefacts carrying nothing hand-written. Dry run first, per
the rule added after the previous purge: both listed with page counts and deletion timestamps,
`must survive: 9200aa27` printed, and the apply pass named the same two ids. Each delete re-read
`deleted_at` immediately beforehand rather than trusting the listing it had just printed. Verified:
**zero** orphaned pages, `9200aa27…` the only site left, and the negative control — `/experiences`
still 8 places and 8 Directions links, `/gallery` still 11 images, the card still _"8 places saved"_.
⚠️ All three sites were `mana-bush-lodge`, so **the subdomain identifies nothing** — the id is the
only thing telling them apart, which is why every line of a purge is scoped to one id.
Run seven — the filters, not just the count
`1dceb388-5ea2-4efb-8991-294542aada8e`. Same result as run six on every axis already listed, so only
the new check is worth recording:
🔑 **A cap can starve a category.** The count being 8 says nothing about WHICH eight. `shop` has
exactly one member in this area, so dropping 9 → 8 could have cut it and left a "Shop" filter that
leads to an empty list — a control implying a capability the page no longer has. Measured on the
live page against the database, group by group:
| | stored | rendered |
| ------ | ------ | -------- |
| All | 8 | 8 |
| Shop | 1 | 1 |
| Nature | 2 | 2 |
Full spread `eat 3 · see 2 · nature 2 · shop 1` — the round-robin still reaches every group at the
lower cap. **Assert the DISTRIBUTION a cap produces, not only its size.**
**The purge.** `9200aa27…` (15 pages), dry run first, `must survive: 1dceb388` printed, zero orphans,
survivor still rendering 8 places and 11 gallery images.
📌 **Runs three through seven have now returned the same result five times.** The wizard path is
settled; each run since has earned its keep only by checking something the previous one did not (run
five: the SEO retraction · run six: the cap on a FIRST fetch · run seven: the distribution). An
eighth identical walkthrough would confirm nothing new — **give it a new question or spend the time
elsewhere.**
---