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_mode、task_kind、display_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 Revenue 或 Estimated Influenced Revenue,不能把 benchmark 估算称为实际收入、已确认收入或系统独立创造的收入。
二、为什么 V3 不再按 closeResult 直接计算
旧设计将 Task 的 close_result 直接映射为金额。这个做法在 V3 中不再可靠:
close_result是跨 Task 类型共享的 Legacy compatibility vocabulary,不能完整表达每种业务目标的终态语义;- 某些 V3 结果向 Legacy 投影时是有损的,例如
payment_restored会兼容映射为close_result = 'other'; - 同一个 Legacy
close_result可能来自不同 Task Policy,不能据此推断收入类型; - V3 要求业务结果、验证强度、证据和 Policy version 同时成立,不能只相信一个标签;
- reopen 后旧结果必须失效,单独统计历史
close_result容易重复计入。
V3 的归因入口应当是:
revenue_mapping_code 是 Policy Catalog 控制的收入投影键,不由前端、AI 或调用方自由填写。代码根据已注册 Policy 和 Outcome 校验后写入数据库。
三、当前 Task 分类与收入映射
3.1 当前 10 种 type_category
type_category 是兼容展示、API 筛选、Calendar 和报表使用的分类字段。当前权威集合共 10 种:
lead_outreach、lead_follow_up 和 booked_not_converted 在 V3 中属于同一 lead_conversion Objective family 的不同 display stage。收入不能在 booked 或普通 follow-up 阶段提前确认,只有 converted Outcome 才能写 membership_conversion。
3.2 当前 7 个受控 revenueMappingCode
Policy Catalog 当前没有 promotion_converted、event_signed_up 或独立 complaint_resolved revenue mapping。它们不能在 V1 查询层临时通过字符串判断补出,否则会绕过 Policy Guard。
四、当前数据库设计
4.1 tasks 当前已有的 V3 Outcome 字段
4.2 当前写入逻辑
V3 Outcome 的写入不是调用方自由更新字段,而是:
- 调用方提交结构化 Outcome;
- Policy Catalog 根据
task_kind + policy_version解析合法结果; - 代码校验
result_code、closure reason、verification type、completed fact 和 note requirement; - 证据解析和 store authorization 通过;
- mutation kernel 原子更新 Task snapshot 并写 timeline / receipt;
revenue_mapping_code从 Policy Outcome 复制到 Task,而不是信任外部输入;- reopen 时清除 terminal outcome 和
revenue_mapping_code,防止旧结果继续计入。
这套设计符合系统世界观:AI 可以提出结果,但最终接受结果、写库和收入投影的是受控代码。
4.3 当前配置基础
store_config 当前已有:
store_id主键;pricingJSONB,默认{};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.v1的membership_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 三层事实必须分开
V1 只有前两层。没有权威外部收入事实时,不得把 estimated amount 展示成 Confirmed Revenue。
5.2 基本计算单位
一个可计入的 attribution unit 是一个 accepted terminal Task Outcome,必须同时满足:
Task 的 closed_at 只表示工作人员何时完成操作,不能代替 outcome_occurred_at。缺少业务时间的候选必须进入 unknownBusinessTimeOutcomes,不能按 closed_at 悄悄计入。
5.3 推荐 V1 Benchmarks
以下配置是估算参数,不是数据库当前已有事实:
如果无法可靠区分普通 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 的估算价值。
则:
Referral 建议作为独立的 Estimated Pipeline Value 展示,不默认混入 MRR。只有 referral 对应的人后来产生独立、权威的 membership conversion,并且建立防重复的 identity link 后,才能把真实转化收入归入 Confirmed Revenue。
5.5 年化显示
如果产品需要 Estimated Annual Impact:
它只是年化 run-rate,不代表已经实现 12 个月收入。UI 必须标注 Annualized estimate,不能显示为年度已实现收入。
六、去重、时间和更正规则
6.1 去重键
V1 不应简单 COUNT(*)。最低要求是按当前 Task terminal snapshot 去重:
如果未来引入历史 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 和版本;长期建议拆成独立配置对象。推荐逻辑结构:
要求:
- 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:
这个 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:
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 和证据。
不推荐展示:
- 没有
Estimated或Influenced限定词的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。建议:
如果产品必须在上线初期展示历史趋势,应给 Legacy estimate 独立 definition version 和明显标签,不能与 V3 evidence-backed amount 混成一个数字。
十、当前还缺什么
P0:定义与事实边界
- 决定产品名称:
Estimated Impacted Revenue或Estimated 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
- 把 membership conversion 现有 proof query 扩展为 7 个 mapping 的统一 contract;
- 保留 candidate / accepted / rejected / unknown time coverage;
- 暂不计算金额;
- 验证每种 Policy 的真实生产数据覆盖率。
Phase 2:Estimated Impacted Revenue
- 上线 store-level Revenue Benchmarks;
- 生成 definition-versioned estimates;
- Dashboard 展示 Estimated MRR 和 breakdown;
- referral 独立展示 pipeline value;
- feature flag 灰度开启。
Phase 3:Attribution Ledger
- 引入 append-only attribution ledger;
- 支持 benchmark snapshot、reopen reversal 和 correction;
- 支持稳定历史报表和审计 drilldown。
Phase 4:Confirmed Revenue
- 接入权威 billing / POS / CRM;
- 建立 estimate → confirmed linkage;
- 展示 confirmed amount 与 attribution confidence;
- 用本店数据训练动态 coefficient,但仍由代码控制版本和边界。
十二、验收不变量
实现时至少固定以下不变量:
- 未注册的
task_kind、Policy version、result code 或 revenue mapping 必须 fail closed; revenue_mapping_code只能来自 Policy Catalog,不能信任前端或 AI 自报;- 没有 evidence-backed Outcome 时金额不可进入主 KPI;
- 未知
outcome_occurred_at不得用closed_at静默代替; - disabled / unavailable 必须返回
null,不能返回伪零; - reopen 或 Outcome correction 不得产生重复收入;
- rejected、unknown-time、missing-benchmark 必须可见,不能静默丢弃;
- 所有读写按授权
store_id隔离; - benchmark 更新必须可追溯到 definition version 或 snapshot;
- estimated、pipeline value 和 confirmed revenue 必须在 API 与 UI 中分开;
- qualification activity、Outcome credit 和 revenue amount 是三个不同概念;
- AI 只能提出结构化 Outcome,Policy Guard 和受控代码决定是否接受及如何归因。
十三、与旧文档的关键 Crosswalk
十四、最终原则
Task V3 Impacted Revenue 不是“给每种关闭原因贴一个价格”,而是:
系统接受了一个有证据、可审计、发生时间明确的业务结果;Policy Catalog 将该结果投影到受控的收入类型;Attribution 模块再按当时生效的 benchmark definition 生成可解释的估算。
这个边界确保:
- Task 仍然是业务目标和执行事实,不变成金额杂项表;
- AI 不直接决定收入;
- Legacy 兼容字段不会污染 V3 truth;
- 未知和拒绝不会静默消失;
- 未来接入真实 billing 后,可以从 estimate 平滑演进到 confirmed,而不需要推翻现有模型。