games-development-ai/docs/agent-specs/_archive/2026-06-09-B4四链路烟测报告.md
zizi 7f24a344d0 docs(agent-specs): B2 归档——64 个闭线工作记录移入 _archive/,热目录顶层 90→26
承接目录治理:上轮只压缩内容未减文件数,闭线工作记录仍平铺致目录看着仍一堆(创始人指出)。本次执行 B2 归档。

64 个 ≤06-15 闭线档(25 压缩桩 + 闭线 review/report/纪要/edit-plan)git mv 入 docs/agent-specs/_archive/(文件名不变、仍 git 跟踪可查)。热目录 ≤06-15 仅留 13 活档(决策/纲领/SoT/活spike)+13 个 06-16 在飞。

活资产 20 处旧路径引用(.agents/docs/memory/_index)同步改 _archive/,引用断裂复测=0;_index 活地图 + 治理档状态收口。约束:0 个 06-16 被移、orchestrator 等未跟踪在飞档零误纳。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 13:26:19 +00:00

14 KiB
Raw Blame History

B4 四链路(广告/收益/分享/互动)staging 烟测登记

日期:2026-06-09 | 执行:测试工程师 subagent | 目标环境:staging(mini-desktop, http://100.64.0.7:48080) 目的:给 MVP 总账一份「真实/桩」的诚实清册,不修代码、不下结论性承诺。 判据:HTTP 200 ∧ body.code==0 ∧ 结构合理 = 通;受控业务错误码精确命中 = 链路活但按设计拒绝。 写库纪律:全程零业务写入,唯一例外为 2 条 telemetry 测试事件(eventId 前缀 b4smoke-,已留清理 SQL,见 §6)。


1. 结论速览(总表)

链路 判定 一句话
广告 部分真实 后端计费链(幂等/归因/落账/合规闸门/T+1 对账锚点)真实,但计价与激励校验是 mock SPI、staging 0 个广告位、前端完全未接后端计费 API(宿主桩弹层自产自销)
收益 部分真实 账户原子账本/提现状态机/80% 分成结算代码真实且幂等,但打款是 mock 状态机、结算 Job 在 staging 被关闭(xxl.job.enabled=false)永不运行、前端无收益页入口、全链路 0 数据
分享 部分真实 端点活:发布门禁真实(project.status==4)、utm_source 渠道归因真实、versionId 回填真实;但 OG 标题/封面/描述=空串桩、分享域名写死占位 https://wanxiang.ai/s/
互动 部分真实(排序权重路径=已证,走 telemetry) interact 幂等落库+聚合计数回显真实、前端 InteractBar 已接线;但 interact 信号未接排序权重(排序的 like/share 权重实际来自 telemetry 事件,B2 已证+本次复证)、举报转 compliance 是占位日志、互动态回显恒 false

staging 数据现状(只读核查,烟测前后均如此,证明探针零污染):

ad_slot=0  ad_revenue=0  trade_account=0  trade_income=0  trade_withdraw=0  interact_log=0

即:四条链路在 staging 从未被真实使用过(对比:feed/telemetry 主链路 B1/B2 已有数据)。


2. 路径发现方法

  • 模块定位:game-cloud/game-module-ad(广告)、game-module-trade(收益/分成/提现)、game-module-feed(分享+互动)、game-module-telemetry(互动遥测口径)。
  • app 侧前缀:/app-api 由框架按包名 controller.app.* 自动添加(各 controller 头注释自述,如 AdController.java:28;并经本次 curl 实测证实路径可达)。
  • Flyway V6(ad)/V7(trade)/V10 均无 INSERT 种子(grep 实证)→ 广告位等运营数据需人工配置,staging 没人配过。

3. 各链路详情

3.1 广告链路(game-module-ad)

端点烟测表

# 路径 方法 HTTP code 判定 证据
1 /app-api/ad/slot/list-enabled GET 200 0 真实(但空配置) 实测 {"code":0,"data":[]};DB game_ad_slot=0 行;AdSlotService 真查库(AdController.java:48-51)
2 /app-api/ad/report/impression POST(假 slotId 探针,零写) 200 1111002000 部分真实 实测精确命中 AD_REPORT_SLOT_DISABLED(ErrorCodeConstants.java:27),证明 路由→VO 校验→Service→slot 查库 全链活;计费核心见下
3 /app-api/ad/report/reward POST(同上探针) 200 1111002000 部分真实 同上,同走 bill() 计费核心

真伪判读(源码亲核)

  • 真实部分:计费核心 bill() = slot 校验→合规闸门→(traceId,eventType) 幂等先查+DuplicateKeyException 并发兜底→gameId 经 ProjectApi 反查创作者归因→落 game_ad_revenue 台账(settle_status=0,statDate=今日)——AdRevenueServiceImpl.java:108-171。结算回标幂等 0→1(同文件 179-188)。
  • 桩部分:
    • 计价 mock:唯一 provider 是 MockAdProvider,calcRevenue = ecpmFloor/1000 整除(MockAdProvider.java:29-35),verifyReward() 恒 true(同文件 38-41);工厂对未注册 provider(csj/gdt)一律降级 mock(AdProviderFactory.java:41-44)。
    • 合规桩:isMinor() 恒 false、currentSessionCount() 恒 0(AdComplianceChecker.java:60-75,注释自述「MVP 对接点」)。
  • 前端断链(亲核):game-studio 无 src/api/ad.ts(api 目录仅 aigc/feed/project/runtime/telemetry);宿主侧广告是桩弹层——GamePlayer.vue:12「ad/pay 桩弹层:点击模拟激励视频/支付,回调 rewarded:true」、:315-336 模拟看完直接回 rewarded:true,不调 /ad/report/* 也不拉 /ad/slot/list-enabled。即后端计费 API 真实可用但当前无任何调用方。

3.2 收益链路(game-module-trade)

端点烟测表

# 路径 方法 HTTP code 判定 证据
4 /app-api/trade/income/page GET 200 0 真实(0 数据) 实测 {"code":0,"data":{"total":0,"list":[]}};真实分页查 game_trade_income(IncomeServiceImpl.java:94-96,userId 边界强制)
5 /app-api/trade/withdraw/page GET 200 0 真实(0 数据) 实测同上结构;WithdrawServiceImpl.java:161-163
6 /app-api/trade/withdraw/apply POST(amount=1 门槛探针,零写) 200 1106002000 真实 精确命中 TRADE_WITHDRAW_BELOW_MIN;门槛校验先于一切写入(WithdrawServiceImpl.java:70-72,Nacos trade.withdraw-min 默认 500 分),实证未写库
7 /app-api/trade/account/mine GET 未实测 — 真实(代码判读) 有写副作用故未实测:首查即建零值账户(AccountServiceImpl.java:33-58 getOrInitAccount),为守住「不写库」纪律跳过;同 controller 其余端点已证路由与鉴权通

真伪判读(源码亲核)

  • 真实部分:
    • 账户原子账本:余额增减全部下沉行级 UPDATE(SET balance=balance±? WHERE balance>=?),0 行=余额不足防超扣(AccountServiceImpl.java 头注释 17-21 + freeze 72-78)。
    • 提现状态机:insert(uk_biz_no 幂等)+freeze 同事务、审核 CAS 流转防二次发钱/退款(WithdrawServiceImpl.java:66-106、109-158)。
    • 分成结算:T+1 拉 ad 未结算台账→逐笔 uk_source 幂等入账(net=gross×Nacos trade.creator-share 默认 0.80,BigDecimal 向下取整)→先入账后回标+补偿(SettlementServiceImpl.java:54-89;IncomeServiceImpl.java:40-91)。
  • 桩/休眠部分:
    • 打款 mock:审核通过即 1→2「已打款」纯状态翻转,channel=mock,无真实支付渠道(WithdrawServiceImpl.java:44-45、126-135)。
    • 结算调度休眠:唯一触发器是 XXL-Job tradeSettlementJob(SettlementJob.java:39),admin 控制器无手动结算端点(TradeAdminController 仅 withdraw/audit/income/report 四端点,grep 实证);而 staging xxl.job.enabled: false(application-staging.yaml:90-92)且 docker 仅 mysql+redis 两容器(实测 docker ps)→ 即使广告计了费,钱也永远到不了创作者账户。
    • 前端无入口:game-studio 无 src/api/trade.ts,无收益/提现页面。

3.3 分享链路(game-module-feed · share)

端点烟测表

# 路径 方法 HTTP code 判定 证据
8 /app-api/feed/share/9001?channel=wechat GET 200 0 部分真实 实测 data={gameId:9001, shareUrl:"https://wanxiang.ai/s/9001?utm_source=wechat", ogTitle:"", ogImage:"", ogDescription:"", channel:"wechat", versionId:9001} —— OG 三字段空串是桩的活体证据
9 /app-api/feed/share/999999 GET(未发布探针) 200 1103002001 真实 精确命中 FEED_SHARE_GAME_NOT_PUBLISHED,发布门禁生效

真伪判读(源码亲核)

  • 真实部分:发布门禁经 ProjectApi 读 status 仅 PUBLISHED(4) 放行(FeedServiceImpl.java:477-482);utm_source 渠道归因拼接(:462-466);versionId 经 ProjectApi 回填供落地页直达即玩(:261-264、278-284)。
  • 桩部分:ogTitle/ogImage/ogDescription 写死空串,TODO 待对接 project 本体元信息(FeedServiceImpl.java:257-260);分享域名写死占位 https://wanxiang.ai/s/,TODO 待 Nacos 化(:463-464),该域名可达性/备案未验证。
  • 前端入口:已接线(game-studio src/api/feed.ts:73-79 getShareMeta + src/views/share/Share.vue),属 B2′ 已跑通的前端面。
  • 与 B2 的关系:B2 实证的是「share 遥测事件 → share_count → quality_score」;本链路是「分享落地页元数据生成」,两者独立、互不替代。

3.4 互动链路(game-module-feed · interact + telemetry 口径)

端点烟测表

# 路径 方法 HTTP code 判定 证据
10 /app-api/feed/interact POST(action=99 非法探针,零写) 200 1103001000 部分真实 精确命中 FEED_INTERACT_ACTION_INVALID(校验先于写入,FeedServiceImpl.java:195-198),链路活且实证未写库(interact_log 测后仍 0)
11 /app-api/telemetry/events/batch POST(b4smoke- like+share 各 1 条,任务豁免写入) 200 0 已证 实测 {"code":0,"data":{"accepted":2,"rejected":0}};落库核验:game_telemetry_event 两行 process_status=1;game_telemetry_game_stat gameId=9002 当日 like_count=1、share_count=1 —— B2 链路复证成功

真伪判读(源码亲核)

  • 真实部分:interact = 动作枚举校验(1 赞 2 藏 3 享 4 报,FeedActionEnum.java:22-25)→ 幂等 upsert game_feed_interact_log(命中唯一键翻转 active,可取消语义正确)→ 聚合计数回显(FeedServiceImpl.java:193-241)。前端已接线:src/api/feed.ts:60-65 + src/components/InteractBar.vue。
  • 桩/缺失部分:
    • 未接排序权重:FeedInteractLogMapper 仅 feed 模块内部使用(全仓 grep 实证,消费方只有 FeedServiceImpl/FeedConvert);controller 宣称「点赞/收藏/分享/举报 → 排序权重」(AppFeedController.java:64)名不副实——排序的 like/share 权重实际来自 telemetry 事件聚合回灌(EventIngestServiceImpl.java:185-194 计数 → :150-162 QUALITY_REFRESH 回灌 feed_rank)。
    • 举报转 compliance = 占位日志(FeedServiceImpl.java:227-232,TODO 事务内禁远程调用,待 MQ/Feign)。
    • 匿名互动 anon_id = 空串 TODO(:207);feed 流互动态 liked/favorited 回显恒 false(:118 TODO + FeedConvert.java:38)。
  • 「已证」的边界说明:B2 已实证 + 本次 b4smoke 复证的是 telemetry 路径(like/share 事件 → game_stat 计数 → quality_score → feed_rank.sort_score 重排);而 interact 路径(按钮点击 → interact_log → 计数回显)落库真实但只到「回显」为止,不参与排序。staging game_feed_interact_log=0 行也佐证 B2′ 实玩未触发过 interact 写入。

4. 缺口清单(MVP 上线前各链路还缺什么)

广告(上线即赚钱的硬前提全缺)

  1. 前后端断链:game-studio 无 ad API 接线,宿主桩弹层自回调 rewarded:true,不拉广告位、不上报计费 → 后端台账永远 0。
  2. 无真实广告联盟 SPI(穿山甲/优量汇),MockAdProvider 计价=ecpmFloor/1000、激励校验直通——真实接入还有联盟审核闸门(日历闸门)。
  3. 广告位运营数据为零(Flyway 无种子、staging ad_slot=0),需 admin 端配置流程跑一遍。
  4. 未成年识别、单会话频控均为恒放行桩(合规风险,上线前必须接真实信号)。

收益(钱的管道有管无水) 5. T+1 结算调度在 staging 关闭(xxl.job.enabled=false 且无 xxl-job-admin 容器),且无手动触发端点 → 广告收入到创作者账户的链路从未端到端跑通过一次。 6. 打款是 mock 状态机,未接微信/支付宝企业付款(涉及支付资质日历闸门)。 7. 前端无收益/提现页(无 trade.ts),创作者「看见钱」的入口缺失。 8. /trade/account/mine 首查建账的写副作用本次未实测,待一次受控验证。

分享(能分享但分享卡片是白板) 9. OG 标题/封面/描述空串 → 微信/QQ 分享卡片无图无题,传播转化必伤;需对接 project 元信息。 10. 分享域名写死占位 https://wanxiang.ai/s/,未 Nacos 化,域名可达性/备案未验证。

互动(信号进了库但不进排序) 11. interact 信号未接入排序权重,与 controller 文档宣称不符;需决策:要么接通(interact→telemetry 事件或直刷 rank),要么改文档口径承认排序只认 telemetry。 12. 举报→compliance 受理链路未接(占位日志),举报功能存在合规缺口。 13. feed 流互动态回显恒 false:用户刷新后看不到自己点过赞/收藏,体验断点。 14. 匿名互动 anon_id 未透传(未登录用户互动会归到 userId=0)。


5. 烟测覆盖与局限

  • 覆盖:11 个探测中 10 个实测(4 GET + 5 POST + 1 落库核验),1 个因写副作用主动跳过(标注于 §3.2 #7)。
  • 局限:错误路径只探了首个闸门(如 ad 探针停在 slot 校验,未实测归因失败/会话超限分支——已由源码判读补位);admin 侧端点(withdraw/audit、slot 配置)未实测(需 admin 会话且涉写库)。

6. 测试残留物(可清理)

仅 2 条 telemetry 事件 + 1 行当日聚合增量(gameId=9002,2026-06-10 行 like_count/share_count 各 +1):

-- 清理(如需):
DELETE FROM `ruoyi-vue-pro`.game_telemetry_event WHERE event_id LIKE 'b4smoke-%';
-- 聚合行修正(或整行删除当日 9002 行,下次事件会重建):
UPDATE `ruoyi-vue-pro`.game_telemetry_game_stat SET like_count=like_count-1, share_count=share_count-1
 WHERE game_id=9002 AND stat_date='2026-06-10';

其余六张链路表(ad_slot/ad_revenue/trade_account/trade_income/trade_withdraw/interact_log)测前测后均为 0 行,零污染。