Files

42 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 迭代复盘:16-交易关联驱动持仓份额动态调整
> 复盘日期:2026-09-08 迭代状态:**验收通过(2026-09-08)** —— 口径:自动化为主体 + 只读走查 + 真实使用顺带确认(老师拍板,见验收标准.md)
> 关联需求:R-018(已定稿)| 关联计划:PLAN-017
## 结果
迭代 16 达成(R-018 全范围):**数据域分界落地**——幽灵清仓退役(PositionSync 不再写 strategy_holdings 账本);**归属升级为账本写操作**——策略级候选 + 统一份额分配器(委托拆 0..N 段 × 策略 × 量,余额默认全量可改小、允许部分关联)+ 买卖联动账本(买入加仓/建新仓不复活旧行、卖出减仓/归零清仓、仓不足拒绝、无仓拒绝)+ 撤段逆操作(撤建仓买入=作废第三态不产生假清仓历史、撤加仓=减回归零作废、撤卖出=恢复活动仓+份额加回,粒度=段、改归属原子)+ 归属分段存储(trade_order_attributions,真相源)+ R-017 7 天候选退役(holdingId 键控/占位安全逻辑由策略级 targets 承担)+ 漏关联软提示(只读)。存量归属(trade_orders 单列)自动迁移为段表第一段。
验证:新回归 test-r018-attribution 29/29test-position-sync 29/29(幽灵退役断言重写);存量回归 r016 24 / r017 12(语义修订)/ r013 21 / r009 14 / r009-api 13(端点更新)/ r009-sync 8 / r009-normalize 11 / r011-api 12 / r011-tabs 23 / quote-sync 27 全绿;typecheck + build 通过。
## 过程事实
1. **文档链先行**:讨论收敛 → R-018 定稿 → PLAN-017 → 迭代 16 三件套 → 设计约束变更(技术约束-017 / 产品约束-011 / 数据存储设计 §11-13);
2. **阶段A 分界**PositionSync 删 `_autoCloseGhosts`/ghostRounds/账户守卫链/stats.closedGhosts,只保留对账单快照同步(含空快照双重确认与读穿透);软提示新端点 positions/orphan-hints(账本活动行 ∩ 快照缺失 code,只读);
3. **阶段B 存储**strategy_holdings 增 void_at/closed_shares(幂等 ALTER + 活动唯一索引重建收窄至两态皆空——索引创建移出 SCHEMA_SQL 到补列之后,防旧库无列建索引崩溃,quote-sync 回归暴露);closeHolding 记 closed_sharesshares 仍置 0R-016 Q2 展示语义不变);voidHolding/reopenHolding/getHoldingById;新建 trade_order_attributions 段表;存量归属迁移段表第一段(幂等);
4. **阶段C 归属服务**src/trades/AttributionService.js 新增):apply(动作表判定)/ revoke(撤段逆操作,同 holding 逆序、跨 holding 独立)/ setSegments(全量替换、单事务原子);setOrderAttribution 兼容封装 = 替换语义(清旧段设新段);
5. **阶段D API**attribution-targets(策略级 + activityShares/ attribution-set / attribution-segmentsorders 与 trades/history 返回附加 segmentsR-017 attribution-candidates/set-attribution 端点退役;strategy-holdings/history name 兜底改段表 join
6. **阶段E UI**AttributionSelect → AttributionCell + AttributionEditor(余额头 + 段 chips 可撤 + 策略下拉/量输入/截断提示 + 全部撤除/完成);交易记录 tab 顶部漏关联软提示横幅;
7. **阶段F 回归**:新脚本 test-r018-attribution;更新 position-sync(幽灵退役断言)、r0177 天候选退役语义)、r009-api(新端点)、r016-history(段表造归属)。
## 经验教训(复盘沉淀)
### 1. 语义迁移要逐调用点核对 + 用旧回归脚本当哨兵
R-018 把「归属真相源」从 trade_orders 单列迁到段表,牵动 r009/r016/r017/verify-real 一堆脚本与 strategies handler。靠跑存量回归暴露了两类坑:① quote-sync 的旧结构库建库路径在 SCHEMA_SQL 含新列索引时崩溃(索引引用尚不存在的列)——列迁移与索引重建必须同序;② 测试里「UPDATE trade_orders SET holding_id」直改冗余列的方式在真相源切换后不再生效(r016 name 兜底失败)——测试自身要改经段表造数据。沉淀:**存储层语义变更时,先跑全部存量回归锁定断裂点,再逐点核对(skill §5 语义迁移核对)**。
### 2. 「作废」与「清仓」是两个生命周期终态,不能用同一标记
撤建仓买入段若走 closeHolding 会造出假的「已清仓」历史行(R-016 历史层会显示、统计会含)——老师 R3-1 拍板新增 void 第三态。沉淀:**「从未成立」与「曾经成立后卖出」在账本语义上必须区分**,UI 历史层只认 close。
### 3. 服务端不做隐式截断,让 UI 截断并提示余额
卖出段 > 活动仓时服务端直接拒绝(segment-exceeds),由 UI 自动截为可容纳量并醒目提示「余额保留」——避免服务端悄悄改用户意图造成「半生效」状态与提示脱节。沉淀:**涉及钱/仓位的写接口要显式,宁可报错回滚也不要隐式修正**。
### 4. 数据域分界用一句话可执行规则落地
「幽灵清仓是一个同步机制,爪子不许伸到账本」落到代码 = PositionSync 构造里不再持有 storage 写能力路径 + 回归断言 closeHolding 零调用。沉淀:**架构性拍板要落到「哪个模块能写哪张表」的显式约束,并用测试钉死**。
## 遗留/后续
1. **r013-columns 测试漂移(既有,非本迭代引入)**:断言「默认 8 列」但 COLUMN_META 自 R-015 加 4 行情列后实际 14 列(4 默认隐藏)——R-015 后未同步,建议另立小修(列显隐功能未破坏,纯测试预期过期);
2. **R-016/R-017 文档同步**:R-017 迭代 15 复盘所述「候选窗口」语义已被 R-018 取代(7 天候选退役),R-017 需求文档待标注退役(R-018 需求文档已含 T2 决策,归档时统一);
3. **幽灵清仓退役的旧数据影响**:存量库中过去被幽灵清仓转历史的行保持 closed 不变(不回溯);新语义下账本只随交易关联/手动操作走;
4. **UI 待老师人工验收项**:多段拆单交互、撤段恢复活动、作废行不显历史层、软提示横幅、策略持仓 tab 不因 QMT 卖光自动消失(须关联卖出单才 close)。