Skip to content

fix(bridge): 等待图的入口是调用链的边界(修复误报 SyncWaitCycle),检查近线性;补 Node 监听器时机的例外说明 - #535

Merged
eric8810 merged 1 commit into
mainfrom
fix/waits-entry-boundary
Oct 21, 2026
Merged

eric8810 merged 1 commit into
mainfrom
fix/waits-entry-boundary

Conversation

@eric8810

Copy link
Copy Markdown
Contributor

#527 复查发现的三个问题(阻塞 0.15)。

1. 发出方调用链造成的误报 SyncWaitCycle

events.call 带着发出方的调用链(hub.rs,e91a954e 起),而 successors() 只跳过入口本身,没有跳过入口之下发出的调用。

场景:

  • Node p 在等它调用 Python a 的 h;
  • x(来自 Go)压在 h 上面执行,发出 n,然后等一个慢但有限的调用;
  • n 的监听器同步调用 p。

检查报出 p/rust:2 → a/rust:1 → a/rust:2,监听器的正当调用得到 SyncWaitCycle。

修正(waits.rs):

2. 入口使检查在全局锁下变成 O(n²)

  • 表按调用 id 索引(HashMap),回复时 O(1) 删除。
  • started 用一个 id 集合一次算出;内层循环借用,不再克隆 id。
  • 栈顺序只连到同一运行时里下一个已开始的调用(可达性相同)。
  • 未开始的入口没有谁等它,不连“放到一边”的边。
  • 检查与进行中的调用数、调用链长度成近线性(“放到一边”的边除外:每个进入不可重入运行时的跳 × 它发出的调用)。

3. 文档

docs/requirements-protocol-plugins.md / .en.md:“本进程的监听器同步执行到第一个 await”补 Node 的例外:同名的上一次 emit 的监听器调用因同步等待被扣住时,本地监听器排在其后,在之后的微任务里执行。

模型(specs/cross-runtime-sync)

  • 发出改由正在执行的活动做(Emit),Rust 的投递带发出方的调用链(按会话改写),与 hub.rs 一致。
  • 真实图(TrueSucc,以所有投递为边界)和 Rust 的图(RustSucc,以记下的入口为边界)都以入口为链的边界(ChainFree)。
  • current-posts、policy-b-posts、policy-b-posts-node 改为 2 个顶层调用,以便发出方不在被等待的链上。结果:
    • current-posts:卡死
    • policy-b-posts:通过,14,429,655 个状态,约 2 分钟
    • policy-b-posts-node:通过,6,361,544 个状态,39 秒
  • 已核实模型能查出这两个问题:Rust 的链边不以入口为边界时,policy-b-posts 违反 NoFalseCycle(第 1 项的误报);完全不记入口时也违反。
  • 本地 tla2tools v1.7.4 跑了全部配置,都与 expected.txt 一致,已有的通过配置状态数不变。

测试

  • waits.rs::tests::an_emitters_chain_is_not_waited_for:上面的场景,监听器所在运行时单栈与否都不成环(main 上报环)。
  • ::a_listener_with_its_emitters_chain_on_top_of_a_wait:带发出方调用链的监听器压在等待上面,真实的环仍能查出。
  • ::the_check_is_near_linear_in_entries:4,000 个入口的检查耗时小于 1,000 个的 8 倍(按 O(n²) 约 16 倍)。
  • crates/rutis-loader/tests/sync_cycles.rs 全部通过(Python / Node / Bun)。

- 入口(没有调用方同步等待的调用:events.call、异步调用)不论目标是否单栈都记,作为调用链的边界:链边 c → d 只在 d 的链里 c 与 d 之间没有入口时成立。修复 events.call 带发出方调用链时的误报 SyncWaitCycle
- 等待表按调用 id 索引;started 一次算出;栈顺序只连到下一个已开始的调用;未开始的入口不连“放到一边”的边。检查与调用数、调用链长度成近线性
- TLA+:发出由正在执行的活动做,投递带发出方的调用链;真实图与 Rust 的图都以入口为链的边界
- 测试:an_emitters_chain_is_not_waited_for、a_listener_with_its_emitters_chain_on_top_of_a_wait、the_check_is_near_linear_in_entries
- 文档:requirements-protocol-plugins 补 Node 的例外;多语言设计 §9、模型 README、保证表
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant