DocsAutoResponderProcess

Output documents — business intent#

See repo source for current behavior.

This page describes why the pipeline emits each business-facing deliverable list and what stakeholders expect from them. For exact filenames, paths, and column definitions, see DATA_DICTIONARY.html.

#DeliverableFile(s)Primary recipient
1List of Inactive Peopleoutput_document_inactive_people.csv/.jsonInternal ops (run directory; not emailed on N04)
1aSFMC marketing suppression import{BusinessUnit}_NoLongerThere_{YYYY-MM-DD}.csv (e.g. Marketing_NoLongerThere_2026-05-27.csv)Marketing team (notify_marketing_suppression N04)
2List of Alternate Contactsoutput_document_alternate_contacts.csv/.jsonSai Teja (IP4)
3List of Inactive People at New Organizationoutput_document_inactive_new_org.csv/.jsonSai Teja (IP4)
4List of Undeliverablesoutput_document_undeliverables.csv/.jsonRun report consumers
5CUPOLA-undetermined handoff (IP4)output_document_inactive_no_cupola_match.csv/.jsonSai (notify_sai_action_items catalog N05/N06); global Max + Vish Cc
6Email Update Requests (Changed Email)output_document_email_update_requests.csv/.jsonRun directory only; marketing team gets SFMC suppression files via N04 (*_NoLongerThere_*.csv)
7Multipub Auditoutput_document_multipub_audit.csv/.jsonRun directory only; Tarun gets undetermined-sender (1.2) and upload Yes (3.1)
8Human Review digestoutput_document_human_review.csv/.jsonSai Teja (IP4); consolidated review queue
9Impact reportimpact_report.txt + .jsonClient Services (attached to the run-reports email)

Active-only policy. CUPOLA writes apply only on INACTIVE against an active CUPOLA row, or on gated EMAIL_UPDATE / TITLE_UPDATE against an active row. ACTIVE never auto-adds or auto-reactivates; OUT_OF_OFFICE never writes backends. Otherwise rows go to the Human Review digest (#8).

List of Inactive People#

Purpose: Remove or follow up these emails across systems (Cupola, Hodor, Salesforce, SFMC, Multipub).

Fields (conceptual):

Systems and actions:

Marketing email (N04): The marketing team mailbox does not receive this wide internal CSV. When inactive rows exist, the pipeline also writes {BusinessUnit}_NoLongerThere_{YYYY-MM-DD}.csv (see below) and attaches only those SFMC import files via notify_marketing_suppression.


SFMC marketing suppression import#

Purpose: Give Marketing a file they can import into SFMC to suppress addresses the auto-responder marked inactive (deceased, retired, left company, no longer there).

Artifacts: One CSV per business-unit label under processing_reports/run_{timestamp}/, named {BusinessUnit}_NoLongerThere_{YYYY-MM-DD}.csv (run date from folder name). Today all rows map to Marketing_...; future inbox→business-unit mapping may produce additional files (e.g. Energy_...).

Columns: Email Address, Status (always Unsubscribed), Date Added (ISO date). Emails are deduped case-insensitively within each file. UTF-8 with BOM.

Recipient: Marketing team via catalog N04 (NOTIFICATION_EMAIL_ERIN). See MARKETING_SUPPRESSION.html (process guide), NOTIFICATIONS_CATALOG — N04, and DATA_DICTIONARY — marketing suppression deliverable.


List of Alternate Contacts#

Purpose: Consolidate alternate contacts provided in auto-replies and add or update across systems.

Fields (conceptual): Id, AccountName, Email Received From (source / lookup identity), Subject, Email Body (full source message text), Message ID (traceability), Org ID/Name, alternate name/title/email/phone/ext, Cupola Org Person ID / Person ID, HODOR ProsNum when present, comments, planned Cupola action (add vs update), HODOR library and import-template fields, flag when Sales should follow up in Multipub.

Systems and actions:


List of Inactive People at New Organization#

Purpose: Track where inactive people went and whether they should be in our systems at the new org.

Population: Rows are written when Determination.new_org_details is populated after LLM classification. category_mapper._normalize_new_org_details reads nested or flat new_org_* keys from the classifier JSON; _enrich_new_org_details falls back to final_sender_new_email (and optional org name from classifier reasoning) for Left Company, Retired, Deceased, and Changed Email when structured fields are missing.

Fields (conceptual): Id, Account Name, source email, person name, new org ID/name/title/email/phone, Org Person ID, Person ID, HODOR ProsNum when present, comments, Cupola action and whether the org exists / is AI-appropriate where applicable, HODOR library assignment notes, flag when Sales should follow up in Multipub.

Systems and actions:


CUPOLA-undetermined handoff (IP4)#

Purpose: Give IP4 / operations a dedicated queue whenever an automated CUPOLA decision was not possible — no CUPOLA org-person row exists, or the matched row is inactive and the determination would otherwise auto-add / auto-reactivate. Under the Active-only policy this queue also captures ACTIVE determinations with no CUPOLA row and reactivation candidates (inactive CUPOLA rows on ACTIVE outcomes).

Artifacts: output_document_inactive_no_cupola_match.csv and .json under processing_reports/run_{timestamp}/. Rows are delivered inside Notifier.notify_sai_action_items (catalog N05/N06 — inactive contacts with no Cupola match). To: NOTIFICATION_EMAIL_SAI; global Max + Vish Cc.

Fields (conceptual): Account/inbox source, auto-response sender, subject, person/org hints from the email, determination label, Multipub deferral/review context when relevant, Hodor ProsNums and Salesforce IDs if lookup found those without Cupola, message id for traceability.


List of Undeliverables#

Purpose: Consolidate undeliverable auto-response traffic (bounce-backs, invalid addresses) so teams can remove or correct records and align downstream systems.

Fields (conceptual): Id, AccountName, sender email, lookup email, Org Name, Person Name, subject, Cupola org/person and org-person identifiers when resolved, HODOR ProsNums, Multipub subscriber number when resolved, processing status, skip reason when applicable.

Systems and actions:


Email Update Requests (Changed Email)#

Purpose: Per-row deliverable for every email mapped to the Changed Email category. Per-row deliverable for Marketing / SFMC address corrections on changed-email determinations.

Artifacts: output_document_email_update_requests.csv under processing_reports/run_{timestamp}/. Changed-email rows are tracked on the master ledger; they are not attached to marketing email N04. Inactive-people SFMC suppression files (*_NoLongerThere_*.csv) are emailed separately via Notifier.notify_marketing_suppression (NOTIFICATION_EMAIL_ERINmarketing-team-cbi@columbiabooks.com).

Fields (conceptual): Source message id, original sender, lookup email actually used, contact-found flag, contact systems hit, determination, processing status, org name, person name, the new email extracted from the auto-response, and the matched IDs from each backend system (Cupola org/org-person/person, Hodor ProsNum, Multipub SubsNum).

Systems and actions:


Multipub Audit (Tarun handoff)#

Purpose: Cross-check audit for every INACTIVE determination that ran through the Multipub subscription gate. Lets Tarun retire (or compare against) the manual Multipub review queue.

Artifacts: output_document_multipub_audit.csv under processing_reports/run_{timestamp}/. Written for engineering review; not bulk-emailed to Tarun. Tarun receives notify_tarun_undetermined_sender_review (N03) and the upload Yes-path notify_multipub_subscriber_followup_from_upload (N09).

Tarun upload loopback: POST /multipub/upload with outcome=yes|no. Yes → Angel + Yogesh (Matt Cc). Notarun_upload_audit.csv only. See docs/connections/multipub.html.

Fields (conceptual): Account/inbox source, email used for the Multipub lookup, person/org hints, determination label, matched Multipub subsnum, active / recently expired / single-issue subscription counts, the validation gate's flagged/deferred decision, the review reason text, a one-line summary, and the source message id.

Systems and actions:


Human Review digest#

Purpose: Single consolidated queue for every row the pipeline decided not to act on automatically, for rows not acted on automatically. Captures reasons such as:

reason constantWhen
HUMAN_REVIEW_REASON_ACTIVE_NEW_CONTACTACTIVE outcome but no CUPOLA row (no auto-add)
HUMAN_REVIEW_REASON_REACTIVATION_CANDIDATEACTIVE outcome but matched CUPOLA row is inactive (no auto-reactivate)
HUMAN_REVIEW_REASON_UPDATE_ON_INACTIVEEMAIL_UPDATE / TITLE_UPDATE on inactive CUPOLA row
HUMAN_REVIEW_REASON_OUT_OF_OFFICEOUT_OF_OFFICE determination — tracked as its own workflow, no system writes

Artifacts: output_document_human_review.csv under processing_reports/run_{timestamp}/. Actionable rows are filtered into output_document_human_review_action_items.csv and emailed via notify_sai_action_items (catalog N05/N06). Venu's audit email includes reason-key legend + per-reason counts from the master CSV. Each row includes Email Body, reason, reason_detail, suggested_action, and traceability columns.


Impact report#

Purpose: One-page headline summary of what the run actually changed. Driven by utils/impact_report.py, which reads the in-memory CupolaAuditLogger.entries list and derives three counts.

Artifacts: impact_report.txt (human readable) and impact_report.json (machine readable) next to the audit log. Impact metrics are inlined in the N08 run-audit email body and in processing_report.log; impact_report.txt is not attached to that email.

Fields:

FieldMeaning
emails_processedTotal auto-response emails handled in the run
records_deactivatedCUPOLA rows flipped to inactive (status_change audit entries with requested_status=False and auto_applied=True)
records_addedNew CUPOLA rows inserted (contact_addition audit entries with a non-empty contact_id; when this only ticks for REPLACEMENT when CUPOLA_AUTO_ADD_REPLACEMENTS=true)