README.md
Language Markdown8.4 KB124 lines
---type: automation-indexscope: 07-Automationtags: [claude, outreach, automation]created: 2026-07-22last_modified: 2026-09-21---# 07-Automation: Weekly Partner Client PipelineThe **live** Cowork automation that turns live Plinth order data into a partner clientclassification each week, maintains the partner stubs and the XML census, and (on yourapproval) continues to enrichment and Bitrix. Everything here is plain files you canedit in VS Code and re-upload.## The files- **[[partner-thresholds]]**: config + the activation checklist. Tier bands are liveprogram values; `min_orders_to_qualify: TBD` is the arming switch. Single source oftruth; the driver parses the ` ```yaml ` block out of it.- **[[Weekly-Partner-Pipeline-SOP]]**: the full A0→H procedure and the guardrails,including **"Why incremental"**, the Plinth truncation bug that dictates the wholearchitecture. Read that section before touching Stage A.- **`weekly_partner_pipeline.py`**: the deterministic engine, v2 incremental:`seed-baseline` → `ingest` (dedupe by `order_ref`) → `classify` (from local history)→ `verify` (no-shrink) → guarded stub/XML/workbook writes, then the read-only Bitrixstages (`reconcile-deals`, `route`, `outreach-pull-list`, `outreach-audit`). Does notcall Plinth or Bitrix; Claude feeds it the raw page dumps and deal pulls. The file isthe command-line entry point; the code is in **`partner_pipeline/`**, one module perstage (`stages.py` holds the funnel, stage-name and send-token tables).- **`requirements.txt`**: pyyaml and openpyxl for the driver, freezegun for the replay.- **`data/order_history.json`**: the local order history (created at seed time). This,not the API, is the source of truth for lifetime value.- **[[scheduled-task]]**: the live weekly schedule + the exact prompt (ENABLED2026-07-23).- **[[pipeline-routing-rules]]**: the entry rules `route` implements, and the four-funnelaudit scope.- **`sample/`**: the generator and replay that produced every client file in this repo(see "The sample" below).## Current state (2026-07-24)1. **LIVE.** Seeded from Ines's roster workbook (baseline as_of 2026-07-20), armed(`min_orders_to_qualify: 1`), and scheduled: Mondays 06:00 America/Chicago,autonomy `through_vault`. First run completed 2026-07-23: verify OK, stubs + XML censusrefreshed for the whole partner base. (The shipped sample's first run, 2026-09-14:128 partner clients, Palladium 85 · Platinum 28 · Iridium 8 · Rhodium 7.)2. `refresh-xml` maintains the XML map as a **complete partner census** (addsempty-pipeline `pl-` chunks for anyone missing; idempotent).3. Enrichment (Stage G) and Bitrix push (Stage H) remain **manual and human-gated**;nobody is routed into an outreach/watch pipeline until those entry rules are decided.## Activating itFollow **[[Activation-Runbook]]**: the definitive step-by-step, with commandsvalidated against the roster workbook (in this repo, the sample roster in`sample/inputs/`). Short version: two-pass seed (All Accounts then the Complete list),catch-up pull, set `min_orders_to_qualify`, classify + verify + reconcile, one manual E to Hpass, enable the schedule.## The sampleMeridian Display Co. and every client in this vault are fictional. The client data is nothand-written: two scripts in `sample/` invent a client book and then run the real driverover it.- **`sample/generate_sample.py`** invents the book: 381 Plinth accounts with aroster workbook (`sample/inputs/Partner-Clients-Roster_2026-09-07.xlsx`, tabs"2026 Partner Working List", "Complete Partner Clients List" and "All Accounts", totalsthrough 2026-09-07), two weeks of Plinth `orders.fetch` page dumps, and two weeklyBitrix deal enumerations with their stage histories and contacts. It is seeded, so everyrun produces the same world. The world is built to exercise the parts of the driver thatmatter: a Plinth day (2026-09-17) that truncates silently at 50 rows with overlappingoffsets; cancelled (27) and refunded (28) orders; clients crossing a tier band mid-weekand a brand-new customer who qualifies on a first order (`has_baseline=False`); anapproved merge; the directly-partnered Harlow Ridge Homes mailboxes (Rhodium byoverride, never cold-emailed) and a staff mailbox on our own domain; an identity twinwhere only one twin carries the Not Interested closure; a shared company mailbox; arole-named account and a messy shipping-label name; retired Bitrix stages, same-minuteworkflow re-entries, and a cart that moved into production funnels after converting.- **`sample/run_sample.py`** replays two Monday runs (2026-09-14 and 2026-09-21) of`weekly_partner_pipeline.py` against those inputs, doing what the scheduled session doeswith the MCP calls stood in for by files: seed the baseline in two passes and copy theroster as the first Drive-swap base; then per run, pull and ingest each day of thewindow until a page adds nothing, `classify`, `verify`, `write-stubs`, `refresh-xml`,`refresh-workbook`, `reconcile-deals`, `route`, `outreach-pull-list` (attaching stagehistories and contacts only for the deals it asks for), and `outreach-audit`. The clockis pinned to each run date with freezegun, because the driver dates its outputs bytoday's date; that is the only thing it changes. Each run's console output is saved as`05-Outputs/partner-runs/run-log_<date>.txt`.**Regenerating.** The replay refuses to run if `07-Automation/data/order_history.json`exists, so run it on a scratch copy with the generated state removed. The root[[README]] ("Replay the sample") has the exact commands and the `diff` that checks theresult: only the ten hand-researched stubs differ, because the replay does not regeneratethem. The replay copies each day's Plinth pages into `05-Outputs/partner-runs/raw/`, whichis not committed (the committed copy is `sample/inputs/plinth/`).**What came from the replay.** Every stub in `03-Clients/client-stubs/`, the census`03-Clients/partner-client-master-list.xml`, everything in `05-Outputs/partner-runs/` (plusthe two `Bitrix_Pipeline_Outreach_Audit_*.xlsx` workbooks in `05-Outputs/`), and everythingin `07-Automation/data/` (the merge registry and suppression list are copied in from`sample/inputs/`). State after the 2026-09-21 run: 381 Plinth accounts in history; 130partner clients (Palladium 86, Platinum 29, Iridium 8, Rhodium 7), 130 stubs and 130 censuschunks, 43 of them with pipeline placement; 54 deals across the four audited funnels, 28with a verified touch; route: Winback 50, cat 24 first-touch 31, Dormant queue 4, excluded 45.**What was added by hand on top.** Ten stubs carry invented research under `## Research` (written the way `client-enrich` writes it, with sources on `.example` hosts), a few carry Human Notes and Outreach Log rows that match their Bitrix history, `05-Outputs/First Email/` and `05-Outputs/Second Email/` hold eleven sample drafts spread across the six stages, and `04-Working/dual-active-pipelines_2026-09-21.md` is a review note built from the 09-21 census. A fresh replay does not recreate these.## Design decisions worth knowing- **Incremental by necessity.** Plinth `orders.fetch` truncates at roughly 70 orders perresponse with no signal and unreliable offsets (verified on one long-standing account,2026-07-22; see [[DECISIONS]]). Lifetime totals therefore come from the local historystore, never from a single API call. The `verify` no-shrink guardrail is the tripwire.- **Two existing skills do the last two stages**: `client-enrich` (enrichment) and`partner-pipeline-push` (Bitrix). This template chains them; it does not duplicate them.- **Modification date is new.** Neither stubs nor the XML map carried one. The driver adds`last_modified` (frontmatter) and `<last_modified>` (XML), deliberately named apart fromthe historical `updated` key the enrichment writeback avoids.- **Human Notes and Research are never written** by the classifier. Research is only evertouched by `client-enrich`. This is the [[CLAUDE-clients]] scraping-dump contract.- **Bitrix is always human-gated.** Even at full autonomy the SOP holds the push for a person.- **Shared vault:** every write stage appends one [[LEDGER]] entry.## Dependencies`pip install -r 07-Automation/requirements.txt` (openpyxl optional for the driver, whichfalls back to CSV; freezegun is only for replaying the sample). Plinth MCP must be connected for the pull;Apollo/Apify for enrichment; Bitrix for the push.