Q+ OS SDK — API 稳定性与冻结策略(1.6.0 准备)
English summary. This is the API-freeze candidate for OS SDK 1.18.0: module/public-surface list (
os.platform/io/time/sys/fs/sync/net/thread),E_*error codes, handle/capability model, audited against v160_rc1 (Q+ 1.6.0-dev, spec v4.37). It freezes an audit baseline only — no ABI/API 1.0 guarantee; net stays BLOCKED; SDK version string is1.18.0. Seedocs/ENGLISH_SUMMARIES.mdfor the English index; the Chinese text below is authoritative.
状态:1.18.0 API 冻结候选。SDK 仍为 MVP/原型、非发布、非稳定; 本文件冻结的是 命名/错误码/句柄/能力模型 的审计基线,不宣称生产可用或 ABI/API 1.0。 适用基线:v160_rc1(Q+ 1.6.0-dev 候选,spec v4.37);SDK 版本
1.18.0。
1. 模块与公开 API(逐项对照当前实现)
模块清单(pkg/map.txt):os.platform / os.io / os.time / os.sys / os.fs / os.sync / os.net / os.thread。下表为 冻结候选公开面;标记 internal 的符号不属于稳定 API。
| 模块 | 公开 API(冻结候选) | 状态 |
|---|---|---|
| os.platform | version, language_version, target_os, target_arch, capabilities, err_name, require_cap, has_capability | PASS |
| os.io | io_open_read, io_open_write, io_read, io_write, io_seek, io_tell, io_size, io_close, io_exists, io_delete, io_active_handles, io_last_error, io_wait_read, io_wait_write | 基础 PASS;async PARTIAL |
| os.time | time_now_ms, time_sleep_ms, time_sleep_until | PASS |
| os.sys | env, console_write, input_line, arg_count, arg_at, exit_process | PARTIAL(argv/exec 受限) |
| os.fs | os_open, os_read, os_write, os_close, os_stat_size, os_seek, os_tell, os_exists, os_type, os_remove, os_rename, os_mkdir, os_rmdir, os_readdir_count, os_readdir_into, os_remove_recursive | PARTIAL(seek 模拟;递归删除 BLOCKED) |
| os.sync | mutex_new, mutex_lock, mutex_try_lock, mutex_unlock, once_new, once_call, condvar_new, condvar_notify_one, condvar_notify_all, condvar_wait, thread_mutex_new, thread_mutex_lock, thread_mutex_try_lock, thread_mutex_unlock | 同 VM PASS;跨线程仅 channel-token |
| os.thread | thread_create, thread_create_arg, thread_join_handle, thread_error, channel_open, channel_put, channel_get, channel_shutdown | PASS(create/join/channel) |
| os.net | net_tcp_listen, net_tcp_connect, net_accept, net_read, net_write, net_close | BLOCKED(stub;未实现网络) |
内部/非冻结符号(文档列出,不承诺兼容): path_safe, fs_guard, fs_last_error(os.fs);ensure_init, slot_of, slot_alloc, slot_path, slot_free(os.io);NET_BACKEND_NONE(os.net);E_MUTEX_BUSY(os.sync,保留)。
2. 命名/版式规则(冻结)
- 模块前缀:
os.platform用无前缀描述名;os.io=io_*;os.time=time_*;os.sys=sys_*;os.thread=thread_*/channel_*;os.net=net_*;os.sync=mutex_*/once_*/condvar_*/thread_mutex_*。 - os.fs 例外(破坏性变更,1.5.3 起):因语言
std.fs的fs_*与 SDK 平铺命名冲突, os.fs 公开函数统一为os_*(os_open/os_mkdir/os_readdir_into…);不再提供旧fs_*别名。 旧 1.5.2 的fs_*名称视为 已弃用并在 1.6.0 冻结中移除;调用方需迁移到os_*。 - 类型:路径/数据用
string;字节计数/错误码/句柄槽位用i32;时间毫秒用i32;os.sync的 mutex/once/condvar 对象为Array;thread的线程/通道 id 为i32。 - 返回约定:成功
0或布尔/值;失败返回 负数 E_(不抛异常;不返回静默 0 表示错误);bool返回仅用于真值语义(不编码错误码,错误用 E_ API/*_last_error)。 - 版本字符串:
OS_SDK_VERSION = "1.18.0";OS_LANGUAGE_VERSION = "1.6.0-dev"。os.platform.target_os()="linux";target_arch()="linux"/"x86-64"(VM-only)。
3. 错误码表(冻结;与 pkg/os/platform.q 逐项一致)
| 常量 | 值 | 语义 | err_name |
|---|---|---|---|
E_OK | 0 | 成功 | "ok" |
E_GENERIC | -1 | 一般错误 | "generic" |
E_TIMEOUT | -2 | 超时/自旋预算耗尽 | "timeout" |
E_CANCEL | -3 | 取消(保留) | "cancel" |
E_INVALID | -4 | 无效句柄/参数状态 | "invalid" |
E_NOT_FOUND | -5 | 路径/对象不存在 | "not_found" |
E_EXISTS | -6 | 已存在(保留) | "exists" |
E_PERM | -7 | 能力/路径安全拒绝 | "perm" |
E_UNSUPPORTED | -8 | 该平台/版本不支持 | "unsupported" |
E_NOMEM | -9 | 资源耗尽(句柄槽位等) | "nomem" |
E_IO | -10 | I/O/OS 调用失败 | "io" |
E_ARG | -11 | 参数非法(负长度/非法 whence/flags/越界) | "arg" |
E_PLATFORM | -12 | 平台错误(保留) | "platform" |
规则:错误码 只增不改值;新增用未占用负数;E_ 名字/数值/err_name 三者必须同步; 不使用正数错误码;不把 E_ 与 bool 混用。os.platform.err_name 对未知码返回 "unknown"。
4. 句柄生命周期(冻结)
- SDK 句柄是 generation-tagged i32 slot,不是 OS fd:
handle = slot + 1 + gen*MAX_SLOTS,MAX_SLOTS=32,slot 范围 0..31(0 为保留空槽)。 - 状态机:
closed → alloc(open) → active(read/write/seek/tell/size) → close → closed; close 后旧句柄(即使 slot 复用)必须 返回E_INVALID(-4),不静默成功。 - 容量:最多 32 个并发句柄;第 33 个返回
E_NOMEM(-9);io_active_handles()反映活动数。 io_last_error():最近一次失败码;成功不改写历史(调用方需在失败后立即读取)。- 越界/负长度/非法 whence/flags/空路径:
E_ARG(-11)/E_PERM(-7);不存在E_NOT_FOUND(-5)。 - 泄漏语义:程序退出由 VM 回收;SDK 不提供跨进程 fd 继承;
io_close幂等返回E_INVALID而非崩溃。
5. 能力模型(冻结,静态)
能力位:CAP_IO=1、CAP_FS=2、CAP_NET=4、CAP_THREAD=8、CAP_TIME=16、CAP_PROC=32、 CAP_ASYNC_IO=64、CAP_DRIVER=128、CAP_MEM_MAP=256。 CAPS_DEFAULT = 59(IO|FS|TIME|PROC|THREAD),即 NET/ASYNC_IO/DRIVER/MEM_MAP 默认拒绝。 has_capability(cap) 仅对 59 中的位返回 true;require_cap(cap) 失败返回 E_PERM(-7)。 能力模型为 编译期静态:无 manifest、无动态授予、无 setuid;1.6.0 不改变该模型。 任何需要 NET 的 API 在 1.6.0 保持 E_PERM/BLOCKED,网络实现前不得声称可用。
6. 破坏性变更策略(0.x 冻结期)
- 冻结对象:命名规则、E_* 数值/名字、句柄编码与 use-after-close 语义、CAPS_DEFAULT=59、
os.platform.version格式、公开函数签名(参数个数/类型)。 - 允许的兼容变更:新增 E_* 常量(只增不改)、新增模块/函数、新增能力位(默认拒绝)、 文档澄清、错误信息细化(同码)、性能/内部实现变化。
- 需 minor bump + 迁移说明:函数改名/删除(如 1.5.3
fs_*→os_*)、语义收紧、 默认能力位变化、句柄布局变化、返回类型变化。 - 禁止:改既有 E_* 值/含义;静默改变成功/失败语义;删除错误码;把 BLOCKED 改为 PASS 而无实现/证据;把 net 标记为已实现。
- 记录方式:
docs/API_STABILITY.md+OS_SDK_1.6.0_EVIDENCE.md+tools/api_stability_check.sh; 破坏性变更须在CHANGELOG/证据文档中明确迁移路径与影响。
7. 0.x → 1.0 路线(建议,不承诺)
| 阶段 | 目标 | 出口条件 |
|---|---|---|
| 1.5.x | MVP 能力(已到 1.5.5) | 23/23 tests;conformance 10/5/5;qpm e2e 18/18 |
| 1.18.0(本版) | API 冻结候选 + net sys 设计 + 示例/检查 | API_STABILITY/NET_SYS_DESIGN + checker PASS;测试/矩阵保持 |
| 1.6.x | 稳定性硬化、错误路径、文档/示例补全 | 无破坏性变更;边界/容量/句柄测试扩展 |
| 1.7.x(条件) | 语言侧 socket sys 落地后实现 os.net TCP/UDP | 语言 sys surface + loopback fixture + AOT loud 验收 |
| 1.0(远期) | 稳定 API/ABI、跨平台/AOT 结论、发布流程 | net/裸机/Windows/ARM64/AOT 决策完成;签名/发布/许可 |
当前结论:OS SDK 仍为 MVP/原型,0.x 非稳定,非发布;1.6.0 只做冻结准备与设计,不做网络实现。
8. 与当前实现的一致性核查
tools/api_stability_check.sh从pkg/os/platform.q提取 E_* 数值并与本表比对; 从pkg/map.txt遍历模块,核对公开函数均在本文件出现;检查os.fs无旧fs_*公开别名; 检查 net 仍为 stub(无sys_io_test_tcp/无真实 socket 调用);检查版本/能力/句柄常量一致。- 通过标准:脚本 PASS ≥ 12 项、FAIL=0;
os_sdk_test23/23;conformance 10/5/5;qpm e2e 18/18。