Commit Graph
5 Commits
Author SHA1 Message Date
joywayerandClaude Opus 4.7 692c849e0d fallback 链头嵌入根(RemoteConfig 顶层):所有 7 字段真正统一,删字段级特殊兜底
【动机】
上一版"统一接口"虽然合并了 resolve / resolveAudio,但 resolve 内部仍有不对称:
- showmessage / audioDomain / audioBucket: pickString(chain) ?? config.xxx
- appVersion / appDownload / gameVersion / gameZip: 只 pickInt/String(chain),
  顶层声明这 4 个字段也读不到

【方案】
- RemoteConfig 加 4 个 String? 字段(appVersion/appDownload/gameVersion/gameZip)
  配齐与节点 struct 同款 7 字段集合
- extension RemoteConfig: RemoteConfigNode(自然 conform)
- buildChain 首行 var chain = [config]:根始终作为最浅一层
- resolve() 去掉 ?? config.xxx 三处特殊兜底,全 7 字段一律 pickString/Int(chain)

【效果】
- 节点链 1..5 长(含根);所有字段一视同仁,pickString 倒序找即天然包含顶层
- 任何字段都可以在顶层 / agent / game / channel / market 任一层声明,最深层赢
- 算法对称、代码无字段级特殊分支

【硬约束(Plan ADR-009 同步)】
新增字段:加进协议 + 5 个 struct(含 RemoteConfig)+ ResolvedVersion +
resolve() 内一行 pickString/Int(chain, \.xxx);不允许 ?? config.xxx 类回退。

BuildProject 通过。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-27 21:38:03 +08:00
joywayerandClaude Opus 4.7 485f0c6679 合并 resolveAudio 进 resolve():所有 RemoteConfig 字段走单一入口 + 同款 4 层 fallback
【动机】
上个 commit 把 audio_domain/audio_bucket 改成 4 层 fallback,但用了独立的
resolveAudio() 入口 —— 与 resolve() 并存意味着调用方要记两个 API,违反
"统一接口"原则。

【方案】
- ResolvedVersion 加 audioDomain / audioBucket 两个字段(扁平结构)
- resolve() 内直接 pickString(chain, \.audioDomain) ?? config.audioDomain 一次解出
- 删除 resolveAudio() 公开入口
- WebContainerViewController parsed 分支:单次 resolve() 调用 + 同一 r 取所有字段

【硬约束(Plan ADR-009 同步)】
远端 RemoteConfig 所有字段必须走 VersionResolver.resolve(...) 单一入口、
同一套 4 层 fallback;新增字段时加进协议 + 节点 struct + ResolvedVersion +
一行 pickString,不允许为某字段单独写 if 链或 helper。

BuildProject 通过。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-27 21:32:57 +08:00
joywayerandClaude Opus 4.7 a54d1511be audio_domain/audio_bucket 改 4 层 fallback + 顶层兜底,修"音频服务不可用"误报
【bug】
ADR-009 初版只从 RemoteConfig 顶层读 audio_domain / audio_bucket,但渠道方
配置时习惯把这俩字段放在 agent 节点(与 app_version / game_zip 等版本字段同
款层级),导致客户端读到空值后误报 BootError.audioConfigMissing 启动期致命。

【方案】
对齐版本字段的 4 层 fallback 算法:
- Agent / Game / Channel / Market 4 个节点 struct 各加 audioDomain / audioBucket
- RemoteConfigNode 协议加这俩 getter
- VersionResolver 新增 resolveAudio(...) → (domain:String?, bucket:String?)
  逻辑:agent → game → channel → market 倒序找第一个非空,整链空时 fallback 顶层
- WebContainerViewController parsed 分支改用 resolveAudio + print 诊断日志

【兼容性】
顶层 audio_domain / audio_bucket 仍然支持(作为整链兜底),后台不需要改配置
位置;放节点上也能读到——任意一种 layout 都工作。

【文档】
Plan ADR-009 决策表 + 注入时序段 同步更新 + 加 2026-06-27 修订说明记录此次踩坑。

BuildProject 通过,Xcode 诊断 clean。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-27 21:30:10 +08:00
joywayerandClaude Opus 4.7 8125dd4d11 1.11 修订:VersionResolver 改单链 4 层 fallback,删除双子树合并算法(契约影响)
【契约影响】
- RemoteConfig 模型:Agent 节点移除 channellist 字段(线上 JSON 实际只挂 gamelist;此前误读 chulishengji 引入的 channellist 是空 schema)
- VersionResolver 解析算法:从"双子树 + 字段级合并"改为"agentlist → gamelist → channellist → marketlist 单链 4 层 fallback",行为按 daoqi NewRootVC.m:689-810 主路径
- 对外 API ResolvedVersion / resolve(config:agentId:channelId:marketId:gameId:) 签名零变化,WebContainerViewController / SubGameViewController 调用点未动

【设计要点】
- 4 节点类型 conform 同一 private protocol RemoteConfigNode
- 5 字段共用 pickString / pickInt 两个倒序 fallback 工具,不允许为某字段单独写 if 链
- buildChain 集中处理"任一层 id 不匹配立刻截断"语义

【文档同步】
- Design §6.3.2 整段重写
- Plan ADR-008 顶部追加"第三轮修订(2026-06-27)"小节 + 第二轮误读复盘
- Plan ADR-008-D 替换为单链 4 层算法说明 + 保留修订史
- Plan §1.11 / ADR-008-I / 最后更新日期 / Verification-Checklist L73 同步

参考契约章节:docs/H5-Native-Implementation-Design.md §6.3.2、docs/Development-Plan.md ADR-008-D
BuildProject 通过。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-27 20:04:19 +08:00
joywayer dfbc26a024 Phase 1.11:VersionResolver chulishengji 双子树合并算法
实现 msext NewRootVC.m:1372-1538 的 chulishengji 双子树合并算法的纯
函数 Swift 版本,把远端 RemoteConfig 化简为 5 个目标字段决策结果
(appVersion / appDownload / gameVersion / gameZip / showmessage)。

- 新增 ylgamehall/Source/Network/VersionResolver.swift
  - public enum VersionResolver + 纯函数 static func resolve
  - public struct ResolvedVersion: Sendable 含 5 字段
  - 内部 SubtreeExtract 中转 4 字段累加结果(每层非空才覆盖)
  - extractAgentSubtree 4 层(agent → channel → market → game 嵌
    market 命中后)按 NewRootVC.m:885-1013 复刻
  - extractGameSubtree 4 层(game → game-self → channel → market)
    按 NewRootVC.m:1015-1180 复刻
  - mergeIPA 默认 agent 赢;game.appVersion > agent.appVersion 时
    game 赢(NewRootVC.m:1416)
  - mergeZip 默认 game 赢;agent.gameVersion > game.gameVersion 时
    agent 赢(NewRootVC.m:1456)
  - showmessage 任意子树非空就用,最后写赢;回退到 config.showmessage
- 字段名 game_download vs game_zip 由 SubtreeExtract.gameZip 统一吸收,
  Codable 模型已用 gameZip 命名,故无需重复查两个 key
- RootViewController 烟雾测试串接 RemoteConfigClient + VersionResolver,
  打印 chulishengji 合并后的 5 字段
- 真机实测(现网 .txt JSON):
  - appVersion = 43 → 等于本地 BundleConfig.appVersion,不触发 IPA 升级
  - gameVersion = 261 → 远端最新版(本地 version.xml 待 Phase 1.12 读取
    后对比;首装后 version.xml 实测 261 等于本地)
  - gameZip = http://tsgames.daoqi88.cn/zip2/gamehall.zip
    (HTTP,Phase 1.13 下载需 ATS NSExceptionDomains daoqi88.cn)
  - appDownload = itms-services://... 企业签 manifest URL
  - showmessage = ""(无运营公告)
- 单测目前未写(等 Phase 0.2 单测 target 建立后补齐),但生产数据
  已验证算法正确
2026-06-22 02:18:27 +08:00