97 lines
9.5 KiB
Markdown
97 lines
9.5 KiB
Markdown
# 本地模拟器与官方规则等价性审核
|
|
|
|
审核日期:2026-09-11。版本:`7930eb65bf33ac217e012c916fed0b9758e52587`,重点检查新增提交 `fc70d6e` 及当前完整模拟器实现。审核开始时工作区干净。未修改生产代码,未调用官方测试。
|
|
|
|
结论:**当前实现是可用于算法自检的简化模拟器,不能称为官方题面和通信协议的等价实现。** 基本物理门限、位置和频道状态、串行合法动作的计费公式大体一致;截止时间、错误请求、并发、微秒时钟以及一个同位置误差边界存在可复现差异。部分差异原先已有,新增的虚拟超限拦截仍未实现官方结束状态。
|
|
|
|
依据为项目原始 `issue/B题.pdf`(已逐页核对)、`issue/附件/附件2.docx` 的第1—9节;正文提及官方行为均来自这些规则,未假设已知官方源码或隐藏的随机分布。
|
|
|
|
## 已复现的问题
|
|
|
|
### 1. [P1] 没有模拟现实截止时间和25分钟窗口
|
|
|
|
位置:[simulator.py:118](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/simulator.py:118)、[simulator.py:229](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/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](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/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](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/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](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/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](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/simulator.py:104)。
|
|
|
|
校验、执行和幂等写入之间没有会话忙标志或同步机制。通过在观测函数放置线程屏障,令两个不同ID的测量同时处理,两个请求均返回200且接受;第二请求没有按附件2第1.4、5.3节返回409。两次费用计算还可能都从同一旧位置/频道出发。
|
|
|
|
顺序调用下的现有幂等测试无法发现该问题。若该类仅保证调用者串行,需缩小“协议行为一致”的声明;若用于验证官方并发规则,则需要原子化登记、忙状态及同ID未决请求处理,而不是仅依赖客户端不并发。
|
|
|
|
### 6. [P2] 虚拟时钟为浮点累计,没有官方整数微秒量化
|
|
|
|
位置:[simulator.py:226](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/simulator.py:226)。
|
|
|
|
从 `(0,0)` 测到 `(1,1)`,本地返回 `5.282842712474619`,而按官方微秒计时为 `5.282843`。用项目已保存的官方动作前缀也能观察到相同精度差异。连续累计时差可能超过现有复算的固定1微秒阈值。
|
|
|
|
附件2第4.1节规定内部按微秒累计、响应最多6位小数。建议把内部时钟改为整数微秒,并使用从官方记录验证过的逐动作量化规则;只在输出末尾取6位,无法消除逐步累计差异。模拟器与客户端共用连续计时函数的测试通过,只证明两者彼此一致,不能证明与官方一致。
|
|
|
|
### 7. [P2] 正负零被当作不同地点,违反固定地点固定误差
|
|
|
|
位置:[simulator.py:210](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/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`](C:/Users/HelixCopex/code/MATH/src/mcm26b/sim/scenes.py:4) 中“默认完全按题面生成”应改成“采用满足题面范围的自建随机场景”,避免把新增的面积均匀与半径均匀假设解释成题面要求。第四问默认指定3个定向源也仅覆盖一种配置,不能据此代表未知定向数量的全部情况。
|
|
|
|
## 验证与建议顺序
|
|
|
|
运行 `pytest tests/test_protocol_timing.py tests/test_protocol_client.py tests/test_belief.py -q`:47项通过。额外6个距离门限探针通过。上述7类问题均有独立反例或控制条件复现,说明现有测试缺少对这些官方约束的覆盖。
|
|
|
|
复现脚本:[reproduce.py](C:/Users/HelixCopex/code/MATH/tmp/simulator-audit/reproduce.py);原始结果:[results.json](C:/Users/HelixCopex/code/MATH/tmp/simulator-audit/results.json)。脚本仅运行本地对象和内存传输,没有连接2026端口;现实超时探针使用短时限避免等待20分钟。
|
|
|
|
建议先区分“官方约束模式”和“可放宽参数的压力测试模式”,优先修复独立截止时钟与终止状态;随后统一整数微秒计时和坐标规范化;最后补充原始协议输入、标识符及并发验收。当前物理算法自检结果仍有价值,但不能据此保证官方超时、重试、错误请求和并发行为都已验证。
|