chapter.guide / swarm / run 016

Letter Sending Product Spec

2026-05-05  ·  PASS  · Bookmark this page: /swarm/016-letter-sending-product-spec.html

Assignment

Build a complete product spec and implementation plan for the "Letter Sending" feature — a production-ready physical mail system replacing abandoned Lob integration.

Subset: Full roster

Roster

writerarchitecthunterquarterbacklistenerdrapermarket-analyststorytellertech-translatordebrief

What we found

1. There's already substantial code — 12+ files across Python, TypeScript, and JavaScript — but it's fragmented across 3 overlapping implementations and frozen. The plumbing exists; it just needs consolidation and the right gates.

2. Stannp ($868/month for 1,000 letters) beats Lob ($1,130-$1,750) on cost and formatting flexibility. The real fix is architectural: render HTML to PDF locally, upload to any vendor.

3. The letter content needs a voice overhaul — operator-first language, specific facts that prove research, and strict word counts that fit a physical page.

4. A research reliability gate (reject letters when data is insufficient) is the single most important trust-building feature.

Why this matters

Letters are Next Chapter's highest-signal outbound channel for owner-operators over 55. Without them sending, the firm loses its primary differentiation from email-only brokers. The 10-day critical path to first letter means this isn't a quarter-long project — it's a focused sprint.

Where we agreed

Full consensus on:

  • Build a vendor abstraction layer (don't lock to one vendor)
  • `letter_integration.py` is the canonical generator (merge, don't rebuild)
  • Research gate must block bad letters BEFORE generation
  • Dynamic font sizing via character-count tiers (A/B/C/D)
  • Score-tiered routing: auto-approve ≥0.85, QA queue 0.65-0.84, reject <0.55
  • Operator-first voice rules (10 specific rules defined)
  • 5-phase implementation, first letter in ~10 days

Where we disagreed

Vendor choice: Hunter recommended Stannp (cheapest). Quarterback recommended staying with Lob (code exists, switching costs). Resolution: recommend Stannp but build abstraction layer so switching back is one env var change. Ewing decides.

Auto-approve threshold: Architect said 0.85, Quarterback said 0.80. Resolution: 0.85 for batch (cold outreach needs highest quality), 0.65 for ad hoc (post-call, you already know the person).

What surprised us

  • The existing code is far more complete than expected — scoring rubric, variant system, batch CLI, approval workflow all exist. The gap is wiring, not building.
  • Lob's HTML rendering limitations have NOT been fixed as of 2026 — the same Webkit renderer with the same restrictions. The fix was always "render PDF locally first."
  • 400 letters are sitting frozen with 0 approvals due to one missing function call in `ingest_letters.py` (the K2 gap).

What we'd do differently

  • Check for frozen/disabled features before assuming a capability doesn't exist (the letter system was built but gated behind `LETTER_SENDING_ENABLED=false`)
  • The voice guide and emotional mapping should be versioned documents (not just in code comments) so Ewing can iterate on them without touching Python

Currency events

From → ToActionMultiplierBaseScoreNotes
hunter → architectVendor formatting limitation research informed PDF-first design3x26Architect didn't need to research Lob's renderer
writer → architectWord count targets (350/250/150) informed typesetter tier design3x13Tiers calibrated to actual content lengths
draper → writerTrust trigger research directly shaped voice Rule 3 (concrete over abstract)3x26Emotional research → implementable writing rule
listener → quarterbackTension resolution (ad hoc vs batch thresholds) resolved sequencing3x13Different gates for different contexts

Cross-system gaps

FlaggerAffectedGapRecommended change
architectletter_integration.pyNo research gate check before generationAdd `research_gate.py` call at top of `generate_letter_for_target()`
quarterbackcampaign_manager.pyStub implementations for `_render_letter` and `_send_lob`Wire to canonical engine + vendor abstraction
listenertargets tableNo `research_gate_status` columnAdd column + index for enrichment pipeline
writerquality_gate.pyMissing broker-term ban listExtend FORBIDDEN_PHRASES with 12 banned terms