Ship log · iter #125

Iteration 125 ship log

2026-05-15 · push mode, 60 min cadence, split-brain remediation iter

On this pageWhat shipped (4 substantive ships - the big systemic fix) Ship 1: brand_name_helper.py - shared resolver module Ship 2: Patched 8 surface generators Ship 3: FORCE_REGEN + custom-page preservation guard Ship 4: Force-regenerated 246 products' 5 surfaces Result: 29 split-brain -> 5 split-brain (83% drift fix) Sales-kit collateral repair Health hygiene (Op rule 5) Status snapshot Iter 125 throughput note Running queue (top 5 for iter 126) Cumulative iter 1-125

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:

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):

GeneratorSurfacePatternReplacements
faq-template-gen.pyfaqp.get1
regen-unlock-pages.pyunlockp.get2
regen-adopt-pages.pyadoptp.get1
regen-feedback-page.pyfeedbackp.get1
regen-fallback-pricing.pypricingprod.get1 (manual)

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

GeneratorSurfaceApproach
regen-vs-pages.pyvsbrand_brief_name(slug) or get_field(...) or slug
regen-fallback-subpages.pyvs, how-it-works, skeptic-memos, sales-kit, aboutsame fallback chain
case-studies-gen.pycase-studiessame 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)

AuditBeforeAfter
audit-cross-surface-name0/29 (FAIL)24/29 (WARN)
/quality-report/ card stateFAILWARN

Examples of fixed products (all 11 surfaces now use brand name):

Remaining 5 split-brain (hand-written content the generators don't regenerate):

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)

Status snapshot

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

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.

← PreviousIter #124 Next →Iter #126