A 端 v3 / v4 分期实现现状调研

日期:2026-10-06 | 基线:092612a2 | 状态:⚠️ 本报告已订正,见文末「订正记录」

重要:本报告初版结论为「v3 与 v4 应当是两套独立的东西,但只隔了路由层」。
该前提错误——已订正。设计意图见下。

结论(订正后)

v3 与 v4 从设计起就是「一套后端 + 一个开关键」,不是两套独立系统。

三层命名空间是分期实现的手段,不是隔离缺陷。

真正缺的是:开关键从未落地到线上,以及 entries 键名从方案到代码已漂移。


一、设计意图(方案原文,非推断)

依据:docs/plans/2026-09-27-v3后端缺口与v3v4分期对接方案.md(小冈起草,100 行)

位置原文
§四 标题「v3/v4 分期对接(前端开关驱动,后端单代码库永不分叉)」
§一 事实基线「v4 完全体功能域(分销/福钥/语音导览/护照/零售/路况/评价/心愿单)端点全部已存在——v3 精简是前端可见性子集,不是后端裁剪」
§四 开关载体「content_items 键 v3.featureFlags(JSON),经已建的 config_governance 发布/回滚;C 端 app.ts 启动读一次缓存」
§四 规定形态{"tabs":{"play":false},"entries":{"intel":true,"ferry":true},"pay":{"online":false}}
§四 放开粒度「放开粒度=域,每域三件套:flag 放开 + 该域真机验收 + 回执登记。禁按页碎放」

因此:方案里只有 v3.featureFlags 一个键,不存在 v4.featureFlags。

所谓「v4」= 同一套端点被开关逐步放开后的状态,不是另一套代码。


二、实际实现(客观事实,不含评价)

层命名空间端点出处注释
旧 A 端/api/miniapp/admin/*62「bobo 2026-09-25 攻略录入」「B4·L6 内容录入」「B-026 运营补齐」
v3console/api/admin/v317小齐 10-01「独立命名空间,不改动任何既有端点…阶段 1 纵向样板:首页·主视觉」
后台骨架/api/admin/* 其余81「WIP-242 管理后台后端骨架(阿仁)」=权限/审计+CMS+商户+订单+埋点

实测补充:


三、两个真缺口

缺口 1:开关键线上不存在 ⇒ 全部 fail-open

GET /api/miniapp/content/items?keys=v3.featureFlags
→ {"code":0,"data":{"items":[]}}     # 空

feature_flags.py 明确「缺键/解析失败 = 放行(fail-open)」。

所以线上现状是所有功能开关默认放行——分期机制在运行时根本没生效。

发布链路已建好,可直接用:

miniapp_config_governance —— GET /draft、GET /versions、GET /current、POST /publish、POST /rollback

缺口 2:entries 键名漂移

来源用的 entry
方案 §四(9-27)intel、ferry
代码实际(flag_enabled 仅 2 处调用)growth
方案注释提到intel(无实现点)

调用点仅两处,均为写闸:

⚠️ 后果:若按方案形态原样写入而不含 growth,这两处会从「放行」变成「取默认值」——
属于行为变更,不是配置补齐。

缺口 3:content_items 缺通用写入入口(非 SPEC 内的 key 写不进去)

事实依据
content_items 的通用写入能力只存在于 service 层content_items.py:upsert / upsert_many_checked / save_draft / publish / unpublish / delete
HTTP 层的唯一暴露是 v3console,且 key 是注册制admin_v3console.py 17 端点全是 /pages/home/hero* 与 /blocks/{block_id},key 来自 HERO_FIELD_SPEC / _keys_of(block_id)
⇒ v3.featureFlags 不在任何 SPEC 里,通过 v3console 写不了需改代码注册 SPEC,或直连 service 层
方案 §四 说的「经 config_governance 发布/回滚」指错了模块config_governance 管的是 site_config_versions(brandName/slogan/logoUrl),不是 content_items

实际可用路径(已在 staging 验证可行):

容器内 python - 调 content_items.upsert(),走 service 层,保留乐观锁与审计,不裸连 SQL。

脚本:scripts/set_feature_flags_v3.py(带 --commit 保护)。


四、待落地的初始值(按方案 P1 阶段)

方案 §四 分期表:P1 上线版 = 四 tab 六页(现状),零新增。

{"tabs":{"play":false},"entries":{"growth":true,"intel":false,"ferry":false},"pay":{"online":false}}

五、命名陷阱

代码中搜 V4 大量命中,但绝大多数与 A 端无关:

miniapp_redemption.py 中的 V4 指 2026-10-02 的付款语义 V4(履约态 ≠ 收款态)。

另:featureFlags 在别处还有三套同名但无关的实现——

miniprogram/miniprogram/utils/featureFlags.ts(v2 硬编码)、

b-workbench/src/services/FeatureFlags.ts(B 端)、

miniprogram-v3/utils/release-guard.ts 的 TEST_FLAG_KEY(测试可见性,非本机制)。


订正记录

2026-10-06:本报告初版结论为「v3 与 v4 理论上应是两套独立的东西,但实际只隔了路由层」,

并据此建议「建 v4.featureFlags 做版本隔离」。

该结论错误,原因:未先读 docs/plans/2026-09-27-v3后端缺口与v3v4分期对接方案.md。

方案 §四 标题即写明「后端单代码库永不分叉」,且 §一 明确 v4 功能域端点全部已存在。

方法论:项目内已有方案文档时,必须先读方案再动手——

否则会照着"看起来合理的直觉"造轮子,并在仓库里留下误导后人的错结论。