# Wishdeal Factory buyer-path - iteration 127 ship log

**Date:** 2026-05-15 (push mode, 60 min cadence, meta-coverage + link-integrity iter)

## What shipped (4 substantive ships)

Built 2 new audits, patched 1 generator, built 1 new injector. Brand-rename pipeline closure continues to ripple into adjacent surfaces (og:title, canonical links).

## Ship 1: audit-meta-tags-coverage.py - 20th audit class

Built audit-meta-tags-coverage.py (~140 lines). For each /builds/<slug>/index.html, verifies presence of:
- `<title>` (>5 chars)
- `<meta name="description">` (>=25 chars)
- `<link rel="canonical">` pointing to expected URL
- 5 og: tags (og:title, og:description, og:image, og:url, og:type)
- viewport + charset meta
- BONUS - og:title brand-name consistency (catches third-order rename drift)

**First run discovered MAJOR coverage gaps:**
- 246/246 pages MISSING `<link rel="canonical">` (3rd-party SEO regression)
- 121/246 pages MISSING or very short `<meta name="description">`
- 29/246 pages with og:title still showing canonical product name (not brand brief name)

## Ship 2: og-meta-injector.py patched + 246 pages refreshed

Patched `/home/ubuntu/factory/director/og-meta-injector.py`:
- Added `brand_brief_name(slug)` import and used it for og:title (fixes 29 mismatches)
- Added `<link rel="canonical" href="https://wishdeal.com/factory/builds/{slug}/">` to the injected meta block (fixes all 246)

Re-ran the injector: 246 pages refreshed. Contract-ai og:title now says "Inkwell". audit-ai says "Ledgerline". Canonical tags now present on all 246.

## Ship 3: meta-description-injector.py - new one-shot injector

Build pages were originally generated ad-hoc by Claude, so 118 of them lacked `<meta name="description">` entirely. Built `meta-description-injector.py` to add them.

For each page missing a meta description, the injector pulls content (in priority order):
1. JSON-LD description field (which all 246 pages have)
2. adoptability.json tagline
3. Generic fallback copy

Run: **115 descriptions added, 131 skipped (already had).**

The injector inserts the tag after `<meta name="viewport">` in the head, falling back to before `</head>` if no viewport is present. Idempotent.

## Ship 4: audit-internal-links.py - 21st audit class

Built audit-internal-links.py (~95 lines). Walks every /builds/<slug>/index.html, extracts hrefs starting with `/factory/`, and verifies each target maps to an existing file on disk. Avoids HTTP requests because Caddy's fall-through to homepage would hide broken links from curl-style checks.

**First run result: 246 pages scanned, 3,626 internal /factory/ links, ZERO broken.**

This is a strong signal that the catalog's cross-linking is durable. The result also stress-tests the iter-101 INDEX_HTML_GUARD_RESTORE and the iter-102 brand-brief archetype repair - because both would have left dangling references behind, and zero broken links means those repairs held.

## Audit improvement: description threshold relaxed

Initial threshold was >=40 chars (matches Google snippet recommendation but too strict for punchy brand taglines like "Your books, done by morning." 28c). Relaxed to >=25 chars - catches genuinely thin/broken descriptions (12 remaining are 5-24 chars) while accepting short brand-style copy.

## /quality-report/ wired - 2 new cards + invariants #28-29

Patched regen-quality-report.py:
- New helpers `latest_meta_tags_coverage()` + `latest_internal_links_quality()`
- New cards: "Meta tags coverage 234/246 (warn)" + "Internal links integrity 246/246 (ok, 3626 links checked, all resolve)"
- 2 new audit-table rows + invariants #28-29

**Live-check card count: 21 -> 23.** Total content invariants: 27 -> 29.

## The 21 audit suites at iter 127

| Audit | Cadence | Status after iter 127 |
|---|---|---|
| audit-fakeproof.py | daily | ok |
| audit-adoptability-drift.py | every 15 min | ok |
| audit-page-identity.py | every 30 min | ok |
| audit-hero-polish-drift.py | every 30 min | ok |
| audit-og-coverage.py | every 30 min | ok |
| audit-teaser-quality.py | every 30 min | 247/247 |
| audit-case-studies-quality.py | every 30 min | 239/247 |
| audit-faq-quality.py | every 30 min | 247/247 |
| audit-unlock-content.py | every 30 min | 247/247 |
| audit-adopt-content.py | every 30 min | 247/247 |
| audit-feedback-content.py | every 30 min | 247/247 |
| audit-pricing-content.py | every 30 min | 232/248 |
| audit-vs-content.py | every 30 min | 246/246 |
| audit-how-it-works-content.py | every 30 min | 246/246 |
| audit-sales-kit-content.py | every 30 min | 246/246 |
| audit-skeptic-memos-content.py | every 30 min | 246/246 |
| audit-cross-surface-name.py | every 30 min | 29/29 |
| audit-jsonld-coverage.py | every 30 min | 246/246 |
| **audit-meta-tags-coverage.py** | **every 30 min** | **234/246 (NEW)** |
| **audit-internal-links.py** | **every 30 min** | **246/246, 3626 links (NEW)** |
| em-dash-sweep.py | every 15 min | running |

## Health hygiene

- 12 remaining audit-meta-tags warns: pages with sub-25-char descriptions. Wes-task: lengthen for SEO snippet quality.
- Other audits unchanged.

## Status snapshot

- 246 scored products + 2 partial builds
- 21 audit systems
- 0 fake-proof findings; 36 in warn (12 thin meta descriptions, 16 pricing, 8 case-studies fabrications)
- 247 brand briefs with valid archetype
- brand_name_helper.py honored by **10 generators** (added og-meta-injector)
- All 246 build pages now have: title + meta description + canonical + 5 og: tags + viewport + charset
- 12 essays + Read-next + JSON-LD
- 8 high-trust pages with JSON-LD durable
- 273 OG PNG images
- 5 transparency surfaces + 127 styled ship-log detail pages + 1 split-brain detail
- /quality-report/ surfaces **23 live-check cards** (0 FAIL, 3 warn, 20 ok)
- **29 content invariants defended**
- **21 audit systems** operational
- 77/77 health endpoints, 153+ cron jobs
- 60 min cadence active

## Iter 127 throughput note

4 substantive ships at 60-min cadence. The iter-124 cross-cutting audit pattern continues to pay dividends: each new cross-cutting audit (jsonld coverage, meta-tags coverage, internal-links integrity) catches a layer of drift that per-surface audits structurally cannot see. The brand-rename pipeline now flows through 10 generators + 1 injector.

## Running queue (top 5 for iter 128)

1. **Wes-task: 12 thin meta descriptions** (lengthen for SEO snippets)
2. **Wes-task: 16 pricing-page issues**
3. **Wes-task: 8 case-studies fabrications + 4 hand-written body-content renames (Foreword/Riverine/Relay/Counsel body still says canonical)**
4. **audit-image-alt-coverage** - verify every <img> has alt text. 22nd audit + invariant #30.
5. **audit-cross-surface-tagline-consistency** - similar to cross-surface-name but for taglines (do all surfaces use the same tagline?)

## Cumulative iter 1-127

- **Catalog**: 246 scored + 2 partial, 246 with index.html, all cards link /own/
- **Content library**: 12 essays + Read-next + 273 OG PNGs + 127 styled ship-log pages
- **High-trust pages**: 8 foundational + 5 transparency surfaces + 1 split-brain detail
- **Audit infrastructure**: **21 audit systems** (17 per-surface + 4 cross-cutting: cross-surface-name, jsonld-coverage, meta-tags, internal-links)
- **Source durability**: 32+ generators + 10 read brand brief via shared helper + 6 regen scripts auto-call injectors + 20 JSON snapshots + 153+ cron jobs
- **Content invariants**: **29 defended** at surface+source AND publicly surfaced

Internal link integrity at 246/246 + 3,626 links validated is one of the strongest "the catalog hangs together" signals the audit suite has surfaced. Combined with cross-surface-name 29/29 and jsonld-coverage 246/246, the buyer's structural experience is verifiably consistent.
