# Fabular Reference Storefront — Audit Round 2

**Date:** 2026-06-06 · **Target:** `fabular.pages.dev` (Fresh Haven reference storefront) ·
**Genre:** single-target deep audit (re-probe after adjustments) ·
**Method:** [`README.md`](README.md) · live curl probes + live CWV pass (`scrapers/cwv.py`).
**Prior round:** [`2026-06-06-fabular-digital-health-briefing.html`](2026-06-06-fabular-digital-health-briefing.html)
· sector context [`2026-06-05-seo-geo-ai-readiness.md`](2026-06-05-seo-geo-ai-readiness.md).

## TL;DR

Adjustments closed both **accessibility** gaps (skip-link + valid Barrierefreiheitserklärung).
But a "dive-deeper" re-probe found the storefront's findability is **hollow at the root**:
the sitemap is valid XML yet lists all **2,246 URLs on a dead placeholder host**
(`fresh-haven.example.com`, DNS-fail), so the 2,088-product long tail is undiscoverable —
and the perfect KI 100 never saw it. Two legally-mandatory pages (**Impressum**,
**Datenschutzerklärung**) are **404 and only dangling-referenced**. The data-quality "fix"
filled only the ~24 showcase products; the catalog body is still empty. CWV mobile LCP is
**still failing (~3.1 s)**.

Split cleanly into *demo-isms* (placeholder host, fake UID, emoji-not-photos) and
*template gaps a real tenant would inherit* — the sitemap host bug is the sharpest because
it is a **deploy-pipeline failure that would ship to every tenant**.

## Axis-by-axis

| Axis | Round 1 (2026-06-06) | Round 2 (this) | Verdict |
|---|---|---|---|
| **Compliance — BFSG/a11y** | 70 · risk hoch (no Erklärung −20, no skip-link −10) | both gaps closed | ✅ fixed |
| **Compliance — core legal** | (not isolated) | Impressum + Datenschutz **404 + dangling refs** | 🔴 new, more fundamental |
| **Find-ability** | KI 100 | sitemap → 2,246 dead `example.com` locs | 🔴 new (scorer-blind) |
| **Data-quality** | 91 · thin fields | head filled, catalog body **0%** | 🟠 cosmetic patch |
| **eCommerce schema** | (not isolated) | Offer exemplary; **no image, no GTIN** | 🟠 mixed |
| **CWV (mobile)** | 91 · LCP 2763 ms ✗ | 89 · LCP 3118 ms ✗ · CLS 0.0 ✓ | 🔴 still failing |

### 🔴 Find-ability — the sitemap is present-but-poisoned (headline)

`fabular.pages.dev/sitemap.xml` is valid XML (HTTP 200, 414 KB, 2,247 `<loc>`), but:

```
sitemap <loc> host distribution:  2246 × https://fresh-haven.example.com
canonical / og:url / robots Host / robots Sitemap:  all → https://fabular.pages.dev
curl https://fresh-haven.example.com/ → HTTP 000 (DNS does not resolve)
```

The sitemap host contradicts the canonical host, and the sitemap host does not resolve.
Google Search Console rejects cross-host sitemap URLs submitted under `fabular.pages.dev`;
a crawler/LLM following the sitemap hits 2,246 dead links. Internal nav exposes only
**~24 products per category page**, so the **2,088-product long tail's only complete
discovery path is broken**. The "perfect" KI score is partly hollow.

**Scorer blind-spot (meta-finding):** this slipped past because `scrapers/ai_readiness.py:179`
does `has_sitemap = _head_ok(base + "/sitemap.xml")` — a HEAD-only existence check that never
parses `<loc>` or compares loc-host to canonical. Same false-negative class as the prior
round's own "per-signal fetches have no retry" caveat. Hardening tracked in
[`tasks/0003-ai-readiness-sitemap-host-validation.md`](../../tasks/0003-ai-readiness-sitemap-host-validation.md).

### 🔴 Compliance — BFSG closed, but core legal pages absent

**Fixed:**
- Skip-link present: `Zum Hauptinhalt springen` → `<main id="main-content" tabindex="-1">`.
- `/barrierefreiheit` exists and is **valid**: Konformitätsstatus, "Nicht barrierefreie
  Inhalte", Feedback `mailto:barrierefreiheit@fresh-haven.at`, EN 301 549, AT-Schlichtungsstelle
  (`info@sozialministeriumservice.at`). Both Round-1 BFSG deductions closed.
- Widerruf folded into the AGB (also mirrored as `MerchantReturnPolicy`, 14 days, in product schema).

**Open:**
- **No Impressum** — `/impressum`, `/offenlegung`, `/rechtliches/impressum`, `/imprint`, … all 404.
  Mandatory Offenlegung (ECG §5 AT / DDG §5 DE). AGB carries only name + "Wien 1010" — no
  Firmenbuch / UID / ATU / Geschäftsführer.
- **No Datenschutzerklärung** — `/datenschutz`, `/privacy`, `/rechtliches/datenschutz`, … all 404.
  Mandatory (DSGVO Art. 13). No cookie/consent layer.
- **Dangling references:** the AGB *names* "Impressum" (1×) and "Datenschutzerklärung" (2×); the
  BFSG page *names* "Impressum / Datenschutz / Art. 13" — but **neither page exists and neither is
  linked**. The footer links only AGB + Barrierefreiheit. The template knows it needs these pages
  and points at them; they were never shipped.

### 🟠 Data-quality — the fix was the shop window, not the catalog

```
/api/products  (total: 2088, paginated, limit 24)
  offset    0 (showcase):  shortDescription 100%  ·  nutrition 75%
  offset  500:             shortDescription   0%  ·  nutrition  0%
  offset 1500:             shortDescription   0%  ·  nutrition  0%
```

Descriptions/nutrition were filled only on the ~24 head-of-catalog showcase items; the
2,088-product body is still empty on both. Core fields (price, taxPercent, unitOfMeasure,
categoryName, rating, ratingCount) remain 100%. A content patch on the visible storefront,
not a catalog fill — the Round-1 structural finding stands. (`robots.txt` now adds
`Disallow: /api/` — sensible; AI-bot groups keep allow-all and product detail pages carry
the schema, so not a regression.)

### 🟠 eCommerce schema — exemplary Offer, but no images and no GTIN

Product JSON-LD is strong: `Offer` with `priceValidUntil`, `availability:InStock`,
`itemCondition`, full `shippingDetails` (rate + delivery time), `hasMerchantReturnPolicy`
(14 d), plus `aggregateRating`, `brand`, `sku`; page-level `LocalBusiness/GroceryStore`
with paymentAccepted, geo, areaServed (Wien), openingHours. Above sector norm.

Gaps:
- **`image` missing from Product schema** — because there are **no product images at all**
  (detail pages render emoji + colour `tint`, zero `<img>` assets). Google product rich
  results effectively require `image`; with none, no product rich snippets fire.
- **`gtin`/`mpn` absent** — no global identifier; limits Google Merchant matching (minor for a demo).

### 🔴 CWV — mobile LCP still failing

Live PageSpeed pass (`scrapers/cwv.py --store-id _ref-fabular --force`, 2026-06-06 →
`store_cwv @ 2026-06-01`):

| | Mobile | Desktop |
|---|---|---|
| Perf score | 89 ✗ | 99 ✓ |
| LCP | **3118 ms** (> 2500) | 726 ms |
| FCP | 2707 ms | 726 ms |
| TTFB | 5 ms | 6 ms |
| CLS | **0.0** (was 0.06) | 0.009 |

TTFB is instant (5 ms) but **FCP ≈ LCP on mobile** — the entire delay is client-side
render-blocking, not server. CLS improved to 0.0. LCP unfixed and still failing the 2500 ms
threshold (single PSI run; LCP carries lab variance, so read as "still ~2.8–3.1 s, unfixed,"
not a precise regression). Fix is render-path: defer/inline-critical CSS+JS, preload the
hero LCP element + headline font (`font-display:swap`).

## Strategic so-what

The demo still proves the **ceiling** (KI extraction, Offer schema, BFSG now clean) but the
re-probe shows the *deploy* doesn't reach it — and the worst offender (the `example.com`
sitemap) is a pipeline artifact that would ship verbatim to a real tenant. For the fab4minds
pitch: *"your reference storefront's own sitemap points 2,246 URLs at a domain that doesn't
exist — an LLM or Google following it finds nothing, even though every product page is
perfect."* Closing the legal pages + the sitemap host substitution are template-level fixes
that lift every future tenant at once.

## Sources — every figure reproducible

- **a11y / legal:** live curl of `/`, `/barrierefreiheit`, `/rechtliches/agb`, and 25+ legal
  slugs (all 404 except the two linked) · 2026-06-06.
- **Sitemap:** `curl /sitemap.xml` → 2,247 `<loc>`, host-distribution grep; `curl
  https://fresh-haven.example.com/` → HTTP 000.
- **Data-quality:** `curl /api/products?offset={0,500,1500}` → `total:2088`, field-completeness counts.
- **eCommerce schema:** JSON-LD parse of `/produkt/bio-karotten-1kg` (5 blocks: Organization,
  LocalBusiness/GroceryStore, WebSite, BreadcrumbList, Product).
- **CWV:** `scrapers/cwv.py --store-id _ref-fabular --force` → `store_cwv @ 2026-06-01` (PSI mobile+desktop).
- **Scorer blind-spot:** `scrapers/ai_readiness.py:179`.
- **Follow-up:** `tasks/0003-ai-readiness-sitemap-host-validation.md`.
