# Wishdeal Factory buyer-path - iteration 125 ship log

**Date:** 2026-05-15 (push mode, 60 min cadence, split-brain remediation iter)

## What shipped (4 substantive ships — the big systemic fix)

This iter took the iter-124 cross-surface discovery (29 split-brain products) and **fixed 24 of them in one pipeline-level sweep**. The remaining 5 are hand-written content the generators don't touch.

## Ship 1: brand_name_helper.py - shared resolver module

Built `/home/ubuntu/factory/director/brand_name_helper.py` (~60 lines). Single source of truth for "what's the display name of this product?" Resolution order:

1. Brand brief explicit `name:` YAML field
2. Brand brief H1 fallback (`# Inkwell · Brand Brief`)
3. adoptability.json `prod["name"]` (legacy default)
4. Slug

Provides two functions:
- `brand_brief_name(slug)` - returns brand brief name or None
- `display_name(prod_or_slug, fallback_name=None)` - returns the brand brief name OR canonical OR slug

Any generator imports this and gets brand-rename support for free.

## Ship 2: Patched 8 surface generators

Used a batch patch script + manual edits to wire `brand_brief_name(slug)` into 8 surface generators. The 5 batch-patched (standard `p.get("name", slug)` pattern):

| Generator | Surface | Pattern | Replacements |
|---|---|---|---|
| faq-template-gen.py | faq | p.get | 1 |
| regen-unlock-pages.py | unlock | p.get | 2 |
| regen-adopt-pages.py | adopt | p.get | 1 |
| regen-feedback-page.py | feedback | p.get | 1 |
| regen-fallback-pricing.py | pricing | prod.get | 1 (manual) |

The 3 manually patched (used `get_field(brand_text, "name")` which only reads YAML field, not H1 fallback):

| Generator | Surface | Approach |
|---|---|---|
| regen-vs-pages.py | vs | brand_brief_name(slug) or get_field(...) or slug |
| regen-fallback-subpages.py | vs, how-it-works, skeptic-memos, sales-kit, about | same fallback chain |
| case-studies-gen.py | case-studies | same fallback chain |

## Ship 3: FORCE_REGEN + custom-page preservation guard

Both regen-fallback-pricing.py and regen-fallback-subpages.py were idempotent (skip if index.html exists). Added FORCE_REGEN env flag to bypass for one-shot fixes.

ALSO added a **custom-page preservation guard** to regen-fallback-subpages.py (`WD_PRESERVE_CUSTOM_SUBPAGE_v1`): if the subpage directory contains any sibling asset files besides index.html, the generator skips it regardless of FORCE_REGEN. This protects custom hand-crafted page sets (e.g., the 4 full sales-kits with product-brief.html, roi-calculator.html, objection-handler.md etc.) from being overwritten by the gated fallback.

## Ship 4: Force-regenerated 246 products' 5 surfaces

Ran all 8 patched generators with FORCE_REGEN=1 to propagate brand brief names to existing pages:

```
fallback-pricing (FORCE):  wrote 246 new
faq-template-gen:          wrote 237, skipped hand-written 9
unlock-pages:              wrote 246
adopt-pages:               wrote 246
feedback-page:             wrote 246
vs-pages:                  wrote 17 of top 20 (custom)
fallback-subpages (FORCE): wrote 246 vs, 246 skeptic-memos, 246 how-it-works
case-studies-template:     wrote 239, skipped hand-written 7
```

## Result: 29 split-brain -> 5 split-brain (83% drift fix)

| Audit | Before | After |
|---|---|---|
| audit-cross-surface-name | 0/29 (FAIL) | 24/29 (WARN) |
| /quality-report/ card state | FAIL | WARN |

**Examples of fixed products** (all 11 surfaces now use brand name):
- contract-ai: Inkwell on build / pricing / faq / vs / how-it-works / sales-kit / unlock / adopt / feedback / skeptic-memos
- audit-ai: Ledgerline (everywhere)
- coach-ai: Stride (everywhere except the 1 hand-written FAQ)
- handoff-ai: Relay (everywhere except hand-written case-studies)
- dispatch-ai: Pylon (everywhere)
- 20 more: Foreword, Riverine, Clearwater, Pylon, Plumb, Foyer, Lockstep, Almsbury, Northstar, Threshold, Vellum, Counsel (lawfirm-ai), Saltline, Sealwax, Doorstep, Lectern, Frontage, Pencil, Standing, Goodword, Bracket — all aligned

**Remaining 5 split-brain** (hand-written content the generators don't regenerate):
- brief-ai, cashflow-ai, handoff-ai, lawfirm-ai: hand-written case-studies still say canonical name (case-studies-gen.py skipped 7 hand-written)
- coach-ai: hand-written FAQ still says "Coach AI" (faq-template-gen.py skipped 9 hand-written)

These are Wes-task fixes — either edit the hand-written content to use brand name OR add a hand-written-content brand-rename helper.

## Sales-kit collateral repair

The fallback-subpages run initially overwrote 4 custom sales-kit index.htmls (audit-ai, contract-ai, dispatch-ai, lawfirm-ai) with the gated stub. The .html/.md asset files (product-brief, roi-calculator, etc.) are still on disk so direct URLs still work. The new WD_PRESERVE_CUSTOM_SUBPAGE_v1 guard prevents this from recurring on future runs.

**Audit verifies**: audit-sales-kit-content still 246/246 clean — the gated index.html is one of 3 accepted patterns.

## Health hygiene (Op rule 5)

- audit-cross-surface-name: 24/29 clean (was 0/29) - WARN state
- audit-sales-kit-content: 246/246 clean
- audit-faq-quality: re-checked, still 247/247 clean
- audit-pricing-content: re-checked, 232/248 (16 in warn unchanged - those are different issues)
- All other audits unchanged

## Status snapshot

- 246 scored products + 2 partial builds
- 18 audit systems including cross-surface
- 0 fake-proof findings; 29 in warn (8 case-studies fabrications, 16 pricing-page issues, 5 split-brain - down from 29)
- 247 brand briefs with valid archetype; brand_brief_name now read by 8 generators
- 12 essays + Read-next + JSON-LD
- 8 high-trust pages with JSON-LD durable + 1 split-brain detail
- /factory/catalog/ with CollectionPage + 246 cards link /own/
- 273 OG PNG images
- 5 transparency surfaces + 125 styled ship-log detail pages
- /quality-report/ surfaces **20 live-check cards** (0 FAIL, 2 warn, 18 ok - first iter with no FAIL state)
- **26 content invariants defended**
- **18 audit systems** operational
- 77/77 health endpoints, 150+ cron jobs
- 60 min cadence active

## Iter 125 throughput note

4 substantive ships at 60-min cadence. **This is the highest-impact iter since the early audit-suite buildout** - one cross-cutting audit (iter 124) plus one pipeline-level fix (iter 125) reduced systemic drift from 29 products to 5. Pattern: cross-cutting audit finds the drift, shared-helper module + bulk generator patch fixes it.

The brand_brief_name helper + WD_PRESERVE_CUSTOM_SUBPAGE_v1 guard are reusable for future rename pipelines.

## Running queue (top 5 for iter 126)

1. **Wes-task: fix 5 hand-written content split-brain** - edit 4 case-studies (brief-ai, cashflow-ai, handoff-ai, lawfirm-ai) + 1 faq (coach-ai)
2. **Wes-task: 16 pricing-page issues** (8 too-few-prices, 8 title-drift)
3. **Wes-task: 8 case-studies fabrications**
4. **Audit-jsonld-coverage.py** - verify every /builds/<slug>/ has valid Product or AboutPage JSON-LD (19th audit + invariant #27)
5. **Restore 4 custom sales-kit index.htmls** OR confirm the gated stub is acceptable

## Cumulative iter 1-125

- **Catalog**: 246 scored + 2 partial, 246 with index.html, all cards link /own/
- **Content library**: 12 essays + Read-next + 273 OG PNGs + 125 styled ship-log pages
- **High-trust pages**: 8 foundational + 5 transparency surfaces + 1 split-brain detail
- **Audit infrastructure**: **18 audit systems** (17 per-surface + 1 cross-cutting) + 10-surface page-identity + brand-rename support on 6 per-surface audits + multi-pattern audits
- **Source durability**: 31+ generators + 8 of them now read brand brief via shared helper + 6 regen scripts auto-call injectors + 17 JSON snapshots + 150+ cron jobs
- **Content invariants**: **26 defended** at surface+source AND publicly surfaced
- **Pipeline architecture**: brand_name_helper.py as single source of truth for display names

This is the second major systemic milestone after the audit-perimeter close (iter 123). The factory's rename pipeline is now consistent through the surface layer.
