chore(swap)+test: 删分红EOD历史死代码 + 补计算过程常驻日志(零行为语义变更);契约修复转为暂缓
死代码删除(SwapEodPositionService.UpdateEodPosition,论证+实证链完整): - todayConsumedDividend/originNotional/totalPayment/totalInterest 自 0910969e(7/2 改递推式) 起计算结果从未被消费,仅残留全历史 CalcBondPayment 只读查询+日志副作用,且构成 脏数据(OriginalStockEqvNotional=null/PosiNetPrice=0)下 EOD 崩溃点(除零,实测复现) - 配套边界测试 DividendEodNoDoubleCountTest.脏数据边界_*:删除前红(崩溃)→删除后绿 (不抛异常+四输出字段与正常数据逐字段一致);stash 基线对比确认离线套件无其他差异 - 止血预案:git revert 本提交即回到已验证态 计算过程常驻日志(快速定位,纯增): - [EOD平仓后收盘结息]:口径/autoSwap/平仓前/剩余/平掉额——排障第一入口 - [分红-EOD计提Copy/Update]:窗口/qty/税率/当日新计/账面前值→后值——与 [分红-登记日口径]窗口命中日志构成分红计算全链 - [利息-全平专属分支]:全平分支触发标记,兼作契约修复落地后的验证哨兵 契约修复(EOD传真实比例)转为暂缓:影响快照种子,黄金回放验收门因96库网络未恢复 无法执行,按风险优先级撤回行为变更;方案+回归网(同形状等价oracle)+落地哨兵已 全部就绪并留档于裁决文档,DB恢复后可直接落地。
This commit is contained in:
@@ -247,5 +247,45 @@ namespace YLErp.Modules.SwapModule
|
||||
AssertDecimalEqual(0m, r2.TdPosiDividend, 0.01m, "登记日全平 EOD 不计提当日(PosiQuantity=0,正确)");
|
||||
AssertDecimalEqual(0m, r2.PosiDividendSum, 0.01m, "全平后 PosiDividendSum=0");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 【死代码删除的边界规格】脏数据(OriginalStockEqvNotional=null / PosiNetPrice=0)不得让
|
||||
/// UpdateEodPosition 崩溃,且分红产出与正常数据完全一致。
|
||||
/// 背景:这两个字段在 UpdateEodPosition 内的唯一消费点是历史遗留死代码
|
||||
/// (originNotional→totalPayment 全历史重算,结果从未被使用,2026-08 论证后删除)——
|
||||
/// 删除前该脏数据会在 EOD 抛 InvalidOperationException/除零;删除后是设计内行为。
|
||||
/// 本测试同时钉住:删除后输出等价(与同输入正常数据路径一致)。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void 脏数据边界_死代码涉及字段_不影响EOD分红产出()
|
||||
{
|
||||
// 正常数据基准
|
||||
var eodSvcClean = new EodSvcStub(BondPayments());
|
||||
var tdClean = CreateTrade();
|
||||
var positionClean = CreatePosition();
|
||||
var initialEod = CreateInitialEod();
|
||||
var d1 = new DateTime(2026, 1, 6);
|
||||
var d2 = new DateTime(2026, 1, 7);
|
||||
var r1Clean = eodSvcClean.ExecuteCopyEodPosition(initialEod, tdClean, d1, StartDate);
|
||||
var r2Clean = eodSvcClean.ExecuteUpdateEodPosition(positionClean, r1Clean, tdClean, d2, d1,
|
||||
new List<swap_flow_event> { CloseEvent(InitialQty, r1Clean.PosiDividendSum, d2) });
|
||||
|
||||
// 脏数据:死代码涉及的两字段置脏(活路径零消费,见方法内 grep 论证)
|
||||
var eodSvcDirty = new EodSvcStub(BondPayments());
|
||||
var tdDirty = CreateTrade();
|
||||
tdDirty.OriginalStockEqvNotional = null; // 死代码 (decimal) 强转崩溃点
|
||||
var positionDirty = CreatePosition();
|
||||
positionDirty.PosiNetPrice = 0m; // 死代码除零崩溃点
|
||||
var r1Dirty = eodSvcDirty.ExecuteCopyEodPosition(initialEod, tdDirty, d1, StartDate);
|
||||
var r2Dirty = eodSvcDirty.ExecuteUpdateEodPosition(positionDirty, r1Dirty, tdDirty, d2, d1,
|
||||
new List<swap_flow_event> { CloseEvent(InitialQty, r1Dirty.PosiDividendSum, d2) });
|
||||
|
||||
// 脏数据不崩 + 输出与正常数据逐字段一致
|
||||
AssertDecimalEqual(r2Clean.TdPosiDividend, r2Dirty.TdPosiDividend, 0.0001m, "TdPosiDividend 不受脏字段影响");
|
||||
AssertDecimalEqual(r2Clean.TdCloseDividend, r2Dirty.TdCloseDividend, 0.0001m, "TdCloseDividend 不受脏字段影响");
|
||||
AssertDecimalEqual(r2Clean.PosiDividendSum, r2Dirty.PosiDividendSum, 0.0001m, "PosiDividendSum 不受脏字段影响");
|
||||
AssertDecimalEqual(r2Clean.RealizedDividend, r2Dirty.RealizedDividend, 0.0001m, "RealizedDividend 不受脏字段影响");
|
||||
Console.WriteLine($"[脏数据边界] 正常={r2Clean.PosiDividendSum} 脏数据={r2Dirty.PosiDividendSum}(应相等且不抛异常)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user