mattrguerra/meridian-outreach-vaultmainPrivate on GitHub, published here in full

scheduled-task.md

Language Markdown12.5 KB198 lines

07-Automation/scheduled-task.md

  1. ---
  2. type: automation-schedule
  3. scope: 07-Automation
  4. tags: [claude, outreach, automation, schedule]
  5. created: 2026-07-22
  6. last_modified: 2026-08-10
  7. ---
  8. # Scheduled Task: Weekly Partner Client Pipeline
  9. **ENABLED 2026-07-23: `through_vault` scope.** Live task `weekly-partner-client-pipeline`
  10. (Mondays 06:00 America/Chicago). It maintains the partner stubs and the XML map only: it
  11. does NOT enrich, push to Bitrix, or route anyone into an outreach/watch pipeline; those
  12. entry rules aren't decided yet, and the rest of the runbook resumes once they are. The
  13. authoritative prompt now lives in the task file
  14. (`~/Documents/Claude/Scheduled/weekly-partner-client-pipeline/SKILL.md`); the block below
  15. is the in-vault reference copy, kept in sync.
  16. > [!NOTE] **Synced 2026-08-10: Matt pasted the current prompt into the external
  17. > SKILL.md** (`~/Documents/Claude/Scheduled/weekly-partner-client-pipeline/SKILL.md`),
  18. > clearing the drift that had stood since 08-06. The block below is the in-vault reference
  19. > copy and now matches: steps 5a-c (deal reconcile + route) and 5d-5e (the outreach audit,
  20. > the **second weekly spreadsheet**), four-funnel scope 24/26/36/16.
  21. >
  22. > **No session can verify this.** That path is outside the vault and outside what the
  23. > device bridge will grant, so "synced" rests on Matt's word, not a read. The tell if it
  24. > ever drifts again: Monday's summary reports only ONE spreadsheet, or the audit's Summary
  25. > sheet is stamped "INCOMPLETE RUN". Whenever this reference copy is edited, assume the
  26. > external file is stale until someone re-pastes it, and put the warning callout back.
  27. ## Schedule
  28. - **Cadence:** weekly, Monday 06:00 America/Chicago.
  29. - **Cron:** `0 6 * * 1`
  30. - **Edit freely:** change the day/time here before enabling.
  31. ## What the run does
  32. Runs the [[Weekly-Partner-Pipeline-SOP]] at `autonomy: through_vault`: pulls the
  33. trailing week's orders from Plinth (day-sliced, offset+dedupe until convergence), ingests
  34. them into the local order history, classifies from that history (baseline + deltas),
  35. verifies the no-shrink guardrail (exit 2 halts the run), exports the spreadsheet, then
  36. **creates/upgrades partner stubs, refreshes the XML map** (stamps existing partner
  37. chunks and adds an empty-pipeline chunk for every partner client missing from the map, so
  38. it stays a complete census), and **regenerates the manual Google-Drive-swap workbook**
  39. (`Complete-Partner-Clients-List_updated-<date>.xlsx`) from the previous copy (Plinth
  40. columns refreshed, newly-qualified partner clients appended, All Accounts base rebuilt,
  41. human columns + the curated working tab left untouched), then reconciles the Bitrix deals
  42. into the census, computes the routing candidate lists, and **builds the second
  43. spreadsheet, `Bitrix_Pipeline_Outreach_Audit_<date>.xlsx`** (one sheet per outreach funnel
  44. 24/26/36/16: who is in it, how to find them in Plinth, when they were last actually
  45. contacted), then notifies you. It stops there: no enrichment, no Bitrix **writes**, and
  46. nobody routed into an outreach/watch pipeline. Baseline is seeded and
  47. `min_orders_to_qualify` is set, so the run is armed.
  48. **Two spreadsheets out, every week:** the Drive-swap partner roster (Stage F2) and the
  49. per-pipeline outreach audit (Stage F5). Matt still swaps the roster into Google Drive by hand.
  50. ## The prompt (what the scheduled Claude session executes)
  51. ```
  52. Run the Weekly Partner Client Pipeline for the Meridian Display Co. quarterly-outreach vault.
  53. Read 07-Automation/Weekly-Partner-Pipeline-SOP.md and 07-Automation/partner-thresholds.md
  54. first. CRITICAL CONTEXT: Plinth orders.fetch silently truncates large result sets (~70
  55. orders/response, no "has more" flag) and offset pages overlap. Never treat one response
  56. as complete; never query an all-time total. The SOP's "Why incremental" section governs.
  57. 0. PRECONDITION. If 07-Automation/data/order_history.json does not exist, STOP
  58. immediately and notify Matt that the pipeline is not seeded (see
  59. 07-Automation/Activation-Runbook.md). Do not pull anything.
  60. 1. DELTA PULL (Stage A). For each single day D in the trailing pull_window_days
  61. (from partner-thresholds.md, default 8), oldest first:
  62. a. orders.fetch since=D until=D limit=page_size (dates as yyyymmdd; hard cap 100).
  63. b. Save the raw response to 05-Outputs/partner-runs/raw/<run-date>/D_p0.json
  64. c. python3 07-Automation/weekly_partner_pipeline.py ingest --orders <that file>
  65. d. Read the INGEST line. If added > 0 OR the page had >= suspect_row_count rows,
  66. pull the same day again with offset += page_size, save as D_p1.json, ingest,
  67. and repeat until a page reports added=0. Offsets overlap by design; the
  68. ingest dedupe by order_ref absorbs it.
  69. Plinth throttles at 10 req / 10 sec; just proceed, slowness is fine.
  70. 2. CLASSIFY + EXPORT (Stages B-D):
  71. python3 07-Automation/weekly_partner_pipeline.py classify
  72. (No arguments: it computes from the local history store, never from the API.)
  73. 3. VERIFY (mandatory):
  74. python3 07-Automation/weekly_partner_pipeline.py verify
  75. Exit 0: proceed. Exit 2: a lifetime total SHRANK. That is data loss, not reality. STOP
  76. the run entirely: no stubs, no XML, no Bitrix, and say prominently in the summary which
  77. customers were flagged and that nothing was changed.
  78. 4. WRITE STUBS + REFRESH XML + REFRESH WORKBOOK (through_vault; only if verify exited 0):
  79. python3 07-Automation/weekly_partner_pipeline.py write-stubs --plan 05-Outputs/partner-runs/partner-classification_<date>.plan.json
  80. python3 07-Automation/weekly_partner_pipeline.py refresh-xml --plan 05-Outputs/partner-runs/partner-classification_<date>.plan.json
  81. python3 07-Automation/weekly_partner_pipeline.py refresh-workbook --plan 05-Outputs/partner-runs/partner-classification_<date>.plan.json
  82. Human Notes are never touched; refresh-xml backs up first. refresh-xml keeps the XML
  83. map a COMPLETE census of the partner base: it stamps every partner client already in
  84. the map AND adds a chunk (empty `<pipelines count="0" />`, id `pl-<user_id>`) for any
  85. partner client missing from it. Idempotent: re-running never duplicates. refresh-workbook
  86. regenerates the Drive-swap workbook `Complete-Partner-Clients-List_updated-<date>.xlsx`
  87. from the latest existing copy (base): refreshes only the Plinth-derived columns, appends
  88. newly-qualified partner clients, rebuilds the All Accounts base, renames the dated
  89. Plinth LTV header, and leaves the curated working tab + every human column untouched.
  90. The vault copy is NOT wired to Google Drive: Matt uploads it by hand. If write-stubs
  91. prints a FLAGGED list (stubs from messy Plinth name fields), include it verbatim for
  92. review. Do NOT delete or rename anything.
  93. 5. DEAL RECONCILE + ROUTE + OUTREACH AUDIT (5a-c added 2026-08-06; 5d-e added 2026-08-10.
  94. Entry rules: 07-Automation/pipeline-routing-rules.md. Everything here READS Bitrix and
  95. writes nothing back to it.):
  96. a. Enumerate EVERY deal in the FOUR in-scope outreach funnels: 24, 26, 36, 16.
  97. (Scope set by Matt 2026-08-10. 7 Days Delivery Up-Keep (28) and Cold Outreach (30)
  98. are deliberately OUT of scope; do not add them back without asking.)
  99. pipeline_summary per funnel for the stage list, then list_records per non-empty
  100. stage (add created_from="2020-01-01" on stages over 50 rows; split date windows
  101. until counts match). Save ONE JSON to
  102. 05-Outputs/partner-runs/bitrix-deals_<run-date>.json as
  103. {"deals":[{"deal_id","cat","stage","stage_date","title","owner","created","value"}]}.
  104. reconcile-deals ignores everything outside 24/26/36, so one file feeds both.
  105. KNOWN LIMIT: date-filtered list_records returns at most 200 rows per call and
  106. ignores sub-day time bounds, so two parked stages cannot be fully enumerated:
  107. C26:UC_JUUNES ("Client") and C16:NEW ("New Abandoned Cart"). Record
  108. the counts you could not enumerate in the summary; never pretend they were covered.
  109. b. python3 07-Automation/weekly_partner_pipeline.py reconcile-deals --deals <that file>
  110. c. python3 07-Automation/weekly_partner_pipeline.py route
  111. d. python3 07-Automation/weekly_partner_pipeline.py outreach-pull-list --deals <that file>
  112. Read 05-Outputs/partner-runs/outreach-pull-list_<date>.json. For every id in
  113. need_history call get_stage_history(entity_type=deal) and attach the result to that
  114. deal in the enumeration JSON as "history":[{"stage","at"}] (stage = the raw id like
  115. "C36:EXECUTING", at = "YYYY-MM-DD HH:MM"). For every id in need_contact call
  116. get_record and attach "contact":{"name","email","phone"}. Deals NOT in need_history
  117. must be left WITHOUT a history key: that is how the cache gets used. Batch ~10
  118. concurrent; on QUERY_LIMIT_EXCEEDED reduce the batch and retry. No id may be skipped.
  119. e. python3 07-Automation/weekly_partner_pipeline.py outreach-audit --deals <that file>
  120. MUST run after step 4's refresh-workbook: it resolves Plinth ID, phone, tier
  121. and LTV out of that workbook. Writes the second spreadsheet,
  122. 05-Outputs/Bitrix_Pipeline_Outreach_Audit_<date>.xlsx, and updates
  123. 07-Automation/data/outreach_touch_cache.json.
  124. route is read-only and emits the weekly candidate lists (winback import CSV +
  125. cat24/dormant in the JSON). Do NOT create deals, do NOT move stages, do NOT "correct"
  126. a stage the audit flags: loading lists into Bitrix stays human-gated.
  127. 6. STOP. Do NOT enrich (client-enrich) and do NOT push to Bitrix (partner-pipeline-push).
  128. Post a short summary to Matt: run date, verify result, tier counts, stubs created vs
  129. upgraded, XML chunks stamped vs newly added, reconcile stats (new/updated blocks,
  130. unmatched/ambiguous deals), route counts (winback / cat24 / dormant queue / excluded),
  131. any FLAGGED names, and any has_baseline=False customers worth a look (count only).
  132. For the audit: BOTH spreadsheet filenames, deals per funnel, how many clients have a
  133. verified touch vs never contacted, how many histories were pulled fresh vs reused from
  134. cache, the count with no Plinth match, and the parked stages you could not enumerate.
  135. Call out anything the audit DROPPED (no history and no cache entry): that is a bug
  136. signal, not a normal result.
  137. 7. LEDGER. Both spreadsheets + raw dumps + history + stubs + XML + the touch cache were
  138. written under the vault: append ONE batched entry to LEDGER.md (attribution by session
  139. email; Matt = hello@meridiandisplay.example, Hazel = accounts@meridiandisplay.example),
  140. per the CLAUDE.md shared-vault rule.
  141. Do not expose customer PII in the chat summary. Counts and tiers only.
  142. ```
  143. > Step 5a's KNOWN LIMIT predates the 2026-08-11 enumeration fix recorded in the SOP
  144. > (sub-day windows do work when `tz=Europe/Moscow` is passed; verify coverage against the
  145. > stage total). The prompt above is the 2026-08-10 sync and has not been re-pasted since.
  146. ## After thresholds are set: the human-approved continuation
  147. **Update 2026-07-27:** Stage F2 (`refresh-workbook`) now also runs automatically each week:
  148. it regenerates the Drive-swap workbook from the previous copy (Plinth columns refreshed,
  149. newly-qualified partner clients appended, working tab + human columns untouched). Matt still
  150. swaps the file into Google Drive by hand; the vault copy is not connected to Drive.
  151. **Update 2026-07-23:** Stages E and F (write-stubs + refresh-xml) now run automatically each
  152. week under `through_vault`. Stages G and H below (enrich, Bitrix push) stay manual and
  153. human-gated, and nobody is routed into a watch/outreach pipeline until those rules exist.
  154. Once [[partner-thresholds]] has real numbers, review the spreadsheet, then run the
  155. downstream stages by hand (or ask me to):
  156. ```
  157. # Stage E: create missing stubs / upgrade existing (adds last_modified)
  158. python3 07-Automation/weekly_partner_pipeline.py write-stubs \
  159. --plan 05-Outputs/partner-runs/partner-classification_<date>.plan.json
  160. # Stage F: refresh the XML map: stamp existing + add missing partner chunks (backs up first)
  161. python3 07-Automation/weekly_partner_pipeline.py refresh-xml \
  162. --plan 05-Outputs/partner-runs/partner-classification_<date>.plan.json
  163. # Stage G: enrich the new + changed stubs
  164. # invoke the `client-enrich` skill on that cohort
  165. # Stage H: push the approved cohort to Bitrix
  166. # invoke the `partner-pipeline-push` skill (one deal per client, tagged by User Group)
  167. ```
  168. Each of E to H that changes the vault gets its own LEDGER entry.
  169. ## To widen autonomy later
  170. Set `autonomy` in [[partner-thresholds]] to `through_vault` (auto stubs + XML, hold
  171. Bitrix) or `full` (everything). Bitrix push stays human-gated in the SOP regardless:
  172. change that only deliberately.