Skip to content

feat(root-abi): Root ABI 运行时绑定与跨语言 ABI 验证(R-00020 / LCE-P0-006) - #9

Merged
Go1c merged 1 commit into
mainfrom
feat/r-00020-root-abi-runtime
Aug 29, 2026
Merged

feat(root-abi): Root ABI 运行时绑定与跨语言 ABI 验证(R-00020 / LCE-P0-006)#9
Go1c merged 1 commit into
mainfrom
feat/r-00020-root-abi-runtime

Conversation

@Go1c

@Go1c Go1c commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

这张卡做了什么

在 LCE-P0-005 已发布的 Root ABI 生成物之上,实现 §8.3 的运行时面:AbiExpectationSymbolResolverRootApiTableViewbind_root_apiHandleGuard,并补齐 C / C# 跨语言布局探针。

不加载动态库(本卡非目标):测试用进程内 extern "C" entry + 泄漏的合规 table 充当已映射镜像。

关键设计

布局常量一个都不手写。 生成绑定 rust/contracts.rs#[path] 只读引入(不复制、不改写,cargo fmt 实测不触碰它);字段偏移取自它的 offset_of!,table 最小尺寸取自它的 size_of——后者已包含上游声明的保留 slot,恰等于 ADR-040 §4 的派生最小值 16 + (functionCount + reservedSlots) * pointerBytes,而 reservedSlots 本身没有任何 Rust 可消费常量。

期望值双路互锚。 生成绑定(上游 compiler 产出)与 lumio-core-contracts 的 bundle 标量视图(上游 root-abi-bundle.json 嵌入字节)是两条独立派生路径;编译期 const 断言逐项要求二者一致,任一侧漂移即编译失败。

读取顺序即安全边界。 全部 unsafe 集中在 bind.rs:先判 null 与对齐,再读 ADR-040 §4 冻结的 16 字节 header 前缀,abi_version / struct_size / capability_bits 依次过关后,才允许读 table 指针;每张 table 同样先过 header 再读 slot。每次越过头部的读取都由已校验的 struct_size 证明落在对象内。

两处对 §8.3 的显式偏差(ADR 0010)

上游 ADR-040「What this bundle deliberately does not freeze」明写:V1 未冻结 capability_bits 是 bitmask 还是计数、未冻结任何位位置,且「a consumer must not derive a capability key from either source」。

  1. 不提供 supports(CapabilityId) —— 照 §8.3 写出来的任何实现都必然是本仓自造的位映射,正是 ADR-040 禁止的事。capability_bits 改为不透明相等校验(相等比较不含 bitmask 假设,子集判定含)。
  2. 不校验 per-table version —— 期望值只发布在 JSON 里,运行时闭包为此引入 JSON 解析依赖不成比例;读出后如实公开,并配守卫测试钉住「不比较」是显式行为。

两处都不用同名临时方法 / alias / 假 Golden 填补,沿用 lumio-core-contracts 对 §6.1 缺位 seam 的同一处置。

验证

  • just nextest110/110(基线 80,本卡新增 30 = 17 负例 + 8 正例 + 5 handle)
  • 三语言 22 条 size/align/offset/slot 事实逐行 diff 一致(C / C# / Rust)
  • just check 全段、just check-contractsjust check-generated、spec-lint + 17 项自测:全绿
  • 对照组:4 条 bind 守卫逐一变异 → 对应负例逐一变红;篡改 header 副本 → C 编译 exit 1;C# 测量值偏离 → 探针 exit 1

详细命令与输出见 R-00020 卡上的证据评论。

🤖 Generated with Claude Code

只读引入 LCE-P0-005 发布的架构源 Rust 绑定(#[path],不复制不改写),
在其上实现 AbiExpectation / SymbolResolver / RootApiTableView / bind_root_api:

- 全部 unsafe 集中在 bind.rs;读取顺序严格「先校验 header 前缀,再读后续 slot」,
  每次越过头部的读取都先由已校验的 struct_size 证明落在对象内。
- 布局常量一个都不手写:偏移取自生成结构体的 offset_of!,最小尺寸取自
  生成绑定的 size_of(已含上游声明的保留 slot,恰等于 ADR-040 §4 的派生最小值)。
- 期望值经两条独立派生路径互锚(生成绑定 vs contracts 的 bundle 标量视图),
  编译期 const 断言逐项比对,任一侧漂移即编译失败。
- 错误映射按 §8.3:1021 / 1022 / 1004 / 1029 / 1030,均取自架构源 ID Registry。

跨语言:C 探针靠 header 自带的生成 static assert 判 Golden(不抄第二份数值),
C# 探针在运行期与生成物自带的 RootAbiLayout 逐项比对;三语言输出同一规范格式,
22 条 size/align/offset/slot 事实逐行一致。C# 构建产物经 Directory.Build.props
落到 build/,源码树不留 bin/obj。

ADR 0010:上游明确未冻结的语义(capability 位映射、per-table version)保持缺位,
capability_bits 只做不透明相等校验,不自造判定键(ADR-040 明令禁止)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Go1c
Go1c merged commit 3246810 into main Aug 29, 2026
3 checks passed
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