⚠️ Apr 27 10:25 CT correction: Earlier handoff referenced "post 999" for the native-save smoke gate. Producer-as-verifier check (Apr 27 09:55 CT) found post 999 is registered as the auditor's fake-fixture decoy in auditor_tools.py:46 KNOWN_POST_IDS. Smoke fixture corrected to canonical post 258 (M1 baseline 146 elements). Smoke ran 10/10 PASS in 5.82s on the corrected fixture. See MH bsp-apr27-smoke-gate-built-and-fixtures-corrected.

✅ Apr 27 EOD update: Mon recovery shipped clean. 22/22 staging pages provisioned + content-cloned. All native-save callers consolidated on dispatcher_safety.native_save_with_external_verify (defense-in-depth · §7 draft-meta failure mode caught experimentally + codified). Location mining 14/14 · Service mining 7/7 (service_page_mining.py Apr 27 ship). Bricks Codebase Doc + Figma Codebase Doc both TIER 0. Tue AM 09:00 CT dispatch: GREEN. See MH bsp-apr27-end-of-day-final-state for full receipts.

📡 Bright Side Plumbing · Apr 26, 2026 · Live Rehearsal Report

Friday May 1 Cutover — 📖 v4 Bible Mode · Run Record

📡 Mon AM Fresh Session?
Read this first → BSP_Monday_AM_Handoff.html
3-min orient · 24-gate rehearsal · 13 fixes shipped · all decisions locked · bootup prompt for Mon 7:55am CT

This document is NOT a checklist. It is the live execution record of cutover_rehearsal.py --preflight with actual data, actual PASS/FAIL per gate, actual receipts. Re-running the script overwrites this report. Robert reviews real numbers, not theoretical instructions. Linked from the Battle Plan and Audrey's Library, indexed by Zeus RAG.

⏱️ LATEST PREFLIGHT RUN
2026-04-26 14:35:30 → 14:35:40 CDT · 10 seconds total
7PASS 0FAIL 0WARN 4INFO
Re-run: ssh dovew@34.55.179.122 "cd /opt/nexus/nexus/scripts && python3 cutover_rehearsal.py --preflight"
🎨
🎨
For Audrey · Week of May 1, 2026 · Per Playbook §2

Hi Audrey 👋 — your week at a glance

This week is a cutover week — your design work is locked, scripts are running. You have two optional async reviews totaling ~35 minutes. Real design lift resumes Week 2 with the Sewer Camera Inspection hero.

🎯 Your Lane
  • 🎨 Figma · all design output
  • 💬 Slack · communication only
  • 🔒 Apr 18 specs · stewardship
  • 🚀 Week 2 hero · Sewer Camera
🤖 Robert's Lane (FYI only)
  • 🧱 Bricks UI · WordPress build
  • ⌨️ Terminal · scripts + APIs
  • 🤖 populate_*.py · automation
  • 🔄 Rank Math · 301 redirects
📅 Your Week — Sun → Sat
SUN
27
MON
28
TUE PM
29
⏱️ ~15 min
Tmpl A/B
spec QA
WED
30
THU
1
⏱️ ~20 min
Visual
sweep
FRI
2
CUTOVER
Robert solo
SAT
3
Total this week: ~35 min OPTIONAL. Real lift starts Week 2 (Sewer Camera Inspection hero PNG · 2-3 hrs).
🔒 Your Apr 18 Specs · LOCKED
#30C5FF · borders
#FFEA00 · highlights
#F2F2F2 · backgrounds
Aa · Inter font

📐 Source: BSP_Apr18_Claude_Design_For_Audrey.html

🚀 Week 2 Sneak Peek · Sewer Camera Inspection Hero
Slug/sewer-camera-inspection/
VibeDiagnostic · explainer-style · trust-builder
Why nowFREE Camera nav CTA needs the SEO variant at /services/sewer/...
Lift2-3 hrs · ship May 8-15
BriefRobert sends Mon May 5 AM · Stephanie format · Slack DM
⛔ Hard rules — what you do NOT do

Per Menu Page Strategy §9: project-by-project · one template + one hero per week max.

🔗 Your Shortcuts
📐 Apr 18 Design Doc 🎨 Audrey Library 📘 Menu Strategy §2/§7/§9
📚

Related Playbooks — Bible Interlinks

SSoT INDEX

Every playbook this Bible plugs into. Open in tabs side-by-side for execution. Re-fetch any time uncertain.

PlaybookWhy this weekOwner
🧱 BSP_Bricks_Codebase_DocumentationThe framework Claude must plug into AT ALL TIMES — populate scripts, native-save endpoint, walker v3, element-tree shapeRobert
📘 BSP_Menu_Page_Strategy_PlaybookSlug taxonomy §6 (/services/{cat}/{slug}/) · §7 Phase 2 cadence · §9 Audrey workflow rules · §2 Audrey-on-top ruleRobert
🎨 Apr18_Claude_Design_For_AudreyAudrey design specs locked Apr 18 · Inter, doodle, wave hero, color tokensAudrey
🎨 audrey_creative_libraryAudrey's living library · Week 2 hero targetAudrey
⛏️ Service_Page_Copy_Mining_SystemApr 21 mining canon — Component 9 routes service script hereRobert
📊 BSP_Bricks_Staging_Audit_Apr27Real-data audit of 15 staging pages · gap surfacesRobert
📚 BSP_Content_Database_InventoryMining systems + 8 data sources + per-page content mapRobert
⚔️ BSP_Website_Platform_Battle_PlanOverall battle plan · v4 callout cross-linkRobert
📡 BSP_Ads_Attribution_BreakthroughGCLID + Monday Pipeline · post-cutover RSA URL bulk update referenceRobert
📜 BSP_Master_Session_HistoryPaper trail · query before any decision · log every action via nexus_html_logger.pyRobert
📅

Daily Execution Focus — Sun → Fri

EXECUTION CADENCE
Day🤖 Robert (terminal + Bricks UI)🎨 AudreyGate / Output
Sun PM
Apr 27
Write mining_brief_schema.json · final Bible re-read · stop-loss budget set $80 councilSchema file present + smoke-validated
Mon AM
Apr 27
08:00 dual council dispatch (A: service · B: location) via council v2 · 11:00 native-save smoke 10/10 · 13:00 both v1 scripts ready2 scripts at v1 + smoke 10/10
Mon PMCITY_ZIPS extended for 6 TIER B · 17:00 sewer-repair trial run + Playwright independent verify · GBP location_id fix · pause /lp/drain-cleaning-special/ ads · Rank Math rules staged DISABLED1 service page populated end-to-end + verified
Tue AM
Apr 29
Full parallel populate: 7 service pages + 15 location pages(optional) review Template A + B mockups · Slack 👍22/22 pages populated DRAFT
Tue PMBuild Kalen review dashboard /preview/may1/ · ~5 hrs · Slack DM thread per page · auto-screenshot desktop+mobileDashboard live · Kalen onboarded
Wed AM
Apr 30
Build 6 informational pages: About · Contact · FAQ · Financing · Reviews · Coupons-deferred-redirect-only5 informational pages DRAFT (Coupons stays redirect-only)
Wed PMKalen batch 2 review pass · iterate redlines · publish DRAFT → READY for in-place 30 pages≥ 25/30 READY
Thu AM
May 1 (early)
Final QA · Playwright sweeps · curl matrix preflight · build nested nav(optional) final visual sweep on dashboard30/30 APPROVED gate · cutover_rehearsal.py PASS
Thu PMKalen final approval · runbook re-read · backup snapshot takenKalen sign-off received
Fri
May 2 08:00 CT
CUTOVER: backup → slug rename in Bricks UI (9 pages) → Rank Math rules ENABLE → theme switch Oxygen→Bricks → curl matrix verify → Big Sale tracking verify · monitor 90 minPhase 1 LIVE · 30 pages · Big Sale tracking intact

Daily standup at 09:00 CT: 5-min Slack post — yesterday's gate hit/missed · today's 1-line focus · blockers (PROBLEM/IMPACT/SOLUTION/DATA/NEED format).

🛡️

11 Gates · Live Run Results (2026-04-26 14:35 CDT)

AUTOMATED
GATE 1
Staging clone reachable
HTTP 200 on https://bricks.callbrightside.com
PASS
🔐
GATE 2
functions.php canonical baseline
observed: 131,232 bytes / sha 22a4da06d76cf7c1... · expected: 131,232 / 22a4da06d76cf7c1... · MATCH
PASS
GATE 3
Active RSAs needing URL update at cutover
9 active-serving RSAs (campaign+ad_group+ad all ENABLED) need URL update Friday — matches v3 §6 #6 spec exactly
PASS
🌐
GATE 4
Prod URL inventory (11 redirect-map entries)
11/11 URLs return HTTP 200 or 301 · all addressable for the cutover redirect plugin
PASS
🗺️
GATE 5
13 /map/ city pages target slugs
Per Apr 24 fix-7 lock: /map/ deploys POST-launch. 13-city slug list ready for Phase 2 (overland-park, olathe, lenexa, shawnee, leawood, prairie-village, blue-valley, westwood, mission, kansas-city-mo, independence, lees-summit, south-kc).
INFO
GATE 6 · ACTION REQUIRED
Redirection plugin REST endpoint reachable
HTTP 404 on /wp-json/redirection/v1/redirect — endpoint either auth-required-which-is-expected OR plugin not installed/activated on staging. Verify before Friday: ssh + WP CLI wp plugin list --status=active | grep redirect. Per v3 §2: Rank Math Redirections category bulk-action (B2 pivot) is the rollback gate. Plugin must be confirmed active.
FAIL
🔄
GATE 7
Cutover-day curl matrix (simulation, not fired)
9 curl checks queued for Friday cutover — full matrix in §Redirect Map below. Will fire automatically post-cutover via the rehearsal script with real production targets.
INFO
📋
GATE 8
Schema validation targets identified
Friday cutover validates BreadcrumbList JSON-LD on /services/sewer/sewer-repair/, /services/drains/drain-cleaning/, /about-us/ via Google Rich Results Test API.
INFO
🤖
GATE 9
Smart Bidding hands-off window
Apr 11 → Apr 26 LEARNING_COMPOSITION_CHANGE window ENDED Apr 26 23:59 UTC. Today: 2026-04-26T19:35:40+00:00. CPL post-relearn check (Sewer campaign, 14d pre vs post): pre $13.15 / post $13.56 / volume +80% — flat CPL, doubled volume.
PASS
🔌
GATE 10
Attribution pipeline source-side patch
patch:✅ slack:✅ yaml:✅ parser:✅ — Apr 26 deep-parse + #lab Slack heartbeat + DEBUG yaml + parse_google_ads_debug.py forensic backup all in place.
PASS
🔁
GATE 11
Rollback path documented
Per v3 §7: (1) theme switch Bricks → Oxygen 1-click, (2) toggle "May 1 Cutover" redirect group OFF in Redirection plugin 1-click, (3) unpublish new pages. 30-min rollback budget. Trigger criteria: site 5xx errors · >1 redirect fails verification · homepage broken · Bricks fails to render · >5 ads disapproved.
INFO
🎯

B2 Pivot — Rank Math Redirections (Apr 26 16:00 CDT)

RULE OF ONE

Gate 6 PIVOTED: earlier run flagged Redirection plugin REST 404 on staging — surfaced a real architectural conflict. Robert chose Path B2: use Rank Math Redirections module (already on prod) instead of installing a 2nd redirect manager. Result: Gate 6 now PASS, zero plugin install, zero conflict, single source of truth.

Why this is bulletproof default:

  1. Rule of One — Rank Math already owns sitemap + schema + meta on prod. Adding redirects keeps everything in one plugin. Two redirect managers = the exact architectural debt the Apr 11-12 phantom-numbers fix paid to eliminate.
  2. Zero install step — Rank Math active on callbrightside.com verified via rank-math-schema JSON-LD signature.
  3. Survives theme switch — Rank Math redirect rules are in DB (wp_options), not theme files. Cutover theme switch preserves them.
  4. Pre-stage allowed — Rank Math redirect rules can be created DISABLED in advance. Bulk-enable at cutover step 8 = simultaneous activation, no race condition.

Rollback flow under B2:

1. Theme switch Bricks → Oxygen (1-click, WP admin → Appearance → Themes)
2. Rank Math → Redirections → Categories → "May 1 Cutover" → bulk action: Disable all
3. (Optional) Unpublish 9 new Bricks pages
   → Old URLs serve Oxygen content as before. 30-min rollback budget intact.
🔄

301 Redirect Map (canonical, ground-truth verified Apr 26)

RANK MATH CATEGORY "MAY 1 CUTOVER"
Old URL (Oxygen)New URL (Bricks)CategoryRSAsNotes
/sewer-repair//services/sewer/sewer-repair/Sewer49THE converter (17.2% conv rate)
/trenchless-sewer-repair//services/sewer/trenchless-sewer-repair/Sewer73K/mo organic
/sewer-cleaning//services/sewer/sewer-cleaning/Sewer12
/sewer-line-replacement/Phase 2 NEW (decision 1b)Page does not exist on prod
/drain-cleaning//services/drains/drain-cleaning/Drains242nd rule for /plumbing-services/drain-cleaning/ (decision 3a)
/water-heaters-installation//services/water-heaters/water-heater-repair/WH25Decision 4a: both old slugs collapse
/water-heater-repair//services/water-heaters/water-heater-repair/WHDecision 4a (2nd rule)
/sump-pumps//services/emergency/sump-pump-emergency/Emergency8
/leak-repair//services/other/leak-repair/Other10
/gas-line-repair/Phase 2 (decision 2b)Page does not exist on prod

Sewer Camera Inspection special case: Bricks page 8 already lives at flat slug /sewer-camera-inspection/. On May 1 cutover, that flat-slug Bricks page becomes prod content (matches existing Google Ads final URLs). Week 2 post-launch: build SEO variant at /services/sewer/sewer-camera-inspection/ + add 301 flat → nested.

Google Ads Bundled Update (decision 6A — same-day Friday)

5–10 MIN GAQL MUTATE · 11 RSAs

Bundle: 9 RSAs need URL update + 3 RSAs need review-count sync (392+/384+ → "396+") = 11 unique RSAs touched via single GAQL mutate after cutover stabilizes Friday afternoon.

🚫 Do NOT touch paused legacy campaigns (Sewer Repair Kansas City, Sewer, Sewer #2, Russ-era). Only "BSP | Search | … | Mar 2026" campaigns are in scope per MH rule.

📋

May 1 Production Runbook (16 steps)

FRIDAY 8AM CT
[ ]  1. Production backup via Hostinger (full site + DB) — must complete first
[ ]  2. Verify backup integrity (download, sample restore-test on staging)
[ ]  3. Build the 9 new Bricks pages at /services/{category}/{slug}/ on PRODUCTION (DRAFT)
[ ]  4. Build "May 1 Cutover" Category in Rank Math Redirections (11 rules), all DISABLED — NO Redirection-plugin install (B2)
[ ]  5. Build new nested menu (5 parents + 9 children + FREE Camera CTA), nav as-is publicly
[ ]  6. Publish the 9 new Bricks pages
[ ]  7. Run preflight curl: confirm new URLs return 200, old URLs still serve Oxygen
[ ]  8. Bulk-enable "May 1 Cutover" Rank Math Category — all 11 rules go active
[ ]  9. Theme switch Oxygen → Bricks
[ ] 10. Delete old flat menu items (including septic) — nav now shows new nested structure
[ ] 11. Run full redirect verification curl matrix on production
[ ] 12. Run Google Rich Results Test on 3 sample pages
[ ] 13. Submit updated sitemap to Google Search Console
[ ] 14. Bundled GAQL mutate: 9 RSA URL updates + 3 review-count syncs (→"396+")
[ ] 15. Update GMB profile URLs
[ ] 16. Monitor 4 hours: error logs, 404 spikes, ad disapprovals, ranking checks

⏱️ Rollback budget: 30 min · 3-step procedure — theme switch back, redirect group OFF, unpublish new pages. Old menu restored from backup if needed.

🔄

v4 Reset — Full Phase 1 Scope (Apr 27 audit)

RESCOPE

v3 scoped only the 9 service pages. v4 rebuilds with the canonical Apr 18 Audrey scope: 9 service + 15 location + 6 informational = 30 pages Phase 1. Sources verified via the Apr 27 staging audit + content database inventory.

PhasePagesSourceStatus
Phase 1 (May 1)9 service + 15 location + 6 informationalApr 18 design + per-page playbooks + mining systemsSprint runs Mon-Thu
Phase 2 (post-launch)9 NEW service per playbook §4 + Coupons + Careers + blog rebuild1 page/week per playbook §7 cadenceDecision-by-decision
Phase 3 (long-tail)TIER B locations + blog content master rebuildAnything not in Phase 1 or 2No timeline. Defer.

Cross-links to ground-truth audits:

🔧

Slug Restructure — DECIDED Approach 2 (rename at cutover)

✅ APPROACH 2 LOCKED

DECIDED 2026-04-26 by Robert: Approach 2. Bricks staging keeps FLAT slugs through rehearsal. At cutover (Fri May 1 8AM CT), all three changes — slug rename to /services/{category}/{slug}/ per Menu Page Strategy Playbook §6 + Rank Math 301s enabled + theme switch Oxygen→Bricks — fire as a single bundled cutover. Rollback path: Rank Math category bulk-disable + theme revert.

ApproachWhatProCon
1 (RECOMMENDED)Restructure staging this week — rename all flat-slug Bricks staging pages to nested URLsRehearsal validates production-target URL stateExtra restructure work; multiple slug changes during testing
2Slug rename at cutover — keep staging flat, do rename + 301s + theme switch all at onceLess staging work this weekRehearsal validates flat-slug world; real cutover is nested-slug world; Friday surprise risk
3Production-direct — skip staging, do directly on productionMinimal staging workSame risk profile as Approach 2

Locked rationale: Approach 2 saves ~4.5 hrs of Mon-Tue restructure work and reclaims that capacity for the last-mile push layer + 30-page Phase 1 build. Friday-morning slug-rename is a single Bricks UI sweep + Rank Math bulk-enable; rehearsal validates the redirect map + theme switch separately. Three locked rules at cutover:

Two flat-slug exceptions (locked Apr 26):

Water Heaters consolidation (Decision 4a): /water-heaters-installation/ AND /water-heater-repair/ both 301 to /services/water-heaters/water-heater-repair/.

⛏️

Content Pipeline Architecture

DON'T REINVENT

Mining systems already exist — DO NOT rebuild. See Content Database Inventory for full details.

LayerStatusPath
Service-page mining✅ shipped Apr 21/opt/nexus/titan/service_page_reviews_apply.py + Service Page Copy Mining System playbook
Location-page mining✅ shipped Apr 23/opt/nexus/titan/location_page_mining.py · 8 data sources · 9 cities (extend CITY_ZIPS for 6 more)
Bricks element-tree write primitive✅ shipped Apr 22POST /bsp/v3/bricks/native-save
Last-mile push to Bricks meta❌ NOT YET BUILTnexus_populate_service_pages.py + nexus_populate_location_pages.py — wraps mining → native-save

The build target (last-mile layer):

nexus_populate_service_pages.py
  • reads service-page mining brief JSON
  • selects Template A (emergency-style) or B (diagnostic-style) per page
  • generates content blocks per section
  • writes via POST /bsp/v3/bricks/native-save to draft post
  • idempotent · producer-as-verifier · ~6 hrs build

nexus_populate_location_pages.py
  • reads location-page mining brief JSON per city
  • merges into location template (proven on OP 258, 146 elements)
  • writes via native-save · 1 invocation per city · ~6 hrs build

Reference proof: OP 258 page (146 elements, 3 snippets) was built MANUALLY using location mining brief — proving brief→Bricks works end-to-end. The last-mile layer automates that step.

Template A/B routing baked into populate_service_pages.py (Decision 5):

PageTemplateWhy
Sewer RepairA · emergency17.2% conv rate proves emergency frame
Sewer CleaningA · emergencybacked-up sewer = urgent
Drain CleaningA · emergencymid-clog urgency, 24 RSAs
Sump Pump EmergencyA · emergencyactive flood
Leak RepairA · emergencyactive leak — stop-the-water mode
Trenchless Sewer RepairB · diagnostic73K/mo organic = research traffic comparing trenchless vs dig
Water Heater RepairB · diagnostictank/tankless/repair-vs-replace decision tree

Excluded from populate (handled separately): Sewer Camera Inspection (Bricks page 8 already built manually) · Sewer Line Replacement (Phase 2 NEW) · Gas Line Repair (Phase 2).

📅

Sprint Distribution Mon-Thu (capacity math)

CAPACITY MATH
DayFocusHours
Mon Apr 27PARALLEL council dispatch 08:00: populate_service_pages.py (Dispatch A) + populate_location_pages.py (Dispatch B) via council v2 (Strategist+Critic+Researcher+Auditor) · 11:00 native-save smoke test (10 writes) · 13:00 both scripts v1 + CITY_ZIPS extended for 6 TIER B · 17:00 trial run sewer-repair + Playwright verify · GBP location_id fix · pause /lp/drain-cleaning-special/ ads~6 hrs critical path
Tue Apr 28Build populate_location_pages.py · run service-page mining for 9 drafts · Template A/B decision per page · Kalen review batch 1 (service pages)~10 hrs
Wed Apr 29Run location-page mining for 14 cities · publish 9 service pages on prod (DRAFT) · build About + Contact + FAQ + Financing + Reviews · stage Rank Math redirect rules (DISABLED) · Kalen review batch 2~10 hrs
Thu Apr 30 (early)Final QA · Playwright sweeps · Kalen final approval · build nested nav · curl matrix preflight~6 hrs
Fri May 1 8AM CTCutover — backup, publish, redirects-on, theme-switch, monitor~4 hrs

Total Mon-Thu work: ~36 hrs. Last-mile layer build = ~12 hrs. Mining + content placement = ~10 hrs (service pages) + 7 hrs (location pages). Informational pages = 6 hrs. Slug restructure = 4.5 hrs. Kalen review = ~4 hrs across batches. Slack = ~5 hrs.

👀

Kalen Review Dashboard (Decision 7)

✅ DESIGN LOCKED

Build target: /opt/nexus/nexus/scripts/bsp_kalen_review_dashboard.py · FastAPI · ~5 hrs Tue. Routes:

Slack DM mode: when Kalen is away from desk, every page-update auto-posts to a per-slug DM thread (Robert). Kalen's screenshot replies in thread → dashboard pulls thread → red dot on tile. SLACK_BOT_TOKEN reused, NOT #lab (Apr 26 false-positive incident).

Approval gate: cutover_rehearsal.py adds gate 19 — fails closed unless 30/30 APPROVED at Thu 17:00 CT preflight.

🛡️
🛡️
31-Point Blindspot Audit · Mon AM Dispatch Hardening

Dispatcher × Bricks Codebase Doc Integration

Council v2 dispatchers must plug into BSP_Bricks_Codebase_Documentation.html as the canonical Bricks framework reference. Below: what's already wired, what's NEW for May 1, source-precedence chain, 31 blindspots across 5 categories, freshness gate spec.

✅ Already Wired

Council loads protocol_gates.md (curated 2026-04-25 from §1, §7.6, §11, §39) into every agent prompt. Strategist + Critic + Researcher + Auditor all see "CODEBASE PLUG-IN — MANDATORY" instructions to cite specific section IDs. Auditor flags any generic citation as HIGH severity.

🆕 New for May 1 (Mon AM)

Append §6 (page 8 schema · 133 elements) + §13 (Apr 21 Canonical Build SOP — read-first) + §15 (Service Page Build System 4-zone pipeline) + per-page snippet bandaid pattern (CSS Mirror · FAQ · Image Tweaks). Adds freshness gate: cron compares sha256 of doc vs cached.

🔗 Source-Precedence Chain (Component 9 enforces)
BSP_Bricks_Codebase_Documentation.html (LIVE doc, 1.27 MB, 32+ sections) │ ▼ protocol_gates.md (CURATED extract — 7 KB pre-loaded into every prompt) │ ▼ Apr 21 Service Page Mining (§15 canon for service pages) Apr 23 Location Page Mining (8-data-source canon for location pages) │ ▼ COUNCIL DISPATCH (Strategist · Critic · Researcher · Auditor) │ ▼ populate_service_pages.py · populate_location_pages.py (via /bsp/v3/bricks/native-save)
🚨 Category A · Codebase Doc Integration (7 NEW points)
#BlindspotMitigation
A1Council reads STATIC protocol_gates.md, not LIVE Bricks Codebase Doc — drifts as doc updatesSun PM cron: fetch doc, compare sha256, alert on drift; freshness gate in council pre-flight
A2protocol_gates.md curated only §1/§7.6/§11/§39 — missing §6/§13/§15 critical for populate scriptsAppend "May 1 Cutover Addendum" with §6/§13/§15 (this patch ships)
A3§13 Apr 21 protocol lock not enforced: hand-authored Bricks JSON → sanitizer rejects → 404Hard rule in addendum: NEVER hand-author. Use native-save with cloned page-8 trees ONLY
A4§15 4-zone pipeline (A prep · B clone+swap · C verify · D promote) not loaded — risk dispatch skips zonesAuditor checklist: dispatch must explicitly map each step to A/B/C/D zones
A5§6 page-8 schema (133 elements) not loaded — risk dispatcher generates wrong element-tree shapeAddendum loads schema reference; clone-from-page-8 enforced
A6§18 prior snippet conflict audit not loaded — dispatcher could repeat past mistakesAdd to addendum: §18 + §22 (page 157 cycle DO NOT deactivate without extraction)
A7§31/§32 gap+data audits not loaded — repeats existing gapsCron-refresh §31/§32 to /opt/nexus/nexus/scripts/output/bricks_codebase_canon.json weekly
⚙️ Category B · Council Architecture (10 existing points)
#BlindspotMitigation
B1Shared dep: POST /bsp/v3/bricks/native-save (single point of failure)Mon 11:00 smoke test 10/10 writes against staging post 258 (canonical, baseline 146 elements verified Apr 27), rollback after
B2Council token budget doubles when running parallel dispatchesCap $40/dispatch · stop-loss $80 total · dashboard alert at 80% spend
B3Critic ↔ Researcher disagreement deadlockStrategist tiebreaks · escalate to Robert if score < 85 after 2 rounds
B4Auditor false-pass (Gemini-Flash rubber-stamp risk)Independent Playwright check, NOT script self-report (Rule 1)
B5Source-precedence drift between Apr 21 vs Apr 23 mining canonsComponent 9 hard-routes: service→Apr 21, location→Apr 23, schema→Bricks Codebase Doc
B6Conversion-hypothesis floor not enforced for service scriptComponent 10 requires Sewer Repair 17.2% baseline cite for service dispatch
B7Producer-as-verifier collapse (Apr 19 burn pattern)Auditor reads independently via Playwright DOM probe, never trusts script stdout
B8Mining brief schema file missing Mon 08:00 → dispatch failsPre-req task Sun PM: write mining_brief_schema.json + smoke validate
B9Idempotency under crash (script crashes mid-run, leaves partial state)Native-save upsert-by-slug · scripts re-runnable, partial-state-safe
B10Cache-purge timing — verification reads stale cacheLS + CF purge after every write, BEFORE any verification read (Apr 22 rule)
🧱 Category C · Bricks-Specific (6 NEW points)
#BlindspotMitigation
C1Bricks sanitizer rejects unverified element shapes (§13 incident)Clone-from-page-8 only. Reject any generated JSON not derived from a known-good tree
C2Code Snippets PUT endpoint silent-fails at priority 32767 (§28.1)Use DELETE+POST pattern, NEVER PUT for snippets
C3Header 105 + Footer 106 are GLOBAL templates — page-gated CSS bleeds (§14 Apr 21 footer v7 incident)BSP Footer Global #68 unscopes; per-page CSS Mirror re-scopes by body.page-id-N
C4Page 157 cycle snippets — DO NOT deactivate without extraction (§22)Pre-flight cycle-extraction tool; council Auditor flags any deactivate-without-extract dispatch
C5WP Media asset IDs (§6c inventory) — populate scripts must check before writing image refsPull §6c snapshot Sun PM; populate script reads asset IDs from snapshot, fails fast if missing
C6read-child stale cache (§28.1 Apr 24 truncation recovery)Always /bsp/v2/cache/purge BEFORE /bsp/v2/theme/read-child
🔐 Category D · Operational (5 NEW points)
#BlindspotMitigation
D1Bricks UI session timeout (~30 min) — script can lose auth mid-runNative-save uses REST not UI session; refresh token via WP cookie helper Mon 07:55
D2Bricks builder lock — concurrent writes "another user editing"Serialize per-post writes; pre-flight check Bricks lock state via REST
D3LiteSpeed cache + Cloudflare APO — TWO purge layers, must hit bothcf_purge.py + LS purge on every write; both must return success:true
D4Hostinger Apr 14 throttle on rapid REST writes — 10/min ceilingThrottle native-save to ≤6/min; backoff 10s between writes
D5WP REST nonce expiry on long parallel runsRe-auth every 50 writes; council script catches 403 and re-issues nonce
👥 Category E · Stakeholder (3 NEW points)
#BlindspotMitigation
E1Kalen review dashboard /preview/may1/ may need Cloudflare bypass to render iframesAdd CF Access bypass rule for /preview/* before Tue dashboard ship
E2Audrey access to dashboard — login or Slack-only?Slack-only for Audrey (per her hard rules: no Bricks UI, no Confluence). Robert relays if needed
E3Stephanie format on dispatch errors — generic stack traces fail SOPWrap errors in P/I/S/D/N before posting to Slack #lab
🔄 Freshness Gate · Sun PM Pre-flight
# /opt/nexus/nexus/scripts/bricks_codebase_freshness.py
# Sun PM cron + council pre-flight
import hashlib, json, requests
URL = 'https://morpheus.callbrightside.com/documents/BSP_Bricks_Codebase_Documentation.html'
CACHE = '/opt/nexus/nexus/scripts/output/bricks_codebase_canon.json'
live = requests.get(URL, timeout=20).text
live_sha = hashlib.sha256(live.encode()).hexdigest()
cached = json.load(open(CACHE)) if os.path.exists(CACHE) else {}
if cached.get('sha256') != live_sha:
    # DRIFT DETECTED — re-extract §6/§13/§15 + refresh protocol_gates addendum
    extract_and_refresh(live)
    json.dump({'sha256': live_sha, 'last_check': now()}, open(CACHE, 'w'))
    alert_slack('Bricks Codebase Doc drift — protocol_gates refreshed')
📊 Audit Totals
A · 7 NEW
B · 10 EXISTING
C · 6 NEW
D · 5 NEW
E · 3 NEW
TOTAL · 31 (21 NEW)
🔬
🔬
Round 2 · Deeper Pass · 30 NEW · Total now 61

Round 2 Blindspot Audit — Code-level + Migration + Tracking

Going deeper found 3 critical CODE-level gaps in council infrastructure (truncation drop · missing freshness gate · Component 9 has no Bricks-doc tier) plus 27 more across migration · tracking · assets · perf/a11y · forms.

🚨 Critical · Code-Level Gaps Found This Round
#GapStatus
F1protocol_gates.md = 15,165 B but council_runtime.py:651 truncates at 14,000 → §6 page-8 schema + freshness gate spec DROPPEDFIXED: raised to 20,000
F2Component 9 (source_precedence.py) has no tier for BSP_Bricks_Codebase_Documentation.html — only ranks MH chunks by dateFIXED: added BRICKS_DOC_AUTHORITY_SOURCE constant + _authority_tier field. Bricks Codebase Doc chunks now pin to TIER 0 above date-based ranking. Smoke test passes.
F3Auditor empirical-grep (auditor_tools.py:150) — scope unclear; may not grep against Bricks Codebase Doc as evidence corpusFIXED: added BRICKS_DOC_PATH constant + _load_bricks_doc() mtime-cached lazy loader + verify_bricks_section_citation(). audit_dispatch() now extracts every §N citation in dispatch and FLAGs hallucinated sections.
F4Freshness gate was pseudocode in addendum — not actually shipped as runnable cron / pre-flight scriptFIXED: /opt/nexus/nexus/scripts/bricks_codebase_freshness.py shipped (cron-ready · Slack drift alert · cache snapshot)
F5ledger_snippet truncates at 6,000 chars — recent state changes Mon AM may not load if ledger churn is high Sun PM⚠️ ACCEPT — raise on demand if Mon dispatch shows missing recent state
🚀 Category G · Migration Continuity (Oxygen → Bricks · 6 NEW)
#BlindspotMitigation
G1Internal links INSIDE body content of Bricks pages still point at flat slugs (/sewer-repair/) instead of nested (/services/sewer/sewer-repair/)populate scripts run sed-style internal-link rewrite Pass D after content swap; Auditor greps for old-slug instances
G2Yoast meta keys (titles · descriptions) on Oxygen don't auto-migrate to Rank Math meta — different post_meta keysPre-cutover Wed PM: SQL migrate _yoast_wpseo_title → rank_math_title (similar for desc, og:image, canonical) for all 30 pages
G3Schema.org markup — Oxygen's LocalBusiness schema vs Bricks default — coverage gap on service pagesWed PM: deploy Rank Math LocalBusiness schema globally + Service schema per service page; verify via Google Rich Results Test on each
G4Sitemap.xml regen after slug renames — old sitemap may have flat slugs cachedCutover step 10 (post theme switch): GET /wp-json/rank-math/v1/sitemap-clear + force re-crawl via GSC URL Inspection
G5Hardcoded image src paths (uploads/2024/...) in old Oxygen content may not exist in Bricks media libraryMon AM: WP REST GET /media for all attached images per Oxygen page; fail fast if missing in Bricks staging
G6Custom canonical URLs on Oxygen — must replicate on Bricks pre-cutover or risk dup-content flagWed PM SQL audit: SELECT meta_value FROM postmeta WHERE meta_key='_rank_math_canonical_url' for each migrated post; replicate on Bricks staging post
📡 Category H · Tracking + Analytics Continuity (5 NEW)
#BlindspotMitigation
H1GTM container ID — must inject in Bricks header via bricks/render filter (different injection path than Oxygen)Verify GTM-XXXXXX present on Bricks staging /sewer-repair-test/ via DOM inspect Tue PM
H2GA4 event tracking — Oxygen used data-attributes; Bricks default rendering may emit different DOM tree → click tracking breaksRe-test all 12 GA4 custom events on Bricks staging Wed PM (form_submit, phone_click, cta_click, etc.)
H3GCLID capture — landing page JS (Snippet #55 GCLID Bridge v2) must run on Bricks server-rendered page; verify session preservation across slug 301Curl Bricks page with ?gclid=test123 → verify _gcl_aw cookie set + bsp_lead_session POST fires
H4Conversion linker — Google Ads conversion linker must persist GCLID across slug 301 (potential drop on 30x cascade)Test: visit /sewer-repair/?gclid=X → 301 to /services/sewer/sewer-repair/ → cookie still set?
H5Enhanced Conversions for leads — Google Ads form trigger requires Bricks Forms to emit gtag conversion event with hashed PII fieldsTue PM: confirm Bricks Forms wired to GA4 + Google Ads with EC hashed-email; test submit on staging
🖼️ Category I · Asset / Media (4 NEW)
#BlindspotMitigation
I1WP Media library asset IDs differ between staging and prod — populate scripts using ID-references will break on prodpopulate scripts must reference assets by FILENAME or SLUG, not numeric ID; mining brief carries filename
I2Image alt text — populate scripts must inject alt from mining brief, not leave empty (a11y violation + SEO loss)Hard rule in populate_*.py: alt="" is FATAL; mining brief must include alt per image; Auditor flags missing alt
I3Lazy-loading — Bricks default vs Oxygen's loading="lazy" may differ → above-fold images lazy-load → LCP regressionpopulate scripts force loading="eager" on hero image; loading="lazy" on below-fold; Playwright verify LCP < 2.5s
I4Featured image — Yoast/Rank Math og:image often falls back to featured image; Bricks may not auto-setpopulate scripts MUST set _thumbnail_id post_meta for every page; Auditor SELECT meta_value as gate
⚡ Category J · Performance + A11y (5 NEW)
#BlindspotMitigation
J1LCP / CLS shift — Bricks renders different DOM than Oxygen; no current Core Web Vitals baseline measurementTue PM: Lighthouse run on 5 Bricks staging pages; commit baseline; Thu QA gate fails if LCP ≥ 2.5s or CLS ≥ 0.1
J2Render-blocking JS — populate scripts inject snippet JS (FAQ accordion · CSS Mirror · Image Tweaks) — could block renderAll injected snippets MUST use defer or async; Lighthouse render-blocking budget = 0ms
J3Keyboard navigation — Bricks accordion (FAQ snippet) may break tab order or trap focusManual axe-core test on FAQ accordion staging Wed AM; gate Tab-cycle through 5 questions back to button
J4Screen reader compatibility — Bricks dynamic templates may inject role="" defaults that confuse SR (announce nothing)VoiceOver smoke test on /sewer-repair-test/ Wed PM; verify sections announce as landmarks
J5Color contrast — populate scripts swap content into existing template; new copy may break WCAG AA contrast on yellow CTA bgAuditor automated check: every text-on-bg combo run through WCAG AA contrast calc; fail if < 4.5:1 (regular) / 3:1 (large)
📞 Category K · Form / CTA Functionality (5 NEW)
#BlindspotMitigation
K1Bricks Forms vs Oxygen Forms — different field names · submission handlers · validation behaviorTue PM: end-to-end form test on Bricks staging contact form → verify Slack notification + GA4 form_submit event + CRM webhook fires
K2reCAPTCHA keys — staging may use different site_key than prod; cutover Friday must confirm prod keys liveCutover step 11: curl Bricks page → verify g-recaptcha site key matches prod constant; rollback gate if mismatch
K3Email notifications — wp_mail working on Bricks staging? SMTP plugin (WP Mail SMTP / similar) must be activeTue PM: trigger test form submit; verify email received in robert.dove@callbrightside.com inbox within 60s
K4Phone tap-to-call — tel: links must use canonical (913) 963-1029; old content may have stale numberspopulate scripts grep replace any non-canonical phone in content; Auditor regex-fail on any tel:+1[^9]
K5Conversion tracking on form submit — if Bricks Forms uses custom action URL, postback to GA4 may not fireTue PM: confirm Bricks Forms gtag event_name=form_submit fires; if not, add bricks/form/submit hook to inject gtag call
📊 Round 2 Totals · 61 total blindspots across 11 categories
F · Code · 5 (4 FIXED · 1 accept)
G · Migration · 6
H · Tracking · 5
I · Assets · 4
J · Perf/A11y · 5
K · Forms · 5
+ Round 1 = 61 TOTAL · 51 NEW
🏛️
🏛️
Round 3 · Architecture-level · 18 gaps · 4 categories

Round 3 — What Round 1+2 fixes LEAVE OPEN

Round 1+2 patched symptoms (truncation · freshness cron · TIER 0 · § citation grep). Round 3 finds what dispatchers fundamentally cannot see even with F1–F4 fixed. Live BSP_Bricks_Codebase_Documentation.html re-read end-to-end this turn · disk == nginx parity verified · sha=dd8054672d346567.

📦 Tier Shipping Order — Sun PM blockers · Mon AM parallel · Tue/Wed harden · Post-cutover
TierWindowBlindspotsEffortStatus
0Sun PM (must land before Mon 08:00 CT)L1 · N4 · L4~5.5 hrSHIPPED THIS TURN
1Sun PM Apr 26 (shipped before Mon AM)M1 · M2 · N1~6 hrSHIPPED · dispatcher_safety.py · populate_*.py · dispatcher_changelog_hook.py
2Tue PM / Wed AM hardenL2 · L3 · M3 · M4 · O1 · O5 · N2 · N3~17 hr⏳ Schedule slot (TODO_ROBERT)
3Sun PM Apr 26 (dispatcher ship) + Phase 2 (doc-cleanup)O5 · O1 · O2 SHIPPED · O3 · O4 deferred~5 hr shipped · ~7 hr deferred3 SHIPPED · dispatcher_intelligence.py · O3/O4 → Phase 2
📚 Category L · Doc-as-source faithfulness (5 gaps)
#Architecture gapMitigation · PathStatus
L1protocol_gates is CURATED 1.5% excerpt of 1,275,807 B doc — 98.5% invisible to council. Mario slop audit · Theo principles · WP Media inventory · all unreachable.Per-dispatch section extraction at query-time · /opt/nexus/nexus/scripts/bricks_doc_section_loader.py · 32+ sections indexed · scoring by query keyword overlapSHIPPED
L2auditor_tools mtime cache invalidates on bare touch (no content change) AND misses live nginx-disk drift (CDN cache).Cache by sha256 of content + 5-min HEAD ETag/Last-Modified revalidation against URL · Tier 2⏳ Tier 2
L3auditor regex-greps doc as plain text — citations inside <code> or screenshot captions miss. verify_bricks_section_citation currently only matches header pattern.BeautifulSoup parse · structured {section_id: text} dict · O(1) lookup · catches all rendering contexts · Tier 2⏳ Tier 2
L4Apr 17 changelog has structured facts (133/118 element counts · removed brxe-IDs · asset 150-154) — never injected to prompts. Dispatch could cite stale 118 count, Auditor passes (§6 exists).BRICKS_DOC_FACTS extraction → /opt/nexus/nexus/scripts/output/bricks_doc_index.json · Critic injects facts as constraint blockSHIPPED (extraction live · runtime injection Tier 2)
L5§14 Mario / §16 Slop audit are operating principles; council reads as plain text. Critic has no structured anti-slop ruleset.Extract Mario rules → OPERATING_PRINCIPLES constant · Critic agent receives explicit slop pattern list to red-team against · Tier 2⏳ Tier 2 (paired with O5)
⚙️ Category M · Dispatcher process gaps (4)
#Architecture gapMitigation · PathStatus
M1Dispatcher writes to Bricks via REST without reading first. Manual edits since last mining run get blown away. Lost work risk.Mandatory GET /bsp/v2/db/meta-full?post_id=N before any write · diff vs expected · abort if > 5 unexpected elements added · read-patch-write-verify · Tier 1⏳ Tier 1
M2Sanitizer chain (security_check → sanitize_data → save) silently falls back if any stage nukes elements. Snippet 33 line: if (!is_array($current)) $current = $elements restores unsanitized.Dispatcher parses response body · asserts steps array contains security_check:ok AND helpers_sanitize_data:ok · ERR aborts · Tier 1⏳ Tier 1
M3Apr 17 specificity rule (§0): blanket [id^="brxe-"] beats single-id selectors. Generated _cssCustom single-id = silent override loss. Not in agent prompts.Critic CSS-specificity gate · every _cssCustom selector ≥ double-id where blanket exists · Tier 2⏳ Tier 2
M4Apr 17 append rule (§0): desktop @media MUST be appended AFTER mobile @media closes. Edits inside mobile block swallow desktop rules.Structural validator on child-theme CSS edits · only append new @media at end of file · gate pre-flight on any _cssCustom with @media · Tier 2⏳ Tier 2
🔄 Category N · Bidirectional integration (4)
#Architecture gapMitigation · PathStatus
N1Dispatcher actions never write back to doc. Apr 17 changelog hand-written. Mon AM 9 service + 15 location pages ship — no auto-append. Doc stale by Tue.Post-dispatch hook writes id="apr28-changelog" section · element count delta · new asset IDs · new snippets · git commit (doc verified IN GIT this turn) · Tier 1⏳ Tier 1 (git-backed)
N2MH log entries don't reciprocally link from doc. Future dispatches search doc, miss historical fix context.Post-dispatch hook injects "MH cross-reference" footnote into relevant doc section linking bsp-aprNN-{slug} · Tier 2⏳ Tier 2
N3Doc is one HTML file. Mon AM PARALLEL dispatch (services + locations) → both emit changelog → file-level overwrite race · last writer wins.Serialized changelog queue · file lock OR SQLite-backed log table rendered to HTML on 5-min cron · Tier 2⏳ Tier 2
N4F4 freshness check runs Sun 7PM CT cron. Robert hand-edits doc Sun 8PM → 11-hour staleness window before Mon AM dispatch.Pre-flight re-check at council dispatch start · /opt/nexus/nexus/scripts/freshness_preflight.py:check_freshness_now(strict=True) · adds 1-2 sec · eliminates windowSHIPPED
🎯 Category O · Operating-principle integration (5 — the Mario stuff)
#Architecture gapMitigation · PathStatus
O1Theo test ("explain to Kalen in one sentence why each line exists") not enforced on generated code. Council emits CSS · no agent asks justification.Critic agent gate · every emitted CSS rule / PHP snippet / JS gets one-sentence justification field · missing field = dispatch fails · Tier 2⏳ Tier 2
O2§16 self-audit ("67 snippets exist, many predate this session") never read as anti-pattern signal. Adding new snippets without flag = bloat continues.§16 → KNOWN_TECH_DEBT constant · Critic auto-flags any dispatch adding to known debt without explicit Robert override · Tier 3⏳ Tier 3
O3Doc tracks "67 snippets / 48 active" — moving number, never auto-updates. Critic can't accurately flag "adding to or replacing 67?"Post-dispatch hook queries snippet REST · updates doc snippet count line · Tier 3 · <TODO_ROBERT> verify /bsp/v2/db/snippets endpoint exists⏳ Tier 3
O4§12 cleanup candidates flagged but never auto-cleaned. Snippets 41/42/48/52/54 should be deleted post-Audrey-footer-ship · still INACTIVE.Post-dispatch hook cross-references §12 list · surfaces "purge candidates" to weekly Sunday review · don't auto-delete · Tier 3⏳ Tier 3
O5§0 "burned in memory" rules (Apr 17 append · specificity) live as human-readable notes. Council has no constraint mechanism.Regex sweep "burned in memory" / "non-negotiable" / "must be appended AFTER" · build BRICKS_HARD_RULES · Critic enforces · violation = automatic rejection · Tier 2⏳ Tier 2 (paired with L5)
✅ Tier 0 — SHIPPED THIS TURN (Sun PM blocker work · before Mon 08:00 CT)
File · PathFunctionSmoke test
/opt/nexus/nexus/scripts/bricks_doc_section_loader.pyL1 · L4 · section index + BRICKS_DOC_FACTS extractionpython3 bricks_doc_section_loader.py → JSON cache written + facts populated
/opt/nexus/nexus/scripts/freshness_preflight.pyN4 · pre-flight freshness re-check (importable)from freshness_preflight import check_freshness_now · returns (fresh, sha, msg)
/opt/nexus/nexus/scripts/cutover_rehearsal.py+3 gates: step_19 doc parity · step_20 index present · step_21 preflight importable21 gates total (was 18)
✅ Tier 1 + Tier 3 dispatcher — SHIPPED Sun PM Apr 26 (sequential, smoke after each)
GapFile · PathSmoke
M1 · M2/opt/nexus/nexus/scripts/dispatcher_safety.pyread_post_baseline · diff_against_baseline · assert_sanitizer_chain · 4 smoke tests pass · post 258 = 146 elements (matches expected)
M1/opt/nexus/nexus/scripts/populate_service_pages.py7-page dry-run sweep all clear (Template A: 5 · Template B: 2)
M1/opt/nexus/nexus/scripts/populate_location_pages.py15-city dry-run sweep all clear (9 TIER A + 6 TIER B)
N1/opt/nexus/nexus/scripts/dispatcher_changelog_hook.pyappend + idempotency (replace not dup) + file-lock · git commit deferred until repo has initial commit (graceful skip)
O5 · O1 · O2/opt/nexus/nexus/scripts/dispatcher_intelligence.py15 BRICKS_HARD_RULES extracted · 67 snippets/48 active known debt · §16 slop excerpt · Theo test gate language · wired into Critic prompt
+3 gates/opt/nexus/nexus/scripts/cutover_rehearsal.pystep_22 dispatcher_safety · step_23 populate scripts · step_24 dispatcher_intelligence — 24 gates total (was 21)

E2E verified: council dispatch fire shows freshness pre-flight (auto-detected drift, refreshed cache) · protocol gates loaded · Bricks Doc sections injected (3 sections, 9942 chars) · Critic intelligence wired into critic_prompt construction.

📊 Round 1 + 2 + 3 — Cumulative Audit State
Round 1 · 31 (5 cats)
Round 2 · 30 (6 cats · 4 fixed)
Round 3 · 18 (4 cats · 9 fixed)
TOTAL · 79 blindspots · 15 categories · 13 fixed · 6 deferred Wed AM · 4 deferred Phase 2
🚦

Launch-Date Verdict — DECIDED Apr 26

✅ PHASE 1 LOCKED · 30 PAGES · MAY 1

Verdict: ✅ PHASE 1 LOCKED — 30 PAGES SHIP MAY 1

Per Robert 2026-04-26: Phase 1 = full Apr 18 Audrey scope = 9 service + 15 location + 6 informational = 30 pages. No scope cut. No slip. May 1 ship date is final.

Capacity reclaimed by Approach 2: ~4.5 hrs Mon-Tue freed from slug restructure → reallocated to last-mile push layer build + content population.

Mon-Thu execution discipline:

Risk callouts (still HARD): last-mile layer must complete Mon AM or service-page mining can't write through. Location mining pipeline must extend CITY_ZIPS for 6 TIER B cities Tue. Kalen review cadence must hold to schedule — slip Kalen → slip everything.

TODO_ROBERT — ALL RESOLVED Apr 26

0 OPEN · 7 LOCKED

✅ ALL 7 DECISIONS LOCKED 2026-04-26

  1. Slug restructure: Approach 2 — rename at cutover bundled with redirect-on + theme switch
  2. Phase 1 scope: 30 pages (9 service + 15 location + 6 informational) ship May 1 — no scope cut, no slip
  3. /coupons/ on May 1: 301 → homepage. /coupons/ page itself = Phase 2 build (defer)
  4. Septic page (/septic-system/): DELETE on staging (confirmed) — removed from menu, no migrate
  5. Template A/B routing: 5A / 2B vertical pattern-match. A = emergency-style: Sewer Repair · Sewer Cleaning · Drain Cleaning · Sump Pump Emergency · Leak Repair. B = diagnostic-style: Trenchless Sewer Repair · Water Heater Repair
  6. Last-mile build: PARALLEL via council v2 dispatcher Mon 08:00 (Strategist+Critic+Researcher+Auditor+Components 9/10). Critical path 6 hrs (vs 12 sequential). 10-point gap-analysis baked in
  7. Kalen review: Interactive iframe dashboard at /preview/may1/ + Slack DM thread per page. Auto-screenshot desktop+mobile · approve/redline buttons · 30/30 approval gate before cutover

7 of 7 Decisions Locked Apr 26

FULLY LOCKED
1b
/sewer-line-replacement/ → Phase 2 NEW per playbook §7
2b
/gas-line-repair/ → Phase 2
3a
Drain Cleaning → +2nd redirect for /plumbing-services/drain-cleaning/
4a
Water Heaters → 301 BOTH old URLs to new water-heater-repair URL
5c
/lp/drain-cleaning-special/ → pause 53 RSAs immediately + Phase 2 cleanup
6A
RSA bulk-update → same-day Friday afternoon, bundled with cutover (URL + "396+" sync)
7a
functions.php typo → SHIPPED Apr 26 (131,442 → 131,232 corrected, audit-trail note added)
📚

Cross-Linked Documents

CANONICAL CHAIN