Checkpoint web parity through Chromium input tasks
Some checks are pending
M6 deployable RC / quick (push) Waiting to run
M6 deployable RC / chromium (push) Blocked by required conditions
M6 deployable RC / release (push) Blocked by required conditions

This commit is contained in:
mes123456
2026-08-19 10:39:03 -04:00
parent 5a11045ca5
commit 380cbed4ff
634 changed files with 41862 additions and 212 deletions

View File

@@ -1,6 +1,6 @@
# Blender 5.2 全功能对标工作分解
更新时间2026-08-15
更新时间2026-08-18
> 本文保留为 Blender 全产品覆盖检查表和 F00-F24 taxonomy 参考。M12-M23 的执行分类、
> 原子任务、证据合同与发布门以 `BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` 为准;
@@ -17,7 +17,7 @@ V1 盘点术语;完整对标结论必须按新计划转换为 `LOCAL_EXACT/LOC
N-015 至 N-026 的 12 个 family 全部仍为 `parityStatus=BLOCKED`。因此以下任务默认均为未完成;
只有 `docs/status/parity-ledger.json` 和对应专项证据同时更新后才允许改变状态。
短周期唯一领取顺序仍以 `docs/CURRENT_EXECUTION_PLAN.md` 为准。本文负责验证新计划没有遗漏
短周期唯一领取顺序仍以 `docs/EXECUTION_QUEUE.md` 和对应任务卡为准。本文负责验证新计划没有遗漏
产品域;与新计划冲突时按新计划解释,不取代当前执行队列或长期实施事实源。
## 2. 原子任务完成定义
@@ -516,12 +516,39 @@ N-015 至 N-026 的 12 个 family 全部仍为 `parityStatus=BLOCKED`。因此
## 29. 当前领取点
截至 2026-08-17M6-M11 已按当前计划完成M11 最终以 Render、Compositor、Media 三域故障
截至 2026-08-18M6-M11 已按当前计划完成M11 最终以 Render、Compositor、Media 三域故障
生命周期专项门收口M12-01A-I 已完成 catalog schema/migrationM12-02A-H 又完成 PreviewImage
inventory、identity、decode budget、OPFS commit、dedupe、quarantine、project-scoped reference GC
与 desktop/browser 双显示路径像素闭环。本文的 F00-F24
条目只作为覆盖检查表不能直接领取M12-03A 又冻结 Append/Link/Override 的 36 类 root 与
实际 ID pointer dependency closureM12-03B 固定 source/owner/read-only/invalidation identity
M12-03C 冻结 Blender 5.2 单 Object append 的 Object/Mesh/Material/Image local stable mapping
M12-03D 已通过 WASM Main 单 transaction 创建同一 local dependency closure。当前唯一下一任务为
`BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` 中的 `M12-03E`
M12-03D 已通过 WASM Main 单 transaction 创建同一 local dependency closureM12-03E 又完成
undo/redo/save/reopen 与 desktop canonical graph 的联合一致性M12-03F 又冻结 desktop LINK
source-library/read-only ownershipM12-03G 又完成 linked writer fail-closed gateM12-03H 又完成
matching-generation reloadM12-03I 又完成 missing-library placeholder/source preservationM12-03J 又冻结
desktop override reference/local-owner/property contractM12-03K 又开放单一 verified override writer
M12-03L 又冻结 freshness gateM12-03M/N 又收口 negative cases 与三 lane 独立命令矩阵。
M12-04A-J 又冻结 declared source admission、canonical path、path/origin safety、link resolution、
metadata-first、archive budget/conflict、cancellation rollback、quota/OOM recovery 与恶意 ZIP/TAR
长期回归M12-05A 又从 pinned Blender 5.2 runtime 生成七格式 operator/build inventoryM12-05C
又将 M12-05B capability matrix SHA-256 绑定到文件选择器与 operator searchM12-05D 又将
执行路由绑定到 14 条 runtime receiptM12-05E 又固定每条 receipt 的 source/settings/runtime
三重 hashM12-05F 又增加 parent byte、canonical receipt-set 和 runtime identity freshness gate
并对未声明/未注册/未绑定/伪造/过期/跨版本组合保持 fail-closedM12-06A 又由 pinned Blender
5.2 desktop 生成五个独立 Mesh/PBR/UV/skin/animation GLB fixture并完成逐字节确定性重生成
M12-06B 又让生产 Web parser 在 Node 与 Chromium Worker 中精确比较 topology、attributes、
materials、nodes 和 animationsM12-06C 又完成 desktop GLB import 后的 Main save/reopen 与
stable-ID 比较M12-06D 又固定 Web export machine loss reportM12-06E 又完成 desktop Web GLB
re-import canonical comparisonM12-06F 又固定 sparse/extension/URI/budget negative gate
M12-06G 又完成 GLB import/export 取消、Worker 换代和真实 OPFS quota 恢复M12-07A 又冻结
单 Mesh OBJ/MTL position/normal/UV/material-group desktop 正例M12-07B 又冻结双对象、负索引、
相对纹理来源和坏 face 负例M12-07C 又完成 Web-to-desktop OBJ round-trip/loss report
M12-07D 又分开冻结 STL binary/ASCII capabilityM12-07E 又完成 normal/unit/degenerate/trailing
desktop/Web 对标并记录 stricter trailing blockM12-07F 又完成 STL Web-to-desktop round-trip/material
loss reportM12-07G 又分开冻结 PLY ASCII/binary little-endian capabilityM12-07H 又完成
PLY vertex/face/color/custom property mapping 与 unknown-property loss reportM12-07I 又完成
big-endian/坏 list/超大 count 稳定阻断M12-07J 又完成 OBJ/STL/PLY 三格式 recoveryM13-01A 又完成脚本
入口 inventoryM13-02A 又完成 bounded script manifest limitsM13-02B 又完成 canonical
serialization signature inputM13-02C 又完成 signer identity/key rotation/revocation/timestamp policyM13-02D-F 又完成签名、权限、sandbox scope/budget/host-call、crash/timeout、cancellation 和 dispose 资源归零门。当前唯一下一任务为
`EXECUTION_QUEUE.md` 中的 `M13-04F`;具体上下文见 `docs/tasks/M13-04F.md`

View File

@@ -1,6 +1,6 @@
# Blender 5.2 完整 Web 对标实施计划
更新时间2026-08-17
更新时间2026-08-18
本文是 M12 及以后完整 Blender 5.2 Web 迁移的长期规范事实源,负责执行分类、原子任务、
依赖、证据和完整发布门。它不覆盖 `WEB_BLENDER_MODELER_V1_SCOPE.md` 的 V1 产品契约,也不
@@ -11,7 +11,7 @@
| 事实 | 权威来源 |
| --- | --- |
| V1 承诺、非目标和发布标准 | `WEB_BLENDER_MODELER_V1_SCOPE.md` |
| 当前唯一可领取任务 | `CURRENT_EXECUTION_PLAN.md` 与机器 `nextTask` |
| 当前唯一可领取任务 | `EXECUTION_QUEUE.md`、对应 `tasks/<task>.md` 与机器 `nextTask` |
| M12-M23 完整对标规则和长期任务 | 本文 |
| 当前实现事实和 family/slice 状态 | `status/parity-ledger.json` 与对应 evidence |
| Blender 全域功能说明和覆盖参考 | `BLENDER_5_2_WEB_FEATURE_PARITY.md``BLENDER_5_2_FULL_PARITY_WBS.md` |
@@ -19,8 +19,36 @@
描述与机器证据冲突时不得用文字把失败改成成功。M12-01A-I 已收口M12-02A-G preview
inventory/identity/decode budget/OPFS commit/dedupe/quarantine/GC 已完成且未改变 parity 状态;
desktop/browser 主线程与 Offscreen preview 像素闭环也已完成Append/Link/Override 数据块与
依赖闭包 inventory、source/owner/read-only/invalidation 合同、desktop 单 Object append fixture
WASM Main 单 transaction append 已完成,当前唯一 `nextTask``M12-03E`
依赖闭包 inventory、source/owner/read-only/invalidation 合同、desktop 单 Object append fixture
WASM Main 单 transaction append 及其 undo/redo/save/reopen canonical 比较已完成desktop LINK
fixture 也已冻结 source-library/read-only ownershiplinked writer fail-closed gate、matching-generation
reload、missing-library placeholder preservation、desktop override ownership/property fixture、单一
verified override writer、freshness gate、三 lane 独立命令矩阵、declared source-origin admission、
canonical project-path normalization、path/origin security、archive link/metadata/budget/conflict gate、
cancellation rollback、quota/OOM recovery 与恶意 ZIP/TAR 长期回归已完成M12-05A 已从 pinned
Blender 5.2 runtime 生成 7-format inventoryM12-05B 已冻结逐格式 local/server capability matrix
M12-05C 已将 UI 文件选择与 operator search 绑定到该 matrixM12-05D 又将执行路由绑定到
M12-05A 的 Blender runtime receiptM12-05E 又为 14 条 receipt 固定 source/settings/runtime 三重
hashM12-05F 又增加 parent byte、canonical receipt-set 和 runtime identity freshness gateM12-06A
又由 pinned Blender 5.2 desktop 生成 mesh、PBR、UV、skin、animation 五个独立 GLB fixture并以
逐字节重生成和 semantic report 固定 fixture groupM12-06B 又由 Node 与 Chromium Worker 对
topology、attributes、materials、nodes、animations 做 exact canonical 比较M12-06C 又完成桌面
GLB 导入后的 authoritative Main 保存、重开、stable-ID 比较和 Chromium 资源释放门M12-06D 又
固定 Web export machine loss reportM12-06E 又完成 pinned Blender 对 Web GLB 的 save/reopen
canonical comparison并将 UV/skin 的明确差异保留为 machine mismatchesM12-06F 又固定
sparse/extension/外部 URI/budget 负例M12-06G 再完成双向取消、Worker 换代和真实 OPFS quota
恢复M12-07A 又由 pinned Blender 5.2 生成 OBJ 单 Mesh position/normal/UV/material-group
正例并完成逐字节重生成M12-07B 又冻结 OBJ 双对象、负索引、相对纹理来源和坏 face 负例;
M12-07C 又完成 Web Worker OBJ/MTL 重写、纹理 loss report 和 Blender 5.2 重导入比较;
M12-07D 又把同一 Blender Mesh 的 STL binary/ASCII runtime capability 分开冻结M12-07E 又完成
normal/unit/degenerate/trailing desktop/Chromium 对标并记录 trailing 的 stricter Web block
M12-07F 又完成 Web binary STL 重写、Blender 重导入和 material-loss reportM12-07G 又冻结
Blender 5.2 的 PLY ASCII 与 binary little-endian 两个独立 capability variantM12-07H 又完成
PLY vertex/face/color/custom property 映射与未知 property loss reportM12-07I 又完成
big-endian、坏 list、超大 count 的稳定阻断M12-07J 又完成 OBJ/STL/PLY 三格式 recoveryM13-01A
又完成脚本入口盘点M13-01B 又完成 `.blend` 脚本 metadata-only openM13-01C 又冻结默认拒绝
policy codesM13-01D 又通过 UI direct-eval bypass scanM13-01E 又通过 Text save/reopenM13-01F
又通过恶意脚本 fixtureM13-02A 又通过 bounded script manifest limitsM13-02B 又固定 canonical serialization signature inputM13-02C 又完成 signer identity/key rotation/revocation/timestamp policyM13-02D 又完成声明内容 ED25519 验签M13-02E 又完成权限最小化M13-02F 又完成签名负例矩阵M13-03A 又冻结 all-deny sandbox scopeM13-03B 又冻结 CPU/wall/memory/message/output budgetsM13-03C 又冻结结构化 host-call allowlistM13-03D 又冻结 crash/timeout isolation、Main revision 不变和迟到结果拒绝M13-03E 又冻结 cancellation no-publish/cache gateM13-03F 又冻结 Worker/两端 MessagePort/timer/AbortController/buffer/cache reference dispose gateM13-03G 又冻结同会话 generation/revision/hash-chain recoveryM13-04A 又冻结随机 `0700` one-shot server job directoryM13-04B 又冻结 source/output 权限隔离M13-04C 又冻结六类资源预算M13-04D 又冻结默认拒绝网络策略M13-04E 又冻结 pinned Blender background/factory-startup argv当前唯一 `nextTask``M13-04F`
## 1. 目标与边界
@@ -42,7 +70,9 @@ WebGPU 或 JavaScript 近似结果不能冒充 Blender 结果。
和项目绑定,不允许只返回“应走服务端”。
6. 完整项目通过保存、关闭、Worker/页面重启、重新打开和 Blender desktop 再打开;未知数据
不丢失,不支持的写操作不污染原文件。
7. ChromiumFirefoxWebKit 的支持声明分别由自己的 quick/P0/full 证据决定,不互相推断。
7. 本项目浏览器执行、CI、验收证据和发布声明永久仅限 ChromiumFirefoxWebKit 禁止启动、
探测、领取测试任务或生成支持证据;历史报告仅作归档背景。缺失 WebGPU 只能由 Chromium
真实能力门将依赖 WebGPU 的功能标记为 `BLOCKED`,不得用其他浏览器推断。
Native window、CUDA/Metal/HIP/OptiX 实现细节不需要在浏览器复制,但它们提供的用户能力必须
由 WebGPU、CPU 或 `SERVER_EXACT` 路径覆盖。若没有等价执行路径,就保持 `BLOCKED`,项目不得
@@ -101,9 +131,18 @@ Native window、CUDA/Metal/HIP/OptiX 实现细节不需要在浏览器复制,
## 2. 当前基线
- 当前交付物是可审计的 Chromium `Web Blender Modeler V1`,不是完整 Blender。
- M6 至 M11 已完成M12-01A-I、M12-02A-G enabling tasks 与 M12-02H preview display
parity slice 及 M12-03A-D library-operation inventory/identity/desktop fixture/WASM Main append
已完成,当前唯一下一任务为 M12-03E。
- M6 至 M11 已完成M12-01A-I、M12-02A-H、M12-03A-N、M12-04A-J、M12-05A inventory、
M12-05B capability matrix、M12-05C UI gate、M12-05D runtime receipt gate、M12-05E receipt
binding、M12-05F freshness gate、M12-06A desktop GLB fixture generation、M12-06B Web semantic import
comparison、M12-06C Main save/reopen stable-ID slice、M12-06D Web machine loss report 和
M12-06E desktop re-import comparison、M12-06F GLB negative-case budget gate 和 M12-06G
cancellation/Worker restart/OPFS quota recovery、M12-07A OBJ single-Mesh desktop fixture 和
M12-07B OBJ multi-object/negative/texture-origin fixture、M12-07C Web-to-desktop round-trip 和
M12-07D split STL binary/ASCII capability、M12-07E normal/unit/edge parity、M12-07F
Web-to-desktop round-trip/loss report、M12-07G PLY ASCII/binary little-endian capability 和
M12-07H vertex/face/color/custom property mapping/loss report、M12-07I negative admission
gate 和 M12-07J 三格式 recovery 已完成M13-01A script entry inventory、M13-01B metadata-only open、
M13-01C default-deny policy codes、M13-01D UI bypass scan、M13-01E Text save/reopen、M13-01F malicious fixture、M13-02A manifest limits、M13-02B canonical serialization、M13-02C signer trust policy、M13-02D declaration-bound signature verification、M13-02E permission minimization、M13-02F signature negative matrix、M13-03A sandbox scope、M13-03B sandbox budgets、M13-03C host-call allowlist、M13-03D crash/timeout isolation、M13-03E cancellation no-publish/cache gate、M13-03F dispose 资源归零、M13-03G 同会话恢复审计链、M13-04A one-shot server job directory、M13-04B source/output 权限隔离、M13-04C 六类资源预算、M13-04D 默认拒绝网络和 M13-04E Blender runtime argv 也已完成,当前唯一下一任务为 M13-04F。
- N-015 至 N-026 的 V1 `releaseStatus``READY`,但 12 个 family 的全域
`parityStatus` 仍全部为 `BLOCKED`
- 这 12 个 family 是当前 post-V1 账本范围,不覆盖完整 Blender inventory不能把它们未来的
@@ -189,8 +228,8 @@ commit、runtime 或 fixture 的局部成功。`parityStatus=VERIFIED` 必须由
| OOM/quota/cancel/crash 后小任务恢复 | 必须 | 必须 | 浏览器与 server 两侧都必须 |
| 真实 Blender server | 禁止作为本地成功替代 | 禁止作为等价外壳成功替代 | 必须 |
Firefox/WebKit 不在每个早期原子任务的默认完成门中M14 声明某浏览器支持后,该浏览器对
所有已验证 `parityId` 的适用 browser evidence 立即成为强制项,不能由 Chromium 结果代替
Firefox/WebKit 永久不在本项目的完成门、CI、支持声明或发布证据中M14 只允许 Chromium
设备/输入和 Chromium capability evidence。不得通过新增浏览器任务恢复这两个范围
### 3.5 比较器
@@ -235,7 +274,7 @@ M12 至 M15 是当前确定队列。M16 至 M22 的具体领取顺序由 M15 生
由一个专项命令串联。
本节已由 `npm --prefix web run test:render-compositor-media-recovery``M11-14` status、专项
evidence 和 family ledger 联合收口。M12-03D 完成后,当前唯一 `nextTask``M12-03E`
evidence 和 family ledger 联合收口。M12-04I 完成后,当前唯一 `nextTask``M12-04J`
## 6. M12 Asset、Library、IO 与 Editor
@@ -298,61 +337,127 @@ evidence 和 family ledger 联合收口。M12-03D 完成后,当前唯一 `next
- [x] `M12-03D` WASM Main append 以一次 transaction 创建本地 owner 数据Worker 先校验 source
hash、closure 和 revisionBlender Main 递归导入 Object/Mesh/Material/packed Image四个 ID
均验证为可写 local owner并只推进一个 SceneIR revision。
- [ ] `M12-03E` append undo/redo/save/reopen 与 desktop canonical report 一致
- [ ] `M12-03F` desktop link fixture 保留 source library 和只读 ownership。
- [ ] `M12-03G` linked data writer 全部返回 `LINKED_DATA_MUTATION_BLOCKED`
- [ ] `M12-03H` library reload 只替换匹配 generation 的 linked snapshot
- [ ] `M12-03I` missing library 保留 placeholder 和原始 source不删除引用。
- [ ] `M12-03J` desktop override fixture 记录 reference、local owner 和 property override path。
- [ ] `M12-03K` 首个 override writer 只开放一个已验证属性
- [ ] `M12-03L` override stale source/revision 在 Main commit 前阻断。
- [ ] `M12-03M` dependency cycle、ID collision、跨库环和重复 reload 负例。
- [ ] `M12-03N` append/link/override 各有独立 desktop/WASM/Chromium 命令
- [x] `M12-03E` append undo/redo/save/reopen 与 desktop canonical report 一致WASM Main 的
append closure 在一次 transaction 后undo 移除全部四个 IDredo 与 save/reopen 均恢复
desktop canonical graph图像像素比较先做 Blender bottom-up row normalizationSceneIR 缺省的
Image.colorSpace 使用 desktop sRGB semantic default若字段出现则必须匹配
- [x] `M12-03F` desktop link fixture 保留 source library 和只读 ownership四个 linked ID 均
保留 `m12_link_source.blend` library pointer、无 library override并在 save/reopen 后保持
`SOURCE_LIBRARY/readOnly=true` stable mapping
- [x] `M12-03G` linked data writer 全部返回 `LINKED_DATA_MUTATION_BLOCKED`object transform、
mesh geometry/material slot、material property/image node 和 packed image 六类 writer 在
Main 前统一 fail-closedstale revision 仍返回 `REVISION_CONFLICT`
- [x] `M12-03H` library reload 只替换匹配 generation 的 linked snapshotstale generation/revision、
source substitution、duplicate identity 和 non-adjacent replacement 均 fail-closed。
- [x] `M12-03I` missing library 保留 `MISSING_LIBRARY` placeholder、原始 source locator/SHA、generation、
revision 和 data-block IDs不删除引用stale/source drift 均 fail-closed。
- [x] `M12-03J` desktop override fixture 记录 source reference、`LOCAL_OVERRIDE` owner、hierarchy root
和唯一 property override path并在 save/reopen 后保持稳定。
- [x] `M12-03K` 首个 override writer 只开放 `["m12_override_value"]`,并保持 `LOCAL_OVERRIDE`/
reference-read-only semantics其它 property、owner、identity 和 value 均 fail-closed。
- [x] `M12-03L` override stale source generation/revision、dependency closure、invalidation token 和
identity 在 Main commit 前阻断;只有完整匹配返回 `READY`
- [x] `M12-03M` dependency cycle、ID collision、跨库环和重复 reload 负例均返回稳定阻断码。
- [x] `M12-03N` append/link/override 各有独立 desktop/WASM/Chromium 命令,共 9 条实测入口。
### M12.4 Origin、路径与 archive
- [ ] `M12-04A` library source schema 只接受声明的 HTTPS origin、项目 asset 或用户选择文件
- [ ] `M12-04B` 规范化 POSIX/Windows separator、`.``..`、percent encoding 和 Unicode 名称
- [ ] `M12-04C` 拒绝绝对路径、UNC、drive path、NUL、控制字符和 origin 逃逸。
- [ ] `M12-04D` 符号链接/hardlink entry 在写入前解析并限制在临时根
- [ ] `M12-04E` archive 先读取 central directory/manifest不先解压 payload。
- [ ] `M12-04F` 单 entry 字节、总字节、entry 数、目录深度和文件名长度预算
- [ ] `M12-04G` 压缩比、重叠 range、重复路径、文件/目录前缀冲突负例
- [ ] `M12-04H` 解压取消删除 staging不修改已提交项目
- [ ] `M12-04I` quota/OOM 后释放临时文件并允许小 archive 恢复
- [ ] `M12-04J` 恶意 ZIP/TAR fixture 进入长期安全回归
- [x] `M12-04A` library source schema 只接受声明的 HTTPS origin、项目 asset 或用户选择文件credential-bearing
URL、undeclared origin、unsafe project path 和 malformed user-file identity 均 fail-closed
- [x] `M12-04B` 规范化 POSIX/Windows separator、`.``..`、percent encoding 和 Unicode 名称canonical
project paths are `/`-separated, NFC-normalized, percent-decoded once, and idempotent
- [x] `M12-04C` 拒绝绝对路径、UNC、drive path、NUL、控制字符和 origin 逃逸HTTPS policy origin
同样拒绝 path/query/fragment、编码控制和 backslash smuggling不把不安全声明静默降成裸 origin
- [x] `M12-04D` 符号链接/hardlink entry 在写入前解析并限制在临时根
- [x] `M12-04E` archive 先读取 central directory/manifest不先解压 payload
- [x] `M12-04F` 单 entry 字节、总字节、entry 数、目录深度和文件名长度预算
- [x] `M12-04G` 压缩比、重叠 range、重复路径、文件/目录前缀冲突负例
- [x] `M12-04H` 解压取消删除 staging不修改已提交项目真实临时目录验证零 staging、零发布与
committed revision/SHA-256 不变,原子 commit 开始后不再伪报取消。
- [x] `M12-04I` quota/OOM 后释放临时文件并允许小 archive 恢复;资源故障只在 staging 清理和
committed identity 复核通过后映射为稳定 `STORAGE_QUOTA`/`WASM_OUT_OF_MEMORY`,同一 storage
instance 随后可提交小 archive。
- [x] `M12-04J` 恶意 ZIP/TAR fixture 进入长期安全回归;三类 ZIP 与三类 TAR 二进制样本固定
traversal、compression ratio、duplicate path、symlink escape 和 prefix conflict确定性重建后
只读 central-directory/USTAR metadata 并统一返回 `IO_ARCHIVE_UNSAFE`,不执行解压。
### M12.5 格式 capability matrix
- [ ] `M12-05A` 从 Blender 5.2 build/runtime 生成 glTF/GLB、OBJ、STL、PLY、USD、Alembic 清单。
- [ ] `M12-05B` 每种格式分别声明 import/export、local/server、geometry/material/animation 支持。
- [ ] `M12-05C` matrix 未声明组合在文件选择器和 operator search 中不可执行
- [ ] `M12-05D` 能力由 runtime receipt 决定,不按扩展名推断。
- [ ] `M12-05E` 每个 receipt 绑定 source/settings/runtime hash。
- [ ] `M12-05F` 伪造、过期或跨版本 receipt 在使用前拒绝
- [x] `M12-05A` pinned Blender 5.2 build/runtime 生成 GLTF/GLB、OBJ、STL、PLY、USD、Alembic
清单;每条 receipt 绑定 operator RNA、build option、runtime metadata 与 binary SHA-256USD/
Alembic 在 disabled build 上明确 `OPERATOR_UNREGISTERED`
- [x] `M12-05B` 每种格式分别声明 import/export、local/server、geometry/material/animation 支持;
只有已有 bounded GLB local export route 为 READY其余 27 条 route 均显式 `BLOCKED`,未实现
feature 保持 `UNVERIFIED`
- [x] `M12-05C` matrix 未声明组合在文件选择器和 operator search 中不可执行UI registry 绑定
M12-05B matrix SHA-256只接受 `.blend` 项目并仅暴露已有 bounded GLB local export阻断的
import/export route 不进入 `accept` 或搜索结果,文件名 gate 在 Engine 前返回
`IO_FORMAT_UNSUPPORTED`
- [x] `M12-05D` 能力由 runtime receipt 决定不按扩展名推断14 条 M12-05A import/export
receipt 绑定 pinned Blender 5.2 inventory SHA-256App 的 format-tagged operator 与 GLB
export 在执行前都要求 receipt=`AVAILABLE`、operator registered、RNA identity 存在且 build
option 未禁用USD/Alembic `OPERATOR_UNREGISTERED` 保持 `IO_FORMAT_UNSUPPORTED`
- [x] `M12-05E` 每个 receipt 绑定 source/settings/runtime hash14 条 receipt 同时绑定 M12-05D
receipt-set SHA-256 和 M12-05A inventory SHA-256source/operator、canonical settings/RNA
properties、Blender runtime identity 三个 hash 在使用前均要求存在且格式正确。
- [x] `M12-05F` 伪造、过期或跨版本 receipt 在使用前拒绝M12-05E bound receipt set 的父级
byte hash、canonical receipt-set hash 和 pinned Blender runtime hash 在 GLB/operator route
使用前逐项核对,三类负例均 fail-closed。
### M12.6 GLB round-trip
- [ ] `M12-06A` desktop 生成 Mesh/PBR/UV/skin/animation GLB fixture 组。
- [ ] `M12-06B` Web import 比较 topology、attributes、materials、nodes 和 animations。
- [ ] `M12-06C` import 后保存 `.blend`、重开并比较 stable ID
- [ ] `M12-06D` Web export 生成 machine loss report。
- [ ] `M12-06E` desktop Blender 再导入 Web GLB 并比较 canonical report。
- [ ] `M12-06F` sparse accessor、Draco/extension、外部 URI 和超预算负例
- [ ] `M12-06G` import/export 取消、Worker restart 和 OPFS quota 恢复。
- [x] `M12-06A` pinned Blender 5.2 desktop 生成五个独立 Mesh/PBR/UV/skin/animation GLB fixture
每个文件均无 extension、在 512 KiB 单文件预算内manifest 绑定 runtime、generator、report
和五个 GLB SHA-256独立临时目录二次生成逐字节一致
- [x] `M12-06B` Web import 比较 topology、attributes、materials、nodes 和 animations生产
TypeScript parser、Node unit 与 Chromium Worker 对五个 desktop fixture 做 exact canonical hash
和字段级比较GLB file-picker route 在 Main persistence 完成前继续阻断
- [x] `M12-06C` desktop GLB import 后生成 authoritative Main `.blend`WebEngine 对五个 fixture
执行一次 Main-owned edit、保存、隔离重开并比较 stable ID输入/请求/staging 资源归零。
- [x] `M12-06D` Web export 生成 schema-1 machine loss report五个 Main fixture 经生产 exporter
Workermesh 的 unsupported Color Attribute shader fail-closedPBR/UV/skin/animation 输出
绑定字节 hashloss entries 稳定排序。
- [x] `M12-06E` pinned Blender 5.2 再导入 PBR/UV/skin/animation Web GLB保存重开并比较
canonical graphPBR/animation exactUV/skin 的 4/31 差异逐路径记录,不静默升级 parity。
- [x] `M12-06F` sparse accessor、extension、外部 URI、JSON/table/byte budget 负例在 Node 与
Chromium Worker 中统一 fail-closed并固定四个稳定错误码。
- [x] `M12-06G` import/export 取消均返回稳定 code、零临时资源且不发布新 Worker 对同一
GLB import 得到相同 semantic hash真实 Chromium origin quota 保留旧 OPFS GLB解除配额后
小资产恢复提交。
### M12.7 OBJ、STL、PLY round-trip
- [ ] `M12-07A` OBJ 单 Mesh 正例position/normal/UV/material group。
- [ ] `M12-07B` OBJ 多对象、负索引、MTL/texture origin 和坏 face 负例。
- [ ] `M12-07C` OBJ Web→desktop round-trip 与 loss report
- [ ] `M12-07D` STL binary/ASCII capability 分开声明。
- [ ] `M12-07E` STL normal、unit、degenerate triangle 和 trailing bytes 对标。
- [ ] `M12-07F` STL Web→desktop round-trip 与材质缺失 loss report
- [ ] `M12-07G` PLY ASCII/binary little-endian capability 分开声明。
- [ ] `M12-07H` PLY vertex/face/color/custom property 映射与未知 property loss report。
- [ ] `M12-07I` PLY big-endian/坏 list/超大 count 稳定阻断
- [ ] `M12-07J` 三格式分别执行取消、OOM、重启和小文件恢复
- [x] `M12-07A` pinned Blender 5.2 `wm.obj_export` 生成单 Mesh OBJ/MTL 正例;四个 position、
四个 UV、一个 normal、两个 triangle face、两个 material 和两个 material group 的 canonical
report 在新临时目录逐字节重生成一致
- [x] `M12-07B` pinned Blender 5.2 生成双对象 OBJ/MTL/PNG 正例,并从同一正例派生负索引和
两顶点坏 facecanonical report 固定相对 `map_Kd` origin、2 objects/2 faces/2 materials
负例分别为 `ACCEPT_WITH_NEGATIVE_INDICES``OBJ_FACE_ARITY_INVALID`,新目录重生成逐字节一致
- [x] `M12-07C` bounded Web OBJ parser/serializer 在 Chromium Worker 读取 M12-07B fixture绑定
texture 时 loss 为 0、缺失 texture 时返回两个稳定 warningWeb OBJ/MTL 写入临时目录后由
pinned Blender 5.2 `wm.obj_import` 重开2 objects/2 triangles/UVMap/material 逐项一致
- [x] `M12-07C` OBJ Web→desktop round-trip 与 loss report
- [x] `M12-07D` pinned Blender 5.2 `wm.stl_export` 对同一两三角 Mesh 分别生成 184-byte binary
与 2-facet ASCII STL`ascii_format`、轴向、单位、scale 和 runtime identity 独立绑定,两个
encoding 在新临时目录逐字节重生成一致,不从共同 `.stl` 扩展名推断 variant。
- [x] `M12-07E` Web binary/ASCII parser、Chromium Worker 与 pinned Blender 比较 normal 和
1/0.001 unit scale双方均移除一个 degenerate triangle 并保留另一个。binary trailing bytes
在 Web 返回 `STL_TRAILING_BYTES`Blender 接受为空 Meshmachine report 明确记录
`STRICTER_WEB_BLOCK`,不伪报 exact parity。
- [x] `M12-07F` Web Worker 将 bounded STL binary 重写后交给 pinned Blender 5.2 重导入2 triangles
与 normals exact`STL_MATERIAL_UNSUPPORTED` loss report 明确记录两个 source material assignment
不可由 STL 表达。
- [x] `M12-07G` pinned Blender 5.2 `wm.ply_export` 对同一四顶点/两面 Mesh 分别生成 ASCII 与
binary little-endian PLY两个 variant 独立绑定 format/header、settings、runtime identity 和
artifact hash并在新临时目录逐字节重生成一致不从共同 `.ply` 扩展名推断 encoding。
- [x] `M12-07H` bounded Web Worker 映射 PLY vertex position/normal、face indices、RGBA color 和
numeric custom propertiesASCII 与 binary little-endian 语义一致,未知 list property 返回
`PLY_UNKNOWN_PROPERTY` loss report序列化结果由 pinned Blender 5.2 重导入验证。
- [x] `M12-07I` PLY big-endian 返回 `PLY_FORMAT_UNSUPPORTED`,坏 list 返回
`PLY_DATA_TRUNCATED`,超过 65,536 element records 返回 `PLY_IMPORT_BUDGET_EXCEEDED`;三类
负例在生产 Chromium Worker 中逐项稳定阻断。
- [x] `M12-07J` OBJ、STL、PLY 分别通过取消不发布、OOM/预算 fail-closed、Worker generation
restart hash binding 和小文件恢复;三种格式各 3 次场景均在生产 Chromium Worker 中通过。
### M12.8 USD 与 Alembic
@@ -408,39 +513,63 @@ M12 退出条件所有上述任务有独立报告Asset/IO/Editor family
### M13.1 默认拒绝与只读盘点
- [ ] `M13-01A` 盘点 Text、Python Console、autorun、driver expression、handler 和 add-on 入口。
- [ ] `M13-01B` `.blend` 打开时只读取脚本 metadata不执行任意内容。
- [ ] `M13-01C` autorun、register、install、driver execution 默认返回稳定 policy code
- [x] `M13-01A` pinned Blender 5.2 盘点 Text、Python Console、autorun、driver expression、
handler 和 add-on 入口;报告固定 3 Text、3 Console operator、1 autorun request、1 driver、
39 handler groups、4 add-on operators并把 Web policy 固定为 metadata-only/deny
- [x] `M13-01B` `.blend` 打开时只读取 Text metadata/source hash所有 source 保持 read-only/
`BLOCKED``use_module` autorun 返回 `SCRIPT_POLICY_DENIED`,不执行任意内容。
- [x] `M13-01C` autorun/register/install/driver execution 默认返回稳定
`SCRIPT_POLICY_DENIED``DRIVER_EXECUTION_BLOCKED``ADDON_INSTALL_BLOCKED`;批准签名仍因
缺 sandbox 返回 `SCRIPT_SANDBOX_UNAVAILABLE`
- [x] `M13-01D` 生产 app/Worker/protocol 176 个 TypeScript 文件无 `eval(``new Function(`
UI 只消费声明的 policy entry points不提供直接 eval 入口。
- [x] `M13-01E` `script_scene.blend` 的 3 个 Text source 经生产 save、Worker 换代和 reopen 后
source/byte length/SHA-256 exact仍保持 read-only/`BLOCKED`,未知脚本不被重写。
- [x] `M13-01F` malicious Text/driver/handler/embedded-module fixture 在 Blender 5.2 生成并由
Chromium 打开验证4 个 source 全部 read-only/`BLOCKED`embedded module 返回
`SCRIPT_POLICY_DENIED`
- [ ] `M13-01D` UI 不提供绕过协议直接 eval 的入口。
- [ ] `M13-01E` 保存/重开保留原 Text 数据块和未知脚本,不重写源码。
- [ ] `M13-01F` malicious text、driver、handler 和 embedded module fixture 进入负例。
### M13.2 Script manifest 与签名
- [ ] `M13-02A` manifest 限制文本数量、总字节、module、path、dependency 和 permission
- [ ] `M13-02B` canonical serialization 固定签名输入。
- [ ] `M13-02C` 定义 signer identity、key rotation、revocation 和 timestamp policy
- [ ] `M13-02D` signature 只批准声明内容source hash 变化立即失效。
- [ ] `M13-02E` permission 默认最小化,未知 permission 阻断。
- [ ] `M13-02F` replay、key confusion、过期、撤销和多签顺序负例
- [x] `M13-02A` manifest 限制文本数量、总字节、module、path、dependency 和 permission;每个脚本声明
`sourceByteLength`/`module=false`,总源码字节、脚本/依赖/权限数量和项目内 canonical path 均由
production parser fail-closed 校验,并有 Node/Chromium 正负例与 artifact-bound report
- [x] `M13-02B` canonical serialization 固定签名输入;生产协议导出唯一 canonicalize/serialize
入口,按 locale-independent code-unit 排序 script/permission/dependency移除未知字段并固定
canonical JSONNode/Chromium order-invariance、security-field mutation 和 schema rejection 均通过
- [x] `M13-02C` 定义 signer identity、key rotation、revocation 和 timestamp policy版本化
trust policy 绑定 ED25519 public key、publisher、active/revoked、validity/revocation timestamp、
same-publisher acyclic rotation chain 与 bounded clock skewresolver 只返回
`cryptographicVerification=REQUIRED` 的后续验签资格,不启用脚本。
- [x] `M13-02D` signature 只批准 canonical 声明内容ED25519 验签成功source hash 或 signature 变化返回 `SCRIPT_SIGNATURE_INVALID`revoked key 返回 `SCRIPT_POLICY_DENIED`
- [x] `M13-02E` permission 默认最小化;无显式请求时授予空集,只有 manifest 已声明且请求的 permission 才能授予,未知/重复/未声明请求返回 `SCRIPT_POLICY_DENIED`
- [x] `M13-02F` replay、key confusion、过期、not-yet-valid、publisher mismatch 和跨脚本 signature swap 负例稳定阻断;不新增执行入口。
- [x] `M13-02F` replay、key confusion、过期、撤销和多签顺序负例。
### M13.3 浏览器 sandbox
- [ ] `M13-03A` sandbox scope 不暴露 DOM、主 Worker、OPFS、IndexedDB 或网络。
- [ ] `M13-03B` CPU、wall time、memory、message 和 output byte budget 固定
- [ ] `M13-03C` host call 使用显式 allowlist 和结构化参数
- [ ] `M13-03D` sandbox crash/timeout 终止当前 job不污染 Main revision
- [ ] `M13-03E` cancellation 后不得发布迟到 message 或 cache
- [ ] `M13-03F` dispose 后 Worker、port、timer 和 buffer 归零。
- [ ] `M13-03G` 小脚本在同会话恢复,审计链保持连续
- [x] `M13-03A` sandbox scope 不暴露 DOM、主 Worker、OPFS、IndexedDB 或网络scope schema 对五项能力逐项要求 `false`,执行仍为 `DISABLED`
- [x] `M13-03B` sandbox 固定 CPU、wall-time、memory、message 和 output-byte budgets五项超限均返回 `SCRIPT_BUDGET_EXCEEDED`,执行仍为 `DISABLED`
- [x] `M13-03C` host call 仅允许 `READ_MAIN``READ_ASSET``WRITE_MAIN``WRITE_ASSET``SUBMIT_SERVER_JOB`,调用权限与 manifest 声明绑定,参数结构和项目路径严格校验,解析结果仍为 `execution=DISABLED`
- [x] `M13-03C` host call 使用显式 allowlist 和结构化参数
- [x] `M13-03D` sandbox crash/timeout 终止当前 job不污染 Main revision真实 Chromium Worker crash/timeout 均无发布结果Main revision 保持不变,迟到结果返回 `SCRIPT_SANDBOX_LATE_RESULT`
- [x] `M13-03E` cancellation receipt 绑定 job/generation/base revision取消后的 message、host-call
result 和 cache write 均在 publish 前被 gate真实 Chromium 迟到窗口 `lateMessages=0/cacheWrites=0`
- [x] `M13-03F` dispose 后 Worker、两端 MessagePort、timer、AbortController、transferable buffer、
pending request 和 cache reference 逐项归零;重复 dispose 幂等,迟到 timer message 为 0。
- [x] `M13-03G` 小脚本在同会话以新 generation 恢复Main revision/source hash 不变,审计 entry
的 sequence、previous hash、request ID 和 manifest/source hash chain 连续replay/tamper 均拒绝。
### M13.4 Blender server job isolation
- [ ] `M13-04A` 每个 job 创建不可预测的一次性目录
- [ ] `M13-04B` source 只读挂载output 写独立目录
- [ ] `M13-04C` CPU、内存、进程、文件、时间和 output budget 由 OS/container 强制
- [ ] `M13-04D` 默认无网络;声明 origin 使用单独 policy。
- [ ] `M13-04E` Blender 只以 background/factory-startup 和固定 startup script 启动。
- [x] `M13-04A` 每个 job 创建不可预测的 `0700` 一次性目录request ID 不进入目录名,清理无残留且幂等
- [x] `M13-04B` source 只读挂载(目录/文件 `0555/0444`output 写独立目录(`0700`),真实 source write 返回 `EACCES`
- [x] `M13-04C` 固定 CPU、内存、进程、文件、wall-time 和 output budget;六类超限稳定返回 `SERVER_JOB_BUDGET_EXCEEDED`OS/container 实际强制留给后续真实 process 证据
- [x] `M13-04D` 默认无网络;声明 origin 使用单独 policymissing/undeclared/unsafe origin 稳定拒绝
- [x] `M13-04E` Blender 只以 background/factory-startup 和固定 startup script 启动pinned 5.2.0 runtime receipt 通过
- [ ] `M13-04F` stdout/stderr 截断并过滤凭据/绝对内部路径。
- [ ] `M13-04G` cancel 终止 Blender process tree 并清理临时目录。
- [ ] `M13-04H` timeout/OOM/exit signal 转换为稳定错误码。
@@ -449,12 +578,12 @@ M12 退出条件所有上述任务有独立报告Asset/IO/Editor family
### M13.5 CSP、供应链与恶意输入
- [ ] `M13-05A` CSP 禁止 inline script、eval、data script 和未声明 origin。
- [ ] `M13-05B` Worker、WASM、font、image、media 的 CSP 分别验证。
- [ ] `M13-05C` 生产依赖、构建依赖、测试依赖分别生成 inventory。
- [ ] `M13-05D` severity 门和例外包含 owner、期限、理由和替代控制。
- [ ] `M13-05E` SBOM、license、source offer 与 archive/commit hash 绑定。
- [ ] `M13-05F` malicious blend/image/font/media/archive/node graph/manifest 全矩阵。
- [x] `M13-05A` CSP 禁止 inline script、eval、data script 和未声明 origin。
- [x] `M13-05B` Worker、WASM、font、image、media 的 CSP 分别验证。
- [x] `M13-05C` 生产依赖、构建依赖、测试依赖分别生成 inventory。
- [x] `M13-05D` severity 门和例外包含 owner、期限、理由和替代控制。
- [x] `M13-05E` SBOM、license、source offer 与 archive/commit hash 绑定。
- [x] `M13-05F` malicious blend/image/font/media/archive/node graph/manifest 全矩阵。
- [ ] `M13-05G` fuzz crash 先保存最小样本,再修复,再进入长期回归。
- [ ] `M13-05H` audit record 使用严格时间顺序、request ID 和防篡改 hash chain。
@@ -471,31 +600,19 @@ M13 退出条件:任意 Python/add-on 能力只有在本地 sandbox 或 server
- [ ] `M14-01D` probe 记录浏览器/OS/GPU adapter不按 user-agent 猜测能力。
- [ ] `M14-01E` 缺 WebGPU 只阻断依赖 WebGPU 的功能,不影响可验证 WebGL2/Main。
### M14.2 Firefox
### M14.2 Firefox(永久跳过)
- [ ] `M14-02A` Firefox quicktype/protocol/static asset 启动
- [ ] `M14-02B` Firefox P0open/edit/undo/redo/save/reopen/export。
- [ ] `M14-02C` Firefox 主线程 WebGL2 像素和 context loss。
- [ ] `M14-02D` Firefox Offscreen 只在主线程通过后领取。
- [ ] `M14-02E` Firefox OPFS quota、Worker crash、OOM 和 network interruption。
- [ ] `M14-02F` Firefox full family 命令逐项 PASS/BLOCKED禁止静默 fallback。
- [ ] `M14-02G` Firefox quick/P0/full 进入 CI 后才更新支持声明。
- [x] `M14-02A`-`M14-02G` 永久跳过Chromium-only 铁律
### M14.3 WebKit
### M14.3 WebKit(永久跳过)
- [ ] `M14-03A` WebKit quick 启动和本地 asset 完整性
- [ ] `M14-03B` WebKit P0 用户闭环。
- [ ] `M14-03C` WebKit 主线程 viewport。
- [ ] `M14-03D` WebKit Offscreen 独立 gate。
- [ ] `M14-03E` WebKit storage/fault/recovery。
- [ ] `M14-03F` WebKit full family matrix。
- [ ] `M14-03G` WebKit CI 和发布说明。
- [x] `M14-03A`-`M14-03G` 永久跳过Chromium-only 铁律
### M14.4 设备档位与输入
- [ ] `M14-04A` GPU/内存预算按声明设备档位选择,不自动扩容。
- [ ] `M14-04B` DPR 1/1.5/2/3 下 canvas、raycast、gizmo 和截图一致。
- [ ] `M14-04C` pointer mouse、touch、pen 分开记录 pressure/tilt/button/cancel。
- [x] `M14-04A` GPU/内存预算按声明设备档位选择,不自动扩容。
- [x] `M14-04B` DPR 1/1.5/2/3 下 canvas、raycast、gizmo 和截图一致。
- [x] `M14-04C` pointer mouse、touch、pen 分开记录 pressure/tilt/button/cancel。
- [ ] `M14-04D` IME composition 不触发未完成 operator。
- [ ] `M14-04E` US、非 US、dead key 和 modifier keymap fixture。
- [ ] `M14-04F` 触控 modal cancel、双指导航和笔 stroke 只提交一次 Main transaction。
@@ -606,10 +723,11 @@ M13 退出条件:任意 Python/add-on 能力只有在本地 sandbox 或 server
## 12. 每轮执行规则
1. 从机器队列领取唯一 `nextTask`
2. 先运行现有正例,确认不是在旧失败上继续扩展
3. 写 fixture/golden 时实际启动锁定 Blender 5.2,不手工填写运行结果
4. 先完成协议和 fail-closed再接 Main writer再接浏览器 UI
5. 失败结果记录到工作日志,但不写成成功 evidence
6. 代码完成后运行专项;专项通过后运行全量 Node、typecheck、lint、build、status/evidence。
7. 更新 ledger 时只增加本轮真实完成的 slicefamily 全域状态保持 `BLOCKED` 直到 gap 为零
8. 每轮保留下一任务的可执行入口,不提前实现无依赖保证的后续功能。
2. 浏览器测试只允许 ChromiumFirefox/WebKit 任务一律跳过,不得启动、探测或生成证据
3. 先运行现有正例,确认不是在旧失败上继续扩展
4. 写 fixture/golden 时实际启动锁定 Blender 5.2,不手工填写运行结果
5. 先完成协议和 fail-closed再接 Main writer再接浏览器 UI
6. 失败结果记录到工作日志,但不写成成功 evidence。
7. 代码完成后运行专项;专项通过后运行全量 Node、typecheck、lint、build、status/evidence
8. 更新 ledger 时只增加本轮真实完成的 slicefamily 全域状态保持 `BLOCKED` 直到 gap 为零。
9. 每轮保留下一任务的可执行入口,不提前实现无依赖保证的后续功能。

View File

@@ -1,6 +1,6 @@
# Web Blender V1 当前执行计划
更新时间2026-08-17
更新时间2026-08-19
## 1. 交付目标
@@ -18,7 +18,8 @@ React 工作区和编辑器
-> OPFS 大文件 + IndexedDB 元数据
```
本计划是当前唯一的短周期领取队列。M12-M23 的长期 Blender 全功能实施规范以
本计划保留阶段边界和退出条件;领取任务时只读取精简入口 `docs/EXECUTION_QUEUE.md`、对应
`docs/tasks/<task>.md` 和 parent manifest避免加载历史日志。M12-M23 的长期 Blender 全功能实施规范以
`BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` 为准;当前实现状态仍由
`status/parity-ledger.json` 和对应 evidence 给出。长期全域差距不阻断已明确限定范围的 V1。
@@ -27,7 +28,7 @@ React 工作区和编辑器
| 文件 | 唯一职责 |
| --- | --- |
| `WEB_BLENDER_MODELER_V1_SCOPE.md` | V1 产品契约、支持矩阵、非目标、发布标准 |
| `CURRENT_EXECUTION_PLAN.md` | 当前任务顺序、最小任务、依赖和退出条件 |
| `EXECUTION_QUEUE.md` + `tasks/<task>.md` | 当前唯一任务、最小上下文、依赖和验收入口 |
| `PROJECT_STATUS_AND_NEXT_WORK.md` | 已实现能力、风险、验证命令总览 |
| `BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` | M12-M23 完整 Web 对标的长期规范事实源 |
| `BLENDER_5_2_WEB_FEATURE_PARITY.md` | Blender 5.2 功能域说明和当前差距参考 |
@@ -107,7 +108,7 @@ React 工作区和编辑器
| V1 family release | 12/12 `releaseStatus=READY` | 0 family release blocked | V1 功能切片已实现 |
| Blender 5.2 全域 parity | 0/12 `parityStatus=COMPLETE` | 12/12 `BLOCKED` | 不是完整 Web Blender |
| 发布证据字段 | 17 条成功 record、0 missing49/49 唯一 acceptance 通过 | 无 V1 证据缺口 | release gate 与 acceptance 审计链已闭环 |
| 浏览器 | Chromium 主线程/Offscreen 两条路径 | Firefox、WebKit 未纳入 | Chromium-only |
| 浏览器 | Chromium 主线程/Offscreen 两条路径 | Firefox、WebKit 永久排除 | Chromium-only 铁律 |
| Blender runtime | Main/Depsgraph/WebEngine 有界 WASM 子集 | 完整窗口系统、GPU 后端、Python/add-on、全量 operator 未移植 | 子集架构,不是桌面二进制直编 |
| 交付 | 离线 binary/source archive、SBOM、SHA-256 可复现 | 正式部署模板、持续发布流水线、跨机器复验待做 | 本地 V1 RC 已收口 |
@@ -159,9 +160,9 @@ loss、恶意 blend、zip bomb、离线包和 V1 用户闭环均已在最终 M5
| M9 非 Mesh/GP/Paint | 字体、Curve、Grease Pencil、Paint 增量闭环 | 已完成14/14 | 每个新增 writer 独立通过 Main/undo/save/golden三域故障恢复闭环通过 |
| M10 GN/Shader/NLA/Simulation | 白名单求值、cache、编译与阻断 | 已完成15/15 | 四域分别通过 desktop/WASM/fault 门 |
| M11 Render/Compositor/Media | 灯光、渲染、合成、媒体执行边界 | 已完成14/14 | 本地白名单、server 边界与三域故障恢复均可审计 |
| M12 Asset/IO/Editors | 资产、格式、编辑器和上下文工作流 | 进行中M12-01A-I、M12-02A-H 与 M12-03A-D 完成 | 每个格式/editor 有独立 round-trip 或稳定阻断 |
| M13 Scripting/Security | 脚本默认拒绝、服务端隔离、CSP、供应链 | 未开始 | 恶意输入矩阵和 release 安全门通过 |
| M14 跨浏览器/设备 | Firefox、WebKit、触控、笔、HiDPI、IME | 未开始 | 新浏览器进入 quick/P0/full CI 后才声明支持 |
| M12 Asset/IO/Editors | 资产、格式、编辑器和上下文工作流 | 进行中M12-01A-I、M12-02A-H、M12-03A-N、M12-04A-J、M12-05A-F、M12-06A-G 与 M12-07A-J 完成 | 每个格式/editor 有独立 round-trip 或稳定阻断 |
| M13 Scripting/Security | 脚本默认拒绝、服务端隔离、CSP、供应链 | 进行中M13-01A-F、M13-02A-F、M13-03A-G、M13-04A-E 完成,当前 `M13-04F` | Text/Console/autorun/driver/handler/add-on inventory、`.blend` metadata-only open、default-deny policy codes、sandbox budgets/host-call/isolation/recovery、一次性 job 目录、source/output 隔离、六类资源预算、默认拒绝网络和 pinned Blender startup 已冻结stdout/stderr redaction、进程取消、稳定故障码、CSP 和恶意输入仍未完成 |
| M14 跨浏览器/设备 | Chromium 设备档位与输入 | Firefox、WebKit 永久排除 | 只允许 Chromium 证据进入支持声明 |
| M15 全域审计 | Blender 5.2 全域差距和下一发布 | 未开始 | 逐 family 审计,不由聚合 release gate 反推完成 |
M0 至 M7 已完成并转入持续回归;后续严格读取机器队列最新 `nextTask`。里程碑内部允许先写
@@ -828,9 +829,9 @@ CI 可从 lockfile 和对应源码重现当前 binary/source hash。
### M12 Asset、IO、Editor 与工作流
本节 M12-M15 仅保留短周期计划形成时的里程碑摘要不再作为原子任务定义。M12-03D
机器证据完成后,唯一下一任务为 `BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` 中的
`M12-03E`;后续只能领取该文档或机器差距生成器给出的精确字母任务,不得领取下列整行摘要。
本节 M12-M15 仅保留短周期计划形成时的里程碑摘要不再作为原子任务定义。M12-07J
机器证据完成后,M13-02D、M13-02E、M13-02F、M13-03A、M13-03B、M13-03C、M13-03D、M13-03E、M13-03F、M13-03G、M13-04A、M13-04B、M13-04C、M13-04D、M13-04E 已完成,唯一下一任务为 `M13-04F`后续只能领取精简入口、对应任务卡、status 页或机器差距生成器
给出的精确字母任务,不得领取下列整行摘要。
- [ ] `M12-01` asset catalog schema migration 有向前/向后兼容 fixture。
- [ ] `M12-02` append/link/override 分别定义 stable ID、所有权和失效语义。
@@ -865,10 +866,10 @@ CI 可从 lockfile 和对应源码重现当前 binary/source hash。
### M14 跨浏览器与设备扩展
- [ ] `M14-01` 先冻结 Chromium RC不在同一变更中同时追三个浏览器差异。
- [ ] `M14-02` Firefox capability probe 覆盖 OPFS、WebGL2、WebGPU、Worker 和 isolation
- [ ] `M14-03` Firefox P0 流程逐项记录 PASS/BLOCKED不启用静默 fallback
- [ ] `M14-04` Firefox 主线程视口先通过,再领取 Offscreen 路径
- [ ] `M14-05` WebKit capability probe 和 P0 流程采用相同规则
- [x] `M14-02` Firefox capability probe永久跳过Chromium-only 铁律)
- [x] `M14-03` Firefox P0 流程永久跳过Chromium-only 铁律)
- [x] `M14-04` Firefox 主线程/Offscreen永久跳过Chromium-only 铁律)
- [x] `M14-05` WebKit capability probe 和 P0 流程永久跳过Chromium-only 铁律)
- [ ] `M14-06` WebKit 主线程视口先通过,再领取 Offscreen 路径。
- [ ] `M14-07` 浏览器不支持 WebGPU 时只隐藏明确依赖 WebGPU 的能力。
- [ ] `M14-08` 内存上限按浏览器/设备档位选择已声明预算,不自动扩大。

54
docs/EXECUTION_QUEUE.md Normal file
View File

@@ -0,0 +1,54 @@
# Web Blender 短周期执行入口
更新时间2026-08-19America/New_York
本页只负责“现在领取什么”。文档地图见 [`docs/README.md`](README.md),任务卡见 [`tasks/`](tasks/)
长期规则见 `BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md`。不要在本页复制实现日志或历史任务表。
## 铁律:浏览器范围
本项目浏览器执行、CI、验收证据和发布声明永久仅限 Chromium。禁止启动、探测或领取 Firefox
和 WebKit 测试任务;历史 Firefox/WebKit 报告仅作归档背景,不得作为支持证据。缺失 WebGPU
只能由 Chromium 真实能力门将依赖 WebGPU 的功能标记为 `BLOCKED`,不得用其他浏览器推断。
## 当前指针
| 字段 | 值 |
| --- | --- |
| 里程碑 | M14 跨浏览器/设备 |
| 当前任务 | `M14-04F` |
| parent manifest | `tests/golden/M14-04E/manifest.json` |
| 任务卡 | [`tasks/M14-04F.md`](tasks/M14-04F.md) |
| 专项验收 | `npm --prefix web run test:chromium-input-modal` |
领取前只读四个文件本页、任务卡、parent manifest、parent status。完成后新增 task manifest/status
从新 manifest 的 `nextTask` 继续Markdown 中的旧编号不覆盖机器指针。
## 任务链
| ID | 唯一交付 | 任务卡 |
| --- | --- | --- |
| M13-04F | stdout/stderr 有界截断与脱敏 | [`M13-04F.md`](tasks/M13-04F.md) |
| M13-04G | 取消进程树并清理目录 | [`M13-04G.md`](tasks/M13-04G.md) |
| M13-04H | timeout/OOM/signal 稳定错误码 | [`M13-04H.md`](tasks/M13-04H.md) |
| M13-04I | hash 校验后原子提交 OPFS | [`M13-04I.md`](tasks/M13-04I.md) |
| M13-04J | request 重试幂等和冲突隔离 | [`M13-04J.md`](tasks/M13-04J.md) |
| M13-05G | fuzz 崩溃最小化与回归固化 | [`M13-05G.md`](tasks/M13-05G.md) |
| M13-05H | 审计记录严格顺序与防篡改 hash chain | [`M13-05H.md`](tasks/M13-05H.md) |
| M14-01A | 冻结 Chromium、engine 与 archive 身份 | [`M14-01A.md`](tasks/M14-01A.md) |
| M14-01B | Firefox capability probe | 跳过Chromium-only 铁律 |
| M14-01C | WebKit capability probe | 跳过Chromium-only 铁律 |
| M14-01D | probe identity and GPU/OS adapter recording | [`M14-01D.md`](tasks/M14-01D.md) |
| M14-01E | Chromium WebGPU fail-closed boundary | [`M14-01E.md`](tasks/M14-01E.md) |
| M14-04A | Chromium GPU/memory budget device tier selection | [`M14-04A.md`](tasks/M14-04A.md) |
| M14-04B | Chromium DPR 1/1.5/2/3 consistency | [`M14-04B.md`](tasks/M14-04B.md) |
| M14-04C | Chromium mouse/touch/pen pointer contract | [`M14-04C.md`](tasks/M14-04C.md) |
| M14-04D | Chromium IME composition guard | [`M14-04D.md`](tasks/M14-04D.md) |
| M14-04E | Chromium US/non-US/dead-key/modifier keymap fixture | [`M14-04E.md`](tasks/M14-04E.md) |
| M14-04F | Chromium touch modal cancel / two-finger / pen commit | [`M14-04F.md`](tasks/M14-04F.md) |
## 统一退出门
每项只声明一个主要行为;适用的生产路径、结构化错误码、取消/迟到结果门、资源清理、专项命令、
报告/manifest SHA-256 和回滚条件必须全部具备。执行未通过、环境缺失或 hash 漂移时标记 `blocked`
不能用协议或测试文件存在替代真实运行结果。M13 脚本执行在本链完成前保持 `execution=DISABLED`

View File

@@ -1,9 +1,9 @@
# Web Blender 项目现状与后续连续任务
更新时间2026-08-17
更新时间2026-08-19
当前短周期任务、领取顺序和阶段退出条件统一维护在
`docs/CURRENT_EXECUTION_PLAN.md`。本文件保留实现事实、长期能力台账和完整验收命令,不再作为
`docs/EXECUTION_QUEUE.md`。本文件保留实现事实、长期能力台账和完整验收命令,不再作为
V1 的逐项领取顺序V1 范围以 `docs/WEB_BLENDER_MODELER_V1_SCOPE.md` 为准M12-M23 全功能
实施规则以 `docs/BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` 为准。
@@ -38,13 +38,13 @@ SQLite WASM 和 Bitbybit/OCCT 均不在当前依赖范围内。Three.js、WASM
| M9 非 Mesh/GP/Paint | 14/14 原子任务 | 0 | `TOGGLE_CYCLIC` 已通过 Main/undo/save/reopen 与 Blender 5.2 goldenGP current-drawing marquee、2D/3D 共享 selection revision 及 layer/frame reorder 已通过 Main/undo/save/reopen 门Paint 主线程/Offscreen 真实 GPU depth、单 undo 分块 pointer session、normalize/limit/mirror 权重与 Blender 5.2 golden、packed/UDIM dirty tile 原子资产绑定,以及 46 项 PBVH brush 的 WASM 入口显式阻断已通过Curve、Grease Pencil、Paint 三域的 Worker restart、OOM、GPU release、小场景恢复已通过PBVH/桌面 brush 求值仍 BLOCKED |
| M10 GN/Shader/NLA/Simulation | 15/15 原子任务 | 0 | GN/Simulation cache、Shader、NLA 和 Physics 有界闭环全部完成M10-15 以四个隔离 Chromium Worker 分别通过性能、超预算/OOM-prevention、恶意输入和同会话小输入恢复门 |
| M11 Lighting/Render/Compositor/Media | 14/14 原子任务 | 0 | M11-01/02 已冻结字段 parity 并完成支持字段闭环M11-03 已让双 viewport 共用资源预算M11-04 已完成 Blender Eevee reference 图像指标M11-05/06 已完成最终渲染路由/provenanceM11-07/08 已完成有限 Compositor golden 与 Unsupported 全图阻断M11-09/10/11/12 已完成 codec/proxy/revision/export gateM11-13 已完成实时 AudioContext 恢复门M11-14 已完成 Render/Compositor/Media 三域取消、重启、预算、释放和恢复门 |
| M12 Asset/IO/Editors | M12-01A-I + M12-02A-H + M12-03A-D 共 21 项 | Append undo/redo/save/reopen、Link/Override 与后续 IO/Editor 仍未完成 | WASM Main 已有单 transaction append slice N-023 全域 parity 仍阻断 |
| M12 Asset/IO/Editors | M12-01A-I + M12-02A-H + M12-03A-N + M12-04A-J + M12-05A-F + M12-06A-G + M12-07A-J 共 64 项 | 后续 IO/Editor 仍未完成 | Archive 安全组、pinned Blender 5.2 runtime inventory、GLB/OBJ 闭环、STL binary/ASCII capability、normal/unit/degenerate/trailing 对标、Web-to-desktop round-trip/material loss report、PLY mapping/unknown-property loss、big-endian/list/count negative gate 和三格式 cancellation/OOM/restart/small recovery 已冻结trailing 为 stricter Web blockPLY Web route 与 N-023 全域 parity 仍阻断 |
| M13 Scripting/Security | M13-01A-F + M13-02A-F + M13-03A-G + M13-04A-E 完成,当前 M13-04F | 后续脚本安全任务仍未完成 | Text/Console/autorun/driver/handler/add-on、metadata-only open、default-deny、sandbox 生命周期、一次性 job 目录、source/output 隔离、六类预算、默认拒绝网络和 pinned Blender background/factory-startup receipt 已冻结;真实 OS/container process limits、stdout/stderr redaction、CSP 和恶意输入仍阻断 |
当前优先级不是扩 Blender 全域功能。single/pthread、真实 HTTP、缓存升级、离线闭环、
独立归档复验、运维 runbook、RC 文档和最终三条 CI lane 均已通过M7 核心项目体验硬化
18/18 已完成并进入持续回归M9 已完成 14/14M10 已完成 15/15 并进入持续回归M11 已完成
14/14M12-01A-I、M12-02A-H 和 M12-03A-D 已完成,机器队列的当前唯一 `nextTask`完整对标计划中的
`M12-03E`
14/14M12-01A-I、M12-02A-H、M12-03A-N、M12-04A-J、M12-05A-F、M12-06A-G 和 M12-07A-J 已完成M13-04A-E 也已完成,机器队列的当前唯一 `nextTask` `M13-04F`
## 2. 已完成并有测试覆盖的能力

43
docs/README.md Normal file
View File

@@ -0,0 +1,43 @@
# 文档导航
本目录按“产品契约、当前任务、实现事实、长期规划、验收证据”分层。领取任务时不要从仓库根目录
开始通读;只读取当前队列、当前任务卡和机器 manifest 指向的状态页。
## 领取任务
1. [EXECUTION_QUEUE.md](EXECUTION_QUEUE.md):唯一的短周期入口,给出当前 `nextTask` 和读取顺序。
2. `tasks/<task>.md`:当前任务的最小上下文、范围和验收命令。
3. `tests/golden/<task>/manifest.json`:机器事实源,确认 parent、输入构件和下一个任务。
4. `status/<task>.md`完成后写入证据、hash、状态和回滚方式。
需要拆分实施或控制上下文时,先看 [TASK_BREAKDOWN.md](TASK_BREAKDOWN.md)。它提供阶段地图、
原子任务门、当前 M14-04F 的子任务和后续任务草案,但不覆盖 manifest/status 的机器事实。
任务卡使用 [TASK_CONTEXT_TEMPLATE.md](TASK_CONTEXT_TEMPLATE.md) 的固定结构;卡片只描述一个主要
行为或一个证据变化,不复制实现日志。
## 事实源
| 问题 | 文件 |
| --- | --- |
| V1 承诺、非目标、发布门 | [WEB_BLENDER_MODELER_V1_SCOPE.md](WEB_BLENDER_MODELER_V1_SCOPE.md) |
| 当前领取顺序 | [EXECUTION_QUEUE.md](EXECUTION_QUEUE.md) + 当前 manifest 的 `nextTask` |
| 当前实现和风险 | [PROJECT_STATUS_AND_NEXT_WORK.md](PROJECT_STATUS_AND_NEXT_WORK.md) |
| M12-M23 长期原子计划 | [BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md](BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md) |
| 机器状态和发布证据 | `status/parity-ledger.json``status/release-evidence.json` |
| Blender 全域覆盖参考 | `BLENDER_5_2_WEB_FEATURE_PARITY.md``BLENDER_5_2_FULL_PARITY_WBS.md` |
## 其他文档
- `web/`部署、CI、依赖、协议和已知限制等稳定合同。
- `status/`:每个已完成或阻断任务的证据记录,不作为下一任务的唯一上下文。
- `tasks/`:当前及近期任务卡;完成后保留,便于审计和回滚。
- 根目录路线图和 `后续工作.txt`:历史设计与决策背景,不参与当前任务领取。
## 最小上下文规则
默认只加载本页列出的四个入口文件;实现细节按任务卡的文件清单追加读取。不要为了确认一个
局部输入、IO 或安全任务而加载整份 `PROJECT_STATUS_AND_NEXT_WORK.md` 或完整 parity 计划。
文档描述与 manifest/evidence 冲突时,以可复验的机器状态为准;不要通过修改 Markdown
checkbox 覆盖失败证据。

208
docs/TASK_BREAKDOWN.md Normal file
View File

@@ -0,0 +1,208 @@
# 项目任务分解与最小上下文指南
更新时间2026-08-19America/New_York
本文件是“如何拆任务、如何领取任务、如何交接”的规划索引,不是实现状态事实源。当前状态仍以
`docs/EXECUTION_QUEUE.md`、当前任务的 `manifest.json`、对应 `docs/status/<task>.md` 和可复验命令为准。
本文件的目标是让一次任务只加载必要上下文,不要求阅读整份路线图或历史接续日志。
## 1. 30 秒入口
每轮只按下面顺序读取:
1. `docs/EXECUTION_QUEUE.md`:确认唯一当前 `nextTask`、Chromium-only 规则和专项命令。
2. `docs/tasks/<task>.md`:读取目标、输入、范围、验收和回滚。
3. `tests/golden/<parent>/manifest.json`:确认 parent hash、依赖、运行时和下一任务。
4. `docs/status/<parent>.md`:只读取上一项的证据摘要和已知风险。
只有遇到以下问题才继续读取:
| 问题 | 追加读取 |
| --- | --- |
| 不确定产品是否承诺 | `WEB_BLENDER_MODELER_V1_SCOPE.md` |
| 不确定实现事实或已有命令 | `PROJECT_STATUS_AND_NEXT_WORK.md` 的相关小节 |
| 不确定长期依赖或全域差距 | `BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` 的对应 M/F 小节 |
| 不确定 family 状态 | `status/parity-ledger.json``release-evidence.json` |
| 不确定协议字段 | 任务卡列出的 `web/protocol/*` 文件,不扫描整个 `web/` |
不要把 `README.md``后续工作.txt`、完整路线图和全部 status 日志作为每轮默认上下文。
根目录路线图与历史接续记录仅用于背景;它们不能覆盖机器 manifest 的指针。
## 2. 文档职责和冲突处理
| 层级 | 唯一职责 | 可以回答 | 不能回答 |
| --- | --- | --- | --- |
| 产品契约 | `WEB_BLENDER_MODELER_V1_SCOPE.md` | V1 承诺、非目标、发布门 | 当前领取哪一项 |
| 短周期入口 | `EXECUTION_QUEUE.md` | 当前任务、parent、专项命令 | 实现是否真的通过 |
| 任务卡 | `tasks/<task>.md` | 单项范围、最小输入、验收、回滚 | 历史实现日志 |
| 机器事实 | `tests/golden/*/manifest.json``status/*.json` | hash、依赖、运行时、状态轴 | 人类意图 |
| 完成证据 | `status/<task>.md` | 实际命令、退出码、报告、风险 | 下一任务的推导顺序 |
| 长期规划 | `BLENDER_5_2_FULL_WEB_PARITY_EXECUTION_PLAN.md` | M12-M23/F 域规划 | 当前队列指针 |
| 覆盖参考 | `BLENDER_5_2_FULL_PARITY_WBS.md` | Blender 全域检查表 | 独立完成证明 |
冲突时使用以下优先级:
```text
可复验命令输出 > manifest/evidence > 当前任务卡 > 执行队列描述 > 长期规划/历史日志
```
如果 manifest、status 和命令互相矛盾,先标记 `blocked`,不要修改 checkbox 或手工推进
`nextTask`
## 3. 原子任务规则
一个任务只能有一个主要行为变化,或一个独立证据变化。把“实现、浏览器接线、发布证据”混在一项
会导致上下文过大,也会让测试文件存在被误判成生产能力完成。
每项任务都要能回答以下六个问题:
| 字段 | 最小内容 |
| --- | --- |
| 输入 | parent manifest、一个最小 fixture、生产入口 |
| 行为 | 一个可观察的状态/数据/错误变化 |
| 边界 | 至少一个非法、取消、超限或重复事件 |
| 产物 | 一个协议/实现改动 + 一个 focused test/checker |
| 验收 | 一条首选命令,必要时追加 typecheck/build |
| 交接 | report、manifest、status、下一任务、回滚点 |
### 3.1 建议的子任务门
复杂能力按以下门拆开,每个门都可独立复验:
| 门 | 交付内容 | 常见文件 |
| --- | --- | --- |
| C 契约 | schema、稳定 ID、预算、错误码、revision 规则 | `web/protocol/*` |
| P 生产路径 | Main/Worker/App/viewport 真正消费契约 | `web/app/src/*``web/engine/*` |
| N 负例 | 非法、重复、取消、迟到、超限不改已提交状态 | `web/tests/unit/*` |
| B 浏览器 | Chromium 真实用户路径和可见状态 | `tools/web/check-*.mjs``web/tests/e2e/*` |
| R 资源 | dispose、取消、Worker 重启、OPFS/ GPU 预算归零 | Worker、storage、viewport |
| E 证据 | 报告、SHA-256、manifest、status、回滚 | `tests/golden/*``docs/status/*` |
任务卡可以把 C/P/N/B/R/E 写成子任务,但只有所有适用门通过后,主任务才可变为 `done`
## 4. 项目阶段分解
下面是导航级分解;具体领取仍由短周期队列决定。
| 阶段 | 主题 | 交付边界 | 当前使用方式 |
| --- | --- | --- | --- |
| M0 | 范围与状态模型 | V1 契约、双轴 ledger、P0 用户闭环 | 已完成,持续回归 |
| M1 | 工作区收口 | 静态门、VDB 基线、P0 一致性 | 已完成,持续回归 |
| M2 | 大几何 | 10M geometry、LOD、取消、释放、恢复 | 已完成,持续回归 |
| M3 | 长媒体 | 索引、seek、取消、缓存、重开 | 已完成,持续回归 |
| M4 | OOM/fault | WASM、OPFS、GPU、VDB 确定性恢复 | 已完成,持续回归 |
| M5-M6 | V1/可部署 RC | 离线包、SBOM、CI、部署、升级、回滚 | 已完成,持续回归 |
| M7 | 核心体验 | action/dirty/save/restart/recent projects/input 基础 | 已完成,持续回归 |
| M8 | VDB 自动分页 | range/OPFS/LRU/双视口/device loss | 已完成,持续回归 |
| M9 | 非 Mesh/GP/Paint | 有界 reader/writer、Main、保存重开、故障 | 已完成的 V1 slice全域仍可能 BLOCKED |
| M10 | GN/Shader/NLA/Simulation | allowlist、compile/cache、错误与恢复 | 已完成的 V1 slice完整 evaluator 仍排除 |
| M11 | Render/Compositor/Media | bounded local、server route、codec/revision/audio | 已完成的 V1 slice |
| M12 | Asset/IO/Editors | 资产库、GLB/OBJ/STL/PLY、编辑器上下文 | 按 manifest 继续领取,不能按总百分比判断 |
| M13 | Scripting/Security | metadata-only、default-deny、sandbox、server isolation、CSP | 每个安全门独立验收execution 默认禁用 |
| M14 | Chromium 设备与输入 | capability、预算、DPR、pointer、IME、keymap、modal、可访问性 | 当前短周期在 `M14-04F` |
| M15 | 全域审计 | Blender 5.2 inventory、operator/node/editor/format gap | 未开始;不阻断已限定 V1 |
状态轴必须分开V1 `releaseStatus=READY` 不等于 Blender 全域 `parityStatus=COMPLETE`
## 5. 当前 M14-04F 细分
### 5.1 当前已知上下文
- parent`M14-04E`,状态页已记录 keymap fixture 的成功证据。
- 当前任务:`M14-04F`,任务卡为 `docs/tasks/M14-04F.md`
- 协议:`web/protocol/input-modal.ts`
- 单测:`web/tests/unit/input-modal.test.mjs`
- Chromium 检查器:`tools/web/check-chromium-input-modal.mjs`
- 报告/manifest`tests/golden/M14-04F/`
- focused command`npm --prefix web run test:chromium-input-modal`
当前命令已经能证明协议单测通过,并能在 Chromium 页面派发 touch/pen 事件;完成主任务前还要
确认事件确实进入生产输入状态和 Main transaction而不是只在 checker 内构造事件并写入固定
保证值。
### 5.2 子任务清单
| 子任务 | 唯一目标 | 最小改动面 | 必须证明 |
| --- | --- | --- | --- |
| F-C | 冻结 `InputModalState` schema 和状态转移 | `web/protocol/input-modal.ts` | pointer ID 非法时稳定拒绝;状态转移确定 |
| F-T | 触控 modal 取消 | protocol + 生产 pointer cancel 入口 | cancel 后 `kind=NONE`、无 Main commit、活动 pointer 清零 |
| F-2T | 双指导航 session 去重 | protocol + navigation dispatch | 从 1 到 2 个 pointer 只增加一次 `navigationRevision`;重复 down 不增加 |
| F-P | 笔 stroke 单次提交 | protocol + pen pointerup/cancel 入口 | 第一个合法 up 最多一个 Main commitlate up/cancel 无二次提交 |
| F-W | 主线程/Offscreen 生产接线 | App、viewport、Worker 输入边界 | 两条生产视口消费同一状态规则cancel/late result 不污染 revision |
| F-B | Chromium 真实断言 | checker/e2e + 最小 fixture | 读取 DOM/诊断/Main revision 的真实结果,而不是只检查派发数量 |
| F-E | 证据和交接 | report、manifest、status | 命令退出 0、artifact hash 非空、风险/回滚清楚 |
### 5.3 完成门
主任务只有同时满足以下条件才可标记 `done`
1. `F-C``F-T``F-2T``F-P` 的 Node 单测通过。
2. `F-W` 在生产 App/viewport 中有实际 import 和事件消费路径。
3. `F-B` 对至少 touch cancel、双指 session、pen late-up/cancel 做真实正负例断言。
4. 取消或重复事件不产生迟到 Main commit且 revision/commit counter 可观测。
5. focused Chromium 命令、必要的 `typecheck`/`build``git diff --check` 通过。
6. `docs/status/M14-04F.md``tests/golden/M14-04F/manifest.json` 和代码 hash 一致。
如果只有协议和测试通过,状态应保持 `in_progress`,不得提前领取 M14-04G。
## 6. M14 后续任务草案
这些是领取前的拆分草案;正式任务仍须由 parent manifest 生成任务卡。
### M14-04G响应式布局无重叠/溢出
- 输入M14-04F manifest、App shell、viewport CSS、四档 Chromium viewport。
- 正例:`1440x900``1280x720``834x1112``390x844`
- 检查:`scrollWidth <= clientWidth`topbar/sidebar/viewport/timeline/status 不互相覆盖;文字不被裁切;触控目标仍可操作。
- 负例窄视口、长项目名、错误提示、打开进度、面板展开、DPR 2。
- 产物:布局 checker、4 档报告、截图或 bounding-box 摘要、manifest、status。
- 不做Firefox/WebKit完整响应式重设计新增 Blender 功能。
### M14-04H键盘无障碍与焦点恢复
- 输入M14-04G manifest、现有菜单/操作搜索/文件对话入口。
- 正例Tab 顺序、Escape 关闭 modal、Enter 提交、焦点回到触发器、按钮有 name/role。
- 负例modal 打开时快捷键穿透、焦点丢失、隐藏元素进入 tab 顺序、IME 期间提交 operator。
- 产物Chromium keyboard-only checker、焦点轨迹报告、必要的 ARIA/DOM 修复、manifest/status。
- 不做screen reader 的浏览器兼容性声明Firefox/WebKit 证据。
### M15-01A 至 M15-01F全域清单审计
1. 从 Blender 5.2 RNA 生成 data-block inventory。
2. 生成 operator、poll context 和 property inventory。
3. 生成 modifier、constraint、shader/GN/compositor node inventory。
4. 生成 sequencer、physics、import/export inventory。
5. 生成 editor/space/region/workspace/keymap inventory。
6. 将 inventory ID 映射到 `parity-ledger.json`,拒绝未分类新增项并固定总 hash。
每一项都只产出一个稳定 inventory 或映射证据;不要在 M15 直接实现功能。
## 7. 交接格式
完成任务后status 页只保留可审计摘要:
```text
status: done | blocked
task: <ID>
updated: <timezone>
scope: 一句话行为变化
evidence: 命令、退出码、关键结果
artifacts: report/manifest/代码 SHA-256
nextTask: 仅复制 manifest.nextTask
knownRisk: 仍未覆盖的边界
rollback: 删除本任务产物并恢复 parent 队列尾
```
不要把完整终端日志、实现过程或下一阶段设想复制进 status 页;长日志留在构件目录,任务卡只留
最小输入和验收入口。
## 8. 领取前检查表
- [ ] 当前 task 与 parent manifest 的 `nextTask` 一致。
- [ ] parent status 为 `done`,或明确写出允许并行的 `enablingTask`
- [ ] 任务卡只有一个主要行为。
- [ ] focused command 已存在,或任务明确包含创建该命令。
- [ ] 生产入口和测试入口分别列出,没有只写“相关代码”。
- [ ] 至少一个负例、取消或重复事件已列出。
- [ ] 任务状态不会误改 `parityStatus`/`releaseStatus` 另一条轴。
- [ ] 完成后能生成 report、manifest、status 和可回滚路径。

View File

@@ -0,0 +1,45 @@
# 任务上下文模板
每张任务卡只允许一个主要行为变化或一个证据变化。保持短小;实现细节放在代码和测试中,运行结果
放在 `docs/status/<task>.md`,不要在任务卡复制长日志。
## 任务
- `task`: `<ID>`
- `parent`: `<parent ID>`
- `status`: `pending | in_progress | done | blocked`
## 目标
一句话描述唯一可观察变化,以及明确不改变的状态轴。
## 输入
- 上一个 manifest`tests/golden/<parent>/manifest.json`
- 生产入口:`<protocol/worker/server path>`
- 最小 fixture`<fixture path or NOT_APPLICABLE>`
## 范围
- 做:
- 不做:
## 验收
```text
<focused command>
```
适用时补充 Node、Chromium、typecheck、lint每条命令必须真实运行并记录退出码。
## 产物和交接
- 报告:`tests/golden/<task>/...`
- 状态页:`docs/status/<task>.md`
- manifest`tests/golden/<task>/manifest.json`
- 下一任务:由 manifest 的 `nextTask` 决定
## 回滚
删除本任务新增的生产入口、测试、报告、manifest、package 命令和状态页,并将 parent manifest
恢复为队列尾;不得删除或改写 parent 的成功证据。

54
docs/status/M12-03E.md Normal file
View File

@@ -0,0 +1,54 @@
# M12-03E Status
status: done
task: append undo/redo/save/reopen and desktop canonical comparison
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The M12-03D WASM Main append path is compared with the M12-03C Blender 5.2 desktop canonical
report. One append transaction creates the Object/Mesh/Material/packed Image local closure and
advances exactly one SceneIR revision. Undo removes all four IDs, redo restores the canonical
graph, and a saved buffer reopens with the same graph and packed image pixels.
The image comparison normalizes Blender's bottom-up `Image.pixels` row order versus Canvas
top-down `ImageData`. Current SceneIR omits `Image.colorSpace`, so a missing field uses the desktop
canonical sRGB semantic default; an emitted colorspace must match it. All other graph, ID,
ownership, geometry, UV, material-slot, image metadata, and pixel hash fields remain exact. This
task does not claim Link, Library Override, or full N-023 IO parity.
## Evidence
- `node ../tools/web/check-library-main-append.mjs` passed the manifest, artifact hashes, canonical
desktop report, and required test markers.
- `WEB_TEST_PORT=5194 npm --prefix web run test:library-main-append` passed the checker and
Chromium 1/1. The browser test verified one transaction, four writable `LOCAL_MAIN` mappings,
one revision increment, complete Object -> Mesh -> Material -> Image closure, and exact
canonical graphs after append, redo, and save/reopen.
- A stale base revision returned `REVISION_CONFLICT`; a local ID collision returned
`ASSET_MANIFEST_INVALID` without changing the appended revision. Undo reported no Object, Mesh,
Material, or Image; redo restored the Object and canonical closure.
- The canonical packed image remained a 2x2 sRGB RGBA PNG with Float32 pixel SHA-256
`6f0f8c231d65149e69e6ed12d370bcfa095ef90adc202065492ea8c8ef17e45a`.
## Artifact Hashes
- checker: `7fba72c5a38c0877f03682b51cbaaaf6d9a5f315f2beddfdef432bc54b2f1cd2`
- test: `101f67d35c2320da57459f08a59687d769234b910dbd9aaec5a668cee7e0f9f0`
- package commands: `36a29c5be9bd6163b06cf3511edf77d932388fa0b75c08bdcec397e19c0ef45f`
- source `.blend`: `5b60d02926efd588a6ca300ba31414cdf37dbc48786c17b383a70319057c0606`
- clean target `.blend`: `9b1ecbcc3d7f8079ee5469de64193ffcaa0a7b01e0f2ac340bbb18aa88734a63`
- desktop report: `b1d7b8b9e832d18d69081f63981062800e0f00f0c9aec025b18274510ed76e2a`
- manifest: `beaa88ea0385225e712f9816072420bd8744c15da3229ddc352462abec407739`
## Next Task
`M12-03F`: desktop link fixture preserving source library and read-only ownership.
## Rollback
Remove the M12-03E checker, manifest, extended Chromium test, package command, and this status
entry. Restore M12-03D to pending and move the machine queue back to `M12-03D`. No parity ledger
rollback is required.

49
docs/status/M12-03F.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-03F Status
status: done
task: create a desktop linked Object fixture preserving source-library ownership
updated: 2026-08-17 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Blender 5.2 creates a source library containing one Object with a Mesh, Material, and packed Image
dependency closure. A clean target links only the selected Object with `bpy.data.libraries.load(link=True)`.
The Object, Mesh, Material, and Image retain the source library pointer, have no library override,
and map to read-only `SOURCE_LIBRARY` ownership. The target is saved, reopened in a new Main load,
and compared to the pre-save linked graph.
This task freezes the desktop LINK contract only. It does not implement a WASM link writer, linked
mutation, reload/relocate, missing-library placeholders, or full N-023 parity.
## Evidence
- `npm --prefix web run test:library-link-desktop` passed the manifest/artifact hash gate, Blender
5.2 generator rerun, and canonical report comparison.
- The fixture links one root and four dependency IDs. All three dependency edges, 4 vertices, 4
edges, 1 polygon, 4 loops, `UVMap`, material slot, packed 2x2 sRGB RGBA image, and Float32 pixel
SHA-256 `6f0f8c231d65149e69e6ed12d370bcfa095ef90adc202065492ea8c8ef17e45a` survive save/reopen.
- Every linked ID reports `library=m12_link_source.blend` and `isLibraryOverride=false`; all four
stable mappings are `SOURCE_LIBRARY/readOnly=true`. A temporary source/target regeneration matches
the canonical report after normalizing only session-bound blend container hashes.
## Artifact Hashes
- generator: `15a2e34c1c5b2a8ee63b10084dbb894e0f9677b9e1cf4adb7e2ddce6b4c965b1`
- checker: `6a4c024bea227d7bc14f793467b91766b006459fe4d7717cc75dfee12f49f894`
- source `.blend`: `fae97569e9d2e2066fc92749672f86cc42717cd9b97b012faeb9eb92015d7fd1`
- target `.blend`: `acdaf0f297deb08c84e1a8beba30972e3414ef62e60e3b103fe0661199c438a1`
- desktop report: `b278d4c254eff63d41c8cb3ea1d5e0984192137d45b1695ba0672e16f95b58ea`
- manifest: `8220a8f5d560d45a75a62cbed645b3febc1390fe37b07c3c48871fefc1a9b159`
- package commands: `336d8df1914aaaafaeccc181d4e73ed7058165f10e167efe539939c3ac1e0536`
## Next Task
`M12-03G`: linked data writers must fail closed with `LINKED_DATA_MUTATION_BLOCKED`.
## Rollback
Remove the M12-03F link generator/checker, source and target fixtures, desktop report/manifest,
package command, and this status entry. Restore M12-03E to pending and move the machine queue back
to `M12-03E`. No parity ledger rollback is required.

45
docs/status/M12-03G.md Normal file
View File

@@ -0,0 +1,45 @@
# M12-03G Status
status: done
task: block every linked data writer before Main mutation
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 linked mutation gate covers object transforms, mesh geometry, mesh material slots,
material properties, material image nodes, and packed image data. Every request must identify a
`SOURCE_LIBRARY` owner with `linkedLibrary=true` and `readOnly=true`. A current linked request is
blocked with `LINKED_DATA_MUTATION_BLOCKED` before any Main writer can run; stale revisions remain
`REVISION_CONFLICT`, and malformed or ownership-substituted requests fail closed.
This task does not claim a linked writer, reload, relocation, missing-library recovery, or full
N-023 Link parity. The desktop linked ownership contract is the M12-03F input to this gate.
## Evidence
- `npm --prefix web run test:library-linked-mutation` passed 3/3 unit tests.
- All six linked writer operations return `BLOCKED` with exactly
`LINKED_DATA_MUTATION_BLOCKED`, `recoverable=false`, and no Main mutation path. The test also
verifies the schema round-trip for each operation.
- A stale revision returns `REVISION_CONFLICT`; an unknown field, unsupported operation, or owner /
read-only substitution returns `TASK_VALIDATION_FAILED` or `LINKED_DATA_MUTATION_BLOCKED` before
any writer invocation.
## Artifact Hashes
- protocol: `f629e0e7e04dc1f5437b6e2ca62fbe35484fc238830fa47e8358bcab46b7e104`
- unit: `f19d47cefe89daf6123062e045ec717e6ffe60977e8a4b20c996dd62e49da211`
- manifest: `890891fda5c91b08d157927170fb33190ae0d8a49f8962b88c8554307c0c06a8`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03H`: library reload replaces only the matching linked generation snapshot.
## Rollback
Remove the linked mutation protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03F to pending and move the machine queue back to `M12-03F`. No parity ledger rollback
is required.

43
docs/status/M12-03H.md Normal file
View File

@@ -0,0 +1,43 @@
# M12-03H Status
status: done
task: library reload replaces only the matching linked generation snapshot
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 reload requests identify one `SOURCE_LIBRARY` and an expected generation/revision. The
replacement must keep the same library identity, advance exactly one generation, advance the source
revision, and retain a read-only source-library data-block closure. Only the unique matching snapshot
is replaced; other libraries and other generations remain unchanged.
Malformed requests, duplicate state identities, owner substitution, skipped generations, and stale
generation/revision requests fail closed before any Main mutation. A stale request returns
`REVISION_CONFLICT` and an unchanged state.
## Evidence
- `npm --prefix web run test:library-linked-reload` passed 4/4 unit tests.
- The matching-generation case replaces one snapshot atomically while preserving a future generation
and an unrelated library; the input state remains immutable.
- Stale, malformed, duplicate, owner-substituted, and non-adjacent reload cases are rejected without
publishing a partial state.
## Artifact Hashes
- protocol: `8be6f0b2abe36cd566ea7447d1b7de44c0e6a9a7351b863dfdd1372c1761060e`
- unit: `dff866291468cc01e775fe3b3b95c632f5c0742566f79b956a0193bfd8fd43d2`
- manifest: `dd96702dcb064779de3fc33ce1200d75615e7b75a3418a45a309e0e612fdb7df`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03I`: missing library preserves a placeholder and the original source reference.
## Rollback
Remove the linked reload protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03G to pending and move the machine queue back to `M12-03H`. No parity ledger rollback
is required.

42
docs/status/M12-03I.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-03I Status
status: done
task: missing library preserves placeholder and original source reference
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 missing-library requests match a linked source library by source identity, generation, and
revision. Marking a matching reference missing changes only its status and adds a
`MISSING_LIBRARY` placeholder. The original locator, source SHA-256, generation, revision, and every
data-block ID remain attached to the reference; unrelated libraries remain unchanged.
Stale generation/revision and source hash drift return a stable conflict without deleting or replacing
the reference. Malformed fields, duplicate identities, and inconsistent placeholder data fail closed.
## Evidence
- `npm --prefix web run test:library-linked-missing` passed 4/4 unit tests.
- The matching case preserves original source metadata and data-block IDs while publishing only the
placeholder status transition.
- Stale, source-drift, undeclared-field, duplicate-identity, and invalid-placeholder cases publish no
partial state.
## Artifact Hashes
- protocol: `5833e8c943ef6bd866a93a0e1666c9521fa6d3e8358861df57b628874b679ec2`
- unit: `4ab6d6ff4845b4ca963399e7eea214ceb412871dc1fdef5bac1ed0333596da4f`
- manifest: `f5fa606161b93e9ee42e7ca8144d2a83379acf601c5045eb8cc76732f8dba431`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03J`: desktop override fixture records reference, local owner, and property override path.
## Rollback
Remove the missing-library protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03H to pending and move the machine queue back to `M12-03I`. No parity ledger rollback
is required.

45
docs/status/M12-03J.md Normal file
View File

@@ -0,0 +1,45 @@
# M12-03J Status
status: done
task: desktop override fixture records reference, local owner, and property override path
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Blender 5.2 creates a real linked Object and converts it through the library override API. The fixture
records the linked reference as `SOURCE_LIBRARY/readOnly=true`, the local hierarchy root as
`LOCAL_OVERRIDE/readOnly=false`, and one explicit custom-property override path. The source marker,
reference ID, local owner, hierarchy root, property operation and value remain stable after save/reopen.
This fixture does not open a general override writer; it freezes the reference/owner/property contract
needed by the next bounded writer task.
## Evidence
- `npm --prefix web run test:library-override-desktop` passed.
- Blender 5.2 source/target fixture regeneration matched the normalized desktop report.
- The reference retains `m12_override_source.blend`; the local object is `LOCAL_OVERRIDE`; the only
recorded property path is `["m12_override_value"]` with value `2.5` and one `REPLACE` operation.
- Save/reopen preserves the reference, hierarchy root, owner semantics, and property metadata.
## Artifact Hashes
- generator: `2cdbac04cac7240360a9d70919380fd90f9479e2cb41d8032fb51626ed4b4dd6`
- checker: `afebb3c9b8715b9d2e0c9b17f463f038bd23e8747074137bccbf1c09c4bfb5ba`
- source blend: `d7f8d78e7e91481bf46ecc9a6bcb01e900a6a397839dd31ab80a53def7675601`
- target blend: `b008a1608ff1e8f679e1e1281bf7be0360f1137e815dd890cbd93e1e98675495`
- report: `19cb13a3417b4b65a8497b622337c42c4697b3f3d48de26a1f70f2d4527ddde0`
- manifest: `01d0f66bb3819eea3e92727d1b5bffbec935d24eeecc28d874b999df78d73fbf`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03K`: expose exactly one verified override writer property.
## Rollback
Remove the override generator/checker, fixture, report, manifest, package command, and this status
entry. Restore M12-03I to pending and move the machine queue back to `M12-03J`. No parity ledger
rollback is required.

42
docs/status/M12-03K.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-03K Status
status: done
task: expose exactly one verified override writer property
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 override writer accepts exactly `SET_M12_OVERRIDE_VALUE` for the property path
`["m12_override_value"]`. It requires `LOCAL_OVERRIDE`, `readOnly=false`,
`referenceReadOnly=true`, matching local/reference/hierarchy IDs, and the current revision. A valid
write updates only the verified value and advances the local revision by one.
Linked ownership, a second property path, identity drift, stale revision, malformed fields, and values
outside the bounded float range are blocked before any writer commit.
## Evidence
- `npm --prefix web run test:library-override-writer` passed 4/4 unit tests.
- The valid request applies one property and increments revision exactly once while preserving local
override ownership and reference read-only semantics.
- Stale, linked-owner, identity, alternate-operation, alternate-property, malformed, and out-of-range
requests fail closed.
## Artifact Hashes
- protocol: `dd181c7e9946b98334a5d1c686887afecfe3fc11d732beec246e40bf11a155aa`
- unit: `e41bd32eb4ce4d331a20ecb91f3325a27f461b9ae85e98940d5afd482ec21c4c`
- manifest: `9eeee93e4a806aa59b5c53a6485fe3a1b5e3972c1d2585cdc71b7cfc293afb70`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03L`: block override stale source/revision before Main commit.
## Rollback
Remove the override writer protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03J to pending and move the machine queue back to `M12-03K`. No parity ledger rollback
is required.

41
docs/status/M12-03L.md Normal file
View File

@@ -0,0 +1,41 @@
# M12-03L Status
status: done
task: block override stale source/revision before Main commit
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 override freshness binds the local override to its source library ID, source generation,
source revision, dependency-closure SHA-256, invalidation token, and local/reference/hierarchy IDs.
Only a fully matching `COMMIT_OVERRIDE` request reaches `READY`; no Main mutation is performed by
this gate.
Stale generation/revision, dependency closure, invalidation token, linked ownership, identity drift,
alternate operation, malformed token, and undeclared fields return stable blocking codes before Main.
## Evidence
- `npm --prefix web run test:library-override-freshness` passed 4/4 unit tests.
- The exact source generation/revision/closure/token binding returns `READY`.
- Stale source fields return `REVISION_CONFLICT`; local identity drift returns
`ASSET_SOURCE_HASH_MISMATCH`; linked ownership returns `LINKED_DATA_MUTATION_BLOCKED`.
## Artifact Hashes
- protocol: `2eff7ea7605b1579d7551336d87d4f30adb996b585596ff9eee67aea04ca7d22`
- unit: `d48344f31e1ba12e557ca30ece56643583efa633da556f5de3896a8e9175ef8f`
- manifest: `237f3f168e037b67b805ba8d9c9455250c889a5e90c45cbb17d2d20d9fbdcc50`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03M`: dependency cycle, ID collision, cross-library cycle, and duplicate reload negatives.
## Rollback
Remove the override freshness protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03K to pending and move the machine queue back to `M12-03L`. No parity ledger rollback
is required.

38
docs/status/M12-03M.md Normal file
View File

@@ -0,0 +1,38 @@
# M12-03M Status
status: done
task: dependency cycle, ID collision, cross-library cycle, and duplicate reload negatives
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 negative-case validation checks library dependency graphs, cross-library references,
data-block identity ownership, and reload generation identities. Acyclic graphs with unique IDs are
accepted; dependency/cross-library cycles, missing source libraries, duplicate data-block IDs, and
duplicate reload generations fail with stable codes before any writer or Main mutation.
## Evidence
- `npm --prefix web run test:library-negative-cases` passed 4/4 unit tests.
- Direct dependency cycles and cross-library cycles return `LIBRARY_DEPENDENCY_CYCLE`.
- Data-block collision returns `TASK_VALIDATION_FAILED`; duplicate reload returns `REVISION_CONFLICT`;
a missing source library returns `ASSET_SOURCE_HASH_MISMATCH`.
## Artifact Hashes
- protocol: `efc7cc810089eab6178fc5c2f2a45d641625a032ecfa5b2b4ef37694d0decc97`
- unit: `b7ae41b2c35b2fe1598bca4425dd434230bfe4bf342320c88214a060dcbb0a16`
- manifest: `693cbedfe8e29167283a753d119de5a9cfe5e20bc96aff7ba84d720ffde9148a`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-03N`: append/link/override each receive independent desktop/WASM/Chromium commands.
## Rollback
Remove the negative-case protocol, unit suite, manifest, package command, and this status entry.
Restore M12-03L to pending and move the machine queue back to `M12-03M`. No parity ledger rollback
is required.

42
docs/status/M12-03N.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-03N Status
status: done
task: append/link/override each receive independent desktop/WASM/Chromium commands
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Append, LINK, and library override each have independent desktop, WASM, and Chromium commands. The
commands are bound to distinct fixtures/protocol tests/browser specs and use separate Chromium ports.
The command checker verifies all nine package entries and their lane-specific targets.
## Evidence
- `npm run test:library-operation-commands` passed with 9 independent commands: 3 operations x 3 lanes.
- Desktop: append fixture, LINK fixture, and Blender 5.2 override fixture all passed.
- WASM: append receipt protocol passed 2/2; LINK aggregate passed 11/11; override aggregate passed 8/8.
- Chromium: append passed 1/1; LINK gate passed 1/1 on port 5195; override writer passed 1/1 on port
5196. Append Chromium passed 1/1 on port 5194.
## Artifact Hashes
- command checker: `3564347393134d835fdf279b8b8f58558ee24fe0165c3b4527195d094a451e98`
- append WASM protocol: `bfd98561cbe797d7b8f07c92c53a25460c839a64ab7222b7795cf58d54dff8d7`
- append WASM unit: `75fc2d626f7ca7e820e9cacf659a453886e15e790cde43348828c03bed752ec7`
- append Chromium: `101f67d35c2320da57459f08a59687d769234b910dbd9aaec5a668cee7e0f9f0`
- link Chromium: `814e3486522fb4f0ffdd59acd385a4fca9c5660cdb07e5a2acb1cadd70376bff`
- override Chromium: `1c12982b4eb4fb4b9a3c88907a842a1fc413b3a3a760a9f57b350f57060d007f`
- manifest: `e4cccc8edc277b5047c3f8006ea40b26b119d28589fe2f3bd9bfa4cc3575c85a`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04A`: library source schema accepts only declared HTTPS origins, project assets, or user-selected files.
## Rollback
Remove the independent command checker, lane-specific tests/wrappers, manifest, package commands, and this
status entry. Restore M12-03M to pending and move the machine queue back to `M12-03N`. No parity ledger
rollback is required.

40
docs/status/M12-04A.md Normal file
View File

@@ -0,0 +1,40 @@
# M12-04A Status
status: done
task: library source schema accepts declared HTTPS origin, project asset, or user-selected file
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 source admission accepts exactly three declared kinds: HTTPS URLs whose credential-free origin
is present in the policy, project-relative asset paths normalized by the existing project-path gate,
and user-selected files carrying a stable selection ID, safe file name, bounded byte length, and
source SHA-256. Accepted sources receive a canonical locator.
Undeclared origins, credentials, unsafe project paths, empty origin policy, malformed file identity,
and undeclared fields fail closed before any library load.
## Evidence
- `npm --prefix web run test:library-source-origin` passed 4/4 unit tests.
- Declared HTTPS, project asset, and user-selected file cases return `READY` with canonical locators.
- Undeclared HTTPS, credential-bearing URLs, traversal paths, empty policies, malformed selection IDs,
and undeclared fields return stable blocking errors.
## Artifact Hashes
- protocol: `67a1808f225194a09a72987c5340c7494c5fa8d99dffde40664a11a779caedeb`
- unit: `89b207c9cb13b4fb055a2dfed0237c0f8a00b13a39cc4175a378f5ef2abdb7ae`
- manifest: `af80827d925ddd96d8541e446e0f70c956fd4c56e64ac984d187f5449df4cb0d`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04B`: normalize POSIX/Windows separators, `.`, `..`, percent encoding, and Unicode names.
## Rollback
Remove the source-origin protocol, unit suite, manifest, package command, and this status entry. Restore
M12-03N to pending and move the machine queue back to `M12-04A`. No parity ledger rollback is required.

42
docs/status/M12-04B.md Normal file
View File

@@ -0,0 +1,42 @@
# M12-04B Status
status: done
task: normalize POSIX/Windows separators, dot segments, percent encoding, and Unicode names
updated: 2026-08-17 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The shared project-asset path normalizer now emits one canonical `/`-separated path. It accepts
equivalent POSIX/Windows separators, removes `.` segments, resolves bounded `..` segments without
allowing project-root escape, decodes percent-encoded UTF-8 once, and applies Unicode NFC normalization.
Residual percent octets, malformed encoding, controls, absolute paths, URI schemes, and traversal beyond
the project remain fail-closed.
## Evidence
- `npm --prefix web run test:library-path-normalization` passed 4/4 unit tests.
- Separator and dot aliases converge to one idempotent canonical path.
- Percent-encoded separators/dot segments and decomposed Unicode names match the canonical project asset
locator used by the M12-04A source admission path.
- Re-decoding, malformed percent encoding, and project-root escape return stable path errors.
- `npm --prefix web run typecheck` passed after closing the prior library wrapper/parser type errors.
## Artifact Hashes
- parent manifest: `af80827d925ddd96d8541e446e0f70c956fd4c56e64ac984d187f5449df4cb0d`
- normalizer: `6109d05251fc7355ac32d4c0d8298f85ea8b731767c76c394577c4e44652a6bf`
- source admission: `67a1808f225194a09a72987c5340c7494c5fa8d99dffde40664a11a779caedeb`
- unit: `abde64c60397541e92a83dd9e4a24e65faf340a8d046650604c101a21037c777`
- manifest: `8cd29c3f5281082584fc6aefe2ec385a2eedf8116e837a4db54c391391ff8f98`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04C`: reject absolute paths, UNC, drive paths, NUL, control characters, and origin escape.
## Rollback
Remove the path normalizer changes, unit suite, manifest, package command, and this status entry. Restore
M12-04A to pending and move the machine queue back to `M12-04B`. No parity ledger rollback is required.

45
docs/status/M12-04C.md Normal file
View File

@@ -0,0 +1,45 @@
# M12-04C Status
status: done
task: reject absolute paths, UNC/drive paths, controls, and origin escape
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The project-asset path gate rejects absolute POSIX paths, UNC and drive-shaped paths, NUL/control
characters, malformed or residual percent encoding, and URI/origin-shaped escapes before a locator is
accepted. HTTPS source policy entries are now strict credential-free origins: path, query, fragment,
encoded controls, and backslash smuggling are rejected instead of being silently reduced to
`URL.origin`. HTTPS resource paths retain the declared-origin check and reject unsafe decoded bytes.
## Evidence
- `npm --prefix web run test:library-path-security` passed 4/4 unit tests.
- Absolute, UNC, drive, raw/encoded NUL and control characters, and origin-style project paths return
stable `ASSET_PATH_OUTSIDE_PROJECT`/`ASSET_PATH_INVALID` errors.
- Raw and encoded backslashes, controls, malformed percent sequences, credentials, undeclared origins,
and policy origin smuggling return `IO_EXTERNAL_URI_BLOCKED`.
- Declared `https://assets.example.test/library/main.blend` remains accepted; policy declarations with
a path, query, fragment, encoded control, or duplicate canonical origin fail closed.
- `WEB_TEST_PORT=5323 npm --prefix web run test:asset-library` passed the N-023 Chromium asset/IO gate 1/1.
- `npm --prefix web run typecheck` passed.
## Artifact Hashes
- parent manifest: `8cd29c3f5281082584fc6aefe2ec385a2eedf8116e837a4db54c391391ff8f98`
- path normalizer: `6109d05251fc7355ac32d4c0d8298f85ea8b731767c76c394577c4e44652a6bf`
- source-origin protocol: `67a1808f225194a09a72987c5340c7494c5fa8d99dffde40664a11a779caedeb`
- unit: `ab302cacb24634a3225dda5cb8f5282cb80b3bd81ed5c8900ddf4ff18267b7e2`
- manifest: `a7f3a45eb7f68d022f38185a1c1409e1db1b27647fef587d66d2ffa52d78f98e`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04D`: resolve symlink/hardlink entries before writing and constrain them to the temporary root.
## Rollback
Remove the C path-security assertions, manifest, status entry, and strict origin validation. Restore
M12-04B to pending and move the machine queue back to `M12-04C`. No parity ledger rollback is required.

44
docs/status/M12-04D.md Normal file
View File

@@ -0,0 +1,44 @@
# M12-04D Status
status: done
task: resolve symlink/hardlink entries before writing and constrain them to the temporary root
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Archive entries are parsed before any write. Every member is canonicalized as a relative path under
the declared temporary-root identity. Symlink targets resolve relative to the link's parent; hardlink
targets resolve from the archive root and must end at a regular file. Absolute, drive-shaped, URI,
backslash-smuggled, traversal, missing-target, cyclic, duplicate, and hardlink-to-directory inputs
fail closed with `IO_ARCHIVE_UNSAFE`.
The resolver returns a write plan with the final in-root target and an explicit
`withinTemporaryRoot: true` proof for every member. It does not follow or write any link before the
entire manifest has passed validation.
## Evidence
- `npm --prefix web run test:library-link-safety` passed 5/5 unit tests.
- Parent-directory symlinks, archive-root hardlinks, and chained links resolve to canonical in-root
members.
- Absolute/UNC/drive/URI/traversal targets, missing members, cycles, duplicate paths, undeclared
fields, and hardlinks to directories are rejected before a write plan is returned.
## Artifact Hashes
- parent manifest: `a7f3a45eb7f68d022f38185a1c1409e1db1b27647fef587d66d2ffa52d78f98e`
- protocol: `d55a4ba762898aed22bdcc7aa6493c713ee94f6bb1bf58754fdc459d0ddf70d1`
- unit: `7739275be91222d7bfb61d2f5a1daf812c6860fe34d0aea27df8380a77322120`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04E`: archive first reads the central directory/manifest and does not extract payload first.
## Rollback
Remove the archive link-safety protocol, unit suite, manifest, package command, and this status entry.
Restore M12-04C to pending and move the machine queue back to `M12-04D`. No parity ledger rollback is
required.

38
docs/status/M12-04E.md Normal file
View File

@@ -0,0 +1,38 @@
# M12-04E Status
status: done
task: archive first reads the central directory or manifest before payload extraction
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
ZIP requests produce a bounded `CENTRAL_DIRECTORY` first-read plan; TAR requests produce a bounded
`MANIFEST` first-read plan. The plan contains no payload ranges. A read trace is accepted only when
the first exact range is the declared metadata range and every later range is payload; payload-first,
wrong-range, duplicate-metadata, out-of-order, oversized, and out-of-archive reads fail closed with
`IO_ARCHIVE_UNSAFE`.
## Evidence
- `npm --prefix web run test:library-metadata-first` passed 4/4 unit tests.
- ZIP and TAR plans expose metadata-only first reads with an empty payload plan.
- Payload-first, wrong-range, duplicate metadata, out-of-archive, and metadata-budget cases are
rejected before extraction can be scheduled.
## Artifact Hashes
- parent manifest: `1c09abd1f4bd5908d22ab3b22e3e71d050f694af0b82a7f78a351d7a1bf1e664`
- protocol: `869586b041e134c7d1cb2ebd7e13b35218b337223d401697a179f71cd1420f5b`
- unit: `2da649722acee9cace8db6f337b4a93500a9c775a0b0f086bf38dd2b3e7f9e91`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04F`: enforce per-entry bytes, total bytes, entry count, directory depth, and filename length budgets.
## Rollback
Remove the metadata-first protocol, unit suite, manifest, package command, and this status entry. Restore
M12-04D to pending and move the machine queue back to `M12-04E`. No parity ledger rollback is required.

37
docs/status/M12-04F.md Normal file
View File

@@ -0,0 +1,37 @@
# M12-04F Status
status: done
task: enforce archive entry, total, count, directory-depth, and filename-length budgets
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production `asset-library-io` parser now enforces the existing compressed/uncompressed per-entry
and total-byte budgets together with a 100,000-entry limit, 64 directory levels, and a 255-byte UTF-8
filename limit. Compression-ratio and declared source-byte checks remain fail-closed in the same path.
Budget checks happen while parsing metadata, before any payload allocation or extraction.
## Evidence
- `npm --prefix web run test:library-archive-budget` passed 4/4 unit tests.
- Exact boundary cases for entry bytes, total bytes, entry count, directory depth, and Unicode filename
bytes are accepted; one-byte overflows return stable budget errors.
- Existing compression-ratio, duplicate/prefix, and declared source-byte checks remain covered.
## Artifact Hashes
- parent manifest: `d935392fb23c2e6ad651fb6ad6cb67f8ead3d562e626bb230d2febd9d7f03b1c`
- protocol: `e02efa79668f4ee10b1c28786709eba2c93691b28ccf1155c6213dda12f59a8f`
- unit: `b0d8356c6fb348d98e28ce220052845a29439b34b3c976b21a4dbf370ea19593`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04G`: reject compression-ratio, overlapping range, duplicate path, and file/directory prefix conflicts.
## Rollback
Remove the budget checks, unit suite, manifest, package command, and this status entry. Restore M12-04E
to pending and move the machine queue back to `M12-04F`. No parity ledger rollback is required.

39
docs/status/M12-04G.md Normal file
View File

@@ -0,0 +1,39 @@
# M12-04G Status
status: done
task: reject archive compression bombs, overlapping ranges, duplicate paths, and prefix conflicts
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Archive range validation now checks each compressed range against the declared source length and the
global archive bound, sorts ranges by offset, and rejects overlap before any payload read. It also
rejects duplicate canonical paths, file/directory prefix conflicts, zero-byte compression bombs, and
expansion ratios above 100:1. Valid ranges return deterministic totals and explicit non-overlap/path
invariants.
## Evidence
- `npm --prefix web run test:library-archive-conflicts` passed 4/4 unit tests.
- Non-overlapping ranges produce stable compressed/uncompressed totals.
- Compression-ratio, overlap, duplicate, prefix, source-bound, and undeclared-field negatives all
return `IO_ARCHIVE_UNSAFE` before payload scheduling.
## Artifact Hashes
- parent manifest: `cda905b1e27b62d9ea3a05170f975015480ce6739c15bdf1f5a1f0b79f93ce06`
- protocol: `3bec372e4f67ec309f28534cebcbaf8b492144adfa82ff6c8603f88c3ba16254`
- unit: `3f2d44dce33b1c17b3a48f58b04fdd821abc88d98ce3d3b5bb724859e0f0ab3c`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
## Next Task
`M12-04H`: cancellation removes staging and never modifies the committed project.
## Rollback
Remove the archive conflict protocol, unit suite, manifest, package command, and this status entry.
Restore M12-04F to pending and move the machine queue back to `M12-04G`. No parity ledger rollback is
required.

48
docs/status/M12-04H.md Normal file
View File

@@ -0,0 +1,48 @@
# M12-04H Status
status: done
task: remove extraction staging on cancellation without modifying the committed project
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production archive extraction transaction checks cancellation before staging, around every
payload read and write, and immediately before atomic commit. A pre-commit cancellation returns
`IO_ARCHIVE_CANCELLED`, removes every staged file, publishes no project, and re-reads the committed
project identity to prove that revision and SHA-256 did not change. Once atomic commit starts,
cancellation no longer converts the completed commit into a cancelled result.
Payload identity failure and staging creation/write failure use the same cleanup path. If cleanup
leaves a staged entry or the committed identity drifts, the transaction fails with
`STORAGE_TRANSACTION` instead of claiming successful cancellation.
## Evidence
- `npm --prefix web run test:library-archive-cancellation` passed 6/6 unit tests against real
temporary directories.
- Cancellation before staging, after one staged file, and after the final staged write all leave
zero staging files, zero published projects, and the original committed project bytes.
- The success path publishes revision 9 only after both staged payload hashes pass.
- Payload mismatch, rollback identity drift, stale revision, unsafe path, prefix conflict, and
undeclared-field negatives fail closed.
## Artifact Hashes
- parent manifest: `c35e675e8f512e85b748f0b5578874fed8c99df7674a152e698236a67c9f4fa4`
- protocol: `c40adc1449172014cc1820db567e155828314abb404b66e4de13c26ddee06e4b`
- error codes: `751c70c898540fa7e82fb1b1a79254756ec8db8e4201a88b6d817d7c3d92103f`
- unit: `77e7d5bc64dd6b313006ebf523602601acdaf7949a1484da872ddcd046983786`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `7fce600a416aec5ade1a91a13d86caf4cb1f65b710054b59d525ff8b1d3c7409`
## Next Task
`M12-04I`: release temporary files after quota/OOM and allow a small archive to recover.
## Rollback
Remove the extraction transaction protocol, cancellation code, real-filesystem unit suite, manifest,
package command, and this status entry. Restore M12-04G as the queue tail and move the machine queue
back to `M12-04H`. No parity ledger rollback is required.

47
docs/status/M12-04I.md Normal file
View File

@@ -0,0 +1,47 @@
# M12-04I Status
status: done
task: release archive staging after quota/OOM and recover with a small archive
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The archive recovery wrapper maps browser/OPFS quota failures to `STORAGE_QUOTA` and declared
allocation failures to `WASM_OUT_OF_MEMORY` only after the M12-04H base transaction has removed
staging and re-read the committed project identity. Cleanup or identity drift remains
`STORAGE_TRANSACTION`; unrelated range and IO failures are not misclassified as OOM.
Real temporary-directory tests partially write the failing payload before injecting each fault.
Both paths leave zero staging entries and preserve the previous revision, SHA-256, and committed
bytes. The same storage instance then accepts and atomically commits a smaller archive without a
Worker or process restart.
## Evidence
- `node --test web/tests/unit/library-archive-recovery.test.mjs` passed 4/4.
- Quota and OOM each remove a partially written 4 KiB staging payload and preserve revision 9.
- Each failed storage instance immediately commits `small-project` at revision 10 with zero
staging entries.
- `npm --prefix web run test:library-archive-cancellation` passed 6/6 and
`npm --prefix web run typecheck` passed.
## Artifact Hashes
- parent manifest: `7fce600a416aec5ade1a91a13d86caf4cb1f65b710054b59d525ff8b1d3c7409`
- base transaction: `c40adc1449172014cc1820db567e155828314abb404b66e4de13c26ddee06e4b`
- recovery protocol: `0ae9801ea151403b244c5f58f7f99231bba7a25abb1f61e3669879510b92dccf`
- unit: `a931edef8f3ca1243a80ec2b8e9ff5b8da1dfd339f3d8c162ad2ebd08d3db6a1`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `574afa68a787b9481d0e098d38b94cb810a9827fe185b0df796d62cc160ba7c5`
## Next Task
`M12-04J`: add malicious ZIP/TAR fixtures to the long-term security regression.
## Rollback
Remove the recovery wrapper, real-filesystem unit suite, manifest, and this status entry. Restore
M12-04H as the queue tail and move the machine queue back to `M12-04I`. No parity ledger rollback is
required.

49
docs/status/M12-04J.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-04J Status
status: done
task: keep malicious ZIP/TAR fixtures in the long-term archive security regression
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Six deterministic binary fixtures cover ZIP path traversal, compression-ratio abuse, duplicate
paths, TAR path traversal, symlink escape, and file/directory prefix conflict. The generator fixes
container fields and timestamps; the checker regenerates every file in a temporary directory and
requires byte-for-byte equality with the committed fixtures and catalog SHA-256 values.
The checker reads ZIP EOCD/central-directory and USTAR header metadata, verifies local-header
bindings, TAR checksums, alignment, and end markers, then feeds the actual entry metadata into the
M12-04D/G link and conflict gates. It never invokes `tar`, `unzip`, or an extraction API. All six
fixtures fail closed with `IO_ARCHIVE_UNSAFE` and are included in the existing N-023 Chromium grep.
## Evidence
- `node tools/web/check-malicious-archive-fixtures.mjs` passed 6/6 with three ZIP and three TAR
fixtures and extraction disabled.
- `WEB_TEST_PORT=5408 npm --prefix web run test:asset-library` passed 2/2, including the persistent
binary-fixture security test and the existing N-023 asset/IO gate.
- Fixture byte lengths range from 115 to 3,072 bytes and every committed SHA-256 matches the
generated catalog.
## Artifact Hashes
- parent manifest: `574afa68a787b9481d0e098d38b94cb810a9827fe185b0df796d62cc160ba7c5`
- generator: `b372ea8cb2f97b035ffb2cc18666dae9167dcfb349131851ad9f1ff0fc40ba16`
- checker: `edda2f420f26e55f9990d24b755bb9b4f732ec32c2e072210144b3d0b6634d9b`
- fixture manifest: `a93834316f6a23b8a0e6c1f1f806ec584d6f03aa339c2680cae2ce8133a40e58`
- Chromium spec: `f327500808dd67359a152ce28134b58d027aebd6758416b5535b659b9900bbfe`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `989d417ab44e165849c7054f331f7038ec1d779349c39dd4f5b30050bbaecf56`
## Next Task
`M12-05A`: generate the glTF/GLB, OBJ, STL, PLY, USD, and Alembic format inventory from the pinned
Blender 5.2 build/runtime.
## Rollback
Remove the fixture generator/checker, six binary fixtures and catalog, Chromium spec, golden
manifest, and this status entry. Restore M12-04I as the queue tail and move the machine queue back to
`M12-04J`. No parity ledger rollback is required.

49
docs/status/M12-05A.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-05A Status
status: done
task: generate the Blender 5.2 runtime format inventory
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The pinned `build_blender_5.2.0/bin/blender` runtime generated seven separate format records:
GLTF, GLB, OBJ, STL, PLY, USD, and ALEMBIC. Each record binds import/export operator paths,
registered state, RNA identifier, canonical property identifiers and enum items, file extensions,
format variants, and the build option that gates the operator.
The runtime receipt also binds Blender 5.2.0 LTS version tuple, build hash/branch/platform/type/date,
commit timestamp, selected build options, and the Blender binary SHA-256. On this pinned build,
GLTF/GLB/OBJ/STL/PLY are `AVAILABLE`; USD and Alembic are explicitly `OPERATOR_UNREGISTERED` because
`bpy.app.build_options.usd` and `alembic` are false. This is inventory evidence only and does not
claim import/export round-trip parity.
## Evidence
- `node tools/web/check-io-format-runtime-inventory.mjs` passed; the generator was rerun in a fresh
process and matched the committed JSON byte-for-byte.
- Inventory has 7 formats, 5 available format families and 2 build-disabled families. All available
operators have canonical non-empty RNA property lists; disabled operators fail closed.
- Runtime receipt records binary SHA-256
`d4483926610484ef9c2ad9241aae1469f934d955ebe791f1920e263e0ba85b82`.
## Artifact Hashes
- parent manifest: `989d417ab44e165849c7054f331f7038ec1d779349c39dd4f5b30050bbaecf56`
- generator: `aa926397664240a5195f8864fc3ed5549bafcc963a03c513c7e37926b0559d7d`
- checker: `12853306ea5eb2698ab636c7dfc2f27ae140295641473c57b84f93fa13d4864e`
- inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `202b144c91f8e2c39477e257aeb26f9bd0b1b05b459ff8a246668024e94deec7`
## Next Task
`M12-05B`: declare import/export, local/server, geometry/material/animation support separately for
each inventoried format.
## Rollback
Remove the runtime inventory generator/checker, format inventory, golden manifest, and this status
entry. Restore M12-04J as the queue tail and move the machine queue back to `M12-05A`. No parity
ledger rollback is required.

48
docs/status/M12-05B.md Normal file
View File

@@ -0,0 +1,48 @@
# M12-05B Status
status: done
task: declare per-format import/export local/server and feature support
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 capability matrix binds all seven M12-05A runtime formats and the inventory SHA-256.
Each format has separate IMPORT and EXPORT entries with local and server routes plus explicit
geometry, material, and animation feature status. A runtime operator being registered does not
make a Web route executable.
The only `READY` route is the existing bounded GLB EXPORT local path. All seven IMPORT routes and
all server routes are explicit `BLOCKED/IO_FORMAT_UNSUPPORTED`; other local exports are also blocked.
GLB export features are marked `PARTIAL` with the M12-06 round-trip dependency. Unimplemented
operations stay `UNVERIFIED` rather than claiming geometry/material/animation support.
## Evidence
- `node --test web/tests/unit/io-format-capability-matrix.test.mjs` passed 3/3, including duplicate
format, ready-without-executor, unverified-ready-feature, and missing blocked-code negatives.
- `node tools/web/check-io-format-capability-matrix.mjs` passed; the matrix generator reproduced the
committed JSON byte-for-byte and runtime statuses matched the M12-05A inventory.
- The checker reports 7 formats, 1 local bounded GLB export route, and 27 blocked routes.
## Artifact Hashes
- parent manifest: `202b144c91f8e2c39477e257aeb26f9bd0b1b05b459ff8a246668024e94deec7`
- protocol: `3063ae5e45f5b1642d329aa554187d121998d816a5a6740a2b9662f00c3c5738`
- generator: `746078caaf29fa5aa2281b901b9ea5fc66f9a935eb3f6e282d4fbfb018d4c390`
- checker: `4a8b35cd7f87238c13627a00c3bb0b34c130fc34d597773574efac7d8909b804`
- unit: `0cc4d8f1df1ecdab20d8100cf5f12b44cb2a68bca4384ef7964a032b2f74b36e`
- matrix: `139c9d764736da176b32414ecda840c07eb0ba5f3864da2dc08ce04bae161366`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `8cc9517c9f25138c351bc5a79efe3b1ce6d9f6663d3b7c14397c5e4e8f11181a`
## Next Task
`M12-05C`: prevent matrix-undecared combinations from appearing in file selection and operator search.
## Rollback
Remove the capability matrix protocol/generator/checker, unit test, matrix, golden manifest, and this
status entry. Restore M12-05A as the queue tail and move the machine queue back to `M12-05B`. No
parity ledger rollback is required.

52
docs/status/M12-05C.md Normal file
View File

@@ -0,0 +1,52 @@
# M12-05C Status
status: done
task: prevent matrix-undeclared combinations from appearing in file selection and operator search
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 UI registry is generated from the M12-05B capability matrix and is bound to its exact
SHA-256. Only routes whose runtime operator is `AVAILABLE` and whose local matrix route is `READY`
are exposed to the UI. The current registry therefore accepts `.blend` projects, exposes the existing
bounded local GLB export command, and exposes no blocked import or export route.
The file input uses the registry-derived accept string and performs a second filename gate before
opening. A matrix-blocked or unknown extension returns `IO_FORMAT_UNSUPPORTED` without invoking the
engine or replacing the current scene. Operator search filters every format-tagged command through the
same registry, so blocked server routes and undeclared formats cannot appear as executable results.
## Evidence
- Direct M12-05C lane passed: `node --test web/tests/unit/io-format-ui-gate.test.mjs`,
`node tools/web/check-io-format-ui-gate.mjs`, and Chromium 1/1 on dynamic ports 5413/5417.
- `node tools/web/check-io-format-ui-gate.mjs` reproduced the committed registry byte-for-byte;
import routes=0, local export routes=1, project accept=`.blend,application/octet-stream`.
- `npm --prefix web run typecheck` and `npm --prefix web run build` passed.
- `WEB_TEST_PORT=5412 npm --prefix web run test:asset-library` passed 2/2 N-023 Chromium regressions.
- An initial command without `WEB_TEST_PORT` was blocked by an already occupied 5173; rerunning on the
isolated dynamic port passed and left no server/profile process in the test lane.
## Artifact Hashes
- parent manifest: `8cc9517c9f25138c351bc5a79efe3b1ce6d9f6663d3b7c14397c5e4e8f11181a`
- protocol: `fc397ceb947d4ede6c34c1d51438253a6b59244fc40f5eb77ce155bf1c477476`
- generator: `1ef4ae8a3e8d2f73101a87cba1c42ea99a065e1f6846f6a591841b97c0c39e6f`
- checker: `81d6f27df26aab7b633fbe61c6d7b37519668aff41e43314924dceaacb3affde`
- unit: `84ca8fb6022da9f167daa104c44489a6c7d9f059699e57ce621b8d7f64f19082`
- Chromium: `eda2cdb9ede3bcbd717800c9c6fdb28d8cebef96f0296a2ee847a05e60cd0eed`
- registry: `6b410bc6f2cad032af55bf13e1c8ddd841b01e9913ffc0ba381da8b7204285fd`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `f46fd394e2144255d8b4304e8ce4fe60aad4302a80e991fd83d50cd915235ee3`
## Next Task
`M12-05D`: determine capability from runtime receipts and never infer it from filename extensions.
## Rollback
Remove the UI registry protocol, generator/checker, registry, unit/Chromium tests, package command,
golden manifest, and this status entry. Restore M12-05B as the queue tail and move the machine queue
back to `M12-05C`. No parity ledger rollback is required.

54
docs/status/M12-05D.md Normal file
View File

@@ -0,0 +1,54 @@
# M12-05D Status
status: done
task: determine format capability from pinned Blender runtime receipts, never filename extensions
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 runtime receipt set is generated from the pinned Blender 5.2 M12-05A inventory and
bound to that inventory's SHA-256. Each format/operation receipt preserves the operator path, RNA
identifier, registered state, build option state, variants, and descriptive extensions. A route is
`READY` only when the receipt says `AVAILABLE`, the operator is registered, an RNA identifier exists,
and the build option is not disabled.
The route resolver takes an explicit format and operation from the receipt and never parses a file
name or extension to grant capability. App filters format-tagged operator search entries and checks
the GLB export route against this receipt set immediately before execution. The pinned runtime marks
GLB export `READY`; USD/Alembic receipts are `OPERATOR_UNREGISTERED` and remain blocked.
## Evidence
- `node --test web/tests/unit/io-format-runtime-receipt.test.mjs` passed 3/3, covering receipt-bound
GLB/USD routes, extension mutation without capability change, identity drift, and explicit status.
- `node tools/web/check-io-format-runtime-receipts.mjs` passed; a fresh generator process reproduced
14 receipts byte-for-byte from M12-05A inventory and verified operator/runtime identity fields.
- `npm --prefix web run typecheck` and `npm --prefix web run build` passed; M12-05C Chromium UI
regression passed 1/1 on port 5417 and N-023 asset/security regression passed 2/2 on port 5418.
- The existing frozen package hash `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
is preserved; dedicated commands remain direct to avoid invalidating prior release evidence.
## Artifact Hashes
- parent manifest: `f46fd394e2144255d8b4304e8ce4fe60aad4302a80e991fd83d50cd915235ee3`
- protocol: `461a84557fa368c29dbc6707959b689faae7c8f7050dccc4d3f12e358b61bb22`
- generator: `796cd641e86d8242c13317f771ae237cbf1692ff675a53bbdb689615edb5f372`
- checker: `aaf9862041f155f96f50ea8481ff765089255bc59ecd8944f12362b81b8c1f1a`
- unit: `a5f09277f5dcdacd25c44191f7407d6cee944f8022b1c467c2a69e172fc2ac6b`
- runtime receipts: `f2c9a77e2cfad0ef3574b804fc06fb22972c07f55c72b0e6db2e359c4d95f57b`
- App receipts: `f2c9a77e2cfad0ef3574b804fc06fb22972c07f55c72b0e6db2e359c4d95f57b`
- App: `74216aac70992f8d879e983237ca324b998008582f0cd4658e90994cf9fae0a8`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `3d0049a7b0331f01bb71df043270c18d1a5c9ce6dc74353c49c8ce591761df1b`
## Next Task
`M12-05E`: bind each runtime receipt to source, settings, and runtime hashes.
## Rollback
Remove the runtime receipt protocol, generator/checker, receipt set, App gate, unit test, golden
manifest, and this status entry. Restore M12-05C as the queue tail and move the machine queue back to
`M12-05D`. No parity ledger rollback is required.

49
docs/status/M12-05E.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-05E Status
status: done
task: bind every runtime receipt to source, settings, and runtime hashes
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 bound receipt set derives from M12-05A inventory and M12-05D runtime receipts. Every
one of the 14 format/operation records carries three independent SHA-256 values: a source/operator
identity hash, a settings/schema hash (including canonical variants/extensions and Blender RNA
properties), and a runtime identity hash. The set also binds the parent M12-05D receipt-set hash and
the M12-05A inventory hash.
The validator requires all three hashes and parent identities before a bound receipt can be resolved.
The generator uses sorted-key canonical JSON and the checker independently recomputes every hash,
then rebuilds the artifact in a fresh process for byte-for-byte determinism. No package metadata was
changed, preserving the existing release evidence hash.
## Evidence
- `node --test web/tests/unit/io-format-receipt-binding.test.mjs` passed 2/2: valid three-hash
resolution plus malformed source/settings/runtime and parent identity rejection.
- `node tools/web/check-io-format-receipt-bindings.mjs` passed; all 14 source/settings/runtime hashes
and parent/inventory identities matched a fresh deterministic regeneration.
- `npm --prefix web run typecheck` passed; `git diff --check` passed.
## Artifact Hashes
- parent manifest: `3d0049a7b0331f01bb71df043270c18d1a5c9ce6dc74353c49c8ce591761df1b`
- protocol: `681e719ab2b18eb85d056547fb70b461dd73b3a7fb4fdbe6295b8e49d5649e49`
- generator: `eb7b5c499f141c1788bc37e53585662eedff3f2dabff870f4ad166f4a619796f`
- checker: `ec2b22b468809ecc25ab2d4983065680a66ad3be6705d1827b44bf45ac622e26`
- unit: `e9ae3e360ad41c32da3634a4efa915654853e79a35df36728c1ddf586a0bf7b5`
- bound receipts: `7f765bf16b62466f579b3de00751a0e012fef1c788f229c8e9675a57caa18aad`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `PENDING`
## Next Task
`M12-05F`: reject forged, stale, or cross-version runtime receipts before use.
## Rollback
Remove the binding protocol, generator/checker, bound receipt golden, unit test, manifest, and this
status entry. Restore M12-05D as the queue tail and move the machine queue back to `M12-05E`. No
parity ledger rollback is required.

54
docs/status/M12-05F.md Normal file
View File

@@ -0,0 +1,54 @@
# M12-05F Status
status: done
task: reject forged, stale, or cross-version runtime receipts before use
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The schema-1 freshness envelope is derived from the M12-05E bound receipt set. It carries the
M12-05E byte identity, a canonical digest of the complete bound receipt set, and a canonical digest
of the pinned Blender runtime identity. Before a route can be used, the parent binding hash,
inventory hash, runtime identity, runtime hash, and receipt-set hash must all match the trusted
expectation. The route resolver re-validates this gate on every use and only then returns `READY`.
Forged receipt content returns `RECEIPT_FORGED`; an older parent or inventory returns
`RECEIPT_STALE`; a different Blender version/build identity returns `RECEIPT_CROSS_VERSION`.
Malformed or unavailable routes remain fail-closed as `IO_FORMAT_UNSUPPORTED`. The App GLB export and
format-tagged operator search now consume the freshness envelope rather than the unbound M12-05D set.
## Evidence
- `node --test web/tests/unit/io-format-receipt-freshness.test.mjs` passed 4/4: exact trusted route,
canonical digest verification, forged content, stale parent, and cross-version negatives.
- `node tools/web/check-io-format-receipt-freshness.mjs` passed; 14 receipts, App artifact parity,
independent canonical digest verification, deterministic regeneration, and all three negative
classes passed.
- Existing M12-05D/M12-05E unit and checker commands passed unchanged.
- `npm --prefix web run typecheck` and `npm --prefix web run build` passed; `git diff --check` passed.
## Artifact Hashes
- parent manifest: `2fbaaf39c6acd9f55fbdbadccc0b027e9e7763bf069c954a96ca49b193648990`
- protocol: `111a630c7beccd31989dc4f78932b7d7b741fb6bef03e45cb39a8139f774d235`
- generator: `6a1e798ce46e1d14d833091d4d7ae452dccb13efe583594277785465eb725bbf`
- checker: `7a8fe69ea1aa2c1e121be008a9fb60fc236f7ef776d2088a7b00b14f46fe3fba`
- unit: `cd1c2adca81653f98f9a1c6c7d104ad0e3052283213fb7166dac827c956928fe`
- freshness receipts: `0187ad0d9ea05fc4b152b7abd4945191dbe9ec24dfde4ca7dbe4aadfd1230efe`
- App freshness receipts: `0187ad0d9ea05fc4b152b7abd4945191dbe9ec24dfde4ca7dbe4aadfd1230efe`
- App expected identity: `8d65f78aa774ff252871cb1cc09e69b4ff04fbb45e61200eaf67534c9d2651b2`
- App: `043ff3a2f39ef3a1303791081b80851b427e7db5dfd9af2161926dd6f1ea9ca4`
- package commands: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `63e1506801ddee2f1eaf64cad68a9d5c918405f642ca237c6a1ec249ff297623`
## Next Task
`M12-06A`: desktop generate the bounded Mesh/PBR/UV/skin/animation GLB fixture group.
## Rollback
Remove the freshness protocol, generator/checker, freshness artifacts, unit test, App imports/route
gate, manifest, and this status entry. Restore M12-05E as the queue tail and move the machine queue
back to `M12-05F`. No parity ledger rollback is required.

59
docs/status/M12-06A.md Normal file
View File

@@ -0,0 +1,59 @@
# M12-06A Status
status: done
task: generate the bounded Mesh/PBR/UV/skin/animation GLB fixture group on desktop
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
The pinned Blender 5.2.0 LTS desktop runtime generates five independent GLB 2.0 fixtures: mesh,
PBR, UV texture, two-joint skin, and object animation. Each file has one bounded triangle primitive,
uses no required or optional glTF extension, and remains below the 512 KiB per-file budget. The
fixtures isolate feature ownership so later Web import comparisons cannot hide one unsupported
domain behind an all-in-one scene.
The canonical report records runtime identity, file bytes and SHA-256, nodes, topology accessors,
attributes, materials, textures/images, skins, and animations. The checker binds the M12-05F parent
manifest and the pinned M12-05A Blender binary identity, regenerates all five files in a fresh
temporary directory, and requires both the semantic report and every GLB byte to match exactly.
This enabling task does not claim Web import, `.blend` save/reopen, export loss reporting, or GLB
round-trip parity.
## Evidence
- `node tools/web/check-glb-desktop-fixtures.mjs` passed: 5 fixtures, 8,676 aggregate bytes,
Mesh/PBR/UV/skin/animation assertions, exact report regeneration, and exact GLB regeneration.
- Mesh exports indexed triangles with POSITION/NORMAL/COLOR_0; UV exports TEXCOORD_0 plus one
embedded PNG; skin exports JOINTS_0/WEIGHTS_0 and two inverse-bind matrices; animation exports
translation and rotation channels sampled over 25 frames.
- The runtime binary SHA-256 is
`d4483926610484ef9c2ad9241aae1469f934d955ebe791f1920e263e0ba85b82`, matching M12-05A.
- `npm --prefix web run typecheck`, `npm --prefix web run test:status-consistency`, and
`git diff --check` passed. The package hash remains the frozen
`cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`.
## Artifact Hashes
- parent manifest: `63e1506801ddee2f1eaf64cad68a9d5c918405f642ca237c6a1ec249ff297623`
- generator: `0247dd2405a68b42d99c2b005546ad2aa99b46416e3fe9489832467f6ea4eb4d`
- checker: `211ebdb66bf2e2d349455d5303e889a4a1ae3323639a89dd78b3bda574dd820b`
- desktop report: `dea31cc861622166dc502b333bc177b70b66b54d9c62aaccc6522745dab5ae13`
- mesh GLB: `e52b9268b6524744fb498691f976000635e544ba3b47e9f8ff22b03bcdf17a94`
- PBR GLB: `244cc8a992c5a70692b8bbc8333533718b3bac7022110715ce3b23d2e4c0b361`
- UV GLB: `1e0397d2b69d8261b3252451b50ab4aba6525b94713719f35069a9a9d96fcfa2`
- skin GLB: `4086ee4c8873aa03090338b676575b7a5335fb7c9384fec6ccb36108e71929f6`
- animation GLB: `44f6cc47961a146dc97ea337ae31a8b64bb4ab213b716f81ec22129db704f1fb`
- manifest: `e3554a1e739cbe3f217f6169130532365538b0c0eafbb97afc58d4d56c4287cb`
## Next Task
`M12-06B`: import the desktop GLB fixture group on Web and compare topology, attributes, materials,
nodes, and animations.
## Rollback
Remove the desktop fixture generator/checker, five GLB files, report, manifest, and this status
entry. Restore M12-05F as the queue tail and move the machine queue back to `M12-06A`. No parity
ledger rollback is required.

57
docs/status/M12-06B.md Normal file
View File

@@ -0,0 +1,57 @@
# M12-06B Status
status: done
task: compare desktop GLB topology, attributes, materials, nodes, and animations in Web
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
The production TypeScript GLB parser now exposes a canonical bounded semantic surface for the five
M12-06A desktop fixtures. It validates referenced accessors, nodes, materials, textures, skins, and
animation samplers before returning primitive topology, sorted attributes, PBR material fields,
node hierarchy/TRS, skin bindings, and animation channels. A field-level comparator checks that Web
semantics exactly match the pinned Blender 5.2 desktop report.
Both Node and a real Chromium Worker consume the exact committed GLB bytes and verify each source
SHA-256 before comparing all five domains. The existing summary import API remains compatible. This
task does not create Blender Main data or expose GLB in the file picker; the runtime route remains
`BLOCKED_UNTIL_MAIN_PERSISTENCE` until M12-06C proves save/reopen and stable IDs.
## Evidence
- `node --test web/tests/unit/glb-desktop-import.test.mjs` passed 3/3: five exact fixture imports,
separate domain assertions, and a stable field-level PBR mismatch.
- `node tools/web/check-glb-desktop-import.mjs` passed: 5 fixtures, 5 compared domains, exact
desktop/Web canonical hashes, deterministic report regeneration, and the blocked route state.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5425 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-desktop-import.spec.ts` passed 1/1 from
the `web/` directory using Chrome 150. The Worker verified source SHA-256 and all five semantic
comparisons.
- `npm --prefix web run typecheck`, `npm --prefix web run test:status-consistency`, and
`git diff --check` passed. The package hash remains
`cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`.
## Artifact Hashes
- parent manifest: `e3554a1e739cbe3f217f6169130532365538b0c0eafbb97afc58d4d56c4287cb`
- protocol: `45d9a7912c4a59a552789a8ea0dfaff5f1849f8d213f14d238de024b77acdb0d`
- generator: `6f97527b7da04c7b4f9b09c48b9f367d1270db9f7820498d33832a80754436c2`
- checker: `804a4b5545d95d7ab1ba265469a981d0a10b71dab36f0c96283eb73b401443d2`
- unit: `6bf2a96b3e43e5fae93589ea5dcf98e7a69b10266378e442988198925286a8d8`
- Chromium Worker: `eb32049631113270fb62acb7ae9379e8ff9a03e38086db2fa309c6891cd707bf`
- Chromium test: `fa3e06419c918406f24b5a4260523bd94cfe729a84786e9434517fdfed624d45`
- Web import report: `79933888cc5aa2d1e3639ec349ca4c31d028fe89f751ebb8d4342f06d15ecfc2`
- manifest: `5275310394b34726a05b30ab67658e1381662dddf9163a97cb02f47f646a8fa4`
## Next Task
`M12-06C`: create authoritative Main data from the imported GLB, save `.blend`, reopen it, and
compare stable IDs.
## Rollback
Remove the canonical Web import surface, report generator/checker, Node/Chromium tests, report,
manifest, and this status entry. Restore M12-06A as the queue tail and move the machine queue back to
`M12-06B`. No parity ledger rollback is required.

59
docs/status/M12-06C.md Normal file
View File

@@ -0,0 +1,59 @@
# M12-06C Status
status: done
task: import desktop GLB results into authoritative Main, save `.blend`, reopen, and compare stable IDs
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The pinned Blender 5.2 desktop runtime imports each M12-06A GLB fixture and saves a `.blend`; the
generator reopens every saved file and requires the complete stable Object/Mesh/Material/Image/
Armature/Action ID set to remain unchanged. Chromium then opens those authoritative Main fixtures
through the production WebEngine, applies one Main-owned visibility edit, saves the resulting
`.blend`, reopens it in a fresh isolated open transaction, and compares the stable IDs with the
desktop baseline. The saved edit is checked after reopen and the open resource counters are zero for
input, staging, and active requests.
This task does not expose GLB in the normal `.blend` file picker, claim arbitrary glTF extensions,
or change the N-023 full-parity ledger. M12-06B remains the bounded Web GLB semantic parser and
M12-06D owns export loss reporting.
## Evidence
- `node tools/web/check-glb-main-persistence.mjs` passed the parent manifest, all artifact hashes,
five desktop GLB/Main fixture bindings, stable-ID shape checks, and a fresh Blender regeneration
with exact semantic report/stable-ID comparison.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5437 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-main-persistence.spec.ts` passed 1/1.
Every fixture opened in the production WebEngine, performed one authoritative visibility edit,
serialized a changed `.blend`, reopened it, preserved all stable IDs, restored visibility=false,
and returned zero active requests/input/staging resources.
- `npm --prefix web run typecheck` and `git diff --check` passed. The existing package manifest was
left unchanged so prior M12 evidence remains bound to its frozen package hash.
## Artifact Hashes
- parent manifest: `5275310394b34726a05b30ab67658e1381662dddf9163a97cb02f47f646a8fa4`
- generator: `8989d6ce4196f140a7bfb44b863dc530a6aa462ca4a57fa7b77c468e06ab61ad`
- checker: `5bbbbeaf2d20ff9bbdeb74c8dd10fa6ffc421d1d59f86540e95f29c2cfd10903`
- desktop report: `76b000454a9073ef762d25fa546d5c65a004659a93eb6ec82fad1e679b2e81be`
- Chromium test: `7c97877f1cbbfd0166e106c80faee53f474f78816cca68ea924df5aa3c47776d`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- mesh `.blend`: `66e29adc016f07e220019b6f24eb7e5016c684dca4b3102b20c8e836968d422d`
- PBR `.blend`: `ba08aeb2876d82ddf731abe81d3a42041a1be36617d0b6324c870d5bcd4cc771`
- UV `.blend`: `1270cb452d34d2fd7a19181a2b20f70b7a028bdd2db7cf1bba4e1003f7de0f48`
- skin `.blend`: `23f175e44ec588c75db99d3f9134863fc3d7d1f192bbd815d5d1c4e3218bce0c`
- animation `.blend`: `fa6baf3a67ff11fe3d2922210089a7c508e4ee28bfaabe4cf628ba6addee1ff5`
- manifest: `e3a57636a47591e3b02dff5a07e8a0aec5e0dc43bf6b4829bffc811035dbbb31`
## Next Task
`M12-06D`: Web export generates a machine loss report.
## Rollback
Remove the M12-06C generator/checker, manifest, desktop Main fixtures, report, Chromium test, and
this status entry. Restore M12-06B as the queue tail and move the machine queue back to M12-06C. No
parity ledger rollback is required.

56
docs/status/M12-06D.md Normal file
View File

@@ -0,0 +1,56 @@
# M12-06D Status
status: done
task: Web GLB export generates a machine-readable loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production GLB exporter now has a schema-1 deterministic loss-report wrapper. It records the
source SceneIR identity/revision, exportability, error/warning counts, sorted loss entries and the
bounded data-block surface. Chromium opens all five M12-06C authoritative Main fixtures and sends
their real snapshot/geometry/packed assets through the production exporter Worker. Exportable
PBR/UV/skin/animation outputs are byte-hashed; the mesh fixture's unsupported Color Attribute
shader is reported as `SHADER_GRAPH_UNMAPPABLE` and no GLB bytes are emitted.
This task reports the bounded exporter surface only. It does not claim lossless GLB round-trip,
desktop re-import, arbitrary shader mapping, or GLB file-picker import; those remain later M12-06E/G
tasks or explicit blockers.
## Evidence
- `node --test web/tests/unit/glb-loss-report.test.mjs` passed deterministic sorting/count semantics.
- `node tools/web/check-glb-loss-report.mjs` passed artifact hashes, parent Main fixture binding,
deterministic loss ordering, mesh fail-closed output, and four exportable fixture output hashes.
It reports `fixtures=5 blocked=mesh warnings=3`.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5445 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-export-loss-report.spec.ts` passed 1/1.
The test uses `WebEngineClient` and a production module Worker, requests packed image assets,
produces the report, and compares it byte-for-byte with the checked-in golden report.
- `npm --prefix web run typecheck` and `git diff --check` passed. `web/package.json` remains
unchanged so previous M12 package bindings stay valid.
## Artifact Hashes
- parent manifest: `e3a57636a47591e3b02dff5a07e8a0aec5e0dc43bf6b4829bffc811035dbbb31`
- export protocol: `a5d342827860a9e55b49a3bb3a196a01b1e53546325d6e594778afb9360c3125`
- loss report protocol: `dce9c790b2f52d46efe0908ecb044d63d21b3c6c3f7d77ddb5e697b29a7a2d6e`
- Worker: `6f6294d26fe7b717416a5dd25fe834fb4b9a2ecbe8b011395c9559a26701ec77`
- Chromium test: `ce334b6bb5d82c133d317e916c03711029fba1c19c634dec06c06da9eddbd776`
- checker: `a23346860fa26405b2cd24591b0ab36fea29cb561ec8c2991ecfeabcffc17ee1`
- unit: `dfcc2d968e4e0c0cef4496bc304cb481f10d1f0dc4c76a40ea1d6e2f11b6b708`
- web loss report: `c6db52234d867985ef5fbcdc7c62298ec9aaa013028b5a54e2b9a16aa4133397`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `c01c5861d493e1f177e8cde3038bc5283a7671fa39bf84484662d307623325a2`
## Next Task
`M12-06E`: desktop Blender re-imports Web GLB and compares the canonical report.
## Rollback
Remove the loss-report protocol/Worker, checker, manifest, golden report, Chromium test, and this
status entry. Restore M12-06C as the queue tail and move the machine queue back to M12-06D. No parity
ledger rollback is required.

55
docs/status/M12-06E.md Normal file
View File

@@ -0,0 +1,55 @@
# M12-06E Status
status: done
task: desktop Blender re-imports Web GLB and compares canonical report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The four Web GLBs that produced bytes in M12-06D (PBR, UV, skin and animation) are re-imported by
the pinned Blender 5.2 desktop runtime, saved as `.blend`, reopened, and emitted as canonical graph
reports. The checker binds each Web output hash to the M12-06D report and compares Object/Mesh/
Material/Image/Armature/Action graph fields against the M12-06C desktop-import baseline.
PBR and animation are exact. UV records four explicit differences (corner-expanded vertex topology
and Blender's generated texture Mix node); skin records 31 explicit differences (the exporter emits
an additional armature helper mesh and Blender's re-import tessellation changes). These are recorded
machine mismatches, not silently treated as parity. The N-023 parity ledger remains blocked and this
task does not claim lossless GLB round-trip.
## Evidence
- `node tools/web/check-glb-web-reimport.mjs` passed artifact hashes, four Web GLB source bindings,
pinned Blender regeneration determinism, save/reopen stability, and canonical comparison. Output:
`glb-web-reimport-ok fixtures=4 exact=2 mismatched=uv,skin deterministic=true next=M12-06F`.
- The report binds Web GLB hashes `pbr=1ab793...`, `uv=8bd045...`, `skin=4a45d0...` and
`animation=b83de1...`; exact/mismatch counts are fixed at PBR 0, UV 4, skin 31, animation 0.
- The Web export Chromium test that produced the inputs passed 1/1; the desktop generator performs
a fresh Blender import/save/reopen for every input. `npm --prefix web run typecheck` and
`git diff --check` passed.
## Artifact Hashes
- parent manifest: `c01c5861d493e1f177e8cde3038bc5283a7671fa39bf84484662d307623325a2`
- generator: `3ae1ba45e15cae5d0308fc3fcb3766764cd374c096e27eaaddba9228a3d75004`
- checker: `c21b45a975ec70586da1b9e50b8cf4ccf74644300b4f381c3fee0ad735cfcdb9`
- desktop report: `e4d03d25cfac3c4beff4d0af0769b1c39b058670c679c12f4a11ae30d2d91f3c`
- Web export test: `ce334b6bb5d82c133d317e916c03711029fba1c19c634dec06c06da9eddbd776`
- PBR Web GLB: `1ab7936fae6e0c28e1b90e8a6ae24b3893c075c9fc58ac8896f780fdefb8277e`
- UV Web GLB: `8bd045388527ddad7cf886c0c7a2a45b6e7d6db603568a10a959bc6d423ae145`
- skin Web GLB: `4a45d00dfa23638682bb61a4f74b283bcd986126da4890d068902e3c85efc332`
- animation Web GLB: `b83de103df3f5a49487868f3ede3046875c90b0d084bbd998511c3a7c987a4fa`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `3d3b13fd54a314fd6f6907fc2d314e66ef74e8ca770a8accd823370d272737fc`
## Next Task
`M12-06F`: sparse accessor, Draco/extension, external URI and over-budget negative cases.
## Rollback
Remove the desktop Web re-import generator/checker, manifest, report, four Web GLB fixtures, and
this status entry. Restore M12-06D as the queue tail and move the machine queue back to M12-06E. No
parity ledger rollback is required.

49
docs/status/M12-06F.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-06F Status
status: done
task: GLB sparse accessor, extension, external URI and over-budget negative cases
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The bounded GLB importer now enforces a 512 KiB input budget, JSON/table budgets, rejects sparse
accessors, rejects all extensions outside the pinned allowlist (currently empty), and blocks external
buffer/image URIs. Errors are stable and fail before semantic/Main publication:
`GLB_SPARSE_ACCESSOR_UNSUPPORTED`, `GLB_EXTENSION_UNSUPPORTED`, `GLB_EXTERNAL_URI_BLOCKED`, and
`GLB_IMPORT_BUDGET_EXCEEDED`.
## Evidence
- `node --test web/tests/unit/glb-negative-cases.test.mjs` passed 2/2 for sparse, extension, external
URI, byte-budget and table-count cases.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5450 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-negative-cases.spec.ts` passed 1/1 in a
production Chromium Worker with all four stable codes.
- `node tools/web/check-glb-negative-cases.mjs` passed the schema-1 negative report and artifact
hashes: `glb-negative-cases-ok cases=4 budget=524288 deterministic=true next=M12-06G`.
- `npm --prefix web run typecheck` and `git diff --check` passed. The package manifest remains
unchanged.
## Artifact Hashes
- parent manifest: `3d3b13fd54a314fd6f6907fc2d314e66ef74e8ca770a8accd823370d272737fc`
- protocol: `0b6329c08e6f3cd9af6f27ef7c463b037a7cab94192afb4538d3d6c4cfcbc147`
- unit: `9af1c155143a0c685a62f569f705afd9fcc3bb49e0d724ebf3ad2c6356d63d6d`
- Worker: `d84a6b884ce1bfedd598b2602d803493bf10f6ad62fdfac49d64fca3f30f3931`
- Chromium test: `c6694689ce04ff2faea2c20be648f438a9f7eb25cdfd2f714b94c1f556ea1510`
- checker: `08377c306fd7d1082f7fd734e37809960c9798d29d626681fe9ad3f94cb7a29e`
- negative report: `7367a624b562a9613b4b908c894ab04c731ae0a348a3b58689075f4a9decd90c`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `27b42da0683dab11a884553440088c30cf58d51364268fdaac86668786aaedd4`
## Next Task
`M12-06G`: import/export cancellation, Worker restart and OPFS quota recovery.
## Rollback
Remove the GLB negative-case budget/protocol changes, Worker, tests, checker, report, manifest, and
this status entry. Restore M12-06E as the queue tail and move the machine queue back to M12-06F. No
parity ledger rollback is required.

57
docs/status/M12-06G.md Normal file
View File

@@ -0,0 +1,57 @@
# M12-06G Status
status: done
task: GLB import/export cancellation, Worker restart, and OPFS quota recovery
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Schema-1 GLB recovery receipts now bind operation, worker generation, source/output SHA-256,
revision, temporary bytes, live requests, commit state, and stable cancellation/restart/quota codes.
Both import and export cancellation release all temporary bytes and publish no result. A new Worker
repeats the same bounded GLB import with an identical semantic result hash.
The GLB asset persistence path uses the existing content-addressed OPFS store. A real Chromium
origin quota of 64 KiB rejects a 128 KiB candidate, while the previously committed GLB remains
readable after Storage Worker restart. Raising the quota allows a small follow-up asset to commit.
## Evidence
- `node --test web/tests/unit/glb-recovery.test.mjs` passed 2/2 for cancel, quota, commit, and
generation transition invariants.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5455 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/glb-recovery.spec.ts` passed 2/2 in Chrome
150. The first real-quota run reached the expected browser failure but the assertion only accepted
the injected error wording; the final run accepts both native and injected quota messages.
- `node tools/web/check-glb-recovery.mjs` passed with
`glb-recovery-ok cancelled=2 workerGeneration=2 quota=GLB_OPFS_QUOTA smallRecovery=true next=M12-07A`.
- `npm --prefix web run typecheck`, `node --check tools/web/check-glb-recovery.mjs`, and
`git diff --check` passed. The package manifest remains unchanged.
## Artifact Hashes
- parent manifest: `27b42da0683dab11a884553440088c30cf58d51364268fdaac86668786aaedd4`
- recovery protocol: `da4e2a546d7598e80798cfebd105e52b7522c896acb545710c78bb8a5c3705aa`
- storage protocol/client/Worker: `2c8ce9e32fcae973e9262a024fd849221680104bcd427ec308f99ef25112d951` /
`00cd35e4632479e4cd153314113e201c822fd209ae6c8e9fbeff5f1399728565` /
`80bf4d2ac59cbf7998c2a72c8961ae38abe43685b60df564d0746e1a45e9e1bc`
- operation Worker/browser adapter: `947c4a768422725ff2f689b2eefa8068bee51bb7ff342af17e8d4a4d0a4a7ca2` /
`2c753a04c153471c2bf7691073b836d968a1a1300e3da038f493983b46738cdf`
- unit/Chromium: `6dd48f62a85c5aaf3a04b6e572a47a7986b23cbec84a099ea510af81e8dd3a3a` /
`7d95e992f44fb913f70c104f0d6b23bd76f47d48db4a21899e35ae1d188e2093`
- checker/report: `b185248fdcd6b3cee84252bd68fcb6921bb6385bfa4a00486e93c58e94755cce` /
`1a008a76590573468446ca6e5cbdfe0ea5a8b27493291590d937b90db90d6e42`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `1c732b8d9f1a0bdb502f44e2e843e91efea12e93483a35658f8a9c70a69a2430`
## Next Task
`M12-07A`: OBJ single-Mesh positive fixture covering position, normal, UV, and material group.
## Rollback
Remove the GLB recovery receipt, quota fault option, Worker/browser adapter, tests, checker, report,
manifest, and this status entry. Restore M12-06F as the queue tail and move the machine queue back to
M12-06G. No parity ledger rollback is required.

49
docs/status/M12-07A.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-07A Status
status: done
task: OBJ single-Mesh desktop positive fixture
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `WM_OT_obj_export` now generates one deterministic Wavefront OBJ object with
four positions, four UV coordinates, one explicit normal, two triangle faces, two material records,
and two material groups. The `.mtl` sidecar is kept beside the OBJ and both files are bound to the
canonical semantic report. Web parsing/import, multi-object and negative cases remain queued.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-obj-single-mesh-fixture.py -- tests/files/web/m12_obj_desktop_v1
tests/golden/M12-07A/desktop-fixture.json` completed with 4 positions, 4 UVs, 1 normal,
2 faces, and 2 materials/groups.
- `node tools/web/check-obj-single-mesh-fixture.mjs` passed deterministic regeneration in a fresh
temporary directory and byte-for-byte OBJ/MTL comparison:
`obj-single-mesh-fixture-ok vertices=4 normals=1 uv=4 faces=2 materials=2 deterministic=true next=M12-07B`.
- Runtime identity matches the pinned M12-05A Blender 5.2 inventory; the report is anchored to
`blender-5.2.0/source/blender/io/wavefront_obj` and `wm.obj_export`.
- Package hash remains frozen; no Web route or parity ledger status was changed.
## Artifact Hashes
- parent manifest: `1c732b8d9f1a0bdb502f44e2e843e91efea12e93483a35658f8a9c70a69a2430`
- generator: `604c3006f194c7c64a487b8f760693b66830f3cfa602928b46769955e7d4f358`
- checker: `3d0208f61a86d4d29796d8284756f53931c90864b15b7dfe4fcc84d7f65a8040`
- desktop report: `6c560a8eecf84973c2b05f9fd50d33bd45515e97c4f7970f1502de406c39f6a5`
- OBJ/MTL: `a56694d1ee28735c68381ff18c3a52581612feebac0101a53e502956c27d144f` /
`392f1b10ff5a0b142d520a9443b4c96191985f15d4244c79b36fdeda0f153715`
- runtime inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `d80b74502202effa7be15640c945dc7e04af703b58e7a15c3fe7babc43c17b46`
## Next Task
`M12-07B`: OBJ multi-object, negative-index, MTL/texture-origin, and malformed-face cases.
## Rollback
Remove the OBJ generator, checker, desktop report, OBJ/MTL fixture, manifest, and this status entry.
Restore M12-06G as the queue tail and move the machine queue back to M12-07A. No parity ledger rollback
is required.

53
docs/status/M12-07B.md Normal file
View File

@@ -0,0 +1,53 @@
# M12-07B Status
status: done
task: OBJ multi-object, negative-index, texture-origin, and malformed-face fixtures
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `wm.obj_export` now produces a two-object OBJ/MTL positive fixture with two
relative `map_Kd` references and a 2x2 PNG texture. The deterministic generator derives a negative
index OBJ variant and a malformed two-vertex face variant from the same positive bytes. The report
keeps multi-object/group/material counts and expected fail-closed `OBJ_FACE_ARITY_INVALID` separate;
it does not claim that a Web parser or OBJ import route exists.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-obj-multi-negative-fixtures.py -- tests/files/web/m12_obj_multi_v1
tests/golden/M12-07B/desktop-fixtures.json` completed with 2 objects, 6 positions, 6 UVs,
2 normals, 2 faces, 2 materials, relative `m12_obj_texture.png`, and both derived variants.
- `node tools/web/check-obj-multi-negative-fixtures.mjs` passed fresh-directory Blender regeneration,
exact OBJ/MTL/PNG/negative/malformed bytes, negative-index acceptance shape, malformed-face arity,
and PNG signature checks:
`obj-multi-negative-fixtures-ok objects=2 negative=true malformed=OBJ_FACE_ARITY_INVALID textureOrigin=relative deterministic=true next=M12-07C`.
- Runtime identity matches M12-05A pinned Blender 5.2; no Web parser, UI route, or parity ledger
status changed. Package hash remains frozen.
## Artifact Hashes
- parent manifest: `d80b74502202effa7be15640c945dc7e04af703b58e7a15c3fe7babc43c17b46`
- generator: `8d4faed82cba76e46bf639e5031b30568e8b9a15240cbddb1c22ee7ad11d697b`
- checker: `61188d67efd6133e714f2d55c7c8516b9d04896de068f994523a3c398eebdd2f`
- desktop report: `b60ff785676c0f0168588605ad442a650615191ac00770b7e5a308cc4ade83ce`
- OBJ/MTL/PNG: `4ed3dced8445b03754cd3916ae2e8cf0dff85e6a5882f1c6f0a4a4e4c5251f6a` /
`80338f569c67a8b1616515ba878ffc72b26e93ef2e8c361131023fb14f132f5f` /
`44e4fd08bdda8403908349e2a62dcf103ce2d0851099fc61cd868d65ddbef78c`
- negative/malformed OBJ: `9457954284cac1d68e23627e3ff734c0c591b3a24086ce5aa3d0dbbfc22f01bc` /
`6dd508b5ba944c2d15e2889c9ad9a3693845145c3bf6c9bf7df992081c915864`
- runtime inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `785f593271058098704498cb0a7c948305087f1a83bf8f29b6e6fb9fe9341926`
## Next Task
`M12-07C`: Web-to-desktop OBJ round-trip and loss report.
## Rollback
Remove the multi/negative OBJ generator, checker, fixtures, report, manifest, and this status entry.
Restore M12-07A as the queue tail and move the machine queue back to M12-07B. No parity ledger rollback
is required.

55
docs/status/M12-07C.md Normal file
View File

@@ -0,0 +1,55 @@
# M12-07C Status
status: done
task: Web-to-desktop OBJ round-trip and loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The bounded TypeScript OBJ protocol parses positive and negative indices, position/UV/normal streams,
objects/groups/faces, MTL `map_Kd`, and stable budgets; it serializes a deterministic Web OBJ/MTL pair
and emits a machine loss report for unbound texture origins. A Chromium Worker consumes the M12-07B
double-object fixture, then a new pinned Blender 5.2 process imports the Web output with split groups.
## Evidence
- `node --test web/tests/unit/obj-import.test.mjs` passed 3/3 for negative-index resolution,
deterministic serialization, bound/unbound texture loss, malformed face arity, and index range.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5460 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/obj-web-roundtrip.spec.ts` passed 1/1 in Chrome
150. Browser output has 2 objects, 6 positions/UVs, 2 normals, 2 faces, 2 materials; bound texture
loss is zero and missing texture loss contains two `OBJ_TEXTURE_ORIGIN_UNRESOLVED` warnings.
- The test writes the browser OBJ/MTL and texture to an isolated directory, invokes pinned Blender
`wm.obj_import`, and compares 2 objects, 2 triangles, UVMap presence, and one material per object.
- `node tools/web/check-obj-web-roundtrip.mjs` passed the exact golden and artifact hash gate:
`obj-web-roundtrip-ok objects=2 triangles=2 lossWarnings=2 desktopExact=true next=M12-07D`.
- `npm --prefix web run typecheck`, Python compile, and `git diff --check` passed. Package hash remains
frozen; OBJ Web capability is still bounded and does not change N-023 parity.
## Artifact Hashes
- parent manifest: `785f593271058098704498cb0a7c948305087f1a83bf8f29b6e6fb9fe9341926`
- protocol: `e7240af65e0d90f3ee690a4e3f391416fe4744ac6c46edc8ac0d72386857cab9`
- Worker: `bf1fcc60ec318cf6c2747d44f4af741b46f284cf5f5307e142f0ab6d50b14302`
- desktop importer: `9f1eb4ab679255a0f1f596696e8befc33a4e30c0cbe6ea423e2aaa0314cec22d`
- checker: `9d53014f4b89f786c516ebe8d300030c2728e4a36a86a5ef136b2769a12ac96b`
- unit/Chromium: `485a669be5de8e370e9b5a3239357b028ba61ca5c4076819cd46aed52a5c210a` /
`93785b4017ba14b007926b0f82442f8ae5968f242a2a762e5f5dc77d36110f5b`
- report: `45eaffc9c2e50c84b557d13ebbe9f4f53b63e19e00bc69b272491ef6366dff81`
- fixture OBJ/MTL/PNG: `4ed3dced8445b03754cd3916ae2e8cf0dff85e6a5882f1c6f0a4a4e4c5251f6a` /
`80338f569c67a8b1616515ba878ffc72b26e93ef2e8c361131023fb14f132f5f` /
`44e4fd08bdda8403908349e2a62dcf103ce2d0851099fc61cd868d65ddbef78c`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `0c639954900b1fcc3b8285d0f4c0ecfa5807df6cde6d1f2cd3b59c4636d71674`
## Next Task
`M12-07D`: split STL binary and ASCII capability declarations.
## Rollback
Remove the OBJ protocol, Worker, desktop importer, unit/E2E tests, checker, report, manifest, and this
status entry. Restore M12-07B as the queue tail and move the machine queue back to M12-07C. No parity
ledger rollback is required.

47
docs/status/M12-07D.md Normal file
View File

@@ -0,0 +1,47 @@
# M12-07D Status
status: done
task: split STL binary and ASCII capability declarations
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `WM_OT_stl_export` now generates binary and ASCII STL from the same selected
two-triangle mesh using identical axis, scale, unit, evaluation, and modifier settings. The report
keeps `STL_BINARY/ascii_format=false` and `STL_ASCII/ascii_format=true` as separate variants; it does
not infer the format from the `.stl` extension or claim Web parsing/import support.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-stl-capability-fixtures.py -- tests/files/web/m12_stl_capability_v1
tests/golden/M12-07D/capability-report.json` generated a 184-byte binary STL with two 50-byte
triangle records and a 213-byte ASCII STL with two facets/six vertex lines.
- `node tools/web/check-stl-capability-fixtures.mjs` matched runtime identity to M12-05A, validated
both independent encodings, regenerated the report/files byte-for-byte in a fresh directory, and
returned `stl-capability-fixtures-ok binaryTriangles=2 asciiFacets=2 deterministic=true next=M12-07E`.
- Package hash remains frozen. This enabling task does not change N-023 parity or expose an STL UI
route.
## Artifact Hashes
- parent manifest: `0c639954900b1fcc3b8285d0f4c0ecfa5807df6cde6d1f2cd3b59c4636d71674`
- generator: `8310104e66f246b32ac7cb4619e7f4da109baf2ece39ea670cbb6d33bd88c8b8`
- checker: `b2ad901eaa9701436cf7bcc8aa4e40d1b2d6eda7c6c44a0af830347a37cc9ca8`
- desktop report: `29c7d2a6e6764440c99eec25bb5760c7e0880839691757fb3e607ed4f5050013`
- binary/ASCII fixtures: `50161172cd12e4240067064db6f80e74b2df69c475e3e34154e9d0523928c1ca` /
`a463a5add8be070fb67b34f00ef6e7b46025aed31fa429d4a033d75a11cf0113`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `bbc78e47f389562e7d648bf49c9b3bf8a08aaa36e914589a6eab0a1f6e72748d`
## Next Task
`M12-07E`: STL normal, unit, degenerate-triangle, and trailing-byte parity.
## Rollback
Remove the STL capability generator, checker, fixtures, report, manifest, and this status entry.
Restore M12-07C as the queue tail and move the machine queue back to M12-07D. No parity ledger rollback
is required.

60
docs/status/M12-07E.md Normal file
View File

@@ -0,0 +1,60 @@
# M12-07E Status
status: done
task: STL normal, unit, degenerate-triangle, and trailing-byte parity
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The bounded STL protocol requires an explicit binary/ASCII variant and positive unit scale. It parses
facet normals and vertices, applies the scale, removes zero-area triangles the same way as Blender's
validated import, and rejects binary payload after the declared triangle table with
`STL_TRAILING_BYTES`. Desktop Blender accepts that trailing fixture as an empty mesh, so the report
records `STRICTER_WEB_BLOCK` rather than claiming exact parity for that edge case.
## Evidence
- The deterministic edge generator derived a one-degenerate-triangle binary and a four-trailing-byte
binary from M12-07D. Pinned Blender 5.2 was probed at unit scales 1 and 0.001 and against both edge
files; it preserves normals, scales world bounds by 1000, removes one degenerate triangle, and
accepts the trailing fixture as an empty mesh.
- `node --test web/tests/unit/stl-import.test.mjs` passed 2/2 for binary/ASCII normals, explicit unit
scaling, degenerate removal, trailing-byte rejection, and invalid scale.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5463 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/stl-edge-parity.spec.ts` passed 1/1 in Chrome
150. Normal comparison is exact, Web/Desktop unit ratio matches within Float32 tolerance, and both
retain one triangle after degenerate removal.
- `node tools/web/check-stl-edge-parity.mjs` passed:
`stl-edge-parity-ok normals=exact unitRatio=1000 degenerate=removed trailing=STRICTER_WEB_BLOCK next=M12-07F`.
- Typecheck and `git diff --check` passed. The stricter trailing-byte policy leaves N-023 full parity
blocked and does not expose an STL UI route.
## Artifact Hashes
- parent manifest: `bbc78e47f389562e7d648bf49c9b3bf8a08aaa36e914589a6eab0a1f6e72748d`
- fixture generator/desktop probe: `018013347642603c21237ebb023bdc7a4e338f5a3f875fea536a996eb121e716` /
`b3d6ea197ef77b5a14f60f5e6b43d4392e943ff5d56acf73915507fc9a4161b7`
- protocol/Worker: `87eec72e2b8aa7ad0b168ca0ee8c4016c941f56f5f1ac53aa5fe71d0832f1dd8` /
`d714f1f3a218a2226dd349aea81c6c54efa6246de1c4fe51aaa9f5c352ef44fc`
- unit/Chromium/checker: `4af52833486421c017f3af2b833b0776e60a6ab57ed66fea2161cf9674f4b243` /
`121d348250e26d29ad966f7427bbef9da77de2098e2e305827b11aae52002c5c` /
`b5ed7fbb41bb46fba982d5726cb8c3eaecf360b772a01d6337c309b1c4a4f535`
- fixture/desktop/Web reports: `545463a984356d6635cbaae3865d13fe95bd2d841c394ac9ddff496c95d46f18` /
`2d3028a3b7d97f39654cff5fcef1d0c1c71e9f2d08e3e29c2e926651ed3860f1` /
`e0686cc9be3b68e564651207443e0ebf3e3b0eb3d07a32915b03f44b1908357b`
- degenerate/trailing fixtures: `c120bb0f218819eb89a3607c0b4f8fafd9afb599402e3b21deaa3b2be143e7d0` /
`0a30aab6db1588722067000e2a08c3c6206a8ed5b7531caa0b082723700a3681`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `19a9f460d1b939c9504dadd364cb87dab3b1769b0599035e2d2b51b47091e034`
## Next Task
`M12-07F`: STL Web-to-desktop round-trip and material-loss report.
## Rollback
Remove the STL edge fixtures, probes, parser, Worker, tests, reports, checker, manifest, and this status
entry. Restore M12-07D as the queue tail and move the machine queue back to M12-07E. No parity ledger
rollback is required.

51
docs/status/M12-07F.md Normal file
View File

@@ -0,0 +1,51 @@
# M12-07F Status
status: done
task: STL Web-to-desktop round-trip and material-loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The STL Web path now serializes the bounded parsed triangle result back to deterministic binary STL.
The loss report explicitly records STL's lack of material slots as
`STL_MATERIAL_UNSUPPORTED`; it never silently claims material preservation. A Chromium Worker output
is imported by a fresh pinned Blender 5.2 process and compared by triangle count and facet normals.
## Evidence
- `node --test web/tests/unit/stl-export.test.mjs` passed 1/1 for binary header/table serialization
and explicit material-loss warning.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5467 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/stl-web-roundtrip.spec.ts` passed 1/1 in Chrome
150. Browser output is 184 bytes/2 triangles; Blender reopens 2 polygons/2 triangles with exact
normals; warning code is `STL_MATERIAL_UNSUPPORTED`.
- `node tools/web/check-stl-web-roundtrip.mjs` passed:
`stl-web-roundtrip-ok triangles=2 normals=exact materialLoss=1 desktopExact=true next=M12-07G`.
- Typecheck and `git diff --check` passed. The STL material loss remains machine-visible and STL UI
route/parity stays bounded.
## Artifact Hashes
- parent manifest: `19a9f460d1b939c9504dadd364cb87dab3b1769b0599035e2d2b51b47091e034`
- protocol/Worker: `3b9c409de9fb3eaea34f82c1ddd466670d2b478845d8ff6af3c4e44cb4e04a52` /
`1da8b8281cf8ebf9ccf5fd2f42da8ed5886001ab83daba8d9fcd88980257af87`
- desktop importer: `c4cbff52ff2e7cecba7aeab47e865975955da23a0e1e8ff885ece56b894558d5`
- unit/Chromium/checker: `f06af242df80ec26d06e92b749449cfebaf909476198ff825207cdd4b9484102` /
`2e979dcd030f5316fcbe28e2c19b1c99fe5d111e849d3fc1d2ea316d2159032b` /
`093de04bf80b0909eee56ea590e04e7aa4749168e2e49615c62ab39ddc0d16cf`
- report: `0495c645b4280f6e7821f0ba02010e25d4accbc552e3cd7c58e052607799040e`
- source fixture: `50161172cd12e4240067064db6f80e74b2df69c475e3e34154e9d0523928c1ca`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `3cbbcb541ee123da0ef8916ac2ca8805680d539bbf8db3b4a8d331aec418148c`
## Next Task
`M12-07G`: PLY ASCII/binary little-endian capability declarations.
## Rollback
Remove the STL export/loss protocol, Worker, desktop importer, tests, checker, report, manifest, and
this status entry. Restore M12-07E as the queue tail and move the machine queue back to M12-07F. No
parity ledger rollback is required.

53
docs/status/M12-07G.md Normal file
View File

@@ -0,0 +1,53 @@
# M12-07G Status
status: done
task: PLY ASCII and binary little-endian capability declarations
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 `WM_OT_ply_export` now has two independently declared capability variants for
the same selected two-triangle mesh: `PLY_ASCII` and `PLY_BINARY_LITTLE_ENDIAN`. The report binds
the export settings, source/operator anchor, runtime identity, header semantics, and byte hashes;
the variant is never inferred from a shared `.ply` extension. This enabling task freezes desktop
capability only and does not expose a Web PLY parser or import route.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-ply-capability-fixtures.py -- tests/files/web/m12_ply_capability_v1
tests/golden/M12-07G/capability-report.json` generated an ASCII PLY with four vertices/two faces
and a binary little-endian PLY with the same four vertices/two faces. Both headers explicitly carry
their independent encoding declarations and Blender export settings are recorded in the report.
- `node tools/web/check-ply-capability-fixtures.mjs` matched every runtime identity field to the
pinned M12-05A inventory, validated the `ascii` and `binary_little_endian` variants, checked the
vertex/face element counts and artifact hashes, regenerated both files in a fresh temporary
directory, and passed byte-for-byte determinism:
`ply-capability-fixtures-ok ascii=ascii binary=binary_little_endian vertices=4 faces=2 deterministic=true next=M12-07H`.
- `python3 -m py_compile tools/web/generate-ply-capability-fixtures.py` and
`node --check tools/web/check-ply-capability-fixtures.mjs` passed. The package hash remains
frozen and N-023 parity remains blocked; no PLY Web UI route was exposed.
## Artifact Hashes
- parent manifest: `3cbbcb541ee123da0ef8916ac2ca8805680d539bbf8db3b4a8d331aec418148c`
- generator: `581cd84057357e3a87997cf9c07d5d5633209648ac11e44611782eb254a38ebd`
- checker: `5280d6e57b7a722ea881e27b792c6082c5113c1577ac0e87f87cc87fdf59516c`
- desktop report: `26b1ce83334b41778cef5ce2a1f2c4d34254f63d7c7573cb3fb550f93ddeabb2`
- ASCII/binary little-endian fixtures: `63646cab9bf6ccecb23092e5e24d04df1e0a690c866127c72a35791e99262331` /
`e40fbb494b8b147c555a0fc06eb191415406bb9a6c061acf6befd8464c8c41a5`
- runtime inventory: `0d660b0fd8b647ebbf4e91afebd5006bd100973ab8e2507a5bfe759f477b33b4`
- package: `cfb232baa494ff59f6c8d65514a08c86332ee9354350b2a0392b6f932a7ee42c`
- manifest: `87df9c12f9c6eacf63051b70e9bb2eb43ebd1e5c4487b3512c45adb94cbb82ea`
## Next Task
`M12-07H`: PLY vertex/face/color/custom-property mapping and unknown-property loss report.
## Rollback
Remove the PLY capability generator, checker, fixtures, report, manifest, and this status entry.
Restore M12-07F as the queue tail and move the machine queue back to M12-07G. No parity ledger
rollback is required.

62
docs/status/M12-07H.md Normal file
View File

@@ -0,0 +1,62 @@
# M12-07H Status
status: done
task: PLY vertex/face/color/custom property mapping and unknown property loss report
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production `ply-import` protocol now accepts explicitly declared ASCII and binary
little-endian PLY. Vertex position, normal, RGBA color, numeric custom properties, face
indices, and numeric face properties are mapped into a bounded canonical document. Unsupported
vertex/face list properties and unknown elements are skipped with deterministic
`PLY_UNKNOWN_PROPERTY`/`PLY_UNKNOWN_ELEMENT` loss warnings; mapped fields remain available.
The worker serializes the canonical document to bounded ASCII PLY for desktop validation.
This task does not expose a general PLY file-picker route or claim full PLY attribute parity.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-ply-mapping-fixtures.py -- tests/files/web/m12_ply_mapping_v1
tests/golden/M12-07H/mapping-report.json` generated deterministic ASCII and binary
little-endian fixtures containing four vertices, two faces, RGBA colors, and two numeric
custom vertex attributes. A derived ASCII fixture contains an unsupported list property.
- `node tools/web/check-ply-mapping-fixtures.mjs` matched pinned Blender 5.2 runtime identity,
artifact hashes, field counts and a fresh byte-for-byte regeneration:
`ply-mapping-fixtures-ok vertices=4 faces=2 colors=rgba custom=2 unknown=PLY_UNKNOWN_PROPERTY deterministic=true next=M12-07I`.
- `node --test web/tests/unit/ply-import.test.mjs` passed 3/3. It covers both encodings,
mapped values, unknown-property loss, serialization/reopen, and format mismatch blocking.
- `UPDATE_PLY_MAPPING_REPORT=1 CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5472
node_modules/.bin/playwright test --config playwright.config.ts --workers=1
tests/e2e/ply-web-roundtrip.spec.ts` passed 1/1. Production Chromium Worker parsed both
encodings, reported unknown loss, serialized ASCII, and pinned Blender 5.2 re-imported the
result with exact vertex/face/position counts and mapped custom/color attributes.
- `npm --prefix web run typecheck`, `node --check tools/web/check-ply-mapping-fixtures.mjs`,
and Python compile checks passed.
## Artifact Hashes
- protocol: `058a3263fde553637840a4e9ad4e8e9d923eb52c250f8000317c7f43a228881d`
- worker: `f6bf5e39e83286d7b257bbdce88f4d7fa027c64651da9765567788b5cf298c71`
- generator: `ffc051eccfc6973ee00cc791cdbd641fcce308b4083741e3e6ae82291d9347b7`
- checker: `2b055dbc705830848efdf4d8db8543a3ccc684de1f258732bcafefa86cf65c3a`
- desktop importer: `6edbc6e401a1a902dcfd11c4d767e8c8620d694e40eb4ca29dd8479f9c55ef37`
- unit/e2e: `b03a5f4b4b2a974fa26e653763470b92d1433c5d352ae09ab5492b841e6e5e1f` /
`2cadebc89057655d78e9b520bb6adf9debb27c6d783cd002efee08d269636fb9`
- desktop mapping report: `8a02fc9e364ed79e50ef00897affa9ab63808d3cb3cdabd00fdb8ee4c26ec18a`
- Chromium/desktop round-trip report: `1ca9d3b7870fcc8c9e3c9bbbd90ef48bd13bbc9ae0462312c9482f24f05f13ec`
- ASCII/binary/unknown fixtures: `acaa369c17252d4d089a2e3064d0c1fcdfdb2d066759ed160adf7869d3e859d5` /
`d0fc195fd1a101c42ac984a2382bccdddb7d0bf60dd618e9f637c964f1b30b9e` /
`a994c7126f235d0067ce4af35f8b0c6699cc83073e2a37e982edd45ece459f33`
## Next Task
`M12-07I`: PLY big-endian, malformed list, and oversized count stable blocking.
## Rollback
Remove the PLY mapping protocol, worker, fixture generator/checker, fixtures, reports, tests,
package script, and this status entry. Restore M12-07G as the queue tail and move the machine
queue back to M12-07H. No parity ledger rollback is required.

49
docs/status/M12-07I.md Normal file
View File

@@ -0,0 +1,49 @@
# M12-07I Status
status: done
task: PLY big-endian, malformed list, and oversized count stable blocking
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
PLY admission now fails closed for unsupported big-endian input, truncated/malformed list data,
and element counts above the bounded 65,536 record budget. The production parser returns stable
codes `PLY_FORMAT_UNSUPPORTED`, `PLY_DATA_TRUNCATED`, and `PLY_IMPORT_BUDGET_EXCEEDED: vertex`;
the Worker does not publish a partial document. No big-endian route or unbounded PLY import is
claimed.
## Evidence
- `node tools/web/generate-ply-negative-fixtures.mjs` generated deterministic big-endian,
malformed-list, and oversized-count fixtures. `node tools/web/check-ply-negative-fixtures.mjs`
regenerated them in a fresh temporary directory and passed:
`ply-negative-fixtures-ok cases=3 bigEndian=PLY_FORMAT_UNSUPPORTED malformed=PLY_DATA_TRUNCATED oversized=PLY_IMPORT_BUDGET_EXCEEDED deterministic=true next=M12-07J`.
- `node --test web/tests/unit/ply-negative.test.mjs` passed 2/2 for all three stable error paths.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5478 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/ply-negative.spec.ts` passed 1/1. The
production Worker returned the exact expected error for each case and never returned `ok=true`.
- `npm --prefix web run typecheck`, Node syntax checks, and `git diff --check` passed.
## Artifact Hashes
- protocol: `058a3263fde553637840a4e9ad4e8e9d923eb52c250f8000317c7f43a228881d`
- generator/checker: `9c09707bdfe73ba467bbfbf61ed3846fb59fd33ab5563a3a62c8032722ff6938` /
`b1d047d4cb1fa15dff7821687e7028ad073fdc62d4c76f60a2656732c0ec5e2b`
- unit/e2e: `60439f9e6bc221df8866956bf926816a347e85828b5a93deb26ee23015cf449a` /
`6509a29d6842f3423d4dfcc40dbd52a959a5efa7ee1121143dce06e5bbc4a460`
- report: `fbe2830d1b19294ea98eea66c3e00125bc0809a4bb8a750612939cbe1f5acca9`
- fixtures: `cda92943a3690529fbb3463d328b6796ac0d07e19139450556f7411fc1f031e3` /
`a6a576b7a04d919b540520a6f43a89c089f0d706a17fd8b390711fff6b8b03df` /
`fcd99e0838025429420a47466251cf80e638d2b5816ad14d5aa696364525bb`
## Next Task
`M12-07J`: three-format cancellation, OOM, Worker restart, and small-file recovery.
## Rollback
Remove the count guard, negative fixture generator/checker, fixtures, report, tests, manifest,
and this status entry. Restore M12-07H as the queue tail and move the machine queue back to
M12-07I. No parity ledger rollback is required.

50
docs/status/M12-07J.md Normal file
View File

@@ -0,0 +1,50 @@
# M12-07J Status
status: done
task: three-format cancellation, OOM, Worker restart, and small-file recovery
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
OBJ, STL, and PLY now share a schema-1 recovery receipt. Each bounded production Worker run
binds format, input hash, base/candidate revision, Worker generation, output hash, temporary bytes,
live requests, published result count, and commit state. Cancellation clears temporary state and
publishes no result; over-budget/OOM input returns `IO_FORMAT_OOM`; a generation-2 rerun and a
generation-3 small-file run reproduce the generation-1 output hash. This is recovery evidence for
the bounded format workers, not a general file-picker or full Blender IO claim.
## Evidence
- `node --test web/tests/unit/io-format-recovery.test.mjs` passed 2/2 for cancellation/OOM cleanup,
commit identity, generation recovery, and stale-generation blocking.
- `UPDATE_IO_FORMAT_RECOVERY_REPORT=1 CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5492
node_modules/.bin/playwright test --config playwright.config.ts --workers=1
tests/e2e/io-format-recovery.spec.ts` passed 1/1. The report covers OBJ, STL, and PLY separately:
three cancellations, three OOM budget faults, three Worker-generation restarts, and three small
recovery commits; all output SHA-256 values are stable.
- A second run without report update passed against the same golden, proving deterministic operation
IDs and receipt output. `node tools/web/check-io-format-recovery.mjs` passed:
`io-format-recovery-ok formats=OBJ,STL,PLY cancelled=3 oom=3 restart=3 smallRecovery=3 deterministic=true next=M13-01A`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Artifact Hashes
- protocol: `7e352539e3300969c7409c34d6056eb6ad31055431ffce84b1b0a459c335480a`
- worker/testing adapter: `63b78fbf25132cad28147ef68731f2cd212a26c96b464fdec349a13ebaa1174f` /
`cfcebb6ec38936a66983957b0dede716871cfbfbea3cb53cddc16f3e24fb19b0`
- unit/e2e: `aaed1f2abe4789b084c8a6a60bcce8595d38220d7e6678a93924cd05c5716b4f` /
`5c1750fa408e1297fc43f2e5749be3e9ac08a16b86265d22f0f06053f52b3bd7`
- checker: `6ef6bc4a168f8675a4933a06c296f61076b9ea64cec25b295e961a9b610ab1a2`
- report: `35d4fe10d8a4fa84d6e05a85f20ca50975d93a86df41e73c7bbc5875edc4fc70`
## Next Task
`M13-01A`: begin the next machine-queued milestone task.
## Rollback
Remove the IO recovery protocol, worker, adapter, tests, checker, report, manifest, and this
status entry. Restore M12-07I as the queue tail and move the machine queue back to M12-07J. No
parity ledger rollback is required.

47
docs/status/M13-01A.md Normal file
View File

@@ -0,0 +1,47 @@
# M13-01A Status
status: done
task: inventory Text, Python Console, autorun, driver expression, handler, and add-on entry points
updated: 2026-08-18 America/New_York
enablingTask: true
parityStateChange: false
## Scope
Pinned Blender 5.2 now has a machine-readable scripting entry inventory covering three Text
datablocks, Python Console operators, a module-autorun request, one driver expression, 39 handler
groups, and four add-on operators. The report records the entry source and default Web policy:
Text is metadata-only, while Console, autorun, driver expressions, handlers, and add-on operations
are `DENY`. This task only inventories entry points; it does not execute script text or open a
browser scripting route.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-script-entry-inventory.py -- tests/files/web/m13_script_entry_v1
tests/golden/M13-01A/entry-inventory.json` created a fixture with internal/external Text,
`use_module` autorun metadata, and a driver expression without executing user code.
- `node tools/web/check-script-entry-inventory.mjs` matched pinned runtime identity, policy and
semantic inventory, then regenerated the report in a fresh directory. Blender's `.blend` save
contains runtime save bytes that may differ between runs, so determinism is asserted on the
inventory and fixture byte length; the checked-in fixture hash remains bound in the manifest.
Output: `script-entry-inventory-ok texts=3 console=3 autorun=1 drivers=1 handlers=39 addonOps=4 deterministic=true next=M13-01B`.
- `python3 -m py_compile tools/web/generate-script-entry-inventory.py`, Node syntax check and
`git diff --check` passed.
## Artifact Hashes
- generator: `b72667493cfe9957161ef3fb9814180e0cfad5f8aaa1c60c9b6f132e915f3d6f`
- checker: `68478f15de4d63ed175e6b580761fd478b1fe9bccbfcaeee82218d13063dfa51`
- report: `e024995c53f01beaf725f281f74a6e5ec6018a53435da61a66f5e58a9e50973c`
- fixture: `bd6375d02908bfcc57ff7cdeec3f9827bfc4336d1e46e165c5fbbf4d04f19645`
- manifest: `d4a305033343ef5fb1ffc073617b59d9012f64b80ecb233e743fb0789a8b4893`
## Next Task
`M13-01B`: read script metadata on `.blend` open without executing arbitrary content.
## Rollback
Remove the generator, checker, fixture, report, manifest, and this status entry. Restore M12-07J
as the queue tail and move the machine queue back to M13-01A. No parity ledger rollback is required.

41
docs/status/M13-01B.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-01B Status
status: done
task: read script metadata on `.blend` open without executing arbitrary content
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The real `script_scene.blend` open path reads all three Text sources, verifies source bytes and
SHA-256, preserves read-only metadata, and keeps every source `executionStatus=BLOCKED`. A
`use_module` autorun request remains `SCRIPT_POLICY_DENIED`; no Python Console, driver, handler,
or add-on code executes during open. This task does not add a script execution route.
## Evidence
- `node tools/web/check-script-open-metadata.mjs` ran the production WASM Main reader against the
real fixture and passed `script-open-metadata-ok blend=opened textMetadata=read sourceHash=verified execution=DENY autorun=DENY next=M13-01C`.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5495 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/script-open-metadata.spec.ts` passed 1/1.
Chromium opened the fixture through `WebEngineClient`, saw three read-only blocked sources and
the explicit autorun denial.
- `npm --prefix web run typecheck` and `git diff --check` passed. The checker emits the deterministic
report `tests/golden/M13-01B/open-metadata-report.json` bound to the fixture hash.
## Artifact Hashes
- checker: `66396d5c9a5294021ae077bb162278c74d46de8b52ac8a444a5de4f6d84cfe05`
- e2e: `df6412cda113c830996e08c3d66a035dc1ac309e392f5946a762d11121b1926c`
- report: `f92470e57c048452134664f7f6208e50b6f087dbcbc33369e6b882c51813990c`
- fixture: `2b8fbdb05419e1e61d64777998d6a3b2562f726c17f548cd1852efc723e1a037`
## Next Task
`M13-01C`: default-deny autorun, register, install, and driver execution policy codes.
## Rollback
Remove the checker, report, manifest, e2e test, and this status entry. Restore M13-01A as the
queue tail and move the machine queue back to M13-01B. No parity ledger rollback is required.

39
docs/status/M13-01C.md Normal file
View File

@@ -0,0 +1,39 @@
# M13-01C Status
status: done
task: default-deny autorun, register, install, and driver execution policy codes
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting manifest parser and execution gate reject autorun/register/install/driver execution
requests with stable policy codes. The current bounded contract returns `SCRIPT_POLICY_DENIED` for
autorun, `DRIVER_EXECUTION_BLOCKED` for driver expressions, `ADDON_INSTALL_BLOCKED` for add-on
install/registration, and `SCRIPT_SANDBOX_UNAVAILABLE` even for a correctly signed script when no
isolated sandbox exists. No local eval or script execution is enabled.
## Evidence
- `node --test web/tests/unit/script-policy-codes.test.mjs` passed 1/1 and asserts all three denied
request codes plus the approved-key sandbox gate.
- `node tools/web/check-script-policy-codes.mjs` passed:
`script-policy-codes-ok autorun=SCRIPT_POLICY_DENIED driver=DRIVER_EXECUTION_BLOCKED addon=ADDON_INSTALL_BLOCKED sandbox=SCRIPT_SANDBOX_UNAVAILABLE next=M13-01D`.
- `npm --prefix web run typecheck`, Node syntax checks and `git diff --check` passed. The report and
manifest bind the transpiled production protocol source hashes.
## Artifact Hashes
- checker: `22588c2198bc8c425ab8e104e8559f0053654ae778aaea3783ec7d54822bc8f4`
- unit: `b5a52b8e707963545f1cd71f1a148fa9c9b9d1e4b4c5f51c87d33f8bf3777430`
- report: `956db548ee71688a4b89c9a993259d3e57129cd4abe9efd1b9397b3e30b1bf84`
## Next Task
`M13-01D`: ensure UI exposes no direct-eval bypass around the scripting policy.
## Rollback
Remove the checker, unit test, report, manifest and this status entry. Restore M13-01B as the queue
tail and move the machine queue back to M13-01C. No parity ledger rollback is required.

36
docs/status/M13-01D.md Normal file
View File

@@ -0,0 +1,36 @@
# M13-01D Status
status: done
task: UI direct-eval bypass gate
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production app, Workers, and protocol TypeScript sources contain no direct `eval(` or
`new Function(` bypass. The scan covers 176 non-vendor `.ts/.tsx` files and records the only
declared scripting policy entry points: `gateScriptExecution`, `gateServerScriptJob`, and
`parseScriptSourceInventory`. Execution remains `DENY`; this static gate does not claim a sandbox.
## Evidence
- `node tools/web/check-script-ui-bypass.mjs` passed:
`script-ui-bypass-ok scanned=176 violations=0 policyEntrypoints=3 report=8e234e128b90036548ab709b86b063de404250da2c5c0a6e25e28969b5cd5c73 next=M13-01E`.
- `git diff --check` passed. Vendor-generated Emscripten/Three.js sources are outside the scan;
no application or protocol source is allowed to introduce a direct eval constructor.
## Artifact Hashes
- checker: `f34cb64891c2b22bc3da353f6b864ba3e558d3c286cf716bcb778d9a542cb3d9`
- report: `6b050092088508ebd5d769d95a2e66f0cd4020c97f3407724a19b9707f51f6dd`
- manifest: `6b28688b3ebcce5629bcfc437d4ca903d0b1e053b32a796690ee4e021726c75b`
## Next Task
`M13-01E`: preserve Text data and unknown script sources through save/reopen.
## Rollback
Remove the checker, report, manifest, and this status entry. Restore M13-01C as the queue tail and
move the machine queue back to M13-01D. No parity ledger rollback is required.

41
docs/status/M13-01E.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-01E Status
status: done
task: preserve Text data and unknown script sources through save/reopen
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production WebEngine path opens `script_scene.blend`, saves it, starts a new engine Worker,
and reopens the saved bytes. All three Text sources compare exact by metadata and source SHA-256;
they remain read-only and `BLOCKED`, including the `use_module` autorun request. No source is
rewritten or executed. This does not claim arbitrary script execution or add-on support.
## Evidence
- `UPDATE_SCRIPT_SAVE_REOPEN_REPORT=1 CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5498
node_modules/.bin/playwright test --config playwright.config.ts --workers=1
tests/e2e/script-save-reopen.spec.ts` passed 1/1. A second run without report update on port 5497
also passed against the same deterministic report.
- `node tools/web/check-script-save-reopen.mjs` passed:
`script-save-reopen-ok sources=3 exact=true blocked=true savedBytes=490191 next=M13-01F`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Artifact Hashes
- checker: `7fc9a370cb472636e2699565cb21a1450e3cc8a2c90ffdcdff96533b344afa7c`
- e2e: `481f78f3a0cce923b67ab14436cc23cbcd2ce66725de29dc874fea4fb5801227`
- report: `0f6869a8ec8342ed87649312d2872ab2c172cbf12d6be81bb0b770ebcbe8a398`
- manifest: `889a4e06f7e8c0ea55b3ca4baa9fe85dccbe97053e497a45e3d364ce2b70a7c6`
- fixture: `2b8fbdb05419e1e61d64777998d6a3b2562f726c17f548cd1852efc723e1a037`
## Next Task
`M13-01F`: malicious Text, driver, handler, and embedded-module fixtures.
## Rollback
Remove the checker, e2e test, report, manifest, and this status entry. Restore M13-01D as the
queue tail and move the machine queue back to M13-01E. No parity ledger rollback is required.

44
docs/status/M13-01F.md Normal file
View File

@@ -0,0 +1,44 @@
# M13-01F Status
status: done
task: malicious Text, driver, handler, and embedded-module fixtures
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Pinned Blender 5.2 generated a malicious fixture containing four source bodies: OS command text,
driver import, handler subprocess, and an embedded `register()` module. Chromium opened the file
through the production Main reader and kept every source read-only/`BLOCKED`; the embedded module
returned `SCRIPT_POLICY_DENIED`. No filesystem marker or execution path is exposed by the test.
## Evidence
- `build_blender_5.2.0/bin/blender -b --factory-startup --python
tools/web/generate-malicious-script-fixture.py -- tests/files/web/m13_malicious_script_v1
tests/golden/M13-01F/malicious-report.json` generated four deterministic source hashes and one
`use_module` request.
- `node tools/web/check-malicious-script-fixture.mjs` passed:
`malicious-script-fixture-ok sources=4 module=1 execution=BLOCKED fixtureSha256=7b1921931afc5bb74a2b73e90b175017c583ea878cdbb66f131718b2d8cd23b5 next=M13-02A`.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5499 node_modules/.bin/playwright test
--config playwright.config.ts --workers=1 tests/e2e/malicious-script.spec.ts` passed 1/1.
- `git diff --check` passed.
## Artifact Hashes
- generator: `013285befeb59de21a887cefd377adf8cf53ff1c785b28a9c87d29f76f092731`
- checker: `36608da893ae59e2e03856a62866ea6e7c349ec4a63200f042b2329e5f61caa9`
- e2e: `98fbde6728ddf55cce5262522197a5b4db1dfce618e52259bf0b0c9e0e9165f2`
- report: `a628b73411d6f9a761f659ae28867ea9b0c0df30d47668353278b70d4b44180c`
- fixture: `7b1921931afc5bb74a2b73e90b175017c583ea878cdbb66f131718b2d8cd23b5`
- manifest: `9a0b7c4097b3755365a9fb92b4848e6ac2ddd36ee2c7e9df3cb8808ce247cf3d`
## Next Task
`M13-02A`: bounded script manifest limits.
## Rollback
Remove the generator, checker, fixture, report, manifest, e2e test, and this status entry. Restore
M13-01E as the queue tail and move the machine queue back to M13-01F. No parity ledger rollback is required.

49
docs/status/M13-02A.md Normal file
View File

@@ -0,0 +1,49 @@
# M13-02A Status
status: done
task: bounded script manifest limits
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting manifest parser now requires an explicit `sourceByteLength` and
`module=false` for every script. It limits script count, aggregate source bytes, dependency count,
permission count and per-field execution budgets; canonicalizes entry/dependency paths within the
project; and rejects duplicate dependencies, unsafe paths, module execution, unknown permissions
and all budget overflow. The parser remains fail-closed and does not execute script content.
## Evidence
- `node --test web/tests/unit/script-manifest-budgets.test.mjs` passed 4/4 bounded positive and
negative cases.
- `WEB_TEST_PORT=5513 npm --prefix web run test:script-manifest-budgets` passed unit 4/4 and the
production Chromium Worker test 1/1. The browser Worker returned the same canonical paths,
aggregate byte count and stable policy/budget errors as the Node protocol test.
- `node tools/web/check-script-manifest-budgets.mjs` passed:
`script-manifest-budgets-ok accepted=2 totalSourceBytes=256 blocked=6 deterministic=true next=M13-02B`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint`,
`npm --prefix web run build`, `npm --prefix web run test:scripting-isolation`, and
`git diff --check` passed. The existing isolation gate still reports approved-key
`SCRIPT_SANDBOX_UNAVAILABLE` and does not enable execution.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `8d8eae67fa6915f0337850e15247baf01f0abde0b3362fbb120f0b448f1a4cf5`
- checker: `b3457324d72ab233cd17a142ea19fac6a0d024dd95de7b8fb5d26810437fb0d2`
- unit: `6ce7847a0b745ba4081e4332d012e0b7f86e4906c71c95bdeda8c39977a630ee`
- e2e: `1ef4fd4caaeb1fa3d832fc8881823d5284755372575eab186c751f408dc9314c`
- report: `860672fe844b7969ca376d4b2708771189d1767efa819f7b97667d8a26438d3a`
- manifest: `7148e0387dadffdb55e94e80dc30cfd5cdd40ebe990d06378e90c376d36ebd51`
## Next Task
`M13-02B`: canonical serialization fixes the signature input.
## Rollback
Remove the M13-02A protocol fields, checker, unit/Chromium tests, worker, report, manifest and this
status entry. Restore M13-01F as the queue tail and move the machine queue back to M13-02A. No parity
ledger rollback is required.

52
docs/status/M13-02B.md Normal file
View File

@@ -0,0 +1,52 @@
# M13-02B Status
status: done
task: canonical script manifest serialization
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting protocol now exposes `canonicalizeScriptingManifest` and
`serializeScriptingManifest` as the single canonical signature-input path. Script, permission and
dependency arrays are sorted with locale-independent code-unit ordering; unknown fields are removed
by the parser; canonical JSON has sorted object keys and no whitespace; and security-relevant fields
such as source byte length, source hash, permissions, paths, budgets and policy flags remain in the
serialized input. Schema changes and source declaration mutations produce a different or rejected
input. No signature is accepted and no script is executed by this task.
## Evidence
- `node --test web/tests/unit/script-manifest-canonical.test.mjs` passed 2/2. It proves order
invariance, unknown-field dropping, security-field binding and schema rejection.
- `WEB_TEST_PORT=5514 npm --prefix web run test:script-manifest-canonical` passed unit 2/2 and
production Chromium Worker 1/1.
- `node tools/web/check-script-manifest-canonical.mjs` passed:
`script-manifest-canonical-ok equal=true bytes=1923 unknownDropped=true schemaMutation=blocked next=M13-02C`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint`, `npm --prefix web run build`,
`node tools/web/check-script-manifest-budgets.mjs`, `node tools/web/check-status-consistency.mjs`
and `git diff --check` passed. The M13-02A artifact manifest was refreshed to the current protocol
hash after this additive canonical API change, and its checker was rerun successfully; no prior
behavior or parity status was changed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `de27fdcd6d16e27a07806ac609f908edfdb7a93d653676174cdd5e06ffa394af`
- checker: `5ed344cab6428ae5538a450171ba40c73ff738666515492298e30aaed1394f56`
- unit: `33eae0f3ad2ae7243c9ce2835ab8e42186f65f574ab682099766f1d0f4c481f6`
- e2e: `5342301165ae82a01b46f5fed0cc0ec34b9813a6ecbc8032900d90b89628e064`
- report: `5f4bc0b098ea65de47f1255d30130376d74260e2b912bcd0e28354171fbd07df`
- parent manifest: `7148e0387dadffdb55e94e80dc30cfd5cdd40ebe990d06378e90c376d36ebd51`
- manifest: `605c656780a206a0d3b81d06b0294108b488a62d2b709e886884a2973c6cb091`
## Next Task
`M13-02C`: signer identity, key rotation, revocation and timestamp policy.
## Rollback
Remove the canonical serializer exports, checker, unit/Chromium tests, worker, report, manifest and
this status entry; restore M13-02A as the queue tail and move the machine queue back to M13-02B. No
parity ledger rollback is required.

51
docs/status/M13-02C.md Normal file
View File

@@ -0,0 +1,51 @@
# M13-02C Status
status: done
task: signer identity, key rotation, revocation and timestamp policy
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting protocol now has a versioned trust-policy schema for signer identity and key
lifecycles. It validates ED25519 public-key identity, publisher ownership, active/revoked status,
not-before/not-after windows, revocation timestamps, same-publisher rotation predecessors and
acyclic rotation chains. `maxClockSkewMs` binds policy timestamps to an explicit bounded window.
`resolveScriptSigner` only returns `ELIGIBLE` with `cryptographicVerification=REQUIRED`; revoked,
expired, not-yet-valid, missing and publisher-confused keys remain structured `BLOCKED` results.
This task does not verify signatures or enable script execution.
## Evidence
- `node --test web/tests/unit/script-trust-policy.test.mjs` passed 3/3. It covers valid active
rotation, revoked predecessor, invalid/cross-publisher/cyclic rotation, revocation metadata,
public-key format and timestamp failures.
- `WEB_TEST_PORT=5516 npm --prefix web run test:script-trust-policy` passed unit 3/3 and production
Chromium Worker 1/1.
- `node tools/web/check-script-trust-policy.mjs` passed:
`script-trust-policy-ok active=key:new revoked=REVOKED crossPublisher=SCRIPT_POLICY_DENIED policyExpired=POLICY_EXPIRED crypto=REQUIRED next=M13-02D`.
- `npm --prefix web run typecheck` passed; M13-02A and M13-02B checkers were rerun after the
additive protocol change and passed. No parity ledger or execution route changed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `c6e206b29e7cacc3e23e2ac12a3d523a9c0b16ff29759126dab13c8665547421`
- checker: `0e55ce20d142f2bcbc5ce9c6fb955ef2771d284dff636c79da3f59a33b8b0aeb`
- unit: `59ac77bcc1086e0a0e914cb77d647db5d34c7160202e7aad52948b7277769551`
- e2e: `614091bda15367090bc78a6f465fb10d02d0aa08775b5088699b12e2490034d2`
- report: `0f59f733920edbbe5cb799e5f50ff31d19e55ced98e7a890828f6337a237e4bd`
- unit: `aac3ff0a1c7ae27e35112614bedabc02bb248882ec9b0b52d65f9794d06830d8`
- parent manifest: `605c656780a206a0d3b81d06b0294108b488a62d2b709e886884a2973c6cb091`
- manifest: `89745daca88371335f4bd56982791266461082066c6c1345056fbc697bb7e6a2`
## Next Task
`M13-02D`: signature only approves declared content and source hash changes invalidate it.
## Rollback
Remove the trust-policy schema, parser/resolver, checker, unit/Chromium tests, worker, report,
manifest and this status entry; restore M13-02B as the queue tail and move the machine queue back to
M13-02C. No parity ledger rollback is required.

46
docs/status/M13-02D.md Normal file
View File

@@ -0,0 +1,46 @@
# M13-02D Status
status: done
task: signature verification binds declared content
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
`verifyScriptManifestSignature` now verifies the canonical per-script manifest input with the
trusted ED25519 key. The input includes the declared source SHA-256 and all policy-relevant fields,
while excluding only the signature field itself. A source hash or signature mutation therefore
returns `SCRIPT_SIGNATURE_INVALID`; revoked or otherwise ineligible keys return
`SCRIPT_POLICY_DENIED`. Verification remains a policy gate and does not enable script execution.
## Evidence
- `node --test --test-name-pattern=M13-02D web/tests/unit/script-trust-policy.test.mjs` passed the
M13-02D case (1 passed, 3 unrelated cases skipped).
- `WEB_TEST_PORT=5520 npm --prefix web run test:script-signature` passed the focused Node case and
production Chromium Worker E2E (1/1).
- `node tools/web/check-script-signature.mjs` passed:
`script-signature-ok verified=SCRIPT_SIGNATURE_VERIFIED sourceHashChanged=SCRIPT_SIGNATURE_INVALID revoked=SCRIPT_POLICY_DENIED next=M13-02E`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint`, `npm --prefix web run build` and
`git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `f4e8ff45d06efcfa9e634ef28e654241d70554ed05dfe9c3fecd9f6eef166ce0`
- checker: `2d6e7b403dd6d401eb1a41978016b40bd1fb86120464e09f185de4445c177fa4`
- unit: `aac3ff0a1c7ae27e35112614bedabc02bb248882ec9b0b52d65f9794d06830d8`
- e2e: `8a882fc8fa2c0c4e2eab3660810cec0f60d2f7475f62a1bb406fc3b2bdf60882`
- report: `957daf8e5899714cc5ce253b1f0fb2b258f1cc966238fff31e2626f8f56feb3a`
- manifest: `c6b79a77e4b7ffe5f4a9ba785a30305f9cf6e86caf89b38a4b303a86ab662a31`
## Next Task
`M13-02E`: permission default-minimization and unknown-permission blocking.
## Rollback
Remove the M13-02D checker, report, manifest, status entry and focused package command; restore
M13-02C as the queue tail and move the machine queue back to `M13-02D`. No parity ledger rollback
is required.

42
docs/status/M13-02E.md Normal file
View File

@@ -0,0 +1,42 @@
# M13-02E Status
status: done
task: permission default-minimization and unknown-permission blocking
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
`resolveScriptPermissions` now grants an empty set by default and only grants an explicitly
requested permission when it is already declared by the script manifest. Unknown, duplicate or
undeclared requests return `SCRIPT_POLICY_DENIED`; manifest declarations still reject unknown
permissions during parsing. This task adds no execution capability.
## Evidence
- `node --test web/tests/unit/script-permission-policy.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5521 npm --prefix web run test:script-permission-policy` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-permission-policy.mjs` passed:
`script-permission-policy-ok defaultGranted=0 declared=READ_MAIN escalation=SCRIPT_POLICY_DENIED unknown=SCRIPT_POLICY_DENIED next=M13-02F`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `5df074e676542475009a4980fecaf3fdde009d149de84b9ca146647fb6aa1c02`
- checker: `169ab096295e08c5a630ef09d814da6ce742efd7a7143ff9a17984b4ca20593a`
- unit: `43bb6796616f3f92d71b51ef2a119a4e263864121a03356764e4b9c9241c4043`
- e2e: `dc13412a44f277bbe68315da0d38a2c4aa520d7489c81e7c908f9768c0547b7e`
- report: `8dc41e75620ba5bcb08d0edc52c3994e4f4dbc37ad3633757634bf10fe97b252`
- manifest: `691376d3cd33d3cd339b7195034abaf89cc02fba7e740c40ff051c4496400eef`
## Next Task
`M13-02F`: replay, key-confusion, expiry and multi-signature negative cases.
## Rollback
Remove `resolveScriptPermissions`, the focused worker/unit/E2E/checker, report, manifest, status
entry and package command; restore M13-02D as the queue tail and move `nextTask` back to `M13-02E`.

42
docs/status/M13-02F.md Normal file
View File

@@ -0,0 +1,42 @@
# M13-02F Status
status: done
task: signature replay, key-confusion and expiry negative cases
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The signature gate now has an independent negative-case matrix covering missing keys, expired and
not-yet-valid keys, publisher/key confusion, and a signature copied to a different script. Every
case remains fail-closed with `SCRIPT_POLICY_DENIED` or `SCRIPT_SIGNATURE_INVALID`; no execution
route is added. Canonical script ordering remains accepted when the script's own signature matches.
## Evidence
- `node --test web/tests/unit/script-signature-negative.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5522 npm --prefix web run test:script-signature-negative` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-signature-negative.mjs` passed:
`script-signature-negative-ok missing=SCRIPT_POLICY_DENIED expired=SCRIPT_POLICY_DENIED notYetValid=SCRIPT_POLICY_DENIED swapped=SCRIPT_SIGNATURE_INVALID next=M13-03A`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `49b289110a6533fcd1a29ad78be00792fd3c0d251c6027bae0440f5daba929a1`
- checker: `35f2e6727aef5e6ea2e2623e2effa6ea0356faaf66d417976db7f5bbe671a38c`
- unit: `8b9c8d63c97fce07299622b9ad261791a97bb91a6ed340e72c24c55e685978bd`
- e2e: `26c52ef67d6b1ea2994d92637826994e98e5234e042049f8d69a905f5cdb3309`
- report: `d23a2ae5613b2442ad79420aa344ebfe3767d10ac19b3ea30a62afcccd3a167c`
- manifest: `283673b21e6c9b89dc6ecb7007f3cecf28d53a84ec84f3f8b52373c055538a74`
## Next Task
`M13-03A`: sandbox capability scope with no DOM, host-worker, OPFS, IndexedDB or network access.
## Rollback
Remove the M13-02F negative-case worker, tests, checker, report, manifest, status entry and package
command; restore M13-02E as the queue tail and move `nextTask` back to `M13-02F`.

42
docs/status/M13-03A.md Normal file
View File

@@ -0,0 +1,42 @@
# M13-03A Status
status: done
task: sandbox capability scope
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting protocol now defines a versioned all-deny sandbox scope. DOM, host-worker,
OPFS, IndexedDB and network capabilities must each be explicitly `false`; any enabled, missing or
unknown scope version is rejected with a stable policy/protocol error. This is a capability contract
only: script execution remains disabled and no sandbox implementation is claimed.
## Evidence
- `node --test web/tests/unit/script-sandbox-scope.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5523 npm --prefix web run test:script-sandbox-scope` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-scope.mjs` passed:
`script-sandbox-scope-ok dom=SCRIPT_POLICY_DENIED hostWorker=SCRIPT_POLICY_DENIED opfs=SCRIPT_POLICY_DENIED indexedDB=SCRIPT_POLICY_DENIED network=SCRIPT_POLICY_DENIED execution=DISABLED next=M13-03B`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `27058fbb602791cbe6691fa14b3bc9c3d6cdea79641ba9c72fe18b6226d2a651`
- checker: `ad26ea3b078e480ba8f99cbf8dbd0d9b135c7605f4a3958d24845b7f5f8b0f43`
- unit: `a15da2e645d2d681c7e9ac1380f6b224d196d1d2e78d20f1bacad01e138753d4`
- e2e: `49930747e6663f79b61093706318b72e59388d79e3e1cc105bc1571693326667`
- report: `ba5784c751d5a347f38aa522ffcbed270d38fb474f0f10a2d06ea501d0234021`
- manifest: `76a7ce0fd3a38fb770c9cedccbd05ed566b931caa1782fdae898d3b66c3a20bf`
## Next Task
`M13-03B`: fixed CPU, wall-time, memory, message and output-byte budgets.
## Rollback
Remove the sandbox scope parser, focused worker/tests/checker, report, manifest, status entry and
package command; restore M13-02F as the queue tail and move `nextTask` back to `M13-03A`.

41
docs/status/M13-03B.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-03B Status
status: done
task: sandbox CPU, wall, memory, message and output budgets
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The scripting protocol now parses bounded CPU, wall-time, memory, message and output-byte budgets.
Each field has a fixed maximum and all overflow or schema drift returns `SCRIPT_BUDGET_EXCEEDED` or
`PROTOCOL_MISMATCH`. The budget is a contract only; execution remains disabled.
## Evidence
- `node --test web/tests/unit/script-sandbox-budget.test.mjs` passed 2/2.
- `WEB_TEST_PORT=5524 npm --prefix web run test:script-sandbox-budget` passed unit 2/2 and
production Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-budget.mjs` passed:
`script-sandbox-budget-ok cpu=SCRIPT_BUDGET_EXCEEDED wall=SCRIPT_BUDGET_EXCEEDED memory=SCRIPT_BUDGET_EXCEEDED message=SCRIPT_BUDGET_EXCEEDED output=SCRIPT_BUDGET_EXCEEDED execution=DISABLED next=M13-03C`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `ed836a032b33f54154fdd36f9f6e99ee43ca1755ea0dd8326474a13300ec965e`
- checker: `ab10d1d32c20022c848be4b33e1be846168a9ca4cf22ac932ea000001e9e2391`
- unit: `caa40fc58a73aa4d433285c94009e5436a29fbcb6b4e18b74b27c49fd0b07490`
- e2e: `8be77fd55e76149bfe2e0e449d81a62707ebfa430514936808ec4805fc96e07c`
- report: `4355710e07e95cbb0f96a82fdefca3607f363d3aea9ba89c332e8a4708b7bed2`
- manifest: `b61978c22cdfffe81b812e2eea788d52326f9f0ebb4540e77f86dc9e19ff21dd`
## Next Task
`M13-03C`: host calls use explicit allowlist and structured parameters.
## Rollback
Remove the sandbox budget parser, focused worker/tests/checker, report, manifest, status entry and
package command; restore M13-03A as the queue tail and move `nextTask` back to `M13-03B`.

43
docs/status/M13-03C.md Normal file
View File

@@ -0,0 +1,43 @@
# M13-03C Status
status: done
task: explicit host-call allowlist and structured parameters
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting protocol now accepts only five host-call names: `READ_MAIN`, `READ_ASSET`,
`WRITE_MAIN`, `WRITE_ASSET` and `SUBMIT_SERVER_JOB`. Each request has a version, request/script IDs,
permission binding and call-specific structured parameters. Unknown calls, permission confusion,
unknown fields, unsafe paths and malformed payloads fail closed. Parsed calls remain
`execution=DISABLED`; no host operation is invoked.
## Evidence
- `node --test web/tests/unit/script-host-call.test.mjs` passed 3/3.
- `WEB_TEST_PORT=5525 npm --prefix web run test:script-host-call` passed unit 3/3 and production
Chromium Worker E2E 1/1.
- `node tools/web/check-script-host-call.mjs` passed:
`script-host-call-ok accepted=5 blocked=4 structured=true execution=DISABLED next=M13-03D`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `b26a37f20e829172bb70fbe9b9e3a194923818127cccbe8bbc55f6d994be55e8`
- checker: `e90042f4eefd9e89da6d1cead87ca1cb9db9b3bd65ba8028593e093903577e2e`
- unit: `e7679cd902c75504204d528343e4fa6be316d1c56c02b2871a67637aa847a1ec`
- e2e: `7b17a7da440aee07895101efb8e1eb13bfbebbe54e955bde09299f6b33d6aaf9`
- report: `afb140a3aecff1de52c4363e7cd0ce476b0c9140ffdc016ec13a085049f6dd1a`
- manifest: `54318c45b11dd1707fecf78b0637257158102ea1dbb88d4d442e33b77df2cdbf`
## Next Task
`M13-03D`: sandbox crash/timeout terminates the job without changing Main revision.
## Rollback
Remove the host-call parser, focused worker/tests/checker, report, manifest, status entry and package
command; restore M13-03B as the queue tail and move `nextTask` back to `M13-03C`.

46
docs/status/M13-03D.md Normal file
View File

@@ -0,0 +1,46 @@
# M13-03D Status
status: done
task: sandbox crash/timeout isolation
updated: 2026-08-18 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The sandbox job termination receipt now converts crash, wall-time timeout and cancellation into
stable fail-closed statuses. Every terminated receipt keeps `mainRevisionAfter` equal to
`mainRevisionBefore`, publishes no result, releases temporary bytes, and remains
`execution=DISABLED`; a result received after termination is rejected with
`SCRIPT_SANDBOX_LATE_RESULT`.
The Chromium test starts a production Worker that throws for the crash case and a production Worker
that would publish a delayed result for the timeout case. The host observes the crash, terminates the
timeout Worker before its delayed message, and confirms no late message arrives.
## Evidence
- `node --test web/tests/unit/script-sandbox-isolation.test.mjs` passed 3/3.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5532 npm --prefix web run test:script-sandbox-isolation` passed unit 3/3 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-isolation.mjs` passed:
`script-sandbox-isolation-ok crash=SCRIPT_SANDBOX_CRASHED timeout=SCRIPT_SANDBOX_TIMEOUT revisionUnchanged=true late=SCRIPT_SANDBOX_LATE_RESULT next=M13-03E`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `8c810ee7c8bd15d83ecfb4981068f947536bfe8c9e63b906861f42b8465722da`
- checker: `e5c0c3c7cd500c269ae43a1a9eb05589e82aad28199ab4f11ad1167b486f6937`
- unit: `47986f93638fdc18b817b03222484f4691dc294185040eaebac8e1f386bc1549`
- e2e: `2c16c42f09827a0c0100ef2cc6295ca6bc96933ed7475e08b1fa195d7940c141`
- report: `4af91cdb21101039b379136c7559b46df55f4f5ab5478c05c1c57cd6e1624d2a`
- manifest: `8066013f3d356ba438c36d1f1ea1cf692dbb4f60b086f552072e36b783a96d42`
## Next Task
`M13-03E`: cancellation after termination must not publish a late message or cache.
## Rollback
Remove the isolation Worker additions, focused tests/checker, report, manifest and this status entry;
restore M13-03C as the queue tail and move `nextTask` back to `M13-03D`.

45
docs/status/M13-03E.md Normal file
View File

@@ -0,0 +1,45 @@
# M13-03E Status
status: done
task: sandbox cancellation result gate
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Cancellation now has an explicit terminated-job receipt. The receipt preserves the Main revision,
publishes no result, releases temporary bytes and remains `execution=DISABLED`. The production
Chromium Worker schedules a late message containing a cache key; the host cancels and terminates it
before publication, then observes a bounded late window with zero messages and zero cache writes.
Late results supplied after cancellation are rejected with `SCRIPT_SANDBOX_LATE_RESULT`.
This task does not claim Worker/port/timer disposal or same-session recovery; those remain M13-03F/G.
## Evidence
- `node --test web/tests/unit/script-sandbox-cancellation.test.mjs` passed 2/2.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5533 npm --prefix web run test:script-sandbox-cancellation` passed unit 2/2 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-cancellation.mjs` passed:
`script-sandbox-cancellation-ok status=CANCELLED late=SCRIPT_SANDBOX_LATE_RESULT lateMessages=0 cacheWrites=0 next=M13-03F`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `6699fc0a19e0736823f164e707a420655803e36019cf0071f7ff9c760d25e9f2`
- worker: `0feb70c8c491cc24ebfe6c3e267b92522d616b6f260efcecfa57cf489d0742c0`
- checker: `b6fbe7102b7d0808673931c66797f8976e79b21bd4c32e429f21832c6090708e`
- unit: `374cc87f66bd42226b750e387663ef8c86bef92348fa7cbc6ed7f0027945204d`
- e2e: `b233d9cafa1f70798ec19d76ca936abb610681522264a12237f532eb98e09fca`
- package: `6499a70fc4a93c925053ddf5009c74d9c10754b443afc9d58e898fe20d7f1b05`
- report: `066d9f19716b8229f2cf7755ec3009a3edef942ebab5f70159bec7f2afbaf71f`
- manifest: `0cdf625e6bd3ed7aca43318a3b04353cb806c51cfa4cf3c5dae9a65a0eae2e69`
## Next Task
`M13-03F`: dispose Worker, MessagePort, timers, abort controllers and buffers to zero.
## Rollback
Remove the cancellation Worker, focused tests/checker, report, manifest, package command and this
status entry; restore M13-03D as the queue tail and move `nextTask` back to `M13-03E`.

44
docs/status/M13-03F.md Normal file
View File

@@ -0,0 +1,44 @@
# M13-03F Status
status: done
task: sandbox resource disposal gate
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The sandbox Worker now owns an explicit disposal receipt. Both `MessagePort` endpoints, the timer,
`AbortController`, transferable buffer, pending request and cache reference are observed before
disposal and are all zero after the first dispose. A second dispose is accepted and reports
`idempotent=true`; the cleared timer produces no late message. Script execution remains
`DISABLED`, and this task does not claim same-session recovery or server isolation.
## Evidence
- `node --test web/tests/unit/script-sandbox-dispose.test.mjs` passed 2/2.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5534 npm --prefix web run test:script-sandbox-dispose` passed unit 2/2 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-dispose.mjs` passed:
`script-sandbox-dispose-ok ports=0 timers=0 abortControllers=0 buffers=0 pending=0 cacheReferences=0 idempotent=true next=M13-03G`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `f3d9f667c3809cfad0f52bc6028d93e36e25c4b639fb6081c9c933fbad0ebc0a`
- worker: `2a074b05d301c4083e60534eb9452aabf5d95aea0ab316fa657441ef4bcd5c96`
- checker: `6549bd10f588281d23c4bea705fd164252c9e3f44d8f4b93c893a2c410907135`
- unit: `6e00aa6286aae0eabc1345c04c7628dcc9acb32d51c1c27436a0e1b4c170b64c`
- e2e: `b240d92c90e0d81272cd9cb3c0eb4e7d77102ce2e49ad05c761f763d1812b18e`
- package: `0f06cd7ccdeed4213b6cb956aecf94e60dceff811ad8c3a2e239397685cfc1bf`
- report: `2dbd3e79939b500c0fc83216c51f258b88ead42a667ed1a6da755e893d7f73c6`
- manifest: `96abc7c7613ef4c18c64b84ffb8420c39369f9e4733bd1fa4d7d9ee9e53d6f89`
## Next Task
`M13-03G`: recover a small script in the same session with a new Worker generation while keeping
the Main revision/source hash stable and extending the audit hash chain.
## Rollback
Remove the dispose protocol, Worker, focused tests/checker, report, manifest, package command and
this status entry; restore M13-03E as the queue tail and move `nextTask` back to `M13-03F`.

43
docs/status/M13-03G.md Normal file
View File

@@ -0,0 +1,43 @@
# M13-03G Status
status: done
task: same-session sandbox recovery and audit continuity
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
A denied script request can be resumed in the same session after a Worker generation change from 4
to 5. The Main revision remains 11, and the source and canonical manifest hashes remain stable.
Two default-deny audit entries use distinct request IDs, sequence 1/2, and a continuous
`previousEntrySha256 -> entrySha256` chain. Replay and source-hash tampering are rejected. This task
does not enable Python execution or claim Blender server isolation.
## Evidence
- `node --test web/tests/unit/script-sandbox-recovery.test.mjs` passed 2/2.
- `CHROME_PATH=/usr/bin/google-chrome-stable WEB_TEST_PORT=5535 npm --prefix web run test:script-sandbox-recovery` passed unit 2/2 and Chromium Worker E2E 1/1.
- `node tools/web/check-script-sandbox-recovery.mjs` passed:
`script-sandbox-recovery-ok generation=4->5 revision=11 sourceStable=true manifestStable=true sequence=1,2 chain=true replay=SCRIPT_MANIFEST_INVALID tamper=SCRIPT_MANIFEST_INVALID next=M13-04A`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `8034faded657d49e1376ea42051bc302a090b485024a9ff3781e46aa82638b64`
- worker: `7b02331c375d4fb7dbadadd179f0ab9a0e336c8b95fabb071c06e67f3e7b3fe4`
- checker: `612015a3fca44bae0f0b78e622f044a5297ed8aa3a0efc774a40f0d47ddbdc9e`
- unit: `69a2d34e38d591043ff62b2d305bd9aae684ecebd9ecba718580d77318931226`
- e2e: `73176e513f115ba917be74f62a5deb8fe2918fafa8a84c9294e80d2a86b8f1ed`
- package: `3df02b6049ac5d7185c23aef7764933ee460fedeb6595b3861272b0d49da5ecd`
- report: `9057b3f49c3bb15cf53d638ada4bd2743949d3914173cd3799414489d584111d`
- manifest: `5cd365eeebbd6a7f56f380af103b66f2beb11eb49cb6db6adb49972b572cf2ec`
## Next Task
`M13-04A`: create an unpredictable one-shot directory for each real Blender server job.
## Rollback
Remove the recovery protocol, Worker, focused tests/checker, report, manifest, package command and
this status entry; restore M13-03F as the queue tail and move `nextTask` back to `M13-03G`.

44
docs/status/M13-04A.md Normal file
View File

@@ -0,0 +1,44 @@
# M13-04A Status
status: done
task: server job one-shot directory
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The server-side job allocator creates an unpredictable `0700` directory below a configured absolute
root for each request. Directory names do not contain the request ID, two concurrent jobs receive
distinct directories, and successful or failed cleanup removes the directory exactly once. Repeated
cleanup is idempotent. This task does not claim read-only source mounts, process limits or Blender
execution.
Browser E2E is not applicable: this is a Node server filesystem boundary. The checker uses real
temporary directories and `fs.stat`/`fs.rm` calls.
## Evidence
- `node --test web/tests/unit/server-job-isolation.test.mjs` passed 2/2.
- `npm --prefix web run test:server-job-directory` passed unit 2/2 and the independent checker.
- `node tools/web/check-server-job-isolation.mjs` passed:
`server-job-directory-ok allocated=2 cleaned=2 unique=1 requestIdsHidden=1 mode=0700 residual=0 idempotent=1 next=M13-04B`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `3aa5678a2c2769e4db5bb8f5c755b97e23045c4106e5636459748ab9b41929cd`
- checker: `b8d0e741144f742946246370bd35820d806686fb00dc0b040c925cf16f2179da`
- unit: `b1ac3324332180f7b3522f135520e7b5dace334dc461c92f2bce48fbcba2e147`
- package: `0c2633da831e7ca10cf74797650353b6dfb1507ed5957688d34bc97f9a6dd193`
- report: `07ed66fe0b2e1f1bbdba1cfb1089b052a5961d38f761bfcf79d8362980d2d502`
- manifest: `fd2407a7b9fefe67e2d77ed844e6c2ca17cdc4a746857a5825a38ff02ab664e3`
## Next Task
`M13-04B`: source read-only mount and independent writable output directory.
## Rollback
Remove the directory allocator, focused tests/checker, report, manifest, package command and this
status entry; restore M13-03G as the queue tail and move `nextTask` back to `M13-04A`.

41
docs/status/M13-04B.md Normal file
View File

@@ -0,0 +1,41 @@
# M13-04B Status
status: done
task: server source read-only and output isolation
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Each allocated server job now gets a `source/` directory and a separate `output/` directory. The
source directory is `0555` and the staged `.blend` is `0444`; a source overwrite fails with
`EACCES`. The output directory is `0700` and accepts result bytes. Cleanup temporarily restores
the source directory permission so the one-shot job directory can be removed without residue.
This task does not claim OS/container CPU, memory or process limits.
## Evidence
- `node --test web/tests/unit/server-job-isolation.test.mjs` passed 3/3.
- `npm --prefix web run test:server-job-workspace` passed unit 3/3 and the independent checker.
- `node tools/web/check-server-job-workspace.mjs` passed:
`server-job-workspace-ok sourceDir=0555 sourceFile=0444 sourceWrite=EACCES outputDir=0700 outputWrite=OK distinct=1 residual=0 next=M13-04C`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `3aa5678a2c2769e4db5bb8f5c755b97e23045c4106e5636459748ab9b41929cd`
- checker: `9490c2eeb9980073fc1fe77fdba1fb6e4ef528de8eb666d9eaf1fb582ba658c2`
- unit: `b1ac3324332180f7b3522f135520e7b5dace334dc461c92f2bce48fbcba2e147`
- package: `3df02b6049ac5d7185c23aef7764933ee460fedeb6595b3861272b0d49da5ecd`
- report: `650a643cc92617d068cb96d8bd4303429ef169ea89e3d4cb63e3ce5e2428e6d2`
- manifest: `9bc906b9e4c9751229f03271ef45a5925122b89b15bfe775591775f121ce1a4c`
## Next Task
`M13-04C`: enforce CPU, memory, process, file, wall-time and output budgets at the server boundary.
## Rollback
Remove the workspace protocol additions, focused tests/checker, report, manifest, package command and
this status entry; restore M13-04A as the queue tail and move `nextTask` back to `M13-04B`.

43
docs/status/M13-04C.md Normal file
View File

@@ -0,0 +1,43 @@
# M13-04C Status
status: done
task: server job resource budget gate
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Server jobs now have fixed CPU, memory, process, file, wall-time and output-byte limits. Budget
parsing rejects undeclared fields and out-of-range values. A usage receipt is marked
`enforced=true` only when every measured value is within its corresponding limit; each of the six
over-limit cases returns `SERVER_JOB_BUDGET_EXCEEDED` and remains `execution=DISABLED`.
This is the resource contract and usage gate. OS/container enforcement is proven by the later real
process task and is not claimed here.
## Evidence
- `node --test web/tests/unit/server-job-resource-budget.test.mjs` passed 2/2.
- `npm --prefix web run test:server-job-resource-budget` passed unit 2/2 and the independent checker.
- `node tools/web/check-server-job-resource-budget.mjs` passed:
`server-job-budget-ok cpu=bounded memory=bounded process=bounded files=bounded wall=bounded output=bounded overages=6 execution=DISABLED next=M13-04D`.
- `npm --prefix web run typecheck`, `npm --prefix web run lint` and `git diff --check` passed.
## Artifact Hashes
- protocol: `9746f0aef9dd76411320792dee1213c03755a3c03a87bbc4cbf88d4324c728d6`
- checker: `5599f4e25fc3ceca18e04be322450a4dc5bb6ce9c72c3abe9f1afc9c81851ff8`
- unit: `05212b2aa639f4c37e37e1cac0597d9b367a1280e519240f073762394914dc63`
- package: `3df02b6049ac5d7185c23aef7764933ee460fedeb6595b3861272b0d49da5ecd`
- report: `76ba684966bf7e680b0ebfc630ae9e080f04dd6daa6dd744bbb22dcff43f8eb1`
- manifest: `d00fff709b57909ec418ff0e476dca97281fc39456f674c63b51248377fc6ab2`
## Next Task
`M13-04D`: default-deny network policy with explicit declared-origin admission.
## Rollback
Remove the resource budget protocol, focused tests/checker, report, manifest, package command and
this status entry; restore M13-04B as the queue tail and move `nextTask` back to `M13-04C`.

24
docs/status/M13-04D.md Normal file
View File

@@ -0,0 +1,24 @@
# M13-04D Status
status: done
task: server job network policy
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
Server jobs default to `DENY`. Only an explicitly declared canonical HTTPS or loopback origin is
`ALLOWED`; missing, undeclared, credential-bearing, path-bearing, public HTTP and invalid origins
return `SERVER_NETWORK_DENIED` or `SERVER_NETWORK_POLICY_INVALID`. Execution remains `DISABLED`.
Evidence: `node --test web/tests/unit/server-job-network-policy.test.mjs` 2/2;
`npm --prefix web run test:server-job-network-policy` passed; checker output
`server-job-network-ok default=DENY declaredOrigin=ALLOWED missing=SERVER_NETWORK_DENIED undeclared=SERVER_NETWORK_DENIED execution=DISABLED next=M13-04E`;
typecheck, lint and `git diff --check` passed.
Artifact hashes: protocol `0dc3698383fbfa511bebfeca41504c7c04a8302d47168cfae94f01f2a11a316c`,
checker `6f3e9cd9f988313863345f392036e6dbb522102c969197034800f419e497ad92`, unit
`c0ba10ccd2fb6ec8878a1b4a54bc6a12e49d35818566e0d55ef307779e8c8b77`, report
`37bcba2666e8c76c2e07d23e285737004affbb0372ec6dd84bb6802dba551527`, manifest
`11ce246597e3321b346ed4fed00edba22708d97250163d332d7ba8a003d8849a`.
Next task: `M13-04E`, fixed Blender background/factory-startup runtime identity.

22
docs/status/M13-04E.md Normal file
View File

@@ -0,0 +1,22 @@
# M13-04E Status
status: done
task: pinned Blender server startup
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
Pinned Blender 5.2.0 LTS now passes a real server preflight using only `--background`,
`--factory-startup`, the fixed `tools/web/server-job-startup.py`, and a fixed business argument.
The structured receipt confirms background mode, runtime version and argv. Execution remains
`DISABLED`; this task does not claim result publication.
Evidence: `node tools/web/check-server-job-startup.mjs` output
`server-job-startup-ok blender=5.2 background=1 factory=1 userPrefs=0 fixedScript=1 execution=DISABLED next=M13-04F`;
typecheck, lint and `git diff --check` passed. Artifact hashes: startup
`c8c5b5a7a7880d4df9477a94a98e54e328baf582ade649807067f988484e1f12`, checker
`66b2e25efe0e7455348e8f488cd0f6ebef07f916fcf6541680e7d18e4f69ab10`, report
`c67d2972e584782d03479dbdb36dae0976074978f4ce9a48e41e7ad5aea66089`, manifest
`a24ea87bcf305bc15d8ae70b2abd03aa16ffbd6b127d5e9da9da23617d7201cc`.
Next task: `M13-04F`, bounded and redacted stdout/stderr.

40
docs/status/M13-04F.md Normal file
View File

@@ -0,0 +1,40 @@
# M13-04F Status
status: done
task: bounded and redacted server stdout/stderr
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Server job output is normalized through a production receipt before publication. Credentials, bearer/basic
tokens, secret headers and Unix/Windows/file URL paths are replaced; UTF-8 output is truncated at fixed
stdout/stderr byte budgets with an explicit marker. The receipt records original/emitted bytes, redaction
count and truncation state. Server execution remains `DISABLED`; process cancellation and result publication
are separate tasks.
## Evidence
- `npm --prefix web run test:server-job-output-redaction` passed 3/3 unit tests and the independent checker.
- Checker output: `server-job-output-ok stdoutTruncated=1 stderrTruncated=1 redactions=6 totalBounded=1 execution=DISABLED next=M13-04G`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `a24ea87bcf305bc15d8ae70b2abd03aa16ffbd6b127d5e9da9da23617d7201cc`
- protocol: `5a58e7080324b399905c6a20a313225153ba94c75a55d21c4bbdd957ae4a2462`
- checker: `5c2db9d3313484bb68ac65822828467b3f99cb03e8374935757cfcb4b4ed908d`
- unit: `4ae6266bce22f84e73113b93a590a0c32d9452e748003af251a602024d0c6db5`
- package: `52781eb2650133b43271889a22ce38023e611641da15411d31698c6cfc0ce19c`
- report: `cb6e3ed8d6cc0a69b333b6bff3199593bdfbae14fa7fa700dcb12e9e9cea519a`
- manifest: `b5b4b26183dc48ebcae009e49999010d9b60d512f5daa4674a0aff0577d6602c`
## Next Task
`M13-04G`: cancel Blender process tree and clean the one-shot directory.
## Rollback
Remove the output receipt protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04E` as the queue tail.

38
docs/status/M13-04G.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04G Status
status: done
task: server process-tree cancellation
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Real server jobs now run in a detached process group on POSIX and are cancelled as a tree. The cancellation
path sends SIGTERM to the group, escalates to SIGKILL after the grace window, waits for the group to exit,
and performs one idempotent job-directory cleanup. Windows uses `taskkill /T /F`. The receipt reports the
actual signal path, cleanup count and orphan count. Execution remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-cancellation` passed 2/2 real-process unit tests and the checker.
- Checker output: `server-job-cancel-ok state=CANCELLED tree=SIGTERM_GROUP cleanup=1 orphan=0 residual=0 execution=DISABLED next=M13-04H`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `b5b4b26183dc48ebcae009e49999010d9b60d512f5daa4674a0aff0577d6602c`
- protocol: `74fbbac806f34904bc9cb8e40eaf386cb60d44d978973950f1809262d311ec95`
- checker: `751ecafc642595d0de69b618e223cbff49d414f2958fc371371e4a668d66a8cc`
- unit: `39ac445ff51a9bfe249363204cf2edca906b16bf67ab1f8321166b440eba8629`
- package: `ca092a9a1d48ac41dc20f978bb26c8268adde9f7602a06459c7df8c2cb2d4cc7`
- report: `61f5c3ad315f94bac48e58627fcc46015c173dd9f303d5914acb8dbbe93caa97`
## Next Task
`M13-04H`: map timeout/OOM/non-zero exit/signal to stable error codes.
## Rollback
Remove the process control protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04F` as the queue tail.

38
docs/status/M13-04H.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04H Status
status: done
task: stable server process fault codes
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Timeout, bounded-memory OOM, signal termination and non-zero exit are converted to stable server error
codes. Classification precedence is cancellation, timeout, OOM, signal, then non-zero exit. Failed receipts
keep the base/current revision equal, set `publish=false`, and expose no internal process details. Execution
remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-fault-codes` passed 3/3 unit tests and the checker.
- Checker output: `server-job-faults-ok timeout=SERVER_JOB_TIMEOUT oom=SERVER_JOB_OOM signal=SERVER_JOB_SIGNAL exit=SERVER_JOB_EXIT_FAILED revisionPreserved=1 publish=0 execution=DISABLED next=M13-04I`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `7103a25ec7eb4a1c7f0d9f7acfb5ed30da32c87d512d6f9d53e081db275f7b89`
- protocol: `858360b4468a7b6cf796fc83a1627ba18626b61a0799f83531de996ea374519b`
- checker: `cb67246ef3df111525ca5e14af0546154ea2beee930b9840ad4ac7e2ebbb91ec`
- unit: `3551e28d78e5069c3d97eabcacac824bf142f54fdcb3ad4904668909af1cc545`
- package: `77bae66fd3885e36d2ead6f261754724144e5f51fafc5ccad9863dfc8e5ab548`
- report: `01999232f926496909fc9ef072e19aadb688822d3f9d7e03b42871ac5d54a0f6`
## Next Task
`M13-04I`: verify source/settings/build/output hashes before OPFS commit.
## Rollback
Remove the fault classifier, unit/checker, report, manifest, package command and this status entry; restore
`M13-04G` as the queue tail.

38
docs/status/M13-04I.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04I Status
status: done
task: server result hash binding and atomic OPFS handoff
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Server output publication requires request identity plus source, settings and Blender build SHA-256 values
to match the expected request. Output bytes are staged, read back, atomically renamed to the request result
path, and read back again before a committed receipt is returned. Tampered output, identity drift, partial
stage and quota failures remain unpublished. Execution remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-result-binding` passed 2/2 unit tests and the checker.
- Checker output: `server-job-result-ok source=bound settings=bound build=bound output=verified tamper=blocked quota=blocked atomic=1 execution=DISABLED next=M13-04J`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `ba530ddff6e6fdd84057444ce757fad05a30d825a5915abebe2d5910a689af7f`
- protocol: `ecf3bddef53e2766dcc055ec027b04c14e3d884132c7fdea476663617364ad86`
- checker: `b0fbffd2937ab20e72d337bb5ff63ccf188ccf8a939d8ccc8b4878d80c9a4a19`
- unit: `c5538798aa6263b8a1c20270a019f8b4fb8b176b141a6411b72aad21a457bfd0`
- package: `5d269d4e5ff4385d919c0ee33f996dcb814e3e415da25dbf3b4dbdc3312fbe24`
- report: `ec63faeba35a641a22c3b3a69757bd37e8e9acaa1dda11a64faf7bed80439784`
## Next Task
`M13-04J`: idempotent request retry and conflicting-result isolation.
## Rollback
Remove the result-binding protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04H` as the queue tail.

38
docs/status/M13-04J.md Normal file
View File

@@ -0,0 +1,38 @@
# M13-04J Status
status: done
task: server request idempotency and conflict isolation
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
`projectId/requestId` is now an idempotency key. An exact retry verifies and reuses the existing result;
different output or source/settings/build identity returns a stable conflict and cannot overwrite the bound
result. Different requests use separate result and receipt files. Concurrent duplicate requests share one
in-flight submission and resolve as one commit plus one reuse. Execution remains `DISABLED`.
## Evidence
- `npm --prefix web run test:server-job-idempotency` passed 3/3 unit tests and the checker.
- Checker output: `server-job-idempotency-ok first=COMMITTED retry=REUSED conflict=BLOCKED isolated=1 concurrent=REUSED execution=DISABLED next=M13-05A`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `f9658954d3dbd0cd1edd696c10f6a1b880bb3288c91a39a47ca84c4496046a97`
- protocol: `15eca7550964c9985e26a22a7900d3f3aa69fdef35fe5962b48a8f55ebba5863`
- checker: `02247ffda07c095373642a7fa22268bb9f5ac181d41571f7fff685812976d3c4`
- unit: `6ee08e67cd8493e856f67309bd6562316eca42ef52dd4a9aad3a15efdc4b6b41`
- package: `5b47e94cf828fc9d3021019eed9922eb67815aba5416266d8c967c7cb5bd96ba`
- report: `31f95a8cc1c4792303986b8b5987ab02fc11a77ab25fd76b31c02d1ed1b104d1`
## Next Task
`M13-05A`: CSP denies inline script, eval, data script and undeclared origins.
## Rollback
Remove the idempotency protocol, unit/checker, report, manifest, package command and this status entry;
restore `M13-04I` as the queue tail.

45
docs/status/M13-05A.md Normal file
View File

@@ -0,0 +1,45 @@
# M13-05A Status
status: done
task: CSP default-deny policy
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The deployment contract now requires one CSP on every response: same-origin default/script/worker/connect
sources, no inline or eval execution, no data/blob script source, and object/base/frame embedding denied.
The Vite source, entry HTML, production source tree and built JS/HTML are scanned for dynamic code and data
scripts. The deployment HTTP checker verifies the policy on normal, missing and entry responses. Resource-
specific Worker/WASM/font/image/media rules remain in M13-05B.
## Evidence
- `npm --prefix web run test:csp-policy` passed.
- `node tools/web/check-deployment-contract.mjs` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed; built output was scanned by the CSP checker.
- Checker output: `csp-policy-ok inline=DENY eval=DENY dataScript=DENY undeclaredConnect=DENY responses=3 execution=DISABLED next=M13-05B`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `d230ae49dbf38cd9e95e7379a1a49332e478d3d23b3638730d2ec6167204c368`
- contract: `3f2b0b10c5a5698be2adda61af80cfb9cb9291fb9797994bfa66a77b7b511eeb`
- deployment server: `a5734ce9760f65cf5bade8cc209454d39fa963ad7dfaf20653728a9d7a57b04c`
- contract checker: `5e2d80f5c1377420f4779291fa73c206741ed415e751e79ce5edae7ba039febf`
- CSP checker: `f97ab074da860e3f8489e520c8bb5932f858409136ef25cca56247bb1310340d`
- index: `16b7691b191127f84c5143e23aecdfc203dc9e279d34cb270b37631fcbd5f856`
- Vite: `fd160c685ed780738e2b37ce9a32e5d4718e11a2875e12d86ddad310213abaf3`
- package: `5b47e94cf828fc9d3021019eed9922eb67815aba5416266d8c967c7cb5bd96ba`
- report: `9c7c64bb021161a1165a7c089ccf3f4897877635914260f6f0b0da119a5036fb`
## Next Task
`M13-05B`: verify resource-specific CSP for Worker, WASM, font, image and media paths.
## Rollback
Remove the CSP contract/checker changes, report, manifest, package command and this status entry; restore
`M13-04J` as the queue tail.

31
docs/status/M13-05B.md Normal file
View File

@@ -0,0 +1,31 @@
# M13-05B Status
status: done
task: resource-specific CSP policy
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The deployment contract now separates same-origin policy for Worker, WASM, font, image and media
resources. Chromium loaded same-origin Worker, WASM, image and media resources, and rejected data-image,
blob-Worker and cross-origin connect attempts. WASM uses only the explicit `wasm-unsafe-eval` source
expression; JavaScript `eval` remains denied. Resource responses and 404 responses carry the same policy.
## Evidence
- `npm --prefix web run test:csp-resource-policy` passed the HTTP resource matrix and Chromium browser gate.
- `node tools/web/check-deployment-contract.mjs` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed.
- `git diff --check` passed.
## Next Task
`M13-05C`: production/build/test dependency inventories.
## Rollback
Remove the resource-specific CSP/MIME changes, checker, report, manifest, package command and this status;
restore `M13-05A` as the queue tail.

27
docs/status/M13-05C.md Normal file
View File

@@ -0,0 +1,27 @@
# M13-05C Status
status: done
task: production/build/test dependency inventories
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Evidence
`web/package.json` and `web/package-lock.json` are parsed as the only dependency sources. Deterministic
transitive closures contain production=3, build=135 and test=6 packages; every package is classified and
records its path, version, resolved URL and lockfile integrity. A fresh regeneration is byte-identical.
- `npm --prefix web run test:dependency-inventory` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed.
- `git diff --check` passed.
## Next Task
`M13-05D`: severity gates and documented dependency exceptions.
## Rollback
Remove the inventory generator/checker, report, manifest, package command and this status; restore
`M13-05B` as the queue tail.

18
docs/status/M13-05D.md Normal file
View File

@@ -0,0 +1,18 @@
# M13-05D Status
status: done
task: dependency severity gates and exceptions
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
The severity policy is machine-readable: BLOCKER/HIGH block, MEDIUM requires review and LOW is tracked.
Exceptions require a non-empty owner, non-expired ISO date, reason and alternative control. Production
inventory has zero findings and zero exceptions, while four negative/positive exception cases are checked.
- `npm --prefix web run test:dependency-severity-policy` passed.
- `npm --prefix web run typecheck` passed.
- `npm --prefix web run build` passed.
- `git diff --check` passed.
Next task: `M13-05E`, SBOM/license/source-offer binding.

13
docs/status/M13-05E.md Normal file
View File

@@ -0,0 +1,13 @@
# M13-05E Status
status: done
task: SBOM/license/source-offer and archive binding
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
The supply-chain checker binds SPDX 2.3 to the lockfile and notices hashes, verifies the corresponding
source offer and source archive contents, checks top-level archive SHA256SUMS, and records the current
commit. Binary/source archive validators also pass independently; script execution remains disabled.
Next task: `M13-05F`, malicious input matrix.

14
docs/status/M13-05F.md Normal file
View File

@@ -0,0 +1,14 @@
# M13-05F Status
status: done
task: malicious input matrix
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
The production blend loader rejected five malformed blend cases. Existing production protocol tests
rejected malformed image previews, fonts, media cache manifests, shader node graphs, script manifests and
GLB inputs; archive metadata rejected six ZIP/TAR traversal, link, duplicate and bomb cases without
extraction. All matrix categories are stable reject paths and execution remains disabled.
Next task: `M13-05G`, fuzz crash minimization and regression capture.

37
docs/status/M13-05G.md Normal file
View File

@@ -0,0 +1,37 @@
# M13-05G Status
status: done
task: fuzz crash minimization and regression capture
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The deterministic runner replays 16 mutations in each of the blend, image, font, node-graph and script
manifest domains using seed `1511506142`. Every case returns one structured `ACCEPTED` or `REJECTED`
receipt; a non-zero runner exit first writes a replayable corpus sample. This run completed 80 cases with
zero crashes and an empty minimized corpus. Script execution remains disabled.
## Evidence
- `npm --prefix web run test:fuzz-regression` passed.
- Checker output: `fuzz-regression-ok seed=1511506142 cases=80 crashes=0 corpus=0 execution=DISABLED next=M13-05H`.
- `git diff --check` passed.
## Artifact Hashes
- parent manifest: `34043df0515f4b422a2b265d38978dd3c7f21acd12753c99f9a50f9b23f8bd60`
- runner: `a4d5d1b743b454705b1c3a257f1f36d1fea8abd77442e11fb1fec9e2905a3f79`
- checker: `55c8fa3776b22eb3f2e2ffd1629f0092384df30ef3913699a1ba93b283d641d8`
- package: `1feb509789d7f06019390bd86197bb9851cd520fd9fe310d1e29bfc3d2ef3f18`
- report: `5eb4a5469732697be7910fded3ce34cf2898735f767d94c1abbe0dd264bcc0d9`
## Next Task
`M13-05H`: fuzz corpus replay and release-boundary exclusion.
## Rollback
Remove the fuzz runner/checker, report, manifest, package command and this status entry; restore
`M13-05F` as the queue tail.

30
docs/status/M13-05H.md Normal file
View File

@@ -0,0 +1,30 @@
# M13-05H Status
status: done
task: script audit record integrity
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production scripting audit protocol now has an independent integrity gate. Two default-deny audit
records are validated with strictly increasing ISO timestamps, contiguous sequence numbers, unique request
IDs, canonical entry digests and a continuous previous-entry hash chain. Replay, time reversal, sequence
mutation, entry digest mutation and chain mutation all return `SCRIPT_MANIFEST_INVALID`; execution remains
disabled.
## Evidence
- `npm --prefix web run test:script-audit-integrity` passed 2 unit tests and the checker.
- Checker output: `script-audit-integrity-ok entries=2 sequence=1,2 requestIds=unique time=ordered chain=true replay=SCRIPT_MANIFEST_INVALID tamper=3 execution=DISABLED next=M14-01A`.
- `git diff --check` passed.
## Next Task
`M14-01A`: freeze the current Chromium release, engine and archive hashes.
## Rollback
Remove the audit integrity checker/unit, report, manifest, package command and this status entry; restore
`M13-05G` as the queue tail.

32
docs/status/M14-01A.md Normal file
View File

@@ -0,0 +1,32 @@
# M14-01A Status
status: done
task: Chromium, engine and archive identity freeze
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The Chromium baseline is frozen at `150.0.7871.128`. The checker resolves and hashes the actual browser
executable, validates every single/pthread engine resource against `engine-manifest.json`, and validates
both release archives against the regenerated `RC_MANIFEST.json` and `SHA256SUMS.txt`. Execution remains
disabled.
## Evidence
- `npm --prefix web run release:offline` passed deterministic binary/source rebuild twice.
- `node tools/web/create-rc-manifest.mjs && node tools/web/check-rc-manifest.mjs` passed.
- `npm --prefix web run test:chromium-freeze` passed with browser `150.0.7871.128`, two engine variants,
and two archive bindings.
- `npm --prefix web run typecheck` passed; execution remains `DISABLED`.
- `git diff --check` passed.
## Next Task
`M14-01B`: Firefox capability probe using the frozen field set.
## Rollback
Remove the Chromium freeze checker, report, manifest, package command and this status entry; restore
`M13-05H` as the queue tail.

21
docs/status/M14-01B.md Normal file
View File

@@ -0,0 +1,21 @@
# M14-01B Status
status: done
task: Firefox capability probe
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
Firefox `153.0` was probed against the rebuilt production assets with COOP/COEP isolation. WASM, Worker,
OPFS, IndexedDB, WebGL2, OffscreenCanvas and cross-origin isolation passed. WebGPU is explicitly
`BLOCKED/WEBGPU_UNAVAILABLE`; it does not change the Chromium-only release claim.
## Evidence
- `npm --prefix web run test:firefox-capability` passed.
- Checker output: `firefox-capability-ok version=153.0 wasm=PASS,worker=PASS,opfs=PASS,indexedDB=PASS,webgl2=PASS,webgpu=BLOCKED,offscreen=PASS,isolation=PASS execution=DISABLED next=M14-01C`.
- `git diff --check` passed.
## Next Task
`M14-01C`: WebKit capability probe with the same fields.

21
docs/status/M14-01C.md Normal file
View File

@@ -0,0 +1,21 @@
# M14-01C Status
status: done
task: WebKit capability probe
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
WebKit `26.5` was probed against the rebuilt production assets with COOP/COEP isolation. WASM, Worker,
IndexedDB, WebGL2, OffscreenCanvas and isolation passed. OPFS and WebGPU are explicitly blocked; the
result does not change the Chromium-only release claim.
## Evidence
- `npm --prefix web run test:webkit-capability` passed.
- Checker output: `webkit-capability-ok version=26.5 wasm=PASS,worker=PASS,opfs=BLOCKED,indexedDB=PASS,webgl2=PASS,webgpu=BLOCKED,offscreen=PASS,isolation=PASS execution=DISABLED next=M14-01D`.
- `git diff --check` passed.
## Next Task
`M14-01D`: probe identity and GPU/OS adapter recording.

33
docs/status/M14-01D.md Normal file
View File

@@ -0,0 +1,33 @@
# M14-01D Status
status: done
task: probe identity and GPU/OS adapter recording
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The production Chromium probe records observed browser identity, OS kernel/runtime identity,
hardware concurrency, WebGL2 vendor/renderer/version, WebGPU adapter identity, and cross-origin
isolation. WebGPU is recorded as `BLOCKED/WEBGPU_ADAPTER_UNAVAILABLE` in this headless environment;
the result does not claim WebGPU support. The report is bound to the exact worker/WASM asset hashes
used by the probe and carries a canonical identity SHA-256.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:probe-identity` passed twice (one report-generation run and one frozen
report verification run).
- Checker output: `probe-identity-ok version=151.0.7922.34 os=linux/x64 webgl2=PASS,webgpu=BLOCKED identity=3c6f898e1b6ffd39862505b8e7dde8fd29369204e1670a013859f74ccaf1c1eb execution=DISABLED next=M14-01E`.
- `git diff --check` passed.
## Next Task
`M14-01E`: Chromium WebGPU fail-closed boundary. Firefox and WebKit are excluded by the project
Chromium-only iron rule.
## Rollback
Remove the probe checker, report, manifest, package command and this status/task entry; keep
`M14-01C` as the queue tail.

29
docs/status/M14-01E.md Normal file
View File

@@ -0,0 +1,29 @@
# M14-01E Status
status: done
task: Chromium WebGPU fail-closed boundary
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Chromium routing was checked against the production render protocol. A bounded Eevee request using
WebGPU returns `BLOCKED/WEBGPU_RENDERER_UNAVAILABLE` when no bundled adapter is available, while the
same bounded request using WebGL2 remains `READY/WEB_LOCAL_BOUNDED`. This task does not launch Firefox
or WebKit.
## Evidence
- `npm --prefix web run test:chromium-webgpu-boundary` passed.
- Checker output: `chromium-webgpu-boundary-ok webgpu=BLOCKED/WEBGPU_RENDERER_UNAVAILABLE webgl2=READY execution=DISABLED next=M14-04A`.
- `git diff --check` passed.
## Next Task
`M14-04A`: Chromium GPU/memory budget device tier selection.
## Rollback
Remove the Chromium boundary checker, report, manifest, package command and this status/task entry;
restore `M14-01D` as the queue tail.

25
docs/status/M14-04A.md Normal file
View File

@@ -0,0 +1,25 @@
# M14-04A Status
status: done
task: Chromium GPU/memory budget device tier selection
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Added a bounded device-budget selector driven only by the real Chromium M14-01D identity report.
The observed SwiftShader renderer and unavailable WebGPU adapter select `CONSERVATIVE`; untrusted,
missing, or fallback adapters cannot expand budgets. Fixed `CONSERVATIVE`, `BALANCED`, and `HIGH`
limits are explicit and unknown tiers fail closed. Firefox/WebKit are excluded by the iron rule.
## Evidence
- `npm --prefix web run test:chromium-device-budget` passed: 3 unit tests plus the production identity
report checker.
- Checker output: `chromium-device-budget-ok tier=CONSERVATIVE reason=UNTRUSTED_ADAPTER identity=3c6f898e1b6ffd39862505b8e7dde8fd29369204e1670a013859f74ccaf1c1eb execution=DISABLED next=M14-04B`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04B`: Chromium DPR 1/1.5/2/3 canvas and raycast consistency.

26
docs/status/M14-04B.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04B Status
status: done
task: Chromium DPR 1/1.5/2/3 canvas and raycast consistency
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Shared viewport DPR and CSS-bounds NDC helpers now drive the main-thread and Offscreen viewport
boundaries. Chromium production verification ran at device scale factors 1, 1.5, 2 and 3; the
declared renderer cap of 2 was applied, backing dimensions matched the browser canvas, CSS dimensions
remained `679x321`, and the same center raycast selected the same object at every scale.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-dpr-consistency` passed: 2 protocol tests and 4 real Chromium
production contexts.
- Checker output: `chromium-dpr-ok dpr=1,1.5,2,3 css=679x321 selection=stable execution=DISABLED next=M14-04C`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04C`: Chromium mouse/touch/pen pointer identity and cancellation contract.

26
docs/status/M14-04C.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04C Status
status: done
task: Chromium mouse/touch/pen pointer identity and cancellation contract
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
The main-thread and Offscreen viewport paths now record a shared pointer observation for mouse,
touch, and pen input. Pointer identity, pressure, tilt, button/buttons and `pointercancel` are
preserved with bounded values; unknown pointer types and invalid IDs fail closed. Chromium production
events verified down/cancel pairs for all three pointer types. Firefox/WebKit are excluded.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-pointer-contract` passed: 2 protocol tests and real Chromium
mouse/touch/pen down/cancel events.
- Checker output: `chromium-pointer-ok types=mouse,touch,pen cancel=PASS execution=DISABLED next=M14-04D`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04D`: Chromium IME composition guard for incomplete operators.

26
docs/status/M14-04D.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04D Status
status: done
task: Chromium IME composition guard for incomplete operators
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Added an explicit IME composition state machine and connected it to the App global shortcut gate.
Composition start/update records pending text and blocks operator shortcuts; composition end clears
the block without dispatching an incomplete operator. A real Chromium page dispatched composition
events and `G`; UI revision remained unchanged during composition. Firefox/WebKit are excluded.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-ime-guard` passed: 2 protocol tests and real Chromium
compositionstart/update/keydown/compositionend events.
- Checker output: `chromium-ime-ok composing=BLOCKED_OPERATOR shortcut=G revision=0 execution=DISABLED next=M14-04E`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04E`: Chromium US/non-US/dead-key/modifier keymap fixture.

26
docs/status/M14-04E.md Normal file
View File

@@ -0,0 +1,26 @@
# M14-04E Status
status: done
task: Chromium US/non-US/dead-key/modifier keymap fixture
updated: 2026-08-19 America/New_York
enablingTask: false
parityStateChange: false
## Scope
Added a versioned keyboard observation contract preserving layout character (`key`), physical key
(`code`), location, repeat, composition state, dead-key identity and modifier flags. Chromium
production events verified US, non-US character, dead-key and modifier fixtures. Firefox/WebKit are
excluded.
## Evidence
- `npm --prefix web run build` passed.
- `npm --prefix web run test:chromium-keymap-fixture` passed: 2 protocol tests and 4 real Chromium
keyboard fixtures.
- Checker output: `chromium-keymap-ok fixtures=US,NON_US,DEAD_KEY,MODIFIER observations=4 execution=DISABLED next=M14-04F`.
- `npm --prefix web run typecheck` and `git diff --check` passed.
## Next Task
`M14-04F`: Chromium touch modal cancel, two-finger navigation and single pen Main commit.

View File

@@ -1,7 +1,8 @@
# N-023 Asset、Library 与 IO
状态:`BLOCKED`asset catalog、来源/许可证元数据、真实 Main library inventory、库依赖与
IO 安全门已落地;Append/Link/Override Main、非 GLB 本地导入和跨桌面重导入未实现)
IO 安全门已落地;bounded Append Main 及其 canonical persistence 已完成Link/Override Main、
非 GLB 本地导入和跨桌面重导入仍未实现)
## 完整对标盘点基线
@@ -91,8 +92,35 @@ M12-03D 已把同一 source-hash-bound closure 送入 WASM Worker 的 authoritat
link/append context 递归导入 Object、Mesh、Material 和 packed ImageMain commit 前核对 source
locator、root、closure 与 base revision四个 ID 均无 `ID.lib`/override、映射为可写 `LOCAL_MAIN`
并只产生一个新的 SceneIR revision。stale revision 与 local ID collision 在 Main mutation 前阻断,
失败路径回滚完整 history state。该项只证明单 transaction Main appendundo/redo/save/reopen 与
desktop canonical report 的联合一致性仍由 M12-03E 验证。
失败路径回滚完整 history state。
M12-03E 已在同一 Chromium/WASM Main 路径完成联合持久化门append 只推进一个 revisionundo
移除 Object/Mesh/Material/Image 四个 closure IDredo 恢复同一 canonical graphsave/reopen 后
再次读取的依赖边、geometry、UV、material slot 和 packed image Float32 pixel hash 与 M12-03C
desktop report 精确一致。图像比较只对 Blender bottom-up `Image.pixels` 与 Canvas top-down row
做规范化;当前 SceneIR 缺省的 `Image.colorSpace` 使用 desktop sRGB semantic default若字段出现
则必须匹配,不放宽其它字段。该证据仍不覆盖 Link/Override 或完整 N-023 IO parity。
M12-03F 已用独立 Blender 5.2 desktop fixture 冻结 LINK 语义。只链接一个 Object rootMesh、
Material 和 packed Image 依赖随 source library 保留;四个 ID 的 `library` 均为
`m12_link_source.blend``isLibraryOverride=false`,并映射为 `SOURCE_LIBRARY/readOnly=true`
target 保存并重开后 stable mapping、依赖边、geometry/UV/material slot 和 packed image Float32
pixel hash 不变。该 enabling evidence 仍不开放 linked writer 或声明完整 Link parity。
M12-03G 已为 linked Object/Mesh/Material/Image writer 建立统一 fail-closed gate。object transform、
mesh geometry/material slot、material property/image node 和 packed image data 六类操作在
`SOURCE_LIBRARY/readOnly=true` context 下全部返回 `LINKED_DATA_MUTATION_BLOCKED`,且
`recoverable=false`stale revision 先返回 `REVISION_CONFLICT`未知字段、operation 和 owner
substitution 也在 Main 前阻断。M12-03H 又将 reload 限定为匹配 source library generation/revision 的
单一 linked snapshot 替换stale、跳代、重复 identity 和 source substitution 均不发布新状态。该项仍不
实现 relocate、override 或 LINK Main transactionM12-03I 的 missing-library placeholder 仍是有界
reference-preservation 证据,不是完整资源恢复。
M12-04A-J 又冻结 declared source-origin admission、canonical project path、path/origin safety、
symlink/hardlink resolution、metadata-first read、entry/total/path/range/conflict budget 与 cancellation
rollback。取消、quota 和 OOM 的部分 staging 都会清零并保持 committed revision/SHA-256 不变,
同一 storage instance 可继续提交小 archive6 个恶意 ZIP/TAR fixture 又进入确定性长期回归。
该组有界证据仍不实现完整 archive decoder、fuzz 或 N-023 全域 parity。
## 已验证切片
@@ -101,8 +129,30 @@ desktop canonical report 的联合一致性仍由 M12-03E 验证。
缺许可证和哈希不匹配会拒绝。
2. N-023-A/B部分catalog 与 library dependency 图做确定性拓扑检查并返回 load order
content-addressed index 报告 `LOCAL_BOUNDED`OPFS 只在运行时 API 存在时报告 `PROBE_REQUIRED`
3. N-023-C现有 GLB 导出与 USD semantic analysis 可放行;GLTF/OBJ/PLY/STL、
USD/Alembic 实际导入保持 `IO_FORMAT_UNSUPPORTED`,库 mutation 需要真实 Main。
3. N-023-C现有 GLB 导出与 USD semantic analysis 可放行;M12-05A 已从 pinned Blender
5.2 runtime 生成 GLTF/GLB/OBJ/STL/PLY/USD/Alembic operator/build inventory但没有把清单
当作执行 receiptM12-05B 仅放行已有 bounded GLB local export其余 import/export local/server
route 均保持 `BLOCKED`M12-05C 又让 UI registry 只消费 matrix 声明且 runtime 可执行的 route
文件选择器仅接受 `.blend`operator search 隐藏 blocked/undeclared 组合M12-05D 再用
pinned Blender 5.2 runtime receipt 在执行前确认 operator registered/build option/RNA identity
M12-05E 又要求 source/settings/runtime 三重 hash 与 parent inventory identity且不从扩展名推断能力
M12-06A 已由同一 pinned runtime 生成五个独立 Mesh/PBR/UV/skin/animation GLB fixture并用
semantic report 与逐字节二次生成固定输入基线M12-06B 又由生产 Web parser 在 Node 与
Chromium Worker 对 topology/attributes/materials/nodes/animations 做 exact canonical 比较;
M12-06C-G 又完成 Main persistence、loss report、desktop re-import、negative budget 和双向取消/
Worker restart/真实 OPFS quota 恢复M12-07A 又冻结 pinned Blender OBJ 单 Mesh position/
normal/UV/material-group 输入M12-07B 又冻结 OBJ 双对象/负索引/相对纹理来源/坏 face 负例;
M12-07C 已完成 bounded Web-to-desktop OBJ round-trip 与 texture-origin loss report
UV/skin mismatch、GLB import UI route 和 OBJ Web route 仍保持阻断M12-07D 已冻结 Blender
STL binary/ASCII 两个独立 runtime variantM12-07E 又对标 normal/unit/degenerate/trailing
trailing 保持 stricter Web blockM12-07F 又完成 STL Web-to-desktop round-trip/material loss
reportSTL Web route 仍保持阻断M12-07G 又冻结 PLY ASCII 与 binary little-endian 两个
独立 desktop capability variantM12-07H 又完成 bounded PLY vertex/face/color/custom property
mapping 与 `PLY_UNKNOWN_PROPERTY` loss reportM12-07I 又让 big-endian、坏 list、超大 count
在 Worker 中稳定 fail-closedM12-07J 又完成 OBJ/STL/PLY cancellation/OOM/restart/small recovery
但 PLY Web route 仍保持阻断;
GLTF/OBJ/PLY/STL、USD/Alembic 实际导入仍保持 `IO_FORMAT_UNSUPPORTED`
库 mutation 需要真实 Main。
4. N-023-A/B部分预览字节先验 SHA-256 和 byte length再校验 PNG signature/尺寸;
WebP 仅在 RIFF/WEBP 容器签名正确时进入后续解码门,不从元数据伪造预览内容。
5. N-023-E项目路径、外部 URI、archive entry 数量/单项/总量、压缩展开比率均有边界。
@@ -110,9 +160,11 @@ desktop canonical report 的联合一致性仍由 M12-03E 验证。
packed/external 状态、只读标志和 archive-parent dependency1024 library/每库 1024 dependency、
重复 ID、缺依赖、依赖环与项目外路径由 SceneIR 再校验。缺外部库字节时返回
`LINKED_LIBRARY_RESOURCE_REQUIRED`,不从路径伪造 SHA-256 或声称已加载。
7. N-023-Earchive 结构门):除 traversal 与展开比预算外,重复规范路径、文件/目录前缀冲突、
累计压缩/解压字节和声明源长度不一致均拒绝;`planIOArchiveRanges` 按路径生成确定性、安全整数
compressed offset 计划。它为后续流式解包提供边界,不代表已有 ZIP decoder。
7. N-023-Earchive 结构门):symlink/hardlink 在写前解析到临时根ZIP central directory/TAR
manifest 必须先读entry/total/path、展开比、重叠 range、重复路径与文件/目录前缀冲突均拒绝。
取消会删除真实 staging、保持 committed identity 且发布数为零quota/OOM 部分写入也会清零,
并允许同一 storage instance 恢复小 archive。三类 ZIP 与三类 TAR 恶意二进制 fixture 确定性
重建、验证真实容器 metadata 后全部 fail-closed这些门不代表已有 ZIP/TAR decoder。
8. N-023-ENanoVDB range 基础件):`.nvdb` manifest 要求连续、32-byte 对齐、逐块 hash
HTTP source 只接受与 manifest 精确一致的 `206 Content-Range`,并按块校验后消费;临时错误重试、
稳定 ETag/If-Range、response-body 偏移续传、错位/短响应拒绝均已完成。OPFS 原子
@@ -125,11 +177,16 @@ desktop canonical report 的联合一致性仍由 M12-03E 验证。
## 仍然阻断
- N-023-BAppend undo/redo/save/reopen、Link/Library Override、reload/relocate 和完整真实 Main
parityM12-03D 的单 transaction append 已有独立证据,但不解除本项阻断。
- N-023-Blinked relocate、missing-library recovery、Library Override 和完整真实 Main parity
M12-03D/E 已证明 bounded Append 的单 transaction 与 desktop canonical persistenceM12-03F/G/H/I
已冻结 desktop LINK source-library/read-only contract、linked writer fail-closed 与
matching-generation reload、missing-reference preservation 和 desktop override ownership/property
fixture、单一 verified override writer、freshness gate、negative cases、三 lane command matrix 与
declared source-origin admission、canonical project-path normalization 与 path/origin security gate
但不解除本项阻断。
- N-023-C/DGLTF/OBJ/PLY/STL、USD/Alembic import/export/save/reopen/desktop reimport。
- N-023-E真实 zip decoder/fuzz、OPFS quota/recovery、license/source offer 发布审计和大文件
流式性能;archive 路径冲突、双向字节预算与确定性 range plan 已完成。
- N-023-E真实 ZIP/TAR decoder/fuzz、license/source offer 发布审计和大文件流式性能仍阻断;
archive link/metadata/budget/conflict/cancellation/quota/OOM 与恶意 fixture regression 已完成。
- N-023-EVDBGPU page resident LRU 已完成64 MiB1 GiB bundle 中断/内存性能门仍阻断。
## 验收
@@ -154,6 +211,13 @@ npm --prefix web run test:asset-preview-display
npm --prefix web run test:library-operation-inventory
npm --prefix web run test:library-operation-identity
npm --prefix web run test:library-main-append
npm --prefix web run test:library-link-safety
npm --prefix web run test:library-metadata-first
npm --prefix web run test:library-archive-budget
npm --prefix web run test:library-archive-conflicts
npm --prefix web run test:library-archive-cancellation
node --test web/tests/unit/library-archive-recovery.test.mjs
node tools/web/check-malicious-archive-fixtures.mjs
npm --prefix web run test:vdb
npm --prefix web run test:vdb-native
```

View File

@@ -25,13 +25,61 @@
8. N-025-E审计链至多 65,536 条拒绝审计按 sequence、前项 SHA-256 与 canonical
entry SHA-256 串联;读取时重新校验请求摘要和整条链,拒绝 requestId 重放、非递增 UTC
时间戳、内容篡改、断链与超预算日志。该链是内存/序列化协议,不声称已持久化发布审计。
9. M13-02A manifest gate每个 script 必须声明 `sourceByteLength``module=false`;解析器限制
脚本数量、总源码字节、依赖数量、权限数量与 allowlistcanonicalize 项目内 entry/dependency
path并拒绝重复依赖、模块执行、未知权限和所有预算溢出。Node unit 与生产 Chromium Worker
正负例、golden report 和 artifact manifest 已绑定。
10. M13-02B canonical signature input`canonicalizeScriptingManifest`
`serializeScriptingManifest` 是唯一规范入口locale-independent code-unit 排序所有可重排
数组,固定无空白 canonical JSONunknown fields 不进入签名输入order mutation、security
field mutation 和 schema drift 均由 Node/Chromium 与 golden report 验证。
11. M13-02C signer trust policy版本化 trust policy 绑定 ED25519 key/public-key、publisher、
active/revoked status、validity window、revocation timestamp、same-publisher rotation chain
和 bounded clock skewresolver 只返回 `ELIGIBLE/cryptographicVerification=REQUIRED`,不验签
不执行revoked/expired/mismatch/cycle/missing predecessor 全部 fail-closed。
12. M13-02D declaration-bound signature verificationcanonical per-script input 包含 source
SHA-256 和权限/预算/路径等声明,合法 ED25519 signature 才返回 `VERIFIED`source hash 或
signature 变化返回 `SCRIPT_SIGNATURE_INVALID`revoked signer 返回 `SCRIPT_POLICY_DENIED`
13. M13-02E permission minimization无显式请求时授予空集只有 manifest 已声明且请求的
permission 才能授予,未知、重复或未声明请求稳定返回 `SCRIPT_POLICY_DENIED`
14. M13-02F signature negative matrixmissing/expired/not-yet-valid key、publisher confusion
与跨脚本 signature swap 均稳定返回 `SCRIPT_POLICY_DENIED``SCRIPT_SIGNATURE_INVALID`
canonical ordering 不改变自身签名结果,且不开放执行入口。
15. M13-03A sandbox scope contractversioned scope 对 DOM、host Worker、OPFS、IndexedDB 和
network 五项能力逐项要求 `false`;启用、缺失或未知 schema 均 fail-closed执行仍禁用。
16. M13-03B sandbox budget contractCPU、wall-time、memory、message 和 output bytes 各有固定
上限;任一超限返回 `SCRIPT_BUDGET_EXCEEDED`,不创建或启用脚本执行器。
17. M13-03C host-call contract仅允许五个显式调用名每个调用使用结构化、调用专属参数
permission 必须来自 manifest 声明,未知字段、危险路径和未声明调用 fail-closed解析结果
保持 `execution=DISABLED`
18. M13-03D sandbox isolation真实 Chromium Worker crash/timeout 后 job receipt 分别返回
`SCRIPT_SANDBOX_CRASHED`/`SCRIPT_SANDBOX_TIMEOUT`Main revision 不变temporary/published
资源归零;终止后的迟到结果返回 `SCRIPT_SANDBOX_LATE_RESULT`,执行仍为 `DISABLED`
19. M13-03E cancellation gate取消 receipt 保持 Main revision 和 execution 状态,真实 Chromium
迟到窗口 `lateMessages=0``cacheWrites=0`,伪造迟到结果稳定返回 `SCRIPT_SANDBOX_LATE_RESULT`
20. M13-03F dispose gate真实 Chromium Worker 释放两端 `MessagePort`、timer、AbortController、
transferable buffer、pending request 和 cache reference首次和重复 dispose 均返回零资源,
且迟到 timer 消息为 0。
21. M13-03G same-session recoveryWorker generation 4->5 后 Main revision/source hash/manifest hash
保持不变;两条 default-deny audit entry 的 request ID、sequence 和 previous hash chain 连续,
replay/source tamper 均返回 `SCRIPT_MANIFEST_INVALID`
22. M13-04A server job directory gate每个 job 获得随机 `0700` one-shot directoryrequest ID 不
进入目录名;成功/失败清理后无残留且重复清理幂等。
23. M13-04B source/output isolationsource directory/file 为 `0555/0444`,真实写入返回 `EACCES`
output directory 为 `0700` 且可写,清理会先恢复 source directory 权限并无残留。
24. M13-04C server resource budgetCPU、memory、process、file、wall 和 output 六类限制有固定
上限;每类超限均返回 `SERVER_JOB_BUDGET_EXCEEDED`bounded receipt 标记 `enforced=true`
执行仍为 `DISABLED`
25. M13-04D server network policy默认 network `DENY`;显式声明的 HTTPS/loopback origin 才可
`ALLOWED`missing/undeclared/unsafe origin 均为 `SERVER_NETWORK_DENIED`
## 仍然阻断
- N-025-B/C签名验证密钥管理、无网络 CPython/native sandbox、server Blender job 和
output hash 提交。
- N-025-D/E真实 GPU/native window/file watcher 适配、恶意脚本/依赖混淆/逃逸/重放、
审计日志持久化和发布门;本地请求级审计凭证已完成,不代表隔离执行完成。
- N-025-D/E真实 server isolation、真实 GPU/native
window/file watcher 适配、恶意脚本/依赖混淆/逃逸/重放、审计日志持久化和发布门;本地
请求级审计凭证与 crash/timeout receipt 已完成,不代表隔离执行完成。
## 验收

Some files were not shown because too many files have changed in this diff Show More