title: "Show Launch — Value-First Media Network (one-time activation)" owner: Marquee (Media BU Leader) domain: media risk_tier: 1 verification_rigor: "Tier 1 — Critical Pipeline (production-touching, multi-system, non-recoverable)" version: 1.0 last_updated: 2026-05-06 status: "Operational with mandatory pitfall checks — codifies AOM (2026-04-30) + TRTU (2026-05-05/06) launches"
Show Launch — Value-First Media Network (one-time activation)
Process: End-to-end multi-system activation for a new standalone show in the Value-First Media Network — domain + repo + Vercel project, brand customization, monorepo wiring, Sanity show document, HubSpot Show Listing + Project, launch surfaces, distribution channel resolution, and verification. Owner: Marquee (Media BU Leader) Authoring delegations: Marquee, Squire, Showcase, Canon, Ledger, Marshal, Baldwin, Pixel, Mirror, Curator, Link, Broadcast Last Verified: 2026-05-06 (against TRTU launch end-to-end same week + AOM precedent 2026-04-30) Verification Score: 90% (18 VERIFIED / 20 applicable steps) — Operational Status: Operational First execution: 2026-04-30 (Another Orange Morning, anotherorangemorning.com) Second execution: 2026-05-05/06 (The Road to UNBOUND, theroadtounbound.com) Pattern reference: AOM commit
a7864b994(5P plan + Ledger CAR); TRTU 5P plandocs/plans/the-road-to-unbound-5p-plan.md
Operating Principle
A new (cold-start) session should be able to execute a show launch end-to-end without re-discovering the lessons from AOM or TRTU. Every step has an owning agent, a verification protocol, and an explicit pitfall callout where a prior launch went sideways. Show launches are non-recoverable in the sense that getting the substrate wrong (Vercel account, repo location, schema choices, brand tokens) cascades into rework across every downstream surface — there is no "we'll fix it next episode" for an incorrectly-routed domain or a misnamed Sanity show document.
Distinct from episode-publishing: This procedure covers the one-time activation work to spin up a new show. Per-episode publishing — Riverside-export-to-all-canonical-surfaces — is docs/operating-procedures/episode-publishing.md. The two procedures share an owner (Marquee) and overlap in tooling (Canon, Ledger, Splice, Broadcast) but do not overlap in scope. This procedure terminates when Episode 1 has been launched and the launch project tasks have been closed; episode-publishing takes over from Episode 2 onward.
Operating Principle (cont.) — verification rule
Never claim a step complete on the basis of "should work" reasoning. Every step that writes to a downstream system requires the verify command shown in its Verify with block to be executed and its actual output read. Canon writes specifically must produce a GROQ query result attached to the report, per feedback_canon_verify_after_write.md (3 deviations during TRTU launch). Vercel routing decisions must be verified against reference_vercel_valuefirstagent.md BEFORE the project is provisioned — fixing it after creates a full-project migration (TRTU was misrouted on first attempt, 2026-05-05).
Inputs (what arrives before launch)
The show owner (Chris + Marquee) delivers the following before this procedure begins:
| Input | Format | Notes |
|---|---|---|
| Show concept package | Markdown one-pager + production guide + website brief in /mnt/d/Projects/{show-slug}/ |
TRTU example: one-pager, production-guide-week-1, website-brief, design-brief, brand HTML token sources |
| Brand foundation | HTML/SVG with color tokens, typography spec, do's/don'ts | AOM: Casey's another_orange_morning_v19_unified_footer.svg. TRTU: Brand Foundations.html, Site System.html, P0 Clip Overlays + Thumbnails.html |
| Cast roster | List of host names with HubSpot Contact existence confirmed | AOM: Casey + Chris + rotating Friends. TRTU: Chris, Rob, George, Casey, Kyle (all 5 confirmed in HubSpot before launch) |
| Format decision | Solo / co-host / ensemble + cadence (daily / weekly / event-anchored) | TRTU: weekly ensemble. AOM: daily co-host + Friends |
| Domain decision | Canonical domain name + which Vercel account hosts it | TRTU: theroadtounbound.com on chriscarolan-conveyingyous-projects. AOM: anotherorangemorning.com on unified-support-solutions. Per-property — verify via reference_vercel_valuefirstagent.md |
Agent Ownership Table
| Step | Track | Phase | Agent | Why |
|---|---|---|---|---|
| 1 | A | Source materials | Marquee | BU leader owns brief authorship + revision |
| 2 | A | Brand extraction | Marquee | Reads design system, hands off tokens to Showcase at step 11 |
| 3 | A | Format / cast lock | Human (Chris + show owner) | Editorial decision — never automated |
| 4 | A | Domain account verification | Squire (with Marquee) | Infra provisioning specialist; per reference_vercel_valuefirstagent.md |
| 5 | B | Sanity show document | Canon | Sanity write gateway (mandatory) |
| 6 | B | HubSpot Show Listing | Ledger | HubSpot write gateway (mandatory) |
| 7 | B | HubSpot launch project | Marshal (via Ledger) | Marshal coordinates; Ledger executes the write |
| 8 | B | 5P plan as Listing artifact | Ledger (input from Architect) | Architect drafts the 5P; Ledger persists it as a document_type: plan Listing |
| 9 | C | GitHub repo + Vercel project | Squire | Infrastructure provisioning, NOT Showcase. Per feedback_squire_owns_repo_vercel_setup.md |
| 10 | C | Env vars + first deploy | Squire | Infrastructure provisioning |
| 11 | D | Template clone + brand customization | Showcase | Public-facing site authorship — code, components, copy |
| 12 | D | Sanity client wiring + episode/host queries | Showcase (reads), Canon (any writes) | Site code is Showcase's domain; Sanity writes route through Canon |
| 13 | D | Mirror visual + accessibility QA | Mirror | Playwright-based runtime QA |
| 14 | E | Monorepo wiring (launch metadata, promo route) | Showcase | Public-facing pages on valuefirstteam.com |
| 15 | E | Production materials drop | Marquee | Production-team file set lives under Marquee's BU |
| 16 | E | Launch article (auth-gated) | Baldwin → Canon | Editorial drafting → Sanity publishing |
| 17 | F | LinkedIn channel decision + verification | Marquee with Link | Channel ownership is editorial; Link verifies handle/page status |
| 18 | F | YouTube channel decision + verification | Marquee with Broadcast | Channel ownership is editorial; Broadcast confirms canPublish |
| 19 | F | HubSpot Social Publishing connection check | Broadcast | Channels must be authorized in HubSpot UI before API publish works |
| 20 | G | Episode 1 launch + cross-system audit | Curator + episode-publishing procedure | Hands off to episode-publishing.md |
| 21 | G | Project task closure | Ledger | HubSpot write gateway |
Routing principle (TRTU lesson, 2026-05-05): Squire owns repo + Vercel infrastructure provisioning. Showcase owns site code + brand customization. Conflating them caused a misrouted Vercel account on TRTU's first attempt and required full-project migration. Reference feedback_squire_owns_repo_vercel_setup.md.
Routing principle (TRTU lesson, 2026-05-06): Ledger owns CRM writes, NOT Social Publishing. LinkedIn and YouTube channel verification routes through Marquee + Link/Broadcast, not Ledger. Reference feedback_ledger_not_social_publishing.md.
Procedure
Track A — Source materials, brand, format
Step 1 — Author / revise show brief package (Marquee)
What happens: Marquee authors (or revises if pre-existing) the show concept package in /mnt/d/Projects/{show-slug}/. At minimum: one-pager (identity, hosts, audience, format), production guide (recording cadence, tooling, run-of-show), website brief (site IA, content models, performance budgets). For ensemble shows or shows with mile-marker / segment narrative, add an example episode and a design brief.
Who does it: Marquee
System writes: Local filesystem (/mnt/d/Projects/{show-slug}/)
Trigger: Show approved by Chris (advisory committee decision)
Verify with:
ls -la /mnt/d/Projects/{show-slug}/
# Expected: one-pager, production guide, website brief at minimum
Expected outcome: All source documents present and internally consistent. Tech stack in website brief matches monorepo standard (Astro 5, NOT Next.js). Production guide matches locked recording stack decision (Riverside, apps/media, or other).
Status: VERIFIED 2026-05-05 — TRTU brief package present (one-pager, production guide, website brief, design brief, example episode, brand HTML token sources). Required two revisions (Astro vs Next.js, ensemble vs tiered launch) before substrate work could proceed.
Pitfall: Briefs authored before the launch session locks may carry stale assumptions (TRTU brief originally specified Next.js App Router; AOM Website Build Handoff originally specified Fraunces typography — both wrong). Marquee revises these in the session that approves the launch, BEFORE Showcase reads them at step 11. Otherwise Showcase builds against a stale spec.
Step 2 — Extract brand foundation tokens (Marquee)
What happens: Marquee reads the brand HTML/SVG sources and extracts the canonical token set into a brand-tokens artifact (a markdown file in /mnt/d/Projects/{show-slug}/ is the simplest form). At minimum:
| Category | Tokens to extract |
|---|---|
| Color | Primary palette + neutrals + accent + any gradients (with stops) |
| Typography | Font family, weights, sizes for wordmark / headlines / body |
| Spacing | If the design system specifies a unit scale |
| Visual rules | Don'ts (e.g., AOM: "no gradients on cards, no drop shadows") |
| Iconography / Illustration | Source files for hill silhouettes, sun glow, etc. — paths, not redrawn |
Who does it: Marquee System writes: Local filesystem (brand-tokens artifact in show source dir) Trigger: Step 1 complete; brand source files present
Verify with:
# Brand tokens artifact exists with each category populated
cat /mnt/d/Projects/{show-slug}/brand-tokens.md # or equivalent
Expected outcome: Token set is complete enough that Showcase at step 11 can populate tailwind.config.mjs + CSS variables without re-reading the source HTML/SVG.
Status: VERIFIED 2026-05-06 — TRTU tokens extracted from Brand Foundations.html, Site System.html, P0 Clip Overlays + Thumbnails.html. AOM tokens extracted from Casey's SVG (sunrise gradient stops, hill silhouettes, footer band, cream surface — all present in 5P plan).
Pitfall — typography source-of-truth conflict. AOM's original Website Build Handoff specified Fraunces; Casey's SVG specified Inter. The SVG won (Casey held the line). When the brief and the brand source disagree, the brand source is canonical. Marquee should flag the disagreement to Chris before extraction so the brief gets corrected; do not silently pick the brand source and let the brief drift.
Step 3 — Lock format + cast (Human, with Marquee)
What happens: Show format is locked — solo / co-host / ensemble — and the cast list is finalized. Cadence is locked — daily / weekday / weekly / event-anchored. For ensemble shows, every cast member's HubSpot Contact existence is verified (cast Contact records must already exist; this procedure does NOT create new Contacts).
Who does it: Chris (editorial) + Marquee (verification) System writes: None — humans confirm; this is a decision capture Trigger: Step 1 brief authored
Verify with:
# For each cast member, confirm Contact exists in HubSpot
node scripts/hubspot/api.js search contacts --query "{cast member email}" --limit 1
# Expected: 1 result with the cast member's contact ID
Expected outcome: Format + cadence captured in the 5P plan (step 8). Every cast Contact resolves to a known ID. Format change after this point is a launch decision reversal — costly because it cascades into website brief, production guide, recording stack, episode count.
Status: VERIFIED 2026-05-05 — TRTU locked: weekly ensemble (5 hosts: Chris, Rob, George, Casey, Kyle), Wednesday 10am CT, single ensemble launch episode (NOT four tiered-entrance episodes). All 5 cast Contacts confirmed in HubSpot before substrate work began. AOM locked: daily co-host (Casey + Chris) + rotating Friends, weekday morning 7:15-8:00am CT.
Pitfall: Ensemble launch was originally specified for TRTU as four tiered-entrance episodes; format changed mid-session to single ensemble launch. The change required revising one-pager, production guide, and the 5P plan in parallel. Lock the format BEFORE substrate work begins; format reversal post-substrate forces rework on multiple tracks.
Step 4 — Verify domain + Vercel account routing (Squire with Marquee)
What happens: Squire confirms (a) domain registration status — registered or to-be-registered — and (b) which Vercel account hosts the domain. Per reference_vercel_valuefirstagent.md, two Vercel accounts host VFT properties:
| Account | Slug | Hosts |
|---|---|---|
| Chris Carolan personal | chriscarolan-4469 (account: chriscarolan-conveyingyous-projects) |
valuefirstagent.com, theroadtounbound.com, media, credit-key-app, n2uitive-walkthrough |
unified-support-solutions |
unified-support-solutions |
valuefirstteam.com, clients.valuefirstteam.com, anotherorangemorning.com |
Routing rule: Domain registration determines Vercel account. Do NOT default to "standard VFT Vercel."
Who does it: Squire (CLI verification) with Marquee (decision authority) System writes: None — verification only Trigger: Steps 1-3 complete; domain candidate identified
Verify with:
VERCEL_TOKEN=<token> vercel domains ls --scope chriscarolan-4469
VERCEL_TOKEN=<token> vercel domains ls --scope unified-support-solutions
# Expected: target domain appears under exactly one scope
Expected outcome: Target Vercel account is named explicitly in the launch plan (5P step 8). This is a written commitment, not an assumption.
Status: VERIFIED 2026-05-05 — TRTU theroadtounbound.com confirmed registered on chriscarolan-4469 (Chris confirmed). AOM anotherorangemorning.com confirmed on unified-support-solutions.
Pitfall — the highest-cost TRTU lesson: TRTU was misrouted to unified-support-solutions on first provisioning attempt because of an over-broad reading of "separate Vercel account" framing. The project required full migration to chriscarolan-conveyingyous-projects mid-launch. Verification at this step is mandatory and must be in writing before step 9. Do NOT default to either account; verify per property.
Track B — HubSpot + Sanity substrate
Step 5 — Create Sanity show document (Canon)
What happens: Canon creates the Sanity show document with deterministic ID show-{slug} and these fields:
| Field | Value | Notes |
|---|---|---|
_id |
show-{slug} |
Deterministic; e.g. show-the-road-to-unbound, show-another-orange-morning |
_type |
show |
Sanity schema |
title |
Canonical show name | e.g. "The Road to UNBOUND" |
slug.current |
URL-safe slug | e.g. the-road-to-unbound |
tagline |
Short positioning line | e.g. "21 Wednesdays. Five voices. One road." |
accentColor |
Hex string from brand tokens | e.g. AOM #E8841E |
format |
solo / co-host / ensemble |
From step 3 lock |
frequency |
daily / weekly / event-anchored |
From step 3 lock |
scheduleDays |
Array of weekday names | e.g. ["Wednesday"] (TRTU), ["Mon","Tue","Wed","Thu","Fri"] (AOM) |
scheduleTime |
"HH:MM CT" — Central Time canonical | Per feedback_central_time_canonical.md |
hosts |
Array of references to host Contact-anchored Sanity docs | One ref per cast member |
recurringGuests |
Array of contributor refs (if Friends pattern) | AOM uses this; TRTU doesn't |
Who does it: Canon (Sanity write gateway — mandatory; direct patch.js calls by other agents are governance bypasses)
System writes: Sanity (production dataset, project 0efm0pow)
Trigger: Steps 1-3 complete
Verify with (REQUIRED): Canon must run and return the result of the following GROQ query in its report:
node scripts/sanity/query.js custom "*[_id == 'show-{slug}'][0]{_id, title, 'slug': slug.current, tagline, accentColor, format, frequency, scheduleDays, scheduleTime, 'hostCount': count(hosts), 'recurringGuestCount': count(recurringGuests)}"
Expected outcome: All fields non-null with values matching the spec above. hostCount matches the cast list from step 3. Schedule fields use Central Time.
Status: VERIFIED 2026-05-06 — TRTU show-the-road-to-unbound and AOM show-another-orange-morning both created and queryable. TRTU required Canon correction-cycles for accent color invention and _type mistakes (set to "episode" instead of "siteSettings" on a related write).
Pitfall — Canon verify-after-write protocol (MANDATORY): Per feedback_canon_verify_after_write.md — Canon's "complete" claims have outpaced reality on multiple TRTU launch writes. Every Canon spawn that writes show / episode / siteSettings data MUST include explicit verify GROQ queries Canon executes after each write phase, with the actual results pasted in the report. Never trust _rev alone.
Step 6 — Create HubSpot Show Listing (Ledger)
What happens: Ledger creates the HubSpot Listing record for the show with these properties and associations:
Properties:
| Property | Value | Notes |
|---|---|---|
name |
Canonical show name | e.g. "The Road to UNBOUND" |
listing_content_type |
"series" |
Verified enum value (see skills/hubspot/property-index/listing.json) |
document_authors |
"marquee" |
Marquee owns Media BU listings |
document_review_status |
"published" |
Show Listings publish at creation |
vault_show_url |
Standalone site URL | e.g. https://theroadtounbound.com |
Associations:
| Target | Association | typeId | Category |
|---|---|---|---|
| Each cast Contact | Host_listing (reverse) |
505 | USER_DEFINED |
VF Team Company 49241304942 |
Generic listing-company | 884 | HUBSPOT_DEFINED |
Reference: skills/hubspot/property-index/listing.json for current enum + property values; skills/hubspot/property-index/associations.json for typeId verification.
Who does it: Ledger (HubSpot write gateway — mandatory) System writes: HubSpot (one Listing record + N+1 associations) Trigger: Step 3 complete (need cast list)
Verify with:
node scripts/hubspot/api.js get listings {NEW_SHOW_LISTING_ID} --properties name,listing_content_type,document_authors,document_review_status,vault_show_url
node scripts/hubspot/api.js list-assoc listings {NEW_SHOW_LISTING_ID} contacts
node scripts/hubspot/api.js list-assoc listings {NEW_SHOW_LISTING_ID} companies
Expected outcome: All properties match spec. Contact associations match every cast member from step 3. Company association = 49241304942.
Status: VERIFIED 2026-05-06 — TRTU Show Listing 553728205744 created with 5 host associations + VF Team Company. AOM Show Listing created with Casey + Chris + Friends-pattern.
Pitfall: Use the Host_listing USER_DEFINED association (typeId 505 reverse) for cast members — NOT the generic HUBSPOT_DEFINED contact-listing association. Pass --category USER_DEFINED explicitly to api.js associate for typeId 505 — the default is HUBSPOT_DEFINED and the API returns a misleading "wrong object type" error if you mismatch typeId and category (per wiki/conventions.md § HubSpot data conventions).
Step 7 — Create HubSpot launch project (Marshal via Ledger)
What happens: Marshal coordinates creation of a HubSpot Project on pipeline 888442804 (Agent Operations) for the launch. Ledger executes the write. The project tracks every Process step from this procedure as a Task; tasks complete as steps verify.
Properties:
| Property | Value | Notes |
|---|---|---|
hs_project_name |
"{Show name} — Launch" |
e.g. "The Road to UNBOUND — Launch" |
hs_pipeline |
888442804 |
Agent Operations pipeline |
hs_pipeline_stage |
In Progress |
Stage ID per skills/hubspot/property-index/project.json |
hubspot_owner_id |
Marquee owner mapping | Per VF team owner index |
Associations:
| Target | Association |
|---|---|
| Show Listing from step 6 | Generic project-listing |
VF Team Company 49241304942 |
Generic project-company |
Who does it: Marshal (coordination); Ledger (write execution) System writes: HubSpot (one Project record + 2 associations + N Tasks) Trigger: Step 6 complete
Verify with:
node scripts/hubspot/api.js get projects {NEW_PROJECT_ID} --properties hs_project_name,hs_pipeline,hs_pipeline_stage
node scripts/hubspot/api.js list-assoc projects {NEW_PROJECT_ID} listings
node scripts/hubspot/api.js list-assoc projects {NEW_PROJECT_ID} tasks
Expected outcome: Project exists with all properties and associations. Task list reflects the Process steps from this procedure (typically 15-22 tasks).
Status: VERIFIED 2026-05-06 — TRTU launch project 553725586736 created on pipeline 888442804 with task list reflecting 22-step 5P process; AOM launch project precedent established 2026-04-30.
Pitfall: Marshal coordinates, Marshal does not judge (per wiki/agent-guide.md). When task generation requires domain knowledge (e.g., "what counts as 'site complete'?"), Marshal must spawn the owning agent (Marquee for editorial scope, Showcase for technical scope) rather than guessing.
Step 8 — Persist 5P plan as Listing artifact (Ledger; input from Architect)
What happens: The launch 5P plan (drafted by Architect at the launch dispatch) is persisted to HubSpot as a Listing artifact for queryable launch documentation. Optionally also published as a Google Doc for human review.
Properties:
| Property | Value | Notes |
|---|---|---|
name |
"{Show name} — 5P Plan" |
|
listing_content_type |
"document" |
|
document_type |
"plan" |
Verified enum value |
document_authors |
"marquee, architect" |
|
document_review_status |
"published" |
|
hs_body |
Full 5P plan markdown |
Associations: Show Listing (step 6), Launch Project (step 7), VF Team Company.
Who does it: Ledger (write); Architect drafted the source markdown
System writes: HubSpot
Trigger: Step 7 complete; 5P plan written to docs/plans/{show-slug}-5p-plan.md
Verify with:
node scripts/hubspot/api.js get listings {5P_LISTING_ID} --properties name,listing_content_type,document_type
node scripts/hubspot/api.js list-assoc listings {5P_LISTING_ID} listings
node scripts/hubspot/api.js list-assoc listings {5P_LISTING_ID} projects
Expected outcome: 5P Listing exists with document_type: plan, associated to Show Listing + Launch Project.
Status: VERIFIED 2026-05-06 — TRTU 5P plan persisted as Listing artifact; AOM 5P plan persisted via commit a7864b994 (precedent).
Pitfall: Do NOT persist the 5P as a Note engagement — Notes have a ~65k character ceiling and lack the document_type semantic that makes "show me every plan" queryable. Listings with listing_content_type: document + document_type: plan is the canonical pattern.
Track C — Repository + hosting infrastructure
Step 9 — Provision GitHub repo + Vercel project (Squire)
What happens: Squire creates the GitHub repository and provisions the Vercel project. Order of operations:
- Clone the canonical AOM template into
/mnt/d/Projects/{show-slug}/(template is the AOM standalone Astro site). - Strip AOM-specific artifacts (logo files, copy, episode references that bleed in).
- Initial commit with a clean baseline.
gh repo create Value-First-Team/{slug} --private --source=. --pushvercel link --scope={vercel-account-slug-from-step-4}— explicit scope, never the implicit default.vercel project addif needed; otherwise the link picks up the existing-or-new project per the account.
Who does it: Squire (infrastructure provisioning specialist; per feedback_squire_owns_repo_vercel_setup.md, NOT Showcase)
System writes: GitHub (new repo); Vercel (new project)
Trigger: Step 4 complete (Vercel account verified)
Verify with:
gh repo view Value-First-Team/{slug} --json url,visibility,defaultBranchRef
VERCEL_TOKEN=<token> vercel project ls --scope {account-slug} | grep {slug}
Expected outcome: Repo exists, private, default branch main with initial commit. Vercel project exists under the correct account scope.
Status: VERIFIED 2026-05-06 — TRTU Value-First-Team/the-road-to-unbound on chriscarolan-conveyingyous-projects after migration. AOM Value-First-Team/another-orange-morning on unified-support-solutions.
Pitfall (the TRTU lesson): Showcase does NOT do this step. Squire owns repo + Vercel infrastructure provisioning; Showcase owns site code + brand customization. Conflation caused the TRTU misrouting. Even when Showcase has access, the routing convention says Squire. Reference feedback_squire_owns_repo_vercel_setup.md.
Step 10 — Configure env vars + first deploy (Squire)
What happens: Squire configures the env vars on Vercel for Sanity reads (and any other integrations the standalone site needs):
| Variable | Purpose | Where it comes from |
|---|---|---|
SANITY_PROJECT_ID |
0efm0pow |
Constant (VFT Sanity project) |
SANITY_DATASET |
production |
Constant |
SANITY_API_TOKEN |
Sanity read token | From apps/website/.env (read scope sufficient for standalone sites) |
PUBLIC_SITE_URL |
Canonical domain | From step 4 |
Then domain attachment: vercel domains add {domain} --scope {account-slug} and vercel alias set if the auto-alias doesn't catch.
Who does it: Squire System writes: Vercel (env vars, domain mapping) Trigger: Step 9 complete
Verify with:
VERCEL_TOKEN=<token> vercel env ls --scope {account-slug} {project-name}
VERCEL_TOKEN=<token> vercel domains inspect {domain} --scope {account-slug}
curl -sI https://{domain} | head -3
Expected outcome: Env vars listed for production environment. Domain shows as attached. First deploy returns HTTP 200 (or 308 redirect to www if www-canonical pattern).
Status: VERIFIED 2026-05-06 — TRTU env vars + domain confirmed; AOM env vars + domain confirmed.
Pitfall — apex → www 307/308 redirect. Some VFT properties redirect bare apex to www. subdomain (e.g., valuefirstteam.com → www.valuefirstteam.com). Any URL audit (Mirror at step 13, Lookout, manual curl) MUST follow redirects (curl -L / Playwright page.goto) to avoid false-positive 404 reports. Standalone show sites typically serve the apex directly — verify the redirect behavior before adding to monitoring.
Track D — Site customization
Step 11 — Clone AOM template + customize branding (Showcase)
What happens: Showcase customizes the AOM-template-based standalone site:
- Tailwind config + CSS variables — Pull color tokens, font families, spacing units from step 2 brand-tokens artifact. Every brand value lives in
tailwind.config.mjs+ CSS variables — NEVER hardcoded in components. - Wordmark + logo — From brand source SVG/HTML; do not redraw, copy paths.
- Component customization — Hero, HostCard, EpisodeCard, MileMarker (or show-specific equivalent), SlipCounter (or show-specific equivalent), Countdown (if event-anchored — TRTU has UNBOUND 2026; AOM does not).
- Show-specific component scoping — All bespoke components live under
src/components/show-specific/(or named-show subfolder), NOT globalui/.
Who does it: Showcase (public-facing site authorship) System writes: Local repo + git push (triggering Vercel deploy) Trigger: Steps 9-10 complete; step 2 brand tokens available
Verify with:
# After build + deploy, check brand tokens are not hardcoded:
grep -rn "#E8841E\|#F7C03A" /mnt/d/Projects/{show-slug}/src --include="*.tsx" --include="*.astro" --include="*.ts"
# Expected: zero hits in component code; all references go through Tailwind tokens or CSS variables
Expected outcome: Site renders with brand-faithful styling. No hardcoded brand colors in component code (greppable). Tailwind config is the single source of truth.
Status: VERIFIED 2026-05-06 — TRTU site at https://theroadtounbound.com renders with Brand Foundations tokens cleanly. AOM site at https://anotherorangemorning.com renders with Casey's SVG-derived sunrise gradient.
Pitfall — global a:hover { color: primary } collapse pattern. A blanket a:hover { color: var(--brand-primary) } rule has specificity 1 and overrides per-element Tailwind hover: utilities, causing color-on-color collisions (e.g., a brand-colored link on a brand-colored card section becomes invisible on hover). Apply via :where(a):hover to drop specificity to 0, so per-element utilities can override. Discovered during AOM hover audits.
Step 12 — Build full page set + Sanity wiring (Showcase)
What happens: Showcase builds the canonical page set and wires Sanity queries for show + episode + host data:
| Route | Purpose | Sanity queries |
|---|---|---|
/ (Home) |
Hero + value prop + recent episodes + cast strip + Subscribe CTA | *[_type == "show" && slug.current == "{slug}"][0], recent episodes |
/episodes |
Episode index | *[_type == "episode" && show._ref == "show-{slug}"] ordered by publishedAt |
/episodes/[slug] |
Single episode page | Episode + transcript (PortableText) + Mux player + clips |
/clips |
Clips library (if format produces clips) | *[_type == "clip" && episode->show._ref == "show-{slug}"] |
/cast |
Host roster | All hosts with portrait + bio + accent |
/about |
Long-form show description | Show document body field |
/subscribe |
Distribution channel CTAs | Subscribe links from siteSettings.socialLinks |
Hard requirements (per AOM + TRTU launches):
- Skip-link —
<a href="#main" class="skip-link">Skip to content</a>as first focusable element on every page (WCAG AA) - JSON-LD schema —
Schema.org PodcastSeries(orVideoSeries) on Home,Schema.org PodcastEpisode(orVideoObject) on episode pages - Mobile responsive — Renders correctly at 375px and 768px viewports
- 44px tap targets — All interactive elements meet WCAG 2.5.5 Target Size minimum
- Hover state scoping — Per step 11 pitfall
Who does it: Showcase System writes: Local repo + Vercel deploy Trigger: Step 11 complete
Verify with:
for route in "/" "/episodes" "/cast" "/about" "/subscribe"; do
echo "$route: $(curl -sL -o /dev/null -w '%{http_code}' https://{domain}$route)"
done
# Expected: all return 200
Expected outcome: Every canonical route returns 200. Skip-link present in HTML source. JSON-LD blocks parse as valid schema. Mobile viewports render without horizontal overflow.
Status: VERIFIED 2026-05-06 — TRTU page set deployed and all routes 200. AOM page set deployed.
Pitfall — Sanity Mux schema bridge. The standalone-site episode template queries episode.muxVideo.asset-> (nested ref to mux.videoAsset doc), NOT flat muxAssetId strings. When the show launches without Episode 1 in place, the episode template renders without a player — fine. When Episode 1 is published, the bridge MUST exist (Splice + Canon two-step write). If skipped, the player renders as empty <mux-player> with no playbackId. See episode-publishing.md § Step 7 for the full bridge spec — this pitfall surfaces during the first episode launch.
Step 13 — Mirror visual + accessibility QA (Mirror)
What happens: Mirror runs a Playwright-based QA pass against the deployed site:
- Visual QA per route — Screenshot every canonical route at 375px, 768px, 1280px viewports
- Brand consistency — Confirm wordmark renders, accent color appears in CTAs, no color-on-color collisions
- Accessibility — axe-core scan; zero critical violations; skip-link works; 44px tap targets; keyboard navigation completes
- JSON-LD schema validation — Parse JSON-LD blocks; confirm
Schema.orgtypes resolve - Performance budgets — Lighthouse: Performance ≥ 95, Accessibility ≥ 95, Best Practices ≥ 95, SEO ≥ 95; LCP < 2.0s, CLS < 0.05, TBT < 200ms (per AOM + TRTU 5P standards)
Who does it: Mirror (visual QA + Playwright) System writes: None (read-only) Trigger: Step 12 complete
Verify with:
# Mirror Playwright report attached as evidence
# Includes: Lighthouse scores, axe violation count, per-viewport screenshots
Expected outcome: Lighthouse scores all ≥ 95. Zero critical axe violations. Mobile viewports render without horizontal scroll. Brand tokens consistent across routes.
Status: VERIFIED 2026-05-06 — TRTU Mirror pass ran post-launch with all four Lighthouse scores ≥ 95 and zero critical axe violations. AOM Mirror pass ran post-launch.
Pitfall — fallback rendering is a failure. Per wiki/conventions.md § Engineering standards: if any element renders via a fallback path (Mux player → HubSpot CDN <video> fallback, Sanity-fetched copy → hardcoded fallback string, image → broken-image placeholder), do NOT celebrate. Investigate the primary path failure and fix it. Mirror flags fallback rendering as a defect, not a pass.
Track E — Monorepo wiring + production materials
Step 14 — Wire monorepo show pages (Showcase)
What happens: Showcase wires the show into the monorepo at the following surfaces:
apps/website/src/components/show-promo/launch-metadata.ts— Add an entry toSHOW_LAUNCH_METADATA:'{slug}': { pageTitle: '{Show Name} — Launch Materials', pageDescription: '...', ogImage: 'https://www.valuefirstteam.com/og/media/shows/{slug}.png', }apps/website/src/pages/media/shows/{slug}/index.astro— Public show landing page on valuefirstteam.com. May rely on dynamic[slug].astroif monorepo has one — verify before creating duplicates.apps/website/src/pages/my-value-path/shows/{slug}/promo.astro— Auth-gated launch surface. This is the ONLY launch page; do NOT create a public/launchroute.apps/website/src/content-static/show-launches/{slug}/launch-article.md— Baldwin authors at step 16; the directory is created here.
Who does it: Showcase (public-facing pages on valuefirstteam.com) System writes: Local repo + git push Trigger: Step 5 complete (Sanity show document exists for queries)
Verify with:
curl -sI https://www.valuefirstteam.com/media/shows/{slug} | head -3
# Expected: 200 (after deploy)
# /my-value-path/shows/{slug}/promo: requires auth, expect 200 with auth or 302 redirect to /my-value-path/login
Expected outcome: Public /media/shows/{slug} route returns 200. Auth-gated /my-value-path/shows/{slug}/promo exists. launch-metadata.ts has the new entry.
Status: VERIFIED 2026-05-06 — TRTU entries present in launch-metadata.ts; AOM entries present (precedent).
Pitfall — no public launch pages. Per Chris's directive 2026-05-06: launch materials live ONLY on auth-gated /my-value-path/shows/{slug}/promo. Do NOT create /launch routes on either the standalone site or valuefirstteam.com. TRTU and AOM both had public launch pages removed after this directive. The launch article (step 16) is part of the auth-gated surface, not a public destination.
Step 15 — Drop production materials into clients/vf-team (Marquee)
What happens: Marquee populates clients/vf-team/content/media_network/{Show_Folder}/ with the production materials drop:
| File | Source | Notes |
|---|---|---|
{Show}_Show_Guide.md |
From step 1 brief package | Identity, hosts, philosophy, distribution |
{Show}_Show_Template.md |
From step 1 brief package | Run-of-show, segments, transitions |
{Show}_Production_Guide.md |
From step 1 brief package | Recording cadence, tooling, checklists |
{Show}_Daily_Recap_Framework.md (or weekly) |
From step 1 brief package | Structure for recap article + LinkedIn post |
{Show}_Post-Show_Process_Checklists.md |
From step 1 brief package | Bare minimum + ideal post-broadcast workflows |
{Show}_Friends_Lineup_Framework.md (if applicable) |
From step 1 brief package | Recruitment + onboarding for rotating cast |
{Show}_Custom_Instructions.md (if AI producer involved) |
From step 1 brief package | AI producer role + knowledge file index |
Who does it: Marquee (BU file census) System writes: Local filesystem Trigger: Step 1 complete
Verify with:
ls /mnt/d/Projects/value-first-operations/clients/vf-team/content/media_network/{Show_Folder}/
# Expected: full file set per spec above (mirroring AOM/TRTU folder structure)
Expected outcome: Folder exists with the canonical file set. AOM Another_Morning_Show/ and TRTU The_Road_to_UNBOUND/ are reference structures.
Status: VERIFIED 2026-05-06 — TRTU The_Road_to_UNBOUND/ populated; AOM Another_Morning_Show/ populated (precedent).
Pitfall: This step is bare-minimum file presence. The internal correctness of each document — production checklists matching locked stack, recap framework matching cast voice — is not verified by file existence. Marquee should review each document for stale assumptions inherited from the brief authoring step.
Step 16 — Author launch article (Baldwin → Canon)
What happens: Baldwin authors the show launch article — editorial framing of the show (origin story, what it solves, who it's for, where to find it). Canon publishes the resulting Sanity document.
Sanity document spec:
| Field | Value |
|---|---|
_id |
launch-article-{slug} (deterministic) |
_type |
launchArticle (or whatever schema the show uses; verify) |
title |
Editorial title |
slug.current |
URL slug |
body (PortableText) |
Long-form article — origin, format, cast, where-to-find |
show |
ref to show document from step 5 |
Also write static markdown to apps/website/src/content-static/show-launches/{slug}/launch-article.md for the auth-gated promo route to render.
Who does it: Baldwin (rich media-embedded article writer) → Canon (Sanity write gateway) System writes: Sanity (one document); local repo (one markdown file) Trigger: Step 5 (show doc) + step 14 (auth-gated promo route exists) complete
Verify with:
node scripts/sanity/query.js custom "*[_id == 'launch-article-{slug}'][0]{_id, title, 'slug': slug.current, 'showRef': show._ref, 'bodyBlockCount': count(body)}"
ls /mnt/d/Projects/value-first-operations/apps/website/src/content-static/show-launches/{slug}/launch-article.md
Expected outcome: Sanity document exists with show reference. Static markdown exists at the canonical path. Promo route renders article.
Status: VERIFIED 2026-05-06 — TRTU launch article published; AOM launch article published (precedent).
Pitfall: Baldwin's articles must be grounded in the source materials per feedback_ground_deliverables_in_transcripts.md — origin story should reference actual conversations or 5P plan content, not invented narrative. Pulling content from a previous show's launch article (template-fill) produces a generic article that fails the "first-time visitor understands what the show is in under 15 seconds" test from the 5P performance criteria.
Track F — Distribution surfaces
Step 17 — Lock LinkedIn channel decision (Marquee with Link)
What happens: Marquee decides which LinkedIn channel broadcasts launch posts and live broadcasts (if applicable). Options:
| Channel | When to use |
|---|---|
| Personal page of named host | Show is anchored to a personal brand (TRTU: chris-carolan) |
| VFT Company Page | Show is firm-anchored, not personality-anchored (AOM: VFT Company Page for daily morning show) |
| Co-host personal pages (cross-post) | Ensemble shows where multiple hosts amplify |
Link verifies the candidate channel is connected with publish permission. Marquee captures the decision in writing in the launch project + siteSettings.socialLinks on Sanity.
Who does it: Marquee (decision); Link (channel verification)
System writes: Sanity siteSettings.linkedinUrl via Canon
Trigger: Steps 5-7 complete
Verify with:
node scripts/hubspot/api.js list channels # or equivalent — confirm channel connected with canPublish: true
node scripts/sanity/query.js custom "*[_id == 'siteSettings-{slug}'][0]{linkedinUrl}"
Expected outcome: Named channel resolves and is publish-capable. siteSettings.linkedinUrl matches.
Status: VERIFIED 2026-05-06 — TRTU locked to chris-carolan (personal, channelGuid b2cb0238-cfe8-3c81-9516-6dfe65934802); AOM locked to VFT Company Page.
Pitfall — post-schedule.js was channel-locked. Until commit 84a100bd4 (2026-05-06), scripts/hubspot/post-schedule.js was hardcoded to the VFT Company Page. Marquee's TRTU launch required extending the script with a --channel flag to support personal channels. If a new show targets a channel not yet supported, the script extension is a prerequisite, not a follow-up — file this as a Squire task at substrate phase, not at first-publish phase.
Step 18 — Lock YouTube channel decision (Marquee with Broadcast)
What happens: Marquee decides which YouTube channel hosts the show archive. Default for VFT shows is @Value-First (channel GUID 7e68d7bf-96a1-3c55-9930-c954661fcb6f). Broadcast confirms canPublish: true on the target channel.
Who does it: Marquee (decision); Broadcast (channel verification)
System writes: Sanity siteSettings.youtubeUrl via Canon
Trigger: Step 17 complete (or in parallel)
Verify with:
# Broadcast confirms via HubSpot Social Publishing channel list (see step 19)
node scripts/sanity/query.js custom "*[_id == 'siteSettings-{slug}'][0]{youtubeUrl}"
Expected outcome: Named channel confirmed publish-capable. siteSettings.youtubeUrl matches.
Status: VERIFIED 2026-05-06 — TRTU + AOM both archive on @Value-First (per reference_trtu_broadcasting.md).
Pitfall: youtube-publish.ts --privacy public lowercase is rejected — HubSpot API requires uppercase PUBLIC. Best practice: omit the --privacy flag entirely (defaults to public via HubSpot). Squire fix recommended: align lowercase default with API-required uppercase, or document the omit-the-flag pattern in script help text. This pitfall surfaces at first episode publish, not at show launch — but the show-launch session should flag it for Squire so it's fixed before Episode 1.
Step 19 — Verify HubSpot Social Publishing connection (Broadcast)
What happens: Broadcast confirms that BOTH the LinkedIn channel from step 17 AND the YouTube channel from step 18 are authorized in HubSpot's Social Publishing UI (Marketing → Social → Channels) — not just connected at the platform level. The HubSpot UI authorization is a one-time per-channel setup that the API surface depends on.
Who does it: Broadcast System writes: None (verification only) Trigger: Steps 17-18 complete
Verify with:
# Confirm via HubSpot Marketing > Social > Channels UI:
# - LinkedIn channel from step 17 listed and "Connected"
# - YouTube channel from step 18 listed and "Connected"
# Then test API access:
node scripts/hubspot/post-schedule.js --channel {channel-slug} --dry-run # if --dry-run supported
# OR send a single test post and immediately delete
Expected outcome: Both channels show as connected in HubSpot Social UI. API call returns successful authentication (not 401/403).
Status: VERIFIED 2026-05-06 — TRTU chris-carolan LinkedIn + @Value-First YouTube both confirmed connected with publish permission via successful test publishes during Episode 1 launch.
Pitfall — Ledger ≠ Social Publishing. Per feedback_ledger_not_social_publishing.md — HubSpot's Social Publishing API surface is distinct from CRM and is owned by Broadcast, NOT Ledger. It is tempting to route "anything writing to HubSpot" to Ledger; do not. Ledger writes ABOUT the publish (Note engagements with published-post URLs) AFTER the publish; Broadcast DOES the publish. This routing distinction matters at every episode publish — locking it at show-launch time prevents recurring confusion.
Track G — Verification + closure
Step 20 — Episode 1 launch + cross-system audit (Curator + episode-publishing handoff)
What happens: With substrate, site, and distribution surfaces all in place, the launch is "ready" — but the launch is not complete until Episode 1 publishes successfully. Episode 1 publish executes per docs/operating-procedures/episode-publishing.md; this step terminates show-launch by handing off to that procedure and closing the loop with a Curator cross-system audit immediately after Episode 1 lands on every surface.
Curator audit scope (post-Episode-1):
| System | Check |
|---|---|
| Sanity | show + episode + (recap if applicable) documents exist with correct refs |
| HubSpot | Show Listing + Launch Project + Episode Listing + Note engagement + file association all exist |
| Standalone site | https://{domain}/episodes/{slug} returns 200 with player + transcript |
| Monorepo | https://www.valuefirstteam.com/media/shows/{slug} returns 200 |
| YouTube | Episode 1 video exists on target channel with canonical title |
| Episode 1 launch post exists on target channel |
Who does it: Curator (cross-system audit, read-only); episode-publishing procedure owns Episode 1 mechanics System writes: None (Curator); per episode-publishing for the publish itself Trigger: Steps 1-19 complete; Episode 1 recorded
Verify with:
# Curator one-shot audit prompt:
# "Audit show {slug} launch consistency: Sanity show {ID} + episode {ID}, HubSpot Show Listing {ID} + Project {ID} + Episode Listing {ID}, standalone site /, /episodes/{slug}, monorepo /media/shows/{slug}, YouTube {URL}, LinkedIn post URL. Report any drift."
Expected outcome: Curator returns clean report (all surfaces consistent, zero drift) OR specific drift findings routed to the appropriate gateway (Canon for Sanity drift, Ledger for HubSpot drift, Showcase for site drift).
Status: VERIFIED 2026-05-06 — TRTU Episode 1 ("First Ride") launched and Curator post-launch audit ran clean (per episode-publishing procedure verification). AOM Episode 1 launched 2026-04-30.
Pitfall: Curator is read-only. If drift is found, the fix routes through the appropriate gateway. Do not attempt to fix drift inside Curator's session. Match removal scope precisely if any surfaces need rollback (per wiki/agent-guide.md § Removal operations) — over-correction at launch closure is indistinguishable from a destructive bug.
Step 21 — Close launch project tasks (Ledger)
What happens: Ledger marks the Process tasks COMPLETED on the Launch Project from step 7. Project itself transitions to a closed/completed pipeline stage.
Who does it: Ledger System writes: HubSpot (N Task status updates + 1 Project stage update) Trigger: Step 20 complete
Verify with:
node scripts/hubspot/api.js list-assoc projects {LAUNCH_PROJECT_ID} tasks --properties hs_task_subject,hs_task_status
node scripts/hubspot/api.js get projects {LAUNCH_PROJECT_ID} --properties hs_pipeline_stage
Expected outcome: All launch tasks hs_task_status: "COMPLETED". Project pipeline stage moved to completed/closed (per pipeline 888442804 stage IDs).
Status: VERIFIED 2026-05-06 — TRTU launch project tasks closed after Episode 1 publish + Curator audit; AOM launch project closed 2026-04-30.
Pitfall: Match removal scope precisely (per wiki/agent-guide.md § Removal operations). Do not auto-close adjacent items "while you're there" — close only the tasks tied to this launch. Recurring/operational tasks (e.g., "Weekly episode publish") that may have been created on the launch project belong on a separate ongoing project; do not close them as part of launch closure.
Verification Score Summary
| Step | Status | Track |
|---|---|---|
| 1 — Source materials | VERIFIED | A |
| 2 — Brand extraction | VERIFIED | A |
| 3 — Format / cast lock | VERIFIED | A |
| 4 — Vercel account verification | VERIFIED | A |
| 5 — Sanity show document | VERIFIED | B |
| 6 — HubSpot Show Listing | VERIFIED | B |
| 7 — HubSpot launch project | VERIFIED | B |
| 8 — 5P plan as Listing | VERIFIED | B |
| 9 — GitHub repo + Vercel project | VERIFIED | C |
| 10 — Env vars + first deploy | VERIFIED | C |
| 11 — Brand customization | VERIFIED | D |
| 12 — Page set + Sanity wiring | VERIFIED | D |
| 13 — Mirror visual + a11y QA | VERIFIED | D |
| 14 — Monorepo wiring | VERIFIED | E |
| 15 — Production materials drop | VERIFIED | E |
| 16 — Launch article | VERIFIED | E |
| 17 — LinkedIn channel decision | VERIFIED | F |
| 18 — YouTube channel decision | VERIFIED | F |
| 19 — Social Publishing connection check | VERIFIED | F |
| 20 — Episode 1 + Curator audit | UNTESTED | G |
| 21 — Project task closure | VERIFIED | G |
Score: 18 VERIFIED / 20 applicable steps (Step 20 marked UNTESTED at the audit-of-launches level — per-show audit ran clean for TRTU and AOM; treating the cross-launch generalization as UNTESTED until Show 3 launch validates the procedure's reusability) = 90% Operational (well above the 80% threshold required to describe a process as operational, per docs/quality/verification-protocol.md).
Decay window: Tier 1 (Critical) = 90 days. Re-verify by 2026-08-04 OR after the next show launch (whichever is sooner). Code changes to launch-metadata.ts, the AOM-template baseline, the Vercel routing memory file, the post-schedule.js script, or any HubSpot property index entry referenced here decay all VERIFIED markers immediately.
Critical Pitfalls — Quick Reference
For a cold-start launch session, these are the lessons from AOM + TRTU to internalize before executing:
Vercel account routing is per-property. Domain registration determines account. TRTU was misrouted to
unified-support-solutionson first attempt and required full migration. Verify viareference_vercel_valuefirstagent.mdBEFORE step 9. Two accounts host VFT properties:chriscarolan-conveyingyous-projects(TRTU, valuefirstagent, media) andunified-support-solutions(valuefirstteam, portal, AOM).Squire ≠ Showcase. Squire owns repo + Vercel infrastructure provisioning. Showcase owns site code + brand customization. Conflation caused the TRTU misrouting. Per
feedback_squire_owns_repo_vercel_setup.md.Sanity Mux schema bridge. Episode template queries
episode.muxVideo.asset->(nested ref tomux.videoAssetdoc), NOT flatmuxAssetIdstrings. Show launch terminates with the substrate ready for this — but the bridge itself is wired at first episode publish. Seeepisode-publishing.md § Step 7.Canon's "complete" reports outpace reality. Per
feedback_canon_verify_after_write.md: every Canon spawn requires per-write GROQ verify queries with results pasted in the report. Never trust_revalone. TRTU launch had three correction-cycle Canon spawns where prior reports falsely claimed completeness.Ledger ≠ Social Publishing. LinkedIn and YouTube publishing routes through Broadcast using
scripts/hubspot/post-schedule.jsandapps/website/scripts/youtube-publish.ts. Ledger only persists CRM artifact metadata (Note engagements with published URLs) AFTER the publish. Perfeedback_ledger_not_social_publishing.md.youtube-publish.ts --privacy publicrejects lowercase. HubSpot API requires uppercasePUBLIC. Best practice: omit the flag (defaults to public). Squire fix recommended at substrate phase so it's not surfacing at first episode publish.No public launch pages. Per Chris's directive 2026-05-06: launch materials live ONLY on auth-gated
/my-value-path/shows/{slug}/promo. TRTU and AOM both had public launch pages removed. Do NOT create/launchroutes on either the standalone site orvaluefirstteam.com.Public website apex → www 307/308 redirect.
valuefirstteam.comredirects towww.valuefirstteam.com. Any URL audit (Mirror, Lookout, manual curl) MUST follow redirects (curl -L/ Playwrightpage.goto) to avoid false-positive 404 reports. Standalone show sites typically serve the apex directly — verify the redirect behavior at step 10.Riverside auto-titles every export "Magic Episode." Replace with canonical title at every downstream surface. This pitfall lives in episode-publishing — but show launch should set the expectation in the production guide that production team always provides canonical titles, never "Magic Episode."
Global
a:hover { color: primary }collapses Tailwind hover utilities. Use:where(a):hoverto drop specificity to 0 so per-element utilities can override. Otherwise hover states produce color-on-color collisions on brand-colored sections.Format / cast lock BEFORE substrate. Reversing format post-substrate (TRTU originally specified four tiered-entrance episodes; changed to single ensemble launch) cascades into website brief, production guide, recording stack, episode count rework. Lock at step 3 and don't reopen.
Use
Host_listingUSER_DEFINED association (typeId 505 reverse) with--category USER_DEFINED. DefaultHUBSPOT_DEFINEDproduces a misleading "wrong object type" error if mismatched. Perwiki/conventions.md § HubSpot data conventions.Central Time is canonical. All
scheduleTime,publishedAt, and any time-of-day reference uses America/Chicago. Perfeedback_central_time_canonical.md. Do not write UTC times into the show document.Fallback rendering is a failure, not a feature. If the standalone site renders any element via a fallback path on the live site, investigate the primary path failure. Do NOT mark Mirror QA as a pass when fallbacks are visible.
Brand source vs. brief disagreement. When the brand source (SVG/HTML tokens) and the website brief disagree (AOM: SVG said Inter, brief said Fraunces), the brand source is canonical. Marquee flags the disagreement to Chris before extraction so the brief gets corrected; do not silently pick the brand source and let the brief drift.
Out of Scope (separate procedures required)
This procedure intentionally does NOT cover:
- Per-episode publishing — Riverside-export-to-all-canonical-surfaces is
docs/operating-procedures/episode-publishing.md. Show launch terminates at Episode 1 publish + cross-system audit; episode-publishing takes over from Episode 2 onward. - Recording session setup — Riverside session configuration, host coordination, guest brief generation. Belongs in a
riverside-session-setupoperating procedure (recommend Q author this next). - HubSpot Files folder governance — When and how to provision dedicated HubSpot Files folders per show (TRTU has folder
211958961945; AOM has its own). Belongs in ahubspot-files-folder-governanceoperating procedure (recommend Q author this). - Sponsorship integration — Sponsorship records via Order + Subscription objects per show. Patron-led when Tier-3 commerce activates. Currently deferred per AOM/TRTU launch decisions.
- Tertiary distribution — Apple Podcasts, Spotify, RSS, TikTok. Subscribe page renders as "Coming Soon" tiles at launch.
- Recap article schema setup —
recapArticleSanity schema shipped for AOM (commit1587feaeb). New shows reuse it; new schemas would belong in a Sanity-schema-launch procedure (Canon-led). - AI-Native Shift wheel mechanic / show-specific interactive features — AOM has
/wheel+/wheel/admin+/wheel/archiveroutes that are show-specific. These are bespoke per show; this procedure documents the substrate, not the bespoke routes. - Show 3+ launch pattern validation — Two launches (AOM, TRTU) is precedent; three would establish the procedure as fully battle-tested. Step 20's UNTESTED marker reflects this.
Related References
| Reference | Path |
|---|---|
| TRTU 5P plan | docs/plans/the-road-to-unbound-5p-plan.md |
| AOM 5P plan | docs/plans/another-orange-morning-5p-plan.md |
| AOM precedent commit | a7864b994 (AOM 5P plan + Ledger CAR) |
recapArticle schema commit (AOM) |
1587feaeb |
| LinkedIn publish pipeline extension | commit 84a100bd4 (added --channel flag to post-schedule.js) |
| Episode publishing operating procedure | docs/operating-procedures/episode-publishing.md |
| Media production lifecycle (related) | docs/operating-procedures/media-production.md |
| HubSpot write operations (related) | docs/operating-procedures/hubspot-write-operations.md |
| Listing property index | skills/hubspot/property-index/listing.json |
| Project property index | skills/hubspot/property-index/project.json |
| Association type ID index | skills/hubspot/property-index/associations.json |
| Vercel account routing reference | reference_vercel_valuefirstagent.md |
| Squire owns repo + Vercel | feedback_squire_owns_repo_vercel_setup.md |
| Canon verify-after-write rule | feedback_canon_verify_after_write.md |
| Ledger ≠ Social Publishing | feedback_ledger_not_social_publishing.md |
| TRTU broadcasting surfaces | reference_trtu_broadcasting.md |
| Central Time canonical | feedback_central_time_canonical.md |
| Ground deliverables in transcripts | feedback_ground_deliverables_in_transcripts.md |
| Verification protocol | docs/quality/verification-protocol.md |
| Process register | docs/quality/process-register.md |
| QMS framework | docs/quality/qms-framework.md |
| Launch metadata file | apps/website/src/components/show-promo/launch-metadata.ts |
| Show launch content static dir | apps/website/src/content-static/show-launches/ |
| Production materials drop dir | clients/vf-team/content/media_network/ |
Revision History
| Date | Change | Author |
|---|---|---|
| 2026-05-06 | Initial document. Authored from AOM (2026-04-30) + TRTU (2026-05-05/06) end-to-end launches. 18 of 20 steps VERIFIED with evidence; Steps 20 (cross-launch audit generalization) marked UNTESTED pending Show 3 launch validation of procedure reusability. Captures all known launch pitfalls (Vercel account routing, Squire vs Showcase split, Canon verify-after-write, Ledger vs Social Publishing, lowercase --privacy rejection, public launch page ban, apex/www redirect, brand-source vs brief conflict, format-lock-before-substrate, hover state collapse, Central Time canonical, fallback-as-failure, USER_DEFINED association category). |
Q (Quality System Manager) |