# 迭代复盘: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/29;test-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_shares(shares 仍置 0,R-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-segments;orders 与 trades/history 返回附加 segments;R-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(幽灵退役断言)、r017(7 天候选退役语义)、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)。