Task V3 Impacted Revenue 归因设计

本文是 revenue-attribution.md 的 V3 版本补充,不修改或替代原文件。

本文以当前 callytics-infrastructure 的 Task V3 Policy Catalog、Neon schema 和 API reporting contract 为事实来源。旧文档中的 9 个 closeResult 模型仅作为产品历史背景,不再作为新实现的主键。

一、结论

V3 已经具备 Impacted Revenue 的核心事实基础:

  • Task 有明确的业务目标身份:task_modetask_kinddisplay_type
  • 正向业务结果由版本化 Policy Catalog 授权;
  • 收入候选结果写入受控的 revenue_mapping_code
  • 结果同时保存 result_code、验证方式、证据引用和业务发生时间;
  • 所有数据按 store_id 隔离,并保留 tenant_id 演进字段;
  • reopen 会清除旧的 terminal revenue projection,避免开放任务继续携带已关闭收入结果。

但系统还不能直接交付完整 Impacted Revenue 金额,因为以下能力尚未落地:

  • Revenue Benchmarks 没有正式 schema、写入 API 和管理 UI;
  • 没有覆盖 7 个 revenue mapping 的统一、严格 read contract;
  • 没有金额归因快照或可重算 ledger;
  • 缺少 billing / POS / CRM 等权威收入事实;
  • retention 还没有独立 V3 Managed Policy;
  • 历史 Legacy Task 与 V3 Outcome 的归因边界尚未统一;
  • Dashboard 当前的 V3 proof query 只覆盖 membership conversion,且默认关闭。

因此 V1 应展示 Estimated Impacted RevenueEstimated Influenced Revenue,不能把 benchmark 估算称为实际收入、已确认收入或系统独立创造的收入。


二、为什么 V3 不再按 closeResult 直接计算

旧设计将 Task 的 close_result 直接映射为金额。这个做法在 V3 中不再可靠:

  1. close_result 是跨 Task 类型共享的 Legacy compatibility vocabulary,不能完整表达每种业务目标的终态语义;
  2. 某些 V3 结果向 Legacy 投影时是有损的,例如 payment_restored 会兼容映射为 close_result = 'other'
  3. 同一个 Legacy close_result 可能来自不同 Task Policy,不能据此推断收入类型;
  4. V3 要求业务结果、验证强度、证据和 Policy version 同时成立,不能只相信一个标签;
  5. reopen 后旧结果必须失效,单独统计历史 close_result 容易重复计入。

V3 的归因入口应当是:

Task Policy
  → accepted terminal Outcome
  → evidence + verification accepted
  → revenue_mapping_code
  → benchmark definition version
  → estimated impacted revenue

revenue_mapping_code 是 Policy Catalog 控制的收入投影键,不由前端、AI 或调用方自由填写。代码根据已注册 Policy 和 Outcome 校验后写入数据库。


三、当前 Task 分类与收入映射

3.1 当前 10 种 type_category

type_category 是兼容展示、API 筛选、Calendar 和报表使用的分类字段。当前权威集合共 10 种:

Workstreamtype_categoryV1 是否直接形成 Revenue Outcome说明
Lead Funnellead_outreach首次联系工作本身不是收入结果
Lead Funnellead_follow_up跟进过程本身不是收入结果
Lead Funnelbooked_not_converted最终转换为会员时计入 conversion
Member Carecancellation_riskV3 cancellation_request 的兼容分类
Member Careretention暂不计入尚无独立 V3 Managed Policy 和严格观察期 contract
Member Carerenewal包括续约和可证明的 freeze-return continuity
Member Carepayment_recovery已是独立、真实的分类,不再借用 renewal
Revenue Growthwin_back前会员重新激活
Revenue Growthupgrade会员升级增量
Revenue Growthreferral合格 referral 被捕获;后续是否转化需单独定义

lead_outreachlead_follow_upbooked_not_converted 在 V3 中属于同一 lead_conversion Objective family 的不同 display stage。收入不能在 booked 或普通 follow-up 阶段提前确认,只有 converted Outcome 才能写 membership_conversion

3.2 当前 7 个受控 revenueMappingCode

revenueMappingCodeV3 task_kind正向 result_codeLegacy close_result收入语义
membership_conversionlead_conversionconvertedconverted,lossless新会员转化 MRR
cancellation_savecancellation_requestcancel_savedcancel_saved,lossless避免取消 MRR
payment_recoverypayment_recoverypayment_restoredother,lossy支付连续性恢复 MRR
renewal_retentionrenewalrenewedrenewed,lossless续约或冻结回归 MRR
membership_upgradeupgradeupgradedupgraded,lossless会员升级增量 MRR
member_reactivationwin_backwon_backwon_back,lossless前会员重新激活 MRR
qualified_referralreferralreferral_capturedreferral_obtained,lossless合格 referral 价值;不是自动等同会员收入

Policy Catalog 当前没有 promotion_convertedevent_signed_up 或独立 complaint_resolved revenue mapping。它们不能在 V1 查询层临时通过字符串判断补出,否则会绕过 Policy Guard。


四、当前数据库设计

4.1 tasks 当前已有的 V3 Outcome 字段

字段作用Impacted Revenue 用法
store_id当前唯一的数据隔离键所有 benchmark、查询和聚合必须按 store 授权与隔离
tenant_id多租户演进预留当前 nullable,不可替代 store_id 做隔离
task_modemanaged / flexible 等模式V1 仅接受已注册 Managed Policy 的 Outcome
task_kindV3 业务目标类型解析对应 Policy
display_type当前展示/兼容类型UI 分组使用,不作为收入事实来源
creation_policy_version创建时 Policy 版本证明 Task 身份是否合法
result_codeTask-kind-specific terminal result必须与 Policy Outcome 匹配
closure_reason_code为什么终止区分 goal achieved、customer declined、compliance stop 等
outcome_verification_type结果验证方式控制哪些结果可进入估算
outcome_evidence_refs支撑结果的 typed evidence审计、drilldown 和 proof query 使用
outcome_occurred_at业务结果实际发生时间收入报表的时间归属,不能用操作关闭时间替代
closed_atTask 被关闭的操作时间仅用于 lifecycle;业务时间缺失时必须单列 coverage
closed_by_typestaff / ai / system / import区分结果来源和 attribution eligibility
closed_by_subject_id关闭主体身份员工 credit 和审计使用
outcome_policy_version接受 Outcome 的 Policy 版本重算和历史定义解释必须保留
revenue_mapping_codeterminal revenue projection keyImpacted Revenue 的主要分类键
aggregate_version乐观并发版本proof contract 和幂等审计使用
close_resultLegacy compatibility projection只用于兼容,不应作为 V3 金额主键
close_typeLegacy auto/manual/create_closed不能单独证明收入真实发生

4.2 当前写入逻辑

V3 Outcome 的写入不是调用方自由更新字段,而是:

  1. 调用方提交结构化 Outcome;
  2. Policy Catalog 根据 task_kind + policy_version 解析合法结果;
  3. 代码校验 result_code、closure reason、verification type、completed fact 和 note requirement;
  4. 证据解析和 store authorization 通过;
  5. mutation kernel 原子更新 Task snapshot 并写 timeline / receipt;
  6. revenue_mapping_code 从 Policy Outcome 复制到 Task,而不是信任外部输入;
  7. reopen 时清除 terminal outcome 和 revenue_mapping_code,防止旧结果继续计入。

这套设计符合系统世界观:AI 可以提出结果,但最终接受结果、写库和收入投影的是受控代码。

4.3 当前配置基础

store_config 当前已有:

  • store_id 主键;
  • pricing JSONB,默认 {}
  • updated_at

pricing 目前只被描述为 membership tiers、intro offers、class packs 等价格配置,Revenue Benchmarks 没有正式 typed schema、校验、版本或计算接线。不能假设其中已经存在 customerAvgPrice 等字段。

4.4 当前 reporting 基础

Dashboard Multi-store API 已有一套 Task V3 Outcome proof query,但当前边界是:

  • 只覆盖 lead_conversion.v1membership_conversion
  • 只接受严格、evidence-backed、Staff-confirmed 的 conversion bundle;
  • 使用 outcome_occurred_at 作为业务时间;
  • 把 unknown business time 和 rejected candidates 分开暴露,不能静默丢弃;
  • 默认由 TASK_V3_OUTCOME_REPORTING_ENABLED 关闭,当前未通过 CDK 接线;
  • contract 明确声明 causal attribution 尚未建立;
  • 没有 billing / POS truth 时,不返回 revenue amount。

因此当前 proof query 是 Impacted Revenue 的验证模板,不是已经完成的收入模块。


五、V1 指标定义

5.1 三层事实必须分开

层级含义UI 建议措辞
Outcome Count有证据支持的业务结果次数Verified outcomes
Estimated Impact按配置 benchmark 估算的业务影响Estimated Impacted Revenue
Confirmed Revenue来自 billing / POS / CRM 的真实金额Confirmed Revenue

V1 只有前两层。没有权威外部收入事实时,不得把 estimated amount 展示成 Confirmed Revenue。

5.2 基本计算单位

一个可计入的 attribution unit 是一个 accepted terminal Task Outcome,必须同时满足:

status = closed
AND task_mode = managed
AND task_kind / policy version 已注册
AND result_code 与 Policy Outcome 一致
AND revenue_mapping_code 与 Policy Outcome 一致
AND outcome_verification_type 在该 Outcome allowlist 内
AND outcome_evidence_refs 通过 proof contract
AND outcome_occurred_at 位于查询业务时间范围
AND 当前 snapshot 未被 reopen 或更正为非收入结果

Task 的 closed_at 只表示工作人员何时完成操作,不能代替 outcome_occurred_at。缺少业务时间的候选必须进入 unknownBusinessTimeOutcomes,不能按 closed_at 悄悄计入。

5.3 推荐 V1 Benchmarks

以下配置是估算参数,不是数据库当前已有事实:

配置键默认值单位用途
customerAvgMonthlyPrice149USD / person / monthconversion、cancel save、renewal、win-back、payment recovery
upgradeAvgMonthlyIncrement40USD / person / monthmembership upgrade
paymentRecoveryCoefficient0.75ratio排除一部分自然重试恢复
renewalRetentionCoefficient1.00ratio普通续约默认全额;freeze-return 可另设子规则
freezeRecoveryCoefficient0.70ratio仅在证据能识别 freeze-return 时使用
qualifiedReferralEstimatedValue待定USD / referralreferral 尚未等同真实会员转化
currencyUSDISO 4217金额展示与跨地区扩展

如果无法可靠区分普通 renewal 和 freeze recovery,V1 不应对所有 renewal_retention 一律乘 0.70。应先统一使用 renewal coefficient,或者将 freeze-return 作为经过 Policy 授权的 subtype / evidence attribute 后再拆分。

5.4 计算公式

设:

  • N(code) 为查询窗口内满足 proof contract 的唯一 Outcome 数量;
  • P 为配置的平均月费;
  • U 为平均升级月增量;
  • C(code) 为 attribution coefficient;
  • R 为 qualified referral 的估算价值。

则:

Membership Conversion MRR
  = N(membership_conversion) × P

Cancellation Save MRR
  = N(cancellation_save) × P

Payment Recovery MRR
  = N(payment_recovery) × P × C(payment_recovery)

Renewal Retention MRR
  = N(renewal_retention) × P × C(renewal_retention)

Membership Upgrade MRR
  = N(membership_upgrade) × U

Member Reactivation MRR
  = N(member_reactivation) × P

Qualified Referral Estimated Value
  = N(qualified_referral) × R
Estimated Impacted MRR
  = Conversion MRR
  + Cancellation Save MRR
  + Payment Recovery MRR
  + Renewal Retention MRR
  + Membership Upgrade MRR
  + Member Reactivation MRR

Referral 建议作为独立的 Estimated Pipeline Value 展示,不默认混入 MRR。只有 referral 对应的人后来产生独立、权威的 membership conversion,并且建立防重复的 identity link 后,才能把真实转化收入归入 Confirmed Revenue。

5.5 年化显示

如果产品需要 Estimated Annual Impact:

Estimated Annualized Impact = Estimated Impacted MRR × 12

它只是年化 run-rate,不代表已经实现 12 个月收入。UI 必须标注 Annualized estimate,不能显示为年度已实现收入。


六、去重、时间和更正规则

6.1 去重键

V1 不应简单 COUNT(*)。最低要求是按当前 Task terminal snapshot 去重:

store_id + task_id + aggregate_version + revenue_mapping_code

如果未来引入历史 Outcome ledger,应使用稳定的 outcome_id 或 command receipt identity,确保同一个 close command 重试不会重复计入。

6.2 reopen

Task reopen 后:

  • 当前 snapshot 的 result_code、Outcome proof 和 revenue_mapping_code 必须失效;
  • Current-state dashboard 不再计入旧结果;
  • 历史 ledger 可以保留原归因记录,但必须标记 reversed / superseded;
  • 重新关闭并产生新 Outcome 时,生成新的 attribution event。

6.3 Outcome correction

如果员工或更强证据更正 Outcome:

  • 不覆盖历史归因事实;
  • 写 reversal 或 superseding attribution event;
  • Dashboard current view 使用最新有效版本;
  • Audit view 能解释金额为什么减少、消失或改变类别。

6.4 查询时间

收入 Outcome 按 outcome_occurred_at 进入业务窗口。以下时间不能混用:

  • created_at:Task 创建时间;
  • closed_at:系统操作关闭时间;
  • outcome_occurred_at:业务结果实际发生时间;
  • attribution snapshot calculated_at:金额计算时间。

6.5 Store 和 currency

  • 查询、benchmark 和 attribution record 都必须带 store_id
  • 当前隔离不能只依赖 tenant_id
  • currency 必须来自 store benchmark snapshot,不应由浏览器 locale 推断;
  • 多店汇总只有在 currency 一致或完成明确 FX conversion 后才能求和。

七、建议新增的数据模型

7.1 Revenue Benchmark 配置

短期可以扩展 store_config.pricing,但必须添加 typed schema 和版本;长期建议拆成独立配置对象。推荐逻辑结构:

{
  "revenueBenchmarks": {
    "definitionVersion": "task-revenue.v1",
    "currency": "USD",
    "customerAvgMonthlyPrice": 149,
    "upgradeAvgMonthlyIncrement": 40,
    "paymentRecoveryCoefficient": 0.75,
    "renewalRetentionCoefficient": 1,
    "freezeRecoveryCoefficient": 0.7,
    "qualifiedReferralEstimatedValue": null
  }
}

要求:

  • API 对金额、比例、currency 和 definition version 做严格校验;
  • coefficient 范围为 0 到 1;
  • 金额使用 decimal / integer cents,避免 JavaScript float 作为账务存储;
  • 更新 benchmark 不应悄悄改变历史报表而无法解释。

7.2 Attribution Ledger

如果只做实时估算,可以由 API 查询时计算;但为了审计、历史可解释和 benchmark versioning,推荐新增 append-only ledger,例如 task_revenue_attributions

字段说明
idattribution UUID
store_id强制隔离键
tenant_idnullable 演进字段
task_id来源 Task
task_aggregate_version接受 Outcome 时的版本
task_kindPolicy identity
result_codeterminal result
revenue_mapping_code收入映射分类
outcome_occurred_at业务发生时间
outcome_verification_type证明强度
outcome_evidence_refs证明引用快照
benchmark_definition_version计算规则版本
benchmark_snapshot当时使用的价格和 coefficient
amount_minor最小货币单位金额
currencyISO 4217
revenue_periodmonthly_recurring / one_time / pipeline_estimate
calculation_statusestimated / confirmed / reversed / superseded
supersedes_id更正链
calculated_at计算时间

这个 ledger 不能由 AI 直接写入。它由受控 reporting / attribution service 根据 accepted Outcome 和 benchmark definition 生成。

7.3 为什么不能只存最终金额

只在 Task 上存一个 impacted_revenue 数字会丢失:

  • 使用了哪个 benchmark 版本;
  • 为什么乘某个 coefficient;
  • 是否来自 estimate 或真实 billing;
  • reopen / correction 后如何反转;
  • 多币种如何解释;
  • 历史报表为何变化。

Task 保存业务结果,Attribution Ledger 保存对该结果的一次可解释金额投影,两者职责应分开。


八、API 与 Dashboard 建议

8.1 API 返回结构

推荐新增独立 endpoint,而不是扩展 Legacy close-result counters:

{
  "data": {
    "availability": "estimated",
    "definitionVersion": "task-revenue.v1",
    "currency": "USD",
    "estimatedImpactedMrr": 596,
    "annualizedEstimate": 7152,
    "pipelineEstimatedValue": 0,
    "byMappingCode": [],
    "coverage": {
      "candidateOutcomes": 8,
      "acceptedOutcomes": 6,
      "unknownBusinessTimeOutcomes": 1,
      "rejectedOutcomes": 1,
      "missingBenchmarkOutcomes": 0
    }
  }
}

availability 至少区分:

  • disabled:功能未开启,金额必须为 null,不能伪装成 0;
  • unconfigured:没有可用 benchmark;
  • estimated:有 proof 和 benchmark,可提供估算;
  • confirmed:未来接入权威收入事实后的状态。

8.2 Dashboard UI

推荐展示:

  • Estimated Impacted MRR
  • Annualized estimate
  • 按 revenue mapping 分类的 breakdown;
  • Outcome count;
  • coverage / evidence quality;
  • benchmark 来源和最后更新时间;
  • tooltip 明确公式和 coefficient;
  • drilldown 到具体 Task、Outcome time 和证据。

不推荐展示:

  • 没有 EstimatedInfluenced 限定词的 Revenue
  • 把 disabled / unknown 显示为 $0
  • closed_at 填补未知业务时间;
  • 把 qualified referral 直接算作会员 MRR;
  • close_type = auto_closed 当成 AI 已证明收入;
  • 隐藏 rejected 或 missing-evidence candidates。

九、Legacy 数据策略

Legacy Task 可能只有:

  • type_category
  • close_result
  • close_type
  • closed_at
  • 缺少 result_code、verification、evidence 或 outcome_occurred_at

这些记录不能自动升级为 V3 verified revenue。建议:

数据质量处理
完整 V3 Outcome proof进入 Estimated Impacted Revenue
lossless Legacy projection,但缺证据单列 legacyEstimated,默认不混入主 KPI
lossy mapping,例如 payment restored → other不可根据 close_result 反推收入
缺业务时间进入 unknown-time coverage
Policy identity 不明rejected / needs review,绝不静默丢弃

如果产品必须在上线初期展示历史趋势,应给 Legacy estimate 独立 definition version 和明显标签,不能与 V3 evidence-backed amount 混成一个数字。


十、当前还缺什么

P0:定义与事实边界

  • 决定产品名称:Estimated Impacted RevenueEstimated Influenced Revenue
  • 确认 7 个 revenueMappingCode 的 V1 金额公式;
  • 确认 referral 是 pipeline value 还是暂不估值;
  • 决定 renewal 与 freeze-return 是否需要拆分 subtype;
  • 明确 retention 在 V1 中暂不计入,还是先建设独立 V3 Policy;
  • 明确 Benchmark 更新后历史数据是重算还是保留 snapshot。

P1:后端能力

  • Revenue Benchmark typed schema、migration、API 和权限;
  • 7 类 Outcome 的统一 proof contract;
  • attribution calculation module;
  • coverage、rejected、unknown-time 查询;
  • 幂等与 correction / reopen reversal;
  • store / currency aggregation guard;
  • API contract tests 和 PostgreSQL integration tests。

P2:数据与产品

  • Dashboard KPI、breakdown、tooltip 和 drilldown;
  • Rules → Revenue Benchmarks 配置 UI;
  • benchmark audit history;
  • Legacy 数据覆盖率展示;
  • feature flag 和 staged rollout;
  • 指标 telemetry,监控 candidate、accepted、rejected 和 missing benchmark。

P3:Confirmed Revenue

  • 接入 billing / POS / CRM 权威结果;
  • external transaction identity 与 Task Outcome 的 linkage;
  • 实际金额、退款、降级、chargeback 和取消的调整 ledger;
  • estimate 与 confirmed 的 variance 分析;
  • 用本店历史事实逐步校准 attribution coefficient。

十一、推荐实施顺序

Phase 1:只交付可信 Outcome Counts

  1. 把 membership conversion 现有 proof query 扩展为 7 个 mapping 的统一 contract;
  2. 保留 candidate / accepted / rejected / unknown time coverage;
  3. 暂不计算金额;
  4. 验证每种 Policy 的真实生产数据覆盖率。

Phase 2:Estimated Impacted Revenue

  1. 上线 store-level Revenue Benchmarks;
  2. 生成 definition-versioned estimates;
  3. Dashboard 展示 Estimated MRR 和 breakdown;
  4. referral 独立展示 pipeline value;
  5. feature flag 灰度开启。

Phase 3:Attribution Ledger

  1. 引入 append-only attribution ledger;
  2. 支持 benchmark snapshot、reopen reversal 和 correction;
  3. 支持稳定历史报表和审计 drilldown。

Phase 4:Confirmed Revenue

  1. 接入权威 billing / POS / CRM;
  2. 建立 estimate → confirmed linkage;
  3. 展示 confirmed amount 与 attribution confidence;
  4. 用本店数据训练动态 coefficient,但仍由代码控制版本和边界。

十二、验收不变量

实现时至少固定以下不变量:

  1. 未注册的 task_kind、Policy version、result code 或 revenue mapping 必须 fail closed;
  2. revenue_mapping_code 只能来自 Policy Catalog,不能信任前端或 AI 自报;
  3. 没有 evidence-backed Outcome 时金额不可进入主 KPI;
  4. 未知 outcome_occurred_at 不得用 closed_at 静默代替;
  5. disabled / unavailable 必须返回 null,不能返回伪零;
  6. reopen 或 Outcome correction 不得产生重复收入;
  7. rejected、unknown-time、missing-benchmark 必须可见,不能静默丢弃;
  8. 所有读写按授权 store_id 隔离;
  9. benchmark 更新必须可追溯到 definition version 或 snapshot;
  10. estimated、pipeline value 和 confirmed revenue 必须在 API 与 UI 中分开;
  11. qualification activity、Outcome credit 和 revenue amount 是三个不同概念;
  12. AI 只能提出结构化 Outcome,Policy Guard 和受控代码决定是否接受及如何归因。

十三、与旧文档的关键 Crosswalk

旧文档概念V3 建议
converted closeResultresult_code = converted + revenue_mapping_code = membership_conversion
upgraded closeResultresult_code = upgraded + revenue_mapping_code = membership_upgrade
cancel_saved closeResultresult_code = cancel_saved + revenue_mapping_code = cancellation_save
win_back closeResultresult_code = won_back + revenue_mapping_code = member_reactivation
payment_recovered当前 V3 为 payment_restored + payment_recovery
freeze_recovered当前需由 renewed + evidence/subtype 区分,不能只看 Legacy closeResult
complaint_resolved当前 Legacy 更接近 issue_resolved,但缺独立 retention V3 Policy 与观察期 contract
promotion_converted当前 taxonomy / Policy Catalog 无对应项,V1 不实现
event_signed_up当前 taxonomy / Policy Catalog 无对应项,V1 不实现
关闭时实时按 closeResult 算金额按 accepted V3 Outcome + mapping + benchmark version 估算
Dashboard Impacted Revenue分为 Outcome Count、Estimated Impact 和未来 Confirmed Revenue

十四、最终原则

Task V3 Impacted Revenue 不是“给每种关闭原因贴一个价格”,而是:

系统接受了一个有证据、可审计、发生时间明确的业务结果;Policy Catalog 将该结果投影到受控的收入类型;Attribution 模块再按当时生效的 benchmark definition 生成可解释的估算。

这个边界确保:

  • Task 仍然是业务目标和执行事实,不变成金额杂项表;
  • AI 不直接决定收入;
  • Legacy 兼容字段不会污染 V3 truth;
  • 未知和拒绝不会静默消失;
  • 未来接入真实 billing 后,可以从 estimate 平滑演进到 confirmed,而不需要推翻现有模型。