# SiegeStack — Read-Only Verification Audit

**Date:** 2026-08-16
**Commit audited:** `674afe5` (working tree clean, level with `origin/main`)
**Method:** static analysis of repository source + read-only git history. No build was run; no build directory is committed or present. Nothing in the repository was modified.

---

## 1. Verdict table

| # | Claim | Verdict | Evidence | Note |
|---|---|---|---|---|
| 1 | Duplicate P21 pages at two URLs, each self-canonicalizing | **REFUTED** | `git ls-files` — no `epicor-p21-kinetic-reporting.html` exists; `netlify.toml:107-117` | The old slug was deleted and 301s to `/prophet-21`. One file, one canonical. |
| 2 | Three template generations (3 navs, 3 footer states) | **PARTIAL** | `index.html`, `services/erp-integration.html`, `working-with-claude.html` — see §4.2 | Real variance exists but not where claimed: **one** nav across 20 pages, **two** footer link-sets, **one** page with no footer. |
| 2.4 | `/epicor-p21-kinetic-reporting` emits no footer | **REFUTED** | route does not exist | Cannot emit anything. `working-with-claude.html` is the footerless page. |
| 2.5 | Homepage nav omits Prophet 21, About, Contact | **REFUTED** | `index.html:806` nav block | Nav contains `/prophet-21`, `/about`, `/contact`. Byte-identical to 19 other pages. |
| 3 | Homepage footer shows `iamnotcheckingit@gmail.com` | **REFUTED** | `index.html:892` | Footer shows `info@siegestack.com`. The gmail address appears **nowhere** in the tree. Was true before `0e125c7` (2026-08-15). |
| 4 | Homepage links to none of `/services/*`, `/prophet-21`, `/industries/distribution`, `/about`, `/contact` | **REFUTED** | `index.html` outbound tally, §2 | Homepage links to **all six** service pages, `/prophet-21` ×3, `/industries/distribution`, `/about` ×2, `/contact` ×2. |
| 5 | Crawl layer unverified | **CONFIRMED (now verified)** | `robots.txt`, `sitemap.xml`, `llms.txt`, `llms-full.txt` | robots + sitemap + llms-full are correct and complete. **`llms.txt` is stale** — missing 12 routes. See §3.2. |
| 6.1 | Homepage `<title>` vs `og:title` reversed | **REFUTED as stated / PARTIAL in substance** | `index.html:19`, `:30`, `:42` | `<title>` and `og:title` are **identical**. `twitter:title` is the reversed one. |
| 6.2 | Homepage carries a `meta keywords` block | **REFUTED** | no match sitewide | Zero `name="keywords"` in any file. Removed in `0e125c7`. |
| 6.3 | Interior pages carry `max-image-preview:large, max-snippet:-1`, homepage does not | **CONFIRMED** | `index.html:17` vs `prophet-21.html:17` | True. Also true of `etl-showcase.html`, which the claim missed. |
| 6.4 | Homepage emits no JSON-LD | **REFUTED** | `index.html:80-140` | Homepage emits `Organization`, `ProfessionalService`, `WebSite`, `Person`, `FAQPage`/`Question`/`Answer`. |
| 6.5 | `og:image` per-page vs shared | **CONFIRMED (shared)** | 22 pages → `/og-card.jpg`; 2 → `/og-working-with-claude-card.jpg` | Both assets exist in repo. |
| 7.1 | Homepage anchors `#solutions #process #faq #schedule #why-us` exist | **CONFIRMED** | `index.html` id inventory | All five present, plus `#proof`, `#knowledge-library`. |
| 7.2 | Interior pages link to non-existent anchors | **REFUTED** | full fragment sweep | Zero dead fragments sitewide. |
| 7.3 | `/contact` exists as a real route | **CONFIRMED** | `contact.html`, `netlify.toml:266`, `sitemap.xml` | Real page, rewritten, canonical, in sitemap. |
| 8 | Metric wording inconsistent across pages | **REFUTED (values) / PARTIAL (qualifier)** | see §4.4 | All five figures are numerically identical everywhere. The `300+` qualifier is thin on the homepage only. |
| 8b | Homepage percentages contradict `/case-studies` no-percentage policy | **REFUTED — defensible distinction** | `case-studies.html:299` | Reasoning in §4.4. |
| 9 | A fourth process step was removed | **REFUTED** | every commit touching `index.html` | The section has had exactly **3** `<h3>` steps in all 34 commits since it first appeared (`8f8aea9`, 2026-01-21). No fourth step ever existed. |

**Overall:** of 8 substantive claims, **1 confirmed** (6.3), **2 partial** (2, 8), **5 refuted**. The external analysis appears to describe the site as it stood **before commit `0e125c7` (2026-08-15)**, whose message reads: *"Phase 1: one nav, one footer, no dead anchors, no gmail, no keywords meta."* That single commit invalidates claims 2, 3, 6.2 and 7.

---

## 2. Route inventory

24 published HTML routes (excluding `/jesse`, `/nicole`, `/secret`, `/404`, and the Google verification file).

Nav: **A** = canonical 11-link block (byte-identical). **A′** = same block minus its own self-link. **A″** = same links, absolute homepage href. **deck** = slide controls, not site nav.
Footer: **A** = full 18-link footer (indent variant A/B are byte-identical apart from leading whitespace and are counted as one). **C** = 15-link footer lacking the six `/services/*` links. **none** = no `<footer>`.

| Route | Nav | Footer | Canonical | robots | Inbound (self-excl.) | Sitemap |
|---|---|---|---|---|---|---|
| `/` | A | A | self | `index, follow` | 139 | ✅ |
| `/about` | A | A | self | full | 42 | ✅ |
| `/contact` | A | A | self | full | 53 | ✅ |
| `/case-studies` | A | A | self | full | 59 | ✅ |
| `/case-studies/kpi-console` | A | A | self | full | 6 | ✅ |
| `/case-studies/label-service` | A | A | self | full | 6 | ✅ |
| `/case-studies/month-to-date-timeout` | A | A | self | full | 6 | ✅ |
| `/insights` | A | A | self | full | 47 | ✅ |
| `/prophet-21` | **A′** | A | self | full | 49 | ✅ |
| `/operations-modernization` | A | A | self | full | 39 | ✅ |
| `/etl-showcase` | A | A | self | **`index, follow`** | 39 | ✅ |
| `/erp-report-slow-month-to-date` | A | A | self | full | 9 | ✅ |
| `/sql-server-erp-performance` | A | A | self | full | 26 | ✅ |
| `/industries/distribution` | A | **C** | self | full | 20 | ✅ |
| `/services/erp-integration` | A | **C** | self | full | 21 | ✅ |
| `/services/etl-data-pipelines` | A | A | self | full | 20 | ✅ |
| `/services/bi-dashboards` | A | A | self | full | 20 | ✅ |
| `/services/automated-reporting` | A | A | self | full | 19 | ✅ |
| `/services/performance-tuning` | A | A | self | full | 20 | ✅ |
| `/services/security-access-audit` | A | A | self | full | 19 | ✅ |
| `/privacy-policy` | A | A | self | **`noindex, follow`** | 22 | ⚠️ **listed** |
| `/working-with-claude` | **deck** | **none** | self | full + video | 2 | ✅ |
| `/working-with-claude-blog` | **A″** | A | self | full + video | 7 | ✅ |
| `/consultant-expertise` | **none** | **none** | self | `noindex, follow` | **0** | ❌ (correct) |

*"full" = `index, follow, max-image-preview:large, max-snippet:-1`.*

**Zero-inbound routes:** `/consultant-expertise` only — deliberate (noindex intake form, excluded from sitemap and from the `llms-full` allowlist by name at `scripts/build-llms-full.mjs:164`).

**Reachability from `/`:** every route except `/consultant-expertise` is reachable in **≤2 hops**. One hop: 18 routes. Two hops: `/case-studies/*` (via `/case-studies`), `/erp-report-slow-month-to-date` (via `/case-studies`, `/insights`, `/prophet-21`), `/working-with-claude` (via `/working-with-claude-blog`). `/consultant-expertise` is unreachable at any depth.

**Broken internal links:** none. Every internal `href` resolves to a published route or an existing asset. **Zero references to the old P21 slug** in any HTML, txt or xml file — it survives only as the two 301 rules in `netlify.toml`.

---

## 3. Claim-by-claim detail

### 3.1 Claim 1 — the duplicate that does not exist

1. **Source files.** `/prophet-21` ← `prophet-21.html`. `/epicor-p21-kinetic-reporting` ← **nothing**. No file of that name exists anywhere in the working tree or the index.
2. **Diff size.** Not applicable — there is only one file. `UNVERIFIABLE by construction`, not by omission.
3. **Canonicals.** `prophet-21.html:20` → `https://siegestack.com/prophet-21`. The other URL emits no document of its own.
4. **Redirects.** `netlify.toml:107-111` and `:113-117` — both `/epicor-p21-kinetic-reporting` and `.../epicor-p21-kinetic-reporting.html` are `status = 301, force = true` → `/prophet-21`. `netlify.toml:118-127` rewrites `/prophet-21` → `prophet-21.html` (200) and 301s the `.html` form back to the pretty URL. No `_redirects`, `vercel.json`, `.htaccess`, or framework routing file exists. One edge function exists (`netlify/edge-functions/block-bots.ts`) and is **commented out** at `netlify.toml:75-78`, so it does not run.
5. **Link graph.** 50 internal links point at `/prophet-21`; **0** point at the old slug.
6. **History.** `epicor-p21-kinetic-reporting.html` added in `ded5b10` (2026-08-04), deleted in `811aea3` (2026-08-15) — the same commit that added `prophet-21.html`. It was a rename. `19ea665` then fixed a real 404: a stale pretty-URL rewrite still pointed at the deleted file and, being earlier in the TOML, won. That bug is fixed and the commit message records why.

> **Runtime caveat (not source-verifiable):** rule precedence is Netlify's first-match behaviour. The current ordering places the 301s ahead of the `/prophet-21` rules, which is what `19ea665` was written to guarantee.

### 3.2 Claim 5 — crawl layer

1. **`robots.txt` exists** as a committed static file (not generated). Full contents include `Allow: /`, `Crawl-delay: 1`, and **`Sitemap: https://siegestack.com/sitemap.xml`** — declared. Five SEO backlink crawlers are `Disallow: /` with the tradeoff documented in-file.
2. **`sitemap.xml` is a committed static file**, 23 `<loc>` entries. Contains every published indexable route. **No stale entries** — all 23 resolve to a file. **One route missing:** `/consultant-expertise`, correctly, since it is `noindex`. All 23 carry `lastmod 2026-08-15`.
3. **`llms.txt` (hand-maintained) and `llms-full.txt` (generated by `scripts/build-llms-full.mjs`) both exist.** `llms-full.txt` covers all 23 indexable routes and its allowlist is explicit at `build-llms-full.mjs:35-57`. **`llms.txt` lists only 11 URLs and is stale** — it omits `/about`, `/contact`, all six `/services/*`, `/industries/distribution`, and all three `/case-studies/*` children. Twelve routes added in `811aea3` never reached it.
4. **Canonicals:** all 24 pages self-canonicalize, all correct, none pointing at a duplicate or a non-canonical variant.

---

## 4. Findings not in the claim list

Ordered by severity.

### 4.1 A published slide count is wrong in two places — CONFIRMED

Commit `5f3965e` condensed the deck **37 → 14 slides**. `working-with-claude.html` was updated in all its internal locations (title, description, og, twitter, schema ×2, counter, hidden article — verified, all say 14; the live counter is computed from `document.querySelectorAll('.slide')`, and there are exactly 14 `data-slide` elements). Two references were missed:

- **`working-with-claude-blog.html:679`** — *"View this case study as a 37-slide presentation →"*
- **`llms-full.txt:3835`** — same string, **inherited**: `llms-full.txt` is generated *from* the blog page, and was regenerated *after* the condense (`5f3965e` is an ancestor of `811aea3`). It is faithfully reproducing an error in its source. **Regenerating will not fix it**; the blog page must be corrected first.

This is exactly the failure mode `build-llms-full.mjs:6-14` was written to prevent, recurring one layer up.

### 4.2 Two pages carry a different footer, from the same commit that created them — CONFIRMED

`industries/distribution.html` and `services/erp-integration.html` emit footer variant **C**, which **omits all six `/services/*` links** and substitutes `/#solutions`, `/etl-showcase`, `/operations-modernization`, `/erp-report-slow-month-to-date`. The other 20 pages — including the other five service pages — emit variant A.

All three were created in the **same commit** (`811aea3`). This is not accumulated template drift; it is a generator inconsistency introduced in one pass. `services/erp-integration` being the odd one out among six sibling pages is the clearest tell.

*(The A/B hash split reported by tooling is leading whitespace only — 4 vs 8 spaces of indentation. Same links, same text. Not a variant.)*

### 4.3 A placeholder email address is published — CONFIRMED

**`etl-showcase.html:2597`** contains `contact: 'billing@yourapp.com'`. It is inside sample/demo content, but it is a fabricated third-party-looking address on a live commercial page. It is the only address in the tree other than `info@siegestack.com`.

### 4.4 `/privacy-policy` is `noindex` **and** listed in the sitemap — CONFIRMED

`privacy-policy.html:17` declares `noindex, follow`; `sitemap.xml` lists `https://siegestack.com/privacy-policy`. A sitemap is a request to index. The two directives contradict; the `noindex` wins, so the sitemap entry is wasted crawl budget and an inconsistency signal. Either is defensible alone — both together are not.

### 4.5 `etl-showcase` shares the homepage's reduced robots value — CONFIRMED

The claim identified the homepage as the only page lacking `max-image-preview:large, max-snippet:-1`. **`etl-showcase.html:17`** also carries the bare `index, follow`. Two pages, not one.

### 4.6 `twitter:title` diverges from `og:title` on four pages — CONFIRMED

| Page | `og:title` | `twitter:title` |
|---|---|---|
| `index.html:30/42` | Custom Integrations, Dashboards & Apps \| SiegeStack | **SiegeStack \| Custom Integrations & Dashboards** |
| `working-with-claude.html:35/57` | …A 14-Slide Case Study on Shipping Production Work | …A 14-Slide Case Study |
| `working-with-claude-blog.html` | …A Real Workflow That Ships Production Work | …A Real Workflow That Ships |
| `etl-showcase.html` | CRM **&** ERP Integration Experts | CRM **`&amp;`** ERP Integration Experts |

The last is a **double-escaping bug** — `&amp;` will render literally as `&amp;` in a Twitter card. The homepage one is the word-order inversion the external analysis attributed to `<title>`/`og:title`.

### 4.7 `_headers` and `netlify.toml` have silently diverged — CONFIRMED

`_headers` documents itself three times as deliberately mirroring `netlify.toml` (*"Change one, change the other"*). It mirrors the `/secret`, `/jesse`, `/nicole` and service-worker blocks faithfully. But **`netlify.toml` has `/*.js` and `/*.css` immutable-for-a-year rules that `_headers` does not**. Asset caching therefore depends entirely on one of the two files. The stated invariant — that the two agree so it cannot matter which wins — no longer holds for scripts and stylesheets.

*This matters because `/consultant-form.js` is the site's only external script and is served immutable; it is protected by a `?v=` token added at `consultant-expertise.html:226` on 2026-08-16.*

### 4.8 Case-study child pages carry only breadcrumb structured data — CONFIRMED

`case-studies/kpi-console.html`, `label-service.html`, `month-to-date-timeout.html` emit **only** `BreadcrumbList` + `ListItem`. The hub (`case-studies.html`) emits `Article`, `CollectionPage`, `Organization`, `WebSite`, `Thing`. The three actual case studies — the pages with the substance — carry no `Article` or `CreativeWork` type at all.

### 4.9 `/consultant-expertise` has no nav and no footer — CONFIRMED, low severity

It is the only indexable-adjacent page with neither. Consistent with being an unlisted intake form; noted because it means a visitor who lands there has no navigation out.

---

## 5. Corrections to the external assessment

1. **It is describing a pre-`0e125c7` snapshot.** That commit (2026-08-15) is titled *"Phase 1: one nav, one footer, no dead anchors, no gmail, no keywords meta"* and its body states it found **five** nav variants (not three) and the gmail address on **five** pages / fourteen occurrences (not just the footer). Claims 2, 3, 6.2 and 7 were all true at some point and were all fixed in that single commit. The assessment is not fabricated — it is stale.

2. **Claim 1 is wrong in a way that matters.** There is no duplicate page. There was a genuine, severe bug here — `19ea665` records `/epicor-p21-kinetic-reporting` returning **404** on its established URL — but that is the opposite failure from "two URLs serving identical content", and it is fixed. Reporting it as duplication would send someone to add a canonical or a redirect that already exists.

3. **Claim 6.1 is right about a defect and wrong about which tags.** `<title>` and `og:title` on the homepage are character-for-character identical. The inversion is in `twitter:title`. Anyone acting on the claim as written would inspect two matching tags and conclude the report was noise — and miss the real one.

4. **Claim 2 is directionally right, specifically wrong.** Template variance exists, but: it is **one** nav (byte-identical across 20 pages, with two justified exceptions and one deck-control false positive), **two** footer link-sets, and one footerless page. The pages named in the claim are not the affected pages — `/epicor-p21-kinetic-reporting` does not exist, and the homepage and `/case-studies` share the identical nav and an identical footer link-set. The genuinely inconsistent pages (`services/erp-integration`, `industries/distribution`) go unmentioned.

5. **Claim 9 is confidently false.** Three prior analyses are cited as describing a four-step process. The section has had exactly three steps in **every one of the 34 commits** that touched `index.html` since it was introduced on 2026-01-21, and the string "four-step" appears nowhere in the repository's history. This is a fabrication that has been repeated and is now being treated as corroborated by repetition. Three sources agreeing is not evidence when none of them checked.

6. **Claim 8's contradiction charge does not hold.** `case-studies.html:299` says: *"**Why there are no percentages on this page.** …Those numbers are only worth anything if someone measured the before state… Where a baseline was captured, it is named."* The policy is scoped to that page and is explicitly conditional on measurement, not an absolute ban. The homepage's `~27%` links directly to `working-with-claude-blog#perf-gain`, where the measurement is described. `llms.txt:18` further qualifies it: *"describes one audit of one estate."* Publishing a measured figure with its methodology one click away is the behaviour the policy asks for, not a violation of it. **Defensible distinction, not a contradiction.**

7. **Claim 8's `300+` point is fair.** On the homepage (`index.html:630`) the label reads only *"views audited"*. "Views" without qualification reads as page-views in a marketing context; it means **SQL Server database views**. The linked target and `llms.txt` both qualify it correctly; the homepage stat tile does not. This is the one place the external analysis found something real that nobody else flagged.

---

## 6. Remediation backlog

Ordered by damage if left alone. **Nothing below was changed.**

### P1 — `working-with-claude-blog.html:679`: "37-slide presentation" → 14

- **Why it matters:** a published, linkable factual claim about the site's own flagship content is wrong by a factor of 2.6. It is the first thing a reader sees before clicking through to a deck that visibly says `1 / 14`. It also propagates: `llms-full.txt:3835` already carries it into the file that AI crawlers are explicitly pointed at by `robots.txt`.
- **Files:** `working-with-claude-blog.html:679`, then regenerate `llms-full.txt` via `node scripts/build-llms-full.mjs`.
- **Careless-change risk:** fixing `llms-full.txt` directly instead of its source. It is generated; the next regeneration silently reverts it and the error returns looking fixed. Fix the blog page **first**, regenerate **second**.

### P2 — `llms.txt` is missing 12 of 23 routes

- **Why it matters:** `robots.txt` names this file as the citation guide for AI crawlers. It omits `/about`, `/contact`, every service page, `/industries/distribution`, and all three case-study children — i.e. the entire Phase 3 URL surface. The pages exist, are in the sitemap, and are in `llms-full.txt`; only the hand-maintained index is stale.
- **Files:** `llms.txt`.
- **Careless-change risk:** `llms.txt` is hand-maintained *by design* — it carries the citation policy prose that a generator cannot produce. Do not "fix" this by generating it; add the twelve entries. The header comment in `scripts/build-llms-full.mjs:6-14` explains the split.

### P3 — `etl-showcase.html:2597`: `billing@yourapp.com`

- **Why it matters:** a placeholder address published on a commercial page. Low-probability harm, zero-cost fix, and the kind of detail a prospective client notices.
- **Files:** `etl-showcase.html:2597`.
- **Careless-change risk:** it sits inside sample/demo content illustrating an integration payload. Replacing it with `info@siegestack.com` would make a **real** address look like a system-generated billing contact and could attract misdirected mail. Prefer an obviously-fictional but non-branded value (`billing@example.com` — RFC 2606 reserved).

### P4 — Footer variant C on two pages

- **Why it matters:** `services/erp-integration` and `industries/distribution` drop all six `/services/*` footer links. Costs internal link equity to the service pages and gives two pages a visibly different footer.
- **Files:** `services/erp-integration.html`, `industries/distribution.html`.
- **Careless-change risk:** these two pages' footers are **not** merely a subset — variant C carries four links (`/#solutions`, `/etl-showcase`, `/operations-modernization`, `/erp-report-slow-month-to-date`) that variant A does not. A blind copy-paste of variant A **removes** four working links. Merge, do not overwrite. Also note the A/B indentation split: match the surrounding file's indentation or the diff will be noisier than the change.

### P5 — Homepage and `/etl-showcase` robots value

- **Why it matters:** both omit `max-image-preview:large, max-snippet:-1`. The homepage is the highest-value page on the site and is the one most likely to be shown with a rich snippet.
- **Files:** `index.html:17`, `etl-showcase.html:17`.
- **Careless-change risk:** minimal. Do not apply the `max-video-preview:-1` variant used by the two `working-with-claude` pages — neither of these has video.

### P6 — `twitter:title` divergence

- **Why it matters:** `etl-showcase.html` will render a literal `&amp;` in its Twitter card — a visible escaping bug. The homepage's inverted word order is cosmetic but means the site presents two different name orders for itself.
- **Files:** `etl-showcase.html`, `index.html`, and optionally the two `working-with-claude` pages (whose shorter twitter titles are a deliberate length accommodation and are **fine as they are**).
- **Careless-change risk:** Twitter titles are length-constrained; the two `working-with-claude` truncations are intentional. Fix only the escaping bug and, if desired, the homepage word order.

### P7 — `/privacy-policy` noindex vs sitemap

- **Why it matters:** contradictory crawl directives. Small, but it is the kind of signal an audit tool flags and a human then has to re-investigate.
- **Files:** either `sitemap.xml` (remove the entry) or `privacy-policy.html:17` (drop to `index, follow`).
- **Careless-change risk:** pick one deliberately. A privacy policy is often *wanted* in the index for trust signals; if so, change the page's meta, not the sitemap. Whichever is chosen, the other must match.

### P8 — Case-study children lack `Article` structured data

- **Why it matters:** the three pages with the actual case-study content are typed only as breadcrumbs. The hub outranks its own children structurally.
- **Files:** `case-studies/kpi-console.html`, `case-studies/label-service.html`, `case-studies/month-to-date-timeout.html`.
- **Careless-change risk:** do not copy the hub's `CollectionPage` type — these are single articles, not collections. Any `datePublished` added must be real; inventing one to satisfy a schema validator publishes a false fact, which is precisely what `case-studies.html:299` establishes as this site's policy against.

### P9 — `_headers` / `netlify.toml` divergence on `/*.js` and `/*.css`

- **Why it matters:** `_headers` states three times that it mirrors `netlify.toml` so that precedence cannot matter. For scripts and stylesheets that is no longer true, so the site's asset caching now silently depends on which file Netlify honours.
- **Files:** `_headers` (add the two rules) or `netlify.toml` (document the deliberate asymmetry).
- **Careless-change risk:** **highest on this list.** Adding `/*.js` immutable to `_headers` extends year-long caching to `jesse-sw.js` and `nicole-sw.js` unless the existing service-worker exceptions are ordered ahead of it. A service worker cached for a year cannot be replaced by deploying — the browser keeps running the old one. `netlify.toml:...` already carries a comment warning about exactly this. Any edit here must preserve the service-worker rules' precedence, and should be verified against the live response headers before being trusted.

---

## 7. Verification status

**Verified from source (deterministic):** all file existence and absence claims; all canonical, robots, title, og, twitter and JSON-LD values; nav and footer variant grouping via content hashing; internal link graph and inbound counts; sitemap, robots.txt, llms.txt and llms-full.txt contents; slide-count references; process step count across all 34 revisions of `index.html`; the complete email-address inventory across the tree and its full git history.

**Appears to be the case (depends on runtime behaviour not observable from source):**
- Netlify's first-match redirect precedence, on which the `/epicor-p21-kinetic-reporting` → `/prophet-21` 301 depends. Source ordering is correct; only a live request proves the rule fires.
- Which of `_headers` and `netlify.toml` wins a header conflict.
- That `/consultant-form.js` is served immutable — observed live earlier in this session, not re-checked for this audit.

**UNVERIFIABLE (would require modification):**
- Whether footer variant C on the two affected pages is a generator bug or an intentional per-section footer. Settling it would require re-running the Phase 3 generator, which is not committed, or editing a page to observe the result. The commit message for `811aea3` describes the generator's intent but does not enumerate footers.
- Whether `llms-full.txt` currently matches what `scripts/build-llms-full.mjs` would produce. Settling it requires running the generator and diffing — a write. **What I can say from source:** the generator is an ancestor-consistent build of the committed pages, and the one discrepancy found (the 37-slide string) traces to its source page rather than to generator drift.

**No claim in this report is asserted without a file path, and no verdict was inferred from likelihood.**

---

## 8. Addendum — the stale-edge hypothesis, tested live (2026-08-16 20:55 UTC)

The open question left by §7 was whether Netlify's edge, rather than the analyst's fetch layer, was serving a pre-Phase-1 homepage — in which case Googlebot would hold a copy with the gmail footer and `meta keywords`, and no repository change would fix it.

**Tested against production. The edge is not stale.**

| Check | Result |
|---|---|
| `Age` on bare `/` | **0** |
| `Cache-Control` on `/` | `public,max-age=3600` (HTML is *not* long-cached) |
| `ETag`, bare vs `?cb=<ts>` | **identical** — `5abf3ded…-ssl` |
| `iamnotcheckingit@gmail.com` in live `/` | **0 occurrences** (bare *and* cache-busted) |
| `name="keywords"` in live `/` | **0** |
| Live `/` nav | current 11-link block, includes `/prophet-21`, `/about`, `/contact` |
| Live `/` process steps | **3** |
| `info@siegestack.com` in live `/` | 2 |

Decisive check: the live homepage diffed against `index.html` at HEAD is **byte-identical apart from Netlify's injected RUM script**, which is added at serve time and is not in the repository. The edge is serving the current deploy.

**Conclusion:** the stale copies were in the analyst's fetch layer, not at the edge. No purge is required and no HTML cache rule needs changing — `max-age=3600` on HTML is already the correct, short value, declared identically in both `_headers` and `netlify.toml`.

**Correction to the proposed mechanism:** the `_headers` / `netlify.toml` divergence (§4.7, P9) **cannot** produce a stale homepage. The divergence is confined to `/*.js` and `/*.css`; both files agree on `/*` HTML at `max-age=3600`. P9 remains a real finding about script and stylesheet caching, but it is unrelated to this hypothesis and should not be prioritised as its fix.

**Not verifiable from here:** Google Search Console's URL Inspection holds the copy Google actually fetched and rendered, and no repository or HTTP check can substitute for it. Given `Age: 0`, matching ETags, and byte-identical content, a stale Googlebot copy is unlikely — but the Search Console record is the only direct evidence and remains worth pulling.

### Backlog amendment — P3 (`billing@yourapp.com`) fix corrected

The proposed remediation *"replace with `info@siegestack.com`"* is **wrong and should not be applied.** Verified context: `etl-showcase.html:2597` sits inside a JavaScript template literal (`code: \`…\``) within the executing `<script>` block that opens at `etl-showcase.html:2092`. It is **sample code displayed to visitors** — a multi-tenant API handler for a hypothetical SaaS app, using the same placeholder convention as `tenantSlug` (`:2580`) and `acme` (`:2417`).

`billing@yourapp.com` is the *fictional application's own* billing contact, not a SiegeStack contact surface. Substituting the real address would:

1. misrepresent what the sample depicts — implying SiegeStack handles that app's billing;
2. ship a live address into code a reader may copy and run;
3. require an edit **inside a `<script>` block**, the one class of change that HTML-level checks cannot validate.

Correct fix: an unambiguously fictional, non-branded value — `billing@example.com` (RFC 2606 reserved). Severity is lower than §4.3 originally implied: the string is visible only to a reader studying the code sample, and it reads as a placeholder in context rather than as a stale real address.

---

## 9. Addendum — Claim 1 verified against production (2026-08-16 21:0x UTC)

§3.1 refuted Claim 1 from source and git history alone, and flagged rule precedence as runtime behaviour it could not observe. That left a real gap: **a 404-fix rewrite that now serves one file at two paths would look correct in the repository and still produce two indexable URLs.** Source evidence cannot close that; only a request can.

Tested:

| URL | Status | Canonical in served body |
|---|---|---|
| `/prophet-21` | **200** | `https://siegestack.com/prophet-21` |
| `/epicor-p21-kinetic-reporting` | **301** → `/prophet-21` | none — 26-byte redirect stub |
| `/epicor-p21-kinetic-reporting.html` | **301** → `/prophet-21` | none |
| `/prophet-21.html` | **301** → `/prophet-21` | none |

The old slug returns a **26-byte body with no `<link rel="canonical">` at all**, which is what excludes the "one file, two paths" case: a page served at both would return 200 with a full body at each. Exactly one URL returns 200, and all four variants resolve to a single canonical. `llms.txt` and `sitemap.xml` each reference `prophet-21` once and `epicor-p21-kinetic-reporting` zero times.

**Claim 1: REFUTED — now confirmed at runtime, not inferred.** The `19ea665` fix works as its commit message claims.

---

## 10. Correction to this report's own backlog: P9 was wrong, and wrong dangerously

P9 (§6) recommended adding the missing `/*.js` and `/*.css` rules to `_headers` so the two files would agree. **That remedy was incorrect and would have manufactured the defect it was written to prevent.** It is recorded here rather than silently amended, because the in-tree comments now carry the correct reasoning but cannot carry the fact that the written remedy was wrong.

What probing the live system showed, which reading the config did not:

| Asset | Live `Cache-Control` |
|---|---|
| `/consultant-form.js` | `public,max-age=31536000,immutable` |
| `/jesse-sw.js` | `no-cache,must-revalidate` |
| `/nicole-sw.js` | `no-cache,must-revalidate` |

The specific service-worker rules already win over the broad `/*.js` rule. **There was no live defect.** And adding `/*.js` to `_headers` would have put both service workers in scope of a year-long immutable cache — and a service worker cached for a year cannot be replaced by deploying, because the browser keeps running the old one. The bug would have outlived every subsequent fix, on the two pages where it is least visible and most costly.

The finding underneath was real but smaller than stated: nothing recorded *why* the asymmetry exists, so the next reader would draw the same conclusion and might act on it. Resolved in `ce53586` by documenting the boundary in both files — comments only, no rule moved. `/*.css` was found to match nothing today (the site has no external stylesheet) and was deliberately kept, with a note that whoever adds the first one inherits the year-long cache and needs a `?v=` token on day one.

**The generalisable lesson, and the reason this section exists:** a remediation item derived from reading configuration encoded a change that would have created an outage-class bug. Config review found the asymmetry; only touching the running system distinguished "diverged and broken" from "diverged and correct." Any audit that stops at source produces confident items of exactly this shape, and the shape is invisible from inside the audit. **Verify a proposed fix against the live system before it reaches a backlog, not after it reaches production.**

---

## 11. What this report is for

Most of the verdicts above are refutations, and the confirmed findings were fixed in `e9d33c4` and `ce53586` within an hour of the report being written. The durable value is not the confirmed list. It is:

- **The negative space** — the record of what was checked and found *not* broken. Every canonical, every anchor, every nav and footer variant, every metric, the crawl layer, the full email inventory across history, and the process step count across all 34 revisions. Re-deriving that costs hours; knowing it was checked, when, and at which commit costs nothing.
- **The corrections trail** (§5, §8, §10) — where an assessment was wrong, and *by what mechanism*. Three distinct failure modes are recorded: a caching layer misread as template drift, three passes of one tool mistaken for three corroborating sources, and a config-derived remedy that would have caused the fault it targeted. Those recur; the specific findings do not.
- **The dated commit anchor.** Every claim here is pinned to `674afe5`. A future assessment that disagrees can be diffed against this one instead of re-litigated.
