Files
mcm-26-b/.zcode/plans/plan-sess_4d6694a9-3cc0-4ded-bca4-4a58061ec3fa.md
T
2026-09-11 02:32:31 +08:00

6.7 KiB
Raw Blame History

修复计划:7 项 P2 问题 + 3 项规划调整

已核实:7 个问题的定位与审核报告一致;另确认关联缺陷 planner/__init__.py:392 用 > 判断遮挡预算(实际放行 5 个被遮挡探点,注释口径为 4)。用户已确认:环探保留启发式+重写依据;误差场采用逐点白噪声哈希。

修改一:模拟器固定误差场(问题1)

文件 src/mcm26b/sim/simulator.py:

  • 新增 _bearing_error(channel, pos):sha256(f"{error_seed}|{channel}|{round(x,6)}|{round(y,6)}") 前 8 字节映射到 [-error_half_deg, +error_half_deg)。同一(源频道, 位置)读数恒定,不同点独立。
  • _observe(L193)改为调用它;删除顺序随机流 self._rng(构造参数 error_seed 保留)。
  • 模块 docstring 更新:同位置误差固定;分布仍是测试假设。
  • 新增测试:同位置重复测量(不同 request_id)svd_deg 相同;同种子两次构造结果一致。

修改二:Q4 对跖探点公式(问题2)

文件 src/mcm26b/planner/__init__.py(L440-447):

  • L447:dx / norm * scale → dx * scale(dy 同理),使偏移模长 = min(norm, safe)。圆心为原点、原探点 (200,0)、safe≥200 时返回 (-200,0)。
  • L444 退化分支:min(safe, 1.0) → safe(方向 +x),不再钳到 1m。
  • 新增单测:对跖点坐标(safe≥norm 与 safe<norm 两种)。

修改三:环探依据重写 + 预算一致(问题3,保留启发式)

  • planner/__init__.py 模块 docstring、DirectionalExtension docstring、_next_probe docstring(L428-431):删除"≥180° 弧"声称,改为诚实表述:源位于环上且朝向沿外切线时可见弧可退化为单点,固定 45° 步进无最坏命中保证;梯子只提高提前命中率,完备性完全由后备清除兜底。
  • docs/协议规则表与状态机.md §7(L166-172)同步重写。
  • L392 > → >=,config.py:85 注释与文档同步为"4 个被遮挡探点(选点/对跖/环探×2)"。
  • 新增 scripts/benchmark_q4.py:批量种子扫描(--problem 4,可配源数/定向数/种子范围/输出路径),逐局记录 measures、clears、后备清除格数与 attempts、virtual_time、completed,落盘 output/q4/benchmark.json 并打印汇总表——用于验证修复后的后备清除成本(审核"验证后备成本"要求),同时为论文问题4结果表提供可复现数字。

修改四:通信失败可靠收尾(问题4)

文件 planner/__init__.py run()(L195-205):

  • client.enter() 纳入 try;except 顺序:DeadlineExceeded → (TransportError, ProtocolError, InconsistentBelief) → Exception 兜底;stop_reason 分别记 real_budget_exhausted / transport_failure / protocol_error / inconsistent_belief / unexpected_error,summary 增 abort_detail(异常类型+消息,截断)。
  • /exit 改为尽力而为:client.exit() 失败不再中断收尾;_summary 接受 info=None(exit_reason="exit_unreachable",virtual_time 取 client.state.virtual_time_s)。
  • summary 增 channel_status 快照(每频道状态 + 候选 MEC 半径,约 20 条)——即"保存未完成状态";--log 的 JSONL 本就有全过程留痕。
  • cli.py 无需改(completed=false 已映射退出码 1)。
  • 新增测试:注入连续三次传输失败(若 ScriptedFaultTransport 不支持持久失败则扩展其故障类型),断言 run() 正常返回 summary 不抛异常、有 /exit 尝试留痕、退出码路径为 1。

修改五:Q1 近平行退化情形(问题5)

文件 src/mcm26b/geometry/localization.py(L216-226):

  • 衰退方向判定改为对浮点平面系数的精确有理数运算(Fraction):候选方向仍枚举各平面法线的垂直方向 (b,-a)/(-b,a);先用浮点快速预筛(max > 1e-9 直接排除,浮点误差远小于该阈值),近零候选再用 Fraction 精确检验 ∀(d,e,f): d·dir_x + e·dir_y ≤ 0。平面系数本身是 float(精确有理数),故结论对量化输入精确,消除 2e-14 阈值与顶点过滤 eps=1e-9 的口径错配导致的漏判。
  • 顶点枚举与 PARALLEL_EPS 预筛保持现状。
  • 回归测试:审核复现输入 [(0,0,1°), (0,0.01,358.99999999999°)] → status=unbounded、diameter_infinite=true、不给清除保证;scripts/benchmark_q1.py 两档结果不回归。

修改六:默认舍入裕量统一(问题6)

  • config.py:75:bearing_rounding_margin_deg 默认 0.0 → 0.005,注释改为"覆盖服务器两位小数舍入偏差(≤0.005°);库默认与 CLI 默认一致"。
  • q1 子命令与 geometry/__main__.py 的 --rounding-margin-deg 默认保持 0(离线敏感性分析语义不变,审核未要求改)。
  • 新增断言 SearchConfig().bearing_rounding_margin_deg == 0.005,并用默认配置复跑"边缘读数保留真源"场景;检查显式传参的现有测试不受影响;README 如有默认值描述一并更新。

修改七:后验评分补 near 分支(问题7)

文件 planner/__init__.py _worst_posterior_radius(L93-110):

  • 增加 near 分支:probe.clip_disk(q, field.near_radius_m, search.polygon_sides),多边形非空则纳入 max;direction 端点分支保留,docstring 说明 safe 盘内 no_signal 不可能故不枚举。
  • 调用点(粗评/加密复评两处)传入 near_radius_m 与 polygon_sides。
  • 新增测试:候选集 [(-4,0),(4,0)](两点退化区域)、q=原点 → 最坏后验 ≈ 4m(修复前报 2m);test_loop_q3/q4 场景回归(选点可能变化,但断言均为清除状态类,预期无碍)。

规划调整落地

  • A(第二问定位):docs/algo-2.md §13(L231 附近)明确交付为"安全选点的启发式基线":解析安全盘证书已实现并证明;§10 区间上界未实现,采样最大值仅作粗筛,不得称严格最坏上界。
  • B(第三问):无代码改动;顺序约束(先修改一/四,再官方演练)在 docs/B题建模分析与实施计划.md 演练清单处注明。
  • C(第四问预算口径):_summary 增 total_requests(measures+clears);DirectionalExtension._summary 增 fallback_clear_attempts(Σ attempts);docs/协议规则表与状态机.md §7 后备清除段注明"后备 /clear 请求计入总请求与现实预算"。

测试与验收

  • 每项修改配单测(新增约 10-12 项),全套 pytest 通过(95 → ~107 项)。
  • 冒烟:uv run mcm26b sim-check;uv run mcm26b run --problem 3/4 --self-test 若干种子。
  • 运行 scripts/benchmark_q4.py 记录修复后后备成本,输出落盘。

执行顺序

修改一(模拟器)→ 修改四(收尾)→ 修改六 → 修改七 → 修改二 → 修改三 → 修改五 → 文档同步 → 全量回归。