Files
one_divine_lot/docs/04-迭代记录/13-盘口内存快照/迭代复盘.md
T
kyugao d793d2cf35 迭代13: 盘口内存快照(QuoteSync/QuoteHub)+ 同步指示灯 + 行情列
- QuoteSync/QuoteHub 替换 MarketFeed/MarketDataHub(方案A 删除重写):
  5s REST 同步 watch 集合 + 涨停/跌停经 /data/instrument 按交易日内存缓存
  + 读穿透走适配层 getTicks(修正旧 hub 绕适配层的层级破洞)
- WS 数据通路移除(从无生效结论;ingest 留 source 标签回归口子)
- market_quotes_cache 表退役 DROP(幂等);价格单一入口 = QuoteHub
- 数据同步指示灯组: QMT连接|持仓数据|行情数据(绿/黄/灰,点击即同步/即时探测)
  + sync-status 端点(吸收 market-stats)+ sync-now;修复 runtime 漏传 positionSync 致持灯恒灰
- 策略持仓表行情列: 涨停价/跌停价/今开/最高(COLUMN_META defaultVisible=false,纯价格)
- 回归 test-quote-sync.mjs 27 项(含 DROP 幂等真实 SQLite 验证)
- 文档链: R-015 + PLAN-014 + 迭代三件套 + 技术约束-010/012变更、018新增 + 产品约束-012

需求: R-015(老师五拍板: 替换/WS移除/纯内存DROP/watch现状/指示灯)
2026-09-03 13:26:25 +08:00

4.8 KiB
Raw Blame History

迭代复盘:13-盘口内存快照(QuoteSync/QuoteHub + 同步指示灯)

复盘日期:2026-09-02 | 迭代状态:已实施,待老师人工验收 关联需求:R-015 关联计划:PLAN-014

结果

迭代 13 达成:盘口数据与持仓对称收敛——QuoteSync(取数:prime + 5s REST + 涨停跌停按交易日缓存)/ QuoteHub(存查:内存快照 + watch 集合 + 读穿透 + getQuote 单一入口)替换 MarketFeed/MarketDataHub(方案 A 删除重写);WS 通路移除;market_quotes_cache 表 DROP 退役(含 loadMarket 残迹清理,warmup bug 随之消灭);新增涨停/跌停字段(/data/instrument 首次启用);会话头部新增持仓/盘口同步指示灯(绿黄灰 + 点击即同步 + sync-status 端点吸收 market-stats)。

过程事实

  1. 讨论驱动逐项拍板2026-09-02,五项):① 替换 vs 包壳 → 方案 A 替换(DataStore.loadMarket 残迹为前车之鉴);② WS 移除(无生效结论 + 全市场推送被过滤 + REST 5s 已覆盖;ingest 留来源标签口子);③ 纯内存不落库(老师纠正 AI 的「表加两列」方案:缓存表整个退役,价格单一入口 = QuoteHub;AI 复以落库三问复核通过——warmup bug 复现证明落库从未真正生效);④ watchCodes 维持现状不收缩不加限(WS 移除后膨胀仅轻微浪费,切回旧 tab 价格秒显是免费福利);⑤ 指示灯(老师提出):绿黄灰三态不引入红(红留 QMT 健康灯表达连接层)、点击即 syncNow、PriceCell 灰点方案取消(管道健康全局灯表达,个股停牌属数据语义另议);
  2. warmup bug 实锤:讨论中复现 DataStore.loadMarket() 返回 DataStore 实例自身 → Object.entries 枚举出 sqlite/loaded/marketLoaded 三个内部属性 → 「重启首屏有价」自上线起从未生效,一直靠 getByCodes 磁盘兜底路径撑着——成为「不落库」决策的关键证据;
  3. 实现:getTicks 适配层通道(修正旧 hub 绕过适配层自 fetch 的层级破洞)、QuoteSync/QuoteHub、SqliteStore DROP + 行情方法删除、DataStore 行情方法删除、market-snapshot 扩展字段、sync-status/sync-now 端点、SyncIndicators 组件、wsInfo 清理;
  4. 验证typecheck + buildtest-quote-sync 全绿;存量回归 test-position-sync 34/34、test-r013 21/21
  5. 文档链R-015 + PLAN-014 + 迭代三件套 + 技术约束-018 + 产品约束-012 + 技术约束-010/012 变更(本轮讨论后统一落)。

经验教训(复盘沉淀)

1. 「缓存落库」的隐性成本会以 bug 形式讨债

  • market_quotes_cache 三件套(loadMarket 残迹 / warmup 假工作 / isEmpty 与 migrateJson 的行情耦合)活了三代迭代才被 root cause——落库换来的「重启首屏有价」实际从未工作,而读穿透 1 秒内就能补齐;
  • 沉淀:给「可再生缓存」落库前,先验证它的读取路径真的被走到(监控 stats.diskHitCount 之类),否则就是无人受益的死重 + 未来 bug 的温床。

2. 同域两个类(Feed/Hub)的「分工」挡不住职责漂移

  • MarketDataHub 本该只管存查,却自己 fetch REST(绕适配层)、管 watch 过滤、管落库防抖——「取」与「存」的边界在实践中糊掉;
  • 沉淀:类职责用「它消费谁、被谁消费」检查:QuoteHub 只消费 QuoteSync/dataSource 补拉,只被 api/前端消费;出现第三条边即重构信号。

3. 全局状态灯 > 局部灰点

  • 老师把 PriceCell 灰点讨论升级为「同步指示灯」,一并覆盖持仓+盘口两域——数据管道健康是全局属性,表达在全局位置(会话头部)比逐格标记更正确,且复用既有健康灯心智;
  • 沉淀:故障可视化先问「这是单个数据的错,还是管道的错」——后者永远放全局。

4. 交易日是行情静态数据的正确缓存键

  • 涨停/跌停/昨收「当天不变」的知识决定缓存粒度:按交易日缓存 + 日切失效,而不是跟 5s 同步周期走(省 99% 的合约请求);
  • 沉淀:为同步数据分类「每周期变(tick)/每日变(合约静态)/每次变(手动归属)」,各自匹配刷新节奏。

遗留/后续

  1. 个股停牌标识:QMT 正常但单票不出 tick 时价格陈旧且无提示——属数据语义,老师确认另议;
  2. WS 回归路径ingest 已留 source 标签;T-005 草稿维持起草,需要亚秒级行情时再议订阅契约;
  3. 指示灯扩展位sync-status 已按域结构化(position/quote/qmt),未来交易域(TradeSync 60s)可加第三盏灯,前端加一行渲染;
  4. 前端 getQuote 消费扩展:涨停/跌停已随 market-snapshot 下发,UI 尚无展示列(如需「接近涨停提示」另立需求)。