Files
mcm-26-b/output/reviews/simulator-equivalence-7930eb6.md
T
2026-09-11 08:29:56 +08:00

9.5 KiB

本地模拟器与官方规则等价性审核

审核日期:2026-09-11。版本:7930eb65bf33ac217e012c916fed0b9758e52587,重点检查新增提交 fc70d6e 及当前完整模拟器实现。审核开始时工作区干净。未修改生产代码,未调用官方测试。

结论:当前实现是可用于算法自检的简化模拟器,不能称为官方题面和通信协议的等价实现。 基本物理门限、位置和频道状态、串行合法动作的计费公式大体一致;截止时间、错误请求、并发、微秒时钟以及一个同位置误差边界存在可复现差异。部分差异原先已有,新增的虚拟超限拦截仍未实现官方结束状态。

依据为项目原始 issue/B题.pdf(已逐页核对)、issue/附件/附件2.docx 的第1—9节;正文提及官方行为均来自这些规则,未假设已知官方源码或隐藏的随机分布。

已复现的问题

1. [P1] 没有模拟现实截止时间和25分钟窗口

位置:simulator.py:118、simulator.py:229。

/enter 总是返回配置的完整时长,没有测试窗口起点、进入时刻或服务端现实截止状态。响应时间戳也仅在每次成功动作后加40毫秒。模拟器本身从未依据现实经过时间拒绝动作。客户端的主动预算检查不能代替独立服务器约束;否则客户端预算代码失效时,自建测试仍可能成功。

复现将现实上限缩短为0.02秒,在 /enter 后真实等待约0.04秒,新的 /measure 仍被接受。缩短阈值只用于快速验证缺失的服务端截止机制,不表示官方允许小数秒上限。

官方附件2第4.5、6.2节要求截止时刻为25分钟窗口截止与进入后20分钟中较早者,剩余完整秒数范围0—1200,截止后不执行新请求。建议引入可注入单调时钟和窗口起点,独立于客户端模拟这些约束。

2. [P1] 虚拟超限后仍允许成功退出,掩盖了被强制结束

位置:simulator.py:130。这是 fc70d6e 新增逻辑中的差异。

当前超限检查只拒绝 /measure 和 /clear,且不设置终止状态;紧随其后的 /exit 仍返回 accepted=true, exit_reason=user_exit。

复现:从原点检测 (1800000,0) 后虚拟时间为360005秒,下一次检测被拒绝,但 /exit 成功。允许已经登记的跨限动作完成本身符合附件;错误在于超限后还能登记新的退出动作。

官方附件2第4.5、9.2节规定达到限时即结束并关闭接口,不能事后 /exit 查询或得到正常退出。建议统一终止状态,在越界动作完成后关闭后续新动作入口,内存传输用明确的连接关闭异常模拟,保留已登记请求的处理规则。

3. [P2] 传输层绕过了多项官方请求校验

位置:transport.py:27。

urlsplit(url).path 丢弃查询参数,json.loads 默认接受重复键,headers完全未检查,也没有请求体大小检查。以下探针均得到200且接受:带查询参数的 /enter?wrong=1、Content-Type为 text/plain、重复 request_id 键、超过65536字节的合法JSON加空白请求体。非法JSON则直接抛出 JSONDecodeError,没有按官方返回400 JSON错误。

附件2第5.1—5.3节分别要求404、415、400、413及400。当前内存回环并不是HTTP服务,本身可以选择不实现完整网络栈,但必须明确它不覆盖协议等价性;若用于接口兼容验收,应补独立请求边界校验与错误映射。BOM、嵌套深度及Content-Encoding同样需要按规范验证。

4. [P2] 标识符校验遗漏控制字符和格式字符

位置:simulator.py:79。

公共字段只验证字符串、非空和UTF-8长度。request_id="e\n" 与 request_id="e\u200b" 的 /enter 都能成功,且占用幂等ID;官方附件2第5.1、6.3节要求400,并不占用ID。应按官方规定检查控制字符和不可见格式字符。仅检查ASCII控制字符也不足以覆盖U+200B等Unicode格式字符。

5. [P2] 并发不同动作未返回409,还会使用旧状态计费

位置:simulator.py:104。

校验、执行和幂等写入之间没有会话忙标志或同步机制。通过在观测函数放置线程屏障,令两个不同ID的测量同时处理,两个请求均返回200且接受;第二请求没有按附件2第1.4、5.3节返回409。两次费用计算还可能都从同一旧位置/频道出发。

顺序调用下的现有幂等测试无法发现该问题。若该类仅保证调用者串行,需缩小“协议行为一致”的声明;若用于验证官方并发规则,则需要原子化登记、忙状态及同ID未决请求处理,而不是仅依赖客户端不并发。

6. [P2] 虚拟时钟为浮点累计,没有官方整数微秒量化

位置:simulator.py:226。

从 (0,0) 测到 (1,1),本地返回 5.282842712474619,而按官方微秒计时为 5.282843。用项目已保存的官方动作前缀也能观察到相同精度差异。连续累计时差可能超过现有复算的固定1微秒阈值。

附件2第4.1节规定内部按微秒累计、响应最多6位小数。建议把内部时钟改为整数微秒,并使用从官方记录验证过的逐动作量化规则;只在输出末尾取6位,无法消除逐步累计差异。模拟器与客户端共用连续计时函数的测试通过,只证明两者彼此一致,不能证明与官方一致。

7. [P2] 正负零被当作不同地点,违反固定地点固定误差

位置:simulator.py:210。

误差键直接拼接 round() 后浮点字符串,保留 0.0 与 -0.0 的区别。源设为 (1000,0),同频道在 (0.0,0.0) 测得359.75°,随后在 (-0.0,0.0) 测得0.09°。两个检测位置是同一个几何点,却得到不同误差,可被利用成无移动的额外误差样本。

题面附录2第(1)项规定同一地点重复检测不改变误差。建议将量化坐标转换为规范化整数格索引,或至少将所有正负零统一,保证数值相等的坐标使用同一键。

符合题设的部分与尚不能判定等价的假设

项目 审核结果
距离超过实际接收半径返回无信号,等于半径仍可收 一致;额外检查了1000米及1000.0001米边界
5米以内near,超过5米返回方向 一致;检查了5米及5.0001米
20米以内可清除,定向背面也可清除 一致;检查了20米及20.0001米,清除不依赖朝向
清除后同源不能再次清除、同频道不再发信号 相关已有测试通过
移动距离/5,检测5秒,切频道1秒,清除成功5秒/失败3秒 连续公式一致;微秒累计另见问题6
clear不改变测向频道;新enter初始原点和频道1 一致
合法串行请求相同ID相同内容回放、不同内容409 基本一致;不覆盖并发及终止后的连接状态
坐标范围、频道范围、未知字段与robot/arena不匹配 常规分支已有实现;不替代原始请求校验
源数10—16、源位置在圆内、半径1000—1500 默认生成器满足范围
源数、位置、接收半径均匀分布 题面没有规定均匀分布,只规定范围和未知性;这是合法的自建分布,不能称为官方分布
逐位置哈希白噪声误差 是一种测试假设;题面只规定有界及同地点固定,没有规定不同点独立或均匀
自检默认30分钟 cli.py 和配置显式提供的工程模式;题面正式与演练均是至多20分钟程序预算。可保留压力模式,但与官方等价模式应分开
测试用0源/1源、指定半径等构造 可作为单元测试输入,无须禁止;不能当作官方合法案例生成的保证
官方随机种子、案例分布、加密日志、UI/上传生命周期 未复现或不可由公开说明推出,不作等价声明

scenes.py 中“默认完全按题面生成”应改成“采用满足题面范围的自建随机场景”,避免把新增的面积均匀与半径均匀假设解释成题面要求。第四问默认指定3个定向源也仅覆盖一种配置,不能据此代表未知定向数量的全部情况。

验证与建议顺序

运行 pytest tests/test_protocol_timing.py tests/test_protocol_client.py tests/test_belief.py -q:47项通过。额外6个距离门限探针通过。上述7类问题均有独立反例或控制条件复现,说明现有测试缺少对这些官方约束的覆盖。

复现脚本:reproduce.py;原始结果:results.json。脚本仅运行本地对象和内存传输,没有连接2026端口;现实超时探针使用短时限避免等待20分钟。

建议先区分“官方约束模式”和“可放宽参数的压力测试模式”,优先修复独立截止时钟与终止状态;随后统一整数微秒计时和坐标规范化;最后补充原始协议输入、标识符及并发验收。当前物理算法自检结果仍有价值,但不能据此保证官方超时、重试、错误请求和并发行为都已验证。