Files
Neo-ZQYY/docs/_overview/wave1-findings/F1-6-tasks.md
Neo 32716bc71a feat(backend): F1-6 sprint2 #2 累计消费总额加入 sandbox_replay
新增指标(无 fdw_queries 原查询 + 0 现有调用方 + 无 thin wrapper),沿用
sprint 1/sprint2 #1 模式 @trace_service + @runtime_aware decorator + 显式
stat_date <= ctx.business_date 上界 + dws_member_consumption_summary
.total_consume_amount 字段 items_sum 口径。

双口径数值验证 PASS(member=2799207087163141 黄先生,直接 Python 调用):
- 4a live(today=2026-05-05): get_total_consume_amount=1252.65
- 4b sandbox=2026-04-20: get_total_consume_amount=999.99(walkthrough 测试快照)

unit test sprint1+sprint2 累计 19/19 PASS,无回归。

记录 thin wrapper 决策原则到 spec §5.5(迁移辅助层,非常态架构;
fdw_queries 长远退化纯 ETL 物理访问层,清理放收尾 sprint)。

注:#3 累计交易笔数因 spec §4 字段未明确(dws_order_summary vs
total_visit_count)暂停,等 Neo 决断后继续。

详见 docs/audit/changes/2026-05-06__f1_6_sprint2_total_consume_amount.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 00:52:08 +08:00

7.2 KiB
Raw Blame History

F1-6 沙箱时光机阶段 B 任务清单

创建日期:2026-05-05 (F1-5b 收尾后启动) 完整模块 spec:docs/_overview/sandbox-replay-engine-spec.md 上游:F1-5b 全部完成(commit 5d4da0a)

状态:Sprint 1 已启动并完成,Sprint 2-4 待启动

一、阶段 B 总览

按 sandbox-replay-engine-spec 阶段 B 拆 4 个 sprint:

Sprint 范围 工作量 状态
Sprint 1 框架(sandbox_replay 模块 + runtime_aware decorator) + 1 个试点指标(距上次到店天数迁移) M ~ 4-5h 完成(2026-05-05)
Sprint 2 5 个会员相关 P1 指标(60d 消费 / 累计消费总额 / 累计交易笔数 / 储值卡余额 / 累计 GMV) M ~ 4h 🔄 进行中(#1 60d 消费 2026-05-06)
Sprint 3 5 个助教/门店相关 P1 + MP-2 完整(daily salary 含 ETL 改造) L ~ 8-10h 待启动
Sprint 4 5 个 P2 指标(RS 重算 / 客户黏性 / 任务完成率 / Excel 修正 / 月度新增流失) M-L ~ 6-8h 待启动

二、Sprint 1 收口(2026-05-05)

范围

  1. 建立 apps/backend/app/services/sandbox_replay/ 模块脚手架
  2. 实现 @runtime_aware(metric=...) decorator(自动注入 RuntimeContext)
  3. 试点迁移:get_last_visit_days(距上次到店天数,P1-4)
    • consumption_replay.py 新实现
    • fdw_queries.get_last_visit_days 改 thin wrapper(兼容 75+ 现有调用)
  4. Unit test 10/10 PASS
  5. MCP 端到端 4a/4b 双口径 PASS

关键 bug 发现 + 修复

bug:@trace_service + @runtime_aware 嵌套时,trace_service 的 _build_params_dictinspect.signature(func).bind(*args, **kwargs) 做参数 redact。functools.wraps 默认设置 __wrapped__inspect.signature 追溯到原函数(含 keyword-only 必传 ctx 参数),导致 sig.bind 抛 TypeError: missing a required argument: 'ctx'

只在 FastAPI 请求 + 有活跃 TraceContext 时触发(直接 Python 调用 get_current_trace 返回 None,跳过 _build_params_dict,不复现)。

修复:runtime_aware 的 wrapper 不用 functools.wraps,改用手动复制 __name__/__qualname__/__module__/__doc__,不设 __wrapped__,让 inspect.signature 看到 wrapper 自身 (*args, **kwargs) 签名,sig.bind 永远成功。

双口径验证证据(关键样本)

目标 member: 2799207087163141(黄先生)

维度 4a live (today=2026-05-05) 4b sandbox=2026-04-20
stat_date 数据 2026-05-01 2026-04-15(walkthrough 测试快照)
last_consume_date 2026-04-03 2026-03-20
daysSinceVisit 计算 32 = 05-05 - 04-03 31 = 04-20 - 03-20
API 返回 32 ✓ 31 ✓

测试快照已清理,sandbox 已切回 live。

走查脚本

_DEL/walkthrough_f1_6/:

  • step_sprint1_probe_member.py — 找有 last_consume 的会员
  • step_sprint1_check_view.py — 视图层 RLS 行为
  • step_sprint1_direct_call.py — 直接调 sandbox_replay 函数
  • step_sprint1_repro_etl_conn.py — etl_conn 复用模式
  • step_sprint1_call_service.py — 直接调 customer_service.get_customer_detail
  • step_sprint1_4b_probe.py — sandbox=4-20 视图行为
  • step_sprint1_4b_find_member.py — 找 sandbox 下有数据的 member
  • step_sprint1_4b_stat_dist.py — stat_date 分布
  • step_sprint1_4b_seed_data.py — 插测试快照
  • step_sprint1_cleanup.py — 清理 + 切回 live

Sprint 1 commit

feat(backend): F1-6 sprint1 sandbox_replay 模块脚手架 + get_last_visit_days 迁移试点


三、Sprint 2 范围(进行中)

启动顺序按方案 A:从已有 consumption_replay.py 模块扩展开始,新模块靠后。

5 个会员相关 P1 指标

# 指标 当前实现位置 目标迁移到 复杂度 状态
1 60 天消费 fdw_queries.get_consumption_60d sandbox_replay/consumption_replay.py(扩展) S 2026-05-06(thin wrapper)
2 累计消费总额 (无,新增) sandbox_replay/consumption_replay.py(扩展) S 2026-05-06(无 wrapper,0 调用方)
3 累计交易笔数 (字段未定,需 Neo 决断 dws_order_summary vs total_visit_count) sandbox_replay/consumption_replay.py(扩展) S ⏸️ 暂停(spec §4 字段未明确)
4 会员储值卡余额 fdw_queries.get_member_balance sandbox_replay/balance_replay.py(新建) S 待启动
5 累计 GMV dws_finance_daily_summary.gross_amount(门店级,与现有"区间 GMV"语义不同) sandbox_replay/finance_replay.py(新建) S 待启动

Sprint 2 实施模式

所有指标走 @runtime_aware decorator + app.v_dws_* 视图查询。每个指标:

  • 1 个新函数 to sandbox_replay/
  • 1 个 thin wrapper in fdw_queries.py(兼容)
  • 单元测试(本地不入仓)+ MCP 双口径走查(navigate_to + snapshot + screenshot,含 UI 实地验证)
  • 审计 + 单独 commit

Sprint 2 commit

  • #1 60d 消费 — commit d418621(2026-05-06)
  • #2 累计消费总额 — feat(backend): F1-6 sprint2 #2 累计消费总额加入 sandbox_replay(待提交)
  • #3 累计交易笔数 — 暂停(spec §4 字段未明确,需 Neo 决断 dws_order_summary vs dws_member_consumption_summary.total_visit_count)

估算

5 指标 × 30-50min = 3-4h(#1 实际 ~ 40min)


四、Sprint 3 范围(待启动)

5 个助教/门店相关 P1 + MP-2 完整

# 指标 备注
6 累计服务客户数(助教) dws_assistant_customer_stats daily
7 助教等级 dws_assistant_daily_detail.assistant_level_code
8 月度课时(助教) dws_assistant_daily_detail.base_hours 聚合
9 月度计费金额(助教) dws_assistant_daily_detail.total_ledger_amount 聚合
10 月度新增/流失会员 dws_member_*_summary daily
MP-2 完整 daily salary board-coach 月度面板 需 ETL 团队配合:新建 dws_assistant_daily_salary 表 + ETL Excel 上传 UI 改造

Sprint 3 估算

5 指标 ~ 3-4h + MP-2 完整 5-6h(含 ETL 改造) = L ~ 8-10h


五、Sprint 4 范围(待启动)

5 个 P2 算法重算指标

# 指标 难点
11 RS 关系指数 算法窗口期 + 衰减函数,daily 重算需重做累计
12 客户黏性指数 类似 RS,有时间衰减
13 任务完成率(coach_tasks) 需补 dws daily 聚合视图
14 Excel 修正(扣款/奖励/支出/收入) 依赖 effective_date(F1-5b prep 已就位),后端 SQL 加截断
15 月度新增/流失会员(算法版) dws_member_lifecycle 重算

Sprint 4 估算

M-L ~ 6-8h


六、阶段 C(F1-7+ 远期)

详见 sandbox-replay-engine-spec.md §11.5:

  • 3 个 P3 指标(门店等级 / 助教星级 / 累计 KPI)
  • biz.sandbox_audit_log 用户行为审计表
  • AI app8_consolidate prompt audit

七、关联

  • 完整模块 spec:docs/_overview/sandbox-replay-engine-spec.md
  • F1-5b 任务清单:docs/_overview/wave1-findings/F1-5b-tasks.md
  • F1-5b MP-2 prep 审计:docs/audit/changes/2026-05-05__wave1_f1_5b_mp2_prep.md
  • P20 SPEC §11.4 + §11.5(F1-6 待办登记):docs/prd/specs/P20-runtime-context-sandbox.md
  • Sprint 1 审计:docs/audit/changes/2026-05-05__f1_6_sprint1_sandbox_replay_kickoff.md