Contact Context Smoke

0. 这份 smoke 要回答什么

Call Input Smoke 检查单次 calls row 是否准确。Contact Context Smoke 检查的是下一层:

contacts-analyzer 看到的 contact-level context 是否够准、够完整、够可解释。

如果 task 错了,可能不是 task decision policy 本身错,而是 contact context 已经缺关键事实:

  • Contact snapshot 没带 doNotContact / lifecycleStage / leadStatus
  • Message 只有 VoiceMail (no transcript),AI 根本没看到客户留言内容。
  • Lead record 没带 booking 相关事实,AI 不知道这是不是已经预约。
  • Open task 没带 attemptCount / dueAt,AI 不知道该 record_progress 还是 close unable_to_reach
  • Recently closed task 没进入 context,AI 可能重复创建同类 task。

这不是完整的 Contact Accuracy Foundation。它是 demo 前的 lightweight upstream sanity check:确认 Task Accuracy 的 contact input 没有明显歪掉。

1. 它在 pipeline 里的位置

Neon facts
  contacts
  messages
  leads
  tasks
  task_progress_events
        |
        v
contacts-analyzer prompt context
  CONTACT / snapshot
  PREVIOUS SUMMARY
  LEAD RECORDS
  RECENT MESSAGES
  OPEN TASKS
  PLAYBOOK GUIDANCE
  RECENTLY CLOSED TASKS
        |
        v
ContactsAnalysisSchema
  contact profile fields
  taskDecisions[]
        |
        v
Policy Guard / writer / DB constraints
        |
        v
Task timeline + contact history + UI

这份 smoke 覆盖的是:

contact/message/lead/task facts
   -> contacts-analyzer prompt context
   -> AI 是否能基于这些 facts 做正确 contact / task 判断

它不测试 raw audio transcription 质量,也不测试 Vapi。它直接假设 call/message/lead/task facts 已经落库,然后检查 context builder 是否把必要字段喂给 AI。

2. 当前 production context 已经喂了什么

当前 contacts-analyzer 的 user message 不是只喂一段 text。它会把多张表压成半结构化 context:

CONTACT:
CURRENT TIME:
STORE TIMEZONE:
LOCAL TIME:
DO NOT CONTACT:
LIFECYCLE STAGE:
LIFECYCLE STATE:
LAST ACTIVITY:
CURRENT LEAD STATUS:

PREVIOUS SUMMARY:

LEAD RECORDS:
RECENT CALLS:
RECENT MESSAGES:
OPEN TASKS:
PLAYBOOK GUIDANCE:
RECENTLY CLOSED TASKS:

Contact Context Smoke 重点看 RECENT CALLS 以外的部分:current snapshot、messages、leads、open tasks、progress state、recently closed tasks 和 playbook guidance。

3. Smoke 的 review 原则

不要做所有全排列。这里按 contact decision point 覆盖:

  • Source identity:这是 call、SMS、voicemail、lead record,还是 existing task?
  • Recency:发生时间、当前时间、store timezone、last activity。
  • Safety/context:doNotContact、terminal lifecycle、recently closed task、existing duplicate task。
  • Process state:open task、attemptCountdueAt、progress history。
  • Lead facts:lead source、lead type、received time、booking facts。
  • Message facts:SMS body、voicemail transcription、DNC keywords、callback timing。
  • UI explainability:task timeline、customer summary、related open tasks 是否让 staff 能 30 秒看懂。

这个 smoke 不是看模型“会不会编一个合理故事”,而是看 production contact context 是否足够支撑正确判断。

4. 第一批 smoke scenario set

每个 scenario 至少检查三件事:

  • DB facts:上游表里字段是否写对。
  • Prompt contextcontacts-analyzer user message 是否带到了这些字段。
  • Expected implication:这些 facts 是否足够支持后续 contact / task decision。

CT-01 Existing lead books intro

业务状态

Lead 接通电话并确认预约 intro / first class。

必须看到的 contact context

  • Lead record 存在。
  • CONTACT snapshot 能显示当前 lifecycle / lead status。
  • Open task 如果是 lead_outreach / lead_follow_up,要出现在 OPEN TASKS
  • OPEN TASKS 里的 taskReftypeCategoryattemptCountdueAt 必须可见。

Expected implication

已有 lead task 应该 close as booked。不要因为已经 booked 再创建 intake、waiver、arrival logistics task。

CT-02 Trial completed but not converted

业务状态

Lead 已经完成 trial / first class,但还没购买 membership。

必须看到的 contact context

  • 有可靠 attendance / post-trial 证据,不只是 generic SMS。
  • Contact stage 仍是 lead
  • leadStatus 可以是 showed / trialed
  • PREVIOUS SUMMARY 或 recent facts 说明 trial 体验和未转化原因。

Expected implication

后续 task 才能走 booked_not_converted。如果只是 booked upcoming class,不应该提前创建。

CT-03 Outbound no-answer on existing open task

业务状态

员工对一个 open task 打电话,没人接。

必须看到的 contact context

  • OPEN TASKS 里有对应 open task。
  • attemptCountdueAt 出现在 OPEN TASKS
  • 最新 call facts 能证明 outbound no-answer。
  • 没有客户新表达的 objection / DNC / close outcome。

Expected implication

通常是 record_progress,不是 create new task,也不是随便 close。若 attemptCount 达到 policy threshold,再按 Task Accuracy policy 判断是否 close unable_to_reach

CT-04 Voicemail callback request

业务状态

客户留 voicemail,说希望明天回电或指定时间 follow up。

必须看到的 contact context

  • messages.type = VoiceMail
  • voicemailTranscription 有内容
  • Prompt 显示 VoiceMail (transcribed)
  • 文本里能看出 callback timing
  • Store timezone / local time 存在,方便生成 UTC nextDueAt

Expected implication

如果有 existing task,应该 record_progress with callback_requested / follow_up_scheduled。如果没有 existing task,而且是清晰 unresolved objective,才考虑 create task。

CT-05 SMS STOP / DNC

业务状态

客户回复 STOP / unsubscribe / do not contact。

必须看到的 contact context

  • RECENT MESSAGES 显示 SMS body。
  • Contact snapshot 的 doNotContact 如果已是 true,必须传给 AI。
  • Writer / policy 仍要 sticky enforce,不能只靠模型。

Expected implication

AI 不应该创建普通 outreach task。DNC 是 safety gate,应该阻断 proactive call/SMS/email。

CT-06 Wrong number / non-customer business inquiry

业务状态

来电或消息是 wrong number、vendor、corporate sponsorship、partner、marketing pitch,和健身 customer lifecycle 无关。

必须看到的 contact context

  • Current snapshot 能允许 lifecycleStage = unknown
  • Recent call/message summary 保存有用事实,但不要伪造成 lead/member
  • 如果已有 open fitness task,要能在 OPEN TASKS 看到它,方便 close invalid existing task

Expected implication

lifecycleStage 应该是 unknown,普通 fitness task 应该 no-op 或 close invalid existing task。

CT-07 Unresolved complaint

业务状态

会员投诉 billing、staff、facility、policy 或 app issue,且没有明确解决。

必须看到的 contact context

  • call/message summary 里有 complaint evidence
  • followUpNeeded = yes when unresolved
  • Contact profile 要能设置或保留 hasOpenComplaint = true
  • 如果已有 retention/cancellation task,prompt 里必须能看到 existing task context

Expected implication

这类通常进入 retentioncancellation_risk,取决于是否有 churn/cancel risk。不能只当成普通 history summary。

CT-08 Referral / bring-a-friend opportunity with existing task

业务状态

现有会员主动说要带朋友、问 guest pass、推荐家人,或留下 referral opportunity;同一个 contact 可能还有 renewal / cancellation / retention task。

必须看到的 contact context

  • Recent call/message 明确提 referral / guest / friend
  • Contact identity 明确是 member 或 known customer
  • Existing open tasks 全部进入 context,不要只显示一个 objective
  • UI 能显示 same contact 的 related open tasks,避免 staff 误以为只生成一个 objective

Expected implication

这可以产生 referral task。若同一个 contact 还有另一个 open task,Task UI 要能让 staff 看见 related open tasks。

CT-09 Churned member asks to rejoin

业务状态

前会员主动来电或发消息,说想重新加入或回来上课。

必须看到的 contact context

  • Contact snapshot 已是 churned,或 recent call facts 显示 former_member
  • inbound customer-initiated re-engagement evidence
  • 如果 interaction 当场完成 rejoin,outcome 要能显示 success;否则 follow-up remains open

Expected implication

后续 task 应该偏向 win_back。这不是 cold outbound win-back;是 customer-initiated reactivation。

5. 当前已发现的 contact context 风险

5.1 Lead facts 可能不够

当前 prompt 里的 LEAD RECORDS 主要展示:

receivedAt + firstName + lastName + leadType

leads schema 还有 booking/source/raw email 相关字段。对于“lead 是否已经 booked / trialed / needs follow-up”的判断,v1 smoke 应该验证现有字段是否够用。

如果不够,下一步不是马上把 rawBody 全塞进 prompt,而是先加 targeted context:

  • booking date/time
  • lead source / email subject
  • parsed class time if available
  • ingestion source when helpful

5.2 Store isolation 的 prompt 输入要继续验证

Open tasks 当前按 phone + storeId 取,这是对的,因为 task mutation 必须 store-scoped。

Recent calls / messages / leads 当前更像 phone + franchise scoped context。demo 前 smoke 要验证同一个 phone 在多 store 下不会把另一个 store 的 facts 喂给 AI。若发现风险,应该优先把 recent calls/messages/leads context 也收敛到 store-scoped 或 source-store-aware。

5.3 Playbook guidance 只在 open task 存在时注入

当前 PLAYBOOK GUIDANCE 是按 open task categories 注入的。这个对 progress / close / update 很有用。

但 create case 没有 existing open task 时,AI 主要靠 task taxonomy 和 call/contact facts 创建新 task。后续如果要让 create 的 suggestedActions 更稳定,可以考虑给 create candidate category 注入轻量 playbook guidance,但不要在 demo 前强行扩 scope。

5.4 Contact Accuracy Foundation v1 的长期形态

Contact Accuracy 不是让 AI 读一堆历史后自由发挥“这个人是什么状态”。更稳的形态是:

Neon facts
  contacts / calls / messages / leads / tasks / progress / closed tasks

Context Builder
  - store-scoped contact snapshot
  - recent calls/messages with source store evidence
  - lead records with booking/source facts
  - open tasks with taskRef / category / attemptCount / dueAt
  - task_progress_events
  - recently closed tasks
  - playbook guidance when applicable

LLM structured output
  - lifecycleStage / lifecycleState evidence
  - intent / complaint / DNC signals
  - taskDecisions[]

Deterministic writer / Policy Guard
  - sticky DNC
  - duplicate task guard
  - store_id isolation
  - allowed mutation policy

persisted contact state + tasks + timeline

这和 AI Agent Foundation 的关系是:

  • Facts:多张表的历史事实,不是一段自由文本。
  • Context Builder:决定 AI 到底看见什么;如果这里漏字段,下游 task 再聪明也会错。
  • Structured Output Schema:让 contact state 和 taskDecisions[] 可验证、可 replay。
  • Policy Guard:DNC、duplicate、store mismatch 不能只靠模型自觉。
  • Eval / Replay:Contact Accuracy smoke 先验证 input 是否喂对,完整 foundation 再验证 lifecycle / intent / safety state 是否稳定。

6. Demo 前怎么用这份 smoke

每个 demo candidate 至少检查这一条链:

DB row facts
  -> contacts-analyzer userMessage
  -> AI output
  -> writer mutation
  -> Task UI / timeline

建议最小操作:

  1. 从 8-12 个 demo candidate 里选 3 个真实端到端 case。
  2. 对每个 case 保存一份 prompt context 或 OpenRouter log。
  3. 在 DB 里确认 contact/message/lead/task 的关键字段。
  4. 在 UI 里确认 task card、timeline、customer summary、related open tasks 能解释发生了什么。
  5. 如果错了,先归因:contact context 错、prompt contract 错、task decision 错、writer/policy 错,还是 UI 隐藏了正确结果。

一句话:

Demo 要讲的是 Task 准 + 写库安全 + UI 可解释;Contact Context Smoke 确保“Task 准”不是建立在看错 contact context 的基础上。