装载与运行原因码
原因码集中定义在 src/shared/codes.ts。装载判定只有三种结果:允许、拒绝、待用户裁决;运行期另有一组不参与装载判定的码。
被拒单元只会拿到码与通用说明,不会拿到哈希、目标名、路径、发布者指纹等参照值。guard:report 只记录「单元 ID + 码 + 时间」,时间以 UTC 毫秒表示,不包含参照值。判定流程与记录边界见装载管线与 guard。
怎么读这张表
- 拒绝是最终结果;单元不会进入挂载。
- 待裁决不是最终结果:装载器保持等待,收到用户答复后重读相关信任快照并重新判定。
- 运行期码不属装载判定,不记入
guard:report。 - 表中的「通用说明」就是单元与界面能看到的全部文本;同一码不因具体原因改变措辞。
拒绝码(REJECT_CODES)
| 码 | 出现阶段 | 通用说明 |
|---|---|---|
LOADER_MANIFEST_INVALID | 解析清单、内容核验 | 单元清单无法解析或内容与清单不符 |
LOADER_VERSION_UNSATISFIED | 版本求解 | 单元清单的格式版本不受支持 |
GUARD_RPM_HASH_MISMATCH | 启动 | 根插件名单校验失败,拒绝启动 |
GUARD_ROOT_ENTRY_MISMATCH | 启动 | 根插件身份校验失败,拒绝启动 |
GUARD_CONTRACT_INCOMPATIBLE | 准入判定 | 单元声明的契约版本与当前框架不兼容 |
GUARD_IR_UNSUPPORTED | 准入判定 | 单元声明的剧本 IR 版本不受支持 |
GUARD_SLOT_UNDECLARED | 准入判定 | 单元的落点不在根插件名单声明的范围内 |
GUARD_POLICY_CLOSED | 准入判定 | 单元试图写入不开放的目标 |
GUARD_CLASSIFICATION_MISMATCH | 准入判定 | 单元的类别与其内容或写边声明不符 |
GUARD_CAP_UNAVAILABLE | 准入判定 | 单元所需的能力在当前环境中不存在 |
GUARD_BUDGET_EXCEEDED | 准入判定、资源校验 | 单元超出资源预算 |
GUARD_ISOLATION_REQUIRED | 准入判定 | 该类单元必须在隔离环境中运行 |
GUARD_SIGNATURE_INVALID | 签名核验 | 签名核验失败:该单元极可能已被第三方改动 |
GUARD_UNSIGNED_IN_RELEASE | 签名核验 | 发布构建不接受未签名的代码单元 |
GUARD_PUBLISHER_REVOKED | 签名核验 | 该发布者的密钥已被撤销 |
GUARD_NAME_FORBIDDEN_CHAR | 准入判定 | 发布者名含有不允许的字符 |
GUARD_NAME_CONFUSABLE | 准入判定 | 发布者名与已有发布者视觉上无法区分,或混用了多种文字 |
GUARD_NAME_CHARSET | 准入判定 | 发布者名不符合字符集要求 |
GUARD_DECODE_PATH_FORBIDDEN | 准入判定 | 数据包与资源包不得影响解码路径 |
GUARD_SECURE_UI_OVERRIDE | 准入判定 | 安全关键界面不受资源包影响 |
GUARD_SLOT_REPLACE_TAKEN | 准入判定 | 该机制插槽的替换位已被占用 |
GUARD_SLOT_NAME_TAKEN | 准入判定 | 实现位中已有同名实现 |
GUARD_INDETERMINATE | 准入判定 | 判定条件不完整,按规定拒绝 |
LOADER_USER_DECLINED | 待裁决之后 | 用户拒绝了该单元 |
LOADER_POST_CHECK_FAILED | 装载后核验 | 装载后核验发现实际行为与声明不符,已卸载 |
LOADER_REGISTRY_CYCLE | 挂载、写入 registry | 单元写入的条目与既有条目形成循环引用 |
GUARD_PERSISTENCE_UNDECLARED | 准入判定 | 代码单元未声明可清理性(persistence) |
LOADER_UNLOADED | 装载进行中 | 装载完成前已被卸载,本次装载已撤销 |
几条容易混淆的边界:
GUARD_SIGNATURE_INVALID与GUARD_UNSIGNED_IN_RELEASE不同:前者表示签名存在但核验失败,后者表示根本没有签名。核验失败不得被解释为「第三方原版」。LOADER_MANIFEST_INVALID也用于核验后内容发生变化、清单与文件表不符等情形;它不表示「格式版本不对」,后者是LOADER_VERSION_UNSATISFIED。LOADER_POST_CHECK_FAILED不是准入拒绝:单元曾进入挂载,发现问题后已卸载。LOADER_UNLOADED是撤销本次装载,不发送「单元已装载」通知。GUARD_INDETERMINATE是 fail-closed:任何意外、参照缺失都落到这里,不猜测放行。
待裁决码(PENDING_CODES)
| 码 | 通用说明 | 何时出现 |
|---|---|---|
GUARD_PUBLISHER_UNLISTED | 发布者不在官方清单内,需要用户确认 | 签名有效,但发布者不在官方清单;用户同意后按 TOFU 记录 |
GUARD_PUBLISHER_KEY_CONFLICT | 同名发布者出现了不同的密钥,需要用户裁决 | 同一发布者名已记录过另一把密钥;已记录的一方照常,新来者挂起 |
GUARD_UNSIGNED_UNAPPROVED | 未签名单元需要用户批准 | 未签名单元没有批准记录,或归档 hash 与上次批准不同 |
GUARD_CONSENT_REQUIRED | 单元申请的权限需要用户同意 | 缺少按单元的同意:需用户同意的能力或 trusted 写入目标未同意,或归档 hash 变化/申请范围扩大 |
待裁决码可以同时出现,例如一个发布者不在清单内、同时又申请了敏感能力的单元。界面必须把每个待裁决理由分别列出,不能用一次「同意」覆盖没有展示的项。裁决结果只影响本次装载;用户拒绝后得到 LOADER_USER_DECLINED。
运行期码(RUNTIME_CODES)
| 码 | 说明 | 处置 |
|---|---|---|
SCRIPT_UNKNOWN_COMMAND | 剧本用到了没有任何单元提供的指令,已停止 | 本次播放停止;检查指令命名空间或补上提供者;optional 指令不会触发该码 |
TRANSLATE_BUDGET_EXCEEDED | 翻译作业超出本次预算,已中止并清理暂存,可调高预算重试 | 隔离环境销毁、本次暂存清理;用户可在界面调高墙钟、输入与输出预算后重试 |
运行期码不记入 guard:report,也不改变单元的装载状态。SCRIPT_UNKNOWN_COMMAND 只用于「无人提供」;演出类指令没有执行者时属于降级,不报此码。
GENERIC_MESSAGES 的边界
GENERIC_MESSAGES 覆盖全部拒绝码与待裁决码,RUNTIME_MESSAGES 覆盖运行期码。它们共同遵守:
- 只描述问题类别,不包含哈希、文件名、目标名、发布者指纹、路径或时间。
- 不因同一码的不同触发原因改变文本,避免把内部参照值泄露给被拒单元。
- 界面可以额外展示用户可理解的上下文,但不得把
guard:report的参照值回填给单元。 - 码本身是稳定契约;新增或改变语义须同步更新
src/shared/codes.ts与本站。
代码中的入口与查询
| 位置 | 内容 |
|---|---|
src/shared/codes.ts | REJECT_CODES、PENDING_CODES、RUNTIME_CODES、GENERIC_MESSAGES、RUNTIME_MESSAGES |
KernelControl.report() | 外壳控制面:boot 经 KernelConfig.onControl 取得,不注册为扩展服务;返回 { unitId, code, at } 列表,at 为 UTC 毫秒 |
guard:report.entries() | 只读服务:只在 Kernel 自身的隔离作用域可见,内容与 report() 相同 |
kernel:loader | 只有 units()、pending()、authorize();不提供 report() |
kernel:on-unit-rejected | 载荷 { id, code };无法识别 ID 时为固定占位值 |
LoadOutcome | 成功为 { status: "loaded", id, kind, notices },拒绝为 { status: "rejected", id?, code } |
相关页面:装载管线与 guard、包清单与目录、剧本 IR v1、信任与签名、Kernel。