From 61b27cdebe79f60cea0bd04b2f3188574118ae13 Mon Sep 17 00:00:00 2001 From: mes123456 Date: Thu, 3 Sep 2026 11:11:20 +0800 Subject: [PATCH] feat(web): batch modifier reader coverage --- docs/EXECUTION_QUEUE.md | 6 +- docs/status/WBV2-P1145-001.md | 2 +- docs/status/WBV2-P1146-000.md | 7 + docs/status/WBV2-P1146-001.md | 8 + docs/status/WBV2-P1147-000.md | 7 + docs/status/WBV2-P1147-001.md | 8 + docs/status/WBV2-P1148-000.md | 7 + docs/status/WBV2-P1148-001.md | 8 + docs/tasks/WBV2-P1146-000.md | 45 + docs/tasks/WBV2-P1146-001.md | 45 + docs/tasks/WBV2-P1147-000.md | 33 + docs/tasks/WBV2-P1147-001.md | 45 + docs/tasks/WBV2-P1148-000.md | 45 + docs/tasks/WBV2-P1148-001.md | 45 + my-tools/README.md | 4 + my-tools/authorize_next_wbv2_task.py | 274 +- my-tools/start_unattended.sh | 11 + nextTask.md | 10 +- .../web/modifier_reader_batch_scene.blend | Bin 0 -> 98591 bytes .../modifier_reader_batch_three_scene.blend | Bin 0 -> 98640 bytes .../web/modifier_reader_batch_two_scene.blend | Bin 0 -> 98565 bytes .../WBV2-P1145-001/continuous-commit.log | 5 + .../WBV2-P1145-001/continuous-gates.log | 12 + .../WBV2-P1145-001/continuous-runner.log | 3 + tests/golden/WBV2-P1145-001/manifest.json | 4 +- .../golden/WBV2-P1145-001/scheduler-child.log | 0 tests/golden/WBV2-P1146-000/manifest.json | 42 + .../WBV2-P1146-000/module-execution-plan.json | 5684 ++++++++++++++++ .../successor-authorization-report.json | 37 + .../WBV2-P1146-001/continuous-gates.log | 2 + .../WBV2-P1146-001/continuous-runner.log | 4 + tests/golden/WBV2-P1146-001/manifest.json | 1 + .../modifier-reader-batch-production.json | 212 + .../golden/WBV2-P1146-001/module-receipt.json | 131 + tests/golden/WBV2-P1146-001/module-run.log | 49 + .../golden/WBV2-P1146-001/scheduler-child.log | 0 tests/golden/WBV2-P1146-001/task-context.json | 187 + tests/golden/WBV2-P1147-000/manifest.json | 42 + .../WBV2-P1147-000/module-execution-plan.json | 5847 ++++++++++++++++ .../successor-authorization-report.json | 36 + tests/golden/WBV2-P1147-000/task-context.json | 177 + .../WBV2-P1147-001/continuous-gates.log | 2 + .../WBV2-P1147-001/continuous-runner.log | 4 + tests/golden/WBV2-P1147-001/manifest.json | 111 + .../modifier-reader-batch-production.json | 224 + .../golden/WBV2-P1147-001/module-receipt.json | 128 + tests/golden/WBV2-P1147-001/module-run.log | 49 + .../golden/WBV2-P1147-001/scheduler-child.log | 0 tests/golden/WBV2-P1147-001/task-context.json | 187 + tests/golden/WBV2-P1148-000/manifest.json | 42 + .../WBV2-P1148-000/module-execution-plan.json | 6010 +++++++++++++++++ .../successor-authorization-report.json | 36 + .../WBV2-P1148-001/continuous-runner.log | 43 + tests/golden/WBV2-P1148-001/manifest.json | 111 + .../modifier-reader-batch-production.json | 224 + .../golden/WBV2-P1148-001/module-receipt.json | 128 + tests/golden/WBV2-P1148-001/module-run.log | 49 + .../golden/WBV2-P1148-001/scheduler-child.log | 0 tests/golden/WBV2-P1148-001/task-context.json | 187 + tests/golden/WBV2/dynamic-coverage-audit.json | 564 +- .../WBV2/dynamic-coverage-bindings.json | 540 ++ .../WBV2/dynamic-coverage-manifest.json | 14 +- .../WBV2/dynamic-inventory-check-report.json | 4 +- .../WBV2/dynamic-inventory-manifest.json | 10 +- tests/golden/WBV2/dynamic-inventory.json | 1138 +++- tests/golden/WBV2/task-catalog.jsonl | 6 + tests/golden/WBV2/task-index.json | 2 +- tools/web/bind-wbv2-module-coverage.mjs | 114 + tools/web/emscripten-env.sh | 14 +- tools/web/run-wbv2-module-task.mjs | 111 + ...2-modifier-reader-batch-production.spec.ts | 87 + ...difier-reader-batch-two-production.spec.ts | 81 + 72 files changed, 23097 insertions(+), 208 deletions(-) create mode 100644 docs/status/WBV2-P1146-000.md create mode 100644 docs/status/WBV2-P1146-001.md create mode 100644 docs/status/WBV2-P1147-000.md create mode 100644 docs/status/WBV2-P1147-001.md create mode 100644 docs/status/WBV2-P1148-000.md create mode 100644 docs/status/WBV2-P1148-001.md create mode 100644 docs/tasks/WBV2-P1146-000.md create mode 100644 docs/tasks/WBV2-P1146-001.md create mode 100644 docs/tasks/WBV2-P1147-000.md create mode 100644 docs/tasks/WBV2-P1147-001.md create mode 100644 docs/tasks/WBV2-P1148-000.md create mode 100644 docs/tasks/WBV2-P1148-001.md create mode 100644 tests/files/web/modifier_reader_batch_scene.blend create mode 100644 tests/files/web/modifier_reader_batch_three_scene.blend create mode 100644 tests/files/web/modifier_reader_batch_two_scene.blend create mode 100644 tests/golden/WBV2-P1145-001/continuous-commit.log create mode 100644 tests/golden/WBV2-P1145-001/continuous-gates.log create mode 100644 tests/golden/WBV2-P1145-001/continuous-runner.log create mode 100644 tests/golden/WBV2-P1145-001/scheduler-child.log create mode 100644 tests/golden/WBV2-P1146-000/manifest.json create mode 100644 tests/golden/WBV2-P1146-000/module-execution-plan.json create mode 100644 tests/golden/WBV2-P1146-000/successor-authorization-report.json create mode 100644 tests/golden/WBV2-P1146-001/continuous-gates.log create mode 100644 tests/golden/WBV2-P1146-001/continuous-runner.log create mode 100644 tests/golden/WBV2-P1146-001/manifest.json create mode 100644 tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json create mode 100644 tests/golden/WBV2-P1146-001/module-receipt.json create mode 100644 tests/golden/WBV2-P1146-001/module-run.log create mode 100644 tests/golden/WBV2-P1146-001/scheduler-child.log create mode 100644 tests/golden/WBV2-P1146-001/task-context.json create mode 100644 tests/golden/WBV2-P1147-000/manifest.json create mode 100644 tests/golden/WBV2-P1147-000/module-execution-plan.json create mode 100644 tests/golden/WBV2-P1147-000/successor-authorization-report.json create mode 100644 tests/golden/WBV2-P1147-000/task-context.json create mode 100644 tests/golden/WBV2-P1147-001/continuous-gates.log create mode 100644 tests/golden/WBV2-P1147-001/continuous-runner.log create mode 100644 tests/golden/WBV2-P1147-001/manifest.json create mode 100644 tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json create mode 100644 tests/golden/WBV2-P1147-001/module-receipt.json create mode 100644 tests/golden/WBV2-P1147-001/module-run.log create mode 100644 tests/golden/WBV2-P1147-001/scheduler-child.log create mode 100644 tests/golden/WBV2-P1147-001/task-context.json create mode 100644 tests/golden/WBV2-P1148-000/manifest.json create mode 100644 tests/golden/WBV2-P1148-000/module-execution-plan.json create mode 100644 tests/golden/WBV2-P1148-000/successor-authorization-report.json create mode 100644 tests/golden/WBV2-P1148-001/continuous-runner.log create mode 100644 tests/golden/WBV2-P1148-001/manifest.json create mode 100644 tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json create mode 100644 tests/golden/WBV2-P1148-001/module-receipt.json create mode 100644 tests/golden/WBV2-P1148-001/module-run.log create mode 100644 tests/golden/WBV2-P1148-001/scheduler-child.log create mode 100644 tests/golden/WBV2-P1148-001/task-context.json create mode 100644 tools/web/bind-wbv2-module-coverage.mjs create mode 100644 tools/web/run-wbv2-module-task.mjs create mode 100644 web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts create mode 100644 web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts diff --git a/docs/EXECUTION_QUEUE.md b/docs/EXECUTION_QUEUE.md index 146e89789..bec5274b9 100644 --- a/docs/EXECUTION_QUEUE.md +++ b/docs/EXECUTION_QUEUE.md @@ -15,9 +15,9 @@ | 字段 | 值 | | --- | --- | | 里程碑 | WBV2 capability workflow | -| 当前任务 | `WBV2-P1145-001` | -| parent manifest | `tests/golden/WBV2-P1145-000/manifest.json` | -| 任务卡 | [`tasks/WBV2-P1145-001.md`](tasks/WBV2-P1145-001.md) | +| 当前任务 | `WBV2-P1148-001` | +| parent manifest | `tests/golden/WBV2-P1148-000/manifest.json` | +| 任务卡 | [`tasks/WBV2-P1148-001.md`](tasks/WBV2-P1148-001.md) | | 专项验收 | `node tools/web/check-execution-control-plane.mjs` | | legacy coverage checkpoint | `M16-GAP-00282` | | legacy coverage parent | `tests/golden/M16-GAP-00281/manifest.json` | diff --git a/docs/status/WBV2-P1145-001.md b/docs/status/WBV2-P1145-001.md index fa2b3046d..87153c847 100644 --- a/docs/status/WBV2-P1145-001.md +++ b/docs/status/WBV2-P1145-001.md @@ -5,4 +5,4 @@ - positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt - dynamic source inventory: `3745` units; verified `350`; unverified `3395`; planning estimate `5200` (non-binding) - historical 6900-entry inventory remains read-only; full-family parity: `false` -- nextTask: `NONE` +- nextTask: `WBV2-P1146-000` diff --git a/docs/status/WBV2-P1146-000.md b/docs/status/WBV2-P1146-000.md new file mode 100644 index 000000000..cf136b369 --- /dev/null +++ b/docs/status/WBV2-P1146-000.md @@ -0,0 +1,7 @@ +# WBV2-P1146-000 status + +- task: `WBV2-P1146-000`; parent: `WBV2-P1145-001`; status: `done` +- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed +- source-backed batch authorized: `MODIFIER_READER_BATCH` (9 units) +- dynamic inventory: `3745` units; verified `350`; unverified `3395`; bound delta `0` +- nextTask: `WBV2-P1146-001` diff --git a/docs/status/WBV2-P1146-001.md b/docs/status/WBV2-P1146-001.md new file mode 100644 index 000000000..6eede490c --- /dev/null +++ b/docs/status/WBV2-P1146-001.md @@ -0,0 +1,8 @@ +# WBV2-P1146-001 status + +- task: `WBV2-P1146-001`; module: `MODIFIER_READER_BATCH`; status: `done` +- source hashes stable: `true`; commands passed: `4` +- positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt +- dynamic source inventory: `3745` units; verified `359`; unverified `3386`; this-segment binding delta: `9`; planning estimate `5200` (non-binding) +- historical 6900-entry inventory remains read-only; full-family parity: `false` +- nextTask: `WBV2-P1147-000` diff --git a/docs/status/WBV2-P1147-000.md b/docs/status/WBV2-P1147-000.md new file mode 100644 index 000000000..f15be1ce9 --- /dev/null +++ b/docs/status/WBV2-P1147-000.md @@ -0,0 +1,7 @@ +# WBV2-P1147-000 status + +- task: `WBV2-P1147-000`; parent: `WBV2-P1146-001`; status: `done` +- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed +- source-backed batch authorized: `MODIFIER_READER_BATCH_TWO` (8 units) +- dynamic inventory: `3745` units; verified `359`; unverified `3386`; bound delta `0` +- nextTask: `WBV2-P1147-001` diff --git a/docs/status/WBV2-P1147-001.md b/docs/status/WBV2-P1147-001.md new file mode 100644 index 000000000..1869d5e7c --- /dev/null +++ b/docs/status/WBV2-P1147-001.md @@ -0,0 +1,8 @@ +# WBV2-P1147-001 status + +- task: `WBV2-P1147-001`; module: `MODIFIER_READER_BATCH_TWO`; status: `done` +- source hashes stable: `true`; commands passed: `4` +- positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt +- dynamic source inventory: `3745` units; verified `359`; unverified `3386`; planning estimate `5200` (non-binding) +- historical 6900-entry inventory remains read-only; full-family parity: `false` +- nextTask: `WBV2-P1148-000` diff --git a/docs/status/WBV2-P1148-000.md b/docs/status/WBV2-P1148-000.md new file mode 100644 index 000000000..838c4b914 --- /dev/null +++ b/docs/status/WBV2-P1148-000.md @@ -0,0 +1,7 @@ +# WBV2-P1148-000 status + +- task: `WBV2-P1148-000`; parent: `WBV2-P1147-001`; status: `done` +- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed +- source-backed batch authorized: `MODIFIER_READER_BATCH_THREE` (8 units) +- dynamic inventory: `3745` units; verified `369`; unverified `3376`; bound delta `0` +- nextTask: `WBV2-P1148-001` diff --git a/docs/status/WBV2-P1148-001.md b/docs/status/WBV2-P1148-001.md new file mode 100644 index 000000000..09cec0960 --- /dev/null +++ b/docs/status/WBV2-P1148-001.md @@ -0,0 +1,8 @@ +# WBV2-P1148-001 status + +- task: `WBV2-P1148-001`; module: `MODIFIER_READER_BATCH_THREE`; status: `done` +- source hashes stable: `true`; commands passed: `4` +- positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt +- dynamic source inventory: `3745` units; verified `377`; unverified `3368`; this-segment binding delta: `8`; planning estimate `5200` (non-binding) +- historical 6900-entry inventory remains read-only; full-family parity: `false` +- nextTask: `NONE` diff --git a/docs/tasks/WBV2-P1146-000.md b/docs/tasks/WBV2-P1146-000.md new file mode 100644 index 000000000..2cb12de97 --- /dev/null +++ b/docs/tasks/WBV2-P1146-000.md @@ -0,0 +1,45 @@ +# WBV2-P1146-000: verify modifier reader batch + +- task: WBV2-P1146-000 +- parent: WBV2-P1145-001 +- status: done +- gap: capability:MODIFIER_READER_BATCH +- ownerFamily: MODIFIER +- targetImplementationClass: LOCAL_EXACT +- Implementation entrypoint: `python3 my-tools/authorize_next_wbv2_task.py --write` + +## 目标 + +以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_datatransfer, MOD_dynamicpaint, MOD_explode, MOD_fluid 的真实 modifier/RNA 元数据。 + +## 输入与范围 + +- Blender modifier sources: `blender-5.2.0/source/blender/modifiers/intern/` +- RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` +- Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` +- Fixture: `tests/files/web/modifier_reader_batch_scene.blend` +- Chromium test: `web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts` +- Selected modifier units: `modifier-source:MOD_datatransfer`, `modifier-source:MOD_dynamicpaint`, `modifier-source:MOD_explode`, `modifier-source:MOD_fluid` +- Selected RNA units: `rna-struct:DataTransferModifier`, `rna-struct:DynamicPaintModifier`, `rna-struct:ExplodeModifier`, `rna-struct:FluidModifier`, `rna-struct:FluidDomainSettings` + +## 验收 + +- one shared Main/WASM/Worker/Chromium chain observes every selected type +- malformed input is rejected without Main mutation +- save/reopen and deterministic second read are exact +- only Chromium is used; JS simulation and per-API duplicate workers are forbidden +- each selected source unit receives an explicit hash-bound coverage binding +- `node tools/web/check-task-context.mjs --task WBV2-P1146-000 --write` + +## 失败边界 + +- any missing source, unsupported type, hash drift, malformed data or non-exact recovery keeps the batch `in_progress`/`blocked` +- partial batch success never claims the omitted family; historical inventory remains read-only + +## 交付与回滚 + +- Receipt: `tests/golden/WBV2-P1146-000/module-receipt.json` +- Aggregate production evidence: `tests/golden/WBV2-P1146-000/modifier-reader-batch-production.json` +- Manifest: `tests/golden/WBV2-P1146-000/manifest.json` +- Status: `docs/status/WBV2-P1146-000.md` +- Rollback: restore WBV2-P1145-001 as queue parent without rewriting prior evidence. diff --git a/docs/tasks/WBV2-P1146-001.md b/docs/tasks/WBV2-P1146-001.md new file mode 100644 index 000000000..959115e5d --- /dev/null +++ b/docs/tasks/WBV2-P1146-001.md @@ -0,0 +1,45 @@ +# WBV2-P1146-001: verify modifier reader batch + +- task: WBV2-P1146-001 +- parent: WBV2-P1146-000 +- status: done +- gap: capability:MODIFIER_READER_BATCH +- ownerFamily: MODIFIER +- targetImplementationClass: LOCAL_EXACT +- Implementation entrypoint: `node tools/web/run-wbv2-module-task.mjs --task WBV2-P1146-001 --write` + +## 目标 + +以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_datatransfer, MOD_dynamicpaint, MOD_explode, MOD_fluid 的真实 modifier/RNA 元数据。 + +## 输入与范围 + +- Blender modifier sources: `blender-5.2.0/source/blender/modifiers/intern/` +- RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` +- Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` +- Fixture: `tests/files/web/modifier_reader_batch_scene.blend` +- Chromium test: `web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts` +- Selected modifier units: `modifier-source:MOD_datatransfer`, `modifier-source:MOD_dynamicpaint`, `modifier-source:MOD_explode`, `modifier-source:MOD_fluid` +- Selected RNA units: `rna-struct:DataTransferModifier`, `rna-struct:DynamicPaintModifier`, `rna-struct:ExplodeModifier`, `rna-struct:FluidModifier`, `rna-struct:FluidDomainSettings` + +## 验收 + +- one shared Main/WASM/Worker/Chromium chain observes every selected type +- malformed input is rejected without Main mutation +- save/reopen and deterministic second read are exact +- only Chromium is used; JS simulation and per-API duplicate workers are forbidden +- each selected source unit receives an explicit hash-bound coverage binding +- `node tools/web/check-task-context.mjs --task WBV2-P1146-001 --write` + +## 失败边界 + +- any missing source, unsupported type, hash drift, malformed data or non-exact recovery keeps the batch `in_progress`/`blocked` +- partial batch success never claims the omitted family; historical inventory remains read-only + +## 交付与回滚 + +- Receipt: `tests/golden/WBV2-P1146-001/module-receipt.json` +- Aggregate production evidence: `tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json` +- Manifest: `tests/golden/WBV2-P1146-001/manifest.json` +- Status: `docs/status/WBV2-P1146-001.md` +- Rollback: restore WBV2-P1146-000 as queue parent without rewriting prior evidence. diff --git a/docs/tasks/WBV2-P1147-000.md b/docs/tasks/WBV2-P1147-000.md new file mode 100644 index 000000000..e8d75104a --- /dev/null +++ b/docs/tasks/WBV2-P1147-000.md @@ -0,0 +1,33 @@ +# WBV2-P1147-000: authorize modifier reader batch + +- task: WBV2-P1147-000 +- parent: WBV2-P1146-001 +- status: done +- gap: capability:MODIFIER_READER_BATCH_TWO +- ownerFamily: MODIFIER +- targetImplementationClass: QUEUE_ONLY +- Implementation entrypoint: `python3 my-tools/authorize_next_wbv2_task.py --write` + +## 目标 + +授权一个共享 Blender Main/WASM/Chromium modifier reader 批次,验证 Laplacian Deform、Laplacian Smooth、Mask、Shrinkwrap 及其 RNA 元数据。 + +## 输入与范围 + +- Blender sources: `blender-5.2.0/source/blender/modifiers/intern/` +- RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` +- Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` +- Fixture/test: `tests/files/web/modifier_reader_batch_two_scene.blend`, `web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts` + +## 验收 + +- source-backed batch is hash-bound; historical inventory remains immutable +- one shared function chain covers all selected units; verification runs once +- missing source, unsupported data, hash drift or false completion remains blocked +- `node tools/web/check-task-context.mjs --task WBV2-P1147-000 --write` + +## 交付与回滚 + +- Manifest: `tests/golden/WBV2-P1147-000/manifest.json` +- Status: `docs/status/WBV2-P1147-000.md` +- Rollback: restore WBV2-P1146-001 as queue parent. diff --git a/docs/tasks/WBV2-P1147-001.md b/docs/tasks/WBV2-P1147-001.md new file mode 100644 index 000000000..7d69f9b45 --- /dev/null +++ b/docs/tasks/WBV2-P1147-001.md @@ -0,0 +1,45 @@ +# WBV2-P1147-001: verify modifier reader batch two + +- task: WBV2-P1147-001 +- parent: WBV2-P1147-000 +- status: in_progress +- gap: capability:MODIFIER_READER_BATCH_TWO +- ownerFamily: MODIFIER +- targetImplementationClass: LOCAL_EXACT +- Implementation entrypoint: `node tools/web/run-wbv2-module-task.mjs --task WBV2-P1147-001 --write` + +## 目标 + +以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_laplaciandeform, MOD_laplaciansmooth, MOD_mask, MOD_shrinkwrap 的真实 modifier/RNA 元数据。 + +## 输入与范围 + +- Blender modifier sources: `blender-5.2.0/source/blender/modifiers/intern/` +- RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` +- Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` +- Fixture: `tests/files/web/modifier_reader_batch_two_scene.blend` +- Chromium test: `web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts` +- Selected modifier units: `modifier-source:MOD_laplaciandeform`, `modifier-source:MOD_laplaciansmooth`, `modifier-source:MOD_mask`, `modifier-source:MOD_shrinkwrap` +- Selected RNA units: `rna-struct:LaplacianDeformModifier`, `rna-struct:LaplacianSmoothModifier`, `rna-struct:MaskModifier`, `rna-struct:ShrinkwrapModifier` + +## 验收 + +- one shared Main/WASM/Worker/Chromium chain observes every selected type +- malformed input is rejected without Main mutation +- save/reopen and deterministic second read are exact +- only Chromium is used; JS simulation and per-API duplicate workers are forbidden +- each selected source unit receives an explicit hash-bound coverage binding +- `node tools/web/check-task-context.mjs --task WBV2-P1147-001 --write` + +## 失败边界 + +- any missing source, unsupported type, hash drift, malformed data or non-exact recovery keeps the batch `in_progress`/`blocked` +- partial batch success never claims the omitted family; historical inventory remains read-only + +## 交付与回滚 + +- Receipt: `tests/golden/WBV2-P1147-001/module-receipt.json` +- Aggregate production evidence: `tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json` +- Manifest: `tests/golden/WBV2-P1147-001/manifest.json` +- Status: `docs/status/WBV2-P1147-001.md` +- Rollback: restore WBV2-P1147-000 as queue parent without rewriting prior evidence. diff --git a/docs/tasks/WBV2-P1148-000.md b/docs/tasks/WBV2-P1148-000.md new file mode 100644 index 000000000..5818461e3 --- /dev/null +++ b/docs/tasks/WBV2-P1148-000.md @@ -0,0 +1,45 @@ +# WBV2-P1148-000: verify modifier reader batch three + +- task: WBV2-P1148-000 +- parent: WBV2-P1147-001 +- status: done +- gap: capability:MODIFIER_READER_BATCH_THREE +- ownerFamily: MODIFIER +- targetImplementationClass: LOCAL_EXACT +- Implementation entrypoint: `python3 my-tools/authorize_next_wbv2_task.py --write` + +## 目标 + +以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_remesh, MOD_skin, MOD_weighted_normal, MOD_warp 的真实 modifier/RNA 元数据。 + +## 输入与范围 + +- Blender modifier sources: `blender-5.2.0/source/blender/modifiers/intern/` +- RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` +- Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` +- Fixture: `tests/files/web/modifier_reader_batch_three_scene.blend` +- Chromium test: `web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts` +- Selected modifier units: `modifier-source:MOD_remesh`, `modifier-source:MOD_skin`, `modifier-source:MOD_weighted_normal`, `modifier-source:MOD_warp` +- Selected RNA units: `rna-struct:RemeshModifier`, `rna-struct:SkinModifier`, `rna-struct:WeightedNormalModifier`, `rna-struct:WarpModifier` + +## 验收 + +- one shared Main/WASM/Worker/Chromium chain observes every selected type +- malformed input is rejected without Main mutation +- save/reopen and deterministic second read are exact +- only Chromium is used; JS simulation and per-API duplicate workers are forbidden +- each selected source unit receives an explicit hash-bound coverage binding +- `node tools/web/check-task-context.mjs --task WBV2-P1148-000 --write` + +## 失败边界 + +- any missing source, unsupported type, hash drift, malformed data or non-exact recovery keeps the batch `in_progress`/`blocked` +- partial batch success never claims the omitted family; historical inventory remains read-only + +## 交付与回滚 + +- Receipt: `tests/golden/WBV2-P1148-000/module-receipt.json` +- Aggregate production evidence: `tests/golden/WBV2-P1148-000/modifier-reader-batch-production.json` +- Manifest: `tests/golden/WBV2-P1148-000/manifest.json` +- Status: `docs/status/WBV2-P1148-000.md` +- Rollback: restore WBV2-P1147-001 as queue parent without rewriting prior evidence. diff --git a/docs/tasks/WBV2-P1148-001.md b/docs/tasks/WBV2-P1148-001.md new file mode 100644 index 000000000..8c6689462 --- /dev/null +++ b/docs/tasks/WBV2-P1148-001.md @@ -0,0 +1,45 @@ +# WBV2-P1148-001: verify modifier reader batch three + +- task: WBV2-P1148-001 +- parent: WBV2-P1148-000 +- status: done +- gap: capability:MODIFIER_READER_BATCH_THREE +- ownerFamily: MODIFIER +- targetImplementationClass: LOCAL_EXACT +- Implementation entrypoint: `node tools/web/run-wbv2-module-task.mjs --task WBV2-P1148-001 --write` + +## 目标 + +以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_remesh, MOD_skin, MOD_weighted_normal, MOD_warp 的真实 modifier/RNA 元数据。 + +## 输入与范围 + +- Blender modifier sources: `blender-5.2.0/source/blender/modifiers/intern/` +- RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` +- Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` +- Fixture: `tests/files/web/modifier_reader_batch_three_scene.blend` +- Chromium test: `web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts` +- Selected modifier units: `modifier-source:MOD_remesh`, `modifier-source:MOD_skin`, `modifier-source:MOD_weighted_normal`, `modifier-source:MOD_warp` +- Selected RNA units: `rna-struct:RemeshModifier`, `rna-struct:SkinModifier`, `rna-struct:WeightedNormalModifier`, `rna-struct:WarpModifier` + +## 验收 + +- one shared Main/WASM/Worker/Chromium chain observes every selected type +- malformed input is rejected without Main mutation +- save/reopen and deterministic second read are exact +- only Chromium is used; JS simulation and per-API duplicate workers are forbidden +- each selected source unit receives an explicit hash-bound coverage binding +- `node tools/web/check-task-context.mjs --task WBV2-P1148-001 --write` + +## 失败边界 + +- any missing source, unsupported type, hash drift, malformed data or non-exact recovery keeps the batch `in_progress`/`blocked` +- partial batch success never claims the omitted family; historical inventory remains read-only + +## 交付与回滚 + +- Receipt: `tests/golden/WBV2-P1148-001/module-receipt.json` +- Aggregate production evidence: `tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json` +- Manifest: `tests/golden/WBV2-P1148-001/manifest.json` +- Status: `docs/status/WBV2-P1148-001.md` +- Rollback: restore WBV2-P1148-000 as queue parent without rewriting prior evidence. diff --git a/my-tools/README.md b/my-tools/README.md index 74c08addb..c21004a6d 100644 --- a/my-tools/README.md +++ b/my-tools/README.md @@ -62,3 +62,7 @@ python3 my-tools/show_blender_web_scheduler.py --json `--commit --push` is enabled by the launcher and can be disabled for a local dry run with `WBV2_AUTO_COMMIT=0 WBV2_AUTO_PUSH=0`. + +On Linux, the launcher uses `/dev/shm/blender-wasm-` for Emscripten and +temporary compiler caches. CPU compilation remains capped at the repository's +required `-j8`; Chromium evidence stays single-worker for determinism. diff --git a/my-tools/authorize_next_wbv2_task.py b/my-tools/authorize_next_wbv2_task.py index 993ee25aa..8bb10566e 100644 --- a/my-tools/authorize_next_wbv2_task.py +++ b/my-tools/authorize_next_wbv2_task.py @@ -1,10 +1,9 @@ #!/usr/bin/env python3 -"""Authorize the next source-backed Blender/WBV2 module from the live queue. +"""Authorize the next source-backed Blender module batch. -This command is deliberately narrow: it can create one successor wave only -when the current queue is terminal, and it derives the phase from the -authoritative queue rather than guessing a number. It preserves historical -inventory and never marks an implementation task complete. +Each successor is a bounded capability batch. The queue advances only after a +single shared Blender Main/WASM/Worker/Chromium chain produces an aggregate +receipt for every selected source unit. """ from __future__ import annotations @@ -20,6 +19,43 @@ from pathlib import Path from wbv2_runtime import CONTROL_ROOT, INDEX, QUEUE, ROOT, read_json, terminal_pointer +PREFERRED_BATCHES = [ + { + "moduleId": "MODIFIER_READER_BATCH", + "title": "verify modifier reader batch", + "owner": "MODIFIER", + "identifiers": ["MOD_datatransfer", "MOD_dynamicpaint", "MOD_explode", "MOD_fluid"], + "rna": ["DataTransferModifier", "DynamicPaintModifier", "ExplodeModifier", "FluidModifier", "FluidDomainSettings"], + "fixture": "tests/files/web/modifier_reader_batch_scene.blend", + "test": "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "production": "tests/golden/{task}/modifier-reader-batch-production.json", + "types": ["DATA_TRANSFER", "DYNAMIC_PAINT", "EXPLODE", "FLUID"], + }, + { + "moduleId": "MODIFIER_READER_BATCH_TWO", + "title": "verify modifier reader batch two", + "owner": "MODIFIER", + "identifiers": ["MOD_laplaciandeform", "MOD_laplaciansmooth", "MOD_mask", "MOD_shrinkwrap"], + "rna": ["LaplacianDeformModifier", "LaplacianSmoothModifier", "MaskModifier", "ShrinkwrapModifier"], + "fixture": "tests/files/web/modifier_reader_batch_two_scene.blend", + "test": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "production": "tests/golden/{task}/modifier-reader-batch-production.json", + "types": ["LAPLACIANDEFORM", "LAPLACIANSMOOTH", "MASK", "SHRINKWRAP"], + }, + { + "moduleId": "MODIFIER_READER_BATCH_THREE", + "title": "verify modifier reader batch three", + "owner": "MODIFIER", + "identifiers": ["MOD_remesh", "MOD_skin", "MOD_weighted_normal", "MOD_warp"], + "rna": ["RemeshModifier", "SkinModifier", "WeightedNormalModifier", "WarpModifier"], + "fixture": "tests/files/web/modifier_reader_batch_three_scene.blend", + "test": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "production": "tests/golden/{task}/modifier-reader-batch-production.json", + "types": ["REMESH", "SKIN", "WEIGHTED_NORMAL", "WARP"], + }, +] + + def sha(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() @@ -47,194 +83,150 @@ def run_node(*args: str) -> None: raise SystemExit(result.returncode) -def queue_task() -> str: +def current_task() -> str: match = re.search(r"\| 当前任务 \| `(WBV2-P(\d+)-(\d{3}))` \|", QUEUE.read_text(encoding="utf-8")) if not match: raise SystemExit("queue pointer is not a WBV2 task") return match.group(1) -def replace_snapshot(text: str, task: str, parent: str, next_task: str) -> str: +def queue_parent() -> str: + match = re.search(r"\| parent manifest \| `([^`]+)` \|", QUEUE.read_text(encoding="utf-8"), re.IGNORECASE) + if not match: + raise SystemExit("queue parent manifest is missing") + return match.group(1) + + +def snapshot(text: str, task: str, parent: str, next_task: str) -> str: tick = "`" - replacements = { - r"\| Current task when this file was written \| `[^`]+` \|": f"| Current task when this file was written | {tick}{task}{tick} |", - r"\| Current task state \| `[^`]+` \|": f"| Current task state | {tick}in_progress{tick} |", - r"\| Parent manifest \| `[^`]+` \|": f"| Parent manifest | {tick}tests/golden/{parent}/manifest.json{tick} |", - r"\| Current task card \| `[^`]+` \|": f"| Current task card | {tick}docs/tasks/{task}.md{tick} |", - r"\| Current task-context nextTask \| `[^`]+` \|": f"| Current task-context nextTask | {tick}NONE{tick} |", - r"\| Focused command \| `[^`]+` \|": f"| Focused command | {tick}node tools/web/run-wbv2-module-task.mjs --task {task} --write{tick} |", - } - for pattern, replacement in replacements.items(): + substitutions = [ + (r"\| Current task when this file was written \| `[^`]+` \|", f"| Current task when this file was written | {tick}{task}{tick} |"), + (r"\| Current task state \| `[^`]+` \|", f"| Current task state | {tick}in_progress{tick} |"), + (r"\| Parent manifest \| `[^`]+` \|", f"| Parent manifest | {tick}tests/golden/{parent}/manifest.json{tick} |"), + (r"\| Current task card \| `[^`]+` \|", f"| Current task card | {tick}docs/tasks/{task}.md{tick} |"), + (r"\| Current task-context nextTask \| `[^`]+` \|", f"| Current task-context nextTask | {tick}{next_task}{tick} |"), + (r"\| Focused command \| `[^`]+` \|", f"| Focused command | {tick}node tools/web/run-wbv2-module-task.mjs --task {task} --write{tick} |"), + ] + for pattern, replacement in substitutions: text = re.sub(pattern, replacement, text, count=1) return text -def card(task: str, parent: str, status: str, title: str, entrypoint: str) -> str: - return f"""# {task}: {title} +def make_card(task: str, parent: str, status: str, batch: dict, entrypoint: str) -> str: + names = ", ".join(batch["identifiers"]) + units = ", ".join(f"`modifier-source:{name}`" for name in batch["identifiers"]) + rna_units = ", ".join(f"`rna-struct:{name}`" for name in batch["rna"]) + return f"""# {task}: {batch['title']} - task: {task} - parent: {parent} - status: {status} -- gap: capability:CORRECTIVE_SMOOTH_READER -- ownerFamily: MODIFIER +- gap: capability:{batch['moduleId']} +- ownerFamily: {batch['owner']} - targetImplementationClass: LOCAL_EXACT - Implementation entrypoint: `{entrypoint}` ## 目标 -验证 Blender Main 中 Corrective Smooth modifier 的真实类型和 RNA 元数据,并确认 save/reopen、worker termination 和 malformed 输入保持确定性。 +以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 {names} 的真实 modifier/RNA 元数据。 ## 输入与范围 -- Blender source: `blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc` +- Blender modifier sources: `blender-5.2.0/source/blender/modifiers/intern/` - RNA source: `blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc` - Native reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp` -- Fixture: `tests/files/web/modifier_corrective_smooth_scene.blend` -- Chromium test: `web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts` +- Fixture: `{batch['fixture']}` +- Chromium test: `{batch['test']}` +- Selected modifier units: {units} +- Selected RNA units: {rna_units} ## 验收 -- Corrective Smooth is read from Blender Main through the compiled WebEngine/WASM path -- malformed blend is rejected without Main mutation +- one shared Main/WASM/Worker/Chromium chain observes every selected type +- malformed input is rejected without Main mutation - save/reopen and deterministic second read are exact -- Chromium is the only browser and JS simulation is forbidden +- only Chromium is used; JS simulation and per-API duplicate workers are forbidden +- each selected source unit receives an explicit hash-bound coverage binding - `node tools/web/check-task-context.mjs --task {task} --write` ## 失败边界 -- missing source, unsupported modifier, hash drift, malformed data or non-exact recovery remains `in_progress`/`blocked` -- this slice never claims full modifier-family parity or mutates historical inventory +- any missing source, unsupported type, hash drift, malformed data or non-exact recovery keeps the batch `in_progress`/`blocked` +- partial batch success never claims the omitted family; historical inventory remains read-only ## 交付与回滚 - Receipt: `tests/golden/{task}/module-receipt.json` +- Aggregate production evidence: `tests/golden/{task}/modifier-reader-batch-production.json` - Manifest: `tests/golden/{task}/manifest.json` - Status: `docs/status/{task}.md` - Rollback: restore {parent} as queue parent without rewriting prior evidence. """ +def select_batch(inventory: dict) -> dict: + units = {unit.get("identifier"): unit for unit in inventory.get("units", []) if isinstance(unit, dict) and unit.get("coverageStatus") != "VERIFIED"} + for candidate in PREFERRED_BATCHES: + selected = [units.get(name) for name in candidate["identifiers"] + candidate["rna"]] + if all(selected): + return {**candidate, "units": selected} + raise SystemExit("no configured unresolved Blender source batch remains") + + def main() -> int: parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--write", action="store_true", help="write the successor authorization") + parser.add_argument("--write", action="store_true") args = parser.parse_args() - current = queue_task() - pointer = {"task": current, "parentManifest": re.search(r"\| parent manifest \| `([^`]+)` \|", QUEUE.read_text(encoding="utf-8"), re.IGNORECASE).group(1)} - current_manifest_path = CONTROL_ROOT.parent / current / "manifest.json" + current = current_task() + parent_path = queue_parent() + current_manifest_path = ROOT / "tests/golden" / current / "manifest.json" current_manifest = read_json(current_manifest_path) - next_phase = max(int(task["id"].split("-")[1][1:]) for task in json.loads((ROOT / read_json(INDEX)["source"]["path"]).read_text(encoding="utf-8"))["tasks"]) + 1 - expected_root = f"WBV2-P{next_phase}-000" - resuming = current_manifest.get("nextTask") == expected_root - if current_manifest.get("status") != "done" or (current_manifest.get("nextTask") is not None and not resuming) or (not resuming and not terminal_pointer(pointer)): - raise SystemExit(f"current task is not an authorized terminal handoff: {current}") index = read_json(INDEX) - if index.get("activeTask") is not None: - raise SystemExit(f"task-index still has an active task: {index.get('activeTask')}") plan_path = ROOT / index["source"]["path"] plan = json.loads(plan_path.read_text(encoding="utf-8")) - phase = max(int(task["id"].split("-")[1][1:]) for task in plan["tasks"]) + 1 - root_task = f"WBV2-P{phase}-000" - module_task = f"WBV2-P{phase}-001" - module_id = "CORRECTIVE_SMOOTH_READER" - module_source = [ - "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", - "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", - "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", - "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", - "tests/files/web/modifier_corrective_smooth_scene.blend", - "web/app/src/vendor/blender/web_engine.wasm", - ] - for source in module_source: - if not (ROOT / source).is_file(): - raise SystemExit(f"module source is missing: {source}") + terminal = current_manifest.get("status") == "done" and current_manifest.get("nextTask") is None and index.get("activeTask") is None + if not terminal and not current_manifest.get("nextTask"): + raise SystemExit(f"current task is not terminal: {current}") + phase = max(int(item["id"].split("-")[1][1:]) for item in plan["tasks"]) + 1 + root_task, module_task = f"WBV2-P{phase}-000", f"WBV2-P{phase}-001" + inventory = read_json(CONTROL_ROOT / "dynamic-inventory.json") + batch = select_batch(inventory) + if not args.write: + print(json.dumps({"status": "ready", "rootTask": root_task, "nextTask": module_task, "moduleId": batch["moduleId"], "batchSize": len(batch["units"]), "sourceUnits": [unit["id"] for unit in batch["units"]]}, ensure_ascii=False)) + return 0 + + current_status = ROOT / "docs/status" / f"{current}.md" + if current_status.is_file(): + status_text = re.sub(r"- nextTask: `[^`]+`", f"- nextTask: `{root_task}`", current_status.read_text(encoding="utf-8")) + write_text(current_status, status_text) + current_manifest["nextTask"] = root_task + if isinstance(current_manifest.get("artifacts"), dict) and isinstance(current_manifest["artifacts"].get("status"), dict): + current_manifest["artifacts"]["status"]["sha256"] = sha(current_status) + write_json(current_manifest_path, current_manifest) + + source_paths = [unit["locations"][0]["path"] for unit in batch["units"]] + source_paths += ["blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", batch["test"], batch["fixture"], "web/app/src/vendor/blender/web_engine.wasm"] commands = [ "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", "npm --prefix web run typecheck", "npm --prefix web run build", - "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + f"WBV2_BATCH_TASK={module_task} WBV2_BATCH_FIXTURE={batch['fixture']} WBV2_BATCH_TYPES='{json.dumps(batch['types'], separators=(',', ':'))}' WBV2_BATCH_UNITS='{json.dumps([unit['id'] for unit in batch['units']], separators=(',', ':'))}' WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/{Path(batch['test']).name}", ] - root_record = { - "id": root_task, - "phase": str(phase), - "title": "authorize_corrective_smooth_reader_module", - "kind": "enabling", - "owner": "PROGRAM", - "dependsOn": [current], - "parityId": None, - "implementationClass": "QUEUE_ONLY", - "parallelGroup": f"module-root-{phase}", - "gate": "MODULE", - "card": f"docs/tasks/{root_task}.md", - "behavior": "Authorize a source-backed Corrective Smooth reader/recovery module after the Driver reader.", - "outputs": ["successor authorization", "module plan", "manifest", "status"], - "acceptance": ["prior evidence remains hash-bound", "Corrective Smooth has explicit Blender source mapping", "inventory remains source-derived", "one source-backed module is active"], - "commands": ["node tools/web/check-execution-control-plane.mjs"], - "status": "done", - "ready": False, - "queueMutationAllowed": True, - } - module_record = { - "id": module_task, - "phase": str(phase), - "title": "verify_corrective_smooth_reader_module", - "kind": "module", - "owner": "MODIFIER", - "dependsOn": [root_task], - "parityId": module_id, - "implementationClass": "LOCAL_EXACT", - "parallelGroup": "module-corrective_smooth_reader", - "gate": "MODULE", - "card": f"docs/tasks/{module_task}.md", - "behavior": "Verify Corrective Smooth modifier type and RNA metadata through Blender Main reader, protocol and Chromium recovery.", - "outputs": ["module receipt", "negative matrix", "manifest", "status"], - "acceptance": ["source and protocol hashes are bound", "positive Main reader is proven", "negative no-mutation and recovery are proven", "Chromium and save/reopen evidence are exact", "full-family parity remains explicit"], - "status": "in_progress", - "ready": True, - "queueMutationAllowed": True, - "module": { - "moduleId": module_id, - "sourceBacked": True, - "capabilities": ["CAP-CORRECTIVE-SMOOTH-READER", "CAP-CORRECTIVE-SMOOTH-RECOVERY", "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED"], - "sourcePaths": module_source, - "reuseReceipts": [{"manifest": "tests/golden/WBV2-P1107-000/manifest.json", "report": "tests/golden/WBV2-P1107-000/module-receipt.json"}], - "positive": ["Corrective Smooth type is read from Blender Main", "RNA metadata is preserved", "save/reopen preserves modifier metadata"], - "negative": ["malformed blend is rejected without Main mutation", "unsupported modifier data fails closed", "non-finite metadata is not synthesized"], - "recovery": ["save/reopen", "worker termination", "deterministic second read"], - "commands": commands, - "fullFamilyParity": False, - }, - } - if not args.write: - print(json.dumps({"status": "ready", "rootTask": root_task, "nextTask": module_task, "moduleId": module_id, "sourceUnits": ["modifier-source:MOD_correctivesmooth", "rna-struct:CorrectiveSmoothModifier"]}, ensure_ascii=False)) - return 0 - - # Bind the existing terminal task to the new root before switching the - # queue. This preserves the parent/nextTask invariant for every handoff. - current_status_path = ROOT / "docs/status" / f"{current}.md" - if current_status_path.is_file(): - text = current_status_path.read_text(encoding="utf-8") - text = re.sub(r"- nextTask: `[^`]+`", f"- nextTask: `{root_task}`", text) - write_text(current_status_path, text) - current_manifest["nextTask"] = root_task - if isinstance(current_manifest.get("artifacts"), dict) and isinstance(current_manifest["artifacts"].get("status"), dict): - current_manifest["artifacts"]["status"]["sha256"] = sha(current_status_path) - write_json(current_manifest_path, current_manifest) + root_record = {"id": root_task, "phase": str(phase), "title": "authorize_modifier_reader_batch", "kind": "enabling", "owner": "PROGRAM", "dependsOn": [current], "parityId": None, "implementationClass": "QUEUE_ONLY", "parallelGroup": f"module-root-{phase}", "gate": "MODULE", "card": f"docs/tasks/{root_task}.md", "behavior": "Authorize one shared source-backed modifier reader batch.", "outputs": ["successor authorization", "module plan", "manifest", "status"], "acceptance": ["prior evidence remains hash-bound", "batch source mapping is explicit", "inventory remains source-derived"], "commands": ["node tools/web/check-execution-control-plane.mjs"], "status": "done", "ready": False, "queueMutationAllowed": True} + module_record = {"id": module_task, "phase": str(phase), "title": batch["title"], "kind": "module", "owner": batch["owner"], "dependsOn": [root_task], "parityId": batch["moduleId"], "implementationClass": "LOCAL_EXACT", "parallelGroup": f"module-{batch['moduleId'].lower()}", "gate": "MODULE", "card": f"docs/tasks/{module_task}.md", "behavior": f"Verify the {batch['moduleId']} batch through Blender Main, WASM and Chromium recovery.", "outputs": ["aggregate module receipt", "coverage bindings", "manifest", "status"], "acceptance": ["source and protocol hashes are bound", "every selected Main reader type is proven", "negative no-mutation and recovery are proven", "Chromium and save/reopen evidence are exact"], "status": "in_progress", "ready": True, "queueMutationAllowed": True, "module": {"moduleId": batch["moduleId"], "sourceBacked": True, "capabilities": [f"CAP-{batch['moduleId']}-READER", f"CAP-{batch['moduleId']}-RECOVERY", f"CAP-{batch['moduleId']}-FAIL-CLOSED"], "sourcePaths": source_paths, "reuseReceipts": [{"manifest": "tests/golden/WBV2-P1107-000/manifest.json", "report": "tests/golden/WBV2-P1107-000/module-receipt.json"}], "positive": [f"{name} type is read from Blender Main" for name in batch["identifiers"]] + ["shared RNA metadata is preserved", "save/reopen preserves the batch metadata"], "negative": ["malformed blend is rejected without Main mutation", "unsupported batch data fails closed", "non-finite metadata is not synthesized"], "recovery": ["save/reopen", "worker termination", "deterministic second read"], "commands": commands, "fullFamilyParity": False, "evidencePaths": [batch["production"].format(task=module_task)], "coverageBindings": [unit["id"] for unit in batch["units"]]}} root_out = CONTROL_ROOT.parent / root_task root_plan_path = root_out / "module-execution-plan.json" - root_plan = {**plan, "planId": f"BLENDER_WEB_MODULE_EXECUTION_P{phase}", "status": "ACTIVE_MODULE_QUEUE", "tasks": [*plan["tasks"], root_record, module_record], "modules": [*plan.get("modules", []), {"id": module_id, "task": module_task, "owner": "MODIFIER", "sourceBacked": True, "capabilities": module_record["module"]["capabilities"], "sourcePaths": module_source, "reuseReceipts": module_record["module"]["reuseReceipts"], "fullFamilyParity": False}]} + root_plan = {**plan, "planId": f"BLENDER_WEB_MODULE_EXECUTION_P{phase}", "status": "ACTIVE_MODULE_QUEUE", "tasks": [*plan["tasks"], root_record, module_record], "modules": [*plan.get("modules", []), {"id": batch["moduleId"], "task": module_task, "owner": batch["owner"], "sourceBacked": True, "capabilities": module_record["module"]["capabilities"], "sourcePaths": source_paths, "reuseReceipts": module_record["module"]["reuseReceipts"], "fullFamilyParity": False}]} write_json(root_plan_path, root_plan) - root_card_path = ROOT / "docs/tasks" / f"{root_task}.md" - module_card_path = ROOT / "docs/tasks" / f"{module_task}.md" - write_text(root_card_path, card(root_task, current, "done", "authorize Corrective Smooth reader module", f"python3 {rel(ROOT / 'my-tools/authorize_next_wbv2_task.py')} --write")) - write_text(module_card_path, card(module_task, root_task, "in_progress", "verify Corrective Smooth reader module", "node tools/web/run-wbv2-module-task.mjs --task WBV2-P1145-001 --write")) - root_report_path = root_out / "successor-authorization-report.json" - root_status_path = ROOT / "docs/status" / f"{root_task}.md" - root_manifest_path = root_out / "manifest.json" - write_json(root_report_path, {"schemaVersion": 1, "task": root_task, "operation": "AUTHORIZE_SOURCE_BACKED_MODULE", "taskClass": "QUEUE_ENABLEMENT", "status": "PASS", "parent": {"task": current, "manifest": rel(current_manifest_path), "manifestSha256": sha(current_manifest_path)}, "module": {"moduleId": module_id, "task": module_task, "sourceUnits": ["modifier-source:MOD_correctivesmooth", "rna-struct:CorrectiveSmoothModifier"], "sourceBacked": True}, "inventory": {"unitCount": 3745, "verifiedUnits": 350, "unverifiedUnits": 3395, "sourceTreeSha256": read_json(CONTROL_ROOT / "dynamic-inventory.json").get("authority", {}).get("sourceTreeSha256"), "boundUnitDelta": 0}, "nextTask": module_task}) - write_text(root_status_path, f"# {root_task} status\n\n- task: `{root_task}`; parent: `{current}`; status: `done`\n- taskClass: `QUEUE_ENABLEMENT`; no Corrective Smooth parity completion claimed\n- source-backed successor authorized for `CORRECTIVE_SMOOTH_READER`\n- dynamic inventory remains `3745` units; verified `350`; unverified `3395`; bound delta `0`\n- nextTask: `{module_task}`\n") - write_json(root_manifest_path, {"schemaVersion": 1, "task": root_task, "parentTask": current, "operation": "AUTHORIZE_SOURCE_BACKED_MODULE", "status": "done", "enablingTask": True, "parityStateChange": False, "runtime": "MODULE_EXECUTION_QUEUE_BRIDGE", "artifacts": {"parentManifest": {"path": rel(current_manifest_path), "sha256": sha(current_manifest_path)}, "plan": {"path": rel(root_plan_path), "sha256": sha(root_plan_path)}, "report": {"path": rel(root_report_path), "sha256": sha(root_report_path)}, "status": {"path": rel(root_status_path), "sha256": sha(root_status_path)}}, "assertions": {"sourceBackedSuccessor": True, "priorEvidencePreserved": True, "moduleId": module_id, "inventoryTotal": 6900, "effectiveCompleted": 290, "effectivePending": 6609, "dynamicUnitCount": 3745, "dynamicVerifiedUnits": 350, "dynamicUnverifiedUnits": 3395, "boundUnitDelta": 0, "fullHistoricalReproduction": False}, "nextTask": module_task}) - # The new plan becomes authoritative only after all files and cards exist. + root_card_path, module_card_path = ROOT / "docs/tasks" / f"{root_task}.md", ROOT / "docs/tasks" / f"{module_task}.md" + write_text(root_card_path, make_card(root_task, current, "done", batch, f"python3 my-tools/authorize_next_wbv2_task.py --write")) + write_text(module_card_path, make_card(module_task, root_task, "in_progress", batch, f"node tools/web/run-wbv2-module-task.mjs --task {module_task} --write")) + root_report_path, root_status_path, root_manifest_path = root_out / "successor-authorization-report.json", ROOT / "docs/status" / f"{root_task}.md", root_out / "manifest.json" + write_json(root_report_path, {"schemaVersion": 1, "task": root_task, "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", "taskClass": "QUEUE_ENABLEMENT", "status": "PASS", "parent": {"task": current, "manifest": rel(current_manifest_path), "manifestSha256": sha(current_manifest_path)}, "module": {"moduleId": batch["moduleId"], "task": module_task, "batchSize": len(batch["units"]), "sourceUnits": [unit["id"] for unit in batch["units"]], "sourceBacked": True}, "inventory": {"unitCount": inventory["summary"]["unitCount"], "verifiedUnits": inventory["coverage"]["verifiedUnits"], "unverifiedUnits": inventory["coverage"]["unverifiedUnits"], "sourceTreeSha256": inventory["authority"]["sourceTreeSha256"], "boundUnitDelta": 0}, "nextTask": module_task}) + write_text(root_status_path, f"# {root_task} status\n\n- task: `{root_task}`; parent: `{current}`; status: `done`\n- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed\n- source-backed batch authorized: `{batch['moduleId']}` ({len(batch['units'])} units)\n- dynamic inventory: `{inventory['summary']['unitCount']}` units; verified `{inventory['coverage']['verifiedUnits']}`; unverified `{inventory['coverage']['unverifiedUnits']}`; bound delta `0`\n- nextTask: `{module_task}`\n") + write_json(root_manifest_path, {"schemaVersion": 1, "task": root_task, "parentTask": current, "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", "status": "done", "enablingTask": True, "parityStateChange": False, "runtime": "MODULE_EXECUTION_QUEUE_BRIDGE", "artifacts": {"parentManifest": {"path": rel(current_manifest_path), "sha256": sha(current_manifest_path)}, "plan": {"path": rel(root_plan_path), "sha256": sha(root_plan_path)}, "report": {"path": rel(root_report_path), "sha256": sha(root_report_path)}, "status": {"path": rel(root_status_path), "sha256": sha(root_status_path)}}, "assertions": {"sourceBackedSuccessor": True, "moduleId": batch["moduleId"], "batchSize": len(batch["units"]), "inventoryTotal": 6900, "effectiveCompleted": 290, "effectivePending": 6609, "dynamicUnitCount": inventory["summary"]["unitCount"], "dynamicVerifiedUnits": inventory["coverage"]["verifiedUnits"], "dynamicUnverifiedUnits": inventory["coverage"]["unverifiedUnits"], "boundUnitDelta": 0, "fullHistoricalReproduction": False}, "nextTask": module_task}) + run_node("tools/web/generate-v2-task-index.mjs", "--plan-path", rel(root_plan_path)) queue_text = QUEUE.read_text(encoding="utf-8") queue_text = re.sub(r"\| 当前任务 \| `[^`]+` \|", f"| 当前任务 | `{module_task}` |", queue_text, count=1) @@ -243,13 +235,15 @@ def main() -> int: write_text(QUEUE, queue_text) next_path = ROOT / "nextTask.md" if next_path.is_file(): - write_text(next_path, replace_snapshot(next_path.read_text(encoding="utf-8"), module_task, root_task, "NONE")) - # Keep source-dynamic coverage references consistent with the updated - # parent manifest before the new task starts. - run_node("tools/web/reconcile-source-dynamic-coverage.mjs") - run_node("tools/web/check-task-context.mjs", "--task", root_task, "--write") + write_text(next_path, snapshot(next_path.read_text(encoding="utf-8"), module_task, root_task, "NONE")) + # Do not rerun the legacy hard-coded reconciliation here: it would discard + # newer explicit bindings produced by completed module batches. The active + # module's binder owns the incremental inventory update. + # The root is a completed queue-enable record. Preparing its context again + # wastes budget and can fail solely because the parent manifest grew; only + # the active implementation batch needs a packet. run_node("tools/web/check-task-context.mjs", "--task", module_task, "--write") - print(f"wbv2-successor-authorized root={root_task} next={module_task} module={module_id} inventoryDelta=0") + print(f"wbv2-successor-authorized root={root_task} next={module_task} module={batch['moduleId']} batchSize={len(batch['units'])} inventoryDelta=0") return 0 diff --git a/my-tools/start_unattended.sh b/my-tools/start_unattended.sh index d7c1615de..2cf22dfdd 100755 --- a/my-tools/start_unattended.sh +++ b/my-tools/start_unattended.sh @@ -9,6 +9,17 @@ SCHEDULER_PUSH_RETRIES="${WBV2_PUSH_RETRIES:-6}" WATCHDOG_INTERVAL="${WBV2_WATCHDOG_INTERVAL:-10}" WATCHDOG_RESTART_DELAY="${WBV2_WATCHDOG_RESTART_DELAY:-5}" +# Keep repository evidence on disk while placing compiler/transient caches in +# RAM. Eight compile jobs is the repository's stability limit. +if test -d /dev/shm && test -w /dev/shm; then + export WEB_RAM_CACHE_ROOT="${WEB_RAM_CACHE_ROOT:-/dev/shm/blender-wasm-$(id -u)}" + mkdir -p "$WEB_RAM_CACHE_ROOT/emcache" "$WEB_RAM_CACHE_ROOT/tmp" + export EM_CACHE="${EM_CACHE:-$WEB_RAM_CACHE_ROOT/emcache}" + export TMPDIR="${TMPDIR:-$WEB_RAM_CACHE_ROOT/tmp}" +fi +export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL:-8}" +export NINJAFLAGS="${NINJAFLAGS:--j8}" + mkdir -p "$CONTROL_DIR" start_scheduler() { diff --git a/nextTask.md b/nextTask.md index 3b1d9380d..bc6b309f0 100644 --- a/nextTask.md +++ b/nextTask.md @@ -467,12 +467,12 @@ Recorded: 2026-08-29 Asia/Shanghai | Field | Value | | --- | --- | -| Current task when this file was written | `WBV2-P1145-001` | -| Current task state | `done` | -| Parent manifest | `tests/golden/WBV2-P1145-001/manifest.json` | -| Current task card | `docs/tasks/WBV2-P1145-001.md` | +| Current task when this file was written | `WBV2-P1148-001` | +| Current task state | `in_progress` | +| Parent manifest | `tests/golden/WBV2-P1148-000/manifest.json` | +| Current task card | `docs/tasks/WBV2-P1148-001.md` | | Current task-context nextTask | `NONE` | -| Focused command | `node tools/web/check-wbv2-module-execution.mjs` | +| Focused command | `node tools/web/run-wbv2-module-task.mjs --task WBV2-P1148-001 --write` | The snapshot is informational and may become stale. On every resume, the queue, parent manifest, and fresh `print-task-context` output win. Never infer a task diff --git a/tests/files/web/modifier_reader_batch_scene.blend b/tests/files/web/modifier_reader_batch_scene.blend new file mode 100644 index 0000000000000000000000000000000000000000..f47dca237066b040cfafbaa253e78dfd353b5425 GIT binary patch literal 98591 zcmWh!18^ow5RPrzww;S@+qQkNor`VTw(W~^v2Evnd0VqpyF1-8U-x`7-8H*Q)x!9d zF9ZP$ZckEoQ|H}#?#yTGA1q#ps%M7P*GO- z`kz+ux!Bi1O$q94i1}YN{WiF zOpJ_0P*6~0FtD(s%Brdj5m8a!y1IJua&iw;R8;Xl05QoaD0F=N{qME4b=1hn$h?7o z)HO6J)adBw;`I#-`k0uQa?C9(#@X4~Yr$RI+}3^obU}Fe`0NV{3C+L;1_wWgi;1oO z*n=Dz7WOJ5Eq(msLdYM8B;k>f@7nTm^4F-Ss5Ft$(Ta+S&p&=b$Hu`CR8>&{Kte(i z5D^hcYiVhzsj33t;NTd34n0jxWMpJMRyH?_qRI+;>z=?6;M*?IJff&+i|;Qp4cl;t7dMNG7?s zx^G29MSsM`|5*CJq_d0LKS4pEC=?V_c5oylBzj&xet#<)+qtlasJEEdcz~#|)OoI76YEL*Sn4hU0k`FWDa;Au^W(|I zQaGT2;G;w$5g`$kqbP=gL}>6qNH9W32trUyAw)({Bw)mXP&8q}Xv(9^Bd%G%rj@j; zVYUj)I3KyDMDQj+{yd357S#DLR^a*fEglTG$nqd|?F*M-dyRCk%kZedz@GaAuj(?tKE$6}X#DyZf8Y3j`&)(~ z^v5rPKvRTpKLpqlKmVHg0t6O@*R(aV4H_VyJQZAC0oOTlxw16{EyalCh{TDqL zAoGqP5TpJk2CHwqMrz>h>7_m{ZYu^*reTZYE8eN|fGtj4PN34bdEbAY&A2z6Zv7rN znLEPj9wzH85L6BQ#CQB6jNQzgLh$obrY8^23DA$F2=o0TF1?MjV9qw6Y>m(dJ_D^3 z`KQ>oG1ybx_uWAILlAVoUTS(Fa zrV6-x3@sc>A-5Vzl)0ejF@m;0w-nQY9rvW@tDl&zv@U1Y1U9i>8(pQd`!a-%KrwBj ze3NuaYrw9-M!+l)10T!m{LsO&f{h4?)z6szyzP)G8&+l-qcD(2r4j)Tf^SK8sABP3 zuk9jRh$MihsEKco{RoWi6V5YfdfkbZA4K>$$E%jhlM8q(^;v#nZa%evRt@`q5MsR(?mNGw6kA!ut^=-d zirV73u)hw{(yp)^J}KV~TAys_F)YzveZ}lKw|xog%QIAS!F!%=db)JEB4wQ)Y6cv+ z@DN_?Ow6pXKcuF((D6m4UfGwSUwe^F6Fh_-&`T zZKj6)Su=1HTiu!aERdv1)S6}0N@Q6);m$SFjN5#R-CGMaX!X_8FyF>NXr=2KF=S}t zC;(uHRYWTb%$R>GVq}R&W^${XGdjt$R@Aj*8_fC=Ozdm@)8(SnjB}EAfIG<6eZ`;H zST);j9hO{4)k!mqhpiP@-qQP&tq&Vl%J^80t8oU*HK;WTmcqp-k{asu-NR0xkjwQ3 z7-(I?ghS87_^W{@X#-Kw-YH47Y zVBLWDg)l1*B4KHvn97JjbgN1N%f^r*Kl&)(Q8zULqJt2|sde*3Z6|nyrI6sH5^8AB zEc3aSAV#`{z<2%@N}B`Xg~)`^#tR_mJqrfFJtK%hgQ{Tq$4{ZqkhE#; zPO83V0*pW-^0>jI5x7Cj52tA1B%;x0r3s1^8%j=#BFjgJ_)H^+f5OSMRGPZOj0%*I zq9OARfN+b#wKF9DfM)qu!jBT2#2Hv*A|w1@Z+)$yqY1fufv6)&PkK!4eP2tsIFqqG(u5=ecv2y`jg`By{~#@TfQm{1}&9nkyW@Wizt z^fPgCr%Ut}86@l^bpev{4_>J*q#uO%Ujo)LwnWrSY9oJoUgN6?)^YgE-M&>YC>-K} zAWPhIr7r57`=91K!k$u$_B>4|2uI?53POUt7q0rQeD7>=PU`M_00L+2nDpZc2UVK8 znneJNKR@84#Xkbk(kpK-S}DYz8I|_?&cs>Lzc{_z&4LHe_1a!VG@7lVsnX>D7%GO9 zai#(|6Z!-xhq4R>w_apfW;u8}soym}H7Jox$=Dabq7VTT3^V=`MBt_87w2Dt{=8Jx z)t1Buc=M_7KNJ{ahP*q~a?T7s%86JQ>C-MgDiqYZXF&OsA^1yMR$sluq0%dac(YhAVHs(0! z$3jt1{8IxR_tCp}+ttGzY^^GRF*+ci-1@De;~cacW0_8helFPL-HFT7w_*A|%K?6N zJc+Ue4qj!VpL5VIyRdSP(aKXYuVlhsTSPlgpoTciK;we1aAWYeZ(?_9&|uxr(RbA# zbw{VLRI8QsY*Oo2+Z|n9@mBLld*o*uS0et&W0ZOyY#*uCM`znzlYPD3`tJKuxmKcP zt_i4GFu#~d-?HK#X(5O}~w}oYPvdI*Zs2Z7GUEwoB z*LyoyL?Y3jH0vpc4?-#Xa*|f48(g9tK#JtAZYdiM!u!h4mUsy|H#QTd5rs-B3CkgI}{*lC9EDkcr*1r2{95p-ZBpY&oy4G zqBzLhbL##C%!B|`iBm0IUnsD=3~0f@TXHacw87N=#031?z`=dbqoV<++1S`pDm->7 zygdLC3?Ue0S;bM8Vg}Gh*h$6Vhz)q^>WGvDr?Cz6^@Yr3GlUGs6B-^^dP+-sJB`x? zr-}6RkNuSlBqCp5uF1XLluKGh#S=w*ZZ4Yo)K;KL3U_J=UxQ5pYAC(FC3;43S8#N+ z&k??7gkfaW=$nD(F-U;I1cl#bu9u&Fe-0IttFQ;M- zQ|DSoQ!h^pTTuFg!%ZCOsE`6S$gkx&?<#B{ZXt){uo_8RLd@Yu>m)6T#T)}@YOCFFp{uju2n@B0$1TK))Kmquh|?m$ zo5OjgKL`yWbiO9w?GXq@Y@6a2wKjsCrKqw-wIl~;zp?2&a2%-mZFSTN!aNbyQTDdr zX`}$=U?Bk_Y(CGQTB`w)d0wDg5`IvwwO)v#UvPi*{yTSq5hH%3J z+4M>kluI~}23;)tOtdh>*uNw%{i&Y?DjLHmRWYe4KZY`-6O~%XAZX3C!HJ*!73L7g zvVVk?FV|7jVhPgON2F5NO#ykbHh54Iw?aGxos!7=^I8^{{-dP^^JI+riWo}AU)LNz zEBVys;uYsY@}5a6oPkR=!~2w|Ew9aYywuWQqatk6KhBb7u}j1&fkMw?-n(g!v9C@h zb9X?|GMVIqPK^dhTLh%yy+KMad>ZtRtDR(fs&HlHnHq3adboqVNoP$P4j0EzmB_dG zufxbFAi13U44@&ueI;Ms=h2bPu%YZ}S-+zxFKOtf^GJ1-ZvEkKOPyDXBJ7FHv5It32O-kgV_5@%(W(YK92?kFbF@BO@>K*gynJ-(hSh-DR z(Cvw6?!bXymcS22+xP84y$YLgh3&uxjfbKwbzZGL|KuHNWqawa+JD5CEPqj$zZWwz zFG*Y>n?z{GV~I5XtitX%GuH5h`j!q$mZaHiI4jkcjP0dP%gEP=>{HOY>D`0v#UF*S zM~78Vs~Yvul8G6#QjStsiNvz)&0zg0Eoz_=D+E7T$?Sav@J^Z$qUF`i$KdGgg*=hD zS?~kntH|mOqT5KmIdxhwcT!{e+#Ow7JzgKPZ09X+TisNrj&0jG#I|8N`iUzM03b4> z%qJ+dpKZ<(WBDX7eSn?1^OM1AwAng-wNL>^yg)>Ou~o1~x@L_RZ;mo=bHrIe$4LFw zmo$}n5GIL!2OmanVI-=Ju(AR?iIoBzGS)Vm*D{y_mw?>IPYy&Zb@YJ&T`?vSIAhw2 z6+KI-UePfkApo?H024gkI44;d8@!J(asxlN`Sa2GH4t|L54^63@3LJ+`GXa{aGjw5 z)UcsF$C-GUhmWhaGUiG6+g4n`zFesE{gSBY?m_oL=SVf2i z{$8`M0`p}q_v+|})ca+u*LPu%&wH4uK(gxciD%+#cP-h?xc!h zS<;S#VeQc$V2&8}xOtvVu48AGj{fs7x!_pqUzG+gQLiw_{rV7V*rf^mC*D){Gr^DN zBN&H!Dzd%aGXUbouz7#;Ml0_2!gHx3rS)CAyg@LM%4OPUW)ek7dtb+xJ(SLGK0yq6 zo-}}An2t2#_Amqbo<=V0>F7ls;s02OEKq6_z4wy6S4(Q*2~I(1AcHbPPkbM~ibZCU zTcs+IwegBKrodn0_Yrkw_MwE5 z%%H%WH{lKO@%--`#(y^|5lFeagkX6} zF%ac~VFK;RJptdlbK>3UC*SSy7c>NpfepZQmx5~EDXStyv=xTq>BlMJ=r3mSc9Ryd zbtAh9-xBQ_MwdMXM}~(=#EiKagT+teQ0b>I2YRYQHFQ&&7kUb@oAD7}BIpAN*9VL( z1$v%g<9V{FLwS`&G4kc5z~5Hq65W+QW8F3CVjV1KvhEis>)uu$mf!tuoDvZjzf*3) z_GEXZt1vg-Enq9Zvpvl8WUtTk)V9#!tL7xWwKYZF4{Zm6rfEifR0JNdpFS0YUDuLx zyV75~T~`DXmpDZ|)lAlA z42abo1lC(qL~5>JXs)Pb6i9b9Aig|Z$u{54hFS|iIt-T&LsRCPCxXZUORja7=N@&n z^LBMbQS4kS_~|j(kLgMmdH7T}z9Bg2t8z$dTedtn>E=xfkkB6D@e5LGlJNZ zRb-cs)H1@vON1+Sf zR6Smu1Kg0qTc`ad3=F}zzw6gegjJrm;107gWD4W~f(7ZJG*=A$D-`^35S?URlERLx zmIE%|Tusbx<&=GSoASr2uvMfX2nM{psW4n(B&iZ2WS*oMgxN$on8U=J(vOZiD;4HR z)KhxH*xcKHNDc7NCYxx~SZMbY&8XV=J-kpMXbn$+Pk;6pGVb{S!}%}wW- zV?W)m#^oqw_g%-I%F4d~#f*!tAwiQb{m6mE&txrhXO(@s)l7<`eU_lQ&*3f$_Qdru z4CEvv(VRQ!W%t3!8LsboWcl=zKtmg~gS00Q$D|+%0#b!-UUfkPUHt?OlbloMSx~Cw zGM!|@8PpXxo?L+ujg}4`?7oIMAH>SsbUgq5-*`Y+OK@H@JM86M#$9E>C~ET2AOcC{ zB3C^{NP`eK)3hdoIc2Z2#gftnYC))c2UUlZKzl*dgnf>hPGj>X=NKKBpxIn3Y-w&* zS#fSIRT~tH=1(NXsLxRhFdN^O4%VeIBz8R@0so1@IGC7^?NlAme<;hBnO&Q)ilIo5 zfq;m9_Owl~47p&Aq-e~DlO7S!fS}NMqOhzz(NG{mi%qeRU_u7NkbmB0g$*Eu7%>TA zmnJ9X0t4Ohd;}bfA?+r8WgwVpRUCPD%$ifXVaBMr5(zN!J z#j9Ff3GnHU*^Z@ak;KC|8`VJq>cQV;!0oO@V2g}41$X=%Q~O0Xw0 zVLm4pky(=VN~v0A^K{XNxe>|IdN*5ZWHsBLdKi*;@$4^I*|_Ag!R?jlnRP<@CRHQ6 zV0j^OqOa3qh*%zJ$^6%`M80zV5WP{I2&w~30y$oEW#MwQQ96WfY6{2b%y78>L6I?PNH-7WAL5TxTLjc^(u-<fy| zZW|tQ!z;3#lGjym0UTpr4r4`{1)))}a8qGG+lu_?RC5H%G~)`{N$S#N7hI*u5wK89 zO;w)QuVxO*<{tbp^C;83Y9wf$H>6fznBFfJ;ia{Golh~%Kch&L)(7XDUVmF8$C{vB zbS^rhOG|usYk)Ruu$Dkpy-@5PAq<`EGRo|g7Yqk9hOlj4(`V!I*dr#E{?cAT?d6yu zF`sq{@{(g&TrJ$Z`^1`$|6>aFX`(X2IDOd2+KXy3c4c>;d2Yy?Nzo)EGuIf=`a?Pp zL{?Zhf5-qe(5*tsP}t8*(O2K@%&>DtoUu&MeA`>kt)pqpN69U$EEi$C4mH0I_gLN8 zh4Zo>dv4oxqHgyEwpQaLGv(g=CB4E2jl6c~>^Gvo1C#Rbsh|OA*u~x{_N&(?vhN#S zQ2-IF&iv3MCt2Vo_FMLlFzx8pP@oHdo~4(TO0D#pPj)){IR)b_W6DqQyJ25H&s`G}z6q+rJzMFypA`otdo?-u1^0#c?Gew^Ob%Df&3%xPri{4-IG<~b(T1wkAP zT`JY+c$2yvliZGZm83f*d*;CFR!C=ZqX{u+?^(B|$6{I@ew7pO%7u#^njj8c{ojU? zOEikAVY!byggm^hrVzx*w)z{oZkJu$o@UyLUUWw^Te7-_fVO5J>+5@1x3PSE0tT6# zQOENQ*OrT39|D2bRc$x*fTDtqHK~|+X7WGN!F#XD^~$lcHI-hJN{K#H3pG0#!R^Cr znR5v_^(ox5wpHSUcuc92)v{YECeTfd6nvm{X5CzCo1n`wRh9XPiyWhbfFXid}jXWSh*5I6D8ns*g~*9MYN1-lePioVaIa=O|!1PAELW>zo}rMhkyg zWgb9T;wbSD0fhyu` zP0m-gj*8u4;4f?I1+CGYkq%zlDyS)lz4m;YY1-CcI^qQS_%1~^@hQy}qHhT+#DDOB z0u$HhV$MuNkYBn>vz7Pq)3+1)A}25w$3F25@b1UH>ev*`f`Q)GD7PhY6Rz(hYozh& zRJ;z{*gd9g)-<25*&F(5H0VqW{h4zV!mM043&5A>qR1;&z6Tj&+_;?Pc9_Yn3v+WcXptyC!!rL14EN(`u&X}BGIT9)R@H5d* ziUYq(!`2)eX0deZRtdBrsR(o}zW|jG$WA)oyN%fI#k9l9b@>M1gbl2cbvPf)8Q|*V zB;T{hn0{zR(VKO#_z0GXhvOZH#A}D|v>tUcx}^)eTm;y*bR4<;9&^{^ha^^kU>C}H zYni3>>*gKDZ&m8B#wS1x=eA-gJ;_)bIb&p7Jz&?AXcg=Hqc+16u|?N`lI|AqJ=bki z@aQD_E^kMq?tpLa(0;`b8xd5~kzHR;I(f7vF)BXm6b00KW8;ODt;b)LHAoQ7fJITcqL*gOc!?9Rq)@0s<_lj(Ujo3r$k> zq4~b27RJEF`hEMyfqJH0z4z_z-O}fK>n?M?(=l-%1pa45lQd9+q)qahJ?%YZRTbf& z$TA$iF)DZxhy5`60*WMvM{9oqId5FBJ7*1@0tX+`T9%;v%~nJNjBT7jZ5T#k+!$r; zj0-#i(y$&RHw1cj&l@O}8=}-0n7(FalQ*qIg#2K8xs7-RWD~*8W%@PGhJ#Lv&I77D z^Go`XIA!=a#yE1Ljo!NmkHqQg;yFo764%k`D!UPR8~Y3=tDPgqO<^1Ot_N!yDtB#n z6i)82#E45)VEYo}iY;IEjy2d(9yN@fTa2n8xS+49}XSWrD!M(Z=l;BR5 zAkyM`aUG{RTglY>hat#jhx>(>hMt|}k~%JAeJbBs)e9o)Wn-1$+__|?CWGA`(C4=W zT^<++s<@7bwbJJ7iE3bNo5#BGW|NIQ^;!14ndX|wGSG3yUH=-~qQM`L@P2y1zt|i78RsDTEv+0dODpUPaWzoVqVo_`UURUd{H{4;eqOR#7RENiYpF132yzNb5<{Vxm) zcoUiZbq*5~8=g-atVc+EC26XNn#hJRQisefP39MKIFuuFkr1_rbWvJnuJ2S1`UTS^7#t)`3_2z4pvGbR`{7i?tQ5KwGf?_2PXT zsxKzG(BSkqda3%9U3CYw$vH7LL#Z|)s#4Wgr_cdGOsgxsW1CvWxl5_;F1>D*(X={$ zv%GE`s?}}VnyxO&@pT8$jrP^%0{q5m61jtj^(5(wgP~)|!r$7zy-6Ciq#TCXj-~|m z%N925%sqh9`BNwhArtY3l(=?n2S&EPL~OBSp$_l_wR-0uw3EZ^td+095n1Gvd(d|BE{OwM!yAc-OU0UXvmP@rB?~BPMOH4rvIKDY5ElK-Y^=KMGinN6on@+_zi_dl&?GVI?UV?IWpd59r zIesPjAmB;O1pK-TvEmb<7XZFp-R|9hX7cb{P@o~4nqDMC7k3m0f-|=5C}3i^2rdbD zUxw$b%Ry1c(9(iw4y3G_=7fj{9rNgFe&sphRO`tUypnRE9iEQgwQwQ|AEJf zH}Ex^|H3S(vxt#u)jGECOPx9S{>57D#VKji>%m{_g7mun(YH)RWvy?LxsR&AfZdf) z+m$UV;{aFkY#K%wZVBm|mFjiOUN;Hl;npyS6n>P`tQ6U58Ld0pf%j3Z_k3|@&UD7~ ztj-Jei)Q;DIunci_G}@1Tf1mLN4!opce|5*EL&O-AWu$l&Zs?A&F^f(a5fsr zhvDE8S-SahTz%&*sivNkErZ0&(A}$6=I}B-WuDh-RxBFqp^z`}8;|>DG21>cnRcl- zCTXU(=ud#GSQ9iEz{T5+Je39A)*VE(XrOD|VCgpqZ`%OWC9m+V9$hKN@VZ5Bo%FL7Ns z?KQOQUC4r6??e@u$G)QdAsOOZ2CZidb~HIfc;wy+E;K(HH#K2cE2P%d-&G7|Ryd&% zwPDfiGmG!ug|;W4aQR~TA+>wCGiQcr_)Rs7Gq@vd+{Vja-^u=QR4?6cNw&z90*!=L z2ZtTg_cvGI%HSAx6$7tS4H6j^KWiP?GA5@xUB;PTJXPeZaTC5dj9b?rUJrXS?LQl% z;{btevRL!eA7&@J@~$yGI=-MELpW`nYP4zTTT&rR`lNJ%Zi@2EznF0RU?O0JOG$JyCLD~|1*dF>1dV$$*ZuaHlPW#{k@60IXkObTyDGOu zEb;D6($PYrS+!4Lavft6J(~D-c30=#L zEex!A8??ryT{{FG6CH%fZ)ifsa4rQ7npJn%$iou#v!)!!g$?Fnr|o(KB7lhG_5E0` z*>Byg^Rhm2mJ$r|IcMgzZ-4r^JZlqXA5h;YyPA5;d zo#LrHL@!ut#cL6#%gzcFKJk_YHnd9kzRI>zj?_g714s4q#uY&5zf1I2S%9*W*k9en z$KNAJ7NGKaa{CifZgy=;AW19ya)mNhyAyhpPyR#@esZ3fH_GpVxEe63=4BgYs$yJzr$A zx0zbmE3Xbf=)}`Cgk)}Tody>DLAJC)0c+FiTCxx34#QV0%eIgxhl{o)B0c;r4x^g! z5#_ccddt%~DSsbL5+aJEYjmRupav1?TK#thbqV%>V?O^Il9U|AXNbtQ{@yYpCxdo%T3|K|F4$@{rNJ2V4WyxZyfw zl2$V`2RerAVd*vq_d-dlihv?DH|(#n(0d6Zy*W4rWwRqua>Dv0$OWd|hWhW!r=VO! z_p%HtsxE_shdK>mzGRl-Zu47f(iBfxZf-j^X8bPU&p1XV9&_pIPG`zDU{bns(d3=0 z;7*_&AEM3(xH4~eZS%IB_|(yw-DeMDG=Y2GNdw`oCfYIi&3M1qn>OT0 zohm}QG(Izy1a$WnY+us)Y3jYYbWAO8@tcgr_9&3)GI z;xhe<(z>3V*1q1OTt8T^f59v*ur3qm9aj|Rntq1nZ8C2+kEN!YtgWaf^U2*7_Z>Z_ zp^nHxDue|e297F^ombFmX&=glkJ>51wFc@6_8|6Qm8K!#(hf|pbWfze?KHpqY(I+N zj&UI?($3M{pCG+LSx*l)=||Mpo;B#UY!6*00H&~|1KmuEwfp~KnsnOxTTx1xITgr3 z4cb=pcf^SmJ#Otkys(U+6izZWXmwAvjNwZ;C1onXN!xn72lBR}y3OfAS<@k&(y+8* z*xe=vPP|Ip(Pcs5=u%G$*WdYQx(rzAuO>|2&WZ_PUhn()uS6cKH(|<6*PwT~6XT|v zGx;Voi5Ee*F;j#oS^B@bH#7GBIn+gPvj{M)jI3s{?%5H+g-MWuG@i#Jm|)qMrEpy5@lHQ%FfG|ha6`i)XCEVs*?gD+XDn7J}=fFFu_bJ~ZM zCh@WX=nEFs`s2PQ3+eZ<7=7e6N*1}aOegw2wbGJ4x-OW*VPv{EM=Cwf4>_a1pn9~2 zXpKG`8*CZedo|55*sV->VDL1bzVQe!g0&pu?Nwy$yD#8Y&(Dy$A+v|vA!e_5VYu1{ z0zWrpf4P4a3fz{7heGh3Q;5g&nNxLfLMMo;H^XF()n+ewACvu^J4-*0d2On?_E*8@ z;y`xiB4~5RI(;~N6r{%aDu5AdIgT`O>z1N$koAeIHo@fK&Ph2#nG|`UN>Mo*tk12l^dNj!uvHw@S3RhJ9gmT$W<-zv4&{f zuoxbfIvg`}-?Q31#jN(#oj~q%D0}zfE`h!}L{>2a zNmLF;Z$4l3)Nvwq^Y6ODG@DzT(SX)iW*$2k)cR+vGUP&fVO@Pn!94?6aDCR%^3>&9 z9d)n2jTOezJQdWOX_ila+vD4|IPyNgp_T?3o5%=3{N0$MQdW#fv2(u(gg5oGf>}iR z?VPV+xhZTirKT?g2w26R_kme$w=dSJ$FJztUl`_F z_cweLGH> z^`3B;OooWlnmcLHzD7TRq!KSUpAnN` zFzV^Va}PBRtg$6lD1wurxzU+6_!{4f7m5CTnznCl9xR{C0UH$2#|Bf6P8#@;po#Pn z$}QK>>!a9x#z7prI`P*rgmX_J)~BQ#sX3m38I#yvd*tAz|9HKzham%v#+Vfn-!r?c zNn?}cSLQ^2_K7!FX#@EF+4=KS2bBu%pwPosxMc_yQgGg1bqpd@riS=lUi}W3nLOM8 zwhSNVTTe4XhWAF9?SM~Phef&Y;Me!$^$;A+z*@$X5oDWEH8c==mkh*aY?*O znKFZ&s=qQPP_n=kaN{SvDkh~ubA3u##)c8KC~I40Z=tQ)?3@yspf2foK1@Q-Z@NHj z>}gx7bohUW1>>|o#;~gr{9Hgg z^p)Ud$A0}~E9LF&U&Vkl0YTXMuy`I=fw6zWF*H!j(aE>|h#m&R4gp2DbQ^ap#q}YD z6O2Uv{3lWai>0Tj;w-ddTn=b^Y}tRSl(-oX?W>Ck1LRG zr|o@IMr+G;LYwVub;{bhsJAu+&XRkIpTmqt;z54C za5@gjII0QK-5mAm@kXb5(Dl54br-(R_*G_sgJ({c#%&4DXYw0$js0-<-yBGik9%2KoPTi zL>^R&u7a!@L78=JWgoQbWiCz6EyTgWO8D9r;oMz)x5kX)@iRdUVIOZOQkM{d9q@?5_WtMJy zdvuG65JqGSpk7kjaZ_StxADNLfbCyQA-o|KWLc&SZL+|ZAPXS9AeLm6sa|xZ2N|P# zvO}RevPHgn6a~yHYVWJ=P3N6UHHDS(N_MGa8z$|TK-jw(D1#ahvusJ@jav(*rdskW zjdUjiJg>~aWB-cXifN}UL~ThXFb1GK1%hORF_>@zLLM)-%bl;e1zh|8_yUub$oflJ zQxt4AX#q(QV}Z-AOC3wdB@2xN<1r4>272?A5=&WVaG%-6AmeqTx2qGQW^r&}%?oE< z&w{EPI)V;jv&fWEk;p{bQR3IaLnuJomo}6Q_?SZx=O~-FcjK!j_hO?Py z%g|5i57NN~YQBuY%%!UlY~M_v4&+m~O+MG*B7|G~Vd1pTVbtd$CHv&6VQS;DN<6{) z*@LGzbp25R{?)mYMCm%Tr}(3+z*HWY(^?#2 z_LY|(Id;qYR1^wFxpGyJzp4MH$!Gfv zN4%K3X4k(^?wIl9p$Ke9QVs>FHe<*a!H2|ujr3jSM53jA<)@expP2vbHK$|R8;~xE zBPb~u5ztgPq=CW)J>{m?Ny(O29@FXiUEE7Rs4kNZ@5ck6^O*~P;F3VJf@kFuS;Db# zfWa29s~yJ+CNl|)Zyj@C(2z=Xi~&{0raQi(`ig+YVbB!FOq+buXPsQY#&{4M+W%uPwI}^uUO%A3Lhxwz%$+Wc& z0G82dXfeY7+jMGyX8h=aA=J?(gy@F3OmrP8^bo2+DSz#i58xaqA}m>$LllUS|DEq8 z(Or|o+d_eO8seHhSP%qizb4oKURJM3bQ(V4dHfD`OU%bkPKI167dUT|`Ny@?1WUBM z6p}=L1A<9g1qmlBgo2j4mF885LN3w^6#Tb%K;wXx(`34{P+M>s0WVG8Zk#j%RV}n; z5ZD4%fe6#pY?L7m0cPhI0*@lW=kNKm2^8@%iRj!1anvm-bMScVcvcg0zWE44bu;)F zREdzIsck_KZC+9pva5ppTslK}0t+rr2v?MOJ@^XZ(-JvYHw4feG23+Ry0UmgRX-tC z1~e{k6-kw)>uN66{30MU)n1h4B=VSR>j-!YWL&Es{m~%(jes9{1!TOK>3k69*rJo+ zB4CL64hJiUGuyL7^IGf35gQebJB5$lgifIqZFjv*?kZAl(PO^Hg3I9vo2ETSs826! zBbX2Ty9y)h0N?FFzs+-Lkk9v-Y38rzP4!g=S-s5lGeo@GXq z1@Y)O&D$1Q>)<5s1I+i zfE+XdMtteJq530#yh02>!fSg#zcnLbBuYf#?^}x&6VxXBEKN$NDBUrNZy}{yXU{Vz z4Z*X=!glBojv{KLn@NB5&JJ;gF(6Plo7RsaECk9iAdxVk_Tv*|p~ot3V~tiq4cdISG0nH#?X=vRsw!)B`p(q+CckK&|9oQ4FZ}%Q7Pk)2qrpcFAqIXR27Vt7_zW;Wj$jPyMvKfXlE7i-`S~L* zC?b~4YPsD`zcE+~P2f~=s1ZXGo_3tm{sP!P_Ks1)Fzu#~K5xyxe+QX}4@A=G_2C!D z{tOcsurQU#@5e+uODA{oXXHhs05Co(#q)e}FRwp?QYXgrw3_5$_0>Q;1}4u?R?Y{g zRrRm`E^1@NuO@4qTe-+WD!X$gg<7;)4`iOrjUHRd9gaDA9NXXLtW+SjMa!)~+`e{Xyec zq+z5tL*xFGvv1aA3!nT{L`I{Lg~J(HP$7gqkI2>Q>V%sJ5Z`xLJ}} z9>=f?zi`>UE?Tl~ySAga*;QS4n{M?bQ8kTqikhlc!2Czi9ASKf@iHb)_BVFn_I29} zvFlb-F*s?KnJBQJC7mm=upii0l3!2@O>_l=uo14CbDLvxYy69PayzHSxip8uIh`}P z#J;|i08zJc<%ndJBXiD4#Zs`;n_a0E{>3GvSgBQNOQ}++6dFruDHE0|rAVpAaMb($ zVxA~Bs*Pf!)~Fq&dUYKE{?IWW7!oaYD@UbKXq1jJqsk~U>RTshphjzID20keJUPGc zd!qlq)@^fM*)`|?K&TC+igVBuMNMt$|3Ih`iaZez>g0c`F&|hjKgGY*(^Jk*Pfs~N zJw4_8b?f$jntAa?w|^ZNF=yxh-P%rPBsG0PpY)S??rc;(kx$P#_805GF^qe0F0RF~ zVq9BYzp;#4aT}-NQXGoYI1^X?;vO7{`+p!D!|v-M0rOpzH?FV^z^HB={KUY19B6Tc z{gm7Y`-OS=y2OCLu(01P?5Ar-BrBH9*=cp!PO4Lyolp&nd(5(RBAw3u_u66YdT|q6 z18|46>!}c*A2$dC;f`8G^4r|u~g8jtAe5%$Ku**wT z;tMQ~pTTDcIVHh55k5fM2}w7v`fXZC000C4Qy5S%6bN%z$$|_@mfT}4*>061J}^yWBy4A z`6l7cm|8LCQcQgHKPnBl^Dnz8anGU9-DaW(M2Af@D%w_p1FSW&m6u*{nQRrOJU29rQq@)JP9-UVWyqriijweMUB5>&-}` zzI!ldO)5o}2?c;YCWX{ZU{zDu3(=u9&>vMQ3f?Nk(wDr8%IOVvu6dwSF=fTf!Jnwt zBv3ge!i+KAz#<_36+f^_;g#ey&Y~m7o}s59SjUv9VcJtnXPG+DbJ#Z zc$7s{)Z@8ocY>GthB#EIFrbYgHl%v&$ti*f8_CR}))=i*bMN$k8W<^~8YHYTvmaW< zxIAN6e~qI_J!X}y?so06`z_o${&6;WugDCnH;*zaV>h1iDAPTlYbF~v)~Qk;jfo}{ zCsMhjPRVB2WaeS}oHW+)p>H8i|2}GOxT3a4cD^0;o=a&qzb!eA^BN>go@xT}EVE-A z2zVvGLvL2<>9h>e>(D-u+1tv-%V#ED6^E342jIM(cP2Twn}5 zqWvdFNQ-p2Nv9)U2dw_N4;Ly&bd&W0a|q$ucStc zhm|bTq!uwucA{bCo*Ex$T+Ovr#wm~0!ZGkJ_YJG}EFNfkCz{?ja(Vx3Wz6wL(5K z*hl8oil?pyzcZj&ME1%MWP8lFs` zg5S%;H=|)@oc*W_V$4!^v7Ntpde2G9`#(LPE zQxcT)Qx|k#0C1Kf#rt#Qlf7t`tklYnK0vG}O|D#m5iSPp`j;%iPDGDFWE-TAuig$H z>VED{hj9GE4-U_jEV7vNcF68~oJcFw-Ilqs=?d5H&l8;WQ~q0}pkf%@=}W5yW6VOA z`Jz$|o=mC9rB10+3GgryKbyk&;b4cD~EPFqbaqpQ&G zQ1ck2DMOxx&Y3D(~K@1E9+RsDlx`#!HsXxoB0BFkOo&RQH+@U6?a6G#&AdY3$!Bf z5ewYaphanE2iTb==8f~%cF|bb>|=a7_dS+EC~ytQ?^ubWB9S~hamd>0!sXR=?5w4! z6h>ed*d~UklhH2Mx87)QpS(RmS4!X3#n9zt#}5-YQjS}tT+(Ov_by4MTrolZX`v%6 z2mDgeziIPc&KXdX6d!$8aLt*|U1vQ~ZR?HHoi_2;NN4x+AFF|AMdD^O2_?i3Un9^%nbV@e$W^u^MO z8;rr?Y!I}2)N25@mMFSlASMTsDx?ynFk8^vH=tkuVoQ9$PiSK=-Xa08b6~Z>$(|Sl zTlxbW+c!EEV9wO#xD4RPc^e_S0)O*2WW+A~K@d~?Tg=$*H{8_^AE=^w-B?H|Al`C{VLg|u7H8lRlZU2vu90X zCtX_O5tqSwss4qhQ|RS=e$GZdhXr$L0h$!!`w!#s7W#Ar6E>1f@^F}2rgh8{UtGRl z-3IPEYpr2Duv|eW0^EGPZ@v_5kF|B!`;RV|j*XkZ*lTxqx~yEm%F z=S@1*!i4Np$`ylBqI#zy(h-wYo=W%K_H!Iw{qKB5=SiGNkq*lkQfc#wPuM0952sQm z9%Glaq%HJjDgl)WnHdY%z1|OJN@>?}(bs8cT%1x+Qt5MD02BT$2v)ES7oT;k(T)># zskg^QUJVF^@}A73&c)WI+Y^ovZXxCQcvRDzDp*wE_Q8*;`X_q!#4QGfc3qjEs$7-|S&NJC0jIK77P1b$$?) z`)+E;7*3EjVKOv@iQ1QC<7+PgVvnN2X4~T_;S4PG8@&m+q=@Y&U7IYKO`d5Rwdy0? zG%Qw5w2i{Q#?DdPyrvlRZ!-ckjNhgArKp1$Uc3i=&O2(P>yH;JU+#cWmclJ+a0iz3 z1$1~r%f>+;jB%O48Ca5$69Ykh^4>myt&|6V_xFZ-EEA~Qg~O(q|LuzDe)}YP*AfVO zqq#c4*HSJYK!o|%`|p*`&N96b<1_lZL7%!kU%U8`MD)6#t$eMe^%Vsk^k@8=srrOp zX7mH!O+df82{)?r%nixg>{)Ds4f@@!aJ1HQycwUbjQA9d6z4IRIyhfOYnOP1l(D>N zLC*(Y%d0E{8wVpS1tW|f$pbnms#gLN#%GEhG+>MX2F4rF3*p$W&%K`42pZXL|7;!J z*`_*G20APE-2!jD-YbnhT4VE?JMUeK)fIL^ry?)WEd2P7_jbIE*s>I0i214N7;g$^ zF}6N|TIzyVXN))hA4AQQsA8L!)Je}t8E-J1(i(Csq?Y=^mW=-rIDURQF3ayM>ec7G zl;DP=Py=s zxG;k25pSD-Zh$uz3O!aohn>)y5(liGsp!2rL{5WV8{y6Sn|NUDBgk^mD_M)q7)&6R z3W{Jgt!1RU`Y)$Di2f1OZz?pkvG{4ovGcTdDx)9w%?_sVl!MiQVYKb z)}_Vf%9$6TfNN-G?y8KIrESm)@X~a-En&D!*TE^%SPC})i9@>yu}9)?;BMoW(f9|t za^!#u^XEbj+g{Ml`0o`vrfGU>DHA6bD_Ps0Vsyeg)UU1$c5q*>gU}GVxnr-)Iij2t z($RB&*wRHNzvb2luaw#117g4^@6Hb~$Gk72yZsTCe$kjzh=CE_bL#EU^nGFZ8-ZR_iUCBt z!mNtf$fwsH-wQh#cYkPvG)PsH;Fq!{ljEkAU^|rgy+vl#itMA)wkw9K7NG&eae+saqQz6T=ip=qhr1)@ySn(S^gn?2sY%#XbSSI2Q9#v2yhqw<(z zf?AsHr;MjWi#KbHQLn#qJMiUq*V(xZ{}0gaseGh{eZ+;;N>wKmQr#;#FHzU=(DOTv z5iw#$G1uY2@~3dUIc`LMs9mLdv`vlg2kK zQe6Zvldx)S!)vl4_EFxp<+5%_W-j3^gN1`XV^jIJZIv*EswRd)LA*@ZS z*_L>rjdfW{IZUPulK1qiF)hv2pG7g-=c@R~1I$=8*L?#80_-fU5WdEmr9HT451g1> z0va1IrRQEH`M{mWk(n8-W;39aj9sH$XB~6wV6Gt}PW#MxJIRW~>Ja{xu)(BkYc7K@ zwzxdFLqxi4p}@$a&O>Whq`90F=LI~JcB>NHZ4hIN+g76W2>1|xmZ)0^tC85SbzdEN z-2(wW!O0?Jkxl##wqm(C00Drq&ZKAfq3&ms4(};ovKv8I!LW=mkrXM7lOW>ZLqy)y z^(P77K&V zdSlhs@IMgrAw7RX-oVqxH>w7(Hqe!?pRBjNwQ~-x<(5<_ad2jDJ44@O5QJyvthW$A z5xzBUm8LNU+lSPiOMnI{D8YJD>z4Dj4ub*4(7Pn9peTGQh;p;D0%D$kjFEIH8oUNy#=<5E$bF)Kn zM~Im5z)Xz4&}O~04#n0Jiv~v9STUEv1&A*^cCzW0*2snQHrpAy0k(-Q?|sR6^HC5e z2psea@h1^M9((>wTSTsdXJh2!og-u;fSC0*S0GR{X8o8)a&lrrgI!212<2X<-%>P@ zIX&}p6S1~elTCvHVQC3rNIQ3Ex-4u6ushQIu93WvEwSDX8+sh|j2O59*sPif$#?Xb zoiq-}YE1;BE zb<>7n(^uWP5v$|4u639!w0w;X;s?=BN8nb=_N=$eJ?f44PAlrW(}o*evoj5~8o?aS zcVUL*8tia!%QT?AQJYE$TF@u_>sjO%RCUtCx=Cj{*x6!>$A@f&_x5Uo7g0u zV;GI?`AoycwRhmxZVilLKHBoYO%}w<86+8R;N>Jcy{xY~ZmbUr%ip?5s-=I@MW9S!9s6I4H*4Mrvw`QQp3WHg*g1`-9B)>_lC7fj2}q(qFTo zSzXionBU| z0NE&VDB}WYMSZhOZLB($a)qSsE;#a-n7xh3@Y{EVI%C7__?Ag=DR@gqHSUlLnYAE- z^;hZ^v^L`l{(Nz7159e9JJfEg3&KLIaW|iK7n6a1r*xg@$Z>q0?)Z6L+DFFx5rR^& z4ZF|xQYMah&yM%HFI)Q*lT|?&6KvP~e>KH&jCKTU^Sk};Ibwrg?rA36{&6F?h+|Yh zzMku6xEO?|OS{6|k3-TEodkY2kWYv+I!L|Icb33~z4diA!7-6@M^nS=p_FvSewWaW-b7H*U>p6L(>+Zi*_`r;T5K@!QJI=Fm+2 zXa%vTgGeyUAE#<}3dRKq2A2hkbgshs@$+Y0x*J6FvIhv80Z9Uj(yB3J*drf5 zEF3s;h<+MPuvXABX3gtfd{K~%V;~*G16EcTInMTlaCI+w91a{geNCe#uX{W2i-L{c z?3XWm9V&_3XZ)dHZKFP6?H-uxQ*@@(w@m>_lFr4(O_$4`Eg~nTOXyJ6hV! z5TTAEQ3ss@B4y_SqoyNMbP&%ni$E7I#5aXhz;et~M}!#1Kv*1CL?;0P6;wcsVcTPe zH-_2gA`ezajy~un_O`4&gdyT9M~0Q-W9Y)KYwP&{2cv!2q##1rBOgCRI20t-3VOz< z?u?Itu**Xn^d1EWK}7)|#;n5-LV6BHU|Q9-^>imAc3m!i_G!%$8$?agT!?pfK-q14uWh@R?>Zd@Tj{fT11qE2a{hewe2i(HT2_E#`t zTT{B-VrEaZ$9HKvhlG7}7HXRI|K* zP>yM+S~0AE7W~f0dfhTCx0P|#stH)B>9Hy$8{)wjRQ+)nLi~2stlNH}W!EmUYI+Qd zp2eUA{?-8KVNs}3MkQw%CqdO-^h zTFBaZyaE<}2d{1$%F3=ORMqs;ke(+{&9akFjwPtV7;e&nU#6_rUBYtP2v@DDWTmD_ zRVmUC4+5!FJdO(STTPcqCKJilb)!fH*#Aj24I_P!XBmcL`2ByT`??jFZ5#FfU#OO< zl|nHAbMzm$sCX`llQ&kvih~U?fdt~;pPi*+*1d#f+elGgAFk@QVNih9n9a0R z`wnDKP5tIT0ctZ#roBCtPvkN!n)r7zlS@3YAVO}gUW72B%nL#VG* zm@y85YQvxa)qZoJ02NIDxq|;1P^iKM_TTf^5UP?0135>rtJw9gd|Q51eUO7IWueOA zv1rUnYcAm(Ua*Y|UIswpipQc6MN_sRnQ%s<1w2Oh9crX_EE@AXf5h}?ob*jH@X-`~ zG^pleBHfND@`*GKh16vUZxl)^h2#Rve}W`?fhiRvGr)pY1JPb|u%v^LOFQssx}^MK zLwh2*+>%N)Wm*UEvy}-X zur+E37^ZkE8oAgk+lU*uDDZPXNUsEEFMiYj6xH$%6!Q;^#r&hg7^MQDA9-|QM;&O! z&~D&ELfZ)$A$$ZkV5djACEJi)TrW_iATZ58*Na$==UJB5ipQcckC#F=L=_3C!EQ;P z0+T)k3S+Ez5FWL_OM`guCcxu1e%H6{$aYlA^c>GJEB1G1z3)M6QB00M2Eq;*;=mG1 zpf!m>42!seg-9j~&=K4(FloYu2_uGea`wUc2c@rl-4#%ZM2_4}wx>@A&e3%eY>2RF zP6oAVU9;&7R1koE zDhL1z07GJ$E@`9tfd{OtjvRfkM>hfSl_NvjwVmA&9)UrEW?&>;@k_Sm6QK%``~=sq-( zt;m!~@rBO`1D!*YCi|z1kr;ks)F`Vjf;A`>u#A*BT=;!1@?gdv3f7=lFhyrdqek~V zXoYb_M7AilrB{bGa#=7rbXG%#G+2RHn8dI#ue4S5^rWy^eG#mBOB`0cB@RSE_LG|S z^+mwmxnr|SmM~cXrAWj|u%O3U=NvXl6(C!}8wL9mAKeYu!i5bILlL+-gSR zZuIyU9623@moMy}KNR$!yol|?$cf#M1cQy=S`nP-GyYJ}5$NKDb(D0{r|3*!_hjLz zZ@Ym2+&y^#23>}qKPvJc9n6WMj=+ePwrdzy)ZZ92>P!xBvkDw^Weup)xbw_4&0=Wc zWPR^J>w6C(LOCL5D@maZTS*FSkm;Gdas><9)@*+5V#i5T^udGq&>;@kx;i2(5ltFa zi|)g^e3M2r6zGfx@(C^wuy%GwSUYyp$|Deo|Nl3JSwn_2SaDp@KTGB3k9aIY$Aw>( z0}gPukR2N=5rYV?yCTk0D*&YXjug*9J&Dczf`;joBSgE@&s~s!WBP5EDvToeKVcVKbuMtSl z`ay^ch>AW`buA7h@SueyOxC+QJeJ7;&#gXaX*Z+CThy_`(uo?xvPxWYHh#09^Vj9_ z*Fc4*$MprOZ+n8>5q5cq10sC$It(F%w(Hf9Ar06ajy_=3sPQ9)jd`tJFD6(us6oJ7 z({pol9m`DL&j`|F6}h3IXFh!V^!UP)MRR$nv3=C}rc6V|p!0$^p7(g_JbNR^G!`nX{2X4#)I+RHn*mW8_#_dt)RtIn@ujfG-$|sU( z=9V-|TPokqQlyxgQc4P(IQ4!PvHMi97Bu$#jzeMk)dda;<0G70wNg}!lRH% z_>$t1V*=RU2i%iP45j)f69d}Dnx5r02z>OqbL|BlY-YB%rrX*LG$far1|K1{y)BzE zYU3l_U0q;tHqp=?BsD$DK)V?3@pLt`Nk04-hR{ASgK|hQEv7wQT{O3}rCYP?MHvcI z|B)#8e^K_2{xAA}{QnRAzoGvp^#Avt|L61n_W%F6LG%B8|39Y7mH(grU$2Q>5FgKF z8Usf$Be4nr5mHI;i`)HwlK)3?1fiImnwFGMtM}h&aTVLX61P-nWno=a4XK3cR0t;BVUsA5Yi zOA9OO3JXP*)v$`{he88{Ce#vBBvSkc6bOVk0K|z82BanmDDnRuNDweWN<@hN=K$h2 ze27Xl6!8BUJp2FzV34}dfkTB2!6+yV6fg{M0fU7LO~DFK6rdtJQFuynntHDVt^^+aJt?5=N3CM&Z zAuUOuqh=+grT0m8OETS>XfX_%<#1pJOz_$ zX-Rp))8k-CNI+mx1XSt8oyoPd!D9Fvg%ilS){?GYp_$@7oo^!R@SCMU9b z51Bs+H=Nhl(jLn7?=|+Xg#Le;h5EUHQ28f4Qu^aZp65UE{J*wquw+><>?z{^Q9$&J zY%agrGu2}ddG0v`zWxvY<9J|ZEYJc73l}tjxtWCvdt?Ewmr%Re`4p=Pcn($n+T>a>GF`-^Ao^SB;?L|t*D4*i7Xq;uc7=GOy zNzA6w>6SdY!2i(}#Ue0slqpNKn10gwXXNo;#FI9l|EyR67}_u>Kz}H^0WYs>IdZlB z{n_Dx>L`k#A^aD`!U!Vdrt0cN2qT7ZnHPi#RBsIX-4MdB8RH-*^@iCJscdU9;g(JK z4QR@x%`$?8lM_c2Hj1C!{~th2&$1jAGijC&i()3GIUPx*j4UkqN{+2!xC(xUuS?}3 z5~k1QlI&YV#beQ!ltJD9CsNb@52AyV{+aM4BZbOX0TRFs#F>ndj)g^_75$HeH8nM< zQc_Z?l$2C!!i0(T#EBDXnx;V~C#Rs3lhb?f;34MX;==Rx_J#-v5+pelDpbUX5rd~m zlO}vWe*9>srlvAv$lynV1`S!3=XnML28^E)B}&|NUE`^#DLOj3Cr_Tpkt2t%NRcAJ z2@@tjK|$eR!GcB3WHRgO>cofY&G&6COG+}s=!CQSJF`0CWDgUF2= zHz@}W9Q;(MP?6K1L8C{H9!!`pNs}f`n>K9_y?OH{<-mc12oWN37cN{ho6RLlmQbNW zCBJgz%9k%+_?9eLg2>CuD~}N)hMSw)+}zyW-X0n>XxzAQ!-o$aL~`WFak;p-$jHc; zOeP&2U6UqF{QUghym@2WcAq|ds0a}v1P_r&L?V$na^xsdq{x#ePqJjmLeq4gK7A0) znKLK&^z@`spgK_i+1ZsTQzk!i=1g7J ze}8{D9z1w*+qUyOdGh$_>FKp-(E^D?=F8>MhYuflkRU;jAVDHUij+5R-q4{#XK!!M z%*+f24jefg92^oPNT5K0lIP{+apA({%$YNJnlx$Jv}rSE&YU`R>g0Fs+`)qd3l=;? zB2i3CEGHu)Q&UsRnM`KBW5*6BPMl1cG9|ZS#Y&ehUFOW0lhdI?C$Cedj^Ewg9Tpar z)9Iw6qf3$`$=%)EmMvTO`1s72F;mxdzGlrDIB?+PapJ_uS65f}DN>}!!@|N8 zP(XnpLx$kt;dSZK#m~>LO`A5k8#iw9H*em=XJ=>Mp+g5SFt7v?NZ`qnCtJ2`;p5{Q zGiD4LG-z@)YSiRw)~w0duwj$0S+k~9RaHqz36bl%ISm>#bm-8L$Hm1hS+b-`l`3S& zkdZ(F3Gy^)(&TE?s6j;2bkNDkDTxUaCUP(^u;cNVH_$)>H*Va>-Q3*f=H~Lcy1Ki& zJ1bVK?CtG+`SK+X6DCY9MvR!eudmOquC6Xah72oKtZ?DNMP61`mcQ?tudS^;pHDeC zxgtf1AK5h6tX_4PGl#tb$#wzs#p zoCgmcc^t<^j2Ow4C{dC-apEM;%gf94^z^P=xsq$qq9y0Tg-Z?r1Q6t2ym-mGbm@}h z?Ch+msR>cBSoHGp%2%vdk&lgynVFg8Yinylgb2xx966H9vaF}4SEWjo919jKd6q0$ zax7S|;0Y2W$kWpkqPA^~Mq>^J29~#I(IPD^EpKaU+p%NEkRd~uFkzBEdGaL3!^6v? zM2V8m^PE$mLdEa-d@?aH3EJA);^N|3V1Whlv$L~YsZ{1L4CiogaQTlPKkDl0ayvUa zS(fuAO`7CPm@vWf_V$)quwa1?1qu{hU0pI{$Us9w%Wc@Ok-NFMj2U^28a48@wY7Y?T;|PYGj}?j z`Pnjfn3(H}^fRU4tk>xdN)Ih`l0}LeD z+S*btT)2>wl%zU2IkiwwP_G6J8eR<=G_(~eR8XOypn~nIcok_1w6jn@D2k$}6BD{e z<+9?Kl1>S(Xyg9>BY;oAm&qK+GAVc3wp4!Ewfrs}%d;#cmI6z8aks0jT1!cBDM2aE zOeWdL^l-gf&(^EwfApqjJ-LnH7=BeEBQ{A|x7AbiQoZ04+3cG2-oEkMj#5XV>qpm^ z$YVRhu^c0x%@}DEILaHvZKJ4BQs6O4ut)hkyj>=9B*oGgFTzqcet02Q#E0w;E#9u0wkwmk?T^j;jz`Rkwlg+!j+CJMS&;v`+d?7b@09lp@gA{5!fA(1jy(bB5er6Lm46}R zOm?-H?vSv7x3T_j8ahj`muE^mm%)v|EW!{ZojoGyWAU6Dp!tNcKySi2A=D!1t zfaYk;YG9wJ@ZP?T4q{p3UpaXAQ$!;EN?2-KdY|F{n5x0D`G>#$5hrthkw5HA#M@W; zpFswgIhAVSZ!hM8*9X^vTU?!6wOpj@(d__rcMte|h`@n^*iP~D{&Ld}FxCcH7b&L? z;QYe+KaUK|VuJ;Jl&kr;#Cr}9tij`<0e<9l>JWA_q~(S3h(y@quovcg7)u!ii20GZ zn|-iGc%0%x&~k9kRR5jcJ`5V;!FNCX5Y{5O{xJH`9L&SOUHV5`e}Kl@7!qIB`nVDz z@*$M+teQZRJw1BmJ%C?&1L5n%%F6-0d-Nsb04AFNMLTS6!o@}Kv$x>^rS<@I04zU( z9J%x%K7t$kFlDp{cTpp=4m9nH?VQE_4Dxaz;sk+Bjp<1Mx_f~nbr3u|7%2yQ#Sh7_ zQS;k?zdrMf+#e<%K%O43*oQ-%brFCEx4^GXJ?}4)_nUl`^8g}%lRTUU(%C`ufGbiR z5UmRZ+R+mGiKDBLR{BM_RFj-fPzw~j8|}CZ;FJfrCS(K4`2n4<`L>#c@Pi$M1()6M z!4&c*prP;@R6A)`B7Z=6F`JF{@-E5X2}Z-m*1#5d@u7)Q+@pOz&^e2K8)k9wgD|sr zdcuI_fc@K|$*)qs&jJf>_RWKsaZm>NApX&x1m}?+oTQiY0j~a1_RAG~WB4QXz9n#=Jg@@`3sS`vm(hb$7BfR=_sG%p zcxH2YD|ZOza5}Jk_+t8T{Zkp@1!9g1>Ys z4hG-mHz<>$Zp~Z|8N(Og9}C!d1ME6luOS$U)Gw6veZF)H(UC*#4n%t~Q6bl{xucfe zZRzVH6cimiS={aCKdK)?bQ_`z^a|X1NODZwm_~D)HVKlG1ae9==}qqi&mP$VQlYdX zD1oJe`c#`%ni{Y8OJ%Yx2-l{~oat2FNl=Dm2VWaNtAJ0*Ho&t1T*$g7vpGF0dz!Ai z4ns|k*&fGKKEApk7!71|qf-3!!!N$bWicY9iRrk?pYO^7zB@N->zaDV1V(MB7g~Y_eWbeG84d>JW@e zj|DP9L&er)FW;%g?wIVGbVy|0|4HheC49%+-DqhhDf&XERZp~^*Ky+3VpKI&>`_D=f)6W#q9#7r`?h3d#b4D22zzP zWm^qnoMmM%ZA7)sN!P?ar@Bh#bRM@uvg=<)Ki){-Zj!)J0hX#@&_kVJxcMJIlUXyx z31S^Qj@}UcF~NqwoqIdD){R6&9vB^2}p3vF^=D~^n&A;w9}HcdO=@>E7r&IE>7-*UeNi(Fd| zv7bR&Y+;d_5_5Ny!Fks9Gu1fWcH@9X;jP~ROBGt4eret{$fcN%_Yr(RkA?VvU(Yargbm4iTqER`BK~oY z?t;J8(=BxbUR^K%_;nMQsoeq2_nV1#H%k}1;-{$ad)IVdS**PNsC8bYXY2fY^`|h* z+rbo*3I9JM5${ZsvS%L%!=|aUQE82T3V$9&pjy~(zG>pErnAxM-z$3}{}edDd54qw zFLq8dr_z;qKKFURbg1gxprz7UQOykGA|TdhMcr2xPC6vA3KX%YHpQpYj-Vnoc$>l! zRXNqAd!n-b?mV0Y#yf1YR!a9!7yNtLQhsF(?hdAXW>5i*c>;sAR92jifJ>fS0?Zvq!XrF6Ti~sIqASQ}q=EK(a4ys;a%7U_=`243VQ(3_u775!jHZz*(8c4%^Hw)M z*~){fPi-oX;c_~mEl#jrMR3?$leg9B&s9yg-3e*=G7!E@6Mra0v}a4Y3BB(Fl#8!k z*qWN%HQ8)%?;^(G=I8t0GB-7>d(4yc#H2g2^849jLO*3jI_br z?yX%2GQ@Kc&bn_mGDP{-g8kdCUody3j&P?N54Bpo{4S7WFLUlb4CWhr?B)ujNkz1i zF=09cWMyb)SDOR*GX3K`bou6lZf3_D`k@kZ&#!7o zH%XWKS`F?4y+;%q^i0ux(^jW;nsrwr$mfVsuoQNUn1_h%C(t~F4Jg#*RJ7$6UHK~@ z5=iXV$bBWB%eD`Ae8Hfxzknj=on|VJ9XBjLwY>M2(Hg5={-DihuP}DYu|JedCU+23 zJIZ~-0iESuX}Y7*k#`6S?-nEbPszs6)Cdwz4Goa=l*OH$g#`q^}ME?X-oJ| z?JGM&0b`$>Br@D(OTWdtn@$+R^x}fq2p%P$JcoZrGM`d@S(kLg!6Bd{Pi@;#{ z-mp{xECUJ_7=#5LQZ6N29*PUhCJ7-V^+u8|QJfA$l0aC|3sFdeCA?vYGqYqvh%yi` z*`B3VXc6`_(SRlqLQ^)N>62*+u*k>=DX{R8X?K~u0}xXVh9=uXv&pxcf@WD_VBiS- z4$ZRIKnABZ=xBroDtuZBkd`24ry8Q;!q^D1!ukmLLvzP-rBM7n*e@(O;gk(6j-TeC z_z@fVasQTM-kqwjb<>a}0}o zye9f>O@q9(O&rlVCEe?iJZEN66bAEHeFIMU{M)6k){~RVOTfsz15gQJMC}`0Nqj zE&wGwBMxXn%lknb<63z;OukP1eNYT}%tDNGml}6eBI0#?2>o_Ik94V=&|39*D%~rS z@1yg8>;*cO3g|h{Ma~X0X|l z{mbnwkvV{O18=pGA*l|prr)aonm}d0t~ZpMD*x-HnG;4d_V7zV(j#Y&{_=?JUfzRy z!hY=dx3Ejh+h@AfBV5;H))md$W+}c9$%^;vzuRxq<6S)JY#~$Bw=5ob_yfZ*<-8ME ziqnyJdhhxtvT3Z6-9-ag8bOAl*elt>bvynVr-p3BwE5;dvV@bS){dh3cI8Kd_5_x1 z5T-Cb-!-P+)b&bP@s?HL*(r>sn0a!zsKDAi$0A!gEp{?JDLi~EHWQmYS-ZI{Nf=|F;Az)Qq2?qR%fJd{v7aBhM*4T1@m_XlfqE@Q^K zhc)FnCgt)(IZ4w>Ar@t>P)+7uiz|#1`LdhU@5XeB67qXP^F*`?+H9i81F`B`#O_q%X3sd zgae}d@KnUB={#Eg%Qh+9Uw-s6!`TEDKbcSSAn03i+y|Iv#$X6P7N)w zU*gWsDiG#i?FktAAmCFK&SWoo!Eyw*LGaz3!cajSHU9Gw&ycE>7w=f#hYGaR{G<#o zjiksIMejPgZcKaIK-v6R5QOx%?Hfh34D=IaTR{9BWgRI;x)C$39Wtj5ODo3stFY-1 z;+*AGx<9dJWv$!vQivbEzC6q4m+=>3%as3ZC44Dj32`)7=$2fIOEn&x|!+ zpW4y1StI-pvWJ6wCuo1p)F}-2PGv04Un6IL#J%#HO|3I>;f%}UY#djI+1eLk+%oTiVh6o> zEt51f1yeNZ{N?Q6)LkG)>x=M7((I86@P`A`v6bzuFQ4N!GxfNXe= zaAhsMS;{Aq^k1~TYG75Obd$qqg6Ig#4h$R49#O-SU-Z3Xp4ZGpQ6oV3V!;-bDa!9o zISVT-cz~grr|v;443rC1!bW|clI%C_L^5mgvxQnGfJ6$1(^bEgobAu6p4&d9=C~58 zFu&lHz{;s0R)6m@qt5plN#^}50^F&xaeXITDp|YpQ?GLz$u4f z;aM=nzv2&%;)l5y2zv<_O#OxYUAHmTa7~yIr=qNUdBa{w$nC&bYnr?AfeJ+CxQN0NMfh1g6+o9e*Hju=bF&Hy+cC7ADy`; z*cja98bf5+Dd2li$GFswJT}|Rn6-3OqQ7)5a;a&3S8{t_kzTFf))yz9lr{ zD3a0I2*eDC+Sp*tyo|s=eb{vtA2kB)N6n?R_DegKXGL6){EL&KdZ8}W;j}^y%6ojez_){jA{;~etyBekDfJOkJ1|N zNScY<2*y?{M%2oGF=jJ}5kCWWBUdtg1P*YmStiUCcIT6s?gVd9lfVF-`}RHZ7c!yy z(J`~3*KSz4b|Q0~8Qlgi#|JWJq5T(EEEJ9r5I|KW%)N+#K|}u!GTle1y(+^P^f5;gRK?jLhQCVq z0Lo0a(eRQ^s8pMVXJ`_)t;?l9>?3ws!K=J%En!#*E6dY9kb+SWV~7QRuH;6^VtKq& zg^IW#A$x9w-eGyo13D$3&qoj^qxNI$2%%LF@<+kw<>Ig=d2Q`tfsPP}rS14f8vh*a zr)$w8aF{L+_r|S{eg~E?T{08Pfg`58-w*{c$H z#0f0R@$lfh66Q#et ze=~GMAmwUrf1b%)BH(Zptg4B5u6;+j``bH$vdh*u{h%%2o1s&M%*E%bb5?R5TIkH6 ztc^9P#{`p7rB~p9(@_~b{$64*_N?^z0-53Dw{s7m#w%{g?BK%j0N=j)gMCoFsS+Pf zc-PLhXa%4(>3bDZ}%aq$9HGP=_W8MWt}KnL5!@L)n;fp?&pfWy4_HfUYKhn z@&g1Pz}YnQWUTH|Z{x=&+A($KB>-hMv{I%{`){Qgl>Y8^=}2|@H)Yz6su&@HzTE3O zf&;(Q5p&_mDE!4FvpZo7!VW;CJCXM$dpXBdn7Ky^GYE`}%_7#uv~vu|N2L<$=?6ao zW@Q7|ZV=z06JD)iNN)XQk)qNu9fi`xv!2ili5#t&3Gc) zndrjpmPxkz`Jcl6yL~da_<4~YMf;1$F)%S(a*+%f-At@!G&BFXNZ1^zy~Lmy%-7)_ z@A@N(%CHCsISrq&qXo014EjA1DPV&;(P9*&`IFeiX2{_uywvU^p~wFPn4XfPm&Cr}Qlfx0A8Fz%JI3?SN~=RL-H7cq@ZQUERrTkF~q$t7ZMY%W1?J$*4Fw5KZDUEQRE)fA&sFoD$_(RAApED9A$5L`>DbZUjZvc${t$d7dR05a z-xgquA@PXX^$xiGQbYU!z9-_BAHuou^ajwAeW=g&Mh^MY| zF-&%&CuwF!hSY^5jvfhONRO1FQAd;Ba1s>>D+?1G*wJ%8$Ozv1tj&?4w>{=A(q-ww zJ2be*HnO$oX`lTensJHJe^L_!u#pLnz%duaty!o|?dl>_W|p#)m)#zJDDJ|) z8r^~e7ug_!#S?J}2@+2x=ls)5nw8y$V-6(kW}*Z(dq+4Q__vf!75z3YX&09xuE{Ka zf0|*%1fxWWTTQ@8GneTDhTinuCGbAXE3UKWQ}+XNL~E!&yryfH_G_1aI(J=MQC})xpGDG@#;~rSac}_L(&jC+h0m&n`lRKI~cxqGI8B0myb=j05u44bXan2tRPnTJMj}!bRjf3Md3yr! z_u~Xq|Jj8SPt_vLg#Z=Wehfu`_k^%ITg%q_{i-r8b?1!34~?8Mlz{o5N10ca2UXzB z4?J9$EuZpikfZeOv1Mh&D@K^ucH&t5)2QM?J3(jP;Li-O%*|KS0H)2Ss!;JgZDs!5 z)>PdD4N{D@%PlOtg}&P!8vG;7(=04yVXZp9)%HDzQ^~*1XoO_z(}G-gpD{jzRx8ijDQ$)>zjLuh}4FZHztY2>Ok{gzmWakT%N)Zq8+n zM&`=;@`lUr%{aP5UfYmWzK=`!)g>FTjn{FkRB>^mUV0r@;L_`l2F=&g z__9P@+Q3zJc7BP*vf**~m_p=1c5p%^OY04Q7tJ&)((hOi#uU~geV@$ z{MAL?)D%jW(*y{lMM<|JiX?{Reo*B%)H5^Pl6m!vdT{<(iq{q|g1;+X@0iVM*S52$ zu7mT7tO3Q7Q()P9Fhv^PtDAx7I2CE-cb- zC$?;i+`g>00o!1WU9DB!yN^l}H*It#=07Ja$~WDp@H3$8H2G}t&pe&I42zKO2G$+3 zw`{8Q2CA#TeoFL!VD+0jS_xxl`5?8kqVvvM^JV5P46VK&Tz3H2a0^+Njhb*CU9ByD z06nB<<|xiJT%^4>SnL?3Wl>=*{48&mSMVpD>+(u`t9h4rNc-L3 zvIB7IqTb$fr3UODq#6{s2Hfx(aid*=e;D1joo$pPA!XBov(>ZqDEAgE(oZL_Y)sO+ zthY0u)`0zIse=U5PVTFvFHo~18oy3bwB(Cz14S0H>QUy@aPW!bq{nrDAF#0_)3#){ zdN(Sk+!}!a|EJS8{CeEOrvy3%1`TY@C#IM>k(b`72h`EQx}L~(BBn!ac5K*?^o`Z~ zPyi~r&4fi7QI%@z0m*4W?hHpHC#}^a=-!yd2b?8;m}?BfpK7n;!Pz-8$PlbBNp(bm zH$ev4ZIawQHmy@;?^w2$$yD|*CU|er+vp0{(B?PeLq(S3-U8j}%xpaoS&j&CGG{W! zlpLV~Be$cj+!)&;>Ihia{#hKtOoHRPAx(?n?8+8WkBl9d!9>OfOq%IL{GqOz#zJ^g zp%=-pJ_QyvhnU9Dw`s<}{g9Ev#@UL{Nb-((+%y#jd!md!Fp=892b=!Nx09JV4V$0G zO)USf$SAch{h$~Q0s!nJ2ma1S4;V=hAhSei44m2y{j82Y=(7_A-E{xr@08oJ{LnJq zB>F&~pfJ`(oUqT@1n)(7#97YAaUA2E(h=16b`#(uu;ah|Z~seco9vwedl`!s{TJSs zHf6lT!f{ObGgI?2a|@Ga%(O|@S zg@xDRZD{tfIa7wQFkN1=DPvt?WmMSnQDLBuhUP{?^T;L+=w&rx#!rn00)=LV)Qq=W zm><73V2**e8(8|Fk(ID<^2^N@#yj)Hh7&W!J0s>VVzz9Vg(H|AAuw!XCe2@bz?%r> zrNYg}%ow)7=Go`vF0a+7Q06s^{K_(~F@F*IMlfS3zcVY)J{*|AlwrZgiw|fMy?6mh zQOzq(*rpcRy1cx|a9*}-X>;aPX3LhLP)tmXw+83~Tlh-wOqc&5KQds-yyi4RX3~Hu zGw5Rj$1h{HY>93KDAgt=fJNV;erjY?PpB3)y7a}E7G1Ok!bw6TO8i+wpTh_s2Z*;fwbT(O%C=Q@WY zN0Rh}#J$6Vz8P+O;i$N7lioNKl#6qPCM4cI*rPa&wonNayWPkUtbMSdT&(uNa-UEs zRK|i{FA?6n#PX}bKA8ynU_xX$6r+hDF89@JArLA4T*_{q7yiUz;Fvph!|JB))=<0hOe8Wflf~Ht&PsK<_sDvCV2=O^jg~@=DOQIEuHBl)-wekhUOO7~Wzw z+$$H>zTLi_5a-ceu}M&b+4y;47AxUTIdlWZ8xZV@2mXYyAR*8eW=$9}-kLCM#B}k( zyikTs88lsdJkd7RVxVXfV?Vbb+lVV|voL6o2GYdZ7{+WK7TSpO!1AZ8-9+yu-b8S; z*?>fwH#y2|AvkUmVcr;88Evj@A}NyPcguaY@z!JIhUH3+?H(()9uNp;yT=O9SAgyT z+6vHj3t_g9Mtzj?=Yc|?&PfuN8m zB*tQ2?E86rArAb34dsT0?xBgW+ARmxuw3b}BIMbENZYJd^JXmk+Tmsvz52n z&?t&Fm`J02uCWYdq6}xl*}(BDZ()q~!A5Tg97EYCl>18C5INdx;S5K+iLuxSzP|D@ z2p5C{dT0+w6km_F(ngN1Nsl%O!eC$R8%3CBd)071h!k#QWVl7TM`vu0?X8Zo8 zeQjJNDgMkRZ!X&q>5b%z_OgX9&lU=SG}#EkUY^V~jGTmpKR5675bf4uC4@I+4$O&g zdUE2+lhIy7v=~kFxqW9`r8o|SwlcXdBAQn$CVG+mMRsTl&&Y0}&@GH%Y(@jF5nh$Lm=ww@r@R)So^ zgg~43df{v#&=~VbaOR1zZ?zA!g+kvL8~Pzd*-a*fF%Oh|pv!dy_6>bBZ~VR*nfqQg za3(8f-&cBGI2$5Kkv8+fnHSE0U?li`-zR<~tPIO>G>}>Iazy47Sj z&x3`xa#r(j->i1K4SgfOTnYPNG8j3+3r8FJ2S(<^@^-r|ixVdlBE4_+*#>PPtmigE z4xFro<86pG`)pq>l*w@9mr=~c@oqOUcFYErIb1FG!A5Zg-fA-0OPrkxYhoC~eZ#<* z2y=lX4R@=BHZe||p)k%+oS|HtI734@&lbM!dA&s2DE`pM&sK(?7ZYE!$r@POvw^jc zj2&~q$SYUMac1QWm;-INQY@#zTr%7%MhnX@=Av?#C4}4S<%)r0S<DKeL)x=D_l! z#b}{td)b7<@ii;O5%!6;?l<|IG;s|~(@@cg1MH68vc(!n;l!-pDkR1BC0gYc618bAy zcg7pjCN?8$FV~)xH!zv22L=Ygz#vZsjzZ#%278e&aumteH`Ye*Hr{OC=y@_vwoLXI z#^M0Uz}T9YD9+aSl(26F@&>DgY{(nzHe$w4)s5c zKA5ZKqR~DX81u@RZ5I2P3=(VL7_))4$Nh-4hrFCuk|Ov61OsEV@8#LRIH6dMtAR2c z4dgU{ zWfWb@z%d4nAdn3QM0z18mad0#B{&3wiL~+)8q1X)Dx{aAP^bGguu`Pvf*k%Uo%DG^%+ssvxBfJ?&68wRcp%57h zYoi#FE}M&V?Q*?D+6#Pa^R%+1G9Z487s*c zY$RbLIf6kr?<;Ab_r+edk2bT#Nbq&}^GkGrug`mZ9uQdrN0@68S9)SOl=EUkADk>g zq)nUwlwHG(Ft7HBvYYq=+xu>|4}^)Xg}@O;=43Qc7TUg=O|%{4)xz6SyXrd5k z%ekoJTvRS;IM*0{KeaGTDdxZ!78e+MC|AP35(auzth^ydaaRt!jbG3sXtRZ0Sqo_{ z&$Ef%D8j;*>)7qPHh$hqbb*_>)yi882Ij!QF%-JIC(ckV2971@D?x(?1>s)z1Z^c~ z8yJg)KctJwrC18ZTrw~=oDf3jc|#s9`}U1OHr%%!+^uwZv`;qZs<|#}uA1wb>zWJp zLoUK5+jWc?)Z{ z7Y-IeoS~ctjxbv|REA_2&?AmEem9vdq|v_7hO>cStSmn=tii$< zj2vw^@;E~`av{*>4b67B4iY~yNc;xDAP{^O%0O_Gg)!PF3b`g{x1kYM!anlD(O@vq zd)3IV{Ae&zv4vy@$;QdPy@Y~rLP6p}HgMMC8VDxRUJrplvfMY;KpGgkLXtx_ z@;i4Uz1jzoqib>~=h?s+IJ&~p^$_TdHrEv!>DnV}IGbxYSGJL^Sm>gCI2y!I_O}qo zla06;#8Cvw;lA5Pb9pe@H-a>=Bt4w?Lkr1a<0lgmW8VjxjX1Hii7<}_28FUmaRkW? zsBAz|`34@V#a!YK>3JUPbH!laCmX@qH}k-lSB|%FjM>IryFl`%{AS(^#La^Cyde;1 zF-~}!^kO!U^gfzQhI^4Nm>4vBHhv&U#zLETECg#IcvoUBEO2^k-%a#9G8{|ST%0>wt~=SE)pnbAIv{9v)6(nW(Evw`Ip(r`$_qZkH#Kj4de;Yb>Y zlZ~PXtKn>9If6kh*H^4qi3QoLkg%`z)x4iF6!JVF@rT?Ca)sk;(xb^>TEd}GByr!( z%W^rsY9cIl!+oWAqs2U+mj?s{l>2}@TlnQZn2`6CF&inuDB8f84W!*}IG9a@UD`lf z5EhRdB4wma9A&TEH-fJk&Q=R;pC{gIvk+*sjkwp|Ec_9J{z~ta`)Xr2D{o)yvxPD* z7n>x(QONUVc!@GEcDuzH%6VWY`(7foI&Y{On63Ccp+WjF&_ z;$Gk^hO3e1#PQ~$!NMW(_J|{6wVSJ_#ED)I?naVfY-o(RUN|zeg@?HE`)aq+7Jfmt z59XrXWZ*%&Zmv=+b6>3tfy^QT?wD;13U4^i1=fbhhsF}DiQtSRb70VuE?1A0pS_+Q zD?L_VpDYM`;b1xO^(tM5ukaN#LByDHDg5i8&f>QoPY{$3{^|_AI1* zI9mz(Y~biwDRW>D_@dFi8W{?eU@49_*FzwXO)PWZ2;OFRi9z723}c|{*NC(Iv(V>a zu-onBI!Lquxemew;SR#l#2_45+HQ|Ful#B-Fh~qX@b(}0^A*`WKU?`(yoH~P_R(&) z&)fA9zY(l`FqaRT5}cJXG0spf_lcz^mbb6ASO(d`Ps zaKTMbIEpke=!O$%G*LDXjP?bAkD!ov8^InhXq?e-uc0$OadNisyE2Nq(v)zp1FEXVJ5J6Fc4^t}0mdPdMTiZD+o_R(H9u_R^R9*KjAkKiq&!AM;AR|{Q>WlbDq z-fX0aw@Wc7yv@dshJ%T*4;($O3~e}Xs0?8u4Gj8*n+$WG7aKpJQIydD4!uMXv{b?J z<~ZPM?}r3yu3g>-o7uv$1WA`otc5XJ_`;Di5eC{u5Xc*GwAXF?eqx{vH;UwlgY|eN z44gq6Z?zFdjyM?XlZ`lXC?>u5e&-RN}L#k14kT52H8N;l?!jQFm`1WapgzietOCq4F@B0 z;4*JW7Lu`VoGtTY9vB3Y-w2McgK(1|>6N&fEgb5x^2Q2z`(QDe_(Ou@PZ`F7!q^K( z(t>DW%=V368P4F*V4sW>WgZYLEJ-j3H-jgVBX|q?V6ZRud1Ltf5bPUqv)LEkfNbCE zXZF!#G7+rdXkt(pCk{^Lfuv20#lDh+egBlS5BvdXvST24BSD(&69RD{js}?c=K+Z# zjrQ4QAvu1a?3akUG6|NrS2&jC=Y6)A3!HtUSd!bquO`Mq(j&vi?}zljAaIO{KP6c6 z%2B-4LN5l6BPb(Fu>?sQ2n%Vhap)$(T#w>UiThk4?JGanqU)FI7%e1263l(az!*s4 zY&a3-xm-UajwbWS7zo-1Z86XV+Qc4jW(#k(uXgMkB2n5>72j0LD_T56#CXynQ z;maGv686cwnJxS&MX^SDF&kLs!15+@UB&@lu5gUGTreH&KG{QM4lGG=I3c{*_WgYEj)ktTHVaAb29lv@^M+vG45SSUW#LbG zE5q@#;b0%_pBYXZCqeKv?F)*9waXC<>XB_lM#FtSx4{^$3~9I8_Xx&D(Ho+Pw?kMc zlYt^mw1qJnNPB^Qqm2A+InWDnL8Hqx`(CcASc!#RF07F_n#>kX4t+E$Lm$lpe_$W% z+h-%i688rh!2~uJ6y8(qRpfHFgmauQ~gM~EM5UeDJeRF-Q zfu&dCM6bl98S-qQXDf4$6_EVET_|yBN?aNj+}O&1K_d=!j};nC9Bm;DD7^fcg`iL= zjzHl*uo4_g5-60(!jjB=wy;))wU8G3z@H#nNDII6MusssSl)m!u?Es+HZsh0Da8>7 zf^k9;Cer>XV`C`ffw%9696=fm^h$B0k+yG)GnDhrm0nFONgT{|%|#A^V+j=Q`owfurkI`%2P_fiv6p z1N#y3V&Od?EtJJTAlP>+ZQ%IbJTNG9dBefdQ^iUw9OwguJP>C4O41g3LpRqf97Wed z<2SxSng_rSlKfo1LLty*<&71u7M3>L=(-fe(Hr`Kjo%1{KdwnIEJtwHO&o7< zdVb39=K2EO4J<>ihO>b;u=GlqNS^y@+rrv5kmfz~jpOH)G~6cx$?vsIgoT4R z+7~of`)sa9FqDO*4UC1Z;b3_a`)=OgZK!P&~!lq z#^*Ur5rRV(YfSNif=m4Px6%a-m?A8%=*lbVc|}%UQI%H&!d3LaEArqKb?}Nfctx&P zw81N)a*s%Z=ZG?RjtGP2h%R`J$b#pHDtL~Fg6D{)JV!Lab3_t6MDiqWxP}QWtqeBa!G8RZ;hf=v#q#uE4A-AevJm`mLUP?POXxnbu9FRg-DG zz_iYp)=Z`qlWDcUv|ci;mP~6UZ>_*f$y+CRD+S&PJ;TA4{@xBsBrFB4Aqic&8pNzUJ}O0FTF8?|7>nZ>{64biB0yZ`3+EE|Y;JP`fw+OSzGG zZe$Q{q;j#TZn3Fqv8iUUsbaBd(Tvn9UZh$v1Zox6O2xHKajjBZYZO1=J&_8#9Nj4n#4Uwd_CfaFk(bjH=u}XCE{Jn4yZ$1D*&!lh<9ob z*9ye7{%|7IhZCtijH^5#Qg?WTDo2M8>1z0p8OMjz9HteA>81y%H#~?9Z>{028GOay zOCM6>Y)Bot0X6qk=xfkd+}HB0WE}^j(l8+PcCF&I+76`FE~L^fqyk+?o#8@i`1NN( z>g=oRTET0L)e3v->#g5gWq7Oi))?Ljr^4`3F>ihI^OLVHe0AZgo3AZ=ZS$3dYh`n- zKGV9UuJBehZ%y-}nbtGYYUWy1cxwu8EiU1mV# z@{S5GprY{B6W&0&HL3}3E#X>8nAR=Rs%1ZFmbZ@ZRuQH(glWYxtyiYCXIiaHYn5vS z;aWfVW1jzb=Rc;E%G3itY6o9AsIIqe@KuB7tl&8*c-9P_6@zEJ;Hw31t>CQ`ytjUV zj_0i7*%|VzQ=WB#Yn9-uN&!{MSDyQ*5qzyDU^D`{`KS-vQ={Bd9r(I)tqnXi<13WP zz*n8Ow!X5yuBKJB$27I;k;gg)pmd6Q>*=kgTEe4}rgh&t>gcVax7N3IZ>4XYZ~g5) zc{@+uu9LUpWc-2~oF zlDCWG?I3x(N8ZknSBQI5&(TTX?ILjP8o8P-K*z|mQ)Jpf;My%BN2f>}54d)Uz%gH) z1Kv7cxOR!KeghFVbVRo?v9NK-yGC7&&XDgKkVaQWA=i$O>u3UWgS^v?MkmPIG2rbM z@OFXF4v=a0hab~U0n=f4QJ?Xgu8+4%z>9#l!aZl&QcWu0s$(Uy{UQI^F#slcq_?hNAHNH#Z zI~}GS0eMy6>mpHH^sG+;@U-V?Vz}JPh2}Eu3Zz?j*06G zEP!r_+9~mNNxU5rZ+FDo8S!>Syd4p5H$(scFztkRyCB{Uh`0OU?R*%Fu7_9XczA_w zhifP2+UX#t%VFB#@OC%6oeh7{)$kWn=P$ZAZ#VRIxwjKi4MvCS%C{rGSj%2?<6U$# zJiFVo6Q7;!S(_d0?SS5*o8g@wHCr=IzeBotd{&;q6kGc4gj<%-fB5J27t;=Iy|| z-IurX@^)R`j?1(|VcMOr6`cvwu7qhv!nE5m?X*n0EYog;X(z(83*p*fxlRFGyDQhO z=k2V#U6t=Zn06n$od<8%!P{~0cCNSE;O(fqod$20!P{Z*b{D*z1#efu+fnd#Q{HZZ zx0B%Qq`V!^+ePqp5WL+3Zx`k59C*8(w`<_-pu8OeZ>RHit+!*n-RkXBZc>t{1>6MfVhJ419<5eS1QIl&@k443gD#ycqte! z{odRui@4Gut`q=QD#Voraiu_9=?^dU;YxeBQXXEq!tQW{=*d#U(R+e>RNrM(pB zoijWQpZ+|ZJ(WELpT?fTp1z)bPrauxJcaWVhNo|?^o1*R;Y!`Sw1t zm#(?e6<(_5rDFTAbm!@8ddgpZ}9?(t3%u2YYDW*!SYIyVjQQWlzLp+yU=uCt4uTwLcC*Qv#`nZqnJ)8rt^vGbmC_dKbiQs#7`xrGl}a&;+;pl(}?#X-bute zhj=Fd-YLX8gLo$p?+-tH7}di&d3fgz@09b-Adbx(KE>uac9vrkhj*UC<_(kZB+qHX zsJpSu8vf|7Vb2-ookP=^n+jcK2E8+J@67TylN`<*-k${{Y+gM_*?YK zFwZh9T87$n(tZN{3_n9}p1o0f^Jh9|(}_kl1!I`!7(N|C>mY-UFW|__r{?jbX5Uvvo8}B`aD?YR5rxAGsA9xq7!i@4x2j02!&IaBIWh%jB;M3H(%u-TVbqcd} znaR4Y)-qMsnc6Z@*Lix&-6)veS-MWrbMBb6OlFRrQ#5MU>+C+^MxK*i=X}f?p#J2! zC+`%PFdTcilfTT#zsax3e}T{B9h13iflK(3#cau6$zOq=k}&feW}U%Y!Ivj_3QXX- zB-bPPA-T&VL*U35EP?k3yf^YQavcJTyz>LzS&?@fa6OSx7?JCTTsPzsZou_It`o8e zP%hy?CP9!Z1K#oit_N}*kaw1{mU-5)X)XWp?#H_V-urkHFdYH!e7qlE`W`zTBaBCu z^_YY6c!Uk`X*{mqaovu0uH&7K_c`7IY-KqX;W*w|bqK?;2fs0v-Pp=)d}TI1y~b8n zV=JfePJnkb-p_b9*iFYL4k9ap?D;IIkL`>x&-WdSz zEW}n0Vk|fWvcNyNj>oHu1a~*~?I5m|wua-0Th3hU%cQd_(>us)&#$YTz3qKnQ_W87yFL=!s zyuuSqyQkcp=0`IGm!4oPSMZrB*vzL@7=lxn=Q5wh9Az;}aG2|0u7A1i<$9MZ3jYaD z*@P#!gdteUr+Gf@zz|G=1aEmQOF7FBJiVD$p3cClNvBSeHcgs=CF#5xwa%kNw{E>!T~}RCT~F6d z*Gt!3^=a0l>!MfFU-hTHd%%}9Y<&KoIb}6dhy9>YMq)Q^=DdiIN*cMDB?_V|V=kyH zxn<~NI7${05+pYhi=o(&-Tc!jV;Og4sMFoxnFMuJwMRaS&V%NWXp z;wfFOvSu?;KgW*Da&vCVFj-{QgUa{sH zl{9Md0hc1~C*%2^oqxWgX_6W%%bhYF3?JhjK-s^q9&> zOl3tTYt(E^KPKI7xr5LlC&R44sIm@E8H=%?Q79!e%Tq3-xm-ofZ2Y8yI7*#T)jXBm zoCVcYp>8J4C}m7CQ_YlN-e#2Nm}({zlQkWgr2SZiDfy{p=BAnnnQCT~71_;HGfDI3 zAL>YsVlinbt}aPua~!c~Kn; z(HvE-GND+_Nc^m+9OWphdCFX#GK*BF)8`XS7&B}}H{ZT9qnq8V0aGSTO{g4cGFb?w z3z{_}c>BWCgj%Qxjc(l3gobS53t-Az8O#+hJu)mgEag{QhDCNI6vL3Vumv!q8#F+) zuZ7oy@w{6a@AbON>)8h;2EH!C0y&B;gt))>d?7xQa8yGRN3kaK&?tr^gJ=MKXlTS+nK5a$Y#Fy~iGgXpIW#^%`K#f0po-- zTiC)HFgYxI^5wAuu8CONcWw_P~4w$C}V2`%)r|jF=Ae6VmOgj1JA^+fKh=B88trt zE6tZznqR+sy!dB~x17@EgFW_t(K^klf zzxa?~EKE*(l@Wu3!MdzjbNkMKv4!~pda>br!j#E@Y}&98vY~xy+OTl@&V*{dkfNF# z$VQD1ES!C3z#!b2P_&7o*k())Wb^vQh+`aG2T&95)21tkASE;jy@uX90upHnJ%kzo z=_nmZ02L4rLhnUEqy$JP(gZ@}NAJDbXrY5bXi{t+|LTBjp^Cvy>AY^j12%ybuyh&c=SyZqBgG4AUzxUGWYn> zclt%1b9O5UP0$phe$4id<}3LcI}|8C{4~_1B&R6zcBT?iJLdW68aX~Tby39hIpOgf z*)xQz+#SdmTX;sabL9WK$AdeM-^D3QM$tAtTl0(`pX5?%CynJRw;uVD=RRO#hz3RJ zxQ(o#|`zG=UGE9)9*%~>cG zUhw&``$VKi;l*Y$hq5P)XM?QgL?jDX!Be|wvS74fl;bU%Ey;pXk#)vvg^m$TlSm-j}D ztZA*0iv5sg%7jX;Wve&mil@avhekVE)E`B^MSvw;BRvgOA8B-}Uo0Z3soj3&d5D=AiqGpA>^9W%vw3{>H6OJ(eno;d*lB!;oXs1V0 zCgH`3D9t{r6-{-~#_jLMGN5V8OofxxGi3Lg-B~FocS96+?13gN%%Pw;@t3S4r%}7v z-BlW)7<%=Y(mJ=G62TNxfyYjBDR@5%QLK~7wyO8;mQn11ufaXLIj9+1=nJBe=>8kM zw&KPqsHvbi)Kp;VmS*XjF*|*gVK=6Esx0s+MN_I;fwOD0)y*8q(mY$sVWA{1YExUW zf{l|mlXg(;W0_JJ6MysC>16AQP$&}%@_p9W!l1Fd2+KNklCq{?S1k9k!YV$geCV;@QGS@e@ipeN1jwCOR z%J~ROT4y>6ov&nNtV8Ug+3dlo(#x0GS1fxS8f~iY_I8{5hfgar*+gd|zCiP)B;U97 zpg~o#Qu12!yVbvh3W?VL=8OVMdHcN)W)Gon9ihdJ&>~0Z8v+K3$P%gFrGU@ASZrgcj9rGK(128E6J6 z8I=@rw-jV6fbh%wghFk0+oP) zN}Rf2D<*$|m}M+k)sqAj@>QrFK|Db`5iP=3^+T~)nW}#G)#3)__*}0qF`A;_DKhKL zVtKFc$eK@&i@MWfK(B9Obo?W^c~T)UKOSL~`Zt6enKkt~1|#y#7X;myQ!Mn#FZ7!o zmsd)(%6fuFPe7D7^F=&LKZ=wrD)#!)iI1J06nfMfJ-EkWc+V>Nxd_J}p6SJXrDr0X zh%AHuIF_llp|Z*5)-;o+A~dtNSSPa4a_x7v*y3EA{2_ijx6JlphR3amMoanMB>S^I zI0u~wn|&GB*wQP`rp|gDhO|@`QMq?qt}UVxhMG|lQIR<+m&pJ2?WEiXBK4cf8=~z6 zd9uUFatp2?q72WP{6%FQ2Ud)eQs{PD&>PHOFqgvsyg0JBuKKgLeDv;j>@aemt&Hd$@O71AAAVGu)!av3GK3U!g1=Xq_9+|Ut z_n{!CMEAUT_neeEOc~yzc^WHGB3kn(D5~&1n|(|*Wnq6Gxp4OezEHW%5;eOAO@Z;v~zf=-GZKhtZsmk zR)7+ise7YqzByP)NvA&D>!yg9zpHb$(RNn#naILib77&izwxvLPK=FZ550RTGW*)N zKGE$98^^fbPny^iP^nTVdj;SDY|GWI?F6NJ0s$6 z#6qXHOTijD!+oVIp5;rMDd@-DGocXwkH3go0$1|&pi93 zCEp^AU#UL%9tgUsCT#Sybmq2kMmAr8@ot8@!FbS5G}AFb^BObA1V~i?4~A66X{L9XvsH6 zH8dC)ooh_jmV0Gu3=&?I;$O8VuG^P(u&IN9Q42FXiJ;C^6kqQYDY5FK3dQG4&nC+a>tO8IdUrE8FCtH<%&_h-pRg3$<@P4-^y7B9GJTtxS&vd_w25V zTiKl@LK<5k@s1`4M-wNoxiz(BL%1Q|deBXzlcpGIFE z87U__Hb0vxP>TG>_KN>Zn74DT_taR^(L@7cyg?8KE?Y7zGBYgB+=kPAGVi4_4qTow z7e6<)WLD4Qrwuo0Yb8|bBTUwF+zf<-xr|#|g*t`5=J`x^#m4>=F7fq_mx(*ie*U~% zu_M>*A;pU2cd72>8DF)EL*Tru)UfQ6aRZFmaD<6mB<)0=b6e%fy~CTYZ9u~5mpFIBsoxhGYz%)BR6R3|+9s5(R{gU3XJT0Divq*TqY zIu}34{LJK};dEGVI7{46G&Wt8)6FkveuIVNODb189HOS7AEb(%piY->&y;P?lq`r& zmn3CMlgGLZ|9)h1Tuw(2GDge@!I`P+%4r>qG705|2xcLf-Hg1AA(PCm{Tt#GR^;W^ zM1+EHW-7#tfXps=QySfXh7kB^>_${QpRhbYNZ*6PoP|92SXX_+SbhV4LT>oto{%IdVRaEzAjvFB=ke>Mq+Xp)hop)3GZYHBYI1Y z^K_~JMsc$9^e!>7-K4yYIPP-k2MP?vL|3{SxkdizACN}&gmOuYkR+yD0wW}WDFp7GT`b=Axl%BlAvf3sl{4JT(Vvh#5J^;w*JU;c_0Tj@)ZA6>=1Y8-{`fFBT<%d8 zon?xCM2UoVd>*T*)Pj5m-=AcG@j9W;iRoR#)Z)smeBBtf^2M>3Q>dh&{FsE{a&ru8 zZ%qul$8Y^@?xzq{C!e{a%hDSq33)Asq;)aeGRw349{vz2j*)`!D zk`Qxo^QMtK!ZJ5cu_sF(X?fF%IahplBzsOl*sdTGOAxwa$osn#m3gC_0l|DjW*Gcs zRoDV$#FZ|80W{>$+>H@8WFwT*U9)J)c#oJAt_mBGGRp}<#d)mVCNZnV;j6~zAYnC9 z=F_@z8U%B8USF5V49ciBuP@vPmscKcRGk+aZd55gtSFp=VBQt}VZ!yXj{_oZSSnGS zi5H!oPL5Fw6A>^|U)vRJN<4E@Zzv)(y@7~r6_^tW&BxSsM9jt%-XgbIaKn#XIXqY* zqW32*$KBNBCPRob*Lj`-lNxFfmWW}P;%n74Cle7Chv5zYGB0z*h%4WOeh}g+9 z#V0||$!B41c!qpGfmyIy_)y4gR4e(S)CN8l5|+M8C+|c92_v7q?S_wXJWmVzV@v&* zcM;kZ%0!ap<@q*Dju8AQrk56Wf?Om!Bpw|AWwg3-68INV_ZI@4)axV$JAxsMu>pb! z6lDB^jN0FZ5)xIHc~x6$bG7KG7fmA_4KocK_vE}}0qrOl6N zQJ9Fo5Ai1_Wu-pkU*;=5@fvuqL-^I(p-uSO`!#WSbM3mfZq7*^!{HW5n&EKyy|QC# z{P}!rQ{XZ%+<*beKGD%0_6P~zStW}hm9oZ z*J00=or0GD%diu_La@S;!mQFs9o->@$L+T2ob9Q~wyF=yjeaaz9ClIB#m_ja3%;#Gog%Y;6em;^w=Ea0n5;VFymqMVvFw1q4CZRhhzAIJ-E_%6`PyYVd=8g zpTata!lzykg%gNEJ*J=q0?1Xg`t;1x;IL-r%H+lNqwj}1S&La=4~huA!y(PXp|pwx zsnW8*ag=BFFtK4uGbet+#kP5oApnk4D9I7}RN;NFhlx^oxZ0DgLeT^A{ z8x1836g=u1Q|NcB%x4l>%n*c&D~xF>jFoZ5e<1fLrrlESPUb0im@EHrOyT1bY`2QPsXz#{LfZ!yq4#>+fqaYk?y-sZ1XusK4wIG9={U zHk6pmC2JzKp)TNth?Y0t*Z|TVr*g;wrJT8jf+wn`CpH>$6MNp=S2VF5)pVg6`X_h1 z4hR6A9hqiZlu<#XYQ1~jJj#8aZPcTg6>F3g%S7>EOrce>(BVPkm}F`7CYdMa4>^Mp ztJs#YJNU#+@skn5w0*I({UI_z&E;v};ZUmhUfWE=8KtaN*_USd!gX~}*LB4r@q&r_ za3_Vg{isYCBdEO4R*5}`md7Q}<@1G9UFve(6X;5t%1@oR$l$yOS{Ghd=jzhnS_dW` zrS@>pt{RYEFmc?wA{rnf*$)$v!kYUvW{5!dBiExciRW(p8p+tU(FAnF1FLTenZ#lX z)>$Uj*=d%0K|}-Sw|2}8L6PNy)LpMc?;FO1G9iSJswz>*)xJ+dfC#*OluEYBMSH~9 zeB0MgmW~J{KT3Vhaj8@BDy*;9^!5W6`A=)=nPrqT)=3um=P?!xqnvA`R6nGFGNFvC z6L;U!-n={8;*A7#=#Kh`lYw4VjCj7)1Kq=$=c&fWz?8#;_^^-&1ENObM?ruH$2^9L z+mLg5nQ2O+aLr&%;|gWav}^b?wJVJEb*l618li0Qm+;8OWt}`h@DSMlKA^6av-@Uz z7%~|6k%SMJ^wyINI*B(LzhQr2@mgghA+EhCxafBBrz#Ak;M;w#@zCa;(DE&HV+CM- zOuK?!6E~nv08&?`Q1!V>qwHQChSuH9LroB{ClI7LZWz2gCvHM=5&8BidZxn3NB6r^_ zHcY5TgKiDzg7OU61fCHDC9FJfBcW71ZqEXMr~qInDOEMV$>45s6~urGV!#P8;24|7 zR&%8$aygMwC6NXIf*{@Ubat3xcc@UehM@Ri!Zr{r3)GbbYLQY)9SsKuVL4XWfuc-4s)d*~!>!nH^USMsOyy8H2)jE8=(6$A)9MysO0uL%NBefFwSh)9Y%df3`68n=^)8_HCB z<#M1IoaS6tmDyfO=LpVr1ZO#dS=-PeB(%__Nw5%l0~DjL2+#@&-C$Q9H=fL2(rk)Q z)X1PhSX_%>)`Y^YMs-4l8b1lmLqfBnDigR#rCX)?%S`;oXa*EGo^bmP;CNWWYMRfa zAzQ1!(~Rv$qG7s*OBbv;3MZD1yP1yLNvj@8+h+}spL|nO$dW;U5imX0`A8cI1wVs; zY4Zh~jrs2!9ibUW=$~!qQzRHg5THyTA;Dn;0S$x&us$Ibt~dy@j)DsfrX>(~Ti| zx+Le@w%wUoM5yAQduLO4TRS+`~L`MWs5J6XKpyM^r z-WrIw2KurF$~+MOVoJH|1h^5?x8WJLOSurN+u-|fivtjII9Rv-<~e!UTQOZb>|g6YpFc9&K7@|DJD7TwM=dRDxqT02VbqkTtRg zzpAke8MxA+O&bYDKh^1lZU0P7wGDmT5`*%gPV=EwZ^1GAz*2_H7rfhxU97OC+p1=b z#Io-ECQQ^Amk8pRcA}cmrr&|UPa3m0mN6?)4w&c^YF|Ow%O1Xu+7jO*KYuj^1h1N|mhJ@GIAc{cEBbv=4ccwt8nRuR;>2Sd6gP8R z-e_MmXPuNa(xo{cU15FWseY64RHjRok(c*z?X5`PiB|bbHj$Oau2$*GT;Ub$h6CV& zO?ahn!-4f;fvQt@xK-eiO=u;2!yz@&gklBV)yj3rCb$yQ)yj6cK-pO_)XGh&)$fcO zYGt_0Lk`nIB>1$2DSYTR_Cpv&N zg^3RLBX5zdFcTegBX1@6{~<~7cFy;-?63WMtBKYh-83mV-p3$$0Bb=BRY&rhkq+0sU zxb9Zz{11{y2S8*}40g8A(xH~t2Pdriq@{e$CaLm+J=2`ct(Y%9TILS5VlDGQB_HfH zTIPMOCvzWMzs{4E5Fgw;ww4X|!5;U;r`iXXbA6FF(gk?De=0TGYP=%w%=bT~tK1!j zGl!+toz|^ZZB(u(?A846DA8@?iyL;hNm_Q>u0Zpe%*<}puIh_rd7W*p^}LgN0|;e9 zT?`&>5<#(17b``38Xead7E=#5@t|@ACo{X61kB;dnztw>?KkWgk+}ks#v67Cn)~UV z*JT7Wnz(dNrsEpjV&S1C4pI%ZrbN0Y`Ekv?;?2P(R&!X5Hpn>if!1w9r3Pkmlf^<; zezJbzy4?-chM&k>p839!bvv3WVNFbp21Zf?Q=^WNRL9h)VQMHKc0mxkK!{xcp+;q| z@mtlXPnmR53f@YmurhO@T4;d_p35a8k&*|F62FxqzMm{Unk7EemfQ;OQH!q1Ly zt-B{4G3He<*2p4q$xNqt;>%LExNFD=+0+BsXZ_im{iAzC_rRmZ4@h4DNhwT?Bt}va zQzLyGFoWZ}O;no0c8zWE}0J9hH!c-{$;^ zzbs*w>_NCV3Eb^lMWT|*hgE-(jgfUVN@q4jHGn!vCAdwY-vsNsuNxLcaa-Y-{aE*{ zVaqjddo4S0O*{8GN%RtyG-C!VZ^k}cF3r4?d8de9t83 zn=B{Qt8FnA>14P$r5=IM`1e0YxSZ@t^I#8c&Kq||(d+Qy-`K2&fsJ1_oV zl2I@bnP^@1Xn=^npzkh+ot-lt?}l%5!(-jBAe|f0Fls!PO?HSV}W$3ds$8(lQis z7G)s;{!q(31q`Zo5SIUO2Q|+&JI^n1AA_TTz~dnBSV#CvM|g}QoW8A&?Y%c(sGjU{ z`gilyqnp3;>sUz=G|%S;>jicg?D$umj*f7YntSwiCW}$?JV1U4ExfJ`DkP?co|HOR ze{hi__;4@;Y``DusH-yM!=St17QV+J%k9L6qagGcr*^=&7XjRddnxd&oV&r(yKL`$ z){8o%(_2EKYCh%HEnMVqy&b5(Ns>^+;1nyL(ByBT3$rMHDtpk-TNSH5Ddg?6dR#Lq~UvxW@GZvTSS~lT)5j zQ&~3vc_X6s(P&s$lzM+hCh^a@&)&}jy}8|n7}vADjvyj96jf7LRYabPGy?KOi5=Bt z?(Ep|Pk(MuFKv3{uJ1VrnbRHA1OoHa)osAPbvY#j5Ed#ocG3Gj3A~)EPPDpvbnmZ& zOtsvZemOJtK__;DAFH&dy(#iiCkBjF#yU=i@kx;nnQKm{G`U$vxLiU*Ot3I{kW)9QZkd2%U(UI8I0EIsvDM+Oxm9i* zqQ^UqQE*?X_x5Xk6&`qFmZ+8x=LE6Q|Bm0w}GFrYgq>DJJr@n%!lUS>#l!driUXTPB~TP!_&~C@8z}`cu||L z;3F?QGt>kbVp_GaQNBBH0D@)n5DW~488V%OfHn8fd>cg+ z0$aNYwsTC;F(s5;cTPg?SJ9wy_{;#5by#XL9l&*Bi7p+tmxdcjgNv_X_tvq-U9dPZ z?K&(a!8lbqp&~?QY?k~8OX)g6>eXCg3|nIK-HrUT{w4ab>hz*~Wc@02gv<)S1D^-N zvye)k>p&WHSoJ!PIznj>M>lm=l3BLyBEH0M5~A^4r}ZT$6-URQb`lcA6B?urw0wlY zs^ITh`)$aY<@J8uoO<^aO||1={%*S8qUZ>u zfPf9)hLH1Q2&DmBAJUqmp1I2!5G5{rSk;9zIP2E{$t*`Zn=H)SuEy^e1K5G>A|Yiy zNv77`fiU+#m`fn*JRr=%?kE+DHl+ptu;L#2!u`orr8_<#G4;Z|#4u~qszM|-ez}6P?fs#7$m692V*KqM<-my_}m1LS?h)9V);7tsrw$UG0!ss zO*ea6Ug6NM;4PHZnPoHY%5-yjVR5}U{2J^t3G0J|1tR9Ba3dcyLc69(?Y z9$`z@!oT45eq#IJ?h&w-uv7#%0x*RuT!Y2c?`>lXonVbPx=2_9oH_zlkK60Ox*=i9 zIP@AeCK%RD!Y&iA>~$daI=?zB8v^zkhmOOc$CYCJPEjylYY9h~4+2&QkHeJdhGIIN zY{5VTP#g|Bh7&l!4iG?c^&p5Swu^w3sUI1|?YUY7TD&7+SrG0$IAbJ$w*Jd8ND2te z*@Ovd!UPDQ*a&Oe0}H2iY&ZraVFk;9Q}^JmR$(X-RvihrQ4f09(v7Qvz_>ybs^pP( z05tXZRhZpW9F`8x3!tv|8Nn5YH_r?`NS!^!LT(bDOG8EGgSW zl?HV#J57Hy zvXg_t`Hm5T5-beDt) zLRzU3s_)i`-;FVxCz*mKh|RuPT&^y~sd2u8Jv)WqLCk~pLC@j|(VSn|Q%ZnSOu(Ww z3YxJvhlEZCK$mi}nCr#AzQ#hWn!V|~;&%@;io6QxDy!f6`YhC@XF{!36#>6kze7LP zRUbl!Nf?3(pjVOFvoOZRcqMW#&a9n;`9`Q_)1LPzbX_ZSJrRHF?K7^}($h>es93QD zt!T$g5vmpZN5)=Tu0bnEm=S`w{OnvlyaXL-JXYBQv2w1fmU(-8TrEAzN;PXuHOrdk zOBd(67wbC`>x+%`M#uX4j7IFq&j&$M0-%Wj&^Xcrm7|p{UO_s<*AjkUbQU=>QmJz> zcjN8xsueI2{nB^j45N(vmv0KjD2-=F`^B;53>tcqs_8xG#OasksAsdOXX&)T-IXF2 z*;H>ckHw3vsl;z;pLOxZeX+FA-t4M;>OogcQztIwv$Z>?xi?qNagimtm_4C1kH^?9 zDxQRRBSO6`alXc97)yV;GmI&)FnhNUr-Dntt5=c>?zGVS)CRZF3!Q{L}f;@ zB(PZ$=qw4JED7T*i9L!%;hl++tw=rh<5F3a1sl>Lk054(uojlVQplh)*_DQqO1qK@ zyOJ_Dz~JLjK9ofoLCgS=O@*+&7C{+w20L{$d&^Lg?n!E|3y2I_1kHX7l;br|DHDpghoOwc>&HW^eQf8m&wj7my zLR$ESAk2M2oXou)EvVW`r*;}kCXhGW2g*kBONa7HX=G`Plf^;F;>KhEK$HYsvcz7J z#7L5KotQLYj!jGoLscbtpzG2gQYEoK<=(GPhDC>&TN7RumafNSUJo>pg$~US7q`<~ zQoLiVqc&aiK3llJ(}>5#$Q&wpqrWf7o(L8{D)y5BB^vM_m8RyGCL^txtXP?fsH^x7 zbjeqFrYXa8X^$8{3GCE;NmnjvV!XL8_twzFHT0J?@G#0kolwP%U}ccmi)VN5O~S5$ z`%xD6WkBbpu?Xv_q@Ise$KVVZpGXTuLe*D*aHrT^?9Wm!8M+fS_8MEETjlk%3^F7F=cr6WD6+9 z{-o3fY2kygE@Y3}0vG8Ppe#UyDprJb0XujLoPx4&MOf#H(~Ys7xucI`_T<5V1q*6o zte7emj2H{1iWwuujH!~c%FeC!N)rc-vMTkk3iq%AdXjpAz)l6F;TSQAD$wl^krEx% zS3-Ceb6!Ua9zqoZg7t=s&r5djCfJ))Dvz|_AXME#WK$Q>R?(TWI$BtX=opa}z~+{C zCjBNB^8VSlD0B%6Ikm264}FL*q5I}Ub}UMrc{!D8j?!Uk_XA|_gFecFflyV%9ybi2 zu9%H+T}98dm)bkAvFP+TU?Bl0Uc8Wbk&Yijv2$0R%Tb&*b zViB8Z*)OQvx0^q!sc4G%B7Q#w&uCscOi^vJNRI8SIsi|zE4>vp`#U!bd83Lldwu;r z6o&AV+vsRpkiOJ`RQRj*S5zOo1bY&f@LQ#jzmsVtdsRkmhh*~H)tiwfW(%f->Fc_!TJ0 z{&z%|@R6k%lYNr0^WCi#zmb9xA+lVuJ!+Tjisoh0et)znppowVUmR{(Mf;Ish}EaN z(wk3{i@W{m9`EsuN<2$bZ$;hG{PchV#S;W8JcK^KS2>X`5=X-|4l7LPp z)o%b!YV|wR) zFy}#pC{R^y;4K$JQbFB}6{VET;i>xcsLc1IC)Q&Tm__HRz_UH18&eo9eRR0F^CwcL!fyTVY7CWQQK2wo3Ni;k=om&6WF$Hf-l{B+sxO;!p zS=fPn*%f3i{?SD+` z@WeHoSNM=!`*q9Fxef)!2QR)2xzTy9ehB&J|AwYP?#17SwjTn=XZ!yM@gLSuAIP~G zw2XATztcyr+mZNLTVVL!qJt*D=5o6mOnFxO{GEsCHsj9B_TS#J;$Me}FG#h~3=)1C z-;-P~0;#9}-GZN<**M2`QN%CrnlzFzdXH8 z-8YUJY40w?XI>y8f8Xil`IHh^b@=irg%r(|W<_4T=NHl?rPyzdl@C9I`j2XUwDw=2a+G;={&DW6knVQnp)(;L1S<(DEB7=d*x0*H1p3J9@740}6J~@xW7#HhQ zItxE`guBM4{C@Pquimqg7|{y@h5wqUT}>PRW%Gx(KJa&O=UVx|B|}h~$Mc07f4R1C zCAv$4zb<|ggCG2KT3|?=H}L+uZXmMxt$KxhLuIawKyaT9^Vimp3?}dXJb2DXBe$|U zVLh(Jvbu4u_Y@wZ;PgGN{Jm5>&JnU*9g&$gZvIqWf69MGb~?D{)BQHD3km8b{9F({ zim*_1BR*dafV*6N{r!9DCoSotiam<-H{5TRsoVDz5jg+fOFtL0`;i)4=8;^)2@PP< z>g@8dgFA8YP;pPSvZ3j&;)QCv;iPBZB5hOQBa z4ZQ8cr>lXU$8NgAMHjQ&*r?r{ODd(rLF8!BPn zZuzHObb3a?wc>jlz0QF(1%D!g=&reI;_pxL zzR}s%2wbE*WZUX%`SzS!i}uHSa-hPCt4YNdqnAhG%yrBkojdnyI*a&@d3X++tX5yR zSFkI;uWvjGxx-5VH&BoGpn+-$v0Hgd?bg`7^-AQIibvDFN2@C@cXYw# z-6o~3niT)Wl!;@^@~wos^$ZQq=^=4hUuuiz7y@YK#xv}{7v%j#{wmIrt<=Dqg?-7p z{p{fZ`$c&s!31^K)voYevFd$J@i%{bO;FVD@0LG*r(t>vemaH_rLHoWcn7}{wbjmK z1}pz*#dcm&OuAIne|xNE9VRw@N?+aZTte$-Yj68Gb%Dl9p~VLsqJcYXRDYUxw}qEj z!~0nM$PjlYM9~=1H6N?W*X&>YMCC4Jzq`Yx8GpO(dy?^m8b4SpQC^Cw%keWDO4>xp zSghcx; zN;AvZ`_Ew?))G4ey#yVxha zx5GiC^e^!Jfho5spT?Qq8qc7F30ZcFO`f+4=U!>i{vS#V{K_WlCmR-?aq#|)Er`5o zuwJ=W8qDjyCCF29|K~vvrR5%j-an|mW>MrXpRv|YF4LN2`LEyY(N6zuMYhdFJ`C2I zu=*8P^8#DbS-IB=pxI?qdnD4$OIZ*33HDpx&-{8gVi8V%fLQYgtTE#F&Uat$AKL-X zT~{fW@~B`Iw8ZGub@h_kyFXJNpW{snt6co@WLxyOw4uXE|5m_HEYUs1=0&P2Txm~Y zO%^baNGo|b2!s;|U~9VU2+SEgh1~h?VB)Tv;ZJ?HVpvBj?vuvqe@(dxJO)g~&utK0 zH0>V+)I)b}Q>6a47+hg<0R9O#%tCjRu(T>k+i)|K&fIcY80*xBKYB zh1};OEXga2MYS<2rNtHXa4)D7R`2?Up4_P+;hf0u%COIpCHLbWQ>iN1P1>twP_gNS4g0l-}3ya^2Kqnj?&D> zU*lMdW9JF|!$0dG8k^>I|2{)uN4k!<2&K)FyKmD%xm!|1Y>6*b|4TfH@#ER5&S6sJ zulY6QJR=4U-TL9HdN2RdV(He!Sl44}?<;t}70_F0xtv=uJ28t^`cKr=g9k3_&MgLu zs0l%hG*8IiGR=6`zuLcRzuygEc&5zry7Qg^Mp{$AE9vS>8ZhYjyvIL4?~1q$Bq~Kt4D}o_!V-15>a$DL!o{4;CQzSuhjjU zK8Z?CP7S~(xw*WHuDPyWe<)^|Mbq*iXDc{&vzPhZHz z{pGAR5=Jk3=i&GComMG1i7uvxI-_%U%yhQ6*=Jtd4>`T~{fT(4azj0a^MMAq<10IX z=8E#cWzAV}+foszo$|&CuUizxRg|gcuk+9IVyQPPmJjz2vAGEqq=sbQ+A^HMRSx(TxO3zjtD8 zcYnw-)^OvyEopvDhVlDbT+^RdZ+Q!|W-(lLqnA39^wZppgT4JW=bYMi2V7NTPxrCzbWiJ_!RQb_Y3FSpnh`)Ir|V! zKN-15Me|X>H=86gFKvgk%MVo#N2*nICa3c;_cn2`>pDlI}^wH9~pP+SQD``|x4SNG+Lq2;&ZnqkTjUGiVilyNK6L`PKY{yn_vN^oRX6JJ0r ze}HV?lKdKS?m6QFZYLThhF3cSI_b}Q&fVQ6HR{`#&z@xaeR=hp{?17k6E}-p#H$x6 za5bWujG){H`BlyI?!9fd1P%QY(-iu%B^pmmA7Y)HM}?DfGi5F6^_=BBuIz#dF$9mY z=LheGyQM#Nen$?lv0bWc_F9nu2HEG=1bvM4zpn0W5e)Pva|Qn0MArL8^93IM`vN-p zB0N1*>-%&^`RUt@dt=G%tq+D`G|L5dxi4@Of3lOp=x^3jT%H~9|8fj9a2(s|qk1+8 zd66v|_U`HLPKOIS`rWI$U5{+bDi2z^Ei5my7xNT9OWjpC2;`r*n1At?a#!kbe3R1j z^NC}?Wrt9w$fq^zD)>~sZLvQ8oz3r$Cxtf31(3HtUNw_{OwbU`Wa*#%KL9&G#J^;F ziA5NLwD6I0;SDC&^*!0llDvFx7JUBvfK!8h86|8^~5XP{=&aR@0*Ro z>vn~8XzB=neyEZDY^?W0es$UtigUGW9*n0rj?Z26?`Uxu@?w3@lmB^*GWDkCb{}>2 zS&z>J*@;dmEFbR1rg^8!l#cHpySlb$e(K=^A{DX+z<3L&A>wxIZE40On`zPi&&f3QPCt7Vj$B%-S!`CtI+Tr>YWQQ8CQt6U=8+ekZd@ z)1iF&iA6Wf!3>BGNz6s#MSI^^QEw^QjoitzF>Mj%f%|$XH6FO{ihFx=;I3E8yI#M=W zDlKD`7J*X=SzgkZ zJ=y<3iHY-|-LcCrq1H7fc2AfFW5R3Y>-~<158=B|X6Qj5TF5@UH&)F-=ap2r-xg4R zmhPOC{mSx0h$r%&6_roR|8AcIu&L_Fk*1r+n+NzsxmjY$VNMsbMQnu4bO<0D3!7bn zaSs3~d;&avpI17KG7rJjv-`M`I|ovf9x+D#ZuWnT$C#mV6|B8A3VfRR>%EWTU3C(g z;Wf#Aa9yk99{-b=9*45Iu|0`TiS6tj8xzt z!8wckR(?0Kk@FOCA|BG-J%W`3c zf4I?xW7wC8&btiu$S33p>E2LAY$kw@n-A=j-fre^CmG{*>EYNrsmsl0ah^$~7#p86 zUqtUhj5FwGyyAU}8!hj$s17@Z9#=Ib$SIxtx=fxy9zka$N@K>xFL*GxH^^xz-R8Xp ze~o!X{K>egY~d9=>74wj&jJ5+#&Hckx{Gx4H*Ru9`=L6938sE#<*!pk2FI+lo4Cd> zbInHZdyVD|@9pjoYLC$O(%4<8Rw*qkrt0_I*30zbiz2CcyV5eO?ks5~!?dWZBlW!q zD!sy>d!F-#76m@DW>?<5K(_JV;ffv?A@wcl*u0Vt44GsWGGj>geLt1F)(z&F-m9YP zb~+CVJ~#0O_xiFMyXSBe?7wKM{+4h84jkOvis`}4>wk&c;&K-X_EWMlKY8G->GR6is!o<_*@hd)9P8%7m0>fdeUzIilXBv#_C>tNY0;6PfkX9N2aXd3_0Zv ze@Q~~On(^n^{8hklb^Mfew*y(Rqk&pW~SwNQmqC1Fi|}ji@D{EWx&|4Mz|05YLll8 z^xds|xiFiBwgG43AoCymN1V$w*e`_k&T#X`I|%)R%CZ!{%(58KO`Y$za&!?IdlL}O z@;c$KwU3jZ%^b&xCnESAGpS-)Feh=gC5H{OKh~Z)zPqm|{ieVzylkiZW+bJ)@Va%U zjf(P{<@LA+{%BMBGHvBN&e@LCp|zR+X1ihGz||n{<7_^By#Db2V*3H;d4Ts|xe4Sa zJFoW}Htr2TPovrE1`_OByYvM+H$TJY=7K-_tPwfW*BkKe$;3ac3BUXRIi<#oxB-)k zxDP;_c!y6J)J3~=75-S6Vf9A551DQtsPDZSPj|~tm&Eg=I8cB)qcz*TwuQ28KK2T@N z$n_p%+5#)Tl5SJK(hnrHS@!b-+1+6Gv1d>|OYU)=)}PwrW4H4D6YCC=xb?m~7tN41 z4|tpB-lsmOiP~x!PNkI!-|^pV@hE<`X!yV{Xmfzso{@Qu2xlSpH``W7ZfdK+K@_*% z_jBNVDt@SIBe*{8A)gqX0(}UT{7H!HqOMjl>zAUFM}R*{;!~{eQTs-osr5V`9!w6CPV+#7uiHZ! zRc>D=>=jM#-Ghtr4^ltr+>eChb3E1vCAQ{SdVh>w=VslW(bD%}2c&O>-G1QyO$y_Q zu5<6LzXYoBEbu^wRA*^?bB(_mzg^osgW&}{mmkT;0W4N#0YT>lacsE9pf|s8-CzDz zv+;475bVwIIq+C7Gl~6nC$13-{eMb)U8A)DylOK^bif5l=u2TbItPDB(kyBuxaf(1 z`-2yoLl|otEuK@eo+tjwB?Ie)R$2kS@+46Qk~I0n=S{ddIr9rWbUq}mBh)n(M)Xyv zj7<3`n5Qbe=rwrYkLL5H5MRu~BQ~S8eaO1PQYRpO!4N-?I}=v>Z+II)6O(~(W(Hs9 zIgQ8n4eVWq(-WNy+w{+|mwi1uS$ih_Hr^m*VOs1dWJ$z8X1T+v8%^>{Y~^}K%eL|i*Ou-dZ^C|d0k+Mi<|eq zcuvXxe_Zwv2@(ixa`XRQ2zuY6avaGOaL1MOLlmGdkD&Xn%?1^ z6`40UKd5wkc1P4JTgu%s!?)xa`t07-(xc{1c2>{8DEcFb#awM{@lqGL-|g=dTOfXo za=DIl(5DWX7MBJZ_^S=0rbaMAC9SdYpT4ADDr4TZOzTAqz`epbOK)yz^l+-1`*7ny z!qWp{q_6wa$k=xM6Q}8<(C-WyPO(<@QWNJ#2TpA)H?BqEzw3W4+ObilH3K9Nyw2=j zPIW_iC@c9`2|G@3ERnOXqB@_K<#_s6_-AU~x!0_1>+H_4ai7@Iv3oteH45k#h0ZeH zaBYYux}|uRL2w=qB`F;Fp+%0`atZW^#>&(z61R^ zDIcU%m$BAiRGOFtU|TSs^bDqh)b)N3Scld78$fJEQ zwrbRY)A-AE$D(P=6K<{Z^FAfNUb>mji+qdiT6PUaMs=$2loxV-4lPPYfB5Ju)xB%@ z!1XXtwklfcQ+~?Zz&-unZolHnFp7DWvQ|o;b`Ac^&a6TCSWF+ULU-Eoex^G%#J+jC zEjSb7aYqdqR1|l4Nc~@)8NDB|cGqoYxaOfD^nWY;%_w?>1oV#}H$EhPcG*q2=&nq03US?Yyq*p1X{%Xpk%bxt@=QogrF)VAt z3r$cXsTmkA3*2IhB1!I>bP{IE8l@NX<4t^H(TkUkM}aVl2o~42Q!(0pT|)=nO%B&3iVvko zi+=q2d6AU-1a+^?4eF!_uhE!5?(bl)gChP*=ekCH?>;?H{>>0l*LcV)Q@8o*+~p|c zv|^(L^AIFiYKZ^f-=R9Cw{8Gh@2`)5xTahk0I=R-a0y{UNN|pPtKhWbt~*Ho{Cl z)Y7m&)tT~&?=j_EUG9HV%EAV44#)alOYy&{YCIThGa-Q*EE64ny=O1m^L06ZqA-Fe zs?*7X+a`^-%QG??841`2KFBsqT4UTdLZ}-9gA(g@F9od4mGwe#?VxxiW}LER2TDgN z_3u*pm9Z=>gB3sSKdyi>12ZQs*WS5f85ki#t0s8Fmt6@mB7Dkt z`Fd9yePa@6zr5h)=prJ&YO1AJs=AyR8G!B&y(CTiE!{%+{dJ3~{-zGJX_Ujq{jNFl zjV|4(HH(TI1%I4_rJlfzFu!m4Gr$Juf6QCnjRbR}1O?4T;yrrrh@PrsK@^Yk5e!hj zxUSk)<=~37b5XgcX5n#8Xvt-=$vu}NiR``>rDaqM{`1^~klheACsGvUe*n915DX^= zr6*#;+(ov7Isb~;yPEGx>oBTR!=VVrx?FX_xEgzZ^0JMPLSx+1NEdB>k#&~!Ck z7ZcyNPE>QX$`DBM52eZR^;eoV>*dGSh(=Bowrg>T$E3(jB?zM9BL~0!)sMddmnx2s z%-y%BjtVb(7)!)3AMiC}B|;2_IpFKcC-L{CFNfE|RHw|;<5FoQlPUOG^o+uFG>mk! zDKbF-zlf4{m2dvm4}{gMaQ5r6H05Ya+{`#a2(GVCu9f(-jqADhFi^@!;m5d+&z(J= zz=IW5bLrSo>cW#DW2S-J*fjScN2MlSnnG-@BDL0Tl)iQ~Cq@LR@e+gJNxDQXrzNzT z^*30JqIL=G*4sl5tp~T&>)k;esDqY`(w5`8Mg_5XoJm})O5PnXg;wfcxIS=bvNMMD z<{-|ELaT7GzwUt>FTq5ogAf+2L2D}BWrP(J@P}ce1cL4l$Zt+g`?@EO?c|%byL1-o zV1@5GM~O4nThl7Q@FMtnfRx3h*-1BI_FnE>(2pT1DKw{ke2ddi<}hWT{W2YP=`DQ( z_5k$-Lyymzf}+~2stB}TtM4dZouI0?$|dW$_}g)w-{5ZEQl#L8p&V0CEtT5mL1OXk zH1@(tu;fH_R}CWbMbW*v`3B74d!F?RSs?4q zUQaR!LY+t&&O~mql}{y3i_q#h;IxjJ&AmiyE~w%#r>dy%z#}4ai$e{tzC?rM1=OIf zLO0Mc+4E&L&|V^TveRhX>5X(*l{Yyzp*a@davDvg_mf($TwwYVvG3L;Ouc9RM%g6vmju^-uu;4^u*TfO&0)6gq zm;ZIZs%Si~Y}?$cKC+qslz9F8q-CwT0nGv}#(UByW=sFFavn553|ykerl>{Bz~|c{ zB)(SHt5nWcfy7nx+V8GiYE1O-H4;FuxlNs5X81Mk&E0ZAnDDV8%)g8NkDE_~u<$RU zdyNfNmf+8%1(o3m!MzRwAFweA#vq+EbD8K;Tn9$gad#3ewrNDf4+BsTJG!f!2XHeC zbE4+*N>Ia8p~|U)yL>Ac=g&tI-n_sdq|jH_`z$IkBmo(Uck{BB80!oDz?YOuB(1S6 zumi(peuNX{tQQd{MdKu3Rb_5(?=D#GUhz{_mU%fmM}9|56xVJ~_-6p~3dg~Myb?T~ zKTN^}4jL{aa+hyVwJccXo`x(CAVEs;1REkSG5PtF&T{EM<_R#dOJK6w%9|e-kP-A4 zP$ka!QduK(Av-R|P)|2sj~RR;B%te_W}C`0IV`~b+Q6i{kq*Q5GiBw*vySLyqKe^> zZ`Uym_5vMpB8P4dqRmobbDX;J8N03`tXO0cvWIk+vdLGg zHRQ-~_#Fr~gQf_=<27ZgO`no5!LTKr2GB3x6xTLp2&qtTm^0&t&?-3?1E^aQz7I2P0q$di#QBBuu z@D%N#nu^Pxw(u2_EK(An;lWFvsystKFOM!-ZWu|)H_?OLu{C4?U5=}H};&pg*d`pDUk zcxw0@@OjQ!<5I7`z9>9-FGcCoSu*b>(1+!@KZ-vh{D1%3_n)sfXrS~!SwZ&FgSb+> zc{v}XI{PS}4e=LIK|(>y%HT=gh-I?+A55Z}4mg9KRujyg)C4tTtvVyOJDP#|&hY`a zV^mHo0Da2mNFy_SxdD2k>Ch^pxKK8CV)1+Q*T>OBhrkDpZwXu+2w;hnCGH5-sBnfc zE0&b0o?DFIakUymJW$(oGc;l2asf0zmJ@W zVJVu(dq~-seZPVQPfLS>r;T~x0G1~GmLwM;cKA@C`PJueOkxHHeNO}Y&vQ3p#b+^j zV<=~9XG8#*Z{1Tl?tRBSw*tNYCx~NfdoGV)8H?k3&^k?+NfioXa=_FJe)(6YVwxxl z4^SpO59}a$^V#4#%vlHXT^WWoTU1OMKzC#`hZso2S;bY_;Z?Tp8cW z4raRBBY^133A=-rUf%6^?L{yeJHme&Wit`>_glt@<@>#%g1Z6un>U_b+{dtq@Tfmdog=ZCB2 zYb79J#=P==q8!dJ)IV-a0uyR?4eqcE8r?6}UHbJ_m+ldC;jesfNB*ej?*MBfHfwTB zxVCkc_}?*HBb5Oj&CmihKXW#h>Mi~3CswG{kwQypEH0@#h**w*joK&nfj~^A0%4G~oI(O)D_@|~X(@r1 zqbG{J%a9&>Gh>*M&8nqE2R0#6^)!3G6$8x`8s_0ZU9*og#zzxc2MN7r2B)ce>&x6J z@iDqjNPzNxLJW(b zv|`QA@j%1@v^gTm#cpZ_#Q?gRT^0GmHqU4I#Rm*^OeE zd()p}1oCo!DMmoOvEG4_Z(*U7G_4@CJC13lr3+i(f97ynU|UdZ2Yb92rN=S@ArG0X z?fc$_hLQs&6>C(587}((s9-If7a{Sh`}*RZb6GDx-2`qU)H0^F?{(}PcMMo1V|m_A_F)%ZLYGTiqsi_+Ur{0&MKc^u2OSmjzT8o7Jy%G4 zUuKbtyhU^*VuxvGlk@sgt#U+3#Qr3;q(U-A`*f3pHoHs0OQIYBP+-lT;A9FY1~$r9 zyPpbWaV+Ii8VRz_fG{S?Ou5>9dRw6yj<>}!Yt9KdvAWx|+yS(MfnzeYrKcB{{Q3f+U@MDMaNL!woVEV8g#bZ#A`mzp zfa_gcCsH~F!7D0ia*^;a;s!;GleJro9{mtnrUl-|%UFXZr&yJTL-4T~yVY(e6ZNVz zNEJvtCGxxCQSdDK%3HRkz5M#R3%OXbr|jl>b*PHdFtTW3TN>69*3)iJvGf z78G>scn+waEwEMo`NnqCfBxamDrhH4vHcM2wesQ18L+Uh`eWkvA@*kR-{qulE4->^ zr!qJXRBqL039`(yDs_#@qo&K#X3$oi^Hqs5=>;TEaJOn9D-UQ<6{(B4naCfs&R`+4 z5q8ED`|Pe|i<;I=8QCEv0&qZGqHnDMO^`sN@>vygrKjOOwv_rR0VX5@ck45{%!iYca! z!@S2t%YjFaugc-Vx?XGUzJtjpV#mw+q;;lxo`)7&FMX9Dd(d&+8Jy!uXM>&2Wc14B zl7F@#rUoSZEzs{y20C#CA<_QbQJt-*nHIxr;@DjEABwW%`AHR z;h8qG`p>_5#As*l-M&z^B2`26XdWV=KS~cA#>htdR&i=^)pknm#QzafuN&EyN8wrn z$6RVLjf4CLz*)4Wg)Bp21+JhU@7j2M*yA!-Ub(d6rp4;&!kt#ECgwk*bFXPDeGZ3W z%Wt<@3_CU&lu>bXRQeb~hkXzxjqK>;=?Vy0t1s%MEU-UJQy)6lD@AV}BCnFKh4gz& zA^`3G4D|fyuy2`xQBcoL2Mm%cCV4VX<0R%T$jsE_jnYUIPEyGqyanJ`>y^D*yV1{g zpn?bUz+O?x?2}Hl$R)s(XI zBtDN>U&M-0qK!Z6EL@!v#+YsV#2(;HS1r(n*reEYZ|l$AJwi?H$J09ln=@b06;dx1 zPQzU=syR3q4dJEeDa*69F(v}d0WPr!DdV}&^l1f+9FlyPFVXae0c$aj-D-<2TPIW> z27#Hg3e+W~h93Z$ytKVH zC>9Qf0Hw1_E}7YJ6-%0>yH^Ft1qm1xg8Zk)Vo8q5;P^y=*+tgD1_8)2%NMwE@NJu{ zpn)wnABeUR&3e}mRFmW8!Nrk!xFEp0o3jF?^D=%yVgT4(kX-C^Q*ZNN`0UEWUnK%l zbl@1niT^%w%QNI2BJ5U&GKxiJ!F~-=t9Qi=|2IIT$ouIbsJkf1gzZe@ zSK|-Xob82c12+pk&sRDZGMV@sR7TB|-er4;jqHgJVGRagF9m9V>F}TfZBug|a63ak zix6Cr%l*!&++*}^RM|N1n z7WoXolXEnrQP|_McS;JC^e55&LFYTxnRsPJ$Qa@UR?T$@SQM{p>W%?)vYhAy0f;;5 zIAt95>3}FGF;749!1s8P+z*Fhow)?Jb#R;|5>R-Op1gnU#G+H=^LPPj@=ieY6L>HL zqCf@RB`C=%-gZ@0jByBRE%J>VShhH�?y@SV1P>r>iLw+K4ta^^xyF=}=b>>F`8V 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 n0002{1^@s-1_1zBi~snN literal 0 HcmV?d00001 diff --git a/tests/files/web/modifier_reader_batch_three_scene.blend b/tests/files/web/modifier_reader_batch_three_scene.blend new file mode 100644 index 0000000000000000000000000000000000000000..abd0f46f7e4c312120526eb17ea9bca003c3338a GIT binary patch literal 98640 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 ?7M;$U#D*uanW`fS5qA_>Yu+GRKcS>j&c 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�?y@ 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 blender-web-editor@0.1.0-rc.1 typecheck +> tsc -p tsconfig.json --noEmit + + +> blender-web-editor@0.1.0-rc.1 lint +> eslint app + diff --git a/tests/golden/WBV2-P1145-001/continuous-runner.log b/tests/golden/WBV2-P1145-001/continuous-runner.log new file mode 100644 index 000000000..be1991ac3 --- /dev/null +++ b/tests/golden/WBV2-P1145-001/continuous-runner.log @@ -0,0 +1,3 @@ +v2-task-index-generated tasks=71 active=NONE output=tests/golden/WBV2/task-index.json +task-context-ok task=WBV2-P1145-001 parent=WBV2-P1145-000 contentTokens=1840 envelopeTokens=658/1024 estimatedTokens=2864/3500 taskBytes=1771 next=NONE output=tests/golden/WBV2-P1145-001/task-context.json +module-task-complete task=WBV2-P1145-001 module=CORRECTIVE_SMOOTH_READER next=null commands=4 diff --git a/tests/golden/WBV2-P1145-001/manifest.json b/tests/golden/WBV2-P1145-001/manifest.json index 003097a9f..3bf1af1eb 100644 --- a/tests/golden/WBV2-P1145-001/manifest.json +++ b/tests/golden/WBV2-P1145-001/manifest.json @@ -47,7 +47,7 @@ }, "status": { "path": "docs/status/WBV2-P1145-001.md", - "sha256": "e4fccc7e41be4081f9019138d0dbf204b5d3681cdbb23546362b8140485ac4c2" + "sha256": "d86883f696ea02127ba8b24b69ead3afa397e01fa07e0cedbb8d3b3cacdcbfb4" }, "log": { "path": "tests/golden/WBV2-P1145-001/module-run.log", @@ -83,5 +83,5 @@ "historicalEffectivePending": 6609, "historicalReproduction": false }, - "nextTask": null + "nextTask": "WBV2-P1146-000" } diff --git a/tests/golden/WBV2-P1145-001/scheduler-child.log b/tests/golden/WBV2-P1145-001/scheduler-child.log new file mode 100644 index 000000000..e69de29bb diff --git a/tests/golden/WBV2-P1146-000/manifest.json b/tests/golden/WBV2-P1146-000/manifest.json new file mode 100644 index 000000000..ef494cf40 --- /dev/null +++ b/tests/golden/WBV2-P1146-000/manifest.json @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1146-000", + "parentTask": "WBV2-P1145-001", + "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", + "status": "done", + "enablingTask": true, + "parityStateChange": false, + "runtime": "MODULE_EXECUTION_QUEUE_BRIDGE", + "artifacts": { + "parentManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "plan": { + "path": "tests/golden/WBV2-P1146-000/module-execution-plan.json", + "sha256": "e5215ac212b87c0aee8c526d490df30bc6e9cd4a6db4f9634b3c893b6b36c7bb" + }, + "report": { + "path": "tests/golden/WBV2-P1146-000/successor-authorization-report.json", + "sha256": "bf17e9bdeb3c39aaca1e97fcff1ebe8154e2d4bc17bd15a523028146a933994e" + }, + "status": { + "path": "docs/status/WBV2-P1146-000.md", + "sha256": "ded9ac0ad58665cc0f4e1d1d672e8460772b632ed8df173555d281fcc20856f4" + } + }, + "assertions": { + "sourceBackedSuccessor": true, + "moduleId": "MODIFIER_READER_BATCH", + "batchSize": 9, + "inventoryTotal": 6900, + "effectiveCompleted": 290, + "effectivePending": 6609, + "dynamicUnitCount": 3745, + "dynamicVerifiedUnits": 350, + "dynamicUnverifiedUnits": 3395, + "boundUnitDelta": 0, + "fullHistoricalReproduction": false + }, + "nextTask": "WBV2-P1146-001" +} diff --git a/tests/golden/WBV2-P1146-000/module-execution-plan.json b/tests/golden/WBV2-P1146-000/module-execution-plan.json new file mode 100644 index 000000000..f40cef5c3 --- /dev/null +++ b/tests/golden/WBV2-P1146-000/module-execution-plan.json @@ -0,0 +1,5684 @@ +{ + "schemaVersion": 1, + "planId": "BLENDER_WEB_MODULE_EXECUTION_P1146", + "operation": "FUNCTION_MODULE_MIGRATION_PLAN", + "status": "COMPLETED_MODULE_EXECUTION", + "authority": "blender_main_source_and_existing_hash_bound_receipts", + "executionPointer": "docs/EXECUTION_QUEUE.md", + "inventory": { + "path": "tests/golden/WBV2-P0-002/parity-map.json", + "sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8", + "total": 6900, + "legacyCompleted": 281, + "legacyPending": 6618, + "effectiveCompleted": 290, + "effectivePending": 6609, + "mutation": "forbidden_by_module_execution" + }, + "reusePolicy": { + "completedReceipts": "reuse_without_rerun", + "continuationEvidence": "excluded", + "duplicateValidation": "forbidden", + "fullFamilyParity": "never_inferred" + }, + "verificationPolicy": { + "browser": "chromium_only", + "required": [ + "sourceHash", + "wasmBuild", + "positiveMainMutation", + "negativeNoMutation", + "undoRedo", + "saveReopen", + "aggregateManifest" + ], + "failure": "keep_module_in_progress_and_do_not_advance" + }, + "modules": [ + { + "id": "RENDER_LIGHT_CAMERA", + "task": "WBV2-P1100-001", + "owner": "RENDER", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-LIGHT-TYPE", + "CAP-RENDER-LIGHT-AREA-SHAPE", + "CAP-RENDER-LIGHT-CONTRIBUTION-FACTORS", + "CAP-RENDER-LIGHT-SHADOW-CONTROLS", + "CAP-RENDER-LIGHT-CASCADE-CONTROLS", + "CAP-RENDER-LIGHT-AREA-SIZE-Z", + "CAP-RENDER-LIGHT-CLIP-START", + "CAP-RENDER-WORLD-LIGHTING-CONTROLS", + "CAP-RENDER-WORLD-PROBE-CONTROLS", + "CAP-RENDER-WORLD-ENVIRONMENT-STRENGTH", + "CAP-RENDER-CAMERA-DOF-FOCUS-OBJECT", + "CAP-RENDER-CAMERA-PANORAMA" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P595-002/manifest.json", + "report": "tests/golden/WBV2-P595-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P596-002/manifest.json", + "report": "tests/golden/WBV2-P596-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P597-002/manifest.json", + "report": "tests/golden/WBV2-P597-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P598-002/manifest.json", + "report": "tests/golden/WBV2-P598-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P599-002/manifest.json", + "report": "tests/golden/WBV2-P599-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P600-002/manifest.json", + "report": "tests/golden/WBV2-P600-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P601-002/manifest.json", + "report": "tests/golden/WBV2-P601-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P602-002/manifest.json", + "report": "tests/golden/WBV2-P602-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P603-002/manifest.json", + "report": "tests/golden/WBV2-P603-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P604-002/manifest.json", + "report": "tests/golden/WBV2-P604-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P605-002/manifest.json", + "report": "tests/golden/WBV2-P605-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P606-002/manifest.json", + "report": "tests/golden/WBV2-P606-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SCENE_OBJECT_MESH", + "task": "WBV2-P1100-002", + "owner": "SCENE_MESH", + "sourceBacked": true, + "capabilities": [ + "CAP-MESH-TOPOLOGY-FAMILY", + "CAP-CORE-SCENE-OBJECT", + "CAP-OBJECT-MOVE-COLLECTION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-001/manifest.json", + "report": "tests/golden/WBV2-P11-001/mesh-topology-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P12-002/manifest.json", + "report": "tests/golden/WBV2-P12-002/scene-object-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P24-002/manifest.json", + "report": "tests/golden/WBV2-P24-002/object-move-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MATERIAL_ANIMATION", + "task": "WBV2-P1100-003", + "owner": "MATERIAL_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-MATERIAL-ANIMATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-003/manifest.json", + "report": "tests/golden/WBV2-P12-003/material-animation-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "NONMESH_GEOMETRY", + "task": "WBV2-P1101-000", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-VIEWPORT-NONMESH", + "CAP-NATIVE-DATABLOCK" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "NODES_SIMULATION", + "task": "WBV2-P1101-001", + "owner": "NODES_SIMULATION", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES", + "CAP-SIMULATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ASSET_IO", + "task": "WBV2-P1101-002", + "owner": "ASSET", + "sourceBacked": true, + "capabilities": [ + "CAP-ASSET-LINK-OVERRIDE-RELOAD", + "CAP-ASSET-CATALOG-MUTATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P10-003/manifest.json", + "report": "tests/golden/WBV2-P10-003/module-matrix-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SCULPT_PAINT", + "task": "WBV2-P1101-003", + "owner": "SCULPT_PAINT", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-ATTRIBUTES", + "CAP-SCULPT-PAINT" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P16-002/manifest.json", + "report": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "UI_EDITOR", + "task": "WBV2-P1102-000", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-UI-EDITOR" + ], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "INVENTORY_GATE", + "task": "WBV2-P1102-001", + "owner": "RELEASE", + "sourceBacked": true, + "capabilities": [], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "OBJECT_OPERATIONS", + "task": "WBV2-P1103-000", + "owner": "OBJECT", + "sourceBacked": true, + "capabilities": [ + "CAP-OBJECT-DUPLICATE", + "CAP-OBJECT-CREATE", + "CAP-OBJECT-PARENT", + "CAP-OBJECT-COLLECTION", + "CAP-OBJECT-RENAME", + "CAP-OBJECT-DELETE", + "CAP-OBJECT-TRANSFORM" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P17-002/manifest.json", + "report": "tests/golden/WBV2-P17-002/object-duplicate-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P18-002/manifest.json", + "report": "tests/golden/WBV2-P18-002/object-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P19-002/manifest.json", + "report": "tests/golden/WBV2-P19-002/object-parent-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P20-002/manifest.json", + "report": "tests/golden/WBV2-P20-002/collection-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P21-002/manifest.json", + "report": "tests/golden/WBV2-P21-002/object-rename-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P22-002/manifest.json", + "report": "tests/golden/WBV2-P22-002/object-delete-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P23-002/manifest.json", + "report": "tests/golden/WBV2-P23-002/object-transform-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "COMPOSITOR_SEQUENCER", + "task": "WBV2-P1104-000", + "owner": "MEDIA", + "sourceBacked": true, + "capabilities": [ + "CAP-COMPOSITOR-NODE-GRAPH", + "CAP-COMPOSITOR-UNSUPPORTED-GATE", + "CAP-SEQUENCER-MEDIA-RECOVERY" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "AUDIO_PARTICLE", + "task": "WBV2-P1105-000", + "owner": "AUDIO_PARTICLE", + "sourceBacked": true, + "capabilities": [ + "CAP-SOUND-PROPERTIES", + "CAP-SPEAKER-PROPERTIES", + "CAP-PARTICLE-SETTINGS" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P33-001/manifest.json", + "report": "tests/golden/WBV2-P33-001/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P33-002/manifest.json", + "report": "tests/golden/WBV2-P33-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "RIG_ANIMATION", + "task": "WBV2-P1106-000", + "owner": "RIG", + "sourceBacked": true, + "capabilities": [ + "CAP-RIG-POSE", + "CAP-CONSTRAINTS", + "CAP-NLA-ANIMATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-003/manifest.json", + "report": "tests/golden/WBV2-P13-003/rig-pose-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CORE_SCENE_GRAPH_SETTINGS", + "task": "WBV2-P1129-001", + "owner": "CORE_SCENE", + "sourceBacked": true, + "capabilities": [ + "CAP-SCENE-COMPOSITOR-SETTINGS", + "CAP-SCENE-PERFORMANCE-SETTINGS", + "CAP-SCENE-SAMPLING-SETTINGS" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P65-002/manifest.json", + "report": "tests/golden/WBV2-P65-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P66-002/manifest.json", + "report": "tests/golden/WBV2-P66-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P67-002/manifest.json", + "report": "tests/golden/WBV2-P67-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "UI_EDITOR_VIEW2D_STATE", + "task": "WBV2-P1130-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-EDITOR-VIEW2D-CUR", + "CAP-EDITOR-VIEW2D-MASK", + "CAP-EDITOR-VIEW2D-FAIL-CLOSED" + ], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "CURVE_TOPOLOGY_EDITOR", + "task": "WBV2-P1131-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-TOGGLE-CYCLIC", + "CAP-CURVE-TOPOLOGY-GATE", + "CAP-CURVE-TOPOLOGY-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/M9-05/manifest.json", + "report": "tests/golden/M9-05/curve-toggle-cyclic.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CURVE_HANDLE_GIZMO", + "task": "WBV2-P1132-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-HANDLE-MAIN", + "CAP-CURVE-HANDLE-GIZMO-PREVIEW", + "CAP-CURVE-HANDLE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CURVE_SPLINES_TRANSACTION", + "task": "WBV2-P1133-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-SPLINES-MAIN", + "CAP-CURVE-SPLINES-RECOVERY", + "CAP-CURVE-SPLINES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SURFACE_TOPOLOGY_TRANSACTION", + "task": "WBV2-P1134-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-SURFACE-TOPOLOGY-MAIN", + "CAP-SURFACE-NURBS-BOUNDS", + "CAP-SURFACE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FONT_BODY_TRANSACTION", + "task": "WBV2-P1135-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-BODY-MAIN", + "CAP-FONT-BODY-RECOVERY", + "CAP-FONT-BODY-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FONT_PROPERTIES_TRANSACTION", + "task": "WBV2-P1136-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-PROPERTIES-MAIN", + "CAP-FONT-PROPERTIES-RECOVERY", + "CAP-FONT-PROPERTIES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "METABALL_ELEMENTS_TRANSACTION", + "task": "WBV2-P1137-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-METABALL-ELEMENTS-MAIN", + "CAP-METABALL-ELEMENTS-RECOVERY", + "CAP-METABALL-ELEMENTS-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "TEXT_SOURCE_TRANSACTION", + "task": "WBV2-P1138-001", + "owner": "SCRIPTING", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXT-SOURCE-MAIN", + "CAP-TEXT-SOURCE-RECOVERY", + "CAP-TEXT-SOURCE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1137-001/manifest.json", + "report": "tests/golden/WBV2-P1137-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "TEXTURE_PROPERTIES_TRANSACTION", + "task": "WBV2-P1139-001", + "owner": "TEXTURE", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXTURE-PROPERTIES-MAIN", + "CAP-TEXTURE-PROPERTIES-RECOVERY", + "CAP-TEXTURE-PROPERTIES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1138-001/manifest.json", + "report": "tests/golden/WBV2-P1138-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ACTION_GROUP_READER", + "task": "WBV2-P1140-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-GROUP-READER", + "CAP-ACTION-GROUP-RECOVERY", + "CAP-ACTION-GROUP-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1112-000/manifest.json", + "report": "tests/golden/WBV2-P1112-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ACTION_POSE_MARKERS_READER", + "task": "WBV2-P1141-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-POSE-MARKERS-READER", + "CAP-ACTION-POSE-MARKERS-RECOVERY", + "CAP-ACTION-POSE-MARKERS-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1140-001/manifest.json", + "report": "tests/golden/WBV2-P1140-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FCURVE_SAMPLE_READER", + "task": "WBV2-P1142-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-SAMPLE-READER", + "CAP-FCURVE-SAMPLE-RECOVERY", + "CAP-FCURVE-SAMPLE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1141-001/manifest.json", + "report": "tests/golden/WBV2-P1141-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FCURVE_MODIFIER_READER", + "task": "WBV2-P1143-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-MODIFIER-READER", + "CAP-FCURVE-MODIFIER-RECOVERY", + "CAP-FCURVE-MODIFIER-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1142-001/manifest.json", + "report": "tests/golden/WBV2-P1142-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "DRIVER_READER", + "task": "WBV2-P1144-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-DRIVER-READER", + "CAP-DRIVER-RECOVERY", + "CAP-DRIVER-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1143-001/manifest.json", + "report": "tests/golden/WBV2-P1143-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CORRECTIVE_SMOOTH_READER", + "task": "WBV2-P1145-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-CORRECTIVE-SMOOTH-READER", + "CAP-CORRECTIVE-SMOOTH-RECOVERY", + "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + "tests/files/web/modifier_corrective_smooth_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MODIFIER_READER_BATCH", + "task": "WBV2-P1146-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH-READER", + "CAP-MODIFIER_READER_BATCH-RECOVERY", + "CAP-MODIFIER_READER_BATCH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + } + ], + "tasks": [ + { + "id": "WBV2-P1096-000", + "phase": "1096", + "title": "supersede_generic_continuation_queue", + "kind": "bridge", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1095-003" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "bridge", + "gate": "QUEUE", + "card": "docs/tasks/WBV2-P1096-000.md", + "behavior": "Replace the generic continuation queue with a finite module execution plan without claiming capability parity.", + "outputs": [ + "bridge manifest", + "status" + ], + "acceptance": [ + "no parity claim", + "inventory preserved", + "module plan hash-bound" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1100-000", + "phase": "1100", + "title": "reorganize_module_execution_plan", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1096-000" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-000.md", + "behavior": "Reuse completed source-backed work and activate finite module-level implementation and verification.", + "outputs": [ + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "completed receipts reused", + "generic continuation excluded", + "one module active", + "inventory preserved" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1100-001", + "phase": "1100", + "title": "verify_render_light_camera_module", + "kind": "module", + "owner": "RENDER", + "dependsOn": [ + "WBV2-P1100-000" + ], + "parityId": "RENDER_LIGHT_CAMERA", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-render_light_camera", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-001.md", + "behavior": "Complete the RENDER_LIGHT_CAMERA module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RENDER_LIGHT_CAMERA", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-LIGHT-TYPE", + "CAP-RENDER-LIGHT-AREA-SHAPE", + "CAP-RENDER-LIGHT-CONTRIBUTION-FACTORS", + "CAP-RENDER-LIGHT-SHADOW-CONTROLS", + "CAP-RENDER-LIGHT-CASCADE-CONTROLS", + "CAP-RENDER-LIGHT-AREA-SIZE-Z", + "CAP-RENDER-LIGHT-CLIP-START", + "CAP-RENDER-WORLD-LIGHTING-CONTROLS", + "CAP-RENDER-WORLD-PROBE-CONTROLS", + "CAP-RENDER-WORLD-ENVIRONMENT-STRENGTH", + "CAP-RENDER-CAMERA-DOF-FOCUS-OBJECT", + "CAP-RENDER-CAMERA-PANORAMA" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P595-002/manifest.json", + "report": "tests/golden/WBV2-P595-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P596-002/manifest.json", + "report": "tests/golden/WBV2-P596-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P597-002/manifest.json", + "report": "tests/golden/WBV2-P597-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P598-002/manifest.json", + "report": "tests/golden/WBV2-P598-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P599-002/manifest.json", + "report": "tests/golden/WBV2-P599-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P600-002/manifest.json", + "report": "tests/golden/WBV2-P600-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P601-002/manifest.json", + "report": "tests/golden/WBV2-P601-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P602-002/manifest.json", + "report": "tests/golden/WBV2-P602-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P603-002/manifest.json", + "report": "tests/golden/WBV2-P603-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P604-002/manifest.json", + "report": "tests/golden/WBV2-P604-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P605-002/manifest.json", + "report": "tests/golden/WBV2-P605-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P606-002/manifest.json", + "report": "tests/golden/WBV2-P606-002/implementation-report.json" + } + ], + "positive": [ + "setLightProperties", + "setWorldProperties", + "setCameraProperties", + "camera panorama", + "world environment", + "light shadow/cascade" + ], + "negative": [ + "invalid enum", + "invalid numeric bounds", + "near/far conflict", + "unknown target", + "stale revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker disposal" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:lighting-field-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-lighting-fields-production.spec.ts tests/e2e/lighting-field-roundtrip.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1100-002", + "phase": "1100", + "title": "verify_scene_object_mesh_module", + "kind": "module", + "owner": "SCENE_MESH", + "dependsOn": [ + "WBV2-P1100-001" + ], + "parityId": "SCENE_OBJECT_MESH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-scene_object_mesh", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-002.md", + "behavior": "Complete the SCENE_OBJECT_MESH module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCENE_OBJECT_MESH", + "sourceBacked": true, + "capabilities": [ + "CAP-MESH-TOPOLOGY-FAMILY", + "CAP-CORE-SCENE-OBJECT", + "CAP-OBJECT-MOVE-COLLECTION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-001/manifest.json", + "report": "tests/golden/WBV2-P11-001/mesh-topology-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P12-002/manifest.json", + "report": "tests/golden/WBV2-P12-002/scene-object-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P24-002/manifest.json", + "report": "tests/golden/WBV2-P24-002/object-move-receipt-report.json" + } + ], + "positive": [ + "mesh topology", + "visibility", + "transform", + "collection membership" + ], + "negative": [ + "invalid selection", + "stale revision", + "linked data" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-mesh-topology-production.spec.ts tests/e2e/wbv2-scene-object-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1100-003", + "phase": "1100", + "title": "verify_material_animation_module", + "kind": "module", + "owner": "MATERIAL_ANIMATION", + "dependsOn": [ + "WBV2-P1100-002" + ], + "parityId": "MATERIAL_ANIMATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-material_animation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-003.md", + "behavior": "Complete the MATERIAL_ANIMATION module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MATERIAL_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-MATERIAL-ANIMATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-003/manifest.json", + "report": "tests/golden/WBV2-P12-003/material-animation-receipt-report.json" + } + ], + "positive": [ + "principled material", + "image node", + "keyframe", + "FCurve" + ], + "negative": [ + "unsupported graph", + "stale revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-material-animation-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-000", + "phase": "1101", + "title": "verify_nonmesh_geometry_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1100-003" + ], + "parityId": "NONMESH_GEOMETRY", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nonmesh_geometry", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-000.md", + "behavior": "Complete the NONMESH_GEOMETRY module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NONMESH_GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-VIEWPORT-NONMESH", + "CAP-NATIVE-DATABLOCK" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "positive": [ + "curve", + "surface", + "font", + "volume", + "metaball", + "grease pencil" + ], + "negative": [ + "unsupported data", + "resource missing", + "malformed geometry" + ], + "recovery": [ + "save/reopen", + "resource disposal" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-viewport-nonmesh-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-001", + "phase": "1101", + "title": "verify_nodes_simulation_module", + "kind": "module", + "owner": "NODES_SIMULATION", + "dependsOn": [ + "WBV2-P1101-000" + ], + "parityId": "NODES_SIMULATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nodes_simulation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-001.md", + "behavior": "Complete the NODES_SIMULATION module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NODES_SIMULATION", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES", + "CAP-SIMULATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "allowlisted node graph", + "physics manifest", + "stable hash" + ], + "negative": [ + "unsupported node", + "budget exceeded", + "stale revision" + ], + "recovery": [ + "save/reopen", + "cache disposal" + ], + "commands": [ + "npm --prefix web run test:geometry-node-main-reader", + "npm --prefix web run test:physics-main-reader" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-002", + "phase": "1101", + "title": "verify_asset_io_module", + "kind": "module", + "owner": "ASSET", + "dependsOn": [ + "WBV2-P1101-001" + ], + "parityId": "ASSET_IO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-asset_io", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-002.md", + "behavior": "Complete the ASSET_IO module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ASSET_IO", + "sourceBacked": true, + "capabilities": [ + "CAP-ASSET-LINK-OVERRIDE-RELOAD", + "CAP-ASSET-CATALOG-MUTATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P10-003/manifest.json", + "report": "tests/golden/WBV2-P10-003/module-matrix-receipt-report.json" + } + ], + "positive": [ + "append", + "link", + "override", + "reload", + "asset catalog v2" + ], + "negative": [ + "missing source", + "ownership violation", + "hash drift", + "collision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "IndexedDB restart" + ], + "commands": [ + "npm --prefix web run test:asset-catalog-v2", + "npm --prefix web run test:asset-catalog-migration", + "npm --prefix web run test:asset-catalog-negatives", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-asset-link-override-production.spec.ts tests/e2e/wbv2-asset-catalog-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-003", + "phase": "1101", + "title": "verify_sculpt_paint_module", + "kind": "module", + "owner": "SCULPT_PAINT", + "dependsOn": [ + "WBV2-P1101-002" + ], + "parityId": "SCULPT_PAINT", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-sculpt_paint", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-003.md", + "behavior": "Complete the SCULPT_PAINT module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCULPT_PAINT", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-ATTRIBUTES", + "CAP-SCULPT-PAINT" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P16-002/manifest.json", + "report": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json" + } + ], + "positive": [ + "vertex colors", + "vertex weights", + "bounded sculpt stroke" + ], + "negative": [ + "mirror unverified", + "invalid patch", + "unsupported brush" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run test:paint-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1102-000", + "phase": "1102", + "title": "implement_ui_editor_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1101-003" + ], + "parityId": "UI_EDITOR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-ui_editor", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1102-000.md", + "behavior": "Complete the UI_EDITOR module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-UI-EDITOR" + ], + "sourcePaths": [ + "web/protocol/editor-workflow.ts", + "web/app/src/app/App.tsx", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [], + "positive": [ + "editor context", + "workspace", + "area/region" + ], + "negative": [ + "unsupported editor", + "invalid context" + ], + "recovery": [ + "worker restart", + "save/reopen" + ], + "commands": [ + "npm --prefix web run test:editor-main-reader", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/ui-editor-workflow-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1102-001", + "phase": "1102", + "title": "close_module_execution_gate", + "kind": "module", + "owner": "RELEASE", + "dependsOn": [ + "WBV2-P1102-000" + ], + "parityId": "INVENTORY_GATE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-inventory_gate", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1102-001.md", + "behavior": "Complete the INVENTORY_GATE module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "INVENTORY_GATE", + "sourceBacked": true, + "capabilities": [], + "sourcePaths": [ + "tests/golden/WBV2-P0-002/parity-map.json", + "tests/golden/WBV2-P1100-000/module-execution-plan.json" + ], + "reuseReceipts": [], + "positive": [ + "aggregate module receipts", + "catalog hash" + ], + "negative": [ + "missing receipt", + "hash drift", + "false completion" + ], + "recovery": [ + "re-run affected module only" + ], + "commands": [ + "node tools/web/check-wbv2-module-execution.mjs", + "npm --prefix web run build" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1103-000", + "phase": "1103", + "title": "aggregate_object_operations_module", + "kind": "module", + "owner": "OBJECT", + "dependsOn": [ + "WBV2-P1102-001" + ], + "parityId": "OBJECT_OPERATIONS", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-object_operations", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1103-000.md", + "behavior": "Aggregate the existing source-backed Object Main operations into one module and revalidate the Chromium operator matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "OBJECT_OPERATIONS", + "sourceBacked": true, + "capabilities": [ + "CAP-OBJECT-DUPLICATE", + "CAP-OBJECT-CREATE", + "CAP-OBJECT-PARENT", + "CAP-OBJECT-COLLECTION", + "CAP-OBJECT-RENAME", + "CAP-OBJECT-DELETE", + "CAP-OBJECT-TRANSFORM" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P17-002/manifest.json", + "report": "tests/golden/WBV2-P17-002/object-duplicate-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P18-002/manifest.json", + "report": "tests/golden/WBV2-P18-002/object-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P19-002/manifest.json", + "report": "tests/golden/WBV2-P19-002/object-parent-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P20-002/manifest.json", + "report": "tests/golden/WBV2-P20-002/collection-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P21-002/manifest.json", + "report": "tests/golden/WBV2-P21-002/object-rename-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P22-002/manifest.json", + "report": "tests/golden/WBV2-P22-002/object-delete-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P23-002/manifest.json", + "report": "tests/golden/WBV2-P23-002/object-transform-receipt-report.json" + } + ], + "positive": [ + "duplicate", + "create", + "parent", + "collection", + "rename", + "delete", + "transform apply" + ], + "negative": [ + "unknown object", + "invalid parent cycle", + "malformed transform" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-object-duplicate-production.spec.ts tests/e2e/wbv2-object-create-production.spec.ts tests/e2e/wbv2-object-parent-production.spec.ts tests/e2e/wbv2-collection-create-production.spec.ts tests/e2e/wbv2-object-rename-production.spec.ts tests/e2e/wbv2-object-delete-production.spec.ts tests/e2e/wbv2-object-transform-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1104-000", + "phase": "1104", + "title": "verify_compositor_sequencer_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1103-000" + ], + "parityId": "COMPOSITOR_SEQUENCER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-compositor_sequencer", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1104-000.md", + "behavior": "Verify the source-backed compositor and sequencer module through golden, unsupported-gate and media recovery cases.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main or compositor mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "COMPOSITOR_SEQUENCER", + "sourceBacked": true, + "capabilities": [ + "CAP-COMPOSITOR-NODE-GRAPH", + "CAP-COMPOSITOR-UNSUPPORTED-GATE", + "CAP-SEQUENCER-MEDIA-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/compositor.ts", + "web/protocol/sequencer.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "positive": [ + "compositor node graph", + "sequencer still-image timeline", + "media cache contract" + ], + "negative": [ + "unsupported compositor node", + "invalid sequencer strip", + "stale media revision" + ], + "recovery": [ + "worker restart", + "save/reopen", + "media cache replay", + "movie codec blocked without READY receipt" + ], + "commands": [ + "npm --prefix web run test:compositor-node-golden", + "npm --prefix web run test:compositor-unsupported-gate", + "npm --prefix web run test:sequencer-main-reader", + "node --test web/tests/unit/sequencer-media-cache.test.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/smoke.spec.ts -g \"N-021 sequencer|real Blender 5.2 sequencer\"", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1105-000", + "phase": "1105", + "title": "verify_audio_particle_module", + "kind": "module", + "owner": "AUDIO_PARTICLE", + "dependsOn": [ + "WBV2-P1104-000" + ], + "parityId": "AUDIO_PARTICLE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-audio_particle", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1105-000.md", + "behavior": "Verify Sound, Speaker and ParticleSettings mutations against authoritative Blender Main with explicit build capability gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven or a typed build capability blocker is recorded", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "AUDIO_PARTICLE", + "sourceBacked": true, + "capabilities": [ + "CAP-SOUND-PROPERTIES", + "CAP-SPEAKER-PROPERTIES", + "CAP-PARTICLE-SETTINGS" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/protocol/io-media-commands.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P33-001/manifest.json", + "report": "tests/golden/WBV2-P33-001/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P33-002/manifest.json", + "report": "tests/golden/WBV2-P33-002/implementation-report.json" + } + ], + "positive": [ + "Sound properties", + "Speaker properties", + "ParticleSettings properties" + ], + "negative": [ + "missing Main datablock", + "unsupported build feature", + "out-of-range property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker restart" + ], + "commands": [ + "cmake --build build_web_blender6 --target web_engine -- -j8", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-audio-particle-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1106-000", + "phase": "1106", + "title": "verify_rig_animation_module", + "kind": "module", + "owner": "RIG", + "dependsOn": [ + "WBV2-P1105-000" + ], + "parityId": "RIG_ANIMATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-rig_animation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1106-000.md", + "behavior": "Verify armature pose, constraints and NLA animation through the existing Blender Main primitives.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RIG_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-RIG-POSE", + "CAP-CONSTRAINTS", + "CAP-NLA-ANIMATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nla.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-003/manifest.json", + "report": "tests/golden/WBV2-P13-003/rig-pose-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "armature pose", + "constraint edit", + "NLA stack" + ], + "negative": [ + "missing bone", + "invalid constraint influence", + "stale NLA revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-rig-pose-production.spec.ts", + "npm --prefix web run test:nla-operator", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1107-000", + "phase": "1107", + "title": "verify_modifier_system_module", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1106-000" + ], + "parityId": "MODIFIER_SYSTEM", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_system", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1107-000.md", + "behavior": "Verify modifier stack visibility and bounded parameter mutation through authoritative Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_SYSTEM", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER-STATE-MUTATION", + "CAP-MODIFIER-PARAMETER-EDIT", + "CAP-MODIFIER-STACK-READER" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/modifier-graph.ts", + "web/protocol/depsgraph.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P9-002/manifest.json", + "report": "tests/golden/WBV2-P9-002/modifier-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P11-002/manifest.json", + "report": "tests/golden/WBV2-P11-002/modifier-parameter-receipt-report.json" + } + ], + "positive": [ + "modifier visibility toggle", + "bounded DECIMATE parameter mutation", + "modifier stack evaluation reader" + ], + "negative": [ + "unknown modifier UUID", + "stale mesh revision", + "out-of-range parameter" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-production.spec.ts tests/e2e/wbv2-modifier-parameter-production.spec.ts", + "npm --prefix web run test:modifier-goldens", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1108-000", + "phase": "1108", + "title": "verify_nodes_graph_module", + "kind": "module", + "owner": "NODES", + "dependsOn": [ + "WBV2-P1107-000" + ], + "parityId": "NODES_GRAPH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nodes_graph", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1108-000.md", + "behavior": "Verify Geometry Nodes graph identity, allowlisted evaluation, field budgets and unsupported graph retention.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive graph reader/evaluation evidence is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NODES_GRAPH", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES-GRAPH", + "CAP-GEOMETRY-NODES-ALLOWLIST", + "CAP-GEOMETRY-NODES-FIELD-BUDGET" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/geometry-nodes.ts", + "web/protocol/geometry-node-commands.ts", + "web/protocol/depsgraph.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "allowlisted graph identity", + "Blender depsgraph geometry evaluation", + "field materialization with exact domain cardinality" + ], + "negative": [ + "unsupported node graph", + "field budget overflow", + "stale or invalid graph command" + ], + "recovery": [ + "save/reopen", + "worker restart", + "graph retention after rejected command", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:geometry-node-evaluator-golden", + "npm --prefix web run test:geometry-node-field-budget", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1109-000", + "phase": "1109", + "title": "verify_io_format_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1108-000" + ], + "parityId": "IO_FORMAT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-io_format", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1109-000.md", + "behavior": "Verify format capability routing, runtime receipts, recovery and fail-closed file UI gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive format routing/readiness evidence is proven", + "negative and recovery cases are proven", + "Chromium and deterministic recovery receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "IO_FORMAT", + "sourceBacked": true, + "capabilities": [ + "CAP-IO-FORMAT-CAPABILITY-MATRIX", + "CAP-IO-FORMAT-RUNTIME-RECEIPTS", + "CAP-IO-FORMAT-RECOVERY", + "CAP-IO-FORMAT-UI-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/asset-library-io.ts", + "web/protocol/io-format-capability-matrix.ts", + "web/protocol/io-format-receipt-binding.ts", + "web/protocol/io-format-runtime-receipt.ts", + "web/protocol/io-format-recovery.ts", + "web/protocol/io-format-ui-gate.ts", + "web/protocol/glb-export.ts", + "web/protocol/glb-import.ts", + "web/protocol/nonmesh-export.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "GLB export readiness", + "format runtime receipt inventory", + "declared .blend import route" + ], + "negative": [ + "unverified format route", + "cancelled or OOM operation", + "unsupported file extension" + ], + "recovery": [ + "worker restart", + "small operation recovery", + "deterministic receipt replay", + "fail-closed UI route" + ], + "commands": [ + "node tools/web/check-io-format-receipt-bindings.mjs", + "node tools/web/check-io-format-runtime-receipts.mjs", + "node tools/web/check-io-format-recovery.mjs", + "node tools/web/check-io-format-ui-gate.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/io-format-recovery.spec.ts tests/e2e/io-format-ui-gate.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1110-000", + "phase": "1110", + "title": "verify_render_pipeline_module", + "kind": "module", + "owner": "RENDER", + "dependsOn": [ + "WBV2-P1109-000" + ], + "parityId": "RENDER_PIPELINE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-render_pipeline", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1110-000.md", + "behavior": "Verify render backend routing, explicit resource budgets and Blender reference comparison in Chromium.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive render/reference evidence is proven", + "negative and recovery cases are proven", + "Chromium and deterministic render receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RENDER_PIPELINE", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-BACKEND-ROUTING", + "CAP-RENDER-RESOURCE-BUDGET", + "CAP-RENDER-REFERENCE-COMPARISON" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/render-routing.ts", + "web/protocol/render-budget.ts", + "web/protocol/render-capabilities.ts", + "web/protocol/render-image-comparison.ts", + "web/protocol/server-render-job.ts", + "web/app/src/three-adapter/render-routing.ts", + "web/app/src/three-adapter/render-image-comparison.ts", + "web/app/src/workers/viewport-render.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "bounded local backend routing", + "reference render metrics", + "resource budget acceptance" + ], + "negative": [ + "unknown or unavailable backend", + "aggregate texture/light budget overflow", + "wrong composition reference" + ], + "recovery": [ + "retain previous texture set", + "offscreen renderer parity", + "worker restart", + "deterministic second render" + ], + "commands": [ + "npm --prefix web run test:render-resource-budget", + "npm --prefix web run test:render-routing", + "npm --prefix web run test:render-reference", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1111-000", + "phase": "1111", + "title": "verify_scripting_security_module", + "kind": "module", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1110-000" + ], + "parityId": "SCRIPTING_SECURITY", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-scripting_security", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1111-000.md", + "behavior": "Verify script source Main reader, deny-by-default permission policy and sandbox isolation/recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive reader and policy evidence is proven", + "negative and recovery cases are proven", + "Chromium sandbox receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCRIPTING_SECURITY", + "sourceBacked": true, + "capabilities": [ + "CAP-SCRIPT-MAIN-READER", + "CAP-SCRIPT-PERMISSION-POLICY", + "CAP-SCRIPT-SANDBOX-ISOLATION", + "CAP-SCRIPT-SANDBOX-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/scripting-platform.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/workers/script-permission-policy-test.worker.ts", + "web/app/src/workers/script-sandbox-isolation-test.worker.ts", + "web/app/src/workers/script-sandbox-recovery-test.worker.ts", + "web/app/src/testing/script-sandbox-recovery.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "script source inventory reader", + "explicit READ_MAIN permission", + "new-generation recovery audit" + ], + "negative": [ + "autorun denied by default", + "undeclared permission", + "sandbox crash/timeout/late result" + ], + "recovery": [ + "worker restart", + "sandbox generation rollover", + "continuous audit chain", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:script-main-reader", + "npm --prefix web run test:scripting-isolation", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/script-permission-policy.spec.ts tests/e2e/script-sandbox-isolation.spec.ts tests/e2e/script-sandbox-recovery.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1112-000", + "phase": "1112", + "title": "verify_animation_timeline_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1111-000" + ], + "parityId": "ANIMATION_TIMELINE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-animation_timeline", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1112-000.md", + "behavior": "Verify frame evaluation and NLA time mapping through the production Worker and Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive frame/NLA evaluation is proven", + "negative and recovery cases are proven", + "Chromium and deterministic evaluation receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ANIMATION_TIMELINE", + "sourceBacked": true, + "capabilities": [ + "CAP-FRAME-EVALUATION", + "CAP-NLA-TIME-MAPPING", + "CAP-ANIMATION-SAVE-REOPEN" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nla.ts", + "web/protocol/depsgraph.ts", + "web/protocol/scene-ir.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "frame 1/5/10 evaluation", + "NLA track and strip mapping", + "Blender depsgraph animation result" + ], + "negative": [ + "stale NLA revision", + "invalid strip topology", + "unsupported animation domain" + ], + "recovery": [ + "save/reopen", + "worker restart", + "deterministic repeated evaluation", + "preserve rejected stack" + ], + "commands": [ + "npm --prefix web run test:frame-evaluation", + "node tools/web/check-nla-evaluation-golden.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/nla-evaluation-golden.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1113-000", + "phase": "1113", + "title": "verify_shader_material_module", + "kind": "module", + "owner": "MATERIAL", + "dependsOn": [ + "WBV2-P1112-000" + ], + "parityId": "SHADER_MATERIAL", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-shader_material", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1113-000.md", + "behavior": "Verify bounded Shader graph compilation, stable compile keys and fail-closed pipeline recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Shader Main compilation is proven", + "negative and recovery cases are proven", + "Chromium and deterministic compile receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SHADER_MATERIAL", + "sourceBacked": true, + "capabilities": [ + "CAP-SHADER-GRAPH-COMPILER", + "CAP-SHADER-COMPILE-KEY", + "CAP-SHADER-FAIL-CLOSED-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/shader-graph.ts", + "web/protocol/shader-graph-commands.ts", + "web/protocol/shader-compiler.ts", + "web/protocol/render-capabilities.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "Principled/Image/Normal/Math graph compile", + "stable compile key", + "real Main shader material path" + ], + "negative": [ + "unknown shader node", + "graph cycle or duplicate link", + "unsupported renderer backend" + ], + "recovery": [ + "retain previous material after compile failure", + "worker restart", + "deterministic repeated compile", + "save/reopen material graph" + ], + "commands": [ + "npm --prefix web run test:shader-compile", + "npm --prefix web run test:shader-pipeline", + "npm --prefix web run test:shader-capability", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1114-000", + "phase": "1114", + "title": "verify_grease_pencil_module", + "kind": "module", + "owner": "DRAWING", + "dependsOn": [ + "WBV2-P1113-000" + ], + "parityId": "GREASE_PENCIL", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-grease_pencil", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1114-000.md", + "behavior": "Verify Grease Pencil layer/frame Main mutations, stable identity validation and roundtrip recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Grease Pencil Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GREASE_PENCIL", + "sourceBacked": true, + "capabilities": [ + "CAP-GREASE-PENCIL-LAYER-FRAME", + "CAP-GREASE-PENCIL-STROKE-READER", + "CAP-GREASE-PENCIL-ROUNDTRIP" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/grease-pencil.ts", + "web/protocol/grease-pencil-reorder.ts", + "web/protocol/grease-pencil-selection.ts", + "web/protocol/grease-pencil-marquee.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/grease-pencil.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "create and reorder layer", + "insert and move frame", + "stable Grease Pencil drawing reader" + ], + "negative": [ + "forged drawing identity", + "occupied frame target", + "stale layer/frame revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic layer/frame replay" + ], + "commands": [ + "npm --prefix web run test:grease-pencil-reorder", + "npm --prefix web run test:grease-pencil", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1115-000", + "phase": "1115", + "title": "verify_curve_surface_editing_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1114-000" + ], + "parityId": "CURVE_SURFACE_EDITING", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_surface_editing", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1115-000.md", + "behavior": "Verify Curve topology/handle edits, Surface topology and non-mesh/font roundtrip through Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive non-mesh Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_SURFACE_EDITING", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-HANDLES", + "CAP-SURFACE-TOPOLOGY", + "CAP-NONMESH-FONT-ROUNDTRIP" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nonmesh-geometry-commands.ts", + "web/protocol/curve-topology-editor.ts", + "web/protocol/non-mesh.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + } + ], + "positive": [ + "Curve control point and handle edit", + "Curve cyclic/topology operator", + "Surface and Font property mutation" + ], + "negative": [ + "invalid curve selection/domain", + "occupied or stale frame/topology target", + "malformed non-mesh property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic multispline replay" + ], + "commands": [ + "npm --prefix web run test:curve-topology-operator", + "npm --prefix web run test:nonmesh-roundtrip", + "npm --prefix web run test:nonmesh-desktop-golden", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1116-000", + "phase": "1116", + "title": "verify_storage_recovery_module", + "kind": "module", + "owner": "STORAGE", + "dependsOn": [ + "WBV2-P1115-000" + ], + "parityId": "STORAGE_RECOVERY", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-storage_recovery", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1116-000.md", + "behavior": "Verify IndexedDB catalog migration/restart and OPFS asset preview deduplication, quarantine and reference GC.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive storage commit/recovery evidence is proven", + "negative and quarantine cases are proven", + "Chromium restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "STORAGE_RECOVERY", + "sourceBacked": true, + "capabilities": [ + "CAP-INDEXEDDB-CATALOG-MIGRATION", + "CAP-OPFS-PREVIEW-COMMIT", + "CAP-OPFS-QUARANTINE-GC" + ], + "sourcePaths": [ + "web/protocol/storage.ts", + "web/protocol/storage-budget.ts", + "web/protocol/save-transaction.ts", + "web/protocol/recent-projects.ts", + "web/protocol/asset-preview.ts", + "web/protocol/asset-preview-decode.ts", + "web/app/src/storage/asset-catalog-indexeddb.ts", + "web/app/src/storage/asset-preview-opfs-commit.ts", + "web/app/src/storage/asset-preview-quarantine.ts", + "web/app/src/storage/asset-preview-reference-gc.ts", + "web/app/src/storage/opfs-files.ts", + "web/app/src/storage/migrations.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "v1 to v2 catalog migration", + "page/Worker restart identity", + "content-addressed preview deduplication" + ], + "negative": [ + "partial catalog migration", + "corrupt preview quarantine", + "cross-project or non-final reference GC" + ], + "recovery": [ + "IndexedDB restart", + "OPFS commit replay", + "quarantine cleanup", + "deterministic reference reclamation" + ], + "commands": [ + "npm --prefix web run test:asset-catalog-restart", + "npm --prefix web run test:asset-preview-dedup", + "npm --prefix web run test:asset-preview-quarantine", + "npm --prefix web run test:asset-preview-reference-gc", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1117-000", + "phase": "1117", + "title": "verify_simulation_cache_module", + "kind": "module", + "owner": "SIMULATION", + "dependsOn": [ + "WBV2-P1116-000" + ], + "parityId": "SIMULATION_CACHE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-simulation_cache", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1117-000.md", + "behavior": "Verify simulation cache identity, physics-family payload integrity, lifecycle recovery and deterministic LRU pruning.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive cache identity/lifecycle evidence is proven", + "negative integrity and budget cases are proven", + "Chromium restart and quarantine receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SIMULATION_CACHE", + "sourceBacked": true, + "capabilities": [ + "CAP-SIMULATION-CACHE-IDENTITY", + "CAP-PHYSICS-CACHE-INTEGRITY", + "CAP-SIMULATION-CACHE-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/simulation-cache.ts", + "web/protocol/physics-simulation.ts", + "web/protocol/physics-cache-playback.ts", + "web/protocol/storage.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "graph/source/revision cache identity", + "all physics-family frame hashes", + "verified playback lifecycle" + ], + "negative": [ + "source or payload hash drift", + "revision/range mismatch", + "cache byte/frame budget overflow" + ], + "recovery": [ + "cancel and cleanup", + "LRU prune with protected playback", + "corruption quarantine", + "worker restart" + ], + "commands": [ + "npm --prefix web run test:simulation-cache-identity", + "npm --prefix web run test:simulation-cache-lifecycle", + "npm --prefix web run test:physics-cache-family", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1118-000", + "phase": "1118", + "title": "verify_ui_input_interaction_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1117-000" + ], + "parityId": "UI_INPUT_INTERACTION", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-ui_input_interaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1118-000.md", + "behavior": "Verify keyboard-only user actions, input mutex, IME/pointer state and responsive editor interaction under deployment CSP.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive keyboard Main mutation and save are proven", + "negative mutex/input cases are proven", + "Chromium accessibility and responsive receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_INPUT_INTERACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-KEYBOARD-USER-ACTIONS", + "CAP-INPUT-MODAL-STATE", + "CAP-IME-SHORTCUT-GUARD", + "CAP-RESPONSIVE-CSP-UI" + ], + "sourcePaths": [ + "web/app/index.html", + "web/app/src/app/App.tsx", + "web/app/src/app/app-shell.css", + "web/app/src/workers/web-engine.worker.ts", + "web/protocol/user-action-state.ts", + "web/protocol/project-action-mutex.ts", + "web/protocol/ime-composition.ts", + "web/protocol/input-modal.ts", + "web/protocol/pointer-contract.ts", + "web/protocol/worker-fault.ts", + "web/tests/unit/user-action-state.test.mjs", + "web/tests/unit/project-action-mutex.test.mjs", + "web/tests/unit/ime-composition.test.mjs", + "web/tests/unit/input-modal.test.mjs", + "web/tests/unit/pointer-contract.test.mjs" + ], + "reuseReceipts": [], + "positive": [ + "keyboard-only Add Cube Main mutation", + "keyboard save/reopen and GLB export", + "responsive controls at desktop/mobile viewports" + ], + "negative": [ + "concurrent project action mutex", + "IME shortcut suppression", + "pointer cancel/touch modal cleanup" + ], + "recovery": [ + "worker restart", + "save interruption recovery", + "responsive layout preservation", + "deterministic repeated keyboard loop" + ], + "commands": [ + "node --test web/tests/unit/user-action-state.test.mjs web/tests/unit/project-action-mutex.test.mjs web/tests/unit/ime-composition.test.mjs web/tests/unit/input-modal.test.mjs web/tests/unit/pointer-contract.test.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/user-action-state.spec.ts tests/e2e/project-action-mutex.spec.ts tests/e2e/keyboard-accessibility.spec.ts tests/e2e/responsive-layout.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1119-000", + "phase": "1119", + "title": "verify_library_workflow_module", + "kind": "module", + "owner": "ASSET", + "dependsOn": [ + "WBV2-P1118-000" + ], + "parityId": "LIBRARY_WORKFLOW", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-library_workflow", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1119-000.md", + "behavior": "Verify append, link, override and reload library flows through authoritative Main with path and dependency safety gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive library Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "LIBRARY_WORKFLOW", + "sourceBacked": true, + "capabilities": [ + "CAP-LIBRARY-APPEND", + "CAP-LIBRARY-LINK", + "CAP-LIBRARY-OVERRIDE", + "CAP-LIBRARY-RELOAD-SAFETY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/library-main-append.ts", + "web/protocol/library-linked-mutation.ts", + "web/protocol/library-linked-reload.ts", + "web/protocol/library-linked-missing.ts", + "web/protocol/library-override-writer.ts", + "web/protocol/library-override-freshness.ts", + "web/protocol/library-negative-cases.ts", + "web/protocol/library-operation-identity.ts", + "web/protocol/library-source-origin.ts", + "web/protocol/asset-path.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P9-003/manifest.json", + "report": "tests/golden/WBV2-P9-003/asset-catalog-receipt-report.json" + } + ], + "positive": [ + "append object into Main", + "linked read-only object", + "local override and reload identity" + ], + "negative": [ + "missing library source", + "dependency/cross-library cycle", + "unsafe path or ownership mutation" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic library replay" + ], + "commands": [ + "npm --prefix web run test:library-main-append", + "npm --prefix web run test:library-link-chromium", + "npm --prefix web run test:library-override-chromium", + "npm --prefix web run test:library-negative-cases", + "npm --prefix web run test:library-path-security", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1120-000", + "phase": "1120", + "title": "verify_volume_nanovdb_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1119-000" + ], + "parityId": "VOLUME_NANOVDB", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-volume_nanovdb", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1120-000.md", + "behavior": "Verify NanoVDB manifest, paged feedback, OPFS commit/restart and production viewport volume roundtrip.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive volume resource and viewport evidence is proven", + "negative and recovery cases are proven", + "Chromium OPFS/restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "VOLUME_NANOVDB", + "sourceBacked": true, + "capabilities": [ + "CAP-NANOVDB-MANIFEST", + "CAP-NANOVDB-PAGED-FEEDBACK", + "CAP-NANOVDB-OPFS-RESTART", + "CAP-NANOVDB-VIEWPORT-ROUNDTRIP" + ], + "sourcePaths": [ + "web/protocol/volume-vdb.ts", + "web/protocol/nanovdb-page-feedback.ts", + "web/protocol/nanovdb-device-recovery.ts", + "web/protocol/storage.ts", + "web/app/src/volume/nanovdb-opfs.ts", + "web/app/src/volume/nanovdb-stream.ts", + "web/app/src/volume/nanovdb-viewport.ts", + "web/app/src/volume/nanovdb-float32.ts", + "web/app/src/render/nanovdb-volume-renderer.ts", + "web/app/src/workers/vdb-opfs-test.worker.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "validated NanoVDB bundle manifest", + "content-addressed OPFS commit", + "main/offscreen production viewport volume" + ], + "negative": [ + "manifest/chunk hash mismatch", + "stale source binding", + "WebGPU/resource availability block" + ], + "recovery": [ + "OPFS Worker restart", + "paged feedback resume", + "quota/device loss cleanup", + "deterministic volume save/reopen" + ], + "commands": [ + "npm --prefix web run test:vdb-availability", + "npm --prefix web run test:vdb-native", + "npm --prefix web run test:nanovdb-page-feedback", + "npm --prefix web run test:nanovdb-opfs-restart", + "npm --prefix web run test:nanovdb-volume-roundtrip", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1121-000", + "phase": "1121", + "title": "verify_paint_stroke_module", + "kind": "module", + "owner": "SCULPT", + "dependsOn": [ + "WBV2-P1120-000" + ], + "parityId": "PAINT_STROKE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-paint_stroke", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1121-000.md", + "behavior": "Verify paint pointer sessions, depth visibility and PBVH capability gates through the production Worker.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive paint Main transaction is proven", + "negative and recovery cases are proven", + "Chromium pointer/GPU receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "PAINT_STROKE", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-POINTER-SESSION", + "CAP-PAINT-DEPTH-VISIBILITY", + "CAP-PAINT-PBVH-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/protocol/sculpt.ts", + "web/protocol/paint.ts", + "web/protocol/paint-stroke-session.ts", + "web/protocol/paint-depth-visibility.ts", + "web/protocol/paint-pbvh-capability.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/three-adapter/paint-depth-visibility.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "ordered paint pointer chunks", + "main/offscreen depth visibility", + "PBVH inventory capability query" + ], + "negative": [ + "stale/discontinuous pointer chunks", + "forged or over-budget depth samples", + "missing PBVH WASM entrypoint" + ], + "recovery": [ + "pointer cancel without Main mutation", + "undo step after paint commit", + "worker restart", + "deterministic capability replay" + ], + "commands": [ + "npm --prefix web run test:paint-stroke-session", + "npm --prefix web run test:paint-depth-visibility", + "npm --prefix web run test:paint-pbvh-capability", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1122-000", + "phase": "1122", + "title": "verify_engine_runtime_module", + "kind": "module", + "owner": "RUNTIME", + "dependsOn": [ + "WBV2-P1121-000" + ], + "parityId": "ENGINE_RUNTIME", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-engine_runtime", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1122-000.md", + "behavior": "Verify WebEngine variant manifest/selection, compiled WASM Main ABI and Worker crash recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive compiled WASM Main lifecycle is proven", + "negative variant/hash cases are proven", + "Chromium Worker restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ENGINE_RUNTIME", + "sourceBacked": true, + "capabilities": [ + "CAP-ENGINE-VARIANT-MANIFEST", + "CAP-ENGINE-WASM-MAIN-ABI", + "CAP-WORKER-CRASH-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_api.h", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/CMakeLists.txt", + "web/protocol/engine-variant.ts", + "web/protocol/worker-fault.ts", + "web/protocol/save-transaction.ts", + "web/app/src/engine-client/engine-variant-bootstrap.ts", + "web/app/src/engine-client/browser-engine-variant-session.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "single/pthread manifest binding", + "compiled WASM Main open/save lifecycle", + "engine and storage Worker recovery" + ], + "negative": [ + "malformed variant/resource declaration", + "mixed-version/hash mismatch", + "pthread unavailable fallback" + ], + "recovery": [ + "single-thread fallback", + "Worker crash restart", + "operation-log restore", + "deterministic repeated startup" + ], + "commands": [ + "npm --prefix web run test:engine-manifest-v2", + "npm --prefix web run test:engine-variant-selection", + "npm --prefix web run test:engine-variant-fallback", + "npm --prefix web run test:engine-variant-install", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-native-engine-production.spec.ts tests/e2e/worker-crash-recovery.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1123-000", + "phase": "1123", + "title": "repair_glb_roundtrip_dependency_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1122-000" + ], + "parityId": "GLB_ROUNDTRIP_REPAIR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-glb_roundtrip_repair", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1123-000.md", + "behavior": "Repair the standalone GLB checker dependency chain and verify mesh/non-mesh Blender roundtrip plus Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive GLB and non-mesh roundtrip are proven", + "negative and recovery cases are proven", + "Chromium save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GLB_ROUNDTRIP_REPAIR", + "sourceBacked": true, + "capabilities": [ + "CAP-GLB-MESH-ROUNDTRIP", + "CAP-GLB-NONMESH-ROUNDTRIP", + "CAP-GLB-CHROMIUM-RECOVERY" + ], + "sourcePaths": [ + "tools/web/check-glb-blender-roundtrip.mjs", + "tools/web/check-nonmesh-glb-blender-roundtrip.mjs", + "tools/web/blender-check-glb-roundtrip.py", + "web/protocol/glb-export.ts", + "web/protocol/glb-import.ts", + "web/protocol/nonmesh-export.ts", + "web/protocol/nonmesh-binary.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "mesh/material/skin/animation GLB roundtrip", + "Curve/Surface/Font/Metaball non-mesh mapping", + "desktop GLB Main persistence in Chromium" + ], + "negative": [ + "sparse or oversized GLB", + "external URI/extension rejection", + "non-mesh export loss gate" + ], + "recovery": [ + "cancel without publishing output", + "Worker restart", + "OPFS quota retains old asset", + "deterministic Blender roundtrip" + ], + "commands": [ + "npm --prefix web run test:glb-blender-roundtrip", + "npm --prefix web run test:nonmesh-glb-blender-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/glb-negative-cases.spec.ts tests/e2e/glb-recovery.spec.ts tests/e2e/glb-main-persistence.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1124-000", + "phase": "1124", + "title": "record_historical_hash_drift_module", + "kind": "module", + "owner": "PROVENANCE", + "dependsOn": [ + "WBV2-P1123-000" + ], + "parityId": "HISTORICAL_HASH_DRIFT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-historical_hash_drift", + "gate": "EVIDENCE", + "card": "docs/tasks/WBV2-P1124-000.md", + "behavior": "Record legacy M12 artifact hash drift without re-signing historical manifests or changing the immutable inventory.", + "outputs": [ + "drift report", + "module receipt", + "manifest", + "status" + ], + "acceptance": [ + "original and observed hashes are recorded", + "provenance remains BLOCKED_SOURCE_LOST where bytes cannot be restored", + "historical manifests and inventory remain unchanged", + "deterministic drift evidence is reproducible", + "no full-family parity claim" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "HISTORICAL_HASH_DRIFT", + "sourceBacked": true, + "capabilities": [ + "CAP-HISTORICAL-HASH-AUDIT", + "CAP-PROVENANCE-SOURCE-LOST-GATE" + ], + "sourcePaths": [ + "tools/web/check-m12-manifest-drift.mjs", + "tests/golden/corrective/rehydration/M12-manifest-sha-drift.json", + "tests/golden/WBV2-P0-002/parity-map.json" + ], + "reuseReceipts": [], + "positive": [ + "84 drift entries captured", + "43 affected artifact paths indexed", + "immutable inventory binding preserved" + ], + "negative": [ + "missing original bytes", + "attempted historical re-signing", + "inventory mutation" + ], + "recovery": [ + "deterministic report rerun", + "source cache can restore original bytes later", + "new capability manifests reference drift evidence only" + ], + "commands": [ + "node tools/web/check-m12-manifest-drift.mjs --write", + "node tools/web/check-m12-manifest-drift.mjs", + "node tools/web/check-wbv2-module-execution.mjs" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1125-000", + "phase": "1125", + "title": "repair_geometry_nodes_allowlist_module", + "kind": "module", + "owner": "NODES", + "dependsOn": [ + "WBV2-P1124-000" + ], + "parityId": "GEOMETRY_NODES_ALLOWLIST_REPAIR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-geometry_nodes_allowlist_repair", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1125-000.md", + "behavior": "Persist Geometry Nodes graph overrides in Web-safe Main storage and align allowlist assertions with real materialization behavior.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "supported graph Main materialization is proven", + "unsupported graph remains rejected without mutation", + "save/reopen graph retention is exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GEOMETRY_NODES_ALLOWLIST_REPAIR", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES-MAIN-PERSISTENCE", + "CAP-GEOMETRY-NODES-ALLOWLIST-CONSISTENCY", + "CAP-GEOMETRY-NODES-SAVE-REOPEN" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/geometry-nodes.ts", + "web/protocol/geometry-node-commands.ts", + "web/protocol/web-engine.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/geometry-node-allowlist.spec.ts", + "web/tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "allowlisted graph materializes into Main", + "Scene IDProperty graph override persists", + "save/reopen retains graph identity/hash" + ], + "negative": [ + "unsupported simulation node", + "invalid graph schema", + "missing node/link endpoint" + ], + "recovery": [ + "rejected graph leaves baseline unchanged", + "undo/redo graph override", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "cmake --build build_web_blender6 --target web_engine -- -j8", + "npm --prefix web run test:geometry-node-allowlist", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "npm --prefix web run test:geometry-node-field-budget", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1126-000", + "phase": "1126", + "title": "verify_grease_pencil_viewport_module", + "kind": "module", + "owner": "DRAWING", + "dependsOn": [ + "WBV2-P1125-000" + ], + "parityId": "GREASE_PENCIL_VIEWPORT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-grease_pencil_viewport", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1126-000.md", + "behavior": "Verify Grease Pencil 2D/3D selection and marquee integration on both viewport backends using an isolated Chromium port.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "2D and 3D selection revisions converge", + "main-thread and Offscreen marquee are exact", + "stale/foreign selection cases remain fail-closed", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GREASE_PENCIL_VIEWPORT", + "sourceBacked": true, + "capabilities": [ + "CAP-GREASE-PENCIL-SELECTION-REVISION", + "CAP-GREASE-PENCIL-MARQUEE-MAIN", + "CAP-GREASE-PENCIL-MARQUEE-OFFSCREEN" + ], + "sourcePaths": [ + "web/protocol/grease-pencil-selection.ts", + "web/protocol/grease-pencil-marquee.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/grease-pencil.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/workers/viewport-render.worker.ts" + ], + "reuseReceipts": [], + "positive": [ + "2D canvas selection revision", + "main-thread 3D marquee selection", + "OffscreenCanvas 3D marquee selection" + ], + "negative": [ + "stale selection revision", + "foreign drawing identity", + "duplicate or forged point candidate" + ], + "recovery": [ + "selection convergence across backends", + "worker viewport restart", + "deterministic repeated marquee", + "preserve Main revision" + ], + "commands": [ + "WEB_TEST_PORT=5331 npm --prefix web run test:e2e -- --workers=1 tests/e2e/grease-pencil-selection.spec.ts tests/e2e/grease-pencil-marquee.spec.ts", + "node --test web/tests/unit/grease-pencil-selection.test.mjs web/tests/unit/grease-pencil-marquee.test.mjs", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1127-000", + "phase": "1127", + "title": "verify_tracking_mask_module", + "kind": "module", + "owner": "TRACKING", + "dependsOn": [ + "WBV2-P1126-000" + ], + "parityId": "TRACKING_MASK", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-tracking_mask", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1127-000.md", + "behavior": "Verify Mask reader, editable point raycast/marquee and tracking capability gates through Chromium.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Mask reader and interaction evidence is proven", + "negative solve/resource cases are proven", + "Chromium stable IDs and recovery receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TRACKING_MASK", + "sourceBacked": true, + "capabilities": [ + "CAP-MASK-MAIN-READER", + "CAP-MASK-POINT-RAYCAST", + "CAP-TRACKING-SOLVE-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/tracking-mask.ts", + "web/protocol/scene-ir.ts", + "web/app/src/tracking/MaskSelection.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/tests/e2e/smoke.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "Mask layers and splines reader", + "editable Mask point raycast", + "N-022 tracking marker/mask gate" + ], + "negative": [ + "foreign mask point identity", + "missing resource binding", + "camera solve unavailable" + ], + "recovery": [ + "main/offscreen marquee parity", + "worker restart", + "deterministic stable IDs", + "preserve source Main on blocked solve" + ], + "commands": [ + "npm --prefix web run test:mask-main-reader", + "WEB_TEST_PORT=5340 npm --prefix web run test:e2e -- --workers=1 tests/e2e/smoke.spec.ts -g \"N-022 tracking|real Blender 5.2 Mask\"", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1128-000", + "phase": "1128", + "title": "verify_ffmpeg_movie_codec_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1127-000" + ], + "parityId": "SEQUENCER_MOVIE_CODEC", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-sequencer_movie_codec", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1128-000.md", + "behavior": "Use a local ffmpeg.wasm Worker fallback for movie probing and proxy-frame extraction when Chromium HTML media decoding is unavailable.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and core-resource hashes are bound", + "positive MP4 probe and RGBA frame are proven", + "corrupt and source-identity cases are rejected", + "AbortSignal cancellation leaves no live Worker", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SEQUENCER_MOVIE_CODEC", + "sourceBacked": true, + "capabilities": [ + "CAP-FFMPEG-WASM-MOVIE-PROBE", + "CAP-FFMPEG-WASM-PROXY-FRAME", + "CAP-MOVIE-CODEC-RECOVERY" + ], + "sourcePaths": [ + "web/package.json", + "web/package-lock.json", + "web/protocol/sequencer.ts", + "web/app/src/sequencer/SequencerCodecProbe.ts", + "web/app/src/sequencer/FFmpegMovieProbe.ts", + "web/app/src/sequencer/ffmpeg-movie-probe.worker.ts", + "web/app/src/sequencer/SequencerMediaProxyCache.ts", + "web/app/src/vendor/ffmpeg/ffmpeg-core.js", + "web/app/src/vendor/ffmpeg/ffmpeg-core.wasm", + "web/app/public/vendor/ffmpeg/ffmpeg-core.js", + "web/app/public/vendor/ffmpeg/ffmpeg-core.wasm", + "third_party/ffmpeg.wasm/package.json", + "third_party/ffmpeg.wasm/README.md", + "web/tests/e2e/ffmpeg-movie-probe-production.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "browser decode fallback to ffmpeg.wasm", + "16x16 MP4 metadata probe", + "8x8 RGBA proxy frame extraction" + ], + "negative": [ + "corrupt movie payload", + "source SHA mismatch", + "ffmpeg runtime unavailable" + ], + "recovery": [ + "AbortSignal cancellation", + "Worker termination after response", + "cache manifest identity binding", + "deterministic repeated probe" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5342 npm --prefix web run test:e2e -- --workers=1 tests/e2e/ffmpeg-movie-probe-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1129-000", + "phase": "1129", + "title": "authorize_scene_settings_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1128-000" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1129", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1129-000.md", + "behavior": "Authorize one source-backed Core Scene Graph settings module after the terminal P1128 module epoch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1128 evidence remains hash-bound", + "existing receipts are reused", + "inventory remains immutable", + "one source-backed module is active" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ] + }, + { + "id": "WBV2-P1129-001", + "phase": "1129", + "title": "verify_scene_settings_module", + "kind": "module", + "owner": "CORE_SCENE", + "dependsOn": [ + "WBV2-P1129-000" + ], + "parityId": "CORE_SCENE_GRAPH_SETTINGS", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-core_scene_graph_settings", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1129-001.md", + "behavior": "Verify the existing Blender Main scene compositor, performance and sampling setting transactions as one aggregate module.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutations are proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CORE_SCENE_GRAPH_SETTINGS", + "sourceBacked": true, + "capabilities": [ + "CAP-SCENE-COMPOSITOR-SETTINGS", + "CAP-SCENE-PERFORMANCE-SETTINGS", + "CAP-SCENE-SAMPLING-SETTINGS" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-scene-settings-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P65-002/manifest.json", + "report": "tests/golden/WBV2-P65-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P66-002/manifest.json", + "report": "tests/golden/WBV2-P66-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P67-002/manifest.json", + "report": "tests/golden/WBV2-P67-002/implementation-report.json" + } + ], + "positive": [ + "compositor device/precision mutation", + "performance thread/persistence mutation", + "sampling filter/dither mutation" + ], + "negative": [ + "invalid sampling range", + "unknown scene target", + "malformed property set" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic scene settings snapshot" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5344 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-scene-settings-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1130-000", + "phase": "1130", + "title": "authorize_editor_view2d_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1129-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1130", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1130-000.md", + "behavior": "Authorize one source-backed UI editor View2D reader/protocol module after the P1129 scene settings module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1129 evidence remains hash-bound", + "P1102 editor workflow source remains unchanged", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1130-001", + "phase": "1130", + "title": "verify_editor_view2d_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1130-000" + ], + "parityId": "UI_EDITOR_VIEW2D_STATE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-ui_editor_view2d_state", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1130-001.md", + "behavior": "Preserve Blender Graph/Dope Sheet View2D cur and mask state through the Web editor protocol without changing the existing editor workflow parser.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive reader state is proven", + "negative no-publish and recovery are proven", + "Chromium and save/reopen compatibility are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_EDITOR_VIEW2D_STATE", + "sourceBacked": true, + "capabilities": [ + "CAP-EDITOR-VIEW2D-CUR", + "CAP-EDITOR-VIEW2D-MASK", + "CAP-EDITOR-VIEW2D-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/editor-view2d.ts", + "web/app/src/workers/editor-view2d-test.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/ui-editor-view2d-production.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "Graph main-region View2D cur retention", + "Graph main-region pixel mask retention", + "reader/protocol exact state" + ], + "negative": [ + "inverted View2D bounds", + "malformed mask range", + "missing View2D payload" + ], + "recovery": [ + "immutable base editor workflow", + "worker termination", + "deterministic repeated parse", + "save/reopen reader compatibility" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5346 npm --prefix web run test:e2e -- --workers=1 tests/e2e/ui-editor-view2d-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1131-000", + "phase": "1131", + "title": "authorize_curve_topology_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1130-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1131", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1131-000.md", + "behavior": "Authorize one source-backed Curve topology editor module after the P1130 View2D module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1130 evidence remains hash-bound", + "Curve topology source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1131-001", + "phase": "1131", + "title": "verify_curve_topology_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1131-000" + ], + "parityId": "CURVE_TOPOLOGY_EDITOR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_topology_editor", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1131-001.md", + "behavior": "Verify the Blender Curve TOGGLE_CYCLIC topology transaction through the existing Main, protocol, Worker and frontend path.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_TOPOLOGY_EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-TOGGLE-CYCLIC", + "CAP-CURVE-TOPOLOGY-GATE", + "CAP-CURVE-TOPOLOGY-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/editors/curve/curve_ops.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/curve-topology-editor.ts", + "web/app/src/workers/curve-topology-contract-test.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/curve-topology-contract.spec.ts", + "web/tests/e2e/curve-topology-operator.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "TOGGLE_CYCLIC Main mutation", + "operator gate exposes only verified capability", + "save/reopen preserves cyclic spline state" + ], + "negative": [ + "unknown curve operator", + "stale revision claim", + "selection and payload budget overflow" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic contract parse" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5347 npm --prefix web run test:e2e -- --workers=1 tests/e2e/curve-topology-contract.spec.ts tests/e2e/curve-topology-operator.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1132-000", + "phase": "1132", + "title": "authorize_curve_handle_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1131-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1132", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1132-000.md", + "behavior": "Authorize one source-backed Curve handle gizmo module after the P1131 topology module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1131 evidence remains hash-bound", + "Curve handle source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1132-001", + "phase": "1132", + "title": "verify_curve_handle_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1132-000" + ], + "parityId": "CURVE_HANDLE_GIZMO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_handle_gizmo", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1132-001.md", + "behavior": "Verify Curve handle position edits through Blender Main, protocol, Worker, renderer preview and frontend gizmo.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_HANDLE_GIZMO", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-HANDLE-MAIN", + "CAP-CURVE-HANDLE-GIZMO-PREVIEW", + "CAP-CURVE-HANDLE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/nonmesh-interaction.ts", + "web/app/src/workers/nonmesh-interaction-test.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/nonmesh.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/tests/e2e/wbv2-curve-handle-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Curve handle position Main mutation", + "local handle gizmo preview", + "save/reopen preserves handle state" + ], + "negative": [ + "invalid handle identity", + "stale base revision", + "malformed handle position" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic preview" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5348 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-curve-handle-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1133-000", + "phase": "1133", + "title": "authorize_curve_splines_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1132-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1133", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1133-000.md", + "behavior": "Authorize one source-backed Curve spline transaction module after the P1132 handle module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1132 evidence remains hash-bound", + "Curve spline source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1133-001", + "phase": "1133", + "title": "verify_curve_splines_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1133-000" + ], + "parityId": "CURVE_SPLINES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_splines_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1133-001.md", + "behavior": "Verify complete Curve spline replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_SPLINES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-SPLINES-MAIN", + "CAP-CURVE-SPLINES-RECOVERY", + "CAP-CURVE-SPLINES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/tests/e2e/wbv2-curve-splines-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "complete Curve spline Main transaction", + "POLY/BEZIER descriptor retention", + "save/reopen preserves spline state" + ], + "negative": [ + "invalid spline offsets", + "stale base revision", + "mismatched handle payload" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic binary-geometry transaction" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5349 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-curve-splines-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1134-000", + "phase": "1134", + "title": "authorize_surface_topology_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1133-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1134", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1134-000.md", + "behavior": "Authorize one source-backed Surface topology transaction module after the P1133 Curve spline module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1133 evidence remains hash-bound", + "Surface topology source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1134-001", + "phase": "1134", + "title": "verify_surface_topology_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1134-000" + ], + "parityId": "SURFACE_TOPOLOGY_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-surface_topology_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1134-001.md", + "behavior": "Verify Surface NURBS topology replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SURFACE_TOPOLOGY_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-SURFACE-TOPOLOGY-MAIN", + "CAP-SURFACE-NURBS-BOUNDS", + "CAP-SURFACE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/tests/e2e/wbv2-surface-topology-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Surface topology Main transaction", + "NURBS dimensions and weights retention", + "save/reopen preserves surface state" + ], + "negative": [ + "invalid surface dimensions", + "stale base revision", + "control grid budget mismatch" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic surface transaction" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5350 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-surface-topology-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1135-000", + "phase": "1135", + "title": "authorize_font_body_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1134-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1135", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1135-000.md", + "behavior": "Authorize one source-backed Font body transaction module after the P1134 Surface topology module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1134 evidence remains hash-bound", + "Font body source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1135-001", + "phase": "1135", + "title": "verify_font_body_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1135-000" + ], + "parityId": "FONT_BODY_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-font_body_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1135-001.md", + "behavior": "Verify Font body replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FONT_BODY_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-BODY-MAIN", + "CAP-FONT-BODY-RECOVERY", + "CAP-FONT-BODY-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-font-body-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Font body Main mutation", + "UTF-8 text retention", + "save/reopen preserves text" + ], + "negative": [ + "unknown Font data ID", + "body byte budget overflow", + "malformed body payload" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic text state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5351 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-font-body-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1136-000", + "phase": "1136", + "title": "authorize_font_properties_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1135-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1136", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1136-000.md", + "behavior": "Authorize one source-backed Font properties transaction module after the P1135 Font body module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1135 evidence remains hash-bound", + "Font property source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1136-001", + "phase": "1136", + "title": "verify_font_properties_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1136-000" + ], + "parityId": "FONT_PROPERTIES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-font_properties_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1136-001.md", + "behavior": "Verify Font property replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FONT_PROPERTIES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-PROPERTIES-MAIN", + "CAP-FONT-PROPERTIES-RECOVERY", + "CAP-FONT-PROPERTIES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-font-properties-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Font property Main mutation", + "bounded alignment/extrude fields", + "save/reopen preserves properties" + ], + "negative": [ + "unknown Font data ID", + "invalid alignment enum", + "out-of-range numeric property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic property state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5352 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-font-properties-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1137-000", + "phase": "1137", + "title": "authorize_metaball_elements_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1136-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1137", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1137-000.md", + "behavior": "Authorize one source-backed Metaball element transaction module after the P1136 Font properties module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1136 evidence remains hash-bound", + "Metaball element source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1137-001", + "phase": "1137", + "title": "verify_metaball_elements_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1137-000" + ], + "parityId": "METABALL_ELEMENTS_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-metaball_elements_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1137-001.md", + "behavior": "Verify Metaball element replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "METABALL_ELEMENTS_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-METABALL-ELEMENTS-MAIN", + "CAP-METABALL-ELEMENTS-RECOVERY", + "CAP-METABALL-ELEMENTS-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-metaball-elements-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Metaball element Main mutation", + "bounded position/radius/scale retention", + "save/reopen preserves elements" + ], + "negative": [ + "unknown Metaball data ID", + "invalid radius", + "element count topology mismatch" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic element state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-metaball-elements-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1138-000", + "phase": "1138", + "title": "authorize_text_source_module", + "kind": "enabling", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1137-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1138", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1138-000.md", + "behavior": "Authorize a source-backed Text datablock mutation after the P1137 Metaball module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1137 evidence remains hash-bound", + "ID_TXT is registered for WITH_WEB", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1138-001", + "phase": "1138", + "title": "verify_text_source_module", + "kind": "module", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1138-000" + ], + "parityId": "TEXT_SOURCE_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-text_source_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1138-001.md", + "behavior": "Verify Text source replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TEXT_SOURCE_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXT-SOURCE-MAIN", + "CAP-TEXT-SOURCE-RECOVERY", + "CAP-TEXT-SOURCE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/blenkernel/intern/idtype.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-text-source-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1137-001/manifest.json", + "report": "tests/golden/WBV2-P1137-001/module-receipt.json" + } + ], + "positive": [ + "Text source Main mutation", + "ID_TXT registration in WITH_WEB", + "save/reopen preserves source" + ], + "negative": [ + "unknown Text data ID", + "source over 1 MiB", + "linked/read-only Text" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic source state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-text-source-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1139-000", + "phase": "1139", + "title": "authorize_texture_properties_module", + "kind": "enabling", + "owner": "TEXTURE", + "dependsOn": [ + "WBV2-P1138-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1139", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1139-000.md", + "behavior": "Authorize a source-backed Texture property mutation module after P1138 Text.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1138 evidence remains hash-bound", + "ID_TE is registered for WITH_WEB", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1139-001", + "phase": "1139", + "title": "verify_texture_properties_module", + "kind": "module", + "owner": "TEXTURE", + "dependsOn": [ + "WBV2-P1139-000" + ], + "parityId": "TEXTURE_PROPERTIES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-texture_properties_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1139-001.md", + "behavior": "Verify Texture property replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TEXTURE_PROPERTIES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXTURE-PROPERTIES-MAIN", + "CAP-TEXTURE-PROPERTIES-RECOVERY", + "CAP-TEXTURE-PROPERTIES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/blenkernel/intern/idtype.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-texture-properties-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1138-001/manifest.json", + "report": "tests/golden/WBV2-P1138-001/module-receipt.json" + } + ], + "positive": [ + "Texture property Main mutation", + "ID_TE registration in WITH_WEB", + "save/reopen preserves properties" + ], + "negative": [ + "unknown Texture data ID", + "noise depth outside Blender bounds", + "non-finite numeric property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic property state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-texture-properties-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1140-000", + "phase": "1140", + "title": "authorize_action_group_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1139-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1140", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1140-000.md", + "behavior": "Authorize a source-backed ActionGroup reader and recovery module after P1139 Texture.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1139 evidence remains hash-bound", + "ActionGroup has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1140-001", + "phase": "1140", + "title": "verify_action_group_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1140-000" + ], + "parityId": "ACTION_GROUP_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-action_group_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1140-001.md", + "behavior": "Verify ActionGroup metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ACTION_GROUP_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-GROUP-READER", + "CAP-ACTION-GROUP-RECOVERY", + "CAP-ACTION-GROUP-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-action-group-reader-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1112-000/manifest.json", + "report": "tests/golden/WBV2-P1112-000/module-receipt.json" + } + ], + "positive": [ + "ActionGroup Main reader exposes group and expanded metadata", + "three grouped location F-Curves remain grouped", + "save/reopen preserves group metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing animation target is fail-closed", + "unsupported group payload is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic group state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5356 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-action-group-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1141-000", + "phase": "1141", + "title": "authorize_action_pose_markers_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1140-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1141", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1141-000.md", + "behavior": "Authorize a source-backed ActionPoseMarkers reader and recovery module after P1140.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1140 evidence remains hash-bound", + "ActionPoseMarkers has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1141-001", + "phase": "1141", + "title": "verify_action_pose_markers_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1141-000" + ], + "parityId": "ACTION_POSE_MARKERS_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-action_pose_markers_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1141-001.md", + "behavior": "Verify ActionPoseMarkers metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ACTION_POSE_MARKERS_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-POSE-MARKERS-READER", + "CAP-ACTION-POSE-MARKERS-RECOVERY", + "CAP-ACTION-POSE-MARKERS-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-action-pose-markers-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1140-001/manifest.json", + "report": "tests/golden/WBV2-P1140-001/module-receipt.json" + } + ], + "positive": [ + "ActionPoseMarkers Main reader exposes marker names and frames", + "three Blender pose markers remain ordered", + "save/reopen preserves marker metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing animation target is fail-closed", + "non-finite marker frame is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic marker state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5359 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-action-pose-markers-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1142-000", + "phase": "1142", + "title": "authorize_fcurve_sample_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1141-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1142", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1142-000.md", + "behavior": "Authorize a source-backed FCurveSample reader and recovery module after P1141.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1141 evidence remains hash-bound", + "FCurveSample has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1142-001", + "phase": "1142", + "title": "verify_fcurve_sample_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1142-000" + ], + "parityId": "FCURVE_SAMPLE_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-fcurve_sample_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1142-001.md", + "behavior": "Verify FCurveSample data through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FCURVE_SAMPLE_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-SAMPLE-READER", + "CAP-FCURVE-SAMPLE-RECOVERY", + "CAP-FCURVE-SAMPLE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-fcurve-sample-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1141-001/manifest.json", + "report": "tests/golden/WBV2-P1141-001/module-receipt.json" + } + ], + "positive": [ + "FCurveSample Main reader exposes sampled source and values", + "four native FPoint samples remain ordered", + "save/reopen preserves sampled data" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing sampled payload is fail-closed", + "non-finite sampled value is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic sampled state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5365 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-sample-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1143-000", + "phase": "1143", + "title": "authorize_fcurve_modifier_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1142-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1143", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1143-000.md", + "behavior": "Authorize a source-backed FCurve modifier reader and recovery module after P1142.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1142 evidence remains hash-bound", + "FCurveModifiers has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1143-001", + "phase": "1143", + "title": "verify_fcurve_modifier_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1143-000" + ], + "parityId": "FCURVE_MODIFIER_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-fcurve_modifier_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1143-001.md", + "behavior": "Verify FCurve modifier metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FCURVE_MODIFIER_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-MODIFIER-READER", + "CAP-FCURVE-MODIFIER-RECOVERY", + "CAP-FCURVE-MODIFIER-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-fcurve-modifier-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1142-001/manifest.json", + "report": "tests/golden/WBV2-P1142-001/module-receipt.json" + } + ], + "positive": [ + "FCurveModifiers Main reader exposes native modifier stack", + "FModifierCycles preserves type/name/flags/influence", + "save/reopen preserves modifier metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing modifier payload is fail-closed", + "unsupported modifier type is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic modifier state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5368 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-modifier-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1144-000", + "phase": "1144", + "title": "authorize_driver_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1143-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1144", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1144-000.md", + "behavior": "Authorize a source-backed Driver reader and recovery module after P1143.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1143 evidence remains hash-bound", + "Driver has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1144-001", + "phase": "1144", + "title": "verify_driver_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1144-000" + ], + "parityId": "DRIVER_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-driver_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1144-001.md", + "behavior": "Verify Driver metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "DRIVER_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-DRIVER-READER", + "CAP-DRIVER-RECOVERY", + "CAP-DRIVER-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-driver-reader-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1143-001/manifest.json", + "report": "tests/golden/WBV2-P1143-001/module-receipt.json" + } + ], + "positive": [ + "AnimData driver list is read from Blender Main", + "Driver preserves scripted expression and variables", + "save/reopen preserves driver metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing driver target is fail-closed", + "non-finite driver influence is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic driver state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-driver-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1145-000", + "phase": "1145", + "title": "authorize_corrective_smooth_reader_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1144-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1145", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1145-000.md", + "behavior": "Authorize a source-backed Corrective Smooth reader/recovery module after the Driver reader.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "Corrective Smooth has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1145-001", + "phase": "1145", + "title": "verify_corrective_smooth_reader_module", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1145-000" + ], + "parityId": "CORRECTIVE_SMOOTH_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-corrective_smooth_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1145-001.md", + "behavior": "Verify Corrective Smooth modifier type and RNA metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CORRECTIVE_SMOOTH_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-CORRECTIVE-SMOOTH-READER", + "CAP-CORRECTIVE-SMOOTH-RECOVERY", + "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + "tests/files/web/modifier_corrective_smooth_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "Corrective Smooth type is read from Blender Main", + "RNA metadata is preserved", + "save/reopen preserves modifier metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported modifier data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1146-000", + "phase": "1146", + "title": "authorize_modifier_reader_batch", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1145-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1146", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1146-000.md", + "behavior": "Authorize one shared source-backed modifier reader batch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1146-001", + "phase": "1146", + "title": "verify modifier reader batch", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1146-000" + ], + "parityId": "MODIFIER_READER_BATCH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_reader_batch", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1146-001.md", + "behavior": "Verify the MODIFIER_READER_BATCH batch through Blender Main, WASM and Chromium recovery.", + "outputs": [ + "aggregate module receipt", + "coverage bindings", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_READER_BATCH", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH-READER", + "CAP-MODIFIER_READER_BATCH-RECOVERY", + "CAP-MODIFIER_READER_BATCH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "MOD_datatransfer type is read from Blender Main", + "MOD_dynamicpaint type is read from Blender Main", + "MOD_explode type is read from Blender Main", + "MOD_fluid type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts" + ], + "fullFamilyParity": false, + "evidencePaths": [ + "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json" + ], + "coverageBindings": [ + "modifier-source:MOD_datatransfer", + "modifier-source:MOD_dynamicpaint", + "modifier-source:MOD_explode", + "modifier-source:MOD_fluid", + "rna-struct:DataTransferModifier", + "rna-struct:DynamicPaintModifier", + "rna-struct:ExplodeModifier", + "rna-struct:FluidModifier", + "rna-struct:FluidDomainSettings" + ] + } + } + ] +} diff --git a/tests/golden/WBV2-P1146-000/successor-authorization-report.json b/tests/golden/WBV2-P1146-000/successor-authorization-report.json new file mode 100644 index 000000000..6e4d95a78 --- /dev/null +++ b/tests/golden/WBV2-P1146-000/successor-authorization-report.json @@ -0,0 +1,37 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1146-000", + "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", + "taskClass": "QUEUE_ENABLEMENT", + "status": "PASS", + "parent": { + "task": "WBV2-P1145-001", + "manifest": "tests/golden/WBV2-P1145-001/manifest.json", + "manifestSha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "module": { + "moduleId": "MODIFIER_READER_BATCH", + "task": "WBV2-P1146-001", + "batchSize": 9, + "sourceUnits": [ + "modifier-source:MOD_datatransfer", + "modifier-source:MOD_dynamicpaint", + "modifier-source:MOD_explode", + "modifier-source:MOD_fluid", + "rna-struct:DataTransferModifier", + "rna-struct:DynamicPaintModifier", + "rna-struct:ExplodeModifier", + "rna-struct:FluidModifier", + "rna-struct:FluidDomainSettings" + ], + "sourceBacked": true + }, + "inventory": { + "unitCount": 3745, + "verifiedUnits": 350, + "unverifiedUnits": 3395, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "boundUnitDelta": 0 + }, + "nextTask": "WBV2-P1146-001" +} diff --git a/tests/golden/WBV2-P1146-001/continuous-gates.log b/tests/golden/WBV2-P1146-001/continuous-gates.log new file mode 100644 index 000000000..8d227b950 --- /dev/null +++ b/tests/golden/WBV2-P1146-001/continuous-gates.log @@ -0,0 +1,2 @@ +context-governance-ok task=WBV2-P1146-001 contentTokens=1968 envelopeTokens=655/1024 estimatedTokens=2992/3500 inputs=0 commands=1 +{"schemaVersion":1,"operation":"BLENDER_WEB_EXECUTION_CONTROL_PLANE","status":"BLOCKED","authority":{"executionPointer":"docs/EXECUTION_QUEUE.md","productCapabilities":"docs/BLENDER_WASM_CAPABILITY_MATRIX_TEMPLATE.json","legacyCoverage":"tests/golden/M15-03A/next-task-plan.json","historicalEvidence":"tests/golden/corrective/"},"queue":{"currentTask":"WBV2-P1146-001","parentManifest":"tests/golden/WBV2-P1146-000/manifest.json","parentTask":"WBV2-P1146-000","parentNextTask":"WBV2-P1146-001","activeCatalogTask":null,"legacyCoverageTask":"M16-GAP-00282","legacyCoverageParentManifest":"tests/golden/M16-GAP-00281/manifest.json","legacyCoverageState":"active","runnableInputs":null},"efficiency":{"legacyGapTasks":6900,"legacyCompleted":281,"legacyPending":6618,"capabilityClusters":3,"mappedLegacyGaps":9,"averageGapsPerCapability":3,"productiveLane":0,"rule":"one capability task may close multiple legacy cases; legacy cases remain regression coverage"},"dynamicInventory":{"path":"tests/golden/WBV2/dynamic-inventory.json","manifestPath":"tests/golden/WBV2/dynamic-inventory-manifest.json","sourceTreeSha256":"600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202","sourceFiles":6206,"unitCount":3745,"planningEstimate":5200,"hardTarget":false,"verifiedUnits":359,"unverifiedUnits":3386},"capabilityClusters":{"ASSET_CATALOG":{"capabilityId":"CAP-ASSET-CATALOG-MUTATION","sourceGaps":5,"parityLevel":"L0","targetParityLevel":"L4","lifecycleStatus":"planned"},"MODIFIER":{"capabilityId":"CAP-MODIFIER-STATE-MUTATION","sourceGaps":2,"parityLevel":"L0","targetParityLevel":"L3","lifecycleStatus":"planned"},"MESH":{"capabilityId":"CAP-MESH-POSITIVE-EDIT","sourceGaps":2,"parityLevel":"L0","targetParityLevel":"L3","lifecycleStatus":"planned"}},"issues":[{"code":"DYNAMIC_INVENTORY_MANIFEST_HASH_DRIFT","detail":"tests/golden/WBV2/dynamic-inventory.json"}],"remediation":["inspect the control-plane issue and preserve its evidence"],"allowUnrunnable":true,"inputDigest":"ce2b3b4979df4fefec3126d242df0749e25f35f0b20826f5b77d2b2e0b16eb46"} diff --git a/tests/golden/WBV2-P1146-001/continuous-runner.log b/tests/golden/WBV2-P1146-001/continuous-runner.log new file mode 100644 index 000000000..e92c872a5 --- /dev/null +++ b/tests/golden/WBV2-P1146-001/continuous-runner.log @@ -0,0 +1,4 @@ +v2-task-index-generated tasks=73 active=NONE output=tests/golden/WBV2/task-index.json +task-context-ok task=WBV2-P1146-001 parent=WBV2-P1146-000 contentTokens=1968 envelopeTokens=655/1024 estimatedTokens=2992/3500 taskBytes=2307 next=NONE output=tests/golden/WBV2-P1146-001/task-context.json +wbv2-module-coverage-bound task=WBV2-P1146-001 module=MODIFIER_READER_BATCH added=9 verified=359 unverified=3386 +module-task-complete task=WBV2-P1146-001 module=MODIFIER_READER_BATCH next=null commands=4 diff --git a/tests/golden/WBV2-P1146-001/manifest.json b/tests/golden/WBV2-P1146-001/manifest.json new file mode 100644 index 000000000..bcb82f252 --- /dev/null +++ b/tests/golden/WBV2-P1146-001/manifest.json @@ -0,0 +1 @@ +{"schemaVersion":1,"task":"WBV2-P1146-001","parentTask":"WBV2-P1146-000","operation":"MODULE_FUNCTION_EXECUTION","taskClass":"MODULE","status":"done","enablingTask":true,"parityStateChange":false,"runtime":"BLENDER_WEB_FUNCTION_MODULE","artifacts":{"parentManifest":{"path":"tests/golden/WBV2-P1146-000/manifest.json","sha256":"71385fd4a21497b907dd28e745aca35fbfca0e0a76cddcf517d52619d5b9a886"},"source1":{"path":"blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc","sha256":"201bf6334689a689326681db129a63140d4483c40d3187e394ad548090070438"},"source2":{"path":"blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc","sha256":"269d97eefcf59741aa2d59d67a2b29c881e70f6b7331366b5c7e325e51420516"},"source3":{"path":"blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc","sha256":"165d75c5739ed4a88cd72134a881a7802f0c57339307743799f73bf49b788c0c"},"source4":{"path":"blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc","sha256":"41aaadf31d4bf815dd86f1d8f433f925b336ddf4efcd4e377f64d5e8470d7e63"},"source5":{"path":"blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc","sha256":"1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b"},"source6":{"path":"blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc","sha256":"1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b"},"source7":{"path":"blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc","sha256":"1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b"},"source8":{"path":"blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc","sha256":"1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b"},"source9":{"path":"blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc","sha256":"a2ca40cda63b5a6ab77a78d8ee14d039abbf0577f82c7f1904879fac777643d4"},"source10":{"path":"blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp","sha256":"f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990"},"source11":{"path":"web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts","sha256":"afdabf3af64695daca0b78555692729753752c03b10d2470676ba7515c79e0ce"},"source12":{"path":"tests/files/web/modifier_reader_batch_scene.blend","sha256":"de3b7a3aa35625b5071eebd06e3215571ac48ae6959b1ae380ecdf67f9ade0d9"},"source13":{"path":"web/app/src/vendor/blender/web_engine.wasm","sha256":"32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe"},"evidence1":{"path":"tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json","sha256":"4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3"},"moduleReceipt":{"path":"tests/golden/WBV2-P1146-001/module-receipt.json","sha256":"ba4604086e19251098ab01e241a22be0b927180b1a4e76fc04ff7a01bf45dc26"},"status":{"path":"docs/status/WBV2-P1146-001.md","sha256":"8b8bf4c73ae59d9a15a04d47291af701ef9107cba7921b90f5900b3818b4dd9d"},"log":{"path":"tests/golden/WBV2-P1146-001/module-run.log","sha256":"102ce83b881b316bd801879b4820ac173f092f6073b08928bacf5bc843095452"},"plan":{"path":"tests/golden/WBV2-P1146-000/module-execution-plan.json","sha256":"a5cbbd2010df35f49a89c93e479f20d447ce5d4be1e4c3db4050bb60837146d7"},"taskContext":{"path":"tests/golden/WBV2-P1146-001/task-context.json","sha256":"bd24967e771cb0abde2100867ab3fec9d4139d567a6eb4b8ea26a5e01969fd52"}},"assertions":{"moduleId":"MODIFIER_READER_BATCH","sourceBacked":true,"positiveCases":6,"negativeCases":3,"recoveryCases":3,"commandCount":4,"reusedReceiptCount":1,"sourceUnchanged":true,"fullFamilyParity":false,"dynamicInventoryPath":"tests/golden/WBV2/dynamic-inventory.json","dynamicSourceTreeSha256":"600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202","dynamicUnitCount":3745,"dynamicVerifiedUnits":359,"dynamicUnverifiedUnits":3386,"planningEstimate":5200,"historicalInventoryTotal":6900,"historicalEffectiveCompleted":290,"historicalEffectivePending":6609,"historicalReproduction":false},"nextTask":"WBV2-P1147-000"} diff --git a/tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json b/tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json new file mode 100644 index 000000000..375b30e7d --- /dev/null +++ b/tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json @@ -0,0 +1,212 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1146-001", + "operation": "MODIFIER_READER_BATCH_CHROMIUM_SAVE_REOPEN", + "browser": "chromium", + "queueMutation": false, + "fixture": "tests/files/web/modifier_reader_batch_scene.blend", + "fixtureSha256": "de3b7a3aa35625b5071eebd06e3215571ac48ae6959b1ae380ecdf67f9ade0d9", + "expectedTypes": [ + "DATA_TRANSFER", + "DYNAMIC_PAINT", + "EXPLODE", + "FLUID" + ], + "sourceUnits": [ + "modifier-source:MOD_datatransfer", + "modifier-source:MOD_dynamicpaint", + "modifier-source:MOD_explode", + "modifier-source:MOD_cast", + "rna-struct:DataTransferModifier", + "rna-struct:DynamicPaintModifier", + "rna-struct:ExplodeModifier", + "rna-struct:CastModifier" + ], + "before": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:864389176", + "name": "Data Transfer", + "type": "DATA_TRANSFER", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 864389176, + "typeCode": 49 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:1142069749", + "name": "Dynamic Paint", + "type": "DYNAMIC_PAINT", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1142069749, + "typeCode": 40 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:1886000045", + "name": "Explode", + "type": "EXPLODE", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1886000045, + "typeCode": 21 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:874629360", + "name": "Fluid", + "type": "FLUID", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 874629360, + "typeCode": 56 + } + } + ], + "types": [ + "DATA_TRANSFER", + "DYNAMIC_PAINT", + "EXPLODE", + "FLUID" + ], + "after": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:864389176", + "name": "Data Transfer", + "type": "DATA_TRANSFER", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 864389176, + "typeCode": 49 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:1142069749", + "name": "Dynamic Paint", + "type": "DYNAMIC_PAINT", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1142069749, + "typeCode": 40 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:1886000045", + "name": "Explode", + "type": "EXPLODE", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1886000045, + "typeCode": 21 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:874629360", + "name": "Fluid", + "type": "FLUID", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 874629360, + "typeCode": 56 + } + } + ], + "second": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:864389176", + "name": "Data Transfer", + "type": "DATA_TRANSFER", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 864389176, + "typeCode": 49 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:1142069749", + "name": "Dynamic Paint", + "type": "DYNAMIC_PAINT", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1142069749, + "typeCode": 40 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:1886000045", + "name": "Explode", + "type": "EXPLODE", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1886000045, + "typeCode": 21 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchFixture:874629360", + "name": "Fluid", + "type": "FLUID", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 874629360, + "typeCode": 56 + } + } + ], + "saveReopenExact": true, + "deterministicExact": true, + "savedSha256": "de3b7a3aa35625b5071eebd06e3215571ac48ae6959b1ae380ecdf67f9ade0d9", + "malformed": { + "code": "BLEND_READ_FAILED", + "message": "Input is not an uncompressed, gzip, or zstd Blender file" + } +} diff --git a/tests/golden/WBV2-P1146-001/module-receipt.json b/tests/golden/WBV2-P1146-001/module-receipt.json new file mode 100644 index 000000000..154c4d50d --- /dev/null +++ b/tests/golden/WBV2-P1146-001/module-receipt.json @@ -0,0 +1,131 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1146-001", + "operation": "MODULE_FUNCTION_EXECUTION", + "moduleId": "MODIFIER_READER_BATCH", + "status": "PASS", + "source": { + "paths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "before": { + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc": "201bf6334689a689326681db129a63140d4483c40d3187e394ad548090070438", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc": "269d97eefcf59741aa2d59d67a2b29c881e70f6b7331366b5c7e325e51420516", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc": "165d75c5739ed4a88cd72134a881a7802f0c57339307743799f73bf49b788c0c", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc": "41aaadf31d4bf815dd86f1d8f433f925b336ddf4efcd4e377f64d5e8470d7e63", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc": "a2ca40cda63b5a6ab77a78d8ee14d039abbf0577f82c7f1904879fac777643d4", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts": "afdabf3af64695daca0b78555692729753752c03b10d2470676ba7515c79e0ce", + "tests/files/web/modifier_reader_batch_scene.blend": "de3b7a3aa35625b5071eebd06e3215571ac48ae6959b1ae380ecdf67f9ade0d9", + "web/app/src/vendor/blender/web_engine.wasm": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "after": { + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc": "201bf6334689a689326681db129a63140d4483c40d3187e394ad548090070438", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc": "269d97eefcf59741aa2d59d67a2b29c881e70f6b7331366b5c7e325e51420516", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc": "165d75c5739ed4a88cd72134a881a7802f0c57339307743799f73bf49b788c0c", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc": "41aaadf31d4bf815dd86f1d8f433f925b336ddf4efcd4e377f64d5e8470d7e63", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc": "a2ca40cda63b5a6ab77a78d8ee14d039abbf0577f82c7f1904879fac777643d4", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts": "afdabf3af64695daca0b78555692729753752c03b10d2470676ba7515c79e0ce", + "tests/files/web/modifier_reader_batch_scene.blend": "de3b7a3aa35625b5071eebd06e3215571ac48ae6959b1ae380ecdf67f9ade0d9", + "web/app/src/vendor/blender/web_engine.wasm": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "unchanged": true + }, + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json", + "manifestSha256": "a53ebdc52db5dcf27d44e938e5551f1ee2adae8e46c3fe8661604ee6b1000f8c", + "reportSha256": "6dd419799e1a4b9251328d9496f2459d148cd89118740a06b0ee6ffb78e0b1d2" + } + ], + "cases": { + "positive": [ + "MOD_datatransfer type is read from Blender Main", + "MOD_dynamicpaint type is read from Blender Main", + "MOD_explode type is read from Blender Main", + "MOD_fluid type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ] + }, + "commands": [ + { + "command": "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "exitCode": 0 + }, + { + "command": "npm --prefix web run typecheck", + "exitCode": 0 + }, + { + "command": "npm --prefix web run build", + "exitCode": 0 + }, + { + "command": "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "exitCode": 0 + } + ], + "verification": { + "required": [ + "sourceHash", + "wasmBuild", + "positiveMainMutation", + "negativeNoMutation", + "undoRedo", + "saveReopen", + "aggregateManifest" + ], + "chromiumOnly": true, + "fullFamilyParity": false + }, + "inventory": { + "historical": { + "path": "tests/golden/WBV2-P0-002/parity-map.json", + "sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8", + "total": 6900, + "legacyCompleted": 281, + "legacyPending": 6618, + "effectiveCompleted": 290, + "effectivePending": 6609, + "mutation": "forbidden_by_module_execution" + }, + "dynamic": { + "path": "tests/golden/WBV2/dynamic-inventory.json", + "sha256": "3cf5795f89066d759400fa206b559020e27c157708febdab393fa978303a79aa", + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "unitCount": 3745, + "planningEstimate": 5200, + "hardTarget": false, + "verifiedUnits": 359, + "unverifiedUnits": 3386 + } + }, + "nextTask": null +} diff --git a/tests/golden/WBV2-P1146-001/module-run.log b/tests/golden/WBV2-P1146-001/module-run.log new file mode 100644 index 000000000..39c408735 --- /dev/null +++ b/tests/golden/WBV2-P1146-001/module-run.log @@ -0,0 +1,49 @@ +> source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm +ninja: no work to do. + +> npm --prefix web run typecheck + +> blender-web-editor@0.1.0-rc.1 typecheck +> tsc -p tsconfig.json --noEmit + + +> npm --prefix web run build + +> blender-web-editor@0.1.0-rc.1 build +> tsc -p tsconfig.json && vite build --config app/vite.config.ts + +vite v8.2.0 building client environment for production... + transforming...✓ 102 modules transformed. +rendering chunks... +computing gzip size... +dist/index.html 0.46 kB │ gzip: 0.30 kB +dist/assets/storage.worker-D9TqXsGS.js 66.59 kB +dist/assets/web-engine.worker-BfTMiTY1.js 362.11 kB +dist/assets/viewport-render.worker-BKnJyAEz.js 634.08 kB +dist/assets/web_engine-CjnzAIfx.wasm 16,238.37 kB │ gzip: 3,856.73 kB +dist/assets/index-BgTbQCE2.css 15.35 kB │ gzip: 3.91 kB +dist/assets/index-C3AJuKSc.js 1,190.30 kB │ gzip: 316.69 kB + +✓ built in 480ms +[plugin rolldown:vite-resolve] Module "module" has been externalized for browser compatibility, imported by "/home/mes123456/workinf_Blender_Wasm/web/app/src/vendor/blender/web_engine.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details. +[plugin builtin:vite-reporter] +(!) Some chunks are larger than 500 kB after minification. Consider: +- Using dynamic import() to code-split the application +- Use build.rolldownOptions.output.codeSplitting to improve chunking: https://rolldown.rs/reference/OutputOptions.codeSplitting +- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. + +> WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts + +> blender-web-editor@0.1.0-rc.1 test:e2e +> playwright test --config playwright.config.ts --workers=1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts + + +Running 1 test using 1 worker + + ✓ 1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts:12:1 › modifier reader batch preserves concrete Blender Main metadata (1.9s) + + 1 passed (2.8s) +[WebServer] (node:37899) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +[WebServer] (Use `node --trace-warnings ...` to show where the warning was created) +(node:37953) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) diff --git a/tests/golden/WBV2-P1146-001/scheduler-child.log b/tests/golden/WBV2-P1146-001/scheduler-child.log new file mode 100644 index 000000000..e69de29bb diff --git a/tests/golden/WBV2-P1146-001/task-context.json b/tests/golden/WBV2-P1146-001/task-context.json new file mode 100644 index 000000000..c9c1cd475 --- /dev/null +++ b/tests/golden/WBV2-P1146-001/task-context.json @@ -0,0 +1,187 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1146-001", + "parentTask": "WBV2-P1146-000", + "status": "done", + "goal": "以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_datatransfer, MOD_dynamicpaint, MOD_explode, MOD_fluid 的真实 modifier/RNA 元数据。", + "scope": { + "gap": "capability:MODIFIER_READER_BATCH", + "ownerFamily": "MODIFIER", + "implementationClass": "LOCAL_EXACT" + }, + "commands": [ + "node tools/web/check-task-context.mjs --task WBV2-P1146-001 --write" + ], + "inputPaths": [], + "inputSelection": { + "schemaVersion": 1, + "limits": { + "maxFiles": 12, + "evidenceBytes": 8192, + "contextRemainingBytes": 2045, + "contextRemainingTokens": 510 + }, + "source": { + "bytes": 7859, + "tokens": 1966 + }, + "selected": [], + "excluded": [ + { + "path": "blender-5.2.0/source/blender/modifiers/intern/", + "bytes": 10155, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "bytes": 521651, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "bytes": 313993, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "tests/files/web/modifier_reader_batch_scene.blend", + "bytes": 98591, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "bytes": 3939, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1146-001/module-receipt.json", + "bytes": 6621, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "bytes": 5325, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + }, + { + "path": "docs/status/WBV2-P1146-001.md", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + } + ], + "totals": { + "files": 0, + "bytes": 0, + "tokens": 0 + } + }, + "exitCriteria": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "nextTask": null, + "sourceDocuments": { + "queue": "docs/EXECUTION_QUEUE.md", + "taskCard": "docs/tasks/WBV2-P1146-001.md", + "taskIndex": "tests/golden/WBV2/task-index.json", + "parentManifest": "tests/golden/WBV2-P1146-000/manifest.json", + "parentStatus": "docs/status/WBV2-P1146-000.md" + }, + "readPolicy": { + "required": [ + "docs/EXECUTION_QUEUE.md", + "docs/tasks/WBV2-P1146-001.md", + "tests/golden/WBV2-P1146-000/manifest.json", + "docs/status/WBV2-P1146-000.md" + ], + "machineOnly": [ + "tests/golden/WBV2/task-index.json", + "tests/golden/M15-03A/task-catalog.jsonl" + ], + "optionalByNeed": [ + "docs/WEB_BLENDER_MODELER_V1_SCOPE.md", + "任务卡列出的精确协议/生产路径", + "任务卡明确命名的长期计划小节" + ], + "forbiddenByDefault": [ + "完整 CURRENT_EXECUTION_PLAN.md", + "完整 PROJECT_STATUS_AND_NEXT_WORK.md", + "全部 docs/status/*.md", + "完整 parity/WBS 计划", + "README 历史和 test-results/" + ] + }, + "parent": { + "manifest": { + "schemaVersion": 1, + "task": "WBV2-P1146-000", + "parentTask": "WBV2-P1145-001", + "status": "done", + "nextTask": "WBV2-P1146-001", + "artifactCount": 4 + }, + "statusSummary": [ + "# WBV2-P1146-000 status", + "- task: `WBV2-P1146-000`; parent: `WBV2-P1145-001`; status: `done`", + "- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed", + "- source-backed batch authorized: `MODIFIER_READER_BATCH` (9 units)", + "- dynamic inventory: `3745` units; verified `350`; unverified `3395`; bound delta `0`", + "- nextTask: `WBV2-P1146-001`" + ] + }, + "budgets": { + "queueBytes": 4096, + "taskBytes": 2300, + "parentManifestBytes": 24576, + "parentStatusBytes": 6144, + "evidenceFiles": 12, + "evidenceBytes": 8192, + "contextTokens": 3500, + "contextEnvelopeTokens": 1024, + "taskLines": 46, + "taskTokens": 575 + }, + "size": { + "documents": [ + { + "path": "docs/EXECUTION_QUEUE.md", + "bytes": 3830, + "lines": 56, + "tokens": 958 + }, + { + "path": "docs/tasks/WBV2-P1146-001.md", + "bytes": 2300, + "lines": 46, + "tokens": 575 + }, + { + "path": "tests/golden/WBV2-P1146-000/manifest.json", + "bytes": 1376, + "lines": 43, + "tokens": 344 + }, + { + "path": "docs/status/WBV2-P1146-000.md", + "bytes": 353, + "lines": 8, + "tokens": 89 + } + ], + "sourceTokens": 1966, + "evidenceFiles": 0, + "evidenceBytes": 0, + "evidenceTokens": 0, + "totalTokens": 1966, + "reservedEnvelopeTokens": 1024, + "estimatedContextTokens": 2990, + "serializedContextTokens": 653, + "withinBudget": true + } +} diff --git a/tests/golden/WBV2-P1147-000/manifest.json b/tests/golden/WBV2-P1147-000/manifest.json new file mode 100644 index 000000000..e5ec186bf --- /dev/null +++ b/tests/golden/WBV2-P1147-000/manifest.json @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1147-000", + "parentTask": "WBV2-P1146-001", + "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", + "status": "done", + "enablingTask": true, + "parityStateChange": false, + "runtime": "MODULE_EXECUTION_QUEUE_BRIDGE", + "artifacts": { + "parentManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "5c95d240abbd23915c75dcf9ded02818316d821eccaf183412e72eaf27510102" + }, + "plan": { + "path": "tests/golden/WBV2-P1147-000/module-execution-plan.json", + "sha256": "da9a713edd400bc01458e62c72efea743743a21e703289cf630ac0471b8109e1" + }, + "report": { + "path": "tests/golden/WBV2-P1147-000/successor-authorization-report.json", + "sha256": "b01c1ed09739a9fa2d162de6905cd56f6ad29c5b6d4fbc48770de8e66894598f" + }, + "status": { + "path": "docs/status/WBV2-P1147-000.md", + "sha256": "abc154efb5281fb5a0133283fdc7a9fbdbf19f6c59497807469033c015a4301e" + } + }, + "assertions": { + "sourceBackedSuccessor": true, + "moduleId": "MODIFIER_READER_BATCH_TWO", + "batchSize": 8, + "inventoryTotal": 6900, + "effectiveCompleted": 290, + "effectivePending": 6609, + "dynamicUnitCount": 3745, + "dynamicVerifiedUnits": 359, + "dynamicUnverifiedUnits": 3386, + "boundUnitDelta": 0, + "fullHistoricalReproduction": false + }, + "nextTask": "WBV2-P1147-001" +} diff --git a/tests/golden/WBV2-P1147-000/module-execution-plan.json b/tests/golden/WBV2-P1147-000/module-execution-plan.json new file mode 100644 index 000000000..39c2cab31 --- /dev/null +++ b/tests/golden/WBV2-P1147-000/module-execution-plan.json @@ -0,0 +1,5847 @@ +{ + "schemaVersion": 1, + "planId": "BLENDER_WEB_MODULE_EXECUTION_P1147", + "operation": "FUNCTION_MODULE_MIGRATION_PLAN", + "status": "COMPLETED_MODULE_EXECUTION", + "authority": "blender_main_source_and_existing_hash_bound_receipts", + "executionPointer": "docs/EXECUTION_QUEUE.md", + "inventory": { + "path": "tests/golden/WBV2-P0-002/parity-map.json", + "sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8", + "total": 6900, + "legacyCompleted": 281, + "legacyPending": 6618, + "effectiveCompleted": 290, + "effectivePending": 6609, + "mutation": "forbidden_by_module_execution" + }, + "reusePolicy": { + "completedReceipts": "reuse_without_rerun", + "continuationEvidence": "excluded", + "duplicateValidation": "forbidden", + "fullFamilyParity": "never_inferred" + }, + "verificationPolicy": { + "browser": "chromium_only", + "required": [ + "sourceHash", + "wasmBuild", + "positiveMainMutation", + "negativeNoMutation", + "undoRedo", + "saveReopen", + "aggregateManifest" + ], + "failure": "keep_module_in_progress_and_do_not_advance" + }, + "modules": [ + { + "id": "RENDER_LIGHT_CAMERA", + "task": "WBV2-P1100-001", + "owner": "RENDER", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-LIGHT-TYPE", + "CAP-RENDER-LIGHT-AREA-SHAPE", + "CAP-RENDER-LIGHT-CONTRIBUTION-FACTORS", + "CAP-RENDER-LIGHT-SHADOW-CONTROLS", + "CAP-RENDER-LIGHT-CASCADE-CONTROLS", + "CAP-RENDER-LIGHT-AREA-SIZE-Z", + "CAP-RENDER-LIGHT-CLIP-START", + "CAP-RENDER-WORLD-LIGHTING-CONTROLS", + "CAP-RENDER-WORLD-PROBE-CONTROLS", + "CAP-RENDER-WORLD-ENVIRONMENT-STRENGTH", + "CAP-RENDER-CAMERA-DOF-FOCUS-OBJECT", + "CAP-RENDER-CAMERA-PANORAMA" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P595-002/manifest.json", + "report": "tests/golden/WBV2-P595-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P596-002/manifest.json", + "report": "tests/golden/WBV2-P596-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P597-002/manifest.json", + "report": "tests/golden/WBV2-P597-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P598-002/manifest.json", + "report": "tests/golden/WBV2-P598-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P599-002/manifest.json", + "report": "tests/golden/WBV2-P599-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P600-002/manifest.json", + "report": "tests/golden/WBV2-P600-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P601-002/manifest.json", + "report": "tests/golden/WBV2-P601-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P602-002/manifest.json", + "report": "tests/golden/WBV2-P602-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P603-002/manifest.json", + "report": "tests/golden/WBV2-P603-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P604-002/manifest.json", + "report": "tests/golden/WBV2-P604-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P605-002/manifest.json", + "report": "tests/golden/WBV2-P605-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P606-002/manifest.json", + "report": "tests/golden/WBV2-P606-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SCENE_OBJECT_MESH", + "task": "WBV2-P1100-002", + "owner": "SCENE_MESH", + "sourceBacked": true, + "capabilities": [ + "CAP-MESH-TOPOLOGY-FAMILY", + "CAP-CORE-SCENE-OBJECT", + "CAP-OBJECT-MOVE-COLLECTION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-001/manifest.json", + "report": "tests/golden/WBV2-P11-001/mesh-topology-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P12-002/manifest.json", + "report": "tests/golden/WBV2-P12-002/scene-object-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P24-002/manifest.json", + "report": "tests/golden/WBV2-P24-002/object-move-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MATERIAL_ANIMATION", + "task": "WBV2-P1100-003", + "owner": "MATERIAL_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-MATERIAL-ANIMATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-003/manifest.json", + "report": "tests/golden/WBV2-P12-003/material-animation-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "NONMESH_GEOMETRY", + "task": "WBV2-P1101-000", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-VIEWPORT-NONMESH", + "CAP-NATIVE-DATABLOCK" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "NODES_SIMULATION", + "task": "WBV2-P1101-001", + "owner": "NODES_SIMULATION", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES", + "CAP-SIMULATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ASSET_IO", + "task": "WBV2-P1101-002", + "owner": "ASSET", + "sourceBacked": true, + "capabilities": [ + "CAP-ASSET-LINK-OVERRIDE-RELOAD", + "CAP-ASSET-CATALOG-MUTATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P10-003/manifest.json", + "report": "tests/golden/WBV2-P10-003/module-matrix-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SCULPT_PAINT", + "task": "WBV2-P1101-003", + "owner": "SCULPT_PAINT", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-ATTRIBUTES", + "CAP-SCULPT-PAINT" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P16-002/manifest.json", + "report": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "UI_EDITOR", + "task": "WBV2-P1102-000", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-UI-EDITOR" + ], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "INVENTORY_GATE", + "task": "WBV2-P1102-001", + "owner": "RELEASE", + "sourceBacked": true, + "capabilities": [], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "OBJECT_OPERATIONS", + "task": "WBV2-P1103-000", + "owner": "OBJECT", + "sourceBacked": true, + "capabilities": [ + "CAP-OBJECT-DUPLICATE", + "CAP-OBJECT-CREATE", + "CAP-OBJECT-PARENT", + "CAP-OBJECT-COLLECTION", + "CAP-OBJECT-RENAME", + "CAP-OBJECT-DELETE", + "CAP-OBJECT-TRANSFORM" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P17-002/manifest.json", + "report": "tests/golden/WBV2-P17-002/object-duplicate-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P18-002/manifest.json", + "report": "tests/golden/WBV2-P18-002/object-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P19-002/manifest.json", + "report": "tests/golden/WBV2-P19-002/object-parent-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P20-002/manifest.json", + "report": "tests/golden/WBV2-P20-002/collection-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P21-002/manifest.json", + "report": "tests/golden/WBV2-P21-002/object-rename-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P22-002/manifest.json", + "report": "tests/golden/WBV2-P22-002/object-delete-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P23-002/manifest.json", + "report": "tests/golden/WBV2-P23-002/object-transform-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "COMPOSITOR_SEQUENCER", + "task": "WBV2-P1104-000", + "owner": "MEDIA", + "sourceBacked": true, + "capabilities": [ + "CAP-COMPOSITOR-NODE-GRAPH", + "CAP-COMPOSITOR-UNSUPPORTED-GATE", + "CAP-SEQUENCER-MEDIA-RECOVERY" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "AUDIO_PARTICLE", + "task": "WBV2-P1105-000", + "owner": "AUDIO_PARTICLE", + "sourceBacked": true, + "capabilities": [ + "CAP-SOUND-PROPERTIES", + "CAP-SPEAKER-PROPERTIES", + "CAP-PARTICLE-SETTINGS" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P33-001/manifest.json", + "report": "tests/golden/WBV2-P33-001/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P33-002/manifest.json", + "report": "tests/golden/WBV2-P33-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "RIG_ANIMATION", + "task": "WBV2-P1106-000", + "owner": "RIG", + "sourceBacked": true, + "capabilities": [ + "CAP-RIG-POSE", + "CAP-CONSTRAINTS", + "CAP-NLA-ANIMATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-003/manifest.json", + "report": "tests/golden/WBV2-P13-003/rig-pose-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CORE_SCENE_GRAPH_SETTINGS", + "task": "WBV2-P1129-001", + "owner": "CORE_SCENE", + "sourceBacked": true, + "capabilities": [ + "CAP-SCENE-COMPOSITOR-SETTINGS", + "CAP-SCENE-PERFORMANCE-SETTINGS", + "CAP-SCENE-SAMPLING-SETTINGS" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P65-002/manifest.json", + "report": "tests/golden/WBV2-P65-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P66-002/manifest.json", + "report": "tests/golden/WBV2-P66-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P67-002/manifest.json", + "report": "tests/golden/WBV2-P67-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "UI_EDITOR_VIEW2D_STATE", + "task": "WBV2-P1130-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-EDITOR-VIEW2D-CUR", + "CAP-EDITOR-VIEW2D-MASK", + "CAP-EDITOR-VIEW2D-FAIL-CLOSED" + ], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "CURVE_TOPOLOGY_EDITOR", + "task": "WBV2-P1131-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-TOGGLE-CYCLIC", + "CAP-CURVE-TOPOLOGY-GATE", + "CAP-CURVE-TOPOLOGY-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/M9-05/manifest.json", + "report": "tests/golden/M9-05/curve-toggle-cyclic.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CURVE_HANDLE_GIZMO", + "task": "WBV2-P1132-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-HANDLE-MAIN", + "CAP-CURVE-HANDLE-GIZMO-PREVIEW", + "CAP-CURVE-HANDLE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CURVE_SPLINES_TRANSACTION", + "task": "WBV2-P1133-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-SPLINES-MAIN", + "CAP-CURVE-SPLINES-RECOVERY", + "CAP-CURVE-SPLINES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SURFACE_TOPOLOGY_TRANSACTION", + "task": "WBV2-P1134-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-SURFACE-TOPOLOGY-MAIN", + "CAP-SURFACE-NURBS-BOUNDS", + "CAP-SURFACE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FONT_BODY_TRANSACTION", + "task": "WBV2-P1135-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-BODY-MAIN", + "CAP-FONT-BODY-RECOVERY", + "CAP-FONT-BODY-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FONT_PROPERTIES_TRANSACTION", + "task": "WBV2-P1136-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-PROPERTIES-MAIN", + "CAP-FONT-PROPERTIES-RECOVERY", + "CAP-FONT-PROPERTIES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "METABALL_ELEMENTS_TRANSACTION", + "task": "WBV2-P1137-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-METABALL-ELEMENTS-MAIN", + "CAP-METABALL-ELEMENTS-RECOVERY", + "CAP-METABALL-ELEMENTS-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "TEXT_SOURCE_TRANSACTION", + "task": "WBV2-P1138-001", + "owner": "SCRIPTING", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXT-SOURCE-MAIN", + "CAP-TEXT-SOURCE-RECOVERY", + "CAP-TEXT-SOURCE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1137-001/manifest.json", + "report": "tests/golden/WBV2-P1137-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "TEXTURE_PROPERTIES_TRANSACTION", + "task": "WBV2-P1139-001", + "owner": "TEXTURE", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXTURE-PROPERTIES-MAIN", + "CAP-TEXTURE-PROPERTIES-RECOVERY", + "CAP-TEXTURE-PROPERTIES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1138-001/manifest.json", + "report": "tests/golden/WBV2-P1138-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ACTION_GROUP_READER", + "task": "WBV2-P1140-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-GROUP-READER", + "CAP-ACTION-GROUP-RECOVERY", + "CAP-ACTION-GROUP-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1112-000/manifest.json", + "report": "tests/golden/WBV2-P1112-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ACTION_POSE_MARKERS_READER", + "task": "WBV2-P1141-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-POSE-MARKERS-READER", + "CAP-ACTION-POSE-MARKERS-RECOVERY", + "CAP-ACTION-POSE-MARKERS-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1140-001/manifest.json", + "report": "tests/golden/WBV2-P1140-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FCURVE_SAMPLE_READER", + "task": "WBV2-P1142-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-SAMPLE-READER", + "CAP-FCURVE-SAMPLE-RECOVERY", + "CAP-FCURVE-SAMPLE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1141-001/manifest.json", + "report": "tests/golden/WBV2-P1141-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FCURVE_MODIFIER_READER", + "task": "WBV2-P1143-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-MODIFIER-READER", + "CAP-FCURVE-MODIFIER-RECOVERY", + "CAP-FCURVE-MODIFIER-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1142-001/manifest.json", + "report": "tests/golden/WBV2-P1142-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "DRIVER_READER", + "task": "WBV2-P1144-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-DRIVER-READER", + "CAP-DRIVER-RECOVERY", + "CAP-DRIVER-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1143-001/manifest.json", + "report": "tests/golden/WBV2-P1143-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CORRECTIVE_SMOOTH_READER", + "task": "WBV2-P1145-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-CORRECTIVE-SMOOTH-READER", + "CAP-CORRECTIVE-SMOOTH-RECOVERY", + "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + "tests/files/web/modifier_corrective_smooth_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MODIFIER_READER_BATCH", + "task": "WBV2-P1146-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH-READER", + "CAP-MODIFIER_READER_BATCH-RECOVERY", + "CAP-MODIFIER_READER_BATCH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MODIFIER_READER_BATCH_TWO", + "task": "WBV2-P1147-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH_TWO-READER", + "CAP-MODIFIER_READER_BATCH_TWO-RECOVERY", + "CAP-MODIFIER_READER_BATCH_TWO-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_two_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + } + ], + "tasks": [ + { + "id": "WBV2-P1096-000", + "phase": "1096", + "title": "supersede_generic_continuation_queue", + "kind": "bridge", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1095-003" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "bridge", + "gate": "QUEUE", + "card": "docs/tasks/WBV2-P1096-000.md", + "behavior": "Replace the generic continuation queue with a finite module execution plan without claiming capability parity.", + "outputs": [ + "bridge manifest", + "status" + ], + "acceptance": [ + "no parity claim", + "inventory preserved", + "module plan hash-bound" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1100-000", + "phase": "1100", + "title": "reorganize_module_execution_plan", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1096-000" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-000.md", + "behavior": "Reuse completed source-backed work and activate finite module-level implementation and verification.", + "outputs": [ + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "completed receipts reused", + "generic continuation excluded", + "one module active", + "inventory preserved" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1100-001", + "phase": "1100", + "title": "verify_render_light_camera_module", + "kind": "module", + "owner": "RENDER", + "dependsOn": [ + "WBV2-P1100-000" + ], + "parityId": "RENDER_LIGHT_CAMERA", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-render_light_camera", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-001.md", + "behavior": "Complete the RENDER_LIGHT_CAMERA module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RENDER_LIGHT_CAMERA", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-LIGHT-TYPE", + "CAP-RENDER-LIGHT-AREA-SHAPE", + "CAP-RENDER-LIGHT-CONTRIBUTION-FACTORS", + "CAP-RENDER-LIGHT-SHADOW-CONTROLS", + "CAP-RENDER-LIGHT-CASCADE-CONTROLS", + "CAP-RENDER-LIGHT-AREA-SIZE-Z", + "CAP-RENDER-LIGHT-CLIP-START", + "CAP-RENDER-WORLD-LIGHTING-CONTROLS", + "CAP-RENDER-WORLD-PROBE-CONTROLS", + "CAP-RENDER-WORLD-ENVIRONMENT-STRENGTH", + "CAP-RENDER-CAMERA-DOF-FOCUS-OBJECT", + "CAP-RENDER-CAMERA-PANORAMA" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P595-002/manifest.json", + "report": "tests/golden/WBV2-P595-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P596-002/manifest.json", + "report": "tests/golden/WBV2-P596-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P597-002/manifest.json", + "report": "tests/golden/WBV2-P597-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P598-002/manifest.json", + "report": "tests/golden/WBV2-P598-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P599-002/manifest.json", + "report": "tests/golden/WBV2-P599-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P600-002/manifest.json", + "report": "tests/golden/WBV2-P600-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P601-002/manifest.json", + "report": "tests/golden/WBV2-P601-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P602-002/manifest.json", + "report": "tests/golden/WBV2-P602-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P603-002/manifest.json", + "report": "tests/golden/WBV2-P603-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P604-002/manifest.json", + "report": "tests/golden/WBV2-P604-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P605-002/manifest.json", + "report": "tests/golden/WBV2-P605-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P606-002/manifest.json", + "report": "tests/golden/WBV2-P606-002/implementation-report.json" + } + ], + "positive": [ + "setLightProperties", + "setWorldProperties", + "setCameraProperties", + "camera panorama", + "world environment", + "light shadow/cascade" + ], + "negative": [ + "invalid enum", + "invalid numeric bounds", + "near/far conflict", + "unknown target", + "stale revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker disposal" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:lighting-field-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-lighting-fields-production.spec.ts tests/e2e/lighting-field-roundtrip.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1100-002", + "phase": "1100", + "title": "verify_scene_object_mesh_module", + "kind": "module", + "owner": "SCENE_MESH", + "dependsOn": [ + "WBV2-P1100-001" + ], + "parityId": "SCENE_OBJECT_MESH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-scene_object_mesh", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-002.md", + "behavior": "Complete the SCENE_OBJECT_MESH module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCENE_OBJECT_MESH", + "sourceBacked": true, + "capabilities": [ + "CAP-MESH-TOPOLOGY-FAMILY", + "CAP-CORE-SCENE-OBJECT", + "CAP-OBJECT-MOVE-COLLECTION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-001/manifest.json", + "report": "tests/golden/WBV2-P11-001/mesh-topology-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P12-002/manifest.json", + "report": "tests/golden/WBV2-P12-002/scene-object-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P24-002/manifest.json", + "report": "tests/golden/WBV2-P24-002/object-move-receipt-report.json" + } + ], + "positive": [ + "mesh topology", + "visibility", + "transform", + "collection membership" + ], + "negative": [ + "invalid selection", + "stale revision", + "linked data" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-mesh-topology-production.spec.ts tests/e2e/wbv2-scene-object-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1100-003", + "phase": "1100", + "title": "verify_material_animation_module", + "kind": "module", + "owner": "MATERIAL_ANIMATION", + "dependsOn": [ + "WBV2-P1100-002" + ], + "parityId": "MATERIAL_ANIMATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-material_animation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-003.md", + "behavior": "Complete the MATERIAL_ANIMATION module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MATERIAL_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-MATERIAL-ANIMATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-003/manifest.json", + "report": "tests/golden/WBV2-P12-003/material-animation-receipt-report.json" + } + ], + "positive": [ + "principled material", + "image node", + "keyframe", + "FCurve" + ], + "negative": [ + "unsupported graph", + "stale revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-material-animation-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-000", + "phase": "1101", + "title": "verify_nonmesh_geometry_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1100-003" + ], + "parityId": "NONMESH_GEOMETRY", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nonmesh_geometry", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-000.md", + "behavior": "Complete the NONMESH_GEOMETRY module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NONMESH_GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-VIEWPORT-NONMESH", + "CAP-NATIVE-DATABLOCK" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "positive": [ + "curve", + "surface", + "font", + "volume", + "metaball", + "grease pencil" + ], + "negative": [ + "unsupported data", + "resource missing", + "malformed geometry" + ], + "recovery": [ + "save/reopen", + "resource disposal" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-viewport-nonmesh-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-001", + "phase": "1101", + "title": "verify_nodes_simulation_module", + "kind": "module", + "owner": "NODES_SIMULATION", + "dependsOn": [ + "WBV2-P1101-000" + ], + "parityId": "NODES_SIMULATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nodes_simulation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-001.md", + "behavior": "Complete the NODES_SIMULATION module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NODES_SIMULATION", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES", + "CAP-SIMULATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "allowlisted node graph", + "physics manifest", + "stable hash" + ], + "negative": [ + "unsupported node", + "budget exceeded", + "stale revision" + ], + "recovery": [ + "save/reopen", + "cache disposal" + ], + "commands": [ + "npm --prefix web run test:geometry-node-main-reader", + "npm --prefix web run test:physics-main-reader" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-002", + "phase": "1101", + "title": "verify_asset_io_module", + "kind": "module", + "owner": "ASSET", + "dependsOn": [ + "WBV2-P1101-001" + ], + "parityId": "ASSET_IO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-asset_io", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-002.md", + "behavior": "Complete the ASSET_IO module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ASSET_IO", + "sourceBacked": true, + "capabilities": [ + "CAP-ASSET-LINK-OVERRIDE-RELOAD", + "CAP-ASSET-CATALOG-MUTATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P10-003/manifest.json", + "report": "tests/golden/WBV2-P10-003/module-matrix-receipt-report.json" + } + ], + "positive": [ + "append", + "link", + "override", + "reload", + "asset catalog v2" + ], + "negative": [ + "missing source", + "ownership violation", + "hash drift", + "collision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "IndexedDB restart" + ], + "commands": [ + "npm --prefix web run test:asset-catalog-v2", + "npm --prefix web run test:asset-catalog-migration", + "npm --prefix web run test:asset-catalog-negatives", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-asset-link-override-production.spec.ts tests/e2e/wbv2-asset-catalog-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-003", + "phase": "1101", + "title": "verify_sculpt_paint_module", + "kind": "module", + "owner": "SCULPT_PAINT", + "dependsOn": [ + "WBV2-P1101-002" + ], + "parityId": "SCULPT_PAINT", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-sculpt_paint", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-003.md", + "behavior": "Complete the SCULPT_PAINT module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCULPT_PAINT", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-ATTRIBUTES", + "CAP-SCULPT-PAINT" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P16-002/manifest.json", + "report": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json" + } + ], + "positive": [ + "vertex colors", + "vertex weights", + "bounded sculpt stroke" + ], + "negative": [ + "mirror unverified", + "invalid patch", + "unsupported brush" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run test:paint-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1102-000", + "phase": "1102", + "title": "implement_ui_editor_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1101-003" + ], + "parityId": "UI_EDITOR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-ui_editor", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1102-000.md", + "behavior": "Complete the UI_EDITOR module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-UI-EDITOR" + ], + "sourcePaths": [ + "web/protocol/editor-workflow.ts", + "web/app/src/app/App.tsx", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [], + "positive": [ + "editor context", + "workspace", + "area/region" + ], + "negative": [ + "unsupported editor", + "invalid context" + ], + "recovery": [ + "worker restart", + "save/reopen" + ], + "commands": [ + "npm --prefix web run test:editor-main-reader", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/ui-editor-workflow-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1102-001", + "phase": "1102", + "title": "close_module_execution_gate", + "kind": "module", + "owner": "RELEASE", + "dependsOn": [ + "WBV2-P1102-000" + ], + "parityId": "INVENTORY_GATE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-inventory_gate", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1102-001.md", + "behavior": "Complete the INVENTORY_GATE module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "INVENTORY_GATE", + "sourceBacked": true, + "capabilities": [], + "sourcePaths": [ + "tests/golden/WBV2-P0-002/parity-map.json", + "tests/golden/WBV2-P1100-000/module-execution-plan.json" + ], + "reuseReceipts": [], + "positive": [ + "aggregate module receipts", + "catalog hash" + ], + "negative": [ + "missing receipt", + "hash drift", + "false completion" + ], + "recovery": [ + "re-run affected module only" + ], + "commands": [ + "node tools/web/check-wbv2-module-execution.mjs", + "npm --prefix web run build" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1103-000", + "phase": "1103", + "title": "aggregate_object_operations_module", + "kind": "module", + "owner": "OBJECT", + "dependsOn": [ + "WBV2-P1102-001" + ], + "parityId": "OBJECT_OPERATIONS", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-object_operations", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1103-000.md", + "behavior": "Aggregate the existing source-backed Object Main operations into one module and revalidate the Chromium operator matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "OBJECT_OPERATIONS", + "sourceBacked": true, + "capabilities": [ + "CAP-OBJECT-DUPLICATE", + "CAP-OBJECT-CREATE", + "CAP-OBJECT-PARENT", + "CAP-OBJECT-COLLECTION", + "CAP-OBJECT-RENAME", + "CAP-OBJECT-DELETE", + "CAP-OBJECT-TRANSFORM" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P17-002/manifest.json", + "report": "tests/golden/WBV2-P17-002/object-duplicate-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P18-002/manifest.json", + "report": "tests/golden/WBV2-P18-002/object-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P19-002/manifest.json", + "report": "tests/golden/WBV2-P19-002/object-parent-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P20-002/manifest.json", + "report": "tests/golden/WBV2-P20-002/collection-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P21-002/manifest.json", + "report": "tests/golden/WBV2-P21-002/object-rename-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P22-002/manifest.json", + "report": "tests/golden/WBV2-P22-002/object-delete-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P23-002/manifest.json", + "report": "tests/golden/WBV2-P23-002/object-transform-receipt-report.json" + } + ], + "positive": [ + "duplicate", + "create", + "parent", + "collection", + "rename", + "delete", + "transform apply" + ], + "negative": [ + "unknown object", + "invalid parent cycle", + "malformed transform" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-object-duplicate-production.spec.ts tests/e2e/wbv2-object-create-production.spec.ts tests/e2e/wbv2-object-parent-production.spec.ts tests/e2e/wbv2-collection-create-production.spec.ts tests/e2e/wbv2-object-rename-production.spec.ts tests/e2e/wbv2-object-delete-production.spec.ts tests/e2e/wbv2-object-transform-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1104-000", + "phase": "1104", + "title": "verify_compositor_sequencer_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1103-000" + ], + "parityId": "COMPOSITOR_SEQUENCER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-compositor_sequencer", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1104-000.md", + "behavior": "Verify the source-backed compositor and sequencer module through golden, unsupported-gate and media recovery cases.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main or compositor mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "COMPOSITOR_SEQUENCER", + "sourceBacked": true, + "capabilities": [ + "CAP-COMPOSITOR-NODE-GRAPH", + "CAP-COMPOSITOR-UNSUPPORTED-GATE", + "CAP-SEQUENCER-MEDIA-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/compositor.ts", + "web/protocol/sequencer.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "positive": [ + "compositor node graph", + "sequencer still-image timeline", + "media cache contract" + ], + "negative": [ + "unsupported compositor node", + "invalid sequencer strip", + "stale media revision" + ], + "recovery": [ + "worker restart", + "save/reopen", + "media cache replay", + "movie codec blocked without READY receipt" + ], + "commands": [ + "npm --prefix web run test:compositor-node-golden", + "npm --prefix web run test:compositor-unsupported-gate", + "npm --prefix web run test:sequencer-main-reader", + "node --test web/tests/unit/sequencer-media-cache.test.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/smoke.spec.ts -g \"N-021 sequencer|real Blender 5.2 sequencer\"", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1105-000", + "phase": "1105", + "title": "verify_audio_particle_module", + "kind": "module", + "owner": "AUDIO_PARTICLE", + "dependsOn": [ + "WBV2-P1104-000" + ], + "parityId": "AUDIO_PARTICLE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-audio_particle", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1105-000.md", + "behavior": "Verify Sound, Speaker and ParticleSettings mutations against authoritative Blender Main with explicit build capability gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven or a typed build capability blocker is recorded", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "AUDIO_PARTICLE", + "sourceBacked": true, + "capabilities": [ + "CAP-SOUND-PROPERTIES", + "CAP-SPEAKER-PROPERTIES", + "CAP-PARTICLE-SETTINGS" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/protocol/io-media-commands.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P33-001/manifest.json", + "report": "tests/golden/WBV2-P33-001/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P33-002/manifest.json", + "report": "tests/golden/WBV2-P33-002/implementation-report.json" + } + ], + "positive": [ + "Sound properties", + "Speaker properties", + "ParticleSettings properties" + ], + "negative": [ + "missing Main datablock", + "unsupported build feature", + "out-of-range property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker restart" + ], + "commands": [ + "cmake --build build_web_blender6 --target web_engine -- -j8", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-audio-particle-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1106-000", + "phase": "1106", + "title": "verify_rig_animation_module", + "kind": "module", + "owner": "RIG", + "dependsOn": [ + "WBV2-P1105-000" + ], + "parityId": "RIG_ANIMATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-rig_animation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1106-000.md", + "behavior": "Verify armature pose, constraints and NLA animation through the existing Blender Main primitives.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RIG_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-RIG-POSE", + "CAP-CONSTRAINTS", + "CAP-NLA-ANIMATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nla.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-003/manifest.json", + "report": "tests/golden/WBV2-P13-003/rig-pose-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "armature pose", + "constraint edit", + "NLA stack" + ], + "negative": [ + "missing bone", + "invalid constraint influence", + "stale NLA revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-rig-pose-production.spec.ts", + "npm --prefix web run test:nla-operator", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1107-000", + "phase": "1107", + "title": "verify_modifier_system_module", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1106-000" + ], + "parityId": "MODIFIER_SYSTEM", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_system", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1107-000.md", + "behavior": "Verify modifier stack visibility and bounded parameter mutation through authoritative Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_SYSTEM", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER-STATE-MUTATION", + "CAP-MODIFIER-PARAMETER-EDIT", + "CAP-MODIFIER-STACK-READER" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/modifier-graph.ts", + "web/protocol/depsgraph.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P9-002/manifest.json", + "report": "tests/golden/WBV2-P9-002/modifier-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P11-002/manifest.json", + "report": "tests/golden/WBV2-P11-002/modifier-parameter-receipt-report.json" + } + ], + "positive": [ + "modifier visibility toggle", + "bounded DECIMATE parameter mutation", + "modifier stack evaluation reader" + ], + "negative": [ + "unknown modifier UUID", + "stale mesh revision", + "out-of-range parameter" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-production.spec.ts tests/e2e/wbv2-modifier-parameter-production.spec.ts", + "npm --prefix web run test:modifier-goldens", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1108-000", + "phase": "1108", + "title": "verify_nodes_graph_module", + "kind": "module", + "owner": "NODES", + "dependsOn": [ + "WBV2-P1107-000" + ], + "parityId": "NODES_GRAPH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nodes_graph", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1108-000.md", + "behavior": "Verify Geometry Nodes graph identity, allowlisted evaluation, field budgets and unsupported graph retention.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive graph reader/evaluation evidence is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NODES_GRAPH", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES-GRAPH", + "CAP-GEOMETRY-NODES-ALLOWLIST", + "CAP-GEOMETRY-NODES-FIELD-BUDGET" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/geometry-nodes.ts", + "web/protocol/geometry-node-commands.ts", + "web/protocol/depsgraph.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "allowlisted graph identity", + "Blender depsgraph geometry evaluation", + "field materialization with exact domain cardinality" + ], + "negative": [ + "unsupported node graph", + "field budget overflow", + "stale or invalid graph command" + ], + "recovery": [ + "save/reopen", + "worker restart", + "graph retention after rejected command", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:geometry-node-evaluator-golden", + "npm --prefix web run test:geometry-node-field-budget", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1109-000", + "phase": "1109", + "title": "verify_io_format_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1108-000" + ], + "parityId": "IO_FORMAT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-io_format", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1109-000.md", + "behavior": "Verify format capability routing, runtime receipts, recovery and fail-closed file UI gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive format routing/readiness evidence is proven", + "negative and recovery cases are proven", + "Chromium and deterministic recovery receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "IO_FORMAT", + "sourceBacked": true, + "capabilities": [ + "CAP-IO-FORMAT-CAPABILITY-MATRIX", + "CAP-IO-FORMAT-RUNTIME-RECEIPTS", + "CAP-IO-FORMAT-RECOVERY", + "CAP-IO-FORMAT-UI-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/asset-library-io.ts", + "web/protocol/io-format-capability-matrix.ts", + "web/protocol/io-format-receipt-binding.ts", + "web/protocol/io-format-runtime-receipt.ts", + "web/protocol/io-format-recovery.ts", + "web/protocol/io-format-ui-gate.ts", + "web/protocol/glb-export.ts", + "web/protocol/glb-import.ts", + "web/protocol/nonmesh-export.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "GLB export readiness", + "format runtime receipt inventory", + "declared .blend import route" + ], + "negative": [ + "unverified format route", + "cancelled or OOM operation", + "unsupported file extension" + ], + "recovery": [ + "worker restart", + "small operation recovery", + "deterministic receipt replay", + "fail-closed UI route" + ], + "commands": [ + "node tools/web/check-io-format-receipt-bindings.mjs", + "node tools/web/check-io-format-runtime-receipts.mjs", + "node tools/web/check-io-format-recovery.mjs", + "node tools/web/check-io-format-ui-gate.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/io-format-recovery.spec.ts tests/e2e/io-format-ui-gate.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1110-000", + "phase": "1110", + "title": "verify_render_pipeline_module", + "kind": "module", + "owner": "RENDER", + "dependsOn": [ + "WBV2-P1109-000" + ], + "parityId": "RENDER_PIPELINE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-render_pipeline", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1110-000.md", + "behavior": "Verify render backend routing, explicit resource budgets and Blender reference comparison in Chromium.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive render/reference evidence is proven", + "negative and recovery cases are proven", + "Chromium and deterministic render receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RENDER_PIPELINE", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-BACKEND-ROUTING", + "CAP-RENDER-RESOURCE-BUDGET", + "CAP-RENDER-REFERENCE-COMPARISON" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/render-routing.ts", + "web/protocol/render-budget.ts", + "web/protocol/render-capabilities.ts", + "web/protocol/render-image-comparison.ts", + "web/protocol/server-render-job.ts", + "web/app/src/three-adapter/render-routing.ts", + "web/app/src/three-adapter/render-image-comparison.ts", + "web/app/src/workers/viewport-render.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "bounded local backend routing", + "reference render metrics", + "resource budget acceptance" + ], + "negative": [ + "unknown or unavailable backend", + "aggregate texture/light budget overflow", + "wrong composition reference" + ], + "recovery": [ + "retain previous texture set", + "offscreen renderer parity", + "worker restart", + "deterministic second render" + ], + "commands": [ + "npm --prefix web run test:render-resource-budget", + "npm --prefix web run test:render-routing", + "npm --prefix web run test:render-reference", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1111-000", + "phase": "1111", + "title": "verify_scripting_security_module", + "kind": "module", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1110-000" + ], + "parityId": "SCRIPTING_SECURITY", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-scripting_security", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1111-000.md", + "behavior": "Verify script source Main reader, deny-by-default permission policy and sandbox isolation/recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive reader and policy evidence is proven", + "negative and recovery cases are proven", + "Chromium sandbox receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCRIPTING_SECURITY", + "sourceBacked": true, + "capabilities": [ + "CAP-SCRIPT-MAIN-READER", + "CAP-SCRIPT-PERMISSION-POLICY", + "CAP-SCRIPT-SANDBOX-ISOLATION", + "CAP-SCRIPT-SANDBOX-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/scripting-platform.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/workers/script-permission-policy-test.worker.ts", + "web/app/src/workers/script-sandbox-isolation-test.worker.ts", + "web/app/src/workers/script-sandbox-recovery-test.worker.ts", + "web/app/src/testing/script-sandbox-recovery.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "script source inventory reader", + "explicit READ_MAIN permission", + "new-generation recovery audit" + ], + "negative": [ + "autorun denied by default", + "undeclared permission", + "sandbox crash/timeout/late result" + ], + "recovery": [ + "worker restart", + "sandbox generation rollover", + "continuous audit chain", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:script-main-reader", + "npm --prefix web run test:scripting-isolation", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/script-permission-policy.spec.ts tests/e2e/script-sandbox-isolation.spec.ts tests/e2e/script-sandbox-recovery.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1112-000", + "phase": "1112", + "title": "verify_animation_timeline_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1111-000" + ], + "parityId": "ANIMATION_TIMELINE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-animation_timeline", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1112-000.md", + "behavior": "Verify frame evaluation and NLA time mapping through the production Worker and Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive frame/NLA evaluation is proven", + "negative and recovery cases are proven", + "Chromium and deterministic evaluation receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ANIMATION_TIMELINE", + "sourceBacked": true, + "capabilities": [ + "CAP-FRAME-EVALUATION", + "CAP-NLA-TIME-MAPPING", + "CAP-ANIMATION-SAVE-REOPEN" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nla.ts", + "web/protocol/depsgraph.ts", + "web/protocol/scene-ir.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "frame 1/5/10 evaluation", + "NLA track and strip mapping", + "Blender depsgraph animation result" + ], + "negative": [ + "stale NLA revision", + "invalid strip topology", + "unsupported animation domain" + ], + "recovery": [ + "save/reopen", + "worker restart", + "deterministic repeated evaluation", + "preserve rejected stack" + ], + "commands": [ + "npm --prefix web run test:frame-evaluation", + "node tools/web/check-nla-evaluation-golden.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/nla-evaluation-golden.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1113-000", + "phase": "1113", + "title": "verify_shader_material_module", + "kind": "module", + "owner": "MATERIAL", + "dependsOn": [ + "WBV2-P1112-000" + ], + "parityId": "SHADER_MATERIAL", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-shader_material", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1113-000.md", + "behavior": "Verify bounded Shader graph compilation, stable compile keys and fail-closed pipeline recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Shader Main compilation is proven", + "negative and recovery cases are proven", + "Chromium and deterministic compile receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SHADER_MATERIAL", + "sourceBacked": true, + "capabilities": [ + "CAP-SHADER-GRAPH-COMPILER", + "CAP-SHADER-COMPILE-KEY", + "CAP-SHADER-FAIL-CLOSED-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/shader-graph.ts", + "web/protocol/shader-graph-commands.ts", + "web/protocol/shader-compiler.ts", + "web/protocol/render-capabilities.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "Principled/Image/Normal/Math graph compile", + "stable compile key", + "real Main shader material path" + ], + "negative": [ + "unknown shader node", + "graph cycle or duplicate link", + "unsupported renderer backend" + ], + "recovery": [ + "retain previous material after compile failure", + "worker restart", + "deterministic repeated compile", + "save/reopen material graph" + ], + "commands": [ + "npm --prefix web run test:shader-compile", + "npm --prefix web run test:shader-pipeline", + "npm --prefix web run test:shader-capability", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1114-000", + "phase": "1114", + "title": "verify_grease_pencil_module", + "kind": "module", + "owner": "DRAWING", + "dependsOn": [ + "WBV2-P1113-000" + ], + "parityId": "GREASE_PENCIL", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-grease_pencil", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1114-000.md", + "behavior": "Verify Grease Pencil layer/frame Main mutations, stable identity validation and roundtrip recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Grease Pencil Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GREASE_PENCIL", + "sourceBacked": true, + "capabilities": [ + "CAP-GREASE-PENCIL-LAYER-FRAME", + "CAP-GREASE-PENCIL-STROKE-READER", + "CAP-GREASE-PENCIL-ROUNDTRIP" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/grease-pencil.ts", + "web/protocol/grease-pencil-reorder.ts", + "web/protocol/grease-pencil-selection.ts", + "web/protocol/grease-pencil-marquee.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/grease-pencil.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "create and reorder layer", + "insert and move frame", + "stable Grease Pencil drawing reader" + ], + "negative": [ + "forged drawing identity", + "occupied frame target", + "stale layer/frame revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic layer/frame replay" + ], + "commands": [ + "npm --prefix web run test:grease-pencil-reorder", + "npm --prefix web run test:grease-pencil", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1115-000", + "phase": "1115", + "title": "verify_curve_surface_editing_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1114-000" + ], + "parityId": "CURVE_SURFACE_EDITING", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_surface_editing", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1115-000.md", + "behavior": "Verify Curve topology/handle edits, Surface topology and non-mesh/font roundtrip through Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive non-mesh Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_SURFACE_EDITING", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-HANDLES", + "CAP-SURFACE-TOPOLOGY", + "CAP-NONMESH-FONT-ROUNDTRIP" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nonmesh-geometry-commands.ts", + "web/protocol/curve-topology-editor.ts", + "web/protocol/non-mesh.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + } + ], + "positive": [ + "Curve control point and handle edit", + "Curve cyclic/topology operator", + "Surface and Font property mutation" + ], + "negative": [ + "invalid curve selection/domain", + "occupied or stale frame/topology target", + "malformed non-mesh property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic multispline replay" + ], + "commands": [ + "npm --prefix web run test:curve-topology-operator", + "npm --prefix web run test:nonmesh-roundtrip", + "npm --prefix web run test:nonmesh-desktop-golden", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1116-000", + "phase": "1116", + "title": "verify_storage_recovery_module", + "kind": "module", + "owner": "STORAGE", + "dependsOn": [ + "WBV2-P1115-000" + ], + "parityId": "STORAGE_RECOVERY", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-storage_recovery", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1116-000.md", + "behavior": "Verify IndexedDB catalog migration/restart and OPFS asset preview deduplication, quarantine and reference GC.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive storage commit/recovery evidence is proven", + "negative and quarantine cases are proven", + "Chromium restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "STORAGE_RECOVERY", + "sourceBacked": true, + "capabilities": [ + "CAP-INDEXEDDB-CATALOG-MIGRATION", + "CAP-OPFS-PREVIEW-COMMIT", + "CAP-OPFS-QUARANTINE-GC" + ], + "sourcePaths": [ + "web/protocol/storage.ts", + "web/protocol/storage-budget.ts", + "web/protocol/save-transaction.ts", + "web/protocol/recent-projects.ts", + "web/protocol/asset-preview.ts", + "web/protocol/asset-preview-decode.ts", + "web/app/src/storage/asset-catalog-indexeddb.ts", + "web/app/src/storage/asset-preview-opfs-commit.ts", + "web/app/src/storage/asset-preview-quarantine.ts", + "web/app/src/storage/asset-preview-reference-gc.ts", + "web/app/src/storage/opfs-files.ts", + "web/app/src/storage/migrations.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "v1 to v2 catalog migration", + "page/Worker restart identity", + "content-addressed preview deduplication" + ], + "negative": [ + "partial catalog migration", + "corrupt preview quarantine", + "cross-project or non-final reference GC" + ], + "recovery": [ + "IndexedDB restart", + "OPFS commit replay", + "quarantine cleanup", + "deterministic reference reclamation" + ], + "commands": [ + "npm --prefix web run test:asset-catalog-restart", + "npm --prefix web run test:asset-preview-dedup", + "npm --prefix web run test:asset-preview-quarantine", + "npm --prefix web run test:asset-preview-reference-gc", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1117-000", + "phase": "1117", + "title": "verify_simulation_cache_module", + "kind": "module", + "owner": "SIMULATION", + "dependsOn": [ + "WBV2-P1116-000" + ], + "parityId": "SIMULATION_CACHE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-simulation_cache", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1117-000.md", + "behavior": "Verify simulation cache identity, physics-family payload integrity, lifecycle recovery and deterministic LRU pruning.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive cache identity/lifecycle evidence is proven", + "negative integrity and budget cases are proven", + "Chromium restart and quarantine receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SIMULATION_CACHE", + "sourceBacked": true, + "capabilities": [ + "CAP-SIMULATION-CACHE-IDENTITY", + "CAP-PHYSICS-CACHE-INTEGRITY", + "CAP-SIMULATION-CACHE-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/simulation-cache.ts", + "web/protocol/physics-simulation.ts", + "web/protocol/physics-cache-playback.ts", + "web/protocol/storage.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "graph/source/revision cache identity", + "all physics-family frame hashes", + "verified playback lifecycle" + ], + "negative": [ + "source or payload hash drift", + "revision/range mismatch", + "cache byte/frame budget overflow" + ], + "recovery": [ + "cancel and cleanup", + "LRU prune with protected playback", + "corruption quarantine", + "worker restart" + ], + "commands": [ + "npm --prefix web run test:simulation-cache-identity", + "npm --prefix web run test:simulation-cache-lifecycle", + "npm --prefix web run test:physics-cache-family", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1118-000", + "phase": "1118", + "title": "verify_ui_input_interaction_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1117-000" + ], + "parityId": "UI_INPUT_INTERACTION", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-ui_input_interaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1118-000.md", + "behavior": "Verify keyboard-only user actions, input mutex, IME/pointer state and responsive editor interaction under deployment CSP.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive keyboard Main mutation and save are proven", + "negative mutex/input cases are proven", + "Chromium accessibility and responsive receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_INPUT_INTERACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-KEYBOARD-USER-ACTIONS", + "CAP-INPUT-MODAL-STATE", + "CAP-IME-SHORTCUT-GUARD", + "CAP-RESPONSIVE-CSP-UI" + ], + "sourcePaths": [ + "web/app/index.html", + "web/app/src/app/App.tsx", + "web/app/src/app/app-shell.css", + "web/app/src/workers/web-engine.worker.ts", + "web/protocol/user-action-state.ts", + "web/protocol/project-action-mutex.ts", + "web/protocol/ime-composition.ts", + "web/protocol/input-modal.ts", + "web/protocol/pointer-contract.ts", + "web/protocol/worker-fault.ts", + "web/tests/unit/user-action-state.test.mjs", + "web/tests/unit/project-action-mutex.test.mjs", + "web/tests/unit/ime-composition.test.mjs", + "web/tests/unit/input-modal.test.mjs", + "web/tests/unit/pointer-contract.test.mjs" + ], + "reuseReceipts": [], + "positive": [ + "keyboard-only Add Cube Main mutation", + "keyboard save/reopen and GLB export", + "responsive controls at desktop/mobile viewports" + ], + "negative": [ + "concurrent project action mutex", + "IME shortcut suppression", + "pointer cancel/touch modal cleanup" + ], + "recovery": [ + "worker restart", + "save interruption recovery", + "responsive layout preservation", + "deterministic repeated keyboard loop" + ], + "commands": [ + "node --test web/tests/unit/user-action-state.test.mjs web/tests/unit/project-action-mutex.test.mjs web/tests/unit/ime-composition.test.mjs web/tests/unit/input-modal.test.mjs web/tests/unit/pointer-contract.test.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/user-action-state.spec.ts tests/e2e/project-action-mutex.spec.ts tests/e2e/keyboard-accessibility.spec.ts tests/e2e/responsive-layout.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1119-000", + "phase": "1119", + "title": "verify_library_workflow_module", + "kind": "module", + "owner": "ASSET", + "dependsOn": [ + "WBV2-P1118-000" + ], + "parityId": "LIBRARY_WORKFLOW", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-library_workflow", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1119-000.md", + "behavior": "Verify append, link, override and reload library flows through authoritative Main with path and dependency safety gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive library Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "LIBRARY_WORKFLOW", + "sourceBacked": true, + "capabilities": [ + "CAP-LIBRARY-APPEND", + "CAP-LIBRARY-LINK", + "CAP-LIBRARY-OVERRIDE", + "CAP-LIBRARY-RELOAD-SAFETY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/library-main-append.ts", + "web/protocol/library-linked-mutation.ts", + "web/protocol/library-linked-reload.ts", + "web/protocol/library-linked-missing.ts", + "web/protocol/library-override-writer.ts", + "web/protocol/library-override-freshness.ts", + "web/protocol/library-negative-cases.ts", + "web/protocol/library-operation-identity.ts", + "web/protocol/library-source-origin.ts", + "web/protocol/asset-path.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P9-003/manifest.json", + "report": "tests/golden/WBV2-P9-003/asset-catalog-receipt-report.json" + } + ], + "positive": [ + "append object into Main", + "linked read-only object", + "local override and reload identity" + ], + "negative": [ + "missing library source", + "dependency/cross-library cycle", + "unsafe path or ownership mutation" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic library replay" + ], + "commands": [ + "npm --prefix web run test:library-main-append", + "npm --prefix web run test:library-link-chromium", + "npm --prefix web run test:library-override-chromium", + "npm --prefix web run test:library-negative-cases", + "npm --prefix web run test:library-path-security", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1120-000", + "phase": "1120", + "title": "verify_volume_nanovdb_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1119-000" + ], + "parityId": "VOLUME_NANOVDB", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-volume_nanovdb", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1120-000.md", + "behavior": "Verify NanoVDB manifest, paged feedback, OPFS commit/restart and production viewport volume roundtrip.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive volume resource and viewport evidence is proven", + "negative and recovery cases are proven", + "Chromium OPFS/restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "VOLUME_NANOVDB", + "sourceBacked": true, + "capabilities": [ + "CAP-NANOVDB-MANIFEST", + "CAP-NANOVDB-PAGED-FEEDBACK", + "CAP-NANOVDB-OPFS-RESTART", + "CAP-NANOVDB-VIEWPORT-ROUNDTRIP" + ], + "sourcePaths": [ + "web/protocol/volume-vdb.ts", + "web/protocol/nanovdb-page-feedback.ts", + "web/protocol/nanovdb-device-recovery.ts", + "web/protocol/storage.ts", + "web/app/src/volume/nanovdb-opfs.ts", + "web/app/src/volume/nanovdb-stream.ts", + "web/app/src/volume/nanovdb-viewport.ts", + "web/app/src/volume/nanovdb-float32.ts", + "web/app/src/render/nanovdb-volume-renderer.ts", + "web/app/src/workers/vdb-opfs-test.worker.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "validated NanoVDB bundle manifest", + "content-addressed OPFS commit", + "main/offscreen production viewport volume" + ], + "negative": [ + "manifest/chunk hash mismatch", + "stale source binding", + "WebGPU/resource availability block" + ], + "recovery": [ + "OPFS Worker restart", + "paged feedback resume", + "quota/device loss cleanup", + "deterministic volume save/reopen" + ], + "commands": [ + "npm --prefix web run test:vdb-availability", + "npm --prefix web run test:vdb-native", + "npm --prefix web run test:nanovdb-page-feedback", + "npm --prefix web run test:nanovdb-opfs-restart", + "npm --prefix web run test:nanovdb-volume-roundtrip", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1121-000", + "phase": "1121", + "title": "verify_paint_stroke_module", + "kind": "module", + "owner": "SCULPT", + "dependsOn": [ + "WBV2-P1120-000" + ], + "parityId": "PAINT_STROKE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-paint_stroke", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1121-000.md", + "behavior": "Verify paint pointer sessions, depth visibility and PBVH capability gates through the production Worker.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive paint Main transaction is proven", + "negative and recovery cases are proven", + "Chromium pointer/GPU receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "PAINT_STROKE", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-POINTER-SESSION", + "CAP-PAINT-DEPTH-VISIBILITY", + "CAP-PAINT-PBVH-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/protocol/sculpt.ts", + "web/protocol/paint.ts", + "web/protocol/paint-stroke-session.ts", + "web/protocol/paint-depth-visibility.ts", + "web/protocol/paint-pbvh-capability.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/three-adapter/paint-depth-visibility.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "ordered paint pointer chunks", + "main/offscreen depth visibility", + "PBVH inventory capability query" + ], + "negative": [ + "stale/discontinuous pointer chunks", + "forged or over-budget depth samples", + "missing PBVH WASM entrypoint" + ], + "recovery": [ + "pointer cancel without Main mutation", + "undo step after paint commit", + "worker restart", + "deterministic capability replay" + ], + "commands": [ + "npm --prefix web run test:paint-stroke-session", + "npm --prefix web run test:paint-depth-visibility", + "npm --prefix web run test:paint-pbvh-capability", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1122-000", + "phase": "1122", + "title": "verify_engine_runtime_module", + "kind": "module", + "owner": "RUNTIME", + "dependsOn": [ + "WBV2-P1121-000" + ], + "parityId": "ENGINE_RUNTIME", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-engine_runtime", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1122-000.md", + "behavior": "Verify WebEngine variant manifest/selection, compiled WASM Main ABI and Worker crash recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive compiled WASM Main lifecycle is proven", + "negative variant/hash cases are proven", + "Chromium Worker restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ENGINE_RUNTIME", + "sourceBacked": true, + "capabilities": [ + "CAP-ENGINE-VARIANT-MANIFEST", + "CAP-ENGINE-WASM-MAIN-ABI", + "CAP-WORKER-CRASH-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_api.h", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/CMakeLists.txt", + "web/protocol/engine-variant.ts", + "web/protocol/worker-fault.ts", + "web/protocol/save-transaction.ts", + "web/app/src/engine-client/engine-variant-bootstrap.ts", + "web/app/src/engine-client/browser-engine-variant-session.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "single/pthread manifest binding", + "compiled WASM Main open/save lifecycle", + "engine and storage Worker recovery" + ], + "negative": [ + "malformed variant/resource declaration", + "mixed-version/hash mismatch", + "pthread unavailable fallback" + ], + "recovery": [ + "single-thread fallback", + "Worker crash restart", + "operation-log restore", + "deterministic repeated startup" + ], + "commands": [ + "npm --prefix web run test:engine-manifest-v2", + "npm --prefix web run test:engine-variant-selection", + "npm --prefix web run test:engine-variant-fallback", + "npm --prefix web run test:engine-variant-install", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-native-engine-production.spec.ts tests/e2e/worker-crash-recovery.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1123-000", + "phase": "1123", + "title": "repair_glb_roundtrip_dependency_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1122-000" + ], + "parityId": "GLB_ROUNDTRIP_REPAIR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-glb_roundtrip_repair", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1123-000.md", + "behavior": "Repair the standalone GLB checker dependency chain and verify mesh/non-mesh Blender roundtrip plus Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive GLB and non-mesh roundtrip are proven", + "negative and recovery cases are proven", + "Chromium save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GLB_ROUNDTRIP_REPAIR", + "sourceBacked": true, + "capabilities": [ + "CAP-GLB-MESH-ROUNDTRIP", + "CAP-GLB-NONMESH-ROUNDTRIP", + "CAP-GLB-CHROMIUM-RECOVERY" + ], + "sourcePaths": [ + "tools/web/check-glb-blender-roundtrip.mjs", + "tools/web/check-nonmesh-glb-blender-roundtrip.mjs", + "tools/web/blender-check-glb-roundtrip.py", + "web/protocol/glb-export.ts", + "web/protocol/glb-import.ts", + "web/protocol/nonmesh-export.ts", + "web/protocol/nonmesh-binary.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "mesh/material/skin/animation GLB roundtrip", + "Curve/Surface/Font/Metaball non-mesh mapping", + "desktop GLB Main persistence in Chromium" + ], + "negative": [ + "sparse or oversized GLB", + "external URI/extension rejection", + "non-mesh export loss gate" + ], + "recovery": [ + "cancel without publishing output", + "Worker restart", + "OPFS quota retains old asset", + "deterministic Blender roundtrip" + ], + "commands": [ + "npm --prefix web run test:glb-blender-roundtrip", + "npm --prefix web run test:nonmesh-glb-blender-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/glb-negative-cases.spec.ts tests/e2e/glb-recovery.spec.ts tests/e2e/glb-main-persistence.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1124-000", + "phase": "1124", + "title": "record_historical_hash_drift_module", + "kind": "module", + "owner": "PROVENANCE", + "dependsOn": [ + "WBV2-P1123-000" + ], + "parityId": "HISTORICAL_HASH_DRIFT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-historical_hash_drift", + "gate": "EVIDENCE", + "card": "docs/tasks/WBV2-P1124-000.md", + "behavior": "Record legacy M12 artifact hash drift without re-signing historical manifests or changing the immutable inventory.", + "outputs": [ + "drift report", + "module receipt", + "manifest", + "status" + ], + "acceptance": [ + "original and observed hashes are recorded", + "provenance remains BLOCKED_SOURCE_LOST where bytes cannot be restored", + "historical manifests and inventory remain unchanged", + "deterministic drift evidence is reproducible", + "no full-family parity claim" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "HISTORICAL_HASH_DRIFT", + "sourceBacked": true, + "capabilities": [ + "CAP-HISTORICAL-HASH-AUDIT", + "CAP-PROVENANCE-SOURCE-LOST-GATE" + ], + "sourcePaths": [ + "tools/web/check-m12-manifest-drift.mjs", + "tests/golden/corrective/rehydration/M12-manifest-sha-drift.json", + "tests/golden/WBV2-P0-002/parity-map.json" + ], + "reuseReceipts": [], + "positive": [ + "84 drift entries captured", + "43 affected artifact paths indexed", + "immutable inventory binding preserved" + ], + "negative": [ + "missing original bytes", + "attempted historical re-signing", + "inventory mutation" + ], + "recovery": [ + "deterministic report rerun", + "source cache can restore original bytes later", + "new capability manifests reference drift evidence only" + ], + "commands": [ + "node tools/web/check-m12-manifest-drift.mjs --write", + "node tools/web/check-m12-manifest-drift.mjs", + "node tools/web/check-wbv2-module-execution.mjs" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1125-000", + "phase": "1125", + "title": "repair_geometry_nodes_allowlist_module", + "kind": "module", + "owner": "NODES", + "dependsOn": [ + "WBV2-P1124-000" + ], + "parityId": "GEOMETRY_NODES_ALLOWLIST_REPAIR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-geometry_nodes_allowlist_repair", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1125-000.md", + "behavior": "Persist Geometry Nodes graph overrides in Web-safe Main storage and align allowlist assertions with real materialization behavior.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "supported graph Main materialization is proven", + "unsupported graph remains rejected without mutation", + "save/reopen graph retention is exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GEOMETRY_NODES_ALLOWLIST_REPAIR", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES-MAIN-PERSISTENCE", + "CAP-GEOMETRY-NODES-ALLOWLIST-CONSISTENCY", + "CAP-GEOMETRY-NODES-SAVE-REOPEN" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/geometry-nodes.ts", + "web/protocol/geometry-node-commands.ts", + "web/protocol/web-engine.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/geometry-node-allowlist.spec.ts", + "web/tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "allowlisted graph materializes into Main", + "Scene IDProperty graph override persists", + "save/reopen retains graph identity/hash" + ], + "negative": [ + "unsupported simulation node", + "invalid graph schema", + "missing node/link endpoint" + ], + "recovery": [ + "rejected graph leaves baseline unchanged", + "undo/redo graph override", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "cmake --build build_web_blender6 --target web_engine -- -j8", + "npm --prefix web run test:geometry-node-allowlist", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "npm --prefix web run test:geometry-node-field-budget", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1126-000", + "phase": "1126", + "title": "verify_grease_pencil_viewport_module", + "kind": "module", + "owner": "DRAWING", + "dependsOn": [ + "WBV2-P1125-000" + ], + "parityId": "GREASE_PENCIL_VIEWPORT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-grease_pencil_viewport", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1126-000.md", + "behavior": "Verify Grease Pencil 2D/3D selection and marquee integration on both viewport backends using an isolated Chromium port.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "2D and 3D selection revisions converge", + "main-thread and Offscreen marquee are exact", + "stale/foreign selection cases remain fail-closed", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GREASE_PENCIL_VIEWPORT", + "sourceBacked": true, + "capabilities": [ + "CAP-GREASE-PENCIL-SELECTION-REVISION", + "CAP-GREASE-PENCIL-MARQUEE-MAIN", + "CAP-GREASE-PENCIL-MARQUEE-OFFSCREEN" + ], + "sourcePaths": [ + "web/protocol/grease-pencil-selection.ts", + "web/protocol/grease-pencil-marquee.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/grease-pencil.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/workers/viewport-render.worker.ts" + ], + "reuseReceipts": [], + "positive": [ + "2D canvas selection revision", + "main-thread 3D marquee selection", + "OffscreenCanvas 3D marquee selection" + ], + "negative": [ + "stale selection revision", + "foreign drawing identity", + "duplicate or forged point candidate" + ], + "recovery": [ + "selection convergence across backends", + "worker viewport restart", + "deterministic repeated marquee", + "preserve Main revision" + ], + "commands": [ + "WEB_TEST_PORT=5331 npm --prefix web run test:e2e -- --workers=1 tests/e2e/grease-pencil-selection.spec.ts tests/e2e/grease-pencil-marquee.spec.ts", + "node --test web/tests/unit/grease-pencil-selection.test.mjs web/tests/unit/grease-pencil-marquee.test.mjs", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1127-000", + "phase": "1127", + "title": "verify_tracking_mask_module", + "kind": "module", + "owner": "TRACKING", + "dependsOn": [ + "WBV2-P1126-000" + ], + "parityId": "TRACKING_MASK", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-tracking_mask", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1127-000.md", + "behavior": "Verify Mask reader, editable point raycast/marquee and tracking capability gates through Chromium.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Mask reader and interaction evidence is proven", + "negative solve/resource cases are proven", + "Chromium stable IDs and recovery receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TRACKING_MASK", + "sourceBacked": true, + "capabilities": [ + "CAP-MASK-MAIN-READER", + "CAP-MASK-POINT-RAYCAST", + "CAP-TRACKING-SOLVE-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/tracking-mask.ts", + "web/protocol/scene-ir.ts", + "web/app/src/tracking/MaskSelection.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/tests/e2e/smoke.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "Mask layers and splines reader", + "editable Mask point raycast", + "N-022 tracking marker/mask gate" + ], + "negative": [ + "foreign mask point identity", + "missing resource binding", + "camera solve unavailable" + ], + "recovery": [ + "main/offscreen marquee parity", + "worker restart", + "deterministic stable IDs", + "preserve source Main on blocked solve" + ], + "commands": [ + "npm --prefix web run test:mask-main-reader", + "WEB_TEST_PORT=5340 npm --prefix web run test:e2e -- --workers=1 tests/e2e/smoke.spec.ts -g \"N-022 tracking|real Blender 5.2 Mask\"", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1128-000", + "phase": "1128", + "title": "verify_ffmpeg_movie_codec_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1127-000" + ], + "parityId": "SEQUENCER_MOVIE_CODEC", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-sequencer_movie_codec", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1128-000.md", + "behavior": "Use a local ffmpeg.wasm Worker fallback for movie probing and proxy-frame extraction when Chromium HTML media decoding is unavailable.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and core-resource hashes are bound", + "positive MP4 probe and RGBA frame are proven", + "corrupt and source-identity cases are rejected", + "AbortSignal cancellation leaves no live Worker", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SEQUENCER_MOVIE_CODEC", + "sourceBacked": true, + "capabilities": [ + "CAP-FFMPEG-WASM-MOVIE-PROBE", + "CAP-FFMPEG-WASM-PROXY-FRAME", + "CAP-MOVIE-CODEC-RECOVERY" + ], + "sourcePaths": [ + "web/package.json", + "web/package-lock.json", + "web/protocol/sequencer.ts", + "web/app/src/sequencer/SequencerCodecProbe.ts", + "web/app/src/sequencer/FFmpegMovieProbe.ts", + "web/app/src/sequencer/ffmpeg-movie-probe.worker.ts", + "web/app/src/sequencer/SequencerMediaProxyCache.ts", + "web/app/src/vendor/ffmpeg/ffmpeg-core.js", + "web/app/src/vendor/ffmpeg/ffmpeg-core.wasm", + "web/app/public/vendor/ffmpeg/ffmpeg-core.js", + "web/app/public/vendor/ffmpeg/ffmpeg-core.wasm", + "third_party/ffmpeg.wasm/package.json", + "third_party/ffmpeg.wasm/README.md", + "web/tests/e2e/ffmpeg-movie-probe-production.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "browser decode fallback to ffmpeg.wasm", + "16x16 MP4 metadata probe", + "8x8 RGBA proxy frame extraction" + ], + "negative": [ + "corrupt movie payload", + "source SHA mismatch", + "ffmpeg runtime unavailable" + ], + "recovery": [ + "AbortSignal cancellation", + "Worker termination after response", + "cache manifest identity binding", + "deterministic repeated probe" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5342 npm --prefix web run test:e2e -- --workers=1 tests/e2e/ffmpeg-movie-probe-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1129-000", + "phase": "1129", + "title": "authorize_scene_settings_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1128-000" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1129", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1129-000.md", + "behavior": "Authorize one source-backed Core Scene Graph settings module after the terminal P1128 module epoch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1128 evidence remains hash-bound", + "existing receipts are reused", + "inventory remains immutable", + "one source-backed module is active" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ] + }, + { + "id": "WBV2-P1129-001", + "phase": "1129", + "title": "verify_scene_settings_module", + "kind": "module", + "owner": "CORE_SCENE", + "dependsOn": [ + "WBV2-P1129-000" + ], + "parityId": "CORE_SCENE_GRAPH_SETTINGS", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-core_scene_graph_settings", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1129-001.md", + "behavior": "Verify the existing Blender Main scene compositor, performance and sampling setting transactions as one aggregate module.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutations are proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CORE_SCENE_GRAPH_SETTINGS", + "sourceBacked": true, + "capabilities": [ + "CAP-SCENE-COMPOSITOR-SETTINGS", + "CAP-SCENE-PERFORMANCE-SETTINGS", + "CAP-SCENE-SAMPLING-SETTINGS" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-scene-settings-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P65-002/manifest.json", + "report": "tests/golden/WBV2-P65-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P66-002/manifest.json", + "report": "tests/golden/WBV2-P66-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P67-002/manifest.json", + "report": "tests/golden/WBV2-P67-002/implementation-report.json" + } + ], + "positive": [ + "compositor device/precision mutation", + "performance thread/persistence mutation", + "sampling filter/dither mutation" + ], + "negative": [ + "invalid sampling range", + "unknown scene target", + "malformed property set" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic scene settings snapshot" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5344 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-scene-settings-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1130-000", + "phase": "1130", + "title": "authorize_editor_view2d_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1129-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1130", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1130-000.md", + "behavior": "Authorize one source-backed UI editor View2D reader/protocol module after the P1129 scene settings module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1129 evidence remains hash-bound", + "P1102 editor workflow source remains unchanged", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1130-001", + "phase": "1130", + "title": "verify_editor_view2d_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1130-000" + ], + "parityId": "UI_EDITOR_VIEW2D_STATE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-ui_editor_view2d_state", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1130-001.md", + "behavior": "Preserve Blender Graph/Dope Sheet View2D cur and mask state through the Web editor protocol without changing the existing editor workflow parser.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive reader state is proven", + "negative no-publish and recovery are proven", + "Chromium and save/reopen compatibility are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_EDITOR_VIEW2D_STATE", + "sourceBacked": true, + "capabilities": [ + "CAP-EDITOR-VIEW2D-CUR", + "CAP-EDITOR-VIEW2D-MASK", + "CAP-EDITOR-VIEW2D-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/editor-view2d.ts", + "web/app/src/workers/editor-view2d-test.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/ui-editor-view2d-production.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "Graph main-region View2D cur retention", + "Graph main-region pixel mask retention", + "reader/protocol exact state" + ], + "negative": [ + "inverted View2D bounds", + "malformed mask range", + "missing View2D payload" + ], + "recovery": [ + "immutable base editor workflow", + "worker termination", + "deterministic repeated parse", + "save/reopen reader compatibility" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5346 npm --prefix web run test:e2e -- --workers=1 tests/e2e/ui-editor-view2d-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1131-000", + "phase": "1131", + "title": "authorize_curve_topology_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1130-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1131", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1131-000.md", + "behavior": "Authorize one source-backed Curve topology editor module after the P1130 View2D module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1130 evidence remains hash-bound", + "Curve topology source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1131-001", + "phase": "1131", + "title": "verify_curve_topology_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1131-000" + ], + "parityId": "CURVE_TOPOLOGY_EDITOR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_topology_editor", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1131-001.md", + "behavior": "Verify the Blender Curve TOGGLE_CYCLIC topology transaction through the existing Main, protocol, Worker and frontend path.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_TOPOLOGY_EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-TOGGLE-CYCLIC", + "CAP-CURVE-TOPOLOGY-GATE", + "CAP-CURVE-TOPOLOGY-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/editors/curve/curve_ops.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/curve-topology-editor.ts", + "web/app/src/workers/curve-topology-contract-test.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/curve-topology-contract.spec.ts", + "web/tests/e2e/curve-topology-operator.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "TOGGLE_CYCLIC Main mutation", + "operator gate exposes only verified capability", + "save/reopen preserves cyclic spline state" + ], + "negative": [ + "unknown curve operator", + "stale revision claim", + "selection and payload budget overflow" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic contract parse" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5347 npm --prefix web run test:e2e -- --workers=1 tests/e2e/curve-topology-contract.spec.ts tests/e2e/curve-topology-operator.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1132-000", + "phase": "1132", + "title": "authorize_curve_handle_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1131-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1132", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1132-000.md", + "behavior": "Authorize one source-backed Curve handle gizmo module after the P1131 topology module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1131 evidence remains hash-bound", + "Curve handle source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1132-001", + "phase": "1132", + "title": "verify_curve_handle_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1132-000" + ], + "parityId": "CURVE_HANDLE_GIZMO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_handle_gizmo", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1132-001.md", + "behavior": "Verify Curve handle position edits through Blender Main, protocol, Worker, renderer preview and frontend gizmo.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_HANDLE_GIZMO", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-HANDLE-MAIN", + "CAP-CURVE-HANDLE-GIZMO-PREVIEW", + "CAP-CURVE-HANDLE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/nonmesh-interaction.ts", + "web/app/src/workers/nonmesh-interaction-test.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/nonmesh.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/tests/e2e/wbv2-curve-handle-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Curve handle position Main mutation", + "local handle gizmo preview", + "save/reopen preserves handle state" + ], + "negative": [ + "invalid handle identity", + "stale base revision", + "malformed handle position" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic preview" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5348 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-curve-handle-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1133-000", + "phase": "1133", + "title": "authorize_curve_splines_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1132-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1133", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1133-000.md", + "behavior": "Authorize one source-backed Curve spline transaction module after the P1132 handle module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1132 evidence remains hash-bound", + "Curve spline source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1133-001", + "phase": "1133", + "title": "verify_curve_splines_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1133-000" + ], + "parityId": "CURVE_SPLINES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_splines_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1133-001.md", + "behavior": "Verify complete Curve spline replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_SPLINES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-SPLINES-MAIN", + "CAP-CURVE-SPLINES-RECOVERY", + "CAP-CURVE-SPLINES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/tests/e2e/wbv2-curve-splines-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "complete Curve spline Main transaction", + "POLY/BEZIER descriptor retention", + "save/reopen preserves spline state" + ], + "negative": [ + "invalid spline offsets", + "stale base revision", + "mismatched handle payload" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic binary-geometry transaction" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5349 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-curve-splines-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1134-000", + "phase": "1134", + "title": "authorize_surface_topology_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1133-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1134", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1134-000.md", + "behavior": "Authorize one source-backed Surface topology transaction module after the P1133 Curve spline module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1133 evidence remains hash-bound", + "Surface topology source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1134-001", + "phase": "1134", + "title": "verify_surface_topology_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1134-000" + ], + "parityId": "SURFACE_TOPOLOGY_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-surface_topology_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1134-001.md", + "behavior": "Verify Surface NURBS topology replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SURFACE_TOPOLOGY_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-SURFACE-TOPOLOGY-MAIN", + "CAP-SURFACE-NURBS-BOUNDS", + "CAP-SURFACE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/tests/e2e/wbv2-surface-topology-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Surface topology Main transaction", + "NURBS dimensions and weights retention", + "save/reopen preserves surface state" + ], + "negative": [ + "invalid surface dimensions", + "stale base revision", + "control grid budget mismatch" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic surface transaction" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5350 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-surface-topology-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1135-000", + "phase": "1135", + "title": "authorize_font_body_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1134-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1135", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1135-000.md", + "behavior": "Authorize one source-backed Font body transaction module after the P1134 Surface topology module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1134 evidence remains hash-bound", + "Font body source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1135-001", + "phase": "1135", + "title": "verify_font_body_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1135-000" + ], + "parityId": "FONT_BODY_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-font_body_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1135-001.md", + "behavior": "Verify Font body replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FONT_BODY_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-BODY-MAIN", + "CAP-FONT-BODY-RECOVERY", + "CAP-FONT-BODY-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-font-body-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Font body Main mutation", + "UTF-8 text retention", + "save/reopen preserves text" + ], + "negative": [ + "unknown Font data ID", + "body byte budget overflow", + "malformed body payload" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic text state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5351 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-font-body-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1136-000", + "phase": "1136", + "title": "authorize_font_properties_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1135-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1136", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1136-000.md", + "behavior": "Authorize one source-backed Font properties transaction module after the P1135 Font body module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1135 evidence remains hash-bound", + "Font property source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1136-001", + "phase": "1136", + "title": "verify_font_properties_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1136-000" + ], + "parityId": "FONT_PROPERTIES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-font_properties_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1136-001.md", + "behavior": "Verify Font property replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FONT_PROPERTIES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-PROPERTIES-MAIN", + "CAP-FONT-PROPERTIES-RECOVERY", + "CAP-FONT-PROPERTIES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-font-properties-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Font property Main mutation", + "bounded alignment/extrude fields", + "save/reopen preserves properties" + ], + "negative": [ + "unknown Font data ID", + "invalid alignment enum", + "out-of-range numeric property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic property state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5352 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-font-properties-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1137-000", + "phase": "1137", + "title": "authorize_metaball_elements_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1136-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1137", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1137-000.md", + "behavior": "Authorize one source-backed Metaball element transaction module after the P1136 Font properties module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1136 evidence remains hash-bound", + "Metaball element source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1137-001", + "phase": "1137", + "title": "verify_metaball_elements_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1137-000" + ], + "parityId": "METABALL_ELEMENTS_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-metaball_elements_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1137-001.md", + "behavior": "Verify Metaball element replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "METABALL_ELEMENTS_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-METABALL-ELEMENTS-MAIN", + "CAP-METABALL-ELEMENTS-RECOVERY", + "CAP-METABALL-ELEMENTS-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-metaball-elements-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Metaball element Main mutation", + "bounded position/radius/scale retention", + "save/reopen preserves elements" + ], + "negative": [ + "unknown Metaball data ID", + "invalid radius", + "element count topology mismatch" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic element state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-metaball-elements-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1138-000", + "phase": "1138", + "title": "authorize_text_source_module", + "kind": "enabling", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1137-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1138", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1138-000.md", + "behavior": "Authorize a source-backed Text datablock mutation after the P1137 Metaball module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1137 evidence remains hash-bound", + "ID_TXT is registered for WITH_WEB", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1138-001", + "phase": "1138", + "title": "verify_text_source_module", + "kind": "module", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1138-000" + ], + "parityId": "TEXT_SOURCE_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-text_source_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1138-001.md", + "behavior": "Verify Text source replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TEXT_SOURCE_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXT-SOURCE-MAIN", + "CAP-TEXT-SOURCE-RECOVERY", + "CAP-TEXT-SOURCE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/blenkernel/intern/idtype.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-text-source-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1137-001/manifest.json", + "report": "tests/golden/WBV2-P1137-001/module-receipt.json" + } + ], + "positive": [ + "Text source Main mutation", + "ID_TXT registration in WITH_WEB", + "save/reopen preserves source" + ], + "negative": [ + "unknown Text data ID", + "source over 1 MiB", + "linked/read-only Text" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic source state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-text-source-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1139-000", + "phase": "1139", + "title": "authorize_texture_properties_module", + "kind": "enabling", + "owner": "TEXTURE", + "dependsOn": [ + "WBV2-P1138-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1139", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1139-000.md", + "behavior": "Authorize a source-backed Texture property mutation module after P1138 Text.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1138 evidence remains hash-bound", + "ID_TE is registered for WITH_WEB", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1139-001", + "phase": "1139", + "title": "verify_texture_properties_module", + "kind": "module", + "owner": "TEXTURE", + "dependsOn": [ + "WBV2-P1139-000" + ], + "parityId": "TEXTURE_PROPERTIES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-texture_properties_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1139-001.md", + "behavior": "Verify Texture property replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TEXTURE_PROPERTIES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXTURE-PROPERTIES-MAIN", + "CAP-TEXTURE-PROPERTIES-RECOVERY", + "CAP-TEXTURE-PROPERTIES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/blenkernel/intern/idtype.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-texture-properties-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1138-001/manifest.json", + "report": "tests/golden/WBV2-P1138-001/module-receipt.json" + } + ], + "positive": [ + "Texture property Main mutation", + "ID_TE registration in WITH_WEB", + "save/reopen preserves properties" + ], + "negative": [ + "unknown Texture data ID", + "noise depth outside Blender bounds", + "non-finite numeric property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic property state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-texture-properties-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1140-000", + "phase": "1140", + "title": "authorize_action_group_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1139-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1140", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1140-000.md", + "behavior": "Authorize a source-backed ActionGroup reader and recovery module after P1139 Texture.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1139 evidence remains hash-bound", + "ActionGroup has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1140-001", + "phase": "1140", + "title": "verify_action_group_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1140-000" + ], + "parityId": "ACTION_GROUP_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-action_group_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1140-001.md", + "behavior": "Verify ActionGroup metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ACTION_GROUP_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-GROUP-READER", + "CAP-ACTION-GROUP-RECOVERY", + "CAP-ACTION-GROUP-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-action-group-reader-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1112-000/manifest.json", + "report": "tests/golden/WBV2-P1112-000/module-receipt.json" + } + ], + "positive": [ + "ActionGroup Main reader exposes group and expanded metadata", + "three grouped location F-Curves remain grouped", + "save/reopen preserves group metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing animation target is fail-closed", + "unsupported group payload is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic group state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5356 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-action-group-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1141-000", + "phase": "1141", + "title": "authorize_action_pose_markers_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1140-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1141", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1141-000.md", + "behavior": "Authorize a source-backed ActionPoseMarkers reader and recovery module after P1140.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1140 evidence remains hash-bound", + "ActionPoseMarkers has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1141-001", + "phase": "1141", + "title": "verify_action_pose_markers_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1141-000" + ], + "parityId": "ACTION_POSE_MARKERS_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-action_pose_markers_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1141-001.md", + "behavior": "Verify ActionPoseMarkers metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ACTION_POSE_MARKERS_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-POSE-MARKERS-READER", + "CAP-ACTION-POSE-MARKERS-RECOVERY", + "CAP-ACTION-POSE-MARKERS-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-action-pose-markers-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1140-001/manifest.json", + "report": "tests/golden/WBV2-P1140-001/module-receipt.json" + } + ], + "positive": [ + "ActionPoseMarkers Main reader exposes marker names and frames", + "three Blender pose markers remain ordered", + "save/reopen preserves marker metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing animation target is fail-closed", + "non-finite marker frame is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic marker state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5359 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-action-pose-markers-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1142-000", + "phase": "1142", + "title": "authorize_fcurve_sample_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1141-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1142", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1142-000.md", + "behavior": "Authorize a source-backed FCurveSample reader and recovery module after P1141.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1141 evidence remains hash-bound", + "FCurveSample has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1142-001", + "phase": "1142", + "title": "verify_fcurve_sample_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1142-000" + ], + "parityId": "FCURVE_SAMPLE_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-fcurve_sample_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1142-001.md", + "behavior": "Verify FCurveSample data through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FCURVE_SAMPLE_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-SAMPLE-READER", + "CAP-FCURVE-SAMPLE-RECOVERY", + "CAP-FCURVE-SAMPLE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-fcurve-sample-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1141-001/manifest.json", + "report": "tests/golden/WBV2-P1141-001/module-receipt.json" + } + ], + "positive": [ + "FCurveSample Main reader exposes sampled source and values", + "four native FPoint samples remain ordered", + "save/reopen preserves sampled data" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing sampled payload is fail-closed", + "non-finite sampled value is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic sampled state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5365 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-sample-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1143-000", + "phase": "1143", + "title": "authorize_fcurve_modifier_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1142-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1143", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1143-000.md", + "behavior": "Authorize a source-backed FCurve modifier reader and recovery module after P1142.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1142 evidence remains hash-bound", + "FCurveModifiers has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1143-001", + "phase": "1143", + "title": "verify_fcurve_modifier_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1143-000" + ], + "parityId": "FCURVE_MODIFIER_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-fcurve_modifier_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1143-001.md", + "behavior": "Verify FCurve modifier metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FCURVE_MODIFIER_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-MODIFIER-READER", + "CAP-FCURVE-MODIFIER-RECOVERY", + "CAP-FCURVE-MODIFIER-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-fcurve-modifier-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1142-001/manifest.json", + "report": "tests/golden/WBV2-P1142-001/module-receipt.json" + } + ], + "positive": [ + "FCurveModifiers Main reader exposes native modifier stack", + "FModifierCycles preserves type/name/flags/influence", + "save/reopen preserves modifier metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing modifier payload is fail-closed", + "unsupported modifier type is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic modifier state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5368 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-modifier-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1144-000", + "phase": "1144", + "title": "authorize_driver_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1143-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1144", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1144-000.md", + "behavior": "Authorize a source-backed Driver reader and recovery module after P1143.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1143 evidence remains hash-bound", + "Driver has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1144-001", + "phase": "1144", + "title": "verify_driver_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1144-000" + ], + "parityId": "DRIVER_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-driver_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1144-001.md", + "behavior": "Verify Driver metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "DRIVER_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-DRIVER-READER", + "CAP-DRIVER-RECOVERY", + "CAP-DRIVER-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-driver-reader-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1143-001/manifest.json", + "report": "tests/golden/WBV2-P1143-001/module-receipt.json" + } + ], + "positive": [ + "AnimData driver list is read from Blender Main", + "Driver preserves scripted expression and variables", + "save/reopen preserves driver metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing driver target is fail-closed", + "non-finite driver influence is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic driver state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-driver-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1145-000", + "phase": "1145", + "title": "authorize_corrective_smooth_reader_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1144-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1145", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1145-000.md", + "behavior": "Authorize a source-backed Corrective Smooth reader/recovery module after the Driver reader.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "Corrective Smooth has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1145-001", + "phase": "1145", + "title": "verify_corrective_smooth_reader_module", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1145-000" + ], + "parityId": "CORRECTIVE_SMOOTH_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-corrective_smooth_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1145-001.md", + "behavior": "Verify Corrective Smooth modifier type and RNA metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CORRECTIVE_SMOOTH_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-CORRECTIVE-SMOOTH-READER", + "CAP-CORRECTIVE-SMOOTH-RECOVERY", + "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + "tests/files/web/modifier_corrective_smooth_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "Corrective Smooth type is read from Blender Main", + "RNA metadata is preserved", + "save/reopen preserves modifier metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported modifier data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1146-000", + "phase": "1146", + "title": "authorize_modifier_reader_batch", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1145-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1146", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1146-000.md", + "behavior": "Authorize one shared source-backed modifier reader batch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1146-001", + "phase": "1146", + "title": "verify modifier reader batch", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1146-000" + ], + "parityId": "MODIFIER_READER_BATCH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_reader_batch", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1146-001.md", + "behavior": "Verify the MODIFIER_READER_BATCH batch through Blender Main, WASM and Chromium recovery.", + "outputs": [ + "aggregate module receipt", + "coverage bindings", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_READER_BATCH", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH-READER", + "CAP-MODIFIER_READER_BATCH-RECOVERY", + "CAP-MODIFIER_READER_BATCH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "MOD_datatransfer type is read from Blender Main", + "MOD_dynamicpaint type is read from Blender Main", + "MOD_explode type is read from Blender Main", + "MOD_fluid type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts" + ], + "fullFamilyParity": false, + "evidencePaths": [ + "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json" + ], + "coverageBindings": [ + "modifier-source:MOD_datatransfer", + "modifier-source:MOD_dynamicpaint", + "modifier-source:MOD_explode", + "modifier-source:MOD_fluid", + "rna-struct:DataTransferModifier", + "rna-struct:DynamicPaintModifier", + "rna-struct:ExplodeModifier", + "rna-struct:FluidModifier", + "rna-struct:FluidDomainSettings" + ] + } + }, + { + "id": "WBV2-P1147-000", + "phase": "1147", + "title": "authorize_modifier_reader_batch", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1146-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1147", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1147-000.md", + "behavior": "Authorize one shared source-backed modifier reader batch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1147-001", + "phase": "1147", + "title": "verify modifier reader batch two", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1147-000" + ], + "parityId": "MODIFIER_READER_BATCH_TWO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_reader_batch_two", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1147-001.md", + "behavior": "Verify the MODIFIER_READER_BATCH_TWO batch through Blender Main, WASM and Chromium recovery.", + "outputs": [ + "aggregate module receipt", + "coverage bindings", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_READER_BATCH_TWO", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH_TWO-READER", + "CAP-MODIFIER_READER_BATCH_TWO-RECOVERY", + "CAP-MODIFIER_READER_BATCH_TWO-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_two_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "MOD_laplaciandeform type is read from Blender Main", + "MOD_laplaciansmooth type is read from Blender Main", + "MOD_mask type is read from Blender Main", + "MOD_mesh_to_volume type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts" + ], + "fullFamilyParity": false, + "evidencePaths": [ + "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json" + ], + "coverageBindings": [ + "modifier-source:MOD_laplaciandeform", + "modifier-source:MOD_laplaciansmooth", + "modifier-source:MOD_mask", + "modifier-source:MOD_shrinkwrap", + "rna-struct:LaplacianDeformModifier", + "rna-struct:LaplacianSmoothModifier", + "rna-struct:MaskModifier", + "rna-struct:ShrinkwrapModifier" + ] + } + } + ] +} diff --git a/tests/golden/WBV2-P1147-000/successor-authorization-report.json b/tests/golden/WBV2-P1147-000/successor-authorization-report.json new file mode 100644 index 000000000..a3522323b --- /dev/null +++ b/tests/golden/WBV2-P1147-000/successor-authorization-report.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1147-000", + "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", + "taskClass": "QUEUE_ENABLEMENT", + "status": "PASS", + "parent": { + "task": "WBV2-P1146-001", + "manifest": "tests/golden/WBV2-P1146-001/manifest.json", + "manifestSha256": "5c95d240abbd23915c75dcf9ded02818316d821eccaf183412e72eaf27510102" + }, + "module": { + "moduleId": "MODIFIER_READER_BATCH_TWO", + "task": "WBV2-P1147-001", + "batchSize": 8, + "sourceUnits": [ + "modifier-source:MOD_laplaciandeform", + "modifier-source:MOD_laplaciansmooth", + "modifier-source:MOD_mask", + "modifier-source:MOD_mesh_to_volume", + "rna-struct:LaplacianDeformModifier", + "rna-struct:LaplacianSmoothModifier", + "rna-struct:MaskModifier", + "rna-struct:MeshToVolumeModifier" + ], + "sourceBacked": true + }, + "inventory": { + "unitCount": 3745, + "verifiedUnits": 359, + "unverifiedUnits": 3386, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "boundUnitDelta": 0 + }, + "nextTask": "WBV2-P1147-001" +} diff --git a/tests/golden/WBV2-P1147-000/task-context.json b/tests/golden/WBV2-P1147-000/task-context.json new file mode 100644 index 000000000..fe100b7f7 --- /dev/null +++ b/tests/golden/WBV2-P1147-000/task-context.json @@ -0,0 +1,177 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1147-000", + "parentTask": "WBV2-P1146-001", + "status": "done", + "goal": "授权一个共享 Blender Main/WASM/Chromium modifier reader 批次,验证 Laplacian Deform、Laplacian Smooth、Mask、Mesh to Volume 及其 RNA 元数据。", + "scope": { + "gap": "capability:MODIFIER_READER_BATCH_TWO", + "ownerFamily": "MODIFIER", + "implementationClass": "QUEUE_ONLY" + }, + "commands": [ + "node tools/web/check-task-context.mjs --task WBV2-P1147-000 --write" + ], + "inputPaths": [], + "inputSelection": { + "schemaVersion": 1, + "limits": { + "maxFiles": 12, + "evidenceBytes": 8192, + "contextRemainingBytes": 241, + "contextRemainingTokens": 59 + }, + "source": { + "bytes": 9663, + "tokens": 2417 + }, + "selected": [], + "excluded": [ + { + "path": "blender-5.2.0/source/blender/modifiers/intern/", + "bytes": 10155, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "bytes": 521651, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "bytes": 313993, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "tests/files/web/modifier_reader_batch_two_scene.blend", + "bytes": 98528, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "bytes": 3992, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1147-000/manifest.json", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + }, + { + "path": "docs/status/WBV2-P1147-000.md", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + } + ], + "totals": { + "files": 0, + "bytes": 0, + "tokens": 0 + } + }, + "exitCriteria": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "nextTask": "WBV2-P1147-001", + "sourceDocuments": { + "queue": "docs/EXECUTION_QUEUE.md", + "taskCard": "docs/tasks/WBV2-P1147-000.md", + "taskIndex": "tests/golden/WBV2/task-index.json", + "parentManifest": "tests/golden/WBV2-P1146-001/manifest.json", + "parentStatus": "docs/status/WBV2-P1146-001.md" + }, + "readPolicy": { + "required": [ + "docs/EXECUTION_QUEUE.md", + "docs/tasks/WBV2-P1147-000.md", + "tests/golden/WBV2-P1146-001/manifest.json", + "docs/status/WBV2-P1146-001.md" + ], + "machineOnly": [ + "tests/golden/WBV2/task-index.json", + "tests/golden/M15-03A/task-catalog.jsonl" + ], + "optionalByNeed": [ + "docs/WEB_BLENDER_MODELER_V1_SCOPE.md", + "任务卡列出的精确协议/生产路径", + "任务卡明确命名的长期计划小节" + ], + "forbiddenByDefault": [ + "完整 CURRENT_EXECUTION_PLAN.md", + "完整 PROJECT_STATUS_AND_NEXT_WORK.md", + "全部 docs/status/*.md", + "完整 parity/WBS 计划", + "README 历史和 test-results/" + ] + }, + "parent": { + "manifest": { + "schemaVersion": 1, + "task": "WBV2-P1146-001", + "parentTask": "WBV2-P1146-000", + "status": "done", + "nextTask": "WBV2-P1147-000", + "artifactCount": 20 + }, + "statusSummary": [ + "# WBV2-P1146-001 status", + "- task: `WBV2-P1146-001`; module: `MODIFIER_READER_BATCH`; status: `done`", + "- source hashes stable: `true`; commands passed: `4`", + "- positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt", + "- dynamic source inventory: `3745` units; verified `359`; unverified `3386`; this-segment binding delta: `9`; planning estimate `5200` (non-binding)", + "- historical 6900-entry inventory remains read-only; full-family parity: `false`", + "- nextTask: `WBV2-P1147-000`" + ] + }, + "budgets": { + "queueBytes": 4096, + "taskBytes": 1364, + "parentManifestBytes": 24576, + "parentStatusBytes": 6144, + "evidenceFiles": 12, + "evidenceBytes": 8192, + "contextTokens": 3500, + "contextEnvelopeTokens": 1024, + "taskLines": 34, + "taskTokens": 341 + }, + "size": { + "documents": [ + { + "path": "docs/EXECUTION_QUEUE.md", + "bytes": 3830, + "lines": 56, + "tokens": 958 + }, + { + "path": "docs/tasks/WBV2-P1147-000.md", + "bytes": 1364, + "lines": 34, + "tokens": 341 + }, + { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "bytes": 3947, + "lines": 2, + "tokens": 987 + }, + { + "path": "docs/status/WBV2-P1146-001.md", + "bytes": 522, + "lines": 9, + "tokens": 131 + } + ], + "sourceTokens": 2417, + "evidenceFiles": 0, + "evidenceBytes": 0, + "evidenceTokens": 0, + "totalTokens": 2417, + "reservedEnvelopeTokens": 1024, + "estimatedContextTokens": 3441, + "serializedContextTokens": 631, + "withinBudget": true + } +} diff --git a/tests/golden/WBV2-P1147-001/continuous-gates.log b/tests/golden/WBV2-P1147-001/continuous-gates.log new file mode 100644 index 000000000..66907d7b5 --- /dev/null +++ b/tests/golden/WBV2-P1147-001/continuous-gates.log @@ -0,0 +1,2 @@ +context-governance-ok task=WBV2-P1147-001 contentTokens=1972 envelopeTokens=658/1024 estimatedTokens=2996/3500 inputs=0 commands=1 +{"schemaVersion":1,"operation":"BLENDER_WEB_EXECUTION_CONTROL_PLANE","status":"BLOCKED","authority":{"executionPointer":"docs/EXECUTION_QUEUE.md","productCapabilities":"docs/BLENDER_WASM_CAPABILITY_MATRIX_TEMPLATE.json","legacyCoverage":"tests/golden/M15-03A/next-task-plan.json","historicalEvidence":"tests/golden/corrective/"},"queue":{"currentTask":"WBV2-P1147-001","parentManifest":"tests/golden/WBV2-P1147-000/manifest.json","parentTask":"WBV2-P1147-000","parentNextTask":"WBV2-P1147-001","activeCatalogTask":null,"legacyCoverageTask":"M16-GAP-00282","legacyCoverageParentManifest":"tests/golden/M16-GAP-00281/manifest.json","legacyCoverageState":"active","runnableInputs":null},"efficiency":{"legacyGapTasks":6900,"legacyCompleted":281,"legacyPending":6618,"capabilityClusters":3,"mappedLegacyGaps":9,"averageGapsPerCapability":3,"productiveLane":0,"rule":"one capability task may close multiple legacy cases; legacy cases remain regression coverage"},"dynamicInventory":{"path":"tests/golden/WBV2/dynamic-inventory.json","manifestPath":"tests/golden/WBV2/dynamic-inventory-manifest.json","sourceTreeSha256":"600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202","sourceFiles":6206,"unitCount":3745,"planningEstimate":5200,"hardTarget":false,"verifiedUnits":367,"unverifiedUnits":3378},"capabilityClusters":{"ASSET_CATALOG":{"capabilityId":"CAP-ASSET-CATALOG-MUTATION","sourceGaps":5,"parityLevel":"L0","targetParityLevel":"L4","lifecycleStatus":"planned"},"MODIFIER":{"capabilityId":"CAP-MODIFIER-STATE-MUTATION","sourceGaps":2,"parityLevel":"L0","targetParityLevel":"L3","lifecycleStatus":"planned"},"MESH":{"capabilityId":"CAP-MESH-POSITIVE-EDIT","sourceGaps":2,"parityLevel":"L0","targetParityLevel":"L3","lifecycleStatus":"planned"}},"issues":[{"code":"DYNAMIC_INVENTORY_MANIFEST_HASH_DRIFT","detail":"tests/golden/WBV2/dynamic-inventory-check-report.json"}],"remediation":["inspect the control-plane issue and preserve its evidence"],"allowUnrunnable":true,"inputDigest":"ef7843c2b380731839b33dfc71d4d81d01a75b158d59083f9367cd0bf86494e0"} diff --git a/tests/golden/WBV2-P1147-001/continuous-runner.log b/tests/golden/WBV2-P1147-001/continuous-runner.log new file mode 100644 index 000000000..5c924dc6d --- /dev/null +++ b/tests/golden/WBV2-P1147-001/continuous-runner.log @@ -0,0 +1,4 @@ +v2-task-index-generated tasks=75 active=NONE output=tests/golden/WBV2/task-index.json +task-context-ok task=WBV2-P1147-001 parent=WBV2-P1147-000 contentTokens=1972 envelopeTokens=658/1024 estimatedTokens=2996/3500 taskBytes=2313 next=NONE output=tests/golden/WBV2-P1147-001/task-context.json +wbv2-module-coverage-bound task=WBV2-P1147-001 module=MODIFIER_READER_BATCH_TWO added=8 verified=367 unverified=3378 +module-task-complete task=WBV2-P1147-001 module=MODIFIER_READER_BATCH_TWO next=null commands=4 diff --git a/tests/golden/WBV2-P1147-001/manifest.json b/tests/golden/WBV2-P1147-001/manifest.json new file mode 100644 index 000000000..375fb5199 --- /dev/null +++ b/tests/golden/WBV2-P1147-001/manifest.json @@ -0,0 +1,111 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1147-001", + "parentTask": "WBV2-P1147-000", + "operation": "MODULE_FUNCTION_EXECUTION", + "taskClass": "MODULE", + "status": "done", + "enablingTask": true, + "parityStateChange": false, + "runtime": "BLENDER_WEB_FUNCTION_MODULE", + "artifacts": { + "parentManifest": { + "path": "tests/golden/WBV2-P1147-000/manifest.json", + "sha256": "dd7cd4be22eba869cc5df37d700ac5d4a403c759ba925c269ae14fa5bf26678a" + }, + "source1": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "sha256": "d56f120e37066fe9a892ec4090fffec03e149f82c115a6ea8356330a4e8d2096" + }, + "source2": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "sha256": "aa85424124a4bc4760ffdced29d3a4b90fbd51b40861366e6b0ab864a29075ca" + }, + "source3": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "sha256": "601b7197bff84e456278c3551b5aa94c983cd69b32aa8d0b961349a68e38f736" + }, + "source4": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "sha256": "3e71b126cfd20409173f4c9b6de7430ab9ff8a8ea818a511b2e4d7c6a4ecdba7" + }, + "source5": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source6": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source7": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source8": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source9": { + "path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "sha256": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990" + }, + "source10": { + "path": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "sha256": "94eb444af368591967add4c091bcfbf7904d0d0cdf4a770239e70d35d6bdaaee" + }, + "source11": { + "path": "tests/files/web/modifier_reader_batch_two_scene.blend", + "sha256": "e3e6ebfd2c96f2a7fe794dc2f6716e0190adee816297040f65a66f6f60a45c65" + }, + "source12": { + "path": "web/app/src/vendor/blender/web_engine.wasm", + "sha256": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "evidence1": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "moduleReceipt": { + "path": "tests/golden/WBV2-P1147-001/module-receipt.json", + "sha256": "a9bd656dd25a3aa6cff8e11385dfd48d6c4adda7561df1106890d5d13b5882fe" + }, + "status": { + "path": "docs/status/WBV2-P1147-001.md", + "sha256": "31191046d3f82383da156e3e8a540e8af718c3625928670f94324e9625ca38dc" + }, + "log": { + "path": "tests/golden/WBV2-P1147-001/module-run.log", + "sha256": "f33b7fc10f005d8fe6790e3074e3b6ceb5f5e6dc7c4d0555db0845a0cceba47f" + }, + "plan": { + "path": "tests/golden/WBV2-P1147-000/module-execution-plan.json", + "sha256": "d6ac0c2f344c14b8ead86275d4e9578813312273ff04b790fcd240815006481c" + }, + "taskContext": { + "path": "tests/golden/WBV2-P1147-001/task-context.json", + "sha256": "2052f931c85b574e0223997f8a493e731411a8497337b28bfcaaf0c2544c1a28" + } + }, + "assertions": { + "moduleId": "MODIFIER_READER_BATCH_TWO", + "sourceBacked": true, + "positiveCases": 6, + "negativeCases": 3, + "recoveryCases": 3, + "commandCount": 4, + "reusedReceiptCount": 1, + "sourceUnchanged": true, + "fullFamilyParity": false, + "dynamicInventoryPath": "tests/golden/WBV2/dynamic-inventory.json", + "dynamicSourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "dynamicUnitCount": 3745, + "dynamicVerifiedUnits": 359, + "dynamicUnverifiedUnits": 3386, + "planningEstimate": 5200, + "historicalInventoryTotal": 6900, + "historicalEffectiveCompleted": 290, + "historicalEffectivePending": 6609, + "historicalReproduction": false + }, + "nextTask": "WBV2-P1148-000" +} diff --git a/tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json b/tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json new file mode 100644 index 000000000..e55e651ec --- /dev/null +++ b/tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json @@ -0,0 +1,224 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-001", + "operation": "MODIFIER_READER_BATCH_TWO_CHROMIUM_SAVE_REOPEN", + "browser": "chromium", + "queueMutation": false, + "fixture": "tests/files/web/modifier_reader_batch_three_scene.blend", + "fixtureSha256": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739", + "expectedTypes": [ + "REMESH", + "SKIN", + "WEIGHTED_NORMAL", + "WARP" + ], + "sourceUnits": [ + "modifier-source:MOD_remesh", + "modifier-source:MOD_skin", + "modifier-source:MOD_weighted_normal", + "modifier-source:MOD_warp", + "rna-struct:RemeshModifier", + "rna-struct:SkinModifier", + "rna-struct:WeightedNormalModifier", + "rna-struct:WarpModifier" + ], + "before": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1879751496", + "name": "Remesh", + "type": "REMESH", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1879751496, + "typeCode": 41 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1853982967", + "name": "Skin", + "type": "SKIN", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "branchSmoothing": 0, + "flag": 1, + "mode": 7, + "persistentUid": 1853982967, + "skinFlags": 0, + "symmetryAxes": 1, + "typeCode": 42 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1800999687", + "name": "Weighted Normal", + "type": "WEIGHTED_NORMAL", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "flag": 1, + "mode": 7, + "persistentUid": 1800999687, + "typeCode": 54, + "weight": 50 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:614917079", + "name": "Warp", + "type": "WARP", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 614917079, + "typeCode": 35 + } + } + ], + "types": [ + "REMESH", + "SKIN", + "WEIGHTED_NORMAL", + "WARP" + ], + "after": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1879751496", + "name": "Remesh", + "type": "REMESH", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1879751496, + "typeCode": 41 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1853982967", + "name": "Skin", + "type": "SKIN", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "branchSmoothing": 0, + "flag": 1, + "mode": 7, + "persistentUid": 1853982967, + "skinFlags": 0, + "symmetryAxes": 1, + "typeCode": 42 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1800999687", + "name": "Weighted Normal", + "type": "WEIGHTED_NORMAL", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "flag": 1, + "mode": 7, + "persistentUid": 1800999687, + "typeCode": 54, + "weight": 50 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:614917079", + "name": "Warp", + "type": "WARP", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 614917079, + "typeCode": 35 + } + } + ], + "second": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1879751496", + "name": "Remesh", + "type": "REMESH", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1879751496, + "typeCode": 41 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1853982967", + "name": "Skin", + "type": "SKIN", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "branchSmoothing": 0, + "flag": 1, + "mode": 7, + "persistentUid": 1853982967, + "skinFlags": 0, + "symmetryAxes": 1, + "typeCode": 42 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1800999687", + "name": "Weighted Normal", + "type": "WEIGHTED_NORMAL", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "flag": 1, + "mode": 7, + "persistentUid": 1800999687, + "typeCode": 54, + "weight": 50 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:614917079", + "name": "Warp", + "type": "WARP", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 614917079, + "typeCode": 35 + } + } + ], + "saveReopenExact": true, + "deterministicExact": true, + "savedSha256": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739", + "malformed": { + "code": "BLEND_READ_FAILED", + "message": "Input is not an uncompressed, gzip, or zstd Blender file" + } +} diff --git a/tests/golden/WBV2-P1147-001/module-receipt.json b/tests/golden/WBV2-P1147-001/module-receipt.json new file mode 100644 index 000000000..fc372e3b2 --- /dev/null +++ b/tests/golden/WBV2-P1147-001/module-receipt.json @@ -0,0 +1,128 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1147-001", + "operation": "MODULE_FUNCTION_EXECUTION", + "moduleId": "MODIFIER_READER_BATCH_TWO", + "status": "PASS", + "source": { + "paths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_two_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "before": { + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc": "d56f120e37066fe9a892ec4090fffec03e149f82c115a6ea8356330a4e8d2096", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc": "aa85424124a4bc4760ffdced29d3a4b90fbd51b40861366e6b0ab864a29075ca", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc": "601b7197bff84e456278c3551b5aa94c983cd69b32aa8d0b961349a68e38f736", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc": "3e71b126cfd20409173f4c9b6de7430ab9ff8a8ea818a511b2e4d7c6a4ecdba7", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts": "94eb444af368591967add4c091bcfbf7904d0d0cdf4a770239e70d35d6bdaaee", + "tests/files/web/modifier_reader_batch_two_scene.blend": "e3e6ebfd2c96f2a7fe794dc2f6716e0190adee816297040f65a66f6f60a45c65", + "web/app/src/vendor/blender/web_engine.wasm": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "after": { + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc": "d56f120e37066fe9a892ec4090fffec03e149f82c115a6ea8356330a4e8d2096", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc": "aa85424124a4bc4760ffdced29d3a4b90fbd51b40861366e6b0ab864a29075ca", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc": "601b7197bff84e456278c3551b5aa94c983cd69b32aa8d0b961349a68e38f736", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc": "3e71b126cfd20409173f4c9b6de7430ab9ff8a8ea818a511b2e4d7c6a4ecdba7", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts": "94eb444af368591967add4c091bcfbf7904d0d0cdf4a770239e70d35d6bdaaee", + "tests/files/web/modifier_reader_batch_two_scene.blend": "e3e6ebfd2c96f2a7fe794dc2f6716e0190adee816297040f65a66f6f60a45c65", + "web/app/src/vendor/blender/web_engine.wasm": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "unchanged": true + }, + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json", + "manifestSha256": "a53ebdc52db5dcf27d44e938e5551f1ee2adae8e46c3fe8661604ee6b1000f8c", + "reportSha256": "6dd419799e1a4b9251328d9496f2459d148cd89118740a06b0ee6ffb78e0b1d2" + } + ], + "cases": { + "positive": [ + "MOD_laplaciandeform type is read from Blender Main", + "MOD_laplaciansmooth type is read from Blender Main", + "MOD_mask type is read from Blender Main", + "MOD_mesh_to_volume type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ] + }, + "commands": [ + { + "command": "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "exitCode": 0 + }, + { + "command": "npm --prefix web run typecheck", + "exitCode": 0 + }, + { + "command": "npm --prefix web run build", + "exitCode": 0 + }, + { + "command": "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "exitCode": 0 + } + ], + "verification": { + "required": [ + "sourceHash", + "wasmBuild", + "positiveMainMutation", + "negativeNoMutation", + "undoRedo", + "saveReopen", + "aggregateManifest" + ], + "chromiumOnly": true, + "fullFamilyParity": false + }, + "inventory": { + "historical": { + "path": "tests/golden/WBV2-P0-002/parity-map.json", + "sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8", + "total": 6900, + "legacyCompleted": 281, + "legacyPending": 6618, + "effectiveCompleted": 290, + "effectivePending": 6609, + "mutation": "forbidden_by_module_execution" + }, + "dynamic": { + "path": "tests/golden/WBV2/dynamic-inventory.json", + "sha256": "655584256c51e0934af705e9bccec92b64b55df1ce480a08f8a98afbb17e552a", + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "unitCount": 3745, + "planningEstimate": 5200, + "hardTarget": false, + "verifiedUnits": 359, + "unverifiedUnits": 3386 + } + }, + "nextTask": null +} diff --git a/tests/golden/WBV2-P1147-001/module-run.log b/tests/golden/WBV2-P1147-001/module-run.log new file mode 100644 index 000000000..2209a1244 --- /dev/null +++ b/tests/golden/WBV2-P1147-001/module-run.log @@ -0,0 +1,49 @@ +> source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm +ninja: no work to do. + +> npm --prefix web run typecheck + +> blender-web-editor@0.1.0-rc.1 typecheck +> tsc -p tsconfig.json --noEmit + + +> npm --prefix web run build + +> blender-web-editor@0.1.0-rc.1 build +> tsc -p tsconfig.json && vite build --config app/vite.config.ts + +vite v8.2.0 building client environment for production... + transforming...✓ 102 modules transformed. +rendering chunks... +computing gzip size... +dist/index.html 0.46 kB │ gzip: 0.30 kB +dist/assets/storage.worker-D9TqXsGS.js 66.59 kB +dist/assets/web-engine.worker-BfTMiTY1.js 362.11 kB +dist/assets/viewport-render.worker-BKnJyAEz.js 634.08 kB +dist/assets/web_engine-CjnzAIfx.wasm 16,238.37 kB │ gzip: 3,856.73 kB +dist/assets/index-BgTbQCE2.css 15.35 kB │ gzip: 3.91 kB +dist/assets/index-C3AJuKSc.js 1,190.30 kB │ gzip: 316.69 kB + +✓ built in 454ms +[plugin rolldown:vite-resolve] Module "module" has been externalized for browser compatibility, imported by "/home/mes123456/workinf_Blender_Wasm/web/app/src/vendor/blender/web_engine.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details. +[plugin builtin:vite-reporter] +(!) Some chunks are larger than 500 kB after minification. Consider: +- Using dynamic import() to code-split the application +- Use build.rolldownOptions.output.codeSplitting to improve chunking: https://rolldown.rs/reference/OutputOptions.codeSplitting +- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. + +> WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts + +> blender-web-editor@0.1.0-rc.1 test:e2e +> playwright test --config playwright.config.ts --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts + + +Running 1 test using 1 worker + + ✓ 1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts:12:1 › second modifier reader batch preserves concrete Blender Main metadata (1.9s) + + 1 passed (2.8s) +[WebServer] (node:41651) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +[WebServer] (Use `node --trace-warnings ...` to show where the warning was created) +(node:41705) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) diff --git a/tests/golden/WBV2-P1147-001/scheduler-child.log b/tests/golden/WBV2-P1147-001/scheduler-child.log new file mode 100644 index 000000000..e69de29bb diff --git a/tests/golden/WBV2-P1147-001/task-context.json b/tests/golden/WBV2-P1147-001/task-context.json new file mode 100644 index 000000000..e33fba4dc --- /dev/null +++ b/tests/golden/WBV2-P1147-001/task-context.json @@ -0,0 +1,187 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1147-001", + "parentTask": "WBV2-P1147-000", + "status": "in_progress", + "goal": "以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_laplaciandeform, MOD_laplaciansmooth, MOD_mask, MOD_shrinkwrap 的真实 modifier/RNA 元数据。", + "scope": { + "gap": "capability:MODIFIER_READER_BATCH_TWO", + "ownerFamily": "MODIFIER", + "implementationClass": "LOCAL_EXACT" + }, + "commands": [ + "node tools/web/check-task-context.mjs --task WBV2-P1147-001 --write" + ], + "inputPaths": [], + "inputSelection": { + "schemaVersion": 1, + "limits": { + "maxFiles": 12, + "evidenceBytes": 8192, + "contextRemainingBytes": 2024, + "contextRemainingTokens": 504 + }, + "source": { + "bytes": 7880, + "tokens": 1972 + }, + "selected": [], + "excluded": [ + { + "path": "blender-5.2.0/source/blender/modifiers/intern/", + "bytes": 10155, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "bytes": 521651, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "bytes": 313993, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "tests/files/web/modifier_reader_batch_two_scene.blend", + "bytes": 98565, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "bytes": 3982, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1147-001/module-receipt.json", + "bytes": 6352, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "bytes": 5849, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + }, + { + "path": "docs/status/WBV2-P1147-001.md", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + } + ], + "totals": { + "files": 0, + "bytes": 0, + "tokens": 0 + } + }, + "exitCriteria": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "nextTask": null, + "sourceDocuments": { + "queue": "docs/EXECUTION_QUEUE.md", + "taskCard": "docs/tasks/WBV2-P1147-001.md", + "taskIndex": "tests/golden/WBV2/task-index.json", + "parentManifest": "tests/golden/WBV2-P1147-000/manifest.json", + "parentStatus": "docs/status/WBV2-P1147-000.md" + }, + "readPolicy": { + "required": [ + "docs/EXECUTION_QUEUE.md", + "docs/tasks/WBV2-P1147-001.md", + "tests/golden/WBV2-P1147-000/manifest.json", + "docs/status/WBV2-P1147-000.md" + ], + "machineOnly": [ + "tests/golden/WBV2/task-index.json", + "tests/golden/M15-03A/task-catalog.jsonl" + ], + "optionalByNeed": [ + "docs/WEB_BLENDER_MODELER_V1_SCOPE.md", + "任务卡列出的精确协议/生产路径", + "任务卡明确命名的长期计划小节" + ], + "forbiddenByDefault": [ + "完整 CURRENT_EXECUTION_PLAN.md", + "完整 PROJECT_STATUS_AND_NEXT_WORK.md", + "全部 docs/status/*.md", + "完整 parity/WBS 计划", + "README 历史和 test-results/" + ] + }, + "parent": { + "manifest": { + "schemaVersion": 1, + "task": "WBV2-P1147-000", + "parentTask": "WBV2-P1146-001", + "status": "done", + "nextTask": "WBV2-P1147-001", + "artifactCount": 4 + }, + "statusSummary": [ + "# WBV2-P1147-000 status", + "- task: `WBV2-P1147-000`; parent: `WBV2-P1146-001`; status: `done`", + "- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed", + "- source-backed batch authorized: `MODIFIER_READER_BATCH_TWO` (8 units)", + "- dynamic inventory: `3745` units; verified `359`; unverified `3386`; bound delta `0`", + "- nextTask: `WBV2-P1147-001`" + ] + }, + "budgets": { + "queueBytes": 4096, + "taskBytes": 2313, + "parentManifestBytes": 24576, + "parentStatusBytes": 6144, + "evidenceFiles": 12, + "evidenceBytes": 8192, + "contextTokens": 3500, + "contextEnvelopeTokens": 1024, + "taskLines": 46, + "taskTokens": 579 + }, + "size": { + "documents": [ + { + "path": "docs/EXECUTION_QUEUE.md", + "bytes": 3830, + "lines": 56, + "tokens": 958 + }, + { + "path": "docs/tasks/WBV2-P1147-001.md", + "bytes": 2313, + "lines": 46, + "tokens": 579 + }, + { + "path": "tests/golden/WBV2-P1147-000/manifest.json", + "bytes": 1380, + "lines": 43, + "tokens": 345 + }, + { + "path": "docs/status/WBV2-P1147-000.md", + "bytes": 357, + "lines": 8, + "tokens": 90 + } + ], + "sourceTokens": 1972, + "evidenceFiles": 0, + "evidenceBytes": 0, + "evidenceTokens": 0, + "totalTokens": 1972, + "reservedEnvelopeTokens": 1024, + "estimatedContextTokens": 2996, + "serializedContextTokens": 658, + "withinBudget": true + } +} diff --git a/tests/golden/WBV2-P1148-000/manifest.json b/tests/golden/WBV2-P1148-000/manifest.json new file mode 100644 index 000000000..ced1fbeee --- /dev/null +++ b/tests/golden/WBV2-P1148-000/manifest.json @@ -0,0 +1,42 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-000", + "parentTask": "WBV2-P1147-001", + "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", + "status": "done", + "enablingTask": true, + "parityStateChange": false, + "runtime": "MODULE_EXECUTION_QUEUE_BRIDGE", + "artifacts": { + "parentManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "6c9d7b844434668b2614d7215e44c146f7adf081480ec71bff6d534d0df6dbce" + }, + "plan": { + "path": "tests/golden/WBV2-P1148-000/module-execution-plan.json", + "sha256": "4a0c58c01a81a4e417d55dc6c5da7ee1d6c18163b26a931c2876dafb21f5f4d2" + }, + "report": { + "path": "tests/golden/WBV2-P1148-000/successor-authorization-report.json", + "sha256": "6ce2a8d8fd598a9700b1cad03962bad40be755522d1af9221a8cf0f1287171fc" + }, + "status": { + "path": "docs/status/WBV2-P1148-000.md", + "sha256": "30c5ac22b85e9537e3c910480d070f8cd67b7b744efe13d3967a28d54857d2d4" + } + }, + "assertions": { + "sourceBackedSuccessor": true, + "moduleId": "MODIFIER_READER_BATCH_THREE", + "batchSize": 8, + "inventoryTotal": 6900, + "effectiveCompleted": 290, + "effectivePending": 6609, + "dynamicUnitCount": 3745, + "dynamicVerifiedUnits": 369, + "dynamicUnverifiedUnits": 3376, + "boundUnitDelta": 0, + "fullHistoricalReproduction": false + }, + "nextTask": "WBV2-P1148-001" +} diff --git a/tests/golden/WBV2-P1148-000/module-execution-plan.json b/tests/golden/WBV2-P1148-000/module-execution-plan.json new file mode 100644 index 000000000..d80ab41fe --- /dev/null +++ b/tests/golden/WBV2-P1148-000/module-execution-plan.json @@ -0,0 +1,6010 @@ +{ + "schemaVersion": 1, + "planId": "BLENDER_WEB_MODULE_EXECUTION_P1148", + "operation": "FUNCTION_MODULE_MIGRATION_PLAN", + "status": "COMPLETED_MODULE_EXECUTION", + "authority": "blender_main_source_and_existing_hash_bound_receipts", + "executionPointer": "docs/EXECUTION_QUEUE.md", + "inventory": { + "path": "tests/golden/WBV2-P0-002/parity-map.json", + "sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8", + "total": 6900, + "legacyCompleted": 281, + "legacyPending": 6618, + "effectiveCompleted": 290, + "effectivePending": 6609, + "mutation": "forbidden_by_module_execution" + }, + "reusePolicy": { + "completedReceipts": "reuse_without_rerun", + "continuationEvidence": "excluded", + "duplicateValidation": "forbidden", + "fullFamilyParity": "never_inferred" + }, + "verificationPolicy": { + "browser": "chromium_only", + "required": [ + "sourceHash", + "wasmBuild", + "positiveMainMutation", + "negativeNoMutation", + "undoRedo", + "saveReopen", + "aggregateManifest" + ], + "failure": "keep_module_in_progress_and_do_not_advance" + }, + "modules": [ + { + "id": "RENDER_LIGHT_CAMERA", + "task": "WBV2-P1100-001", + "owner": "RENDER", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-LIGHT-TYPE", + "CAP-RENDER-LIGHT-AREA-SHAPE", + "CAP-RENDER-LIGHT-CONTRIBUTION-FACTORS", + "CAP-RENDER-LIGHT-SHADOW-CONTROLS", + "CAP-RENDER-LIGHT-CASCADE-CONTROLS", + "CAP-RENDER-LIGHT-AREA-SIZE-Z", + "CAP-RENDER-LIGHT-CLIP-START", + "CAP-RENDER-WORLD-LIGHTING-CONTROLS", + "CAP-RENDER-WORLD-PROBE-CONTROLS", + "CAP-RENDER-WORLD-ENVIRONMENT-STRENGTH", + "CAP-RENDER-CAMERA-DOF-FOCUS-OBJECT", + "CAP-RENDER-CAMERA-PANORAMA" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P595-002/manifest.json", + "report": "tests/golden/WBV2-P595-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P596-002/manifest.json", + "report": "tests/golden/WBV2-P596-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P597-002/manifest.json", + "report": "tests/golden/WBV2-P597-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P598-002/manifest.json", + "report": "tests/golden/WBV2-P598-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P599-002/manifest.json", + "report": "tests/golden/WBV2-P599-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P600-002/manifest.json", + "report": "tests/golden/WBV2-P600-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P601-002/manifest.json", + "report": "tests/golden/WBV2-P601-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P602-002/manifest.json", + "report": "tests/golden/WBV2-P602-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P603-002/manifest.json", + "report": "tests/golden/WBV2-P603-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P604-002/manifest.json", + "report": "tests/golden/WBV2-P604-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P605-002/manifest.json", + "report": "tests/golden/WBV2-P605-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P606-002/manifest.json", + "report": "tests/golden/WBV2-P606-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SCENE_OBJECT_MESH", + "task": "WBV2-P1100-002", + "owner": "SCENE_MESH", + "sourceBacked": true, + "capabilities": [ + "CAP-MESH-TOPOLOGY-FAMILY", + "CAP-CORE-SCENE-OBJECT", + "CAP-OBJECT-MOVE-COLLECTION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-001/manifest.json", + "report": "tests/golden/WBV2-P11-001/mesh-topology-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P12-002/manifest.json", + "report": "tests/golden/WBV2-P12-002/scene-object-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P24-002/manifest.json", + "report": "tests/golden/WBV2-P24-002/object-move-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MATERIAL_ANIMATION", + "task": "WBV2-P1100-003", + "owner": "MATERIAL_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-MATERIAL-ANIMATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-003/manifest.json", + "report": "tests/golden/WBV2-P12-003/material-animation-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "NONMESH_GEOMETRY", + "task": "WBV2-P1101-000", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-VIEWPORT-NONMESH", + "CAP-NATIVE-DATABLOCK" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "NODES_SIMULATION", + "task": "WBV2-P1101-001", + "owner": "NODES_SIMULATION", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES", + "CAP-SIMULATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ASSET_IO", + "task": "WBV2-P1101-002", + "owner": "ASSET", + "sourceBacked": true, + "capabilities": [ + "CAP-ASSET-LINK-OVERRIDE-RELOAD", + "CAP-ASSET-CATALOG-MUTATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P10-003/manifest.json", + "report": "tests/golden/WBV2-P10-003/module-matrix-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SCULPT_PAINT", + "task": "WBV2-P1101-003", + "owner": "SCULPT_PAINT", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-ATTRIBUTES", + "CAP-SCULPT-PAINT" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P16-002/manifest.json", + "report": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "UI_EDITOR", + "task": "WBV2-P1102-000", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-UI-EDITOR" + ], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "INVENTORY_GATE", + "task": "WBV2-P1102-001", + "owner": "RELEASE", + "sourceBacked": true, + "capabilities": [], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "OBJECT_OPERATIONS", + "task": "WBV2-P1103-000", + "owner": "OBJECT", + "sourceBacked": true, + "capabilities": [ + "CAP-OBJECT-DUPLICATE", + "CAP-OBJECT-CREATE", + "CAP-OBJECT-PARENT", + "CAP-OBJECT-COLLECTION", + "CAP-OBJECT-RENAME", + "CAP-OBJECT-DELETE", + "CAP-OBJECT-TRANSFORM" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P17-002/manifest.json", + "report": "tests/golden/WBV2-P17-002/object-duplicate-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P18-002/manifest.json", + "report": "tests/golden/WBV2-P18-002/object-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P19-002/manifest.json", + "report": "tests/golden/WBV2-P19-002/object-parent-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P20-002/manifest.json", + "report": "tests/golden/WBV2-P20-002/collection-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P21-002/manifest.json", + "report": "tests/golden/WBV2-P21-002/object-rename-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P22-002/manifest.json", + "report": "tests/golden/WBV2-P22-002/object-delete-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P23-002/manifest.json", + "report": "tests/golden/WBV2-P23-002/object-transform-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "COMPOSITOR_SEQUENCER", + "task": "WBV2-P1104-000", + "owner": "MEDIA", + "sourceBacked": true, + "capabilities": [ + "CAP-COMPOSITOR-NODE-GRAPH", + "CAP-COMPOSITOR-UNSUPPORTED-GATE", + "CAP-SEQUENCER-MEDIA-RECOVERY" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "AUDIO_PARTICLE", + "task": "WBV2-P1105-000", + "owner": "AUDIO_PARTICLE", + "sourceBacked": true, + "capabilities": [ + "CAP-SOUND-PROPERTIES", + "CAP-SPEAKER-PROPERTIES", + "CAP-PARTICLE-SETTINGS" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P33-001/manifest.json", + "report": "tests/golden/WBV2-P33-001/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P33-002/manifest.json", + "report": "tests/golden/WBV2-P33-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "RIG_ANIMATION", + "task": "WBV2-P1106-000", + "owner": "RIG", + "sourceBacked": true, + "capabilities": [ + "CAP-RIG-POSE", + "CAP-CONSTRAINTS", + "CAP-NLA-ANIMATION" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-003/manifest.json", + "report": "tests/golden/WBV2-P13-003/rig-pose-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CORE_SCENE_GRAPH_SETTINGS", + "task": "WBV2-P1129-001", + "owner": "CORE_SCENE", + "sourceBacked": true, + "capabilities": [ + "CAP-SCENE-COMPOSITOR-SETTINGS", + "CAP-SCENE-PERFORMANCE-SETTINGS", + "CAP-SCENE-SAMPLING-SETTINGS" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P65-002/manifest.json", + "report": "tests/golden/WBV2-P65-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P66-002/manifest.json", + "report": "tests/golden/WBV2-P66-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P67-002/manifest.json", + "report": "tests/golden/WBV2-P67-002/implementation-report.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "UI_EDITOR_VIEW2D_STATE", + "task": "WBV2-P1130-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-EDITOR-VIEW2D-CUR", + "CAP-EDITOR-VIEW2D-MASK", + "CAP-EDITOR-VIEW2D-FAIL-CLOSED" + ], + "reusedReceipts": [], + "fullFamilyParity": false + }, + { + "id": "CURVE_TOPOLOGY_EDITOR", + "task": "WBV2-P1131-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-TOGGLE-CYCLIC", + "CAP-CURVE-TOPOLOGY-GATE", + "CAP-CURVE-TOPOLOGY-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/M9-05/manifest.json", + "report": "tests/golden/M9-05/curve-toggle-cyclic.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CURVE_HANDLE_GIZMO", + "task": "WBV2-P1132-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-HANDLE-MAIN", + "CAP-CURVE-HANDLE-GIZMO-PREVIEW", + "CAP-CURVE-HANDLE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CURVE_SPLINES_TRANSACTION", + "task": "WBV2-P1133-001", + "owner": "EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-SPLINES-MAIN", + "CAP-CURVE-SPLINES-RECOVERY", + "CAP-CURVE-SPLINES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "SURFACE_TOPOLOGY_TRANSACTION", + "task": "WBV2-P1134-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-SURFACE-TOPOLOGY-MAIN", + "CAP-SURFACE-NURBS-BOUNDS", + "CAP-SURFACE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FONT_BODY_TRANSACTION", + "task": "WBV2-P1135-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-BODY-MAIN", + "CAP-FONT-BODY-RECOVERY", + "CAP-FONT-BODY-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FONT_PROPERTIES_TRANSACTION", + "task": "WBV2-P1136-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-PROPERTIES-MAIN", + "CAP-FONT-PROPERTIES-RECOVERY", + "CAP-FONT-PROPERTIES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "METABALL_ELEMENTS_TRANSACTION", + "task": "WBV2-P1137-001", + "owner": "GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-METABALL-ELEMENTS-MAIN", + "CAP-METABALL-ELEMENTS-RECOVERY", + "CAP-METABALL-ELEMENTS-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "TEXT_SOURCE_TRANSACTION", + "task": "WBV2-P1138-001", + "owner": "SCRIPTING", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXT-SOURCE-MAIN", + "CAP-TEXT-SOURCE-RECOVERY", + "CAP-TEXT-SOURCE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1137-001/manifest.json", + "report": "tests/golden/WBV2-P1137-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "TEXTURE_PROPERTIES_TRANSACTION", + "task": "WBV2-P1139-001", + "owner": "TEXTURE", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXTURE-PROPERTIES-MAIN", + "CAP-TEXTURE-PROPERTIES-RECOVERY", + "CAP-TEXTURE-PROPERTIES-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1138-001/manifest.json", + "report": "tests/golden/WBV2-P1138-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ACTION_GROUP_READER", + "task": "WBV2-P1140-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-GROUP-READER", + "CAP-ACTION-GROUP-RECOVERY", + "CAP-ACTION-GROUP-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1112-000/manifest.json", + "report": "tests/golden/WBV2-P1112-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "ACTION_POSE_MARKERS_READER", + "task": "WBV2-P1141-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-POSE-MARKERS-READER", + "CAP-ACTION-POSE-MARKERS-RECOVERY", + "CAP-ACTION-POSE-MARKERS-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1140-001/manifest.json", + "report": "tests/golden/WBV2-P1140-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FCURVE_SAMPLE_READER", + "task": "WBV2-P1142-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-SAMPLE-READER", + "CAP-FCURVE-SAMPLE-RECOVERY", + "CAP-FCURVE-SAMPLE-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1141-001/manifest.json", + "report": "tests/golden/WBV2-P1141-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "FCURVE_MODIFIER_READER", + "task": "WBV2-P1143-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-MODIFIER-READER", + "CAP-FCURVE-MODIFIER-RECOVERY", + "CAP-FCURVE-MODIFIER-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1142-001/manifest.json", + "report": "tests/golden/WBV2-P1142-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "DRIVER_READER", + "task": "WBV2-P1144-001", + "owner": "ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-DRIVER-READER", + "CAP-DRIVER-RECOVERY", + "CAP-DRIVER-FAIL-CLOSED" + ], + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1143-001/manifest.json", + "report": "tests/golden/WBV2-P1143-001/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "CORRECTIVE_SMOOTH_READER", + "task": "WBV2-P1145-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-CORRECTIVE-SMOOTH-READER", + "CAP-CORRECTIVE-SMOOTH-RECOVERY", + "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + "tests/files/web/modifier_corrective_smooth_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MODIFIER_READER_BATCH", + "task": "WBV2-P1146-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH-READER", + "CAP-MODIFIER_READER_BATCH-RECOVERY", + "CAP-MODIFIER_READER_BATCH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MODIFIER_READER_BATCH_TWO", + "task": "WBV2-P1147-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH_TWO-READER", + "CAP-MODIFIER_READER_BATCH_TWO-RECOVERY", + "CAP-MODIFIER_READER_BATCH_TWO-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_two_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + }, + { + "id": "MODIFIER_READER_BATCH_THREE", + "task": "WBV2-P1148-001", + "owner": "MODIFIER", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH_THREE-READER", + "CAP-MODIFIER_READER_BATCH_THREE-RECOVERY", + "CAP-MODIFIER_READER_BATCH_THREE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_three_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "fullFamilyParity": false + } + ], + "tasks": [ + { + "id": "WBV2-P1096-000", + "phase": "1096", + "title": "supersede_generic_continuation_queue", + "kind": "bridge", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1095-003" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "bridge", + "gate": "QUEUE", + "card": "docs/tasks/WBV2-P1096-000.md", + "behavior": "Replace the generic continuation queue with a finite module execution plan without claiming capability parity.", + "outputs": [ + "bridge manifest", + "status" + ], + "acceptance": [ + "no parity claim", + "inventory preserved", + "module plan hash-bound" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1100-000", + "phase": "1100", + "title": "reorganize_module_execution_plan", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1096-000" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-000.md", + "behavior": "Reuse completed source-backed work and activate finite module-level implementation and verification.", + "outputs": [ + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "completed receipts reused", + "generic continuation excluded", + "one module active", + "inventory preserved" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1100-001", + "phase": "1100", + "title": "verify_render_light_camera_module", + "kind": "module", + "owner": "RENDER", + "dependsOn": [ + "WBV2-P1100-000" + ], + "parityId": "RENDER_LIGHT_CAMERA", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-render_light_camera", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-001.md", + "behavior": "Complete the RENDER_LIGHT_CAMERA module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RENDER_LIGHT_CAMERA", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-LIGHT-TYPE", + "CAP-RENDER-LIGHT-AREA-SHAPE", + "CAP-RENDER-LIGHT-CONTRIBUTION-FACTORS", + "CAP-RENDER-LIGHT-SHADOW-CONTROLS", + "CAP-RENDER-LIGHT-CASCADE-CONTROLS", + "CAP-RENDER-LIGHT-AREA-SIZE-Z", + "CAP-RENDER-LIGHT-CLIP-START", + "CAP-RENDER-WORLD-LIGHTING-CONTROLS", + "CAP-RENDER-WORLD-PROBE-CONTROLS", + "CAP-RENDER-WORLD-ENVIRONMENT-STRENGTH", + "CAP-RENDER-CAMERA-DOF-FOCUS-OBJECT", + "CAP-RENDER-CAMERA-PANORAMA" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P595-002/manifest.json", + "report": "tests/golden/WBV2-P595-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P596-002/manifest.json", + "report": "tests/golden/WBV2-P596-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P597-002/manifest.json", + "report": "tests/golden/WBV2-P597-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P598-002/manifest.json", + "report": "tests/golden/WBV2-P598-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P599-002/manifest.json", + "report": "tests/golden/WBV2-P599-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P600-002/manifest.json", + "report": "tests/golden/WBV2-P600-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P601-002/manifest.json", + "report": "tests/golden/WBV2-P601-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P602-002/manifest.json", + "report": "tests/golden/WBV2-P602-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P603-002/manifest.json", + "report": "tests/golden/WBV2-P603-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P604-002/manifest.json", + "report": "tests/golden/WBV2-P604-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P605-002/manifest.json", + "report": "tests/golden/WBV2-P605-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P606-002/manifest.json", + "report": "tests/golden/WBV2-P606-002/implementation-report.json" + } + ], + "positive": [ + "setLightProperties", + "setWorldProperties", + "setCameraProperties", + "camera panorama", + "world environment", + "light shadow/cascade" + ], + "negative": [ + "invalid enum", + "invalid numeric bounds", + "near/far conflict", + "unknown target", + "stale revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker disposal" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:lighting-field-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-lighting-fields-production.spec.ts tests/e2e/lighting-field-roundtrip.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1100-002", + "phase": "1100", + "title": "verify_scene_object_mesh_module", + "kind": "module", + "owner": "SCENE_MESH", + "dependsOn": [ + "WBV2-P1100-001" + ], + "parityId": "SCENE_OBJECT_MESH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-scene_object_mesh", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-002.md", + "behavior": "Complete the SCENE_OBJECT_MESH module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCENE_OBJECT_MESH", + "sourceBacked": true, + "capabilities": [ + "CAP-MESH-TOPOLOGY-FAMILY", + "CAP-CORE-SCENE-OBJECT", + "CAP-OBJECT-MOVE-COLLECTION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-001/manifest.json", + "report": "tests/golden/WBV2-P11-001/mesh-topology-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P12-002/manifest.json", + "report": "tests/golden/WBV2-P12-002/scene-object-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P24-002/manifest.json", + "report": "tests/golden/WBV2-P24-002/object-move-receipt-report.json" + } + ], + "positive": [ + "mesh topology", + "visibility", + "transform", + "collection membership" + ], + "negative": [ + "invalid selection", + "stale revision", + "linked data" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-mesh-topology-production.spec.ts tests/e2e/wbv2-scene-object-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1100-003", + "phase": "1100", + "title": "verify_material_animation_module", + "kind": "module", + "owner": "MATERIAL_ANIMATION", + "dependsOn": [ + "WBV2-P1100-002" + ], + "parityId": "MATERIAL_ANIMATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-material_animation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1100-003.md", + "behavior": "Complete the MATERIAL_ANIMATION module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MATERIAL_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-MATERIAL-ANIMATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-003/manifest.json", + "report": "tests/golden/WBV2-P12-003/material-animation-receipt-report.json" + } + ], + "positive": [ + "principled material", + "image node", + "keyframe", + "FCurve" + ], + "negative": [ + "unsupported graph", + "stale revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-material-animation-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-000", + "phase": "1101", + "title": "verify_nonmesh_geometry_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1100-003" + ], + "parityId": "NONMESH_GEOMETRY", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nonmesh_geometry", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-000.md", + "behavior": "Complete the NONMESH_GEOMETRY module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NONMESH_GEOMETRY", + "sourceBacked": true, + "capabilities": [ + "CAP-VIEWPORT-NONMESH", + "CAP-NATIVE-DATABLOCK" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "positive": [ + "curve", + "surface", + "font", + "volume", + "metaball", + "grease pencil" + ], + "negative": [ + "unsupported data", + "resource missing", + "malformed geometry" + ], + "recovery": [ + "save/reopen", + "resource disposal" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-viewport-nonmesh-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-001", + "phase": "1101", + "title": "verify_nodes_simulation_module", + "kind": "module", + "owner": "NODES_SIMULATION", + "dependsOn": [ + "WBV2-P1101-000" + ], + "parityId": "NODES_SIMULATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nodes_simulation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-001.md", + "behavior": "Complete the NODES_SIMULATION module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NODES_SIMULATION", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES", + "CAP-SIMULATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "allowlisted node graph", + "physics manifest", + "stable hash" + ], + "negative": [ + "unsupported node", + "budget exceeded", + "stale revision" + ], + "recovery": [ + "save/reopen", + "cache disposal" + ], + "commands": [ + "npm --prefix web run test:geometry-node-main-reader", + "npm --prefix web run test:physics-main-reader" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-002", + "phase": "1101", + "title": "verify_asset_io_module", + "kind": "module", + "owner": "ASSET", + "dependsOn": [ + "WBV2-P1101-001" + ], + "parityId": "ASSET_IO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-asset_io", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-002.md", + "behavior": "Complete the ASSET_IO module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ASSET_IO", + "sourceBacked": true, + "capabilities": [ + "CAP-ASSET-LINK-OVERRIDE-RELOAD", + "CAP-ASSET-CATALOG-MUTATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P10-003/manifest.json", + "report": "tests/golden/WBV2-P10-003/module-matrix-receipt-report.json" + } + ], + "positive": [ + "append", + "link", + "override", + "reload", + "asset catalog v2" + ], + "negative": [ + "missing source", + "ownership violation", + "hash drift", + "collision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "IndexedDB restart" + ], + "commands": [ + "npm --prefix web run test:asset-catalog-v2", + "npm --prefix web run test:asset-catalog-migration", + "npm --prefix web run test:asset-catalog-negatives", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-asset-link-override-production.spec.ts tests/e2e/wbv2-asset-catalog-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1101-003", + "phase": "1101", + "title": "verify_sculpt_paint_module", + "kind": "module", + "owner": "SCULPT_PAINT", + "dependsOn": [ + "WBV2-P1101-002" + ], + "parityId": "SCULPT_PAINT", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-sculpt_paint", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1101-003.md", + "behavior": "Complete the SCULPT_PAINT module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCULPT_PAINT", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-ATTRIBUTES", + "CAP-SCULPT-PAINT" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P16-002/manifest.json", + "report": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json" + } + ], + "positive": [ + "vertex colors", + "vertex weights", + "bounded sculpt stroke" + ], + "negative": [ + "mirror unverified", + "invalid patch", + "unsupported brush" + ], + "recovery": [ + "undo", + "redo", + "save/reopen" + ], + "commands": [ + "npm --prefix web run test:paint-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1102-000", + "phase": "1102", + "title": "implement_ui_editor_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1101-003" + ], + "parityId": "UI_EDITOR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-ui_editor", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1102-000.md", + "behavior": "Complete the UI_EDITOR module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-UI-EDITOR" + ], + "sourcePaths": [ + "web/protocol/editor-workflow.ts", + "web/app/src/app/App.tsx", + "web/app/src/workers/web-engine.worker.ts" + ], + "reuseReceipts": [], + "positive": [ + "editor context", + "workspace", + "area/region" + ], + "negative": [ + "unsupported editor", + "invalid context" + ], + "recovery": [ + "worker restart", + "save/reopen" + ], + "commands": [ + "npm --prefix web run test:editor-main-reader", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/ui-editor-workflow-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1102-001", + "phase": "1102", + "title": "close_module_execution_gate", + "kind": "module", + "owner": "RELEASE", + "dependsOn": [ + "WBV2-P1102-000" + ], + "parityId": "INVENTORY_GATE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-inventory_gate", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1102-001.md", + "behavior": "Complete the INVENTORY_GATE module through its shared Blender Main primitives and aggregate case matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "INVENTORY_GATE", + "sourceBacked": true, + "capabilities": [], + "sourcePaths": [ + "tests/golden/WBV2-P0-002/parity-map.json", + "tests/golden/WBV2-P1100-000/module-execution-plan.json" + ], + "reuseReceipts": [], + "positive": [ + "aggregate module receipts", + "catalog hash" + ], + "negative": [ + "missing receipt", + "hash drift", + "false completion" + ], + "recovery": [ + "re-run affected module only" + ], + "commands": [ + "node tools/web/check-wbv2-module-execution.mjs", + "npm --prefix web run build" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1103-000", + "phase": "1103", + "title": "aggregate_object_operations_module", + "kind": "module", + "owner": "OBJECT", + "dependsOn": [ + "WBV2-P1102-001" + ], + "parityId": "OBJECT_OPERATIONS", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-object_operations", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1103-000.md", + "behavior": "Aggregate the existing source-backed Object Main operations into one module and revalidate the Chromium operator matrix.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "OBJECT_OPERATIONS", + "sourceBacked": true, + "capabilities": [ + "CAP-OBJECT-DUPLICATE", + "CAP-OBJECT-CREATE", + "CAP-OBJECT-PARENT", + "CAP-OBJECT-COLLECTION", + "CAP-OBJECT-RENAME", + "CAP-OBJECT-DELETE", + "CAP-OBJECT-TRANSFORM" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P17-002/manifest.json", + "report": "tests/golden/WBV2-P17-002/object-duplicate-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P18-002/manifest.json", + "report": "tests/golden/WBV2-P18-002/object-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P19-002/manifest.json", + "report": "tests/golden/WBV2-P19-002/object-parent-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P20-002/manifest.json", + "report": "tests/golden/WBV2-P20-002/collection-create-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P21-002/manifest.json", + "report": "tests/golden/WBV2-P21-002/object-rename-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P22-002/manifest.json", + "report": "tests/golden/WBV2-P22-002/object-delete-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P23-002/manifest.json", + "report": "tests/golden/WBV2-P23-002/object-transform-receipt-report.json" + } + ], + "positive": [ + "duplicate", + "create", + "parent", + "collection", + "rename", + "delete", + "transform apply" + ], + "negative": [ + "unknown object", + "invalid parent cycle", + "malformed transform" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-object-duplicate-production.spec.ts tests/e2e/wbv2-object-create-production.spec.ts tests/e2e/wbv2-object-parent-production.spec.ts tests/e2e/wbv2-collection-create-production.spec.ts tests/e2e/wbv2-object-rename-production.spec.ts tests/e2e/wbv2-object-delete-production.spec.ts tests/e2e/wbv2-object-transform-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1104-000", + "phase": "1104", + "title": "verify_compositor_sequencer_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1103-000" + ], + "parityId": "COMPOSITOR_SEQUENCER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-compositor_sequencer", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1104-000.md", + "behavior": "Verify the source-backed compositor and sequencer module through golden, unsupported-gate and media recovery cases.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main or compositor mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "COMPOSITOR_SEQUENCER", + "sourceBacked": true, + "capabilities": [ + "CAP-COMPOSITOR-NODE-GRAPH", + "CAP-COMPOSITOR-UNSUPPORTED-GATE", + "CAP-SEQUENCER-MEDIA-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/compositor.ts", + "web/protocol/sequencer.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P29-003/manifest.json", + "report": "tests/golden/WBV2-P29-003/implementation-report.json" + } + ], + "positive": [ + "compositor node graph", + "sequencer still-image timeline", + "media cache contract" + ], + "negative": [ + "unsupported compositor node", + "invalid sequencer strip", + "stale media revision" + ], + "recovery": [ + "worker restart", + "save/reopen", + "media cache replay", + "movie codec blocked without READY receipt" + ], + "commands": [ + "npm --prefix web run test:compositor-node-golden", + "npm --prefix web run test:compositor-unsupported-gate", + "npm --prefix web run test:sequencer-main-reader", + "node --test web/tests/unit/sequencer-media-cache.test.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/smoke.spec.ts -g \"N-021 sequencer|real Blender 5.2 sequencer\"", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1105-000", + "phase": "1105", + "title": "verify_audio_particle_module", + "kind": "module", + "owner": "AUDIO_PARTICLE", + "dependsOn": [ + "WBV2-P1104-000" + ], + "parityId": "AUDIO_PARTICLE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-audio_particle", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1105-000.md", + "behavior": "Verify Sound, Speaker and ParticleSettings mutations against authoritative Blender Main with explicit build capability gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven or a typed build capability blocker is recorded", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "AUDIO_PARTICLE", + "sourceBacked": true, + "capabilities": [ + "CAP-SOUND-PROPERTIES", + "CAP-SPEAKER-PROPERTIES", + "CAP-PARTICLE-SETTINGS" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/protocol/io-media-commands.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P33-001/manifest.json", + "report": "tests/golden/WBV2-P33-001/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P33-002/manifest.json", + "report": "tests/golden/WBV2-P33-002/implementation-report.json" + } + ], + "positive": [ + "Sound properties", + "Speaker properties", + "ParticleSettings properties" + ], + "negative": [ + "missing Main datablock", + "unsupported build feature", + "out-of-range property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker restart" + ], + "commands": [ + "cmake --build build_web_blender6 --target web_engine -- -j8", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-audio-particle-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1106-000", + "phase": "1106", + "title": "verify_rig_animation_module", + "kind": "module", + "owner": "RIG", + "dependsOn": [ + "WBV2-P1105-000" + ], + "parityId": "RIG_ANIMATION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-rig_animation", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1106-000.md", + "behavior": "Verify armature pose, constraints and NLA animation through the existing Blender Main primitives.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RIG_ANIMATION", + "sourceBacked": true, + "capabilities": [ + "CAP-RIG-POSE", + "CAP-CONSTRAINTS", + "CAP-NLA-ANIMATION" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nla.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-003/manifest.json", + "report": "tests/golden/WBV2-P13-003/rig-pose-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "armature pose", + "constraint edit", + "NLA stack" + ], + "negative": [ + "missing bone", + "invalid constraint influence", + "stale NLA revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-rig-pose-production.spec.ts", + "npm --prefix web run test:nla-operator", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1107-000", + "phase": "1107", + "title": "verify_modifier_system_module", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1106-000" + ], + "parityId": "MODIFIER_SYSTEM", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_system", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1107-000.md", + "behavior": "Verify modifier stack visibility and bounded parameter mutation through authoritative Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_SYSTEM", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER-STATE-MUTATION", + "CAP-MODIFIER-PARAMETER-EDIT", + "CAP-MODIFIER-STACK-READER" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/modifier-graph.ts", + "web/protocol/depsgraph.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P9-002/manifest.json", + "report": "tests/golden/WBV2-P9-002/modifier-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P11-002/manifest.json", + "report": "tests/golden/WBV2-P11-002/modifier-parameter-receipt-report.json" + } + ], + "positive": [ + "modifier visibility toggle", + "bounded DECIMATE parameter mutation", + "modifier stack evaluation reader" + ], + "negative": [ + "unknown modifier UUID", + "stale mesh revision", + "out-of-range parameter" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-production.spec.ts tests/e2e/wbv2-modifier-parameter-production.spec.ts", + "npm --prefix web run test:modifier-goldens", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1108-000", + "phase": "1108", + "title": "verify_nodes_graph_module", + "kind": "module", + "owner": "NODES", + "dependsOn": [ + "WBV2-P1107-000" + ], + "parityId": "NODES_GRAPH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-nodes_graph", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1108-000.md", + "behavior": "Verify Geometry Nodes graph identity, allowlisted evaluation, field budgets and unsupported graph retention.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive graph reader/evaluation evidence is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "NODES_GRAPH", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES-GRAPH", + "CAP-GEOMETRY-NODES-ALLOWLIST", + "CAP-GEOMETRY-NODES-FIELD-BUDGET" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/geometry-nodes.ts", + "web/protocol/geometry-node-commands.ts", + "web/protocol/depsgraph.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-002/manifest.json", + "report": "tests/golden/WBV2-P13-002/geometry-nodes-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "allowlisted graph identity", + "Blender depsgraph geometry evaluation", + "field materialization with exact domain cardinality" + ], + "negative": [ + "unsupported node graph", + "field budget overflow", + "stale or invalid graph command" + ], + "recovery": [ + "save/reopen", + "worker restart", + "graph retention after rejected command", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:geometry-node-evaluator-golden", + "npm --prefix web run test:geometry-node-field-budget", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1109-000", + "phase": "1109", + "title": "verify_io_format_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1108-000" + ], + "parityId": "IO_FORMAT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-io_format", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1109-000.md", + "behavior": "Verify format capability routing, runtime receipts, recovery and fail-closed file UI gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive format routing/readiness evidence is proven", + "negative and recovery cases are proven", + "Chromium and deterministic recovery receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "IO_FORMAT", + "sourceBacked": true, + "capabilities": [ + "CAP-IO-FORMAT-CAPABILITY-MATRIX", + "CAP-IO-FORMAT-RUNTIME-RECEIPTS", + "CAP-IO-FORMAT-RECOVERY", + "CAP-IO-FORMAT-UI-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/asset-library-io.ts", + "web/protocol/io-format-capability-matrix.ts", + "web/protocol/io-format-receipt-binding.ts", + "web/protocol/io-format-runtime-receipt.ts", + "web/protocol/io-format-recovery.ts", + "web/protocol/io-format-ui-gate.ts", + "web/protocol/glb-export.ts", + "web/protocol/glb-import.ts", + "web/protocol/nonmesh-export.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "GLB export readiness", + "format runtime receipt inventory", + "declared .blend import route" + ], + "negative": [ + "unverified format route", + "cancelled or OOM operation", + "unsupported file extension" + ], + "recovery": [ + "worker restart", + "small operation recovery", + "deterministic receipt replay", + "fail-closed UI route" + ], + "commands": [ + "node tools/web/check-io-format-receipt-bindings.mjs", + "node tools/web/check-io-format-runtime-receipts.mjs", + "node tools/web/check-io-format-recovery.mjs", + "node tools/web/check-io-format-ui-gate.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/io-format-recovery.spec.ts tests/e2e/io-format-ui-gate.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1110-000", + "phase": "1110", + "title": "verify_render_pipeline_module", + "kind": "module", + "owner": "RENDER", + "dependsOn": [ + "WBV2-P1109-000" + ], + "parityId": "RENDER_PIPELINE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-render_pipeline", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1110-000.md", + "behavior": "Verify render backend routing, explicit resource budgets and Blender reference comparison in Chromium.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive render/reference evidence is proven", + "negative and recovery cases are proven", + "Chromium and deterministic render receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "RENDER_PIPELINE", + "sourceBacked": true, + "capabilities": [ + "CAP-RENDER-BACKEND-ROUTING", + "CAP-RENDER-RESOURCE-BUDGET", + "CAP-RENDER-REFERENCE-COMPARISON" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/render-routing.ts", + "web/protocol/render-budget.ts", + "web/protocol/render-capabilities.ts", + "web/protocol/render-image-comparison.ts", + "web/protocol/server-render-job.ts", + "web/app/src/three-adapter/render-routing.ts", + "web/app/src/three-adapter/render-image-comparison.ts", + "web/app/src/workers/viewport-render.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "bounded local backend routing", + "reference render metrics", + "resource budget acceptance" + ], + "negative": [ + "unknown or unavailable backend", + "aggregate texture/light budget overflow", + "wrong composition reference" + ], + "recovery": [ + "retain previous texture set", + "offscreen renderer parity", + "worker restart", + "deterministic second render" + ], + "commands": [ + "npm --prefix web run test:render-resource-budget", + "npm --prefix web run test:render-routing", + "npm --prefix web run test:render-reference", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1111-000", + "phase": "1111", + "title": "verify_scripting_security_module", + "kind": "module", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1110-000" + ], + "parityId": "SCRIPTING_SECURITY", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-scripting_security", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1111-000.md", + "behavior": "Verify script source Main reader, deny-by-default permission policy and sandbox isolation/recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive reader and policy evidence is proven", + "negative and recovery cases are proven", + "Chromium sandbox receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SCRIPTING_SECURITY", + "sourceBacked": true, + "capabilities": [ + "CAP-SCRIPT-MAIN-READER", + "CAP-SCRIPT-PERMISSION-POLICY", + "CAP-SCRIPT-SANDBOX-ISOLATION", + "CAP-SCRIPT-SANDBOX-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/scripting-platform.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/workers/script-permission-policy-test.worker.ts", + "web/app/src/workers/script-sandbox-isolation-test.worker.ts", + "web/app/src/workers/script-sandbox-recovery-test.worker.ts", + "web/app/src/testing/script-sandbox-recovery.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "script source inventory reader", + "explicit READ_MAIN permission", + "new-generation recovery audit" + ], + "negative": [ + "autorun denied by default", + "undeclared permission", + "sandbox crash/timeout/late result" + ], + "recovery": [ + "worker restart", + "sandbox generation rollover", + "continuous audit chain", + "deterministic second run" + ], + "commands": [ + "npm --prefix web run test:script-main-reader", + "npm --prefix web run test:scripting-isolation", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/script-permission-policy.spec.ts tests/e2e/script-sandbox-isolation.spec.ts tests/e2e/script-sandbox-recovery.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1112-000", + "phase": "1112", + "title": "verify_animation_timeline_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1111-000" + ], + "parityId": "ANIMATION_TIMELINE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-animation_timeline", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1112-000.md", + "behavior": "Verify frame evaluation and NLA time mapping through the production Worker and Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive frame/NLA evaluation is proven", + "negative and recovery cases are proven", + "Chromium and deterministic evaluation receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ANIMATION_TIMELINE", + "sourceBacked": true, + "capabilities": [ + "CAP-FRAME-EVALUATION", + "CAP-NLA-TIME-MAPPING", + "CAP-ANIMATION-SAVE-REOPEN" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nla.ts", + "web/protocol/depsgraph.ts", + "web/protocol/scene-ir.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "frame 1/5/10 evaluation", + "NLA track and strip mapping", + "Blender depsgraph animation result" + ], + "negative": [ + "stale NLA revision", + "invalid strip topology", + "unsupported animation domain" + ], + "recovery": [ + "save/reopen", + "worker restart", + "deterministic repeated evaluation", + "preserve rejected stack" + ], + "commands": [ + "npm --prefix web run test:frame-evaluation", + "node tools/web/check-nla-evaluation-golden.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/nla-evaluation-golden.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1113-000", + "phase": "1113", + "title": "verify_shader_material_module", + "kind": "module", + "owner": "MATERIAL", + "dependsOn": [ + "WBV2-P1112-000" + ], + "parityId": "SHADER_MATERIAL", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-shader_material", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1113-000.md", + "behavior": "Verify bounded Shader graph compilation, stable compile keys and fail-closed pipeline recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Shader Main compilation is proven", + "negative and recovery cases are proven", + "Chromium and deterministic compile receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SHADER_MATERIAL", + "sourceBacked": true, + "capabilities": [ + "CAP-SHADER-GRAPH-COMPILER", + "CAP-SHADER-COMPILE-KEY", + "CAP-SHADER-FAIL-CLOSED-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/shader-graph.ts", + "web/protocol/shader-graph-commands.ts", + "web/protocol/shader-compiler.ts", + "web/protocol/render-capabilities.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "Principled/Image/Normal/Math graph compile", + "stable compile key", + "real Main shader material path" + ], + "negative": [ + "unknown shader node", + "graph cycle or duplicate link", + "unsupported renderer backend" + ], + "recovery": [ + "retain previous material after compile failure", + "worker restart", + "deterministic repeated compile", + "save/reopen material graph" + ], + "commands": [ + "npm --prefix web run test:shader-compile", + "npm --prefix web run test:shader-pipeline", + "npm --prefix web run test:shader-capability", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1114-000", + "phase": "1114", + "title": "verify_grease_pencil_module", + "kind": "module", + "owner": "DRAWING", + "dependsOn": [ + "WBV2-P1113-000" + ], + "parityId": "GREASE_PENCIL", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-grease_pencil", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1114-000.md", + "behavior": "Verify Grease Pencil layer/frame Main mutations, stable identity validation and roundtrip recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Grease Pencil Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GREASE_PENCIL", + "sourceBacked": true, + "capabilities": [ + "CAP-GREASE-PENCIL-LAYER-FRAME", + "CAP-GREASE-PENCIL-STROKE-READER", + "CAP-GREASE-PENCIL-ROUNDTRIP" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/protocol/grease-pencil.ts", + "web/protocol/grease-pencil-reorder.ts", + "web/protocol/grease-pencil-selection.ts", + "web/protocol/grease-pencil-marquee.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/grease-pencil.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "create and reorder layer", + "insert and move frame", + "stable Grease Pencil drawing reader" + ], + "negative": [ + "forged drawing identity", + "occupied frame target", + "stale layer/frame revision" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic layer/frame replay" + ], + "commands": [ + "npm --prefix web run test:grease-pencil-reorder", + "npm --prefix web run test:grease-pencil", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1115-000", + "phase": "1115", + "title": "verify_curve_surface_editing_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1114-000" + ], + "parityId": "CURVE_SURFACE_EDITING", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_surface_editing", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1115-000.md", + "behavior": "Verify Curve topology/handle edits, Surface topology and non-mesh/font roundtrip through Blender Main.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive non-mesh Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_SURFACE_EDITING", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-HANDLES", + "CAP-SURFACE-TOPOLOGY", + "CAP-NONMESH-FONT-ROUNDTRIP" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/web-engine.ts", + "web/protocol/nonmesh-geometry-commands.ts", + "web/protocol/curve-topology-editor.ts", + "web/protocol/non-mesh.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P12-004/manifest.json", + "report": "tests/golden/WBV2-P12-004/viewport-nonmesh-receipt-report.json" + } + ], + "positive": [ + "Curve control point and handle edit", + "Curve cyclic/topology operator", + "Surface and Font property mutation" + ], + "negative": [ + "invalid curve selection/domain", + "occupied or stale frame/topology target", + "malformed non-mesh property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic multispline replay" + ], + "commands": [ + "npm --prefix web run test:curve-topology-operator", + "npm --prefix web run test:nonmesh-roundtrip", + "npm --prefix web run test:nonmesh-desktop-golden", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1116-000", + "phase": "1116", + "title": "verify_storage_recovery_module", + "kind": "module", + "owner": "STORAGE", + "dependsOn": [ + "WBV2-P1115-000" + ], + "parityId": "STORAGE_RECOVERY", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-storage_recovery", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1116-000.md", + "behavior": "Verify IndexedDB catalog migration/restart and OPFS asset preview deduplication, quarantine and reference GC.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive storage commit/recovery evidence is proven", + "negative and quarantine cases are proven", + "Chromium restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "STORAGE_RECOVERY", + "sourceBacked": true, + "capabilities": [ + "CAP-INDEXEDDB-CATALOG-MIGRATION", + "CAP-OPFS-PREVIEW-COMMIT", + "CAP-OPFS-QUARANTINE-GC" + ], + "sourcePaths": [ + "web/protocol/storage.ts", + "web/protocol/storage-budget.ts", + "web/protocol/save-transaction.ts", + "web/protocol/recent-projects.ts", + "web/protocol/asset-preview.ts", + "web/protocol/asset-preview-decode.ts", + "web/app/src/storage/asset-catalog-indexeddb.ts", + "web/app/src/storage/asset-preview-opfs-commit.ts", + "web/app/src/storage/asset-preview-quarantine.ts", + "web/app/src/storage/asset-preview-reference-gc.ts", + "web/app/src/storage/opfs-files.ts", + "web/app/src/storage/migrations.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "v1 to v2 catalog migration", + "page/Worker restart identity", + "content-addressed preview deduplication" + ], + "negative": [ + "partial catalog migration", + "corrupt preview quarantine", + "cross-project or non-final reference GC" + ], + "recovery": [ + "IndexedDB restart", + "OPFS commit replay", + "quarantine cleanup", + "deterministic reference reclamation" + ], + "commands": [ + "npm --prefix web run test:asset-catalog-restart", + "npm --prefix web run test:asset-preview-dedup", + "npm --prefix web run test:asset-preview-quarantine", + "npm --prefix web run test:asset-preview-reference-gc", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1117-000", + "phase": "1117", + "title": "verify_simulation_cache_module", + "kind": "module", + "owner": "SIMULATION", + "dependsOn": [ + "WBV2-P1116-000" + ], + "parityId": "SIMULATION_CACHE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-simulation_cache", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1117-000.md", + "behavior": "Verify simulation cache identity, physics-family payload integrity, lifecycle recovery and deterministic LRU pruning.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive cache identity/lifecycle evidence is proven", + "negative integrity and budget cases are proven", + "Chromium restart and quarantine receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SIMULATION_CACHE", + "sourceBacked": true, + "capabilities": [ + "CAP-SIMULATION-CACHE-IDENTITY", + "CAP-PHYSICS-CACHE-INTEGRITY", + "CAP-SIMULATION-CACHE-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/simulation-cache.ts", + "web/protocol/physics-simulation.ts", + "web/protocol/physics-cache-playback.ts", + "web/protocol/storage.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P13-004/manifest.json", + "report": "tests/golden/WBV2-P13-004/advanced-domain-receipt-report.json" + } + ], + "positive": [ + "graph/source/revision cache identity", + "all physics-family frame hashes", + "verified playback lifecycle" + ], + "negative": [ + "source or payload hash drift", + "revision/range mismatch", + "cache byte/frame budget overflow" + ], + "recovery": [ + "cancel and cleanup", + "LRU prune with protected playback", + "corruption quarantine", + "worker restart" + ], + "commands": [ + "npm --prefix web run test:simulation-cache-identity", + "npm --prefix web run test:simulation-cache-lifecycle", + "npm --prefix web run test:physics-cache-family", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1118-000", + "phase": "1118", + "title": "verify_ui_input_interaction_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1117-000" + ], + "parityId": "UI_INPUT_INTERACTION", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-ui_input_interaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1118-000.md", + "behavior": "Verify keyboard-only user actions, input mutex, IME/pointer state and responsive editor interaction under deployment CSP.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive keyboard Main mutation and save are proven", + "negative mutex/input cases are proven", + "Chromium accessibility and responsive receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_INPUT_INTERACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-KEYBOARD-USER-ACTIONS", + "CAP-INPUT-MODAL-STATE", + "CAP-IME-SHORTCUT-GUARD", + "CAP-RESPONSIVE-CSP-UI" + ], + "sourcePaths": [ + "web/app/index.html", + "web/app/src/app/App.tsx", + "web/app/src/app/app-shell.css", + "web/app/src/workers/web-engine.worker.ts", + "web/protocol/user-action-state.ts", + "web/protocol/project-action-mutex.ts", + "web/protocol/ime-composition.ts", + "web/protocol/input-modal.ts", + "web/protocol/pointer-contract.ts", + "web/protocol/worker-fault.ts", + "web/tests/unit/user-action-state.test.mjs", + "web/tests/unit/project-action-mutex.test.mjs", + "web/tests/unit/ime-composition.test.mjs", + "web/tests/unit/input-modal.test.mjs", + "web/tests/unit/pointer-contract.test.mjs" + ], + "reuseReceipts": [], + "positive": [ + "keyboard-only Add Cube Main mutation", + "keyboard save/reopen and GLB export", + "responsive controls at desktop/mobile viewports" + ], + "negative": [ + "concurrent project action mutex", + "IME shortcut suppression", + "pointer cancel/touch modal cleanup" + ], + "recovery": [ + "worker restart", + "save interruption recovery", + "responsive layout preservation", + "deterministic repeated keyboard loop" + ], + "commands": [ + "node --test web/tests/unit/user-action-state.test.mjs web/tests/unit/project-action-mutex.test.mjs web/tests/unit/ime-composition.test.mjs web/tests/unit/input-modal.test.mjs web/tests/unit/pointer-contract.test.mjs", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/user-action-state.spec.ts tests/e2e/project-action-mutex.spec.ts tests/e2e/keyboard-accessibility.spec.ts tests/e2e/responsive-layout.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1119-000", + "phase": "1119", + "title": "verify_library_workflow_module", + "kind": "module", + "owner": "ASSET", + "dependsOn": [ + "WBV2-P1118-000" + ], + "parityId": "LIBRARY_WORKFLOW", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-library_workflow", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1119-000.md", + "behavior": "Verify append, link, override and reload library flows through authoritative Main with path and dependency safety gates.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive library Main mutation is proven", + "negative and recovery cases are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "LIBRARY_WORKFLOW", + "sourceBacked": true, + "capabilities": [ + "CAP-LIBRARY-APPEND", + "CAP-LIBRARY-LINK", + "CAP-LIBRARY-OVERRIDE", + "CAP-LIBRARY-RELOAD-SAFETY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/library-main-append.ts", + "web/protocol/library-linked-mutation.ts", + "web/protocol/library-linked-reload.ts", + "web/protocol/library-linked-missing.ts", + "web/protocol/library-override-writer.ts", + "web/protocol/library-override-freshness.ts", + "web/protocol/library-negative-cases.ts", + "web/protocol/library-operation-identity.ts", + "web/protocol/library-source-origin.ts", + "web/protocol/asset-path.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P11-003/manifest.json", + "report": "tests/golden/WBV2-P11-003/asset-link-override-receipt-report.json" + }, + { + "manifest": "tests/golden/WBV2-P9-003/manifest.json", + "report": "tests/golden/WBV2-P9-003/asset-catalog-receipt-report.json" + } + ], + "positive": [ + "append object into Main", + "linked read-only object", + "local override and reload identity" + ], + "negative": [ + "missing library source", + "dependency/cross-library cycle", + "unsafe path or ownership mutation" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic library replay" + ], + "commands": [ + "npm --prefix web run test:library-main-append", + "npm --prefix web run test:library-link-chromium", + "npm --prefix web run test:library-override-chromium", + "npm --prefix web run test:library-negative-cases", + "npm --prefix web run test:library-path-security", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1120-000", + "phase": "1120", + "title": "verify_volume_nanovdb_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1119-000" + ], + "parityId": "VOLUME_NANOVDB", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-volume_nanovdb", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1120-000.md", + "behavior": "Verify NanoVDB manifest, paged feedback, OPFS commit/restart and production viewport volume roundtrip.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive volume resource and viewport evidence is proven", + "negative and recovery cases are proven", + "Chromium OPFS/restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "VOLUME_NANOVDB", + "sourceBacked": true, + "capabilities": [ + "CAP-NANOVDB-MANIFEST", + "CAP-NANOVDB-PAGED-FEEDBACK", + "CAP-NANOVDB-OPFS-RESTART", + "CAP-NANOVDB-VIEWPORT-ROUNDTRIP" + ], + "sourcePaths": [ + "web/protocol/volume-vdb.ts", + "web/protocol/nanovdb-page-feedback.ts", + "web/protocol/nanovdb-device-recovery.ts", + "web/protocol/storage.ts", + "web/app/src/volume/nanovdb-opfs.ts", + "web/app/src/volume/nanovdb-stream.ts", + "web/app/src/volume/nanovdb-viewport.ts", + "web/app/src/volume/nanovdb-float32.ts", + "web/app/src/render/nanovdb-volume-renderer.ts", + "web/app/src/workers/vdb-opfs-test.worker.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "validated NanoVDB bundle manifest", + "content-addressed OPFS commit", + "main/offscreen production viewport volume" + ], + "negative": [ + "manifest/chunk hash mismatch", + "stale source binding", + "WebGPU/resource availability block" + ], + "recovery": [ + "OPFS Worker restart", + "paged feedback resume", + "quota/device loss cleanup", + "deterministic volume save/reopen" + ], + "commands": [ + "npm --prefix web run test:vdb-availability", + "npm --prefix web run test:vdb-native", + "npm --prefix web run test:nanovdb-page-feedback", + "npm --prefix web run test:nanovdb-opfs-restart", + "npm --prefix web run test:nanovdb-volume-roundtrip", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1121-000", + "phase": "1121", + "title": "verify_paint_stroke_module", + "kind": "module", + "owner": "SCULPT", + "dependsOn": [ + "WBV2-P1120-000" + ], + "parityId": "PAINT_STROKE", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-paint_stroke", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1121-000.md", + "behavior": "Verify paint pointer sessions, depth visibility and PBVH capability gates through the production Worker.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive paint Main transaction is proven", + "negative and recovery cases are proven", + "Chromium pointer/GPU receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "PAINT_STROKE", + "sourceBacked": true, + "capabilities": [ + "CAP-PAINT-POINTER-SESSION", + "CAP-PAINT-DEPTH-VISIBILITY", + "CAP-PAINT-PBVH-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/protocol/sculpt.ts", + "web/protocol/paint.ts", + "web/protocol/paint-stroke-session.ts", + "web/protocol/paint-depth-visibility.ts", + "web/protocol/paint-pbvh-capability.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/three-adapter/paint-depth-visibility.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "ordered paint pointer chunks", + "main/offscreen depth visibility", + "PBVH inventory capability query" + ], + "negative": [ + "stale/discontinuous pointer chunks", + "forged or over-budget depth samples", + "missing PBVH WASM entrypoint" + ], + "recovery": [ + "pointer cancel without Main mutation", + "undo step after paint commit", + "worker restart", + "deterministic capability replay" + ], + "commands": [ + "npm --prefix web run test:paint-stroke-session", + "npm --prefix web run test:paint-depth-visibility", + "npm --prefix web run test:paint-pbvh-capability", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1122-000", + "phase": "1122", + "title": "verify_engine_runtime_module", + "kind": "module", + "owner": "RUNTIME", + "dependsOn": [ + "WBV2-P1121-000" + ], + "parityId": "ENGINE_RUNTIME", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-engine_runtime", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1122-000.md", + "behavior": "Verify WebEngine variant manifest/selection, compiled WASM Main ABI and Worker crash recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive compiled WASM Main lifecycle is proven", + "negative variant/hash cases are proven", + "Chromium Worker restart receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ENGINE_RUNTIME", + "sourceBacked": true, + "capabilities": [ + "CAP-ENGINE-VARIANT-MANIFEST", + "CAP-ENGINE-WASM-MAIN-ABI", + "CAP-WORKER-CRASH-RECOVERY" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_api.h", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/CMakeLists.txt", + "web/protocol/engine-variant.ts", + "web/protocol/worker-fault.ts", + "web/protocol/save-transaction.ts", + "web/app/src/engine-client/engine-variant-bootstrap.ts", + "web/app/src/engine-client/browser-engine-variant-session.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/workers/storage.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "single/pthread manifest binding", + "compiled WASM Main open/save lifecycle", + "engine and storage Worker recovery" + ], + "negative": [ + "malformed variant/resource declaration", + "mixed-version/hash mismatch", + "pthread unavailable fallback" + ], + "recovery": [ + "single-thread fallback", + "Worker crash restart", + "operation-log restore", + "deterministic repeated startup" + ], + "commands": [ + "npm --prefix web run test:engine-manifest-v2", + "npm --prefix web run test:engine-variant-selection", + "npm --prefix web run test:engine-variant-fallback", + "npm --prefix web run test:engine-variant-install", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-native-engine-production.spec.ts tests/e2e/worker-crash-recovery.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1123-000", + "phase": "1123", + "title": "repair_glb_roundtrip_dependency_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1122-000" + ], + "parityId": "GLB_ROUNDTRIP_REPAIR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-glb_roundtrip_repair", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1123-000.md", + "behavior": "Repair the standalone GLB checker dependency chain and verify mesh/non-mesh Blender roundtrip plus Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive GLB and non-mesh roundtrip are proven", + "negative and recovery cases are proven", + "Chromium save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GLB_ROUNDTRIP_REPAIR", + "sourceBacked": true, + "capabilities": [ + "CAP-GLB-MESH-ROUNDTRIP", + "CAP-GLB-NONMESH-ROUNDTRIP", + "CAP-GLB-CHROMIUM-RECOVERY" + ], + "sourcePaths": [ + "tools/web/check-glb-blender-roundtrip.mjs", + "tools/web/check-nonmesh-glb-blender-roundtrip.mjs", + "tools/web/blender-check-glb-roundtrip.py", + "web/protocol/glb-export.ts", + "web/protocol/glb-import.ts", + "web/protocol/nonmesh-export.ts", + "web/protocol/nonmesh-binary.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx" + ], + "reuseReceipts": [], + "positive": [ + "mesh/material/skin/animation GLB roundtrip", + "Curve/Surface/Font/Metaball non-mesh mapping", + "desktop GLB Main persistence in Chromium" + ], + "negative": [ + "sparse or oversized GLB", + "external URI/extension rejection", + "non-mesh export loss gate" + ], + "recovery": [ + "cancel without publishing output", + "Worker restart", + "OPFS quota retains old asset", + "deterministic Blender roundtrip" + ], + "commands": [ + "npm --prefix web run test:glb-blender-roundtrip", + "npm --prefix web run test:nonmesh-glb-blender-roundtrip", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/glb-negative-cases.spec.ts tests/e2e/glb-recovery.spec.ts tests/e2e/glb-main-persistence.spec.ts", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1124-000", + "phase": "1124", + "title": "record_historical_hash_drift_module", + "kind": "module", + "owner": "PROVENANCE", + "dependsOn": [ + "WBV2-P1123-000" + ], + "parityId": "HISTORICAL_HASH_DRIFT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-historical_hash_drift", + "gate": "EVIDENCE", + "card": "docs/tasks/WBV2-P1124-000.md", + "behavior": "Record legacy M12 artifact hash drift without re-signing historical manifests or changing the immutable inventory.", + "outputs": [ + "drift report", + "module receipt", + "manifest", + "status" + ], + "acceptance": [ + "original and observed hashes are recorded", + "provenance remains BLOCKED_SOURCE_LOST where bytes cannot be restored", + "historical manifests and inventory remain unchanged", + "deterministic drift evidence is reproducible", + "no full-family parity claim" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "HISTORICAL_HASH_DRIFT", + "sourceBacked": true, + "capabilities": [ + "CAP-HISTORICAL-HASH-AUDIT", + "CAP-PROVENANCE-SOURCE-LOST-GATE" + ], + "sourcePaths": [ + "tools/web/check-m12-manifest-drift.mjs", + "tests/golden/corrective/rehydration/M12-manifest-sha-drift.json", + "tests/golden/WBV2-P0-002/parity-map.json" + ], + "reuseReceipts": [], + "positive": [ + "84 drift entries captured", + "43 affected artifact paths indexed", + "immutable inventory binding preserved" + ], + "negative": [ + "missing original bytes", + "attempted historical re-signing", + "inventory mutation" + ], + "recovery": [ + "deterministic report rerun", + "source cache can restore original bytes later", + "new capability manifests reference drift evidence only" + ], + "commands": [ + "node tools/web/check-m12-manifest-drift.mjs --write", + "node tools/web/check-m12-manifest-drift.mjs", + "node tools/web/check-wbv2-module-execution.mjs" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1125-000", + "phase": "1125", + "title": "repair_geometry_nodes_allowlist_module", + "kind": "module", + "owner": "NODES", + "dependsOn": [ + "WBV2-P1124-000" + ], + "parityId": "GEOMETRY_NODES_ALLOWLIST_REPAIR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-geometry_nodes_allowlist_repair", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1125-000.md", + "behavior": "Persist Geometry Nodes graph overrides in Web-safe Main storage and align allowlist assertions with real materialization behavior.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "supported graph Main materialization is proven", + "unsupported graph remains rejected without mutation", + "save/reopen graph retention is exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GEOMETRY_NODES_ALLOWLIST_REPAIR", + "sourceBacked": true, + "capabilities": [ + "CAP-GEOMETRY-NODES-MAIN-PERSISTENCE", + "CAP-GEOMETRY-NODES-ALLOWLIST-CONSISTENCY", + "CAP-GEOMETRY-NODES-SAVE-REOPEN" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/geometry-nodes.ts", + "web/protocol/geometry-node-commands.ts", + "web/protocol/web-engine.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/geometry-node-allowlist.spec.ts", + "web/tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [], + "positive": [ + "allowlisted graph materializes into Main", + "Scene IDProperty graph override persists", + "save/reopen retains graph identity/hash" + ], + "negative": [ + "unsupported simulation node", + "invalid graph schema", + "missing node/link endpoint" + ], + "recovery": [ + "rejected graph leaves baseline unchanged", + "undo/redo graph override", + "save/reopen", + "deterministic second run" + ], + "commands": [ + "cmake --build build_web_blender6 --target web_engine -- -j8", + "npm --prefix web run test:geometry-node-allowlist", + "npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-geometry-nodes-production.spec.ts", + "npm --prefix web run test:geometry-node-field-budget", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1126-000", + "phase": "1126", + "title": "verify_grease_pencil_viewport_module", + "kind": "module", + "owner": "DRAWING", + "dependsOn": [ + "WBV2-P1125-000" + ], + "parityId": "GREASE_PENCIL_VIEWPORT", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-grease_pencil_viewport", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1126-000.md", + "behavior": "Verify Grease Pencil 2D/3D selection and marquee integration on both viewport backends using an isolated Chromium port.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "2D and 3D selection revisions converge", + "main-thread and Offscreen marquee are exact", + "stale/foreign selection cases remain fail-closed", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "GREASE_PENCIL_VIEWPORT", + "sourceBacked": true, + "capabilities": [ + "CAP-GREASE-PENCIL-SELECTION-REVISION", + "CAP-GREASE-PENCIL-MARQUEE-MAIN", + "CAP-GREASE-PENCIL-MARQUEE-OFFSCREEN" + ], + "sourcePaths": [ + "web/protocol/grease-pencil-selection.ts", + "web/protocol/grease-pencil-marquee.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/grease-pencil.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/app/src/workers/viewport-render.worker.ts" + ], + "reuseReceipts": [], + "positive": [ + "2D canvas selection revision", + "main-thread 3D marquee selection", + "OffscreenCanvas 3D marquee selection" + ], + "negative": [ + "stale selection revision", + "foreign drawing identity", + "duplicate or forged point candidate" + ], + "recovery": [ + "selection convergence across backends", + "worker viewport restart", + "deterministic repeated marquee", + "preserve Main revision" + ], + "commands": [ + "WEB_TEST_PORT=5331 npm --prefix web run test:e2e -- --workers=1 tests/e2e/grease-pencil-selection.spec.ts tests/e2e/grease-pencil-marquee.spec.ts", + "node --test web/tests/unit/grease-pencil-selection.test.mjs web/tests/unit/grease-pencil-marquee.test.mjs", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1127-000", + "phase": "1127", + "title": "verify_tracking_mask_module", + "kind": "module", + "owner": "TRACKING", + "dependsOn": [ + "WBV2-P1126-000" + ], + "parityId": "TRACKING_MASK", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-tracking_mask", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1127-000.md", + "behavior": "Verify Mask reader, editable point raycast/marquee and tracking capability gates through Chromium.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Mask reader and interaction evidence is proven", + "negative solve/resource cases are proven", + "Chromium stable IDs and recovery receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TRACKING_MASK", + "sourceBacked": true, + "capabilities": [ + "CAP-MASK-MAIN-READER", + "CAP-MASK-POINT-RAYCAST", + "CAP-TRACKING-SOLVE-GATE" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/tracking-mask.ts", + "web/protocol/scene-ir.ts", + "web/app/src/tracking/MaskSelection.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/tests/e2e/smoke.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "Mask layers and splines reader", + "editable Mask point raycast", + "N-022 tracking marker/mask gate" + ], + "negative": [ + "foreign mask point identity", + "missing resource binding", + "camera solve unavailable" + ], + "recovery": [ + "main/offscreen marquee parity", + "worker restart", + "deterministic stable IDs", + "preserve source Main on blocked solve" + ], + "commands": [ + "npm --prefix web run test:mask-main-reader", + "WEB_TEST_PORT=5340 npm --prefix web run test:e2e -- --workers=1 tests/e2e/smoke.spec.ts -g \"N-022 tracking|real Blender 5.2 Mask\"", + "npm --prefix web run typecheck" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1128-000", + "phase": "1128", + "title": "verify_ffmpeg_movie_codec_module", + "kind": "module", + "owner": "MEDIA", + "dependsOn": [ + "WBV2-P1127-000" + ], + "parityId": "SEQUENCER_MOVIE_CODEC", + "implementationClass": "LOCAL_BOUNDED", + "parallelGroup": "module-sequencer_movie_codec", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1128-000.md", + "behavior": "Use a local ffmpeg.wasm Worker fallback for movie probing and proxy-frame extraction when Chromium HTML media decoding is unavailable.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and core-resource hashes are bound", + "positive MP4 probe and RGBA frame are proven", + "corrupt and source-identity cases are rejected", + "AbortSignal cancellation leaves no live Worker", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SEQUENCER_MOVIE_CODEC", + "sourceBacked": true, + "capabilities": [ + "CAP-FFMPEG-WASM-MOVIE-PROBE", + "CAP-FFMPEG-WASM-PROXY-FRAME", + "CAP-MOVIE-CODEC-RECOVERY" + ], + "sourcePaths": [ + "web/package.json", + "web/package-lock.json", + "web/protocol/sequencer.ts", + "web/app/src/sequencer/SequencerCodecProbe.ts", + "web/app/src/sequencer/FFmpegMovieProbe.ts", + "web/app/src/sequencer/ffmpeg-movie-probe.worker.ts", + "web/app/src/sequencer/SequencerMediaProxyCache.ts", + "web/app/src/vendor/ffmpeg/ffmpeg-core.js", + "web/app/src/vendor/ffmpeg/ffmpeg-core.wasm", + "web/app/public/vendor/ffmpeg/ffmpeg-core.js", + "web/app/public/vendor/ffmpeg/ffmpeg-core.wasm", + "third_party/ffmpeg.wasm/package.json", + "third_party/ffmpeg.wasm/README.md", + "web/tests/e2e/ffmpeg-movie-probe-production.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "browser decode fallback to ffmpeg.wasm", + "16x16 MP4 metadata probe", + "8x8 RGBA proxy frame extraction" + ], + "negative": [ + "corrupt movie payload", + "source SHA mismatch", + "ffmpeg runtime unavailable" + ], + "recovery": [ + "AbortSignal cancellation", + "Worker termination after response", + "cache manifest identity binding", + "deterministic repeated probe" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5342 npm --prefix web run test:e2e -- --workers=1 tests/e2e/ffmpeg-movie-probe-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1129-000", + "phase": "1129", + "title": "authorize_scene_settings_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1128-000" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1129", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1129-000.md", + "behavior": "Authorize one source-backed Core Scene Graph settings module after the terminal P1128 module epoch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1128 evidence remains hash-bound", + "existing receipts are reused", + "inventory remains immutable", + "one source-backed module is active" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ] + }, + { + "id": "WBV2-P1129-001", + "phase": "1129", + "title": "verify_scene_settings_module", + "kind": "module", + "owner": "CORE_SCENE", + "dependsOn": [ + "WBV2-P1129-000" + ], + "parityId": "CORE_SCENE_GRAPH_SETTINGS", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-core_scene_graph_settings", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1129-001.md", + "behavior": "Verify the existing Blender Main scene compositor, performance and sampling setting transactions as one aggregate module.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutations are proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen receipts are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CORE_SCENE_GRAPH_SETTINGS", + "sourceBacked": true, + "capabilities": [ + "CAP-SCENE-COMPOSITOR-SETTINGS", + "CAP-SCENE-PERFORMANCE-SETTINGS", + "CAP-SCENE-SAMPLING-SETTINGS" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-scene-settings-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P65-002/manifest.json", + "report": "tests/golden/WBV2-P65-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P66-002/manifest.json", + "report": "tests/golden/WBV2-P66-002/implementation-report.json" + }, + { + "manifest": "tests/golden/WBV2-P67-002/manifest.json", + "report": "tests/golden/WBV2-P67-002/implementation-report.json" + } + ], + "positive": [ + "compositor device/precision mutation", + "performance thread/persistence mutation", + "sampling filter/dither mutation" + ], + "negative": [ + "invalid sampling range", + "unknown scene target", + "malformed property set" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic scene settings snapshot" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5344 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-scene-settings-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1130-000", + "phase": "1130", + "title": "authorize_editor_view2d_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1129-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1130", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1130-000.md", + "behavior": "Authorize one source-backed UI editor View2D reader/protocol module after the P1129 scene settings module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1129 evidence remains hash-bound", + "P1102 editor workflow source remains unchanged", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1130-001", + "phase": "1130", + "title": "verify_editor_view2d_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1130-000" + ], + "parityId": "UI_EDITOR_VIEW2D_STATE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-ui_editor_view2d_state", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1130-001.md", + "behavior": "Preserve Blender Graph/Dope Sheet View2D cur and mask state through the Web editor protocol without changing the existing editor workflow parser.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive reader state is proven", + "negative no-publish and recovery are proven", + "Chromium and save/reopen compatibility are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "UI_EDITOR_VIEW2D_STATE", + "sourceBacked": true, + "capabilities": [ + "CAP-EDITOR-VIEW2D-CUR", + "CAP-EDITOR-VIEW2D-MASK", + "CAP-EDITOR-VIEW2D-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/editor-view2d.ts", + "web/app/src/workers/editor-view2d-test.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/ui-editor-view2d-production.spec.ts" + ], + "reuseReceipts": [], + "positive": [ + "Graph main-region View2D cur retention", + "Graph main-region pixel mask retention", + "reader/protocol exact state" + ], + "negative": [ + "inverted View2D bounds", + "malformed mask range", + "missing View2D payload" + ], + "recovery": [ + "immutable base editor workflow", + "worker termination", + "deterministic repeated parse", + "save/reopen reader compatibility" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5346 npm --prefix web run test:e2e -- --workers=1 tests/e2e/ui-editor-view2d-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1131-000", + "phase": "1131", + "title": "authorize_curve_topology_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1130-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1131", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1131-000.md", + "behavior": "Authorize one source-backed Curve topology editor module after the P1130 View2D module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1130 evidence remains hash-bound", + "Curve topology source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1131-001", + "phase": "1131", + "title": "verify_curve_topology_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1131-000" + ], + "parityId": "CURVE_TOPOLOGY_EDITOR", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_topology_editor", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1131-001.md", + "behavior": "Verify the Blender Curve TOGGLE_CYCLIC topology transaction through the existing Main, protocol, Worker and frontend path.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_TOPOLOGY_EDITOR", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-TOPOLOGY-TOGGLE-CYCLIC", + "CAP-CURVE-TOPOLOGY-GATE", + "CAP-CURVE-TOPOLOGY-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/editors/curve/curve_ops.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/curve-topology-editor.ts", + "web/app/src/workers/curve-topology-contract-test.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/curve-topology-contract.spec.ts", + "web/tests/e2e/curve-topology-operator.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "TOGGLE_CYCLIC Main mutation", + "operator gate exposes only verified capability", + "save/reopen preserves cyclic spline state" + ], + "negative": [ + "unknown curve operator", + "stale revision claim", + "selection and payload budget overflow" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic contract parse" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5347 npm --prefix web run test:e2e -- --workers=1 tests/e2e/curve-topology-contract.spec.ts tests/e2e/curve-topology-operator.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1132-000", + "phase": "1132", + "title": "authorize_curve_handle_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1131-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1132", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1132-000.md", + "behavior": "Authorize one source-backed Curve handle gizmo module after the P1131 topology module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1131 evidence remains hash-bound", + "Curve handle source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1132-001", + "phase": "1132", + "title": "verify_curve_handle_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1132-000" + ], + "parityId": "CURVE_HANDLE_GIZMO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_handle_gizmo", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1132-001.md", + "behavior": "Verify Curve handle position edits through Blender Main, protocol, Worker, renderer preview and frontend gizmo.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_HANDLE_GIZMO", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-HANDLE-MAIN", + "CAP-CURVE-HANDLE-GIZMO-PREVIEW", + "CAP-CURVE-HANDLE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/nonmesh-interaction.ts", + "web/app/src/workers/nonmesh-interaction-test.worker.ts", + "web/app/src/app/App.tsx", + "web/app/src/three-adapter/nonmesh.ts", + "web/app/src/three-adapter/viewport.ts", + "web/app/src/three-adapter/offscreen-viewport.ts", + "web/tests/e2e/wbv2-curve-handle-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Curve handle position Main mutation", + "local handle gizmo preview", + "save/reopen preserves handle state" + ], + "negative": [ + "invalid handle identity", + "stale base revision", + "malformed handle position" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic preview" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5348 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-curve-handle-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1133-000", + "phase": "1133", + "title": "authorize_curve_splines_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1132-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1133", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1133-000.md", + "behavior": "Authorize one source-backed Curve spline transaction module after the P1132 handle module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1132 evidence remains hash-bound", + "Curve spline source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1133-001", + "phase": "1133", + "title": "verify_curve_splines_module", + "kind": "module", + "owner": "EDITOR", + "dependsOn": [ + "WBV2-P1133-000" + ], + "parityId": "CURVE_SPLINES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-curve_splines_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1133-001.md", + "behavior": "Verify complete Curve spline replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CURVE_SPLINES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-CURVE-SPLINES-MAIN", + "CAP-CURVE-SPLINES-RECOVERY", + "CAP-CURVE-SPLINES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/tests/e2e/wbv2-curve-splines-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "complete Curve spline Main transaction", + "POLY/BEZIER descriptor retention", + "save/reopen preserves spline state" + ], + "negative": [ + "invalid spline offsets", + "stale base revision", + "mismatched handle payload" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic binary-geometry transaction" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5349 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-curve-splines-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1134-000", + "phase": "1134", + "title": "authorize_surface_topology_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1133-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1134", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1134-000.md", + "behavior": "Authorize one source-backed Surface topology transaction module after the P1133 Curve spline module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1133 evidence remains hash-bound", + "Surface topology source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1134-001", + "phase": "1134", + "title": "verify_surface_topology_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1134-000" + ], + "parityId": "SURFACE_TOPOLOGY_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-surface_topology_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1134-001.md", + "behavior": "Verify Surface NURBS topology replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "SURFACE_TOPOLOGY_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-SURFACE-TOPOLOGY-MAIN", + "CAP-SURFACE-NURBS-BOUNDS", + "CAP-SURFACE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/tests/e2e/wbv2-surface-topology-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Surface topology Main transaction", + "NURBS dimensions and weights retention", + "save/reopen preserves surface state" + ], + "negative": [ + "invalid surface dimensions", + "stale base revision", + "control grid budget mismatch" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "deterministic surface transaction" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5350 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-surface-topology-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1135-000", + "phase": "1135", + "title": "authorize_font_body_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1134-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1135", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1135-000.md", + "behavior": "Authorize one source-backed Font body transaction module after the P1134 Surface topology module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1134 evidence remains hash-bound", + "Font body source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1135-001", + "phase": "1135", + "title": "verify_font_body_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1135-000" + ], + "parityId": "FONT_BODY_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-font_body_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1135-001.md", + "behavior": "Verify Font body replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FONT_BODY_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-BODY-MAIN", + "CAP-FONT-BODY-RECOVERY", + "CAP-FONT-BODY-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-font-body-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Font body Main mutation", + "UTF-8 text retention", + "save/reopen preserves text" + ], + "negative": [ + "unknown Font data ID", + "body byte budget overflow", + "malformed body payload" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic text state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5351 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-font-body-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1136-000", + "phase": "1136", + "title": "authorize_font_properties_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1135-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1136", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1136-000.md", + "behavior": "Authorize one source-backed Font properties transaction module after the P1135 Font body module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1135 evidence remains hash-bound", + "Font property source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1136-001", + "phase": "1136", + "title": "verify_font_properties_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1136-000" + ], + "parityId": "FONT_PROPERTIES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-font_properties_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1136-001.md", + "behavior": "Verify Font property replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FONT_PROPERTIES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-FONT-PROPERTIES-MAIN", + "CAP-FONT-PROPERTIES-RECOVERY", + "CAP-FONT-PROPERTIES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-font-properties-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Font property Main mutation", + "bounded alignment/extrude fields", + "save/reopen preserves properties" + ], + "negative": [ + "unknown Font data ID", + "invalid alignment enum", + "out-of-range numeric property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic property state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5352 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-font-properties-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1137-000", + "phase": "1137", + "title": "authorize_metaball_elements_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1136-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1137", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1137-000.md", + "behavior": "Authorize one source-backed Metaball element transaction module after the P1136 Font properties module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1136 evidence remains hash-bound", + "Metaball element source and protocol are present", + "inventory remains immutable", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1137-001", + "phase": "1137", + "title": "verify_metaball_elements_module", + "kind": "module", + "owner": "GEOMETRY", + "dependsOn": [ + "WBV2-P1137-000" + ], + "parityId": "METABALL_ELEMENTS_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-metaball_elements_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1137-001.md", + "behavior": "Verify Metaball element replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "METABALL_ELEMENTS_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-METABALL-ELEMENTS-MAIN", + "CAP-METABALL-ELEMENTS-RECOVERY", + "CAP-METABALL-ELEMENTS-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-metaball-elements-production.spec.ts" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1101-000/manifest.json", + "report": "tests/golden/WBV2-P1101-000/module-receipt.json" + } + ], + "positive": [ + "Metaball element Main mutation", + "bounded position/radius/scale retention", + "save/reopen preserves elements" + ], + "negative": [ + "unknown Metaball data ID", + "invalid radius", + "element count topology mismatch" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic element state" + ], + "commands": [ + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-metaball-elements-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1138-000", + "phase": "1138", + "title": "authorize_text_source_module", + "kind": "enabling", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1137-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1138", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1138-000.md", + "behavior": "Authorize a source-backed Text datablock mutation after the P1137 Metaball module.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1137 evidence remains hash-bound", + "ID_TXT is registered for WITH_WEB", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1138-001", + "phase": "1138", + "title": "verify_text_source_module", + "kind": "module", + "owner": "SCRIPTING", + "dependsOn": [ + "WBV2-P1138-000" + ], + "parityId": "TEXT_SOURCE_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-text_source_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1138-001.md", + "behavior": "Verify Text source replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TEXT_SOURCE_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXT-SOURCE-MAIN", + "CAP-TEXT-SOURCE-RECOVERY", + "CAP-TEXT-SOURCE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/blenkernel/intern/idtype.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-text-source-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1137-001/manifest.json", + "report": "tests/golden/WBV2-P1137-001/module-receipt.json" + } + ], + "positive": [ + "Text source Main mutation", + "ID_TXT registration in WITH_WEB", + "save/reopen preserves source" + ], + "negative": [ + "unknown Text data ID", + "source over 1 MiB", + "linked/read-only Text" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic source state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-text-source-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1139-000", + "phase": "1139", + "title": "authorize_texture_properties_module", + "kind": "enabling", + "owner": "TEXTURE", + "dependsOn": [ + "WBV2-P1138-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1139", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1139-000.md", + "behavior": "Authorize a source-backed Texture property mutation module after P1138 Text.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1138 evidence remains hash-bound", + "ID_TE is registered for WITH_WEB", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1139-001", + "phase": "1139", + "title": "verify_texture_properties_module", + "kind": "module", + "owner": "TEXTURE", + "dependsOn": [ + "WBV2-P1139-000" + ], + "parityId": "TEXTURE_PROPERTIES_TRANSACTION", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-texture_properties_transaction", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1139-001.md", + "behavior": "Verify Texture property replacement through Blender Main, protocol, Worker and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main mutation is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "TEXTURE_PROPERTIES_TRANSACTION", + "sourceBacked": true, + "capabilities": [ + "CAP-TEXTURE-PROPERTIES-MAIN", + "CAP-TEXTURE-PROPERTIES-RECOVERY", + "CAP-TEXTURE-PROPERTIES-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/blenkernel/intern/idtype.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", + "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", + "web/protocol/web-engine.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/app/App.tsx", + "web/tests/e2e/wbv2-texture-properties-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1138-001/manifest.json", + "report": "tests/golden/WBV2-P1138-001/module-receipt.json" + } + ], + "positive": [ + "Texture property Main mutation", + "ID_TE registration in WITH_WEB", + "save/reopen preserves properties" + ], + "negative": [ + "unknown Texture data ID", + "noise depth outside Blender bounds", + "non-finite numeric property" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "Worker termination and deterministic property state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5353 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-texture-properties-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1140-000", + "phase": "1140", + "title": "authorize_action_group_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1139-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1140", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1140-000.md", + "behavior": "Authorize a source-backed ActionGroup reader and recovery module after P1139 Texture.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1139 evidence remains hash-bound", + "ActionGroup has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1140-001", + "phase": "1140", + "title": "verify_action_group_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1140-000" + ], + "parityId": "ACTION_GROUP_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-action_group_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1140-001.md", + "behavior": "Verify ActionGroup metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ACTION_GROUP_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-GROUP-READER", + "CAP-ACTION-GROUP-RECOVERY", + "CAP-ACTION-GROUP-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-action-group-reader-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1112-000/manifest.json", + "report": "tests/golden/WBV2-P1112-000/module-receipt.json" + } + ], + "positive": [ + "ActionGroup Main reader exposes group and expanded metadata", + "three grouped location F-Curves remain grouped", + "save/reopen preserves group metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing animation target is fail-closed", + "unsupported group payload is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic group state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5356 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-action-group-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1141-000", + "phase": "1141", + "title": "authorize_action_pose_markers_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1140-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1141", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1141-000.md", + "behavior": "Authorize a source-backed ActionPoseMarkers reader and recovery module after P1140.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1140 evidence remains hash-bound", + "ActionPoseMarkers has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1141-001", + "phase": "1141", + "title": "verify_action_pose_markers_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1141-000" + ], + "parityId": "ACTION_POSE_MARKERS_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-action_pose_markers_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1141-001.md", + "behavior": "Verify ActionPoseMarkers metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "ACTION_POSE_MARKERS_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-ACTION-POSE-MARKERS-READER", + "CAP-ACTION-POSE-MARKERS-RECOVERY", + "CAP-ACTION-POSE-MARKERS-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-action-pose-markers-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1140-001/manifest.json", + "report": "tests/golden/WBV2-P1140-001/module-receipt.json" + } + ], + "positive": [ + "ActionPoseMarkers Main reader exposes marker names and frames", + "three Blender pose markers remain ordered", + "save/reopen preserves marker metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing animation target is fail-closed", + "non-finite marker frame is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic marker state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5359 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-action-pose-markers-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1142-000", + "phase": "1142", + "title": "authorize_fcurve_sample_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1141-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1142", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1142-000.md", + "behavior": "Authorize a source-backed FCurveSample reader and recovery module after P1141.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1141 evidence remains hash-bound", + "FCurveSample has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1142-001", + "phase": "1142", + "title": "verify_fcurve_sample_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1142-000" + ], + "parityId": "FCURVE_SAMPLE_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-fcurve_sample_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1142-001.md", + "behavior": "Verify FCurveSample data through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FCURVE_SAMPLE_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-SAMPLE-READER", + "CAP-FCURVE-SAMPLE-RECOVERY", + "CAP-FCURVE-SAMPLE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-fcurve-sample-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1141-001/manifest.json", + "report": "tests/golden/WBV2-P1141-001/module-receipt.json" + } + ], + "positive": [ + "FCurveSample Main reader exposes sampled source and values", + "four native FPoint samples remain ordered", + "save/reopen preserves sampled data" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing sampled payload is fail-closed", + "non-finite sampled value is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic sampled state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5365 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-sample-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1143-000", + "phase": "1143", + "title": "authorize_fcurve_modifier_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1142-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1143", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1143-000.md", + "behavior": "Authorize a source-backed FCurve modifier reader and recovery module after P1142.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1142 evidence remains hash-bound", + "FCurveModifiers has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1143-001", + "phase": "1143", + "title": "verify_fcurve_modifier_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1143-000" + ], + "parityId": "FCURVE_MODIFIER_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-fcurve_modifier_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1143-001.md", + "behavior": "Verify FCurve modifier metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "FCURVE_MODIFIER_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-FCURVE-MODIFIER-READER", + "CAP-FCURVE-MODIFIER-RECOVERY", + "CAP-FCURVE-MODIFIER-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-fcurve-modifier-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1142-001/manifest.json", + "report": "tests/golden/WBV2-P1142-001/module-receipt.json" + } + ], + "positive": [ + "FCurveModifiers Main reader exposes native modifier stack", + "FModifierCycles preserves type/name/flags/influence", + "save/reopen preserves modifier metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing modifier payload is fail-closed", + "unsupported modifier type is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic modifier state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5368 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-fcurve-modifier-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1144-000", + "phase": "1144", + "title": "authorize_driver_reader_module", + "kind": "enabling", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1143-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1144", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1144-000.md", + "behavior": "Authorize a source-backed Driver reader and recovery module after P1143.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "P1143 evidence remains hash-bound", + "Driver has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1144-001", + "phase": "1144", + "title": "verify_driver_reader_module", + "kind": "module", + "owner": "ANIMATION", + "dependsOn": [ + "WBV2-P1144-000" + ], + "parityId": "DRIVER_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-driver_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1144-001.md", + "behavior": "Verify Driver metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "DRIVER_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-DRIVER-READER", + "CAP-DRIVER-RECOVERY", + "CAP-DRIVER-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/protocol/scene-ir.ts", + "web/app/src/workers/web-engine.worker.ts", + "web/app/src/engine-client/WebEngineClient.ts", + "web/tests/e2e/wbv2-driver-reader-production.spec.ts", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1143-001/manifest.json", + "report": "tests/golden/WBV2-P1143-001/module-receipt.json" + } + ], + "positive": [ + "AnimData driver list is read from Blender Main", + "Driver preserves scripted expression and variables", + "save/reopen preserves driver metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "missing driver target is fail-closed", + "non-finite driver influence is not synthesized" + ], + "recovery": [ + "undo", + "redo", + "save/reopen", + "worker termination and deterministic driver state" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-driver-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1145-000", + "phase": "1145", + "title": "authorize_corrective_smooth_reader_module", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1144-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1145", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1145-000.md", + "behavior": "Authorize a source-backed Corrective Smooth reader/recovery module after the Driver reader.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "Corrective Smooth has explicit Blender source mapping", + "inventory remains source-derived", + "one source-backed module is active" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1145-001", + "phase": "1145", + "title": "verify_corrective_smooth_reader_module", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1145-000" + ], + "parityId": "CORRECTIVE_SMOOTH_READER", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-corrective_smooth_reader", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1145-001.md", + "behavior": "Verify Corrective Smooth modifier type and RNA metadata through Blender Main reader, protocol and Chromium recovery.", + "outputs": [ + "module receipt", + "negative matrix", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "positive Main reader is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact", + "full-family parity remains explicit" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "CORRECTIVE_SMOOTH_READER", + "sourceBacked": true, + "capabilities": [ + "CAP-CORRECTIVE-SMOOTH-READER", + "CAP-CORRECTIVE-SMOOTH-RECOVERY", + "CAP-CORRECTIVE-SMOOTH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts", + "tests/files/web/modifier_corrective_smooth_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "Corrective Smooth type is read from Blender Main", + "RNA metadata is preserved", + "save/reopen preserves modifier metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported modifier data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-corrective-smooth-reader-production.spec.ts" + ], + "fullFamilyParity": false + } + }, + { + "id": "WBV2-P1146-000", + "phase": "1146", + "title": "authorize_modifier_reader_batch", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1145-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1146", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1146-000.md", + "behavior": "Authorize one shared source-backed modifier reader batch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1146-001", + "phase": "1146", + "title": "verify modifier reader batch", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1146-000" + ], + "parityId": "MODIFIER_READER_BATCH", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_reader_batch", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1146-001.md", + "behavior": "Verify the MODIFIER_READER_BATCH batch through Blender Main, WASM and Chromium recovery.", + "outputs": [ + "aggregate module receipt", + "coverage bindings", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_READER_BATCH", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH-READER", + "CAP-MODIFIER_READER_BATCH-RECOVERY", + "CAP-MODIFIER_READER_BATCH-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts", + "tests/files/web/modifier_reader_batch_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "MOD_datatransfer type is read from Blender Main", + "MOD_dynamicpaint type is read from Blender Main", + "MOD_explode type is read from Blender Main", + "MOD_fluid type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-production.spec.ts" + ], + "fullFamilyParity": false, + "evidencePaths": [ + "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json" + ], + "coverageBindings": [ + "modifier-source:MOD_datatransfer", + "modifier-source:MOD_dynamicpaint", + "modifier-source:MOD_explode", + "modifier-source:MOD_fluid", + "rna-struct:DataTransferModifier", + "rna-struct:DynamicPaintModifier", + "rna-struct:ExplodeModifier", + "rna-struct:FluidModifier", + "rna-struct:FluidDomainSettings" + ] + } + }, + { + "id": "WBV2-P1147-000", + "phase": "1147", + "title": "authorize_modifier_reader_batch", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1146-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1147", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1147-000.md", + "behavior": "Authorize one shared source-backed modifier reader batch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1147-001", + "phase": "1147", + "title": "verify modifier reader batch two", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1147-000" + ], + "parityId": "MODIFIER_READER_BATCH_TWO", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_reader_batch_two", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1147-001.md", + "behavior": "Verify the MODIFIER_READER_BATCH_TWO batch through Blender Main, WASM and Chromium recovery.", + "outputs": [ + "aggregate module receipt", + "coverage bindings", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_READER_BATCH_TWO", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH_TWO-READER", + "CAP-MODIFIER_READER_BATCH_TWO-RECOVERY", + "CAP-MODIFIER_READER_BATCH_TWO-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_two_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "MOD_laplaciandeform type is read from Blender Main", + "MOD_laplaciansmooth type is read from Blender Main", + "MOD_mask type is read from Blender Main", + "MOD_mesh_to_volume type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts" + ], + "fullFamilyParity": false, + "evidencePaths": [ + "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json" + ], + "coverageBindings": [ + "modifier-source:MOD_laplaciandeform", + "modifier-source:MOD_laplaciansmooth", + "modifier-source:MOD_mask", + "modifier-source:MOD_shrinkwrap", + "rna-struct:LaplacianDeformModifier", + "rna-struct:LaplacianSmoothModifier", + "rna-struct:MaskModifier", + "rna-struct:ShrinkwrapModifier" + ] + } + }, + { + "id": "WBV2-P1148-000", + "phase": "1148", + "title": "authorize_modifier_reader_batch", + "kind": "enabling", + "owner": "PROGRAM", + "dependsOn": [ + "WBV2-P1147-001" + ], + "parityId": null, + "implementationClass": "QUEUE_ONLY", + "parallelGroup": "module-root-1148", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1148-000.md", + "behavior": "Authorize one shared source-backed modifier reader batch.", + "outputs": [ + "successor authorization", + "module plan", + "manifest", + "status" + ], + "acceptance": [ + "prior evidence remains hash-bound", + "batch source mapping is explicit", + "inventory remains source-derived" + ], + "commands": [ + "node tools/web/check-execution-control-plane.mjs" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true + }, + { + "id": "WBV2-P1148-001", + "phase": "1148", + "title": "verify modifier reader batch three", + "kind": "module", + "owner": "MODIFIER", + "dependsOn": [ + "WBV2-P1148-000" + ], + "parityId": "MODIFIER_READER_BATCH_THREE", + "implementationClass": "LOCAL_EXACT", + "parallelGroup": "module-modifier_reader_batch_three", + "gate": "MODULE", + "card": "docs/tasks/WBV2-P1148-001.md", + "behavior": "Verify the MODIFIER_READER_BATCH_THREE batch through Blender Main, WASM and Chromium recovery.", + "outputs": [ + "aggregate module receipt", + "coverage bindings", + "manifest", + "status" + ], + "acceptance": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "status": "done", + "ready": false, + "queueMutationAllowed": true, + "module": { + "moduleId": "MODIFIER_READER_BATCH_THREE", + "sourceBacked": true, + "capabilities": [ + "CAP-MODIFIER_READER_BATCH_THREE-READER", + "CAP-MODIFIER_READER_BATCH_THREE-RECOVERY", + "CAP-MODIFIER_READER_BATCH_THREE-FAIL-CLOSED" + ], + "sourcePaths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_three_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "reuseReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json" + } + ], + "positive": [ + "MOD_remesh type is read from Blender Main", + "MOD_skin type is read from Blender Main", + "MOD_weighted_normal type is read from Blender Main", + "MOD_warp type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ], + "commands": [ + "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "npm --prefix web run typecheck", + "npm --prefix web run build", + "WBV2_BATCH_TASK=WBV2-P1148-001 WBV2_BATCH_FIXTURE=tests/files/web/modifier_reader_batch_three_scene.blend WBV2_BATCH_TYPES='[\"REMESH\",\"SKIN\",\"WEIGHTED_NORMAL\",\"WARP\"]' WBV2_BATCH_UNITS='[\"modifier-source:MOD_remesh\",\"modifier-source:MOD_skin\",\"modifier-source:MOD_weighted_normal\",\"modifier-source:MOD_warp\",\"rna-struct:RemeshModifier\",\"rna-struct:SkinModifier\",\"rna-struct:WeightedNormalModifier\",\"rna-struct:WarpModifier\"]' WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts" + ], + "fullFamilyParity": false, + "evidencePaths": [ + "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json" + ], + "coverageBindings": [ + "modifier-source:MOD_remesh", + "modifier-source:MOD_skin", + "modifier-source:MOD_weighted_normal", + "modifier-source:MOD_warp", + "rna-struct:RemeshModifier", + "rna-struct:SkinModifier", + "rna-struct:WeightedNormalModifier", + "rna-struct:WarpModifier" + ] + } + } + ] +} diff --git a/tests/golden/WBV2-P1148-000/successor-authorization-report.json b/tests/golden/WBV2-P1148-000/successor-authorization-report.json new file mode 100644 index 000000000..391388ca7 --- /dev/null +++ b/tests/golden/WBV2-P1148-000/successor-authorization-report.json @@ -0,0 +1,36 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-000", + "operation": "AUTHORIZE_SOURCE_BACKED_MODULE_BATCH", + "taskClass": "QUEUE_ENABLEMENT", + "status": "PASS", + "parent": { + "task": "WBV2-P1147-001", + "manifest": "tests/golden/WBV2-P1147-001/manifest.json", + "manifestSha256": "6c9d7b844434668b2614d7215e44c146f7adf081480ec71bff6d534d0df6dbce" + }, + "module": { + "moduleId": "MODIFIER_READER_BATCH_THREE", + "task": "WBV2-P1148-001", + "batchSize": 8, + "sourceUnits": [ + "modifier-source:MOD_remesh", + "modifier-source:MOD_skin", + "modifier-source:MOD_weighted_normal", + "modifier-source:MOD_warp", + "rna-struct:RemeshModifier", + "rna-struct:SkinModifier", + "rna-struct:WeightedNormalModifier", + "rna-struct:WarpModifier" + ], + "sourceBacked": true + }, + "inventory": { + "unitCount": 3745, + "verifiedUnits": 369, + "unverifiedUnits": 3376, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "boundUnitDelta": 0 + }, + "nextTask": "WBV2-P1148-001" +} diff --git a/tests/golden/WBV2-P1148-001/continuous-runner.log b/tests/golden/WBV2-P1148-001/continuous-runner.log new file mode 100644 index 000000000..22bdb4c5b --- /dev/null +++ b/tests/golden/WBV2-P1148-001/continuous-runner.log @@ -0,0 +1,43 @@ +v2-task-index-generated tasks=77 active=NONE output=tests/golden/WBV2/task-index.json +task-context-ok task=WBV2-P1148-001 parent=WBV2-P1148-000 contentTokens=1963 envelopeTokens=661/1024 estimatedTokens=2987/3500 taskBytes=2273 next=NONE output=tests/golden/WBV2-P1148-001/task-context.json +node:fs:484 + return binding.readFileUtf8(path, stringToFlags(options.flag)); + ^ + +Error: ENOENT: no such file or directory, open '/home/mes123456/workinf_Blender_Wasm/tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json' + at Object.readFileSync (node:fs:484:20) + at read (file:///home/mes123456/workinf_Blender_Wasm/tools/web/bind-wbv2-module-coverage.mjs:9:27) + at json (file:///home/mes123456/workinf_Blender_Wasm/tools/web/bind-wbv2-module-coverage.mjs:10:35) + at file:///home/mes123456/workinf_Blender_Wasm/tools/web/bind-wbv2-module-coverage.mjs:32:20 + at ModuleJob.run (node:internal/modules/esm/module_job:439:25) + at async node:internal/modules/esm/loader:643:26 + at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) { + errno: -2, + code: 'ENOENT', + syscall: 'open', + path: '/home/mes123456/workinf_Blender_Wasm/tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json' +} + +Node.js v24.19.0 +node:internal/errors:985 + const err = new Error(message); + ^ + +Error: Command failed: /home/mes123456/.nvm/versions/node/v24.19.0/bin/node /home/mes123456/workinf_Blender_Wasm/tools/web/bind-wbv2-module-coverage.mjs --task WBV2-P1148-001 + at genericNodeError (node:internal/errors:985:15) + at wrappedFn (node:internal/errors:539:14) + at checkExecSyncError (node:child_process:942:11) + at execFileSync (node:child_process:978:15) + at file:///home/mes123456/workinf_Blender_Wasm/tools/web/run-wbv2-module-task.mjs:99:5 + at ModuleJob.run (node:internal/modules/esm/module_job:439:25) + at async node:internal/modules/esm/loader:643:26 + at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) { + status: 1, + signal: null, + output: [ null, null, null ], + pid: 135663, + stdout: null, + stderr: null +} + +Node.js v24.19.0 diff --git a/tests/golden/WBV2-P1148-001/manifest.json b/tests/golden/WBV2-P1148-001/manifest.json new file mode 100644 index 000000000..b5f978c3a --- /dev/null +++ b/tests/golden/WBV2-P1148-001/manifest.json @@ -0,0 +1,111 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-001", + "parentTask": "WBV2-P1148-000", + "operation": "MODULE_FUNCTION_EXECUTION", + "taskClass": "MODULE", + "status": "done", + "enablingTask": true, + "parityStateChange": false, + "runtime": "BLENDER_WEB_FUNCTION_MODULE", + "artifacts": { + "parentManifest": { + "path": "tests/golden/WBV2-P1148-000/manifest.json", + "sha256": "7f762c08fcc1df876a427a89358d3713944bd42f06f264fabf365a217c4d98e6" + }, + "source1": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "sha256": "e6b52cbced435c619a2a5e62ee23c3a2bb8b0dc4a3af7308854130895ce10f0d" + }, + "source2": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "sha256": "63736037a0bb5cc553668e0e12ab5ca8f5fee4499a9d0baf7edc1edaa5c3723b" + }, + "source3": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "sha256": "38d31c99424448a9ce76229f937fab5f60bf87dbec8fabdbee705af715467cb9" + }, + "source4": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "sha256": "68da38d98c638637f331120e84781a13d06c80425ccdaa8894c6000af0a2e4b3" + }, + "source5": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source6": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source7": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source8": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "sha256": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b" + }, + "source9": { + "path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "sha256": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990" + }, + "source10": { + "path": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "sha256": "3520b2d03d803d923062c58fdd60530cc8540040bfb35a00c439cfe50167aa03" + }, + "source11": { + "path": "tests/files/web/modifier_reader_batch_three_scene.blend", + "sha256": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739" + }, + "source12": { + "path": "web/app/src/vendor/blender/web_engine.wasm", + "sha256": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "moduleReceipt": { + "path": "tests/golden/WBV2-P1148-001/module-receipt.json", + "sha256": "6c2b32e28fc5a853a5b447efe12b718b2947d91b682e405f4ff9d5e4bf9075c9" + }, + "status": { + "path": "docs/status/WBV2-P1148-001.md", + "sha256": "bbfd0890471b04498c501960087fb99b4547638115548a0d00af8ed577be546d" + }, + "log": { + "path": "tests/golden/WBV2-P1148-001/module-run.log", + "sha256": "cc3e3b0070f8daa45a28877ec583127d882dfbf9929ba48b098dd083109fc341" + }, + "plan": { + "path": "tests/golden/WBV2-P1148-000/module-execution-plan.json", + "sha256": "ddef158adc3211d9cf86d38c288dd9c2ce47c32abae400d2b5929838044e139f" + }, + "taskContext": { + "path": "tests/golden/WBV2-P1148-001/task-context.json", + "sha256": "9e01db52a3744f32ed5867619b62633be58f9a450909151a0be32067b47744b9" + }, + "evidence1": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + } + }, + "assertions": { + "moduleId": "MODIFIER_READER_BATCH_THREE", + "sourceBacked": true, + "positiveCases": 6, + "negativeCases": 3, + "recoveryCases": 3, + "commandCount": 4, + "reusedReceiptCount": 1, + "sourceUnchanged": true, + "fullFamilyParity": false, + "dynamicInventoryPath": "tests/golden/WBV2/dynamic-inventory.json", + "dynamicSourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "dynamicUnitCount": 3745, + "dynamicVerifiedUnits": 377, + "dynamicUnverifiedUnits": 3368, + "planningEstimate": 5200, + "historicalInventoryTotal": 6900, + "historicalEffectiveCompleted": 290, + "historicalEffectivePending": 6609, + "historicalReproduction": false + }, + "nextTask": null +} diff --git a/tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json b/tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json new file mode 100644 index 000000000..e55e651ec --- /dev/null +++ b/tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json @@ -0,0 +1,224 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-001", + "operation": "MODIFIER_READER_BATCH_TWO_CHROMIUM_SAVE_REOPEN", + "browser": "chromium", + "queueMutation": false, + "fixture": "tests/files/web/modifier_reader_batch_three_scene.blend", + "fixtureSha256": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739", + "expectedTypes": [ + "REMESH", + "SKIN", + "WEIGHTED_NORMAL", + "WARP" + ], + "sourceUnits": [ + "modifier-source:MOD_remesh", + "modifier-source:MOD_skin", + "modifier-source:MOD_weighted_normal", + "modifier-source:MOD_warp", + "rna-struct:RemeshModifier", + "rna-struct:SkinModifier", + "rna-struct:WeightedNormalModifier", + "rna-struct:WarpModifier" + ], + "before": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1879751496", + "name": "Remesh", + "type": "REMESH", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1879751496, + "typeCode": 41 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1853982967", + "name": "Skin", + "type": "SKIN", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "branchSmoothing": 0, + "flag": 1, + "mode": 7, + "persistentUid": 1853982967, + "skinFlags": 0, + "symmetryAxes": 1, + "typeCode": 42 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1800999687", + "name": "Weighted Normal", + "type": "WEIGHTED_NORMAL", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "flag": 1, + "mode": 7, + "persistentUid": 1800999687, + "typeCode": 54, + "weight": 50 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:614917079", + "name": "Warp", + "type": "WARP", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 614917079, + "typeCode": 35 + } + } + ], + "types": [ + "REMESH", + "SKIN", + "WEIGHTED_NORMAL", + "WARP" + ], + "after": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1879751496", + "name": "Remesh", + "type": "REMESH", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1879751496, + "typeCode": 41 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1853982967", + "name": "Skin", + "type": "SKIN", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "branchSmoothing": 0, + "flag": 1, + "mode": 7, + "persistentUid": 1853982967, + "skinFlags": 0, + "symmetryAxes": 1, + "typeCode": 42 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1800999687", + "name": "Weighted Normal", + "type": "WEIGHTED_NORMAL", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "flag": 1, + "mode": 7, + "persistentUid": 1800999687, + "typeCode": 54, + "weight": 50 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:614917079", + "name": "Warp", + "type": "WARP", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 614917079, + "typeCode": 35 + } + } + ], + "second": [ + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1879751496", + "name": "Remesh", + "type": "REMESH", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 1, + "mode": 3, + "persistentUid": 1879751496, + "typeCode": 41 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1853982967", + "name": "Skin", + "type": "SKIN", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "branchSmoothing": 0, + "flag": 1, + "mode": 7, + "persistentUid": 1853982967, + "skinFlags": 0, + "symmetryAxes": 1, + "typeCode": 42 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:1800999687", + "name": "Weighted Normal", + "type": "WEIGHTED_NORMAL", + "enabled": true, + "evaluationStatus": "METADATA_ONLY", + "parameters": { + "flag": 1, + "mode": 7, + "persistentUid": 1800999687, + "typeCode": 54, + "weight": 50 + } + }, + { + "meshId": "mesh:Grid", + "uuid": "modifier:object:ModifierBatchThreeFixture:614917079", + "name": "Warp", + "type": "WARP", + "enabled": true, + "evaluationStatus": "BLOCKED", + "parameters": { + "flag": 5, + "mode": 3, + "persistentUid": 614917079, + "typeCode": 35 + } + } + ], + "saveReopenExact": true, + "deterministicExact": true, + "savedSha256": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739", + "malformed": { + "code": "BLEND_READ_FAILED", + "message": "Input is not an uncompressed, gzip, or zstd Blender file" + } +} diff --git a/tests/golden/WBV2-P1148-001/module-receipt.json b/tests/golden/WBV2-P1148-001/module-receipt.json new file mode 100644 index 000000000..e3f596be7 --- /dev/null +++ b/tests/golden/WBV2-P1148-001/module-receipt.json @@ -0,0 +1,128 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-001", + "operation": "MODULE_FUNCTION_EXECUTION", + "moduleId": "MODIFIER_READER_BATCH_THREE", + "status": "PASS", + "source": { + "paths": [ + "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "tests/files/web/modifier_reader_batch_three_scene.blend", + "web/app/src/vendor/blender/web_engine.wasm" + ], + "before": { + "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc": "e6b52cbced435c619a2a5e62ee23c3a2bb8b0dc4a3af7308854130895ce10f0d", + "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc": "63736037a0bb5cc553668e0e12ab5ca8f5fee4499a9d0baf7edc1edaa5c3723b", + "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc": "38d31c99424448a9ce76229f937fab5f60bf87dbec8fabdbee705af715467cb9", + "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc": "68da38d98c638637f331120e84781a13d06c80425ccdaa8894c6000af0a2e4b3", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts": "3520b2d03d803d923062c58fdd60530cc8540040bfb35a00c439cfe50167aa03", + "tests/files/web/modifier_reader_batch_three_scene.blend": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739", + "web/app/src/vendor/blender/web_engine.wasm": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "after": { + "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc": "e6b52cbced435c619a2a5e62ee23c3a2bb8b0dc4a3af7308854130895ce10f0d", + "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc": "63736037a0bb5cc553668e0e12ab5ca8f5fee4499a9d0baf7edc1edaa5c3723b", + "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc": "38d31c99424448a9ce76229f937fab5f60bf87dbec8fabdbee705af715467cb9", + "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc": "68da38d98c638637f331120e84781a13d06c80425ccdaa8894c6000af0a2e4b3", + "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc": "1292112c20eaa113084a2a7093c349e7787db818950d80a6e11b75b287e4287b", + "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp": "f6fbd04315c48ad4dfbf109b91e5b350550d23c227e5c11a71a58f09e923c990", + "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts": "3520b2d03d803d923062c58fdd60530cc8540040bfb35a00c439cfe50167aa03", + "tests/files/web/modifier_reader_batch_three_scene.blend": "bf75a51df11f005991423354eba4adab59fb3c2e2382ecf3993c4b1dea2cc739", + "web/app/src/vendor/blender/web_engine.wasm": "32bc36aba563fe1ed0fb5d0292ca8a3ada1eecd6d45e38d9dcde565f02a312fe" + }, + "unchanged": true + }, + "reusedReceipts": [ + { + "manifest": "tests/golden/WBV2-P1107-000/manifest.json", + "report": "tests/golden/WBV2-P1107-000/module-receipt.json", + "manifestSha256": "a53ebdc52db5dcf27d44e938e5551f1ee2adae8e46c3fe8661604ee6b1000f8c", + "reportSha256": "6dd419799e1a4b9251328d9496f2459d148cd89118740a06b0ee6ffb78e0b1d2" + } + ], + "cases": { + "positive": [ + "MOD_remesh type is read from Blender Main", + "MOD_skin type is read from Blender Main", + "MOD_weighted_normal type is read from Blender Main", + "MOD_warp type is read from Blender Main", + "shared RNA metadata is preserved", + "save/reopen preserves the batch metadata" + ], + "negative": [ + "malformed blend is rejected without Main mutation", + "unsupported batch data fails closed", + "non-finite metadata is not synthesized" + ], + "recovery": [ + "save/reopen", + "worker termination", + "deterministic second read" + ] + }, + "commands": [ + { + "command": "source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm", + "exitCode": 0 + }, + { + "command": "npm --prefix web run typecheck", + "exitCode": 0 + }, + { + "command": "npm --prefix web run build", + "exitCode": 0 + }, + { + "command": "WBV2_BATCH_TASK=WBV2-P1148-001 WBV2_BATCH_FIXTURE=tests/files/web/modifier_reader_batch_three_scene.blend WBV2_BATCH_TYPES='[\"REMESH\",\"SKIN\",\"WEIGHTED_NORMAL\",\"WARP\"]' WBV2_BATCH_UNITS='[\"modifier-source:MOD_remesh\",\"modifier-source:MOD_skin\",\"modifier-source:MOD_weighted_normal\",\"modifier-source:MOD_warp\",\"rna-struct:RemeshModifier\",\"rna-struct:SkinModifier\",\"rna-struct:WeightedNormalModifier\",\"rna-struct:WarpModifier\"]' WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "exitCode": 0 + } + ], + "verification": { + "required": [ + "sourceHash", + "wasmBuild", + "positiveMainMutation", + "negativeNoMutation", + "undoRedo", + "saveReopen", + "aggregateManifest" + ], + "chromiumOnly": true, + "fullFamilyParity": false + }, + "inventory": { + "historical": { + "path": "tests/golden/WBV2-P0-002/parity-map.json", + "sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8", + "total": 6900, + "legacyCompleted": 281, + "legacyPending": 6618, + "effectiveCompleted": 290, + "effectivePending": 6609, + "mutation": "forbidden_by_module_execution" + }, + "dynamic": { + "path": "tests/golden/WBV2/dynamic-inventory.json", + "sha256": "e0c77f91e748bc9341498821590c5acd2e708c97716b7e427efd97770d670d76", + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "unitCount": 3745, + "planningEstimate": 5200, + "hardTarget": false, + "verifiedUnits": 377, + "unverifiedUnits": 3368 + } + }, + "nextTask": null +} diff --git a/tests/golden/WBV2-P1148-001/module-run.log b/tests/golden/WBV2-P1148-001/module-run.log new file mode 100644 index 000000000..f0ffa82d0 --- /dev/null +++ b/tests/golden/WBV2-P1148-001/module-run.log @@ -0,0 +1,49 @@ +> source tools/web/emscripten-env.sh && cmake --build build_web_blender6 --target web_engine -- -j8 && cp build_web_blender6/bin/web_engine.wasm web/app/src/vendor/blender/web_engine.wasm && cp build_web_blender6/bin/web_engine.wasm web/app/public/vendor/blender/web_engine.wasm +ninja: no work to do. + +> npm --prefix web run typecheck + +> blender-web-editor@0.1.0-rc.1 typecheck +> tsc -p tsconfig.json --noEmit + + +> npm --prefix web run build + +> blender-web-editor@0.1.0-rc.1 build +> tsc -p tsconfig.json && vite build --config app/vite.config.ts + +vite v8.2.0 building client environment for production... + transforming...✓ 102 modules transformed. +rendering chunks... +computing gzip size... +dist/index.html 0.46 kB │ gzip: 0.30 kB +dist/assets/storage.worker-D9TqXsGS.js 66.59 kB +dist/assets/web-engine.worker-BfTMiTY1.js 362.11 kB +dist/assets/viewport-render.worker-BKnJyAEz.js 634.08 kB +dist/assets/web_engine-CjnzAIfx.wasm 16,238.37 kB │ gzip: 3,856.73 kB +dist/assets/index-BgTbQCE2.css 15.35 kB │ gzip: 3.91 kB +dist/assets/index-C3AJuKSc.js 1,190.30 kB │ gzip: 316.69 kB + +✓ built in 478ms +[plugin rolldown:vite-resolve] Module "module" has been externalized for browser compatibility, imported by "/home/mes123456/workinf_Blender_Wasm/web/app/src/vendor/blender/web_engine.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details. +[plugin builtin:vite-reporter] +(!) Some chunks are larger than 500 kB after minification. Consider: +- Using dynamic import() to code-split the application +- Use build.rolldownOptions.output.codeSplitting to improve chunking: https://rolldown.rs/reference/OutputOptions.codeSplitting +- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. + +> WBV2_BATCH_TASK=WBV2-P1148-001 WBV2_BATCH_FIXTURE=tests/files/web/modifier_reader_batch_three_scene.blend WBV2_BATCH_TYPES='["REMESH","SKIN","WEIGHTED_NORMAL","WARP"]' WBV2_BATCH_UNITS='["modifier-source:MOD_remesh","modifier-source:MOD_skin","modifier-source:MOD_weighted_normal","modifier-source:MOD_warp","rna-struct:RemeshModifier","rna-struct:SkinModifier","rna-struct:WeightedNormalModifier","rna-struct:WarpModifier"]' WEB_TEST_PORT=5371 npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts + +> blender-web-editor@0.1.0-rc.1 test:e2e +> playwright test --config playwright.config.ts --workers=1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts + + +Running 1 test using 1 worker + + ✓ 1 tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts:15:1 › second modifier reader batch preserves concrete Blender Main metadata (2.0s) + + 1 passed (2.8s) +[WebServer] (node:135365) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +[WebServer] (Use `node --trace-warnings ...` to show where the warning was created) +(node:135419) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) diff --git a/tests/golden/WBV2-P1148-001/scheduler-child.log b/tests/golden/WBV2-P1148-001/scheduler-child.log new file mode 100644 index 000000000..e69de29bb diff --git a/tests/golden/WBV2-P1148-001/task-context.json b/tests/golden/WBV2-P1148-001/task-context.json new file mode 100644 index 000000000..2f7b495d3 --- /dev/null +++ b/tests/golden/WBV2-P1148-001/task-context.json @@ -0,0 +1,187 @@ +{ + "schemaVersion": 1, + "task": "WBV2-P1148-001", + "parentTask": "WBV2-P1148-000", + "status": "done", + "goal": "以一个共享 Blender Main reader、WASM build、Worker 路由和 Chromium receipt 批量验证 MOD_remesh, MOD_skin, MOD_weighted_normal, MOD_warp 的真实 modifier/RNA 元数据。", + "scope": { + "gap": "capability:MODIFIER_READER_BATCH_THREE", + "ownerFamily": "MODIFIER", + "implementationClass": "LOCAL_EXACT" + }, + "commands": [ + "node tools/web/check-task-context.mjs --task WBV2-P1148-001 --write" + ], + "inputPaths": [], + "inputSelection": { + "schemaVersion": 1, + "limits": { + "maxFiles": 12, + "evidenceBytes": 8192, + "contextRemainingBytes": 2067, + "contextRemainingTokens": 515 + }, + "source": { + "bytes": 7837, + "tokens": 1961 + }, + "selected": [], + "excluded": [ + { + "path": "blender-5.2.0/source/blender/modifiers/intern/", + "bytes": 10155, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "bytes": 521651, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp", + "bytes": 313993, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "tests/files/web/modifier_reader_batch_three_scene.blend", + "bytes": 98640, + "reason": "EVIDENCE_BYTE_BUDGET" + }, + { + "path": "web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts", + "bytes": 4082, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1148-001/module-receipt.json", + "bytes": 6746, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "bytes": 5661, + "reason": "CONTEXT_REMAINING_SPACE" + }, + { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + }, + { + "path": "docs/status/WBV2-P1148-001.md", + "bytes": null, + "reason": "GENERATED_EVIDENCE_OUTPUT" + } + ], + "totals": { + "files": 0, + "bytes": 0, + "tokens": 0 + } + }, + "exitCriteria": [ + "source and protocol hashes are bound", + "every selected Main reader type is proven", + "negative no-mutation and recovery are proven", + "Chromium and save/reopen evidence are exact" + ], + "nextTask": null, + "sourceDocuments": { + "queue": "docs/EXECUTION_QUEUE.md", + "taskCard": "docs/tasks/WBV2-P1148-001.md", + "taskIndex": "tests/golden/WBV2/task-index.json", + "parentManifest": "tests/golden/WBV2-P1148-000/manifest.json", + "parentStatus": "docs/status/WBV2-P1148-000.md" + }, + "readPolicy": { + "required": [ + "docs/EXECUTION_QUEUE.md", + "docs/tasks/WBV2-P1148-001.md", + "tests/golden/WBV2-P1148-000/manifest.json", + "docs/status/WBV2-P1148-000.md" + ], + "machineOnly": [ + "tests/golden/WBV2/task-index.json", + "tests/golden/M15-03A/task-catalog.jsonl" + ], + "optionalByNeed": [ + "docs/WEB_BLENDER_MODELER_V1_SCOPE.md", + "任务卡列出的精确协议/生产路径", + "任务卡明确命名的长期计划小节" + ], + "forbiddenByDefault": [ + "完整 CURRENT_EXECUTION_PLAN.md", + "完整 PROJECT_STATUS_AND_NEXT_WORK.md", + "全部 docs/status/*.md", + "完整 parity/WBS 计划", + "README 历史和 test-results/" + ] + }, + "parent": { + "manifest": { + "schemaVersion": 1, + "task": "WBV2-P1148-000", + "parentTask": "WBV2-P1147-001", + "status": "done", + "nextTask": "WBV2-P1148-001", + "artifactCount": 4 + }, + "statusSummary": [ + "# WBV2-P1148-000 status", + "- task: `WBV2-P1148-000`; parent: `WBV2-P1147-001`; status: `done`", + "- taskClass: `QUEUE_ENABLEMENT`; no modifier-family parity completion claimed", + "- source-backed batch authorized: `MODIFIER_READER_BATCH_THREE` (8 units)", + "- dynamic inventory: `3745` units; verified `369`; unverified `3376`; bound delta `0`", + "- nextTask: `WBV2-P1148-001`" + ] + }, + "budgets": { + "queueBytes": 4096, + "taskBytes": 2266, + "parentManifestBytes": 24576, + "parentStatusBytes": 6144, + "evidenceFiles": 12, + "evidenceBytes": 8192, + "contextTokens": 3500, + "contextEnvelopeTokens": 1024, + "taskLines": 46, + "taskTokens": 567 + }, + "size": { + "documents": [ + { + "path": "docs/EXECUTION_QUEUE.md", + "bytes": 3830, + "lines": 56, + "tokens": 958 + }, + { + "path": "docs/tasks/WBV2-P1148-001.md", + "bytes": 2266, + "lines": 46, + "tokens": 567 + }, + { + "path": "tests/golden/WBV2-P1148-000/manifest.json", + "bytes": 1382, + "lines": 43, + "tokens": 346 + }, + { + "path": "docs/status/WBV2-P1148-000.md", + "bytes": 359, + "lines": 8, + "tokens": 90 + } + ], + "sourceTokens": 1961, + "evidenceFiles": 0, + "evidenceBytes": 0, + "evidenceTokens": 0, + "totalTokens": 1961, + "reservedEnvelopeTokens": 1024, + "estimatedContextTokens": 2985, + "serializedContextTokens": 653, + "withinBudget": true + } +} diff --git a/tests/golden/WBV2/dynamic-coverage-audit.json b/tests/golden/WBV2/dynamic-coverage-audit.json index 7504aaf94..35383fa64 100644 --- a/tests/golden/WBV2/dynamic-coverage-audit.json +++ b/tests/golden/WBV2/dynamic-coverage-audit.json @@ -5,11 +5,11 @@ "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", "dynamicInventory": { "path": "tests/golden/WBV2/dynamic-inventory.json", - "beforeSha256": "e56a699f90f434e2c00c8bfe4e7e4af7a9c17cca384521abc90edd7d481187c8", - "afterSha256": "3cf5795f89066d759400fa206b559020e27c157708febdab393fa978303a79aa", + "beforeSha256": "02a76d4b766c5e921edc9a0b162f5be3ebc7218aee56dd63e31593817c231763", + "afterSha256": "6ccf20cd15cf065e6432c209afa7e32557e619837f7880f0f38a2bc01ccaa02d", "unitCount": 3745, - "verifiedUnits": 350, - "unverifiedUnits": 3395 + "verifiedUnits": 377, + "unverifiedUnits": 3368 }, "explicitBindings": [ { @@ -7011,12 +7011,552 @@ }, "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_datatransfer", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_dynamicpaint", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_explode", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_fluid", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:DataTransferModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7542, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:DynamicPaintModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5057, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:ExplodeModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4898, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:FluidModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5023, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:FluidDomainSettings", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "line": 1479, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_laplaciandeform", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_laplaciansmooth", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_mask", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_shrinkwrap", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:LaplacianDeformModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7318, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:LaplacianSmoothModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4484, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:MaskModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5512, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:ShrinkwrapModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5378, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_correctivesmooth", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:CorrectiveSmoothModifier", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4403, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_remesh", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_skin", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_weighted_normal", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_warp", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:RemeshModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6609, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:SkinModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6993, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:WeightedNormalModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 8040, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:WarpModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 2917, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" } ], "coverageByKind": { "modifier-source": { - "verified": 33, - "unverified": 64 + "verified": 46, + "unverified": 51 }, "node": { "verified": 21, @@ -7031,8 +7571,8 @@ "unverified": 2012 }, "rna-struct": { - "verified": 194, - "unverified": 785 + "verified": 208, + "unverified": 771 }, "web-command": { "verified": 96, @@ -7041,8 +7581,8 @@ }, "coverageByFamily": { "MODIFIER": { - "verified": 33, - "unverified": 64 + "verified": 46, + "unverified": 51 }, "NODES": { "verified": 21, @@ -7057,8 +7597,8 @@ "unverified": 53 }, "RNA": { - "verified": 194, - "unverified": 785 + "verified": 208, + "unverified": 771 }, "WEB_ENGINE": { "verified": 96, diff --git a/tests/golden/WBV2/dynamic-coverage-bindings.json b/tests/golden/WBV2/dynamic-coverage-bindings.json index ac39223be..6182fd882 100644 --- a/tests/golden/WBV2/dynamic-coverage-bindings.json +++ b/tests/golden/WBV2/dynamic-coverage-bindings.json @@ -6998,5 +6998,545 @@ }, "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_datatransfer", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_dynamicpaint", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_explode", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_fluid", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:DataTransferModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7542, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:DynamicPaintModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5057, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:ExplodeModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4898, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:FluidModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5023, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:FluidDomainSettings", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "line": 1479, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_laplaciandeform", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_laplaciansmooth", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_mask", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_shrinkwrap", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:LaplacianDeformModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7318, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:LaplacianSmoothModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4484, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:MaskModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5512, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:ShrinkwrapModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5378, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_correctivesmooth", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:CorrectiveSmoothModifier", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4403, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_remesh", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_skin", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_weighted_normal", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_warp", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:RemeshModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6609, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:SkinModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6993, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:WeightedNormalModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 8040, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:WarpModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 2917, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" } ] diff --git a/tests/golden/WBV2/dynamic-coverage-manifest.json b/tests/golden/WBV2/dynamic-coverage-manifest.json index 5cea7cb1c..0db76cfc4 100644 --- a/tests/golden/WBV2/dynamic-coverage-manifest.json +++ b/tests/golden/WBV2/dynamic-coverage-manifest.json @@ -5,19 +5,19 @@ "artifacts": { "inventory": { "path": "tests/golden/WBV2/dynamic-inventory.json", - "sha256": "3cf5795f89066d759400fa206b559020e27c157708febdab393fa978303a79aa" + "sha256": "6ccf20cd15cf065e6432c209afa7e32557e619837f7880f0f38a2bc01ccaa02d" }, "inventoryManifest": { "path": "tests/golden/WBV2/dynamic-inventory-manifest.json", - "sha256": "0f440885c8e8ca401db412b0a5ec1195e79e9ab18eb731b9eae00bd8313c017c" + "sha256": "d85db305e0476115a6508fcb178d6adabc3b352b2837de9e3776722981b8e8fc" }, "bindings": { "path": "tests/golden/WBV2/dynamic-coverage-bindings.json", - "sha256": "8527415d36130b5c0e8f828fc7d402102286c21d30ceb98498ade360961990ab" + "sha256": "15da1b24eceed1de4cec27f4d47d3171163dc323247af278217920ca376c6b32" }, "report": { "path": "tests/golden/WBV2/dynamic-coverage-audit.json", - "sha256": "4e2e6bef38bfda7d068242a0e88325948d7c292014af279711fdec2ecba2e136" + "sha256": "c67af84b3229806950712079b0d05517d041823e2504a47540e8b1166df65049" }, "generator": { "path": "tools/web/reconcile-source-dynamic-coverage.mjs", @@ -26,9 +26,9 @@ }, "coverage": { "unitCount": 3745, - "verifiedUnits": 350, - "unverifiedUnits": 3395, - "boundUnitDelta": 350, + "verifiedUnits": 377, + "unverifiedUnits": 3368, + "boundUnitDelta": 8, "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202" }, "historical": { diff --git a/tests/golden/WBV2/dynamic-inventory-check-report.json b/tests/golden/WBV2/dynamic-inventory-check-report.json index 303cff233..2cf5171d7 100644 --- a/tests/golden/WBV2/dynamic-inventory-check-report.json +++ b/tests/golden/WBV2/dynamic-inventory-check-report.json @@ -24,7 +24,7 @@ }, "planningEstimate": 5200, "hardTarget": false, - "verifiedUnits": 350, - "unverifiedUnits": 3395, + "verifiedUnits": 377, + "unverifiedUnits": 3368, "deterministic": true } diff --git a/tests/golden/WBV2/dynamic-inventory-manifest.json b/tests/golden/WBV2/dynamic-inventory-manifest.json index 42c005b67..ff5af7740 100644 --- a/tests/golden/WBV2/dynamic-inventory-manifest.json +++ b/tests/golden/WBV2/dynamic-inventory-manifest.json @@ -14,11 +14,11 @@ }, "inventory": { "path": "tests/golden/WBV2/dynamic-inventory.json", - "sha256": "3cf5795f89066d759400fa206b559020e27c157708febdab393fa978303a79aa" + "sha256": "6ccf20cd15cf065e6432c209afa7e32557e619837f7880f0f38a2bc01ccaa02d" }, "report": { "path": "tests/golden/WBV2/dynamic-inventory-check-report.json", - "sha256": "f76d38d1257b3ef8e5f1677f725a76dc875a6493c85f95340f27d7701ca4576c" + "sha256": "715b24623dfbe5ef1ce60f9ddb64fb1ffd9ac4bf4ed18162dc68580adc31e1d8" }, "status": { "path": "docs/status/WBV2-DYNAMIC-INVENTORY.md", @@ -47,9 +47,9 @@ }, "planningEstimate": 5200, "hardTarget": false, - "verifiedUnits": 332, - "unverifiedUnits": 3413, - "boundCaseDelta": 272 + "verifiedUnits": 377, + "unverifiedUnits": 3368, + "boundCaseDelta": 8 }, "historical": { "initialEstimate": 6900, diff --git a/tests/golden/WBV2/dynamic-inventory.json b/tests/golden/WBV2/dynamic-inventory.json index 37a5e0237..d4e176aeb 100644 --- a/tests/golden/WBV2/dynamic-inventory.json +++ b/tests/golden/WBV2/dynamic-inventory.json @@ -77,8 +77,8 @@ "estimateDelta": -1455 }, "coverage": { - "verifiedUnits": 350, - "unverifiedUnits": 3395, + "verifiedUnits": 377, + "unverifiedUnits": 3368, "sourceMappingRequired": 3745, "inventoryMutation": "explicit_source_case_bindings_only", "lastReconciledAt": "2026-09-01" @@ -37640,7 +37640,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_correctivesmooth", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_curve", @@ -37688,7 +37708,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_datatransfer", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_decimate", @@ -37804,7 +37844,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_dynamicpaint", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_edgesplit", @@ -37852,7 +37912,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_explode", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_fluid", @@ -37866,7 +37946,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_fluid", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_grease_pencil_armature", @@ -38278,7 +38378,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_laplaciandeform", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_laplaciansmooth", @@ -38292,7 +38412,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_laplaciansmooth", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_lattice", @@ -38354,7 +38494,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_mask", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_mesh_to_volume", @@ -38692,7 +38852,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_remesh", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_screw", @@ -38754,7 +38934,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_shrinkwrap", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_simpledeform", @@ -38802,7 +39002,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_skin", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_smooth", @@ -39166,7 +39386,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_warp", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_wave", @@ -39214,7 +39454,27 @@ "evidence": "modifier-source-file" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "modifier-source:MOD_weighted_normal", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "modifier-source:MOD_weightvg_util", @@ -80164,7 +80424,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:CorrectiveSmoothModifier", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4403, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:CryptomatteEntry", @@ -80510,7 +80790,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:DataTransferModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7542, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:DecimateModifier", @@ -80806,7 +81106,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:DynamicPaintModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5057, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:DynamicPaintSurface", @@ -81008,7 +81328,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:ExplodeModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4898, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:FCurve", @@ -81688,7 +82028,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:FluidDomainSettings", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "line": 1479, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:FluidEffectorSettings", @@ -81730,7 +82090,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:FluidModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5023, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:FollowPathConstraint", @@ -83704,7 +84084,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:LaplacianDeformModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7318, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:LaplacianSmoothModifier", @@ -83718,7 +84118,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:LaplacianSmoothModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4484, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:Lattice", @@ -84964,7 +85384,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:MaskModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5512, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:MaskParent", @@ -88768,7 +89208,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:RemeshModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6609, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:RenderEngine", @@ -89824,7 +90284,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:ShrinkwrapModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5378, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:SimpleDeformModifier", @@ -89900,7 +90380,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:SkinModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6993, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:SmoothModifier", @@ -92918,7 +93418,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:WarpModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 2917, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:WaveModifier", @@ -92966,7 +93486,27 @@ "evidence": "RNA_def_struct" } ], - "coverageStatus": "UNVERIFIED" + "coverageStatus": "VERIFIED", + "coverage": { + "unitId": "rna-struct:WeightedNormalModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 8040, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + } }, { "id": "rna-struct:WeldModifier", @@ -104298,6 +104838,546 @@ }, "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_datatransfer", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_datatransfer.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_dynamicpaint", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_dynamicpaint.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_explode", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_explode.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_fluid", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_fluid.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:DataTransferModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7542, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:DynamicPaintModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5057, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:ExplodeModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4898, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:FluidModifier", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5023, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:FluidDomainSettings", + "task": "WBV2-P1146-001", + "capabilityId": "MODIFIER_READER_BATCH", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_fluid.cc", + "line": 1479, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1146-001/manifest.json", + "sha256": "94c0399e25fe0323bf13a57359c020e6b70bf5dd66006bb0d69e4069e3a71c82" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json", + "sha256": "4dd99944e5eec83d173c28ed9e205a96be0ae197ed37209d8b49f90c797d07d3" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_laplaciandeform", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciandeform.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_laplaciansmooth", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_laplaciansmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_mask", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_mask.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_shrinkwrap", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_shrinkwrap.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:LaplacianDeformModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 7318, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:LaplacianSmoothModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4484, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:MaskModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5512, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:ShrinkwrapModifier", + "task": "WBV2-P1147-001", + "capabilityId": "MODIFIER_READER_BATCH_TWO", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 5378, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1147-001/manifest.json", + "sha256": "3f9df067f99cf6fed57b971d62ab38b07738d2e6ab9c24454bce14b6edf5d18f" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1147-001/modifier-reader-batch-production.json", + "sha256": "bfd794257d3c739c026a52c6995b9cdcf1af892944eebf584937f772741edf94" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_correctivesmooth", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_correctivesmooth.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:CorrectiveSmoothModifier", + "task": "WBV2-P1145-001", + "capabilityId": "CORRECTIVE_SMOOTH_READER", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 4403, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1145-001/manifest.json", + "sha256": "bf90f285d1ef5c5255ef1dfb99656ecc3c47118c035547ef2ac258c1a43bbc96" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1145-001/corrective-smooth-production.json", + "sha256": "2afd10cbf4101867ccd6857181d439b2fad4fe54471f5562c9c056a75d1456ec" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_remesh", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_remesh.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_skin", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_skin.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_weighted_normal", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_weighted_normal.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "modifier-source:MOD_warp", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/modifiers/intern/MOD_warp.cc", + "line": 1, + "evidence": "modifier-source-file" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:RemeshModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6609, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:SkinModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 6993, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:WeightedNormalModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 8040, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" + }, + { + "unitId": "rna-struct:WarpModifier", + "task": "WBV2-P1148-001", + "capabilityId": "MODIFIER_READER_BATCH_THREE", + "sourceLocation": { + "path": "blender-5.2.0/source/blender/makesrna/intern/rna_modifier.cc", + "line": 2917, + "evidence": "RNA_def_struct" + }, + "evidenceManifest": { + "path": "tests/golden/WBV2-P1148-001/manifest.json", + "sha256": "82ed070c23f0aef0ae1f66612cd213bf1af2d8f53095c24e8d1e0235bef268f8" + }, + "productionEvidence": { + "path": "tests/golden/WBV2-P1148-001/modifier-reader-batch-production.json", + "sha256": "560a4b2eae1fec4dc85acf138bf7dd85825643aadb1dcb71acb4788d433a733c" + }, + "sourceTreeSha256": "600cb3dd441f09d9655b740735fbf8fa49ad6c14d308c68d59a29f9c338e4202", + "status": "VERIFIED" } ] } diff --git a/tests/golden/WBV2/task-catalog.jsonl b/tests/golden/WBV2/task-catalog.jsonl index 4f11a95fd..69258590e 100644 --- a/tests/golden/WBV2/task-catalog.jsonl +++ b/tests/golden/WBV2/task-catalog.jsonl @@ -69,3 +69,9 @@ {"id":"WBV2-P1144-001","gapId":"DRIVER_READER","ownerFamily":"ANIMATION","sourceTask":"1144","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["source and protocol hashes are bound","positive Main reader is proven","negative no-mutation and recovery are proven","Chromium and save/reopen evidence are exact","full-family parity remains explicit"]} {"id":"WBV2-P1145-000","gapId":"workflow:authorize_corrective_smooth_reader_module","ownerFamily":"PROGRAM","sourceTask":"1145","state":"completed","targetImplementationClass":"QUEUE_ONLY","exitCriteria":["prior evidence remains hash-bound","Corrective Smooth has explicit Blender source mapping","inventory remains source-derived","one source-backed module is active"]} {"id":"WBV2-P1145-001","gapId":"CORRECTIVE_SMOOTH_READER","ownerFamily":"MODIFIER","sourceTask":"1145","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["source and protocol hashes are bound","positive Main reader is proven","negative no-mutation and recovery are proven","Chromium and save/reopen evidence are exact","full-family parity remains explicit"]} +{"id":"WBV2-P1146-000","gapId":"workflow:authorize_modifier_reader_batch","ownerFamily":"PROGRAM","sourceTask":"1146","state":"completed","targetImplementationClass":"QUEUE_ONLY","exitCriteria":["prior evidence remains hash-bound","batch source mapping is explicit","inventory remains source-derived"]} +{"id":"WBV2-P1146-001","gapId":"MODIFIER_READER_BATCH","ownerFamily":"MODIFIER","sourceTask":"1146","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["source and protocol hashes are bound","every selected Main reader type is proven","negative no-mutation and recovery are proven","Chromium and save/reopen evidence are exact"]} +{"id":"WBV2-P1147-000","gapId":"workflow:authorize_modifier_reader_batch","ownerFamily":"PROGRAM","sourceTask":"1147","state":"completed","targetImplementationClass":"QUEUE_ONLY","exitCriteria":["prior evidence remains hash-bound","batch source mapping is explicit","inventory remains source-derived"]} +{"id":"WBV2-P1147-001","gapId":"MODIFIER_READER_BATCH_TWO","ownerFamily":"MODIFIER","sourceTask":"1147","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["source and protocol hashes are bound","every selected Main reader type is proven","negative no-mutation and recovery are proven","Chromium and save/reopen evidence are exact"]} +{"id":"WBV2-P1148-000","gapId":"workflow:authorize_modifier_reader_batch","ownerFamily":"PROGRAM","sourceTask":"1148","state":"completed","targetImplementationClass":"QUEUE_ONLY","exitCriteria":["prior evidence remains hash-bound","batch source mapping is explicit","inventory remains source-derived"]} +{"id":"WBV2-P1148-001","gapId":"MODIFIER_READER_BATCH_THREE","ownerFamily":"MODIFIER","sourceTask":"1148","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["source and protocol hashes are bound","every selected Main reader type is proven","negative no-mutation and recovery are proven","Chromium and save/reopen evidence are exact"]} diff --git a/tests/golden/WBV2/task-index.json b/tests/golden/WBV2/task-index.json index a3348f4a7..58a06636c 100644 --- a/tests/golden/WBV2/task-index.json +++ b/tests/golden/WBV2/task-index.json @@ -1 +1 @@ -{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P1145-000/module-execution-plan.json","sha256":"699800aa915ee17cb6698a348573f33e4d745909ea1e647ecb508934ee286750"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"bd146fa0e5e73c8884e0d99864c3e5fea4f82964abe6ed0c1b45bd88ac83278b"},"taskCount":71,"activeTask":null,"entries":{"WBV2-P1096-000":{"line":0,"offset":0,"length":267,"previous":"WBV2-P1095-003","next":"WBV2-P1100-000"},"WBV2-P1100-000":{"line":1,"offset":267,"length":300,"previous":"WBV2-P1096-000","next":"WBV2-P1100-001"},"WBV2-P1100-001":{"line":2,"offset":567,"length":375,"previous":"WBV2-P1100-000","next":"WBV2-P1100-002"},"WBV2-P1100-002":{"line":3,"offset":942,"length":377,"previous":"WBV2-P1100-001","next":"WBV2-P1100-003"},"WBV2-P1100-003":{"line":4,"offset":1319,"length":386,"previous":"WBV2-P1100-002","next":"WBV2-P1101-000"},"WBV2-P1101-000":{"line":5,"offset":1705,"length":374,"previous":"WBV2-P1100-003","next":"WBV2-P1101-001"},"WBV2-P1101-001":{"line":6,"offset":2079,"length":382,"previous":"WBV2-P1101-000","next":"WBV2-P1101-002"},"WBV2-P1101-002":{"line":7,"offset":2461,"length":363,"previous":"WBV2-P1101-001","next":"WBV2-P1101-003"},"WBV2-P1101-003":{"line":8,"offset":2824,"length":374,"previous":"WBV2-P1101-002","next":"WBV2-P1102-000"},"WBV2-P1102-000":{"line":9,"offset":3198,"length":365,"previous":"WBV2-P1101-003","next":"WBV2-P1102-001"},"WBV2-P1102-001":{"line":10,"offset":3563,"length":371,"previous":"WBV2-P1102-000","next":"WBV2-P1103-000"},"WBV2-P1103-000":{"line":11,"offset":3934,"length":373,"previous":"WBV2-P1102-001","next":"WBV2-P1104-000"},"WBV2-P1104-000":{"line":12,"offset":4307,"length":389,"previous":"WBV2-P1103-000","next":"WBV2-P1105-000"},"WBV2-P1105-000":{"line":13,"offset":4696,"length":426,"previous":"WBV2-P1104-000","next":"WBV2-P1106-000"},"WBV2-P1106-000":{"line":14,"offset":5122,"length":366,"previous":"WBV2-P1105-000","next":"WBV2-P1107-000"},"WBV2-P1107-000":{"line":15,"offset":5488,"length":373,"previous":"WBV2-P1106-000","next":"WBV2-P1108-000"},"WBV2-P1108-000":{"line":16,"offset":5861,"length":385,"previous":"WBV2-P1107-000","next":"WBV2-P1109-000"},"WBV2-P1109-000":{"line":17,"offset":6246,"length":397,"previous":"WBV2-P1108-000","next":"WBV2-P1110-000"},"WBV2-P1110-000":{"line":18,"offset":6643,"length":394,"previous":"WBV2-P1109-000","next":"WBV2-P1111-000"},"WBV2-P1111-000":{"line":19,"offset":7037,"length":384,"previous":"WBV2-P1110-000","next":"WBV2-P1112-000"},"WBV2-P1112-000":{"line":20,"offset":7421,"length":397,"previous":"WBV2-P1111-000","next":"WBV2-P1113-000"},"WBV2-P1113-000":{"line":21,"offset":7818,"length":393,"previous":"WBV2-P1112-000","next":"WBV2-P1114-000"},"WBV2-P1114-000":{"line":22,"offset":8211,"length":384,"previous":"WBV2-P1113-000","next":"WBV2-P1115-000"},"WBV2-P1115-000":{"line":23,"offset":8595,"length":388,"previous":"WBV2-P1114-000","next":"WBV2-P1116-000"},"WBV2-P1116-000":{"line":24,"offset":8983,"length":388,"previous":"WBV2-P1115-000","next":"WBV2-P1117-000"},"WBV2-P1117-000":{"line":25,"offset":9371,"length":413,"previous":"WBV2-P1116-000","next":"WBV2-P1118-000"},"WBV2-P1118-000":{"line":26,"offset":9784,"length":409,"previous":"WBV2-P1117-000","next":"WBV2-P1119-000"},"WBV2-P1119-000":{"line":27,"offset":10193,"length":379,"previous":"WBV2-P1118-000","next":"WBV2-P1120-000"},"WBV2-P1120-000":{"line":28,"offset":10572,"length":392,"previous":"WBV2-P1119-000","next":"WBV2-P1121-000"},"WBV2-P1121-000":{"line":29,"offset":10964,"length":375,"previous":"WBV2-P1120-000","next":"WBV2-P1122-000"},"WBV2-P1122-000":{"line":30,"offset":11339,"length":385,"previous":"WBV2-P1121-000","next":"WBV2-P1123-000"},"WBV2-P1123-000":{"line":31,"offset":11724,"length":385,"previous":"WBV2-P1122-000","next":"WBV2-P1124-000"},"WBV2-P1124-000":{"line":32,"offset":12109,"length":431,"previous":"WBV2-P1123-000","next":"WBV2-P1125-000"},"WBV2-P1125-000":{"line":33,"offset":12540,"length":406,"previous":"WBV2-P1124-000","next":"WBV2-P1126-000"},"WBV2-P1126-000":{"line":34,"offset":12946,"length":397,"previous":"WBV2-P1125-000","next":"WBV2-P1127-000"},"WBV2-P1127-000":{"line":35,"offset":13343,"length":406,"previous":"WBV2-P1126-000","next":"WBV2-P1128-000"},"WBV2-P1128-000":{"line":36,"offset":13749,"length":406,"previous":"WBV2-P1127-000","next":"WBV2-P1129-000"},"WBV2-P1129-000":{"line":37,"offset":14155,"length":331,"previous":"WBV2-P1128-000","next":"WBV2-P1129-001"},"WBV2-P1129-001":{"line":38,"offset":14486,"length":393,"previous":"WBV2-P1129-000","next":"WBV2-P1130-000"},"WBV2-P1130-000":{"line":39,"offset":14879,"length":348,"previous":"WBV2-P1129-001","next":"WBV2-P1130-001"},"WBV2-P1130-001":{"line":40,"offset":15227,"length":387,"previous":"WBV2-P1130-000","next":"WBV2-P1131-000"},"WBV2-P1131-000":{"line":41,"offset":15614,"length":349,"previous":"WBV2-P1130-001","next":"WBV2-P1131-001"},"WBV2-P1131-001":{"line":42,"offset":15963,"length":383,"previous":"WBV2-P1131-000","next":"WBV2-P1132-000"},"WBV2-P1132-000":{"line":43,"offset":16346,"length":345,"previous":"WBV2-P1131-001","next":"WBV2-P1132-001"},"WBV2-P1132-001":{"line":44,"offset":16691,"length":380,"previous":"WBV2-P1132-000","next":"WBV2-P1133-000"},"WBV2-P1133-000":{"line":45,"offset":17071,"length":346,"previous":"WBV2-P1132-001","next":"WBV2-P1133-001"},"WBV2-P1133-001":{"line":46,"offset":17417,"length":387,"previous":"WBV2-P1133-000","next":"WBV2-P1134-000"},"WBV2-P1134-000":{"line":47,"offset":17804,"length":353,"previous":"WBV2-P1133-001","next":"WBV2-P1134-001"},"WBV2-P1134-001":{"line":48,"offset":18157,"length":392,"previous":"WBV2-P1134-000","next":"WBV2-P1135-000"},"WBV2-P1135-000":{"line":49,"offset":18549,"length":339,"previous":"WBV2-P1134-001","next":"WBV2-P1135-001"},"WBV2-P1135-001":{"line":50,"offset":18888,"length":385,"previous":"WBV2-P1135-000","next":"WBV2-P1136-000"},"WBV2-P1136-000":{"line":51,"offset":19273,"length":349,"previous":"WBV2-P1135-001","next":"WBV2-P1136-001"},"WBV2-P1136-001":{"line":52,"offset":19622,"length":391,"previous":"WBV2-P1136-000","next":"WBV2-P1137-000"},"WBV2-P1137-000":{"line":53,"offset":20013,"length":354,"previous":"WBV2-P1136-001","next":"WBV2-P1137-001"},"WBV2-P1137-001":{"line":54,"offset":20367,"length":393,"previous":"WBV2-P1137-000","next":"WBV2-P1138-000"},"WBV2-P1138-000":{"line":55,"offset":20760,"length":340,"previous":"WBV2-P1137-001","next":"WBV2-P1138-001"},"WBV2-P1138-001":{"line":56,"offset":21100,"length":388,"previous":"WBV2-P1138-000","next":"WBV2-P1139-000"},"WBV2-P1139-000":{"line":57,"offset":21488,"length":344,"previous":"WBV2-P1138-001","next":"WBV2-P1139-001"},"WBV2-P1139-001":{"line":58,"offset":21832,"length":393,"previous":"WBV2-P1139-000","next":"WBV2-P1140-000"},"WBV2-P1140-000":{"line":59,"offset":22225,"length":362,"previous":"WBV2-P1139-001","next":"WBV2-P1140-001"},"WBV2-P1140-001":{"line":60,"offset":22587,"length":382,"previous":"WBV2-P1140-000","next":"WBV2-P1141-000"},"WBV2-P1141-000":{"line":61,"offset":22969,"length":368,"previous":"WBV2-P1140-001","next":"WBV2-P1141-001"},"WBV2-P1141-001":{"line":62,"offset":23337,"length":389,"previous":"WBV2-P1141-000","next":"WBV2-P1142-000"},"WBV2-P1142-000":{"line":63,"offset":23726,"length":364,"previous":"WBV2-P1141-001","next":"WBV2-P1142-001"},"WBV2-P1142-001":{"line":64,"offset":24090,"length":383,"previous":"WBV2-P1142-000","next":"WBV2-P1143-000"},"WBV2-P1143-000":{"line":65,"offset":24473,"length":369,"previous":"WBV2-P1142-001","next":"WBV2-P1143-001"},"WBV2-P1143-001":{"line":66,"offset":24842,"length":385,"previous":"WBV2-P1143-000","next":"WBV2-P1144-000"},"WBV2-P1144-000":{"line":67,"offset":25227,"length":351,"previous":"WBV2-P1143-001","next":"WBV2-P1144-001"},"WBV2-P1144-001":{"line":68,"offset":25578,"length":376,"previous":"WBV2-P1144-000","next":"WBV2-P1145-000"},"WBV2-P1145-000":{"line":69,"offset":25954,"length":371,"previous":"WBV2-P1144-001","next":"WBV2-P1145-001"},"WBV2-P1145-001":{"line":70,"offset":26325,"length":386,"previous":"WBV2-P1145-000","next":null}}} +{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P1148-000/module-execution-plan.json","sha256":"ddef158adc3211d9cf86d38c288dd9c2ce47c32abae400d2b5929838044e139f"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"347fc73617a2505e938fce540ba64cf98b250d30a9415c9fcffde7bb86bba1ea"},"taskCount":77,"activeTask":null,"entries":{"WBV2-P1096-000":{"line":0,"offset":0,"length":267,"previous":"WBV2-P1095-003","next":"WBV2-P1100-000"},"WBV2-P1100-000":{"line":1,"offset":267,"length":300,"previous":"WBV2-P1096-000","next":"WBV2-P1100-001"},"WBV2-P1100-001":{"line":2,"offset":567,"length":375,"previous":"WBV2-P1100-000","next":"WBV2-P1100-002"},"WBV2-P1100-002":{"line":3,"offset":942,"length":377,"previous":"WBV2-P1100-001","next":"WBV2-P1100-003"},"WBV2-P1100-003":{"line":4,"offset":1319,"length":386,"previous":"WBV2-P1100-002","next":"WBV2-P1101-000"},"WBV2-P1101-000":{"line":5,"offset":1705,"length":374,"previous":"WBV2-P1100-003","next":"WBV2-P1101-001"},"WBV2-P1101-001":{"line":6,"offset":2079,"length":382,"previous":"WBV2-P1101-000","next":"WBV2-P1101-002"},"WBV2-P1101-002":{"line":7,"offset":2461,"length":363,"previous":"WBV2-P1101-001","next":"WBV2-P1101-003"},"WBV2-P1101-003":{"line":8,"offset":2824,"length":374,"previous":"WBV2-P1101-002","next":"WBV2-P1102-000"},"WBV2-P1102-000":{"line":9,"offset":3198,"length":365,"previous":"WBV2-P1101-003","next":"WBV2-P1102-001"},"WBV2-P1102-001":{"line":10,"offset":3563,"length":371,"previous":"WBV2-P1102-000","next":"WBV2-P1103-000"},"WBV2-P1103-000":{"line":11,"offset":3934,"length":373,"previous":"WBV2-P1102-001","next":"WBV2-P1104-000"},"WBV2-P1104-000":{"line":12,"offset":4307,"length":389,"previous":"WBV2-P1103-000","next":"WBV2-P1105-000"},"WBV2-P1105-000":{"line":13,"offset":4696,"length":426,"previous":"WBV2-P1104-000","next":"WBV2-P1106-000"},"WBV2-P1106-000":{"line":14,"offset":5122,"length":366,"previous":"WBV2-P1105-000","next":"WBV2-P1107-000"},"WBV2-P1107-000":{"line":15,"offset":5488,"length":373,"previous":"WBV2-P1106-000","next":"WBV2-P1108-000"},"WBV2-P1108-000":{"line":16,"offset":5861,"length":385,"previous":"WBV2-P1107-000","next":"WBV2-P1109-000"},"WBV2-P1109-000":{"line":17,"offset":6246,"length":397,"previous":"WBV2-P1108-000","next":"WBV2-P1110-000"},"WBV2-P1110-000":{"line":18,"offset":6643,"length":394,"previous":"WBV2-P1109-000","next":"WBV2-P1111-000"},"WBV2-P1111-000":{"line":19,"offset":7037,"length":384,"previous":"WBV2-P1110-000","next":"WBV2-P1112-000"},"WBV2-P1112-000":{"line":20,"offset":7421,"length":397,"previous":"WBV2-P1111-000","next":"WBV2-P1113-000"},"WBV2-P1113-000":{"line":21,"offset":7818,"length":393,"previous":"WBV2-P1112-000","next":"WBV2-P1114-000"},"WBV2-P1114-000":{"line":22,"offset":8211,"length":384,"previous":"WBV2-P1113-000","next":"WBV2-P1115-000"},"WBV2-P1115-000":{"line":23,"offset":8595,"length":388,"previous":"WBV2-P1114-000","next":"WBV2-P1116-000"},"WBV2-P1116-000":{"line":24,"offset":8983,"length":388,"previous":"WBV2-P1115-000","next":"WBV2-P1117-000"},"WBV2-P1117-000":{"line":25,"offset":9371,"length":413,"previous":"WBV2-P1116-000","next":"WBV2-P1118-000"},"WBV2-P1118-000":{"line":26,"offset":9784,"length":409,"previous":"WBV2-P1117-000","next":"WBV2-P1119-000"},"WBV2-P1119-000":{"line":27,"offset":10193,"length":379,"previous":"WBV2-P1118-000","next":"WBV2-P1120-000"},"WBV2-P1120-000":{"line":28,"offset":10572,"length":392,"previous":"WBV2-P1119-000","next":"WBV2-P1121-000"},"WBV2-P1121-000":{"line":29,"offset":10964,"length":375,"previous":"WBV2-P1120-000","next":"WBV2-P1122-000"},"WBV2-P1122-000":{"line":30,"offset":11339,"length":385,"previous":"WBV2-P1121-000","next":"WBV2-P1123-000"},"WBV2-P1123-000":{"line":31,"offset":11724,"length":385,"previous":"WBV2-P1122-000","next":"WBV2-P1124-000"},"WBV2-P1124-000":{"line":32,"offset":12109,"length":431,"previous":"WBV2-P1123-000","next":"WBV2-P1125-000"},"WBV2-P1125-000":{"line":33,"offset":12540,"length":406,"previous":"WBV2-P1124-000","next":"WBV2-P1126-000"},"WBV2-P1126-000":{"line":34,"offset":12946,"length":397,"previous":"WBV2-P1125-000","next":"WBV2-P1127-000"},"WBV2-P1127-000":{"line":35,"offset":13343,"length":406,"previous":"WBV2-P1126-000","next":"WBV2-P1128-000"},"WBV2-P1128-000":{"line":36,"offset":13749,"length":406,"previous":"WBV2-P1127-000","next":"WBV2-P1129-000"},"WBV2-P1129-000":{"line":37,"offset":14155,"length":331,"previous":"WBV2-P1128-000","next":"WBV2-P1129-001"},"WBV2-P1129-001":{"line":38,"offset":14486,"length":393,"previous":"WBV2-P1129-000","next":"WBV2-P1130-000"},"WBV2-P1130-000":{"line":39,"offset":14879,"length":348,"previous":"WBV2-P1129-001","next":"WBV2-P1130-001"},"WBV2-P1130-001":{"line":40,"offset":15227,"length":387,"previous":"WBV2-P1130-000","next":"WBV2-P1131-000"},"WBV2-P1131-000":{"line":41,"offset":15614,"length":349,"previous":"WBV2-P1130-001","next":"WBV2-P1131-001"},"WBV2-P1131-001":{"line":42,"offset":15963,"length":383,"previous":"WBV2-P1131-000","next":"WBV2-P1132-000"},"WBV2-P1132-000":{"line":43,"offset":16346,"length":345,"previous":"WBV2-P1131-001","next":"WBV2-P1132-001"},"WBV2-P1132-001":{"line":44,"offset":16691,"length":380,"previous":"WBV2-P1132-000","next":"WBV2-P1133-000"},"WBV2-P1133-000":{"line":45,"offset":17071,"length":346,"previous":"WBV2-P1132-001","next":"WBV2-P1133-001"},"WBV2-P1133-001":{"line":46,"offset":17417,"length":387,"previous":"WBV2-P1133-000","next":"WBV2-P1134-000"},"WBV2-P1134-000":{"line":47,"offset":17804,"length":353,"previous":"WBV2-P1133-001","next":"WBV2-P1134-001"},"WBV2-P1134-001":{"line":48,"offset":18157,"length":392,"previous":"WBV2-P1134-000","next":"WBV2-P1135-000"},"WBV2-P1135-000":{"line":49,"offset":18549,"length":339,"previous":"WBV2-P1134-001","next":"WBV2-P1135-001"},"WBV2-P1135-001":{"line":50,"offset":18888,"length":385,"previous":"WBV2-P1135-000","next":"WBV2-P1136-000"},"WBV2-P1136-000":{"line":51,"offset":19273,"length":349,"previous":"WBV2-P1135-001","next":"WBV2-P1136-001"},"WBV2-P1136-001":{"line":52,"offset":19622,"length":391,"previous":"WBV2-P1136-000","next":"WBV2-P1137-000"},"WBV2-P1137-000":{"line":53,"offset":20013,"length":354,"previous":"WBV2-P1136-001","next":"WBV2-P1137-001"},"WBV2-P1137-001":{"line":54,"offset":20367,"length":393,"previous":"WBV2-P1137-000","next":"WBV2-P1138-000"},"WBV2-P1138-000":{"line":55,"offset":20760,"length":340,"previous":"WBV2-P1137-001","next":"WBV2-P1138-001"},"WBV2-P1138-001":{"line":56,"offset":21100,"length":388,"previous":"WBV2-P1138-000","next":"WBV2-P1139-000"},"WBV2-P1139-000":{"line":57,"offset":21488,"length":344,"previous":"WBV2-P1138-001","next":"WBV2-P1139-001"},"WBV2-P1139-001":{"line":58,"offset":21832,"length":393,"previous":"WBV2-P1139-000","next":"WBV2-P1140-000"},"WBV2-P1140-000":{"line":59,"offset":22225,"length":362,"previous":"WBV2-P1139-001","next":"WBV2-P1140-001"},"WBV2-P1140-001":{"line":60,"offset":22587,"length":382,"previous":"WBV2-P1140-000","next":"WBV2-P1141-000"},"WBV2-P1141-000":{"line":61,"offset":22969,"length":368,"previous":"WBV2-P1140-001","next":"WBV2-P1141-001"},"WBV2-P1141-001":{"line":62,"offset":23337,"length":389,"previous":"WBV2-P1141-000","next":"WBV2-P1142-000"},"WBV2-P1142-000":{"line":63,"offset":23726,"length":364,"previous":"WBV2-P1141-001","next":"WBV2-P1142-001"},"WBV2-P1142-001":{"line":64,"offset":24090,"length":383,"previous":"WBV2-P1142-000","next":"WBV2-P1143-000"},"WBV2-P1143-000":{"line":65,"offset":24473,"length":369,"previous":"WBV2-P1142-001","next":"WBV2-P1143-001"},"WBV2-P1143-001":{"line":66,"offset":24842,"length":385,"previous":"WBV2-P1143-000","next":"WBV2-P1144-000"},"WBV2-P1144-000":{"line":67,"offset":25227,"length":351,"previous":"WBV2-P1143-001","next":"WBV2-P1144-001"},"WBV2-P1144-001":{"line":68,"offset":25578,"length":376,"previous":"WBV2-P1144-000","next":"WBV2-P1145-000"},"WBV2-P1145-000":{"line":69,"offset":25954,"length":371,"previous":"WBV2-P1144-001","next":"WBV2-P1145-001"},"WBV2-P1145-001":{"line":70,"offset":26325,"length":386,"previous":"WBV2-P1145-000","next":"WBV2-P1146-000"},"WBV2-P1146-000":{"line":71,"offset":26711,"length":303,"previous":"WBV2-P1145-001","next":"WBV2-P1146-001"},"WBV2-P1146-001":{"line":72,"offset":27014,"length":356,"previous":"WBV2-P1146-000","next":"WBV2-P1147-000"},"WBV2-P1147-000":{"line":73,"offset":27370,"length":303,"previous":"WBV2-P1146-001","next":"WBV2-P1147-001"},"WBV2-P1147-001":{"line":74,"offset":27673,"length":360,"previous":"WBV2-P1147-000","next":"WBV2-P1148-000"},"WBV2-P1148-000":{"line":75,"offset":28033,"length":303,"previous":"WBV2-P1147-001","next":"WBV2-P1148-001"},"WBV2-P1148-001":{"line":76,"offset":28336,"length":362,"previous":"WBV2-P1148-000","next":null}}} diff --git a/tools/web/bind-wbv2-module-coverage.mjs b/tools/web/bind-wbv2-module-coverage.mjs new file mode 100644 index 000000000..edcde5436 --- /dev/null +++ b/tools/web/bind-wbv2-module-coverage.mjs @@ -0,0 +1,114 @@ +import assert from "node:assert/strict"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); +const abs = (file) => path.join(root, file); +const read = (file) => fs.readFileSync(abs(file), "utf8"); +const json = (file) => JSON.parse(read(file)); +const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex"); +const arg = (name, fallback = null) => { + const index = process.argv.indexOf(name); + return index >= 0 ? process.argv[index + 1] : fallback; +}; +const task = arg("--task"); +if (!task) throw new Error("usage: node tools/web/bind-wbv2-module-coverage.mjs --task "); +const manifestPath = `tests/golden/${task}/manifest.json`; +const productionPath = arg("--production", `tests/golden/${task}/modifier-reader-batch-production.json`); +const manifest = json(manifestPath); +assert.equal(manifest.status, "done"); +const moduleRecord = Object.values(json("tests/golden/WBV2-P1100-000/module-execution-plan.json").tasks ?? {}) + .find((candidate) => candidate.id === task); +const planPath = manifest.artifacts.plan.path; +const plan = json(planPath); +const taskRecord = plan.tasks.find((candidate) => candidate.id === task); +const module = taskRecord?.module; +const requestedUnits = (arg("--units") ?? "").split(",").map((value) => value.trim()).filter(Boolean); +const coverageBindings = requestedUnits.length > 0 ? requestedUnits : module?.coverageBindings ?? []; +const capabilityId = module?.moduleId ?? arg("--capability", task); +if (!coverageBindings.length) throw new Error(`task ${task} has no coverageBindings`); +const production = json(productionPath); +assert.equal(production.browser, "chromium"); +assert.equal(production.queueMutation, false); +assert.equal(production.error, undefined); +assert.equal(production.saveReopenExact, true); +assert.equal(production.deterministicExact, true); +const inventoryPath = "tests/golden/WBV2/dynamic-inventory.json"; +const inventory = json(inventoryPath); +assert.equal(production.fixtureSha256, sha(production.fixture)); +const bindingsPath = "tests/golden/WBV2/dynamic-coverage-bindings.json"; +const existing = fs.existsSync(abs(bindingsPath)) ? json(bindingsPath) : []; +const byId = new Map(existing.map((binding) => [binding.unitId, binding])); +for (const unitId of coverageBindings) { + const unit = inventory.units.find((candidate) => candidate.id === unitId); + assert.ok(unit, `dynamic unit missing: ${unitId}`); + if (unit.coverageStatus === "VERIFIED") { + assert.equal(byId.get(unitId)?.task, task, `dynamic unit already belongs to another task: ${unitId}`); + } + const sourceLocation = unit.locations?.[0]; + assert.ok(sourceLocation?.path, `source location missing: ${unitId}`); + byId.set(unitId, { + unitId, + task, + capabilityId, + sourceLocation, + evidenceManifest: { path: manifestPath, sha256: sha(manifestPath) }, + productionEvidence: { path: productionPath, sha256: sha(productionPath) }, + sourceTreeSha256: inventory.authority.sourceTreeSha256, + status: "VERIFIED", + }); +} +const bindings = [...byId.values()]; +const verifiedIds = new Set(bindings.map((binding) => binding.unitId)); +const updatedUnits = inventory.units.map((unit) => verifiedIds.has(unit.id) + ? { ...unit, coverageStatus: "VERIFIED", coverage: bindings.find((binding) => binding.unitId === unit.id) } + : { ...unit, coverageStatus: "UNVERIFIED", ...(unit.coverage ? {} : {}) }); +const verifiedUnits = updatedUnits.filter((unit) => unit.coverageStatus === "VERIFIED").length; +const updated = { + ...inventory, + coverage: { ...inventory.coverage, verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits, sourceMappingRequired: inventory.summary.unitCount, inventoryMutation: "explicit_source_case_bindings_only", lastReconciledAt: "2026-09-01" }, + units: updatedUnits, + coverageLedger: bindings, +}; +fs.writeFileSync(abs(bindingsPath), `${JSON.stringify(bindings, null, 2)}\n`); +fs.writeFileSync(abs(inventoryPath), `${JSON.stringify(updated, null, 2)}\n`); +const coverageManifestPath = "tests/golden/WBV2/dynamic-coverage-manifest.json"; +if (fs.existsSync(abs(coverageManifestPath))) { + const coverageManifest = json(coverageManifestPath); + coverageManifest.artifacts.inventory.sha256 = sha(inventoryPath); + coverageManifest.artifacts.bindings.sha256 = sha(bindingsPath); + coverageManifest.coverage = { ...coverageManifest.coverage, unitCount: inventory.summary.unitCount, verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits, boundUnitDelta: coverageBindings.length, sourceTreeSha256: inventory.authority.sourceTreeSha256 }; + fs.writeFileSync(abs(coverageManifestPath), `${JSON.stringify(coverageManifest, null, 2)}\n`); +} +const inventoryManifestPath = "tests/golden/WBV2/dynamic-inventory-manifest.json"; +if (fs.existsSync(abs(inventoryManifestPath))) { + const inventoryManifest = json(inventoryManifestPath); + if (inventoryManifest.artifacts?.inventory) inventoryManifest.artifacts.inventory.sha256 = sha(inventoryPath); + if (inventoryManifest.inventory) { + inventoryManifest.inventory.verifiedUnits = verifiedUnits; + inventoryManifest.inventory.unverifiedUnits = inventory.summary.unitCount - verifiedUnits; + inventoryManifest.inventory.boundCaseDelta = coverageBindings.length; + } + fs.writeFileSync(abs(inventoryManifestPath), `${JSON.stringify(inventoryManifest, null, 2)}\n`); +} +const auditPath = "tests/golden/WBV2/dynamic-coverage-audit.json"; +if (fs.existsSync(abs(auditPath))) { + const audit = json(auditPath); + const coverageByKind = {}; + const coverageByFamily = {}; + for (const unit of updatedUnits) { + const kind = coverageByKind[unit.kind] ??= { verified: 0, unverified: 0 }; + const family = coverageByFamily[unit.family] ??= { verified: 0, unverified: 0 }; + const key = unit.coverageStatus === "VERIFIED" ? "verified" : "unverified"; + kind[key] += 1; + family[key] += 1; + } + audit.dynamicInventory = { ...(audit.dynamicInventory ?? {}), path: inventoryPath, afterSha256: sha(inventoryPath), unitCount: inventory.summary.unitCount, verifiedUnits, unverifiedUnits: inventory.summary.unitCount - verifiedUnits }; + audit.explicitBindings = bindings; + audit.coverageByKind = coverageByKind; + audit.coverageByFamily = coverageByFamily; + fs.writeFileSync(abs(auditPath), `${JSON.stringify(audit, null, 2)}\n`); +} +process.stdout.write(`wbv2-module-coverage-bound task=${task} module=${capabilityId} added=${coverageBindings.length} verified=${verifiedUnits} unverified=${inventory.summary.unitCount - verifiedUnits}\n`); diff --git a/tools/web/emscripten-env.sh b/tools/web/emscripten-env.sh index 5b8ca77b0..9ab8751f9 100755 --- a/tools/web/emscripten-env.sh +++ b/tools/web/emscripten-env.sh @@ -29,7 +29,19 @@ fi export WEB_EMSCRIPTEN_VERSION export EM_CONFIG="${web_workspace_root}/.emscripten-web" -export EM_CACHE="${web_workspace_root}/.emcache" +# Prefer RAM-backed compiler caches on Linux hosts with enough tmpfs space. +# The cache only contains derived Emscripten artifacts; evidence and source +# outputs remain in the repository. Callers can override either path. +if [[ -d /dev/shm && -w /dev/shm ]]; then + web_ram_cache_root="${WEB_RAM_CACHE_ROOT-/dev/shm/blender-wasm-${UID}}" + mkdir -p "${web_ram_cache_root}/emcache" "${web_ram_cache_root}/tmp" + export EM_CACHE="${EM_CACHE-${web_ram_cache_root}/emcache}" + export TMPDIR="${TMPDIR-${web_ram_cache_root}/tmp}" +else + export EM_CACHE="${EM_CACHE-${web_workspace_root}/.emcache}" +fi +export CMAKE_BUILD_PARALLEL_LEVEL="${CMAKE_BUILD_PARALLEL_LEVEL-8}" +export NINJAFLAGS="${NINJAFLAGS--j8}" export WEB_EMSCRIPTEN_CFLAGS="-sENVIRONMENT=web,worker -sMODULARIZE=1 -sEXPORT_ES6=1" export WEB_EMSCRIPTEN_LDFLAGS="-sALLOW_MEMORY_GROWTH=1 -sFILESYSTEM=1" diff --git a/tools/web/run-wbv2-module-task.mjs b/tools/web/run-wbv2-module-task.mjs new file mode 100644 index 000000000..6123d0e90 --- /dev/null +++ b/tools/web/run-wbv2-module-task.mjs @@ -0,0 +1,111 @@ +import assert from "node:assert/strict"; +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { execFileSync, spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); +const abs = (file) => path.join(root, file); +const read = (file) => fs.readFileSync(abs(file), "utf8"); +const json = (file) => JSON.parse(read(file)); +const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex"); +const dynamicInventoryPath = "tests/golden/WBV2/dynamic-inventory.json"; +const writeJson = (file, value) => { + fs.mkdirSync(path.dirname(abs(file)), { recursive: true }); + fs.writeFileSync(abs(file), `${JSON.stringify(value, null, 2)}\n`); +}; +const writeText = (file, value) => { + fs.mkdirSync(path.dirname(abs(file)), { recursive: true }); + fs.writeFileSync(abs(file), value); +}; +const taskArg = process.argv.indexOf("--task"); +const task = taskArg >= 0 ? process.argv[taskArg + 1] : null; +if (!task || !process.argv.includes("--write")) throw new Error("usage: node tools/web/run-wbv2-module-task.mjs --task --write"); + +const queue = read("docs/EXECUTION_QUEUE.md"); +const currentTask = queue.match(/\| 当前任务 \| `([^`]+)` \|/u)?.[1]; +const index = json("tests/golden/WBV2/task-index.json"); +const plan = json(index.source.path); +const dynamicInventory = json(dynamicInventoryPath); +const record = plan.tasks.find((candidate) => candidate.id === task); +if (currentTask !== task) throw new Error(`module task is not the authoritative queue task: ${currentTask}!=${task}`); +if (!record?.module) throw new Error(`task ${task} is not a module task`); +const parentId = record.dependsOn?.at(-1); +const parentPath = `tests/golden/${parentId}/manifest.json`; +const parent = json(parentPath); +if (parent.status !== "done" || parent.nextTask !== task) throw new Error(`module parent is not a completed handoff: ${parentId}`); +if (record.status !== "in_progress" || record.ready !== true) throw new Error(`module task ${task} is not active`); +if (!record.module.sourceBacked) throw new Error(`module ${record.module.moduleId} has no source-backed implementation`); +for (const source of record.module.sourcePaths ?? []) if (!fs.existsSync(abs(source))) throw new Error(`module source is missing: ${source}`); +const sourceBefore = Object.fromEntries((record.module.sourcePaths ?? []).map((source) => [source, sha(source)])); +const reusedReceipts = (record.module.reuseReceipts ?? []).map((receipt) => ({ + ...receipt, + manifestSha256: sha(receipt.manifest), + reportSha256: sha(receipt.report), +})); + +const out = `tests/golden/${task}`; +const reportPath = `${out}/module-receipt.json`; +const statusPath = `docs/status/${task}.md`; +const logPath = `${out}/module-run.log`; +const results = []; +let failed = false; +for (const command of record.module.commands ?? []) { + const result = spawnSync("bash", ["-lc", command], { cwd: root, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 }); + const output = `${result.stdout ?? ""}${result.stderr ?? ""}`; + results.push({ command, exitCode: result.status ?? 1, output }); + if ((result.status ?? 1) !== 0) { failed = true; break; } +} +fs.mkdirSync(abs(out), { recursive: true }); +writeText(logPath, results.map((result) => `> ${result.command}\n${result.output}`).join("\n")); +const sourceAfter = Object.fromEntries((record.module.sourcePaths ?? []).map((source) => [source, sha(source)])); +const sourceUnchanged = JSON.stringify(sourceBefore) === JSON.stringify(sourceAfter); +const report = { + schemaVersion: 1, + task, + operation: "MODULE_FUNCTION_EXECUTION", + moduleId: record.module.moduleId, + status: failed || !sourceUnchanged ? "BLOCKED" : "PASS", + source: { paths: record.module.sourcePaths, before: sourceBefore, after: sourceAfter, unchanged: sourceUnchanged }, + reusedReceipts, + cases: { positive: record.module.positive, negative: record.module.negative, recovery: record.module.recovery }, + commands: results.map(({ command, exitCode }) => ({ command, exitCode })), + verification: { required: plan.verificationPolicy.required, chromiumOnly: plan.verificationPolicy.browser === "chromium_only", fullFamilyParity: false }, + inventory: { historical: plan.inventory, dynamic: { path: dynamicInventoryPath, sha256: sha(dynamicInventoryPath), sourceTreeSha256: dynamicInventory.authority.sourceTreeSha256, unitCount: dynamicInventory.summary.unitCount, planningEstimate: dynamicInventory.policy.planningEstimate, hardTarget: dynamicInventory.policy.hardTarget, verifiedUnits: dynamicInventory.coverage.verifiedUnits, unverifiedUnits: dynamicInventory.coverage.unverifiedUnits } }, + nextTask: failed || !sourceUnchanged ? task : plan.tasks[plan.tasks.findIndex((candidate) => candidate.id === task) + 1]?.id ?? null, +}; +writeJson(reportPath, report); +if (failed || !sourceUnchanged) { + writeText(statusPath, `# ${task} status\n\n- task: \`${task}\`; module: \`${record.module.moduleId}\`; status: \`in_progress\`\n- module execution blocked; no queue advance or parity claim\n- source unchanged: \`${sourceUnchanged}\`; failed command: \`${results.find((result) => result.exitCode !== 0)?.command ?? "source hash drift"}\`\n- dynamic source inventory: \`${dynamicInventory.summary.unitCount}\` units; verified \`${dynamicInventory.coverage.verifiedUnits}\`; unverified \`${dynamicInventory.coverage.unverifiedUnits}\`; planning estimate \`${dynamicInventory.policy.planningEstimate}\` (non-binding)\n- historical 6900-entry inventory remains read-only\n- nextTask: \`${task}\`\n`); + process.exitCode = 2; +} else { + const nextTask = report.nextTask; + const planIndex = plan.tasks.findIndex((candidate) => candidate.id === task); + plan.tasks = plan.tasks.map((candidate, index) => index === planIndex ? { ...candidate, status: "done", ready: false } : candidate.id === nextTask ? { ...candidate, status: "in_progress", ready: true } : { ...candidate, ready: false }); + if (!nextTask) plan.status = "COMPLETED_MODULE_EXECUTION"; + writeJson(index.source.path, plan); + execFileSync(process.execPath, [abs("tools/web/generate-v2-task-index.mjs"), "--plan-path", abs(index.source.path)], { cwd: root, stdio: "inherit" }); + let updatedQueue = read("docs/EXECUTION_QUEUE.md"); + if (nextTask) updatedQueue = updatedQueue.replace(/\| 当前任务 \| `[^`]+` \|/u, `| 当前任务 | \`${nextTask}\` |`).replace(/\| parent manifest \| `[^`]+` \|/u, `| parent manifest | \`tests/golden/${task}/manifest.json\` |`).replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, `| 任务卡 | [\`tasks/${nextTask}.md\`](tasks/${nextTask}.md) |`); + writeText("docs/EXECUTION_QUEUE.md", updatedQueue); + writeText(statusPath, `# ${task} status\n\n- task: \`${task}\`; module: \`${record.module.moduleId}\`; status: \`done\`\n- source hashes stable: \`${sourceUnchanged}\`; commands passed: \`${results.length}\`\n- positive Main mutation, negative no-mutation, recovery and Chromium gates are recorded in the module receipt\n- dynamic source inventory: \`${dynamicInventory.summary.unitCount}\` units; verified \`${dynamicInventory.coverage.verifiedUnits}\`; unverified \`${dynamicInventory.coverage.unverifiedUnits}\`; planning estimate \`${dynamicInventory.policy.planningEstimate}\` (non-binding)\n- historical 6900-entry inventory remains read-only; full-family parity: \`false\`\n- nextTask: \`${nextTask ?? "NONE"}\`\n`); + execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", task, "--write"], { cwd: root, stdio: "inherit" }); + const manifestPath = `${out}/manifest.json`; + const evidenceArtifacts = Object.fromEntries((record.module.evidencePaths ?? []).filter((file) => fs.existsSync(abs(file))).map((file, item) => [`evidence${item + 1}`, { path: file, sha256: sha(file) }])); + const artifacts = { parentManifest: { path: parentPath, sha256: sha(parentPath) }, ...Object.fromEntries(record.module.sourcePaths.map((source, item) => [`source${item + 1}`, { path: source, sha256: sha(source) }])), ...evidenceArtifacts, moduleReceipt: { path: reportPath, sha256: sha(reportPath) }, status: { path: statusPath, sha256: sha(statusPath) }, log: { path: logPath, sha256: sha(logPath) }, plan: { path: index.source.path, sha256: sha(index.source.path) }, taskContext: { path: `${out}/task-context.json`, sha256: sha(`${out}/task-context.json`) } }; + writeJson(manifestPath, { schemaVersion: 1, task, parentTask: parentId, operation: "MODULE_FUNCTION_EXECUTION", taskClass: "MODULE", status: "done", enablingTask: true, parityStateChange: false, runtime: "BLENDER_WEB_FUNCTION_MODULE", artifacts, assertions: { moduleId: record.module.moduleId, sourceBacked: true, positiveCases: record.module.positive.length, negativeCases: record.module.negative.length, recoveryCases: record.module.recovery.length, commandCount: results.length, reusedReceiptCount: reusedReceipts.length, sourceUnchanged, fullFamilyParity: false, dynamicInventoryPath, dynamicSourceTreeSha256: dynamicInventory.authority.sourceTreeSha256, dynamicUnitCount: dynamicInventory.summary.unitCount, dynamicVerifiedUnits: dynamicInventory.coverage.verifiedUnits, dynamicUnverifiedUnits: dynamicInventory.coverage.unverifiedUnits, planningEstimate: dynamicInventory.policy.planningEstimate, historicalInventoryTotal: 6900, historicalEffectiveCompleted: 290, historicalEffectivePending: 6609, historicalReproduction: false }, nextTask }); + if (record.module.coverageBindings?.length) { + execFileSync(process.execPath, [abs("tools/web/bind-wbv2-module-coverage.mjs"), "--task", task], { cwd: root, stdio: "inherit" }); + } + if (nextTask) execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", nextTask, "--write"], { cwd: root, stdio: "inherit" }); + let next = read("nextTask.md"); + const tick = String.fromCharCode(96); + const snapshotTask = nextTask ?? task; + const snapshotState = nextTask ? "in_progress" : "done"; + const snapshotNext = nextTask ? plan.tasks[plan.tasks.findIndex((candidate) => candidate.id === nextTask) + 1]?.id ?? "NONE" : "NONE"; + const snapshotCommand = nextTask ? `node tools/web/run-wbv2-module-task.mjs --task ${nextTask} --write` : "node tools/web/check-wbv2-module-execution.mjs"; + next = next.replace(/\| Current task when this file was written \| `[^`]+` \|/u, `| Current task when this file was written | ${tick}${snapshotTask}${tick} |`).replace(/\| Current task state \| `[^`]+` \|/u, `| Current task state | ${tick}${snapshotState}${tick} |`).replace(/\| Parent manifest \| `[^`]+` \|/u, `| Parent manifest | ${tick}tests/golden/${task}/manifest.json${tick} |`).replace(/\| Current task card \| `[^`]+` \|/u, `| Current task card | ${tick}docs/tasks/${snapshotTask}.md${tick} |`).replace(/\| Current task-context nextTask \| `[^`]+` \|/u, `| Current task-context nextTask | ${tick}${snapshotNext}${tick} |`).replace(/\| Focused command \| `[^`]+` \|/u, `| Focused command | ${tick}${snapshotCommand}${tick} |`); + writeText("nextTask.md", next); + console.log(`module-task-complete task=${task} module=${record.module.moduleId} next=${nextTask} commands=${results.length}`); +} diff --git a/web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts b/web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts new file mode 100644 index 000000000..70a8f104d --- /dev/null +++ b/web/tests/e2e/wbv2-modifier-reader-batch-production.spec.ts @@ -0,0 +1,87 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { expect, test } from "@playwright/test"; + +const root = path.resolve(import.meta.dirname, "../../.."); +const fixturePath = path.join(root, "tests/files/web/modifier_reader_batch_scene.blend"); +const fixture = fs.readFileSync(fixturePath); +const fixtureSha256 = crypto.createHash("sha256").update(fixture).digest("hex"); +const expectedTypes = ["DATA_TRANSFER", "DYNAMIC_PAINT", "EXPLODE", "FLUID"]; + +test("modifier reader batch preserves concrete Blender Main metadata", async ({ page }) => { + test.setTimeout(180_000); + await page.goto("/"); + const result = await page.evaluate(async (bytes) => { + const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts"); + const canonical = (snapshot: any) => snapshot.meshes.flatMap((mesh: any) => + (mesh.modifierStack ?? []).map((modifier: any) => ({ + meshId: mesh.id, + uuid: modifier.uuid, + name: modifier.name, + type: modifier.type, + enabled: modifier.enabled, + evaluationStatus: modifier.evaluationStatus, + parameters: modifier.parameters ?? null, + }))); + const client = new WebEngineClient({ timeoutMs: 60_000 }); + const reopenedClient = new WebEngineClient({ timeoutMs: 60_000 }); + const secondClient = new WebEngineClient({ timeoutMs: 60_000 }); + const output: any = {}; + try { + const opened = await client.openBlend(Uint8Array.from(bytes).buffer); + output.before = canonical(opened.snapshot); + output.types = output.before.map((modifier: any) => modifier.type); + const saved = await client.saveBlend(); + output.after = canonical((await reopenedClient.openBlend(saved.slice(0))).snapshot); + output.second = canonical((await secondClient.openBlend(Uint8Array.from(bytes).buffer)).snapshot); + output.saveReopenExact = JSON.stringify(output.before) === JSON.stringify(output.after); + output.deterministicExact = JSON.stringify(output.before) === JSON.stringify(output.second); + output.savedSha256 = await crypto.subtle.digest("SHA-256", saved).then((hash) => + Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join("")); + try { + await client.openBlend(Uint8Array.from([0x42, 0x4c, 0x45, 0x4e, 0x44]).buffer); + output.malformed = { code: "ACCEPTED_MALFORMED" }; + } catch (error: any) { + output.malformed = { code: error?.code, message: error?.message }; + } + } catch (error: any) { + output.error = { code: error?.code, message: error?.message, detail: String(error) }; + } finally { + client.terminate(); + reopenedClient.terminate(); + secondClient.terminate(); + } + return output; + }, Array.from(fixture)); + + const report = { + schemaVersion: 1, + task: "WBV2-P1146-001", + operation: "MODIFIER_READER_BATCH_CHROMIUM_SAVE_REOPEN", + browser: "chromium", + queueMutation: false, + fixture: "tests/files/web/modifier_reader_batch_scene.blend", + fixtureSha256, + expectedTypes, + sourceUnits: [ + "modifier-source:MOD_datatransfer", + "modifier-source:MOD_dynamicpaint", + "modifier-source:MOD_explode", + "modifier-source:MOD_cast", + "rna-struct:DataTransferModifier", + "rna-struct:DynamicPaintModifier", + "rna-struct:ExplodeModifier", + "rna-struct:CastModifier", + ], + ...result, + }; + fs.mkdirSync(path.join(root, "tests/golden/WBV2-P1146-001"), { recursive: true }); + fs.writeFileSync(path.join(root, "tests/golden/WBV2-P1146-001/modifier-reader-batch-production.json"), `${JSON.stringify(report, null, 2)}\n`); + + expect(result.error).toBeUndefined(); + expect(result.types).toEqual(expect.arrayContaining(expectedTypes)); + expect(result.saveReopenExact).toBe(true); + expect(result.deterministicExact).toBe(true); + expect(result.malformed?.code).not.toBe("ACCEPTED_MALFORMED"); +}); diff --git a/web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts b/web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts new file mode 100644 index 000000000..82cd7f905 --- /dev/null +++ b/web/tests/e2e/wbv2-modifier-reader-batch-two-production.spec.ts @@ -0,0 +1,81 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { expect, test } from "@playwright/test"; + +const root = path.resolve(import.meta.dirname, "../../.."); +const task = process.env.WBV2_BATCH_TASK ?? "WBV2-P1147-001"; +const fixtureName = process.env.WBV2_BATCH_FIXTURE ?? "tests/files/web/modifier_reader_batch_two_scene.blend"; +const fixturePath = path.join(root, fixtureName); +const fixture = fs.readFileSync(fixturePath); +const fixtureSha256 = crypto.createHash("sha256").update(fixture).digest("hex"); +const expectedTypes = JSON.parse(process.env.WBV2_BATCH_TYPES ?? '["LAPLACIANDEFORM","LAPLACIANSMOOTH","MASK","SHRINKWRAP"]'); +const sourceUnits = JSON.parse(process.env.WBV2_BATCH_UNITS ?? '["modifier-source:MOD_laplaciandeform","modifier-source:MOD_laplaciansmooth","modifier-source:MOD_mask","modifier-source:MOD_shrinkwrap","rna-struct:LaplacianDeformModifier","rna-struct:LaplacianSmoothModifier","rna-struct:MaskModifier","rna-struct:ShrinkwrapModifier"]'); + +test("second modifier reader batch preserves concrete Blender Main metadata", async ({ page }) => { + test.setTimeout(180_000); + await page.goto("/"); + const result = await page.evaluate(async (bytes) => { + const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts"); + const canonical = (snapshot: any) => snapshot.meshes.flatMap((mesh: any) => + (mesh.modifierStack ?? []).map((modifier: any) => ({ + meshId: mesh.id, + uuid: modifier.uuid, + name: modifier.name, + type: modifier.type, + enabled: modifier.enabled, + evaluationStatus: modifier.evaluationStatus, + parameters: modifier.parameters ?? null, + }))); + const client = new WebEngineClient({ timeoutMs: 60_000 }); + const reopenedClient = new WebEngineClient({ timeoutMs: 60_000 }); + const secondClient = new WebEngineClient({ timeoutMs: 60_000 }); + const output: any = {}; + try { + const opened = await client.openBlend(Uint8Array.from(bytes).buffer); + output.before = canonical(opened.snapshot); + output.types = output.before.map((modifier: any) => modifier.type); + const saved = await client.saveBlend(); + output.after = canonical((await reopenedClient.openBlend(saved.slice(0))).snapshot); + output.second = canonical((await secondClient.openBlend(Uint8Array.from(bytes).buffer)).snapshot); + output.saveReopenExact = JSON.stringify(output.before) === JSON.stringify(output.after); + output.deterministicExact = JSON.stringify(output.before) === JSON.stringify(output.second); + output.savedSha256 = await crypto.subtle.digest("SHA-256", saved).then((hash) => + Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join("")); + try { + await client.openBlend(Uint8Array.from([0x42, 0x4c, 0x45, 0x4e, 0x44]).buffer); + output.malformed = { code: "ACCEPTED_MALFORMED" }; + } catch (error: any) { + output.malformed = { code: error?.code, message: error?.message }; + } + } catch (error: any) { + output.error = { code: error?.code, message: error?.message, detail: String(error) }; + } finally { + client.terminate(); + reopenedClient.terminate(); + secondClient.terminate(); + } + return output; + }, Array.from(fixture)); + + const report = { + schemaVersion: 1, + task, + operation: "MODIFIER_READER_BATCH_TWO_CHROMIUM_SAVE_REOPEN", + browser: "chromium", + queueMutation: false, + fixture: fixtureName, + fixtureSha256, + expectedTypes, + sourceUnits, + ...result, + }; + fs.mkdirSync(path.join(root, `tests/golden/${task}`), { recursive: true }); + fs.writeFileSync(path.join(root, `tests/golden/${task}/modifier-reader-batch-production.json`), `${JSON.stringify(report, null, 2)}\n`); + + expect(result.error).toBeUndefined(); + expect(result.types).toEqual(expect.arrayContaining(expectedTypes)); + expect(result.saveReopenExact).toBe(true); + expect(result.deterministicExact).toBe(true); + expect(result.malformed?.code).not.toBe("ACCEPTED_MALFORMED"); +});