feat(web): add scene multiview authoring
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-29 20:17:50 +08:00
parent 217ab7cfe9
commit acf4d3d3d0
46 changed files with 1939 additions and 36 deletions

View File

@@ -1592,7 +1592,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
type == "insertGreasePencilFrame" || type == "removeGreasePencilFrame" || type == "insertGreasePencilFrame" || type == "removeGreasePencilFrame" ||
type == "setGreasePencilStrokes" || type == "setVertexColors" || type == "setGreasePencilStrokes" || type == "setVertexColors" ||
type == "setVertexWeights" || type == "setCameraProperties" || type == "setLightProperties" || type == "setVertexWeights" || type == "setCameraProperties" || type == "setLightProperties" ||
type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings" || type == "setSceneBindings" || type == "setSceneViewLayerSettings" || type == "setSceneCollectionSettings" || type == "setSceneBorderSettings" || type == "setSceneSimplifySettings" || type == "setSceneColorManagement" || type == "setSceneImageFormat" || type == "setSceneMotionBlur" || type == "setSceneHairSettings" || type == "setSceneCompositorSettings" || type == "setScenePerformanceSettings" || type == "setSceneSamplingSettings" || type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings" || type == "setSceneBindings" || type == "setSceneViewLayerSettings" || type == "setSceneCollectionSettings" || type == "setSceneBorderSettings" || type == "setSceneSimplifySettings" || type == "setSceneColorManagement" || type == "setSceneImageFormat" || type == "setSceneMotionBlur" || type == "setSceneHairSettings" || type == "setSceneCompositorSettings" || type == "setScenePerformanceSettings" || type == "setSceneSamplingSettings" || type == "setSceneMultiviewSettings" ||
type == "setSculptMeshAttributes" || type == "setSculptMeshAttributes" ||
type == "sculptStroke") { type == "sculptStroke") {
if (!engine->authoritative_commands || engine->authoritative_main == nullptr) { if (!engine->authoritative_commands || engine->authoritative_main == nullptr) {
@@ -2196,7 +2196,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
command.value("normalize", false), command.value("limit", 0u), command.value("mirror", false), command.value("normalize", false), command.value("limit", 0u), command.value("mirror", false),
command.value("mirrorAxis", 0), command.value("mirrorTolerance", 1e-4f), main_error); command.value("mirrorAxis", 0), command.value("mirrorTolerance", 1e-4f), main_error);
} }
else if (type == "setCameraProperties" || type == "setLightProperties" || type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings" || type == "setSceneBindings" || type == "setSceneViewLayerSettings" || type == "setSceneCollectionSettings" || type == "setSceneBorderSettings" || type == "setSceneSimplifySettings" || type == "setSceneColorManagement" || type == "setSceneImageFormat" || type == "setSceneMotionBlur" || type == "setSceneHairSettings" || type == "setSceneCompositorSettings" || type == "setScenePerformanceSettings" || type == "setSceneSamplingSettings") else if (type == "setCameraProperties" || type == "setLightProperties" || type == "setWorldProperties" || type == "setSceneProperties" || type == "setSceneRenderSettings" || type == "setSceneAudioSettings" || type == "setSceneUnitSettings" || type == "setSceneTimelineSettings" || type == "setScenePipelineSettings" || type == "setSceneBindings" || type == "setSceneViewLayerSettings" || type == "setSceneCollectionSettings" || type == "setSceneBorderSettings" || type == "setSceneSimplifySettings" || type == "setSceneColorManagement" || type == "setSceneImageFormat" || type == "setSceneMotionBlur" || type == "setSceneHairSettings" || type == "setSceneCompositorSettings" || type == "setScenePerformanceSettings" || type == "setSceneSamplingSettings" || type == "setSceneMultiviewSettings")
{ {
const json properties = command.value("properties", json::object()); const json properties = command.value("properties", json::object());
if (type == "setSceneProperties") { if (type == "setSceneProperties") {
@@ -2290,6 +2290,11 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
engine->authoritative_main, command.value("dataId", "").c_str(), engine->authoritative_main, command.value("dataId", "").c_str(),
properties.dump().c_str(), main_error); properties.dump().c_str(), main_error);
} }
else if (type == "setSceneMultiviewSettings") {
applied = web_engine_blend_main_set_scene_multiview_settings(
engine->authoritative_main, command.value("dataId", "").c_str(),
properties.dump().c_str(), main_error);
}
else { else {
applied = web_engine_blend_main_set_render_properties( applied = web_engine_blend_main_set_render_properties(
engine->authoritative_main, command.value("dataId", "").c_str(), engine->authoritative_main, command.value("dataId", "").c_str(),

View File

@@ -5290,6 +5290,22 @@ json scene_ir_from_blend(const ParsedBlend &blend,
{"pixelAspectY", read_float(*blend.sdna, *render, "yasp").value_or(1.0f)}, {"pixelAspectY", read_float(*blend.sdna, *render, "yasp").value_or(1.0f)},
{"filterSize", read_float(*blend.sdna, *render, "gauss").value_or(1.5f)}, {"filterSize", read_float(*blend.sdna, *render, "gauss").value_or(1.5f)},
{"dither", read_float(*blend.sdna, *render, "dither_intensity").value_or(1.0f)}}; {"dither", read_float(*blend.sdna, *render, "dither_intensity").value_or(1.0f)}};
if (const std::optional<ElementRef> image_format = embedded_element(*blend.sdna, *render, "im_format")) {
const int64_t image_views = read_integer(*blend.sdna, *image_format, "views_format").value_or(R_IMF_VIEWS_INDIVIDUAL);
int64_t stereo_flags = 0;
int64_t display_mode = S3D_DISPLAY_ANAGLYPH;
if (const std::optional<ElementRef> stereo = embedded_element(*blend.sdna, *image_format, "stereo3d_format")) {
stereo_flags = read_integer(*blend.sdna, *stereo, "flag").value_or(0);
display_mode = read_integer(*blend.sdna, *stereo, "display_mode").value_or(S3D_DISPLAY_ANAGLYPH);
}
scene["multiviewSettings"] = {{"enabled", (render_mode & R_MULTIVIEW) != 0},
{"viewsFormat", read_integer(*blend.sdna, *render, "views_format").value_or(SCE_VIEWS_FORMAT_STEREO_3D)},
{"imageViewsFormat", image_views},
{"stereoDisplayMode", display_mode},
{"interlaceSwap", (stereo_flags & S3D_INTERLACE_SWAP) != 0},
{"sideBySideCrossed", (stereo_flags & S3D_SIDEBYSIDE_CROSSEYED) != 0},
{"squeezedFrame", (stereo_flags & S3D_SQUEEZED_FRAME) != 0}};
}
scene["timelineSettings"] = {{"fps", read_integer(*blend.sdna, *render, "frs_sec").value_or(24)}, scene["timelineSettings"] = {{"fps", read_integer(*blend.sdna, *render, "frs_sec").value_or(24)},
{"fpsBase", read_float(*blend.sdna, *render, "frs_sec_base").value_or(1.0f)}, {"fpsBase", read_float(*blend.sdna, *render, "frs_sec_base").value_or(1.0f)},
{"frameStep", read_integer(*blend.sdna, *render, "frame_step").value_or(1)}, {"frameStep", read_integer(*blend.sdna, *render, "frame_step").value_or(1)},

View File

@@ -6577,6 +6577,48 @@ bool web_engine_blend_main_set_scene_sampling_settings(WebBlendMainState *state,
return true; return true;
} }
bool web_engine_blend_main_set_scene_multiview_settings(WebBlendMainState *state,
const char *target_id,
const char *properties_json,
std::string &error)
{
if (state == nullptr || state->main == nullptr || target_id == nullptr || properties_json == nullptr) { error = "RENDER_PROPERTY_INVALID: scene multiview target is missing"; return false; }
Scene *scene = find_scene(state->main, target_id);
if (scene == nullptr || scene->id.lib != nullptr) { error = "LINKED_DATA_MUTATION_BLOCKED: Scene is not editable"; return false; }
const json properties = json::parse(properties_json, nullptr, false);
if (!properties.is_object() || properties.empty()) { error = "RENDER_PROPERTY_INVALID: scene multiview settings must be a non-empty object"; return false; }
const std::unordered_set<std::string> allowed = {"enabled", "viewsFormat", "imageViewsFormat", "stereoDisplayMode", "interlaceSwap", "sideBySideCrossed", "squeezedFrame"};
for (const auto &[key, value] : properties.items()) { (void)value; if (!allowed.contains(key)) { error = "RENDER_PROPERTY_INVALID: unsupported multiview property " + key; return false; } }
auto read_int = [&](const char *key, int minimum, int maximum, int &target) {
if (!properties.contains(key)) return true;
if (!properties[key].is_number_integer()) { error = std::string("RENDER_PROPERTY_INVALID: ") + key + " must be an integer"; return false; }
const int value = properties[key].get<int>();
if (value < minimum || value > maximum) { error = std::string("RENDER_PROPERTY_INVALID: ") + key + " is outside the bounded range"; return false; }
target = value; return true;
};
int views_format = scene->r.views_format;
int image_views_format = scene->r.im_format.views_format;
int display_mode = scene->r.im_format.stereo3d_format.display_mode;
if (!read_int("viewsFormat", 0, 1, views_format) || !read_int("imageViewsFormat", 0, 2, image_views_format) || !read_int("stereoDisplayMode", 0, 4, display_mode)) return false;
scene->r.views_format = eSceneViews_Format(views_format);
scene->r.im_format.views_format = eImageFormat_ViewsFormat(image_views_format);
scene->r.im_format.stereo3d_format.display_mode = eStereoDisplayMode(display_mode);
const auto read_stereo_flag = [&](const char *key, eStereo3dFlag flag) {
if (!properties.contains(key)) return true;
if (!properties[key].is_boolean()) { error = std::string("RENDER_PROPERTY_INVALID: ") + key + " must be boolean"; return false; }
if (properties[key].get<bool>()) scene->r.im_format.stereo3d_format.flag |= flag;
else scene->r.im_format.stereo3d_format.flag &= ~flag;
return true;
};
if (!read_stereo_flag("interlaceSwap", S3D_INTERLACE_SWAP) || !read_stereo_flag("sideBySideCrossed", S3D_SIDEBYSIDE_CROSSEYED) || !read_stereo_flag("squeezedFrame", S3D_SQUEEZED_FRAME)) return false;
if (properties.contains("enabled")) {
if (!properties["enabled"].is_boolean()) { error = "RENDER_PROPERTY_INVALID: enabled must be boolean"; return false; }
if (properties["enabled"].get<bool>()) scene->r.mode |= R_MULTIVIEW; else scene->r.mode &= ~R_MULTIVIEW;
}
scene->id.recalc |= ID_RECALC_PARAMETERS;
return true;
}
bool web_engine_blend_main_write(WebBlendMainState *state, bool web_engine_blend_main_write(WebBlendMainState *state,
std::vector<uint8_t> &bytes, std::vector<uint8_t> &bytes,
std::string &error) std::string &error)

View File

@@ -591,6 +591,10 @@ bool web_engine_blend_main_set_scene_sampling_settings(WebBlendMainState *state,
const char *target_id, const char *target_id,
const char *properties_json, const char *properties_json,
std::string &error); std::string &error);
bool web_engine_blend_main_set_scene_multiview_settings(WebBlendMainState *state,
const char *target_id,
const char *properties_json,
std::string &error);
bool web_engine_blend_main_write(WebBlendMainState *state, bool web_engine_blend_main_write(WebBlendMainState *state,
std::vector<uint8_t> &bytes, std::vector<uint8_t> &bytes,
std::string &error); std::string &error);

View File

@@ -13,9 +13,9 @@
| 字段 | 值 | | 字段 | 值 |
| --- | --- | | --- | --- |
| 里程碑 | WBV2 capability workflow | | 里程碑 | WBV2 capability workflow |
| 当前任务 | `WBV2-P68-000` | | 当前任务 | `WBV2-P69-000` |
| parent manifest | `tests/golden/WBV2-P67-003/manifest.json` | | parent manifest | `tests/golden/WBV2-P68-003/manifest.json` |
| 任务卡 | [`tasks/WBV2-P68-000.md`](tasks/WBV2-P68-000.md) | | 任务卡 | [`tasks/WBV2-P69-000.md`](tasks/WBV2-P69-000.md) |
| 专项验收 | `node tools/web/check-execution-control-plane.mjs` | | 专项验收 | `node tools/web/check-execution-control-plane.mjs` |
| legacy coverage checkpoint | `M16-GAP-00282` | | legacy coverage checkpoint | `M16-GAP-00282` |
| legacy coverage parent | `tests/golden/M16-GAP-00281/manifest.json` | | legacy coverage parent | `tests/golden/M16-GAP-00281/manifest.json` |

View File

@@ -0,0 +1,7 @@
# WBV2-P68-000 status
- task: `WBV2-P68-000`; parent: `WBV2-P67-003`; status: `done`
- capability-family continuation authorized from Blender source
- 6900 inventory: 27 deduplicated batches, 6609 pending rows
- verification and completion overlay: `DEFERRED`
- nextTask: `WBV2-P68-001`

View File

@@ -0,0 +1,7 @@
# WBV2-P68-001 status
- task: `WBV2-P68-001`; parent: `WBV2-P68-000`; status: `done`
- capability-family implementation: `PASS`; 27 deduplicated batches; 6609 pending rows
- Chromium, E2E receipts and completion overlay: `DEFERRED`
- inventory unchanged: `6900/6618`, effective `290/6609`
- nextTask: `WBV2-P68-002`

View File

@@ -0,0 +1,7 @@
# WBV2-P68-002 status
- task: `WBV2-P68-002`; parent: `WBV2-P68-001`; status: `done`
- capability-family implementation: `PASS`; 27 deduplicated batches; 6609 pending rows
- Chromium, E2E receipts and completion overlay: `DEFERRED`
- inventory unchanged: `6900/6618`, effective `290/6609`
- nextTask: `WBV2-P68-003`

View File

@@ -0,0 +1,7 @@
# WBV2-P68-003 status
- task: `WBV2-P68-003`; parent: `WBV2-P68-002`; status: `done`
- capability-family implementation: `PASS`; 27 deduplicated batches; 6609 pending rows
- Chromium, E2E receipts and completion overlay: `DEFERRED`
- inventory unchanged: `6900/6618`, effective `290/6609`
- nextTask: `WBV2-P69-000`

View File

@@ -0,0 +1,38 @@
# WBV2-P68-001: index_capability_family_batches
- task: WBV2-P68-001
- parent: WBV2-P68-000
- status: in_progress
- gap: workflow:index_capability_family_batches
- ownerFamily: RELEASE
- targetImplementationClass: SOURCE_BACKED
## 目标
Reuse the 27 deduplicated capability batches and unique behavior keys.
## 输入与范围
- Blender source authority: `blender-5.2.0/source/blender`
- Batch plan: `tests/golden/WBV2-P27-001/verification-batch-plan.json`
- Implementation entrypoint: `node tools/web/generate-wbv2-capability-continuation-slice.mjs --task WBV2-P68-001 --write`
## 验收
- 6900 inventory and provenance remain read-only
- capability-family deduplication is reused
- malformed, unsupported, hash-drift and false-completion input fails closed
- Chromium, E2E receipts and completion overlays remain deferred
- `node tools/web/check-task-context.mjs --task WBV2-P68-001 --write`
## 失败边界
- missing source or unsupported capability remains in_progress/blocked
- representative implementation is never declared as full-family parity
## 交付与回滚
- Reports: `tests/golden/WBV2-P68-001/`
- Status: `docs/status/WBV2-P68-001.md`
- Manifest: `tests/golden/WBV2-P68-001/manifest.json`
- Rollback: restore WBV2-P68-000 as queue parent and leave the task in_progress.

View File

@@ -0,0 +1,38 @@
# WBV2-P68-002: implement_capability_family_slice
- task: WBV2-P68-002
- parent: WBV2-P68-001
- status: planned
- gap: workflow:implement_capability_family_slice
- ownerFamily: IMPLEMENTATION
- targetImplementationClass: SOURCE_BACKED
## 目标
Implement the next uncovered Blender capability family from the source-backed index.
## 输入与范围
- Blender source authority: `blender-5.2.0/source/blender`
- Batch plan: `tests/golden/WBV2-P27-001/verification-batch-plan.json`
- Implementation entrypoint: `node tools/web/generate-wbv2-capability-continuation-slice.mjs --task WBV2-P68-002 --write`
## 验收
- 6900 inventory and provenance remain read-only
- capability-family deduplication is reused
- malformed, unsupported, hash-drift and false-completion input fails closed
- Chromium, E2E receipts and completion overlays remain deferred
- `node tools/web/check-task-context.mjs --task WBV2-P68-002 --write`
## 失败边界
- missing source or unsupported capability remains in_progress/blocked
- representative implementation is never declared as full-family parity
## 交付与回滚
- Reports: `tests/golden/WBV2-P68-002/`
- Status: `docs/status/WBV2-P68-002.md`
- Manifest: `tests/golden/WBV2-P68-002/manifest.json`
- Rollback: restore WBV2-P68-001 as queue parent and leave the task in_progress.

View File

@@ -0,0 +1,38 @@
# WBV2-P68-003: run_capability_family_smoke
- task: WBV2-P68-003
- parent: WBV2-P68-002
- status: planned
- gap: workflow:run_capability_family_smoke
- ownerFamily: RELEASE
- targetImplementationClass: SOURCE_BACKED
## 目标
Run source and frontend smoke without Chromium parity verification.
## 输入与范围
- Blender source authority: `blender-5.2.0/source/blender`
- Batch plan: `tests/golden/WBV2-P27-001/verification-batch-plan.json`
- Implementation entrypoint: `node tools/web/generate-wbv2-capability-continuation-slice.mjs --task WBV2-P68-003 --write`
## 验收
- 6900 inventory and provenance remain read-only
- capability-family deduplication is reused
- malformed, unsupported, hash-drift and false-completion input fails closed
- Chromium, E2E receipts and completion overlays remain deferred
- `node tools/web/check-task-context.mjs --task WBV2-P68-003 --write`
## 失败边界
- missing source or unsupported capability remains in_progress/blocked
- representative implementation is never declared as full-family parity
## 交付与回滚
- Reports: `tests/golden/WBV2-P68-003/`
- Status: `docs/status/WBV2-P68-003.md`
- Manifest: `tests/golden/WBV2-P68-003/manifest.json`
- Rollback: restore WBV2-P68-002 as queue parent and leave the task in_progress.

View File

@@ -0,0 +1,35 @@
# WBV2-P69-000: authorize_capability_family_wave
- task: WBV2-P69-000
- parent: WBV2-P68-003
- status: in_progress
- gap: workflow:authorize_capability_family_wave
- ownerFamily: PROGRAM
- targetImplementationClass: SOURCE_BACKED
## 目标
Authorize the next capability-family implementation wave from Blender source.
## 输入与范围
- Blender source authority: `blender-5.2.0/source/blender`
- Implementation entrypoint: `node tools/web/generate-wbv2-capability-continuation-root.mjs`
## 验收
- 6900 inventory remains immutable
- capability-family deduplication is reused
- Chromium receipts and completion overlays remain deferred
- `node tools/web/check-task-context.mjs --task WBV2-P69-000 --write`
## 失败边界
- missing source, unsupported capability or hash drift remains in_progress/blocked
## 交付与回滚
- Reports: `tests/golden/WBV2-P69-000/`
- Status: `docs/status/WBV2-P69-000.md`
- Manifest: `tests/golden/WBV2-P69-000/manifest.json`
- Rollback: restore WBV2-P68-003 as queue parent and leave the wave in_progress.

View File

@@ -305,10 +305,10 @@ Recorded: 2026-08-29 Asia/Shanghai
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Current task when this file was written | `WBV2-P68-000` | | Current task when this file was written | `WBV2-P69-000` |
| Current task state | `in_progress` | | Current task state | `in_progress` |
| Parent manifest | `tests/golden/WBV2/WBV2-P67-003/manifest.json` | | Parent manifest | `tests/golden/WBV2/WBV2-P68-003/manifest.json` |
| Current task card | `docs/tasks/WBV2-P68-000.md` | | Current task card | `docs/tasks/WBV2-P69-000.md` |
| Current task-context nextTask | `NONE` | | Current task-context nextTask | `NONE` |
| Focused command | `node tools/web/generate-wbv2-capability-continuation-root.mjs` | | Focused command | `node tools/web/generate-wbv2-capability-continuation-root.mjs` |

View File

@@ -10,11 +10,11 @@
"artifacts": { "artifacts": {
"parentManifest": { "parentManifest": {
"path": "tests/golden/WBV2-P27-001/manifest.json", "path": "tests/golden/WBV2-P27-001/manifest.json",
"sha256": "5c4a9c1188f36cea19aefbb7a904ae2562686df85a2168e434aed6671701ba9f" "sha256": "4d23cf66b3fb53ba71672fe8c78b7ce819e0a81b90e69ef5efbf1d7edaeefefc"
}, },
"sourceBuildReport": { "sourceBuildReport": {
"path": "tests/golden/WBV2-P27-002/source-build-report.json", "path": "tests/golden/WBV2-P27-002/source-build-report.json",
"sha256": "f281944c3c1f2be95d7268ba5297446f04778b5fafcee56c6de6bc47b50c794b" "sha256": "f9a66d0a10ebbdcaa7c325ebce89a6f78902167b4698b8f30146bc6a44522a13"
}, },
"sourceBuildLog": { "sourceBuildLog": {
"path": "tests/golden/WBV2-P27-002/source-build.log", "path": "tests/golden/WBV2-P27-002/source-build.log",

View File

@@ -21,15 +21,15 @@
"artifacts": { "artifacts": {
"sourceApi": { "sourceApi": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"sha256": "621e40eb574546bce9d63d30ee1de7740ec26c8d5c1f9b002b6069f64dc01dfd" "sha256": "08261bd9d574018f91c27ec31445b32a96874ae2fb995669c1d988bdd44dac95"
}, },
"sourceMainState": { "sourceMainState": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", "path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
"sha256": "f42f13a8c0faf61175f7f3580f1eb97499354796548147a340f16f10df1eafc0" "sha256": "81f385a8a5aaa16a0d0205b98996e15010f740f0670b627671cf82fee532c9a2"
}, },
"sourceMainHeader": { "sourceMainHeader": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", "path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
"sha256": "ad70d2b8d0725a8b1a7346d6b9a622bfa3bbcbd791fe3953127ce81d5cc111e3" "sha256": "9ffb9e3fb8e285dae25b9cbdbb1d14564380bf0b169f4e6b8dfdce11d56ecf89"
}, },
"loader": { "loader": {
"path": "web/app/src/vendor/blender/web_engine.js", "path": "web/app/src/vendor/blender/web_engine.js",
@@ -37,7 +37,7 @@
}, },
"wasm": { "wasm": {
"path": "web/app/src/vendor/blender/web_engine.wasm", "path": "web/app/src/vendor/blender/web_engine.wasm",
"sha256": "7b7b35d0b6a2629ae490b995ba101a09853333849d6217417c8f46f6533325b2" "sha256": "71a2c3426410338bf3cf31779ff76e223505dfc3162b9b33c725f2c64e60a756"
}, },
"publicLoader": { "publicLoader": {
"path": "web/app/public/vendor/blender/web_engine.js", "path": "web/app/public/vendor/blender/web_engine.js",
@@ -45,19 +45,19 @@
}, },
"publicWasm": { "publicWasm": {
"path": "web/app/public/vendor/blender/web_engine.wasm", "path": "web/app/public/vendor/blender/web_engine.wasm",
"sha256": "7b7b35d0b6a2629ae490b995ba101a09853333849d6217417c8f46f6533325b2" "sha256": "71a2c3426410338bf3cf31779ff76e223505dfc3162b9b33c725f2c64e60a756"
}, },
"webDistIndex": { "webDistIndex": {
"path": "web/dist/index.html", "path": "web/dist/index.html",
"sha256": "38bc16bef5f818be7079937f5a6776103590c024918be531b56cb80edecbd7c2" "sha256": "05e4341bfdd6fadfae59aefeab7757b0d7a40e649be133b4ab263395e58f425e"
}, },
"webDistWorker": { "webDistWorker": {
"path": "web/dist/assets/web-engine.worker-Be6i9SMZ.js", "path": "web/dist/assets/web-engine.worker-V2DiqGHA.js",
"sha256": "d0b450afbe41774f42ce70179744a5fb6710cd474f45efed885237f174f2040e" "sha256": "b8b5aca950cd388475be61e3028f1d702f32cce9d6f0f165b3f54d70bdb4af7d"
}, },
"webDistWasm": { "webDistWasm": {
"path": "web/dist/assets/web_engine-CALPew94.wasm", "path": "web/dist/assets/web_engine-BqM_TKef.wasm",
"sha256": "7b7b35d0b6a2629ae490b995ba101a09853333849d6217417c8f46f6533325b2" "sha256": "71a2c3426410338bf3cf31779ff76e223505dfc3162b9b33c725f2c64e60a756"
} }
}, },
"verification": { "verification": {

View File

@@ -5,11 +5,11 @@
"blenderRoot": "blender-5.2.0", "blenderRoot": "blender-5.2.0",
"mainAuthority": "blender_main", "mainAuthority": "blender_main",
"sourceFiles": { "sourceFiles": {
"blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp": "34d76e129823438bc77b9bea7ba15f7ecf8b213091ae307eccaa41e221a7eaeb", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp": "81f385a8a5aaa16a0d0205b98996e15010f740f0670b627671cf82fee532c9a2",
"blender-5.2.0/source/blender/web_engine/web_engine_api.cpp": "b7a65578e69e2da1d98694a0ea055fa46c3cdac2178f58662b0fbbb3fd45a228", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp": "08261bd9d574018f91c27ec31445b32a96874ae2fb995669c1d988bdd44dac95",
"web/protocol/web-engine.ts": "d8c3e9e4db3060f9ecc9259889ea5e4f9b89bb22e14ad1916071a921b5229ff4", "web/protocol/web-engine.ts": "7beede931a902bab393e2035907966b8021fbdea77f2e2a9e4444fe1a6c78898",
"web/protocol/web-engine-capabilities.ts": "055d9080b270d876a328386d83aa58d93e05b4d749b6290d1d5510f1fd028320", "web/protocol/web-engine-capabilities.ts": "2d86f2c1a29d0a9a01e27f9243059a976d401fa2f0dcf7406f8985bb9e0220df",
"web/app/src/workers/web-engine.worker.ts": "241da8567188bc4b4625eeb21849cdc69951258ae9728d750a502d074d9d650e" "web/app/src/workers/web-engine.worker.ts": "7e4a714867442879fb36ffbe620d6418bf482b5d8370e009d071d64f1b1be31e"
} }
}, },
"inventory": { "inventory": {

View File

@@ -0,0 +1,151 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_CAPABILITY_CONTINUATION_P68",
"status": "ACTIVE_CAPABILITY_FAMILY_QUEUE",
"authority": "user_authorized_implementation_first_execution",
"sourceAuthority": {
"blenderRoot": "blender-5.2.0",
"mainAuthority": "blender_main",
"externalDocs": "supplemental_toolchain_constraints_only"
},
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"dedupeBy": [
"sourceHash",
"behaviorHash",
"dedupeKey"
]
},
"inventoryPolicy": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609,
"overlayMutation": "forbidden_during_implementation_wave"
},
"tasks": [
{
"id": "WBV2-P68-000",
"phase": "P68",
"title": "authorize_capability_family_wave",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P67-003"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-000",
"gate": "G1",
"card": "docs/tasks/WBV2-P68-000.md",
"behavior": "Authorize capability-family implementation over the immutable 6900-entry inventory.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P68-001",
"phase": "P68",
"title": "index_capability_family_batches",
"kind": "feature",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-000"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-001",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-001.md",
"behavior": "Reuse the 27 deduplicated capability batches and unique behavior keys.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-002",
"phase": "P68",
"title": "implement_capability_family_slice",
"kind": "feature",
"owner": "IMPLEMENTATION",
"dependsOn": [
"WBV2-P68-001"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-002",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-002.md",
"behavior": "Implement the next uncovered Blender capability family from the source-backed index.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "planned",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-003",
"phase": "P68",
"title": "run_capability_family_smoke",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-002"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-003",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-003.md",
"behavior": "Run source and frontend smoke without Chromium parity verification.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "planned",
"ready": false,
"queueMutationAllowed": false
}
]
}

View File

@@ -0,0 +1,30 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-000",
"operation": "AUTHORIZE_CAPABILITY_FAMILY_CONTINUATION",
"status": "PASS",
"parent": {
"task": "WBV2-P67-003",
"manifest": "tests/golden/WBV2-P67-003/manifest.json",
"manifestSha256": "7b69d99753a4204a7e74b2372f81187f980b5000e2e7d102d37e388fd5a9d252"
},
"sourceAuthority": "blender-5.2.0",
"batching": {
"batchCount": 27,
"pendingRows": 6609,
"deduplication": true
},
"verification": {
"status": "DEFERRED",
"chromium": false,
"completionOverlay": false
},
"inventory": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609
},
"nextTask": "WBV2-P68-001"
}

View File

@@ -0,0 +1,39 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-000",
"parentTask": "WBV2-P67-003",
"operation": "AUTHORIZE_CAPABILITY_FAMILY_CONTINUATION",
"status": "done",
"enablingTask": true,
"parityStateChange": false,
"runtime": "SOURCE_BACKED_CAPABILITY_FAMILY_QUEUE",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P67-003/manifest.json",
"sha256": "7b69d99753a4204a7e74b2372f81187f980b5000e2e7d102d37e388fd5a9d252"
},
"plan": {
"path": "tests/golden/WBV2-P68-000/capability-continuation-plan.json",
"sha256": "c9673ba96bb5a57018a1412c4184eab4fd5eb475f646052f104aab520e96cba2"
},
"report": {
"path": "tests/golden/WBV2-P68-000/capability-continuation-root-report.json",
"sha256": "0cce868254e4cd39b8af08213700ed86da1ed42d9a7ceeff81c961f4170d83e7"
},
"status": {
"path": "docs/status/WBV2-P68-000.md",
"sha256": "e4e1836bf62245d284ccf44e3c1d011d2b4e66233db3cfa65572440be69aa717"
}
},
"assertions": {
"batchCount": 27,
"pendingRows": 6609,
"verificationDeferred": true,
"completionOverlayWritten": false,
"inventoryTotal": 6900,
"effectiveCompleted": 290,
"effectivePending": 6609,
"historicalReproduction": false
},
"nextTask": "WBV2-P68-001"
}

View File

@@ -60,7 +60,7 @@
"real Blender source or WebEngine Main path is wired", "real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred" "verification and completion overlay remain deferred"
], ],
"nextTask": null, "nextTask": "WBV2-P68-001",
"sourceDocuments": { "sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md", "queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P68-000.md", "taskCard": "docs/tasks/WBV2-P68-000.md",
@@ -156,7 +156,7 @@
"totalTokens": 1552, "totalTokens": 1552,
"reservedEnvelopeTokens": 1024, "reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2576, "estimatedContextTokens": 2576,
"serializedContextTokens": 619, "serializedContextTokens": 622,
"withinBudget": true "withinBudget": true
} }
} }

View File

@@ -0,0 +1,151 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_CAPABILITY_CONTINUATION_P68",
"status": "ACTIVE_CAPABILITY_FAMILY_QUEUE",
"authority": "user_authorized_implementation_first_execution",
"sourceAuthority": {
"blenderRoot": "blender-5.2.0",
"mainAuthority": "blender_main",
"externalDocs": "supplemental_toolchain_constraints_only"
},
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"dedupeBy": [
"sourceHash",
"behaviorHash",
"dedupeKey"
]
},
"inventoryPolicy": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609,
"overlayMutation": "forbidden_during_implementation_wave"
},
"tasks": [
{
"id": "WBV2-P68-000",
"phase": "P68",
"title": "authorize_capability_family_wave",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P67-003"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-000",
"gate": "G1",
"card": "docs/tasks/WBV2-P68-000.md",
"behavior": "Authorize capability-family implementation over the immutable 6900-entry inventory.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P68-001",
"phase": "P68",
"title": "index_capability_family_batches",
"kind": "feature",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-000"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-001",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-001.md",
"behavior": "Reuse the 27 deduplicated capability batches and unique behavior keys.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-002",
"phase": "P68",
"title": "implement_capability_family_slice",
"kind": "feature",
"owner": "IMPLEMENTATION",
"dependsOn": [
"WBV2-P68-001"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-002",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-002.md",
"behavior": "Implement the next uncovered Blender capability family from the source-backed index.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-003",
"phase": "P68",
"title": "run_capability_family_smoke",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-002"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-003",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-003.md",
"behavior": "Run source and frontend smoke without Chromium parity verification.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "planned",
"ready": false,
"queueMutationAllowed": false
}
]
}

View File

@@ -0,0 +1,32 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-001",
"operation": "IMPLEMENT_CAPABILITY_FAMILY_CONTINUATION",
"status": "PASS",
"family": "INVENTORY.CAPABILITY_BATCH_INDEX",
"sourcePaths": [
"tools/web/build-wbv2-capability-implementation-index.mjs",
"tests/golden/WBV2-P27-001/verification-batch-plan.json"
],
"command": "/home/mes123456/.nvm/versions/node/v24.19.0/bin/node tools/web/build-wbv2-capability-implementation-index.mjs",
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"deduplication": true
},
"verification": {
"status": "DEFERRED",
"chromium": false,
"e2eReceipts": false,
"completionOverlay": false
},
"inventory": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609
},
"nextTask": "WBV2-P68-002"
}

View File

@@ -0,0 +1,53 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-001",
"parentTask": "WBV2-P68-000",
"operation": "IMPLEMENT_CAPABILITY_FAMILY_CONTINUATION",
"status": "done",
"enablingTask": false,
"parityStateChange": false,
"runtime": "SOURCE_BACKED_CAPABILITY_FAMILY_QUEUE",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P68-000/manifest.json",
"sha256": "796f3c2809312666801581722907bca1aadc2c5b087e8073b623bb299d05d3b2"
},
"source1": {
"path": "tools/web/build-wbv2-capability-implementation-index.mjs",
"sha256": "5010e52764f49b52e69140c9b263debb5b53ecb9bec0e2f7ef76f5d6bc9c4704"
},
"source2": {
"path": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"sha256": "56dddc2e4c380f364d1760dfd9bc7a6be04c1bd8979e0c2aeaa69ae80e80a14e"
},
"report": {
"path": "tests/golden/WBV2-P68-001/implementation-report.json",
"sha256": "207462733509feb1dc77fbc3c335e1c92424f70d81c7ddb2962649c5f5b248fb"
},
"status": {
"path": "docs/status/WBV2-P68-001.md",
"sha256": "5ef240211852de08bbb763f666b41526d58fae0a323ccdd1c7c7bf848594d1d0"
},
"plan": {
"path": "tests/golden/WBV2-P68-001/capability-continuation-plan.json",
"sha256": "4f959faf7b967bf74f964b91c35cfdee21f6e6095a5f93563394ab684b14c4ab"
},
"taskContext": {
"path": "tests/golden/WBV2-P68-001/task-context.json",
"sha256": "07af93f22839a014adbc3bc63154ad8a949f677d0aabfdb7ab92cd9be07eaf56"
}
},
"assertions": {
"capabilityFamily": "INVENTORY.CAPABILITY_BATCH_INDEX",
"sourceBacked": true,
"batchCount": 27,
"pendingRows": 6609,
"verificationDeferred": true,
"completionOverlayWritten": false,
"inventoryTotal": 6900,
"effectiveCompleted": 290,
"effectivePending": 6609,
"historicalReproduction": false
},
"nextTask": "WBV2-P68-002"
}

View File

@@ -0,0 +1,167 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-001",
"parentTask": "WBV2-P68-000",
"status": "in_progress",
"goal": "Reuse the 27 deduplicated capability batches and unique behavior keys.",
"scope": {
"gap": "workflow:index_capability_family_batches",
"ownerFamily": "RELEASE",
"implementationClass": "SOURCE_BACKED"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P68-001 --write"
],
"inputPaths": [],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 4232,
"contextRemainingTokens": 1057
},
"source": {
"bytes": 5672,
"tokens": 1419
},
"selected": [],
"excluded": [
{
"path": "blender-5.2.0/source/blender",
"bytes": 12546,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"bytes": 21184,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P68-001/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P68-001.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P68-001/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 0,
"bytes": 0,
"tokens": 0
}
},
"exitCriteria": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"nextTask": "WBV2-P68-002",
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P68-001.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P68-000/manifest.json",
"parentStatus": "docs/status/WBV2-P68-000.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P68-001.md",
"tests/golden/WBV2-P68-000/manifest.json",
"docs/status/WBV2-P68-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-P68-000",
"parentTask": "WBV2-P67-003",
"status": "done",
"nextTask": "WBV2-P68-001",
"artifactCount": 4
},
"statusSummary": [
"# WBV2-P68-000 status",
"- task: `WBV2-P68-000`; parent: `WBV2-P67-003`; status: `done`",
"- capability-family continuation authorized from Blender source",
"- 6900 inventory: 27 deduplicated batches, 6609 pending rows",
"- verification and completion overlay: `DEFERRED`",
"- nextTask: `WBV2-P68-001`"
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1299,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 39,
"taskTokens": 325
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P68-001.md",
"bytes": 1299,
"lines": 39,
"tokens": 325
},
{
"path": "tests/golden/WBV2-P68-000/manifest.json",
"bytes": 1282,
"lines": 40,
"tokens": 321
},
{
"path": "docs/status/WBV2-P68-000.md",
"bytes": 288,
"lines": 8,
"tokens": 72
}
],
"sourceTokens": 1419,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 1419,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2443,
"serializedContextTokens": 620,
"withinBudget": true
}
}

View File

@@ -0,0 +1,151 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_CAPABILITY_CONTINUATION_P68",
"status": "ACTIVE_CAPABILITY_FAMILY_QUEUE",
"authority": "user_authorized_implementation_first_execution",
"sourceAuthority": {
"blenderRoot": "blender-5.2.0",
"mainAuthority": "blender_main",
"externalDocs": "supplemental_toolchain_constraints_only"
},
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"dedupeBy": [
"sourceHash",
"behaviorHash",
"dedupeKey"
]
},
"inventoryPolicy": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609,
"overlayMutation": "forbidden_during_implementation_wave"
},
"tasks": [
{
"id": "WBV2-P68-000",
"phase": "P68",
"title": "authorize_capability_family_wave",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P67-003"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-000",
"gate": "G1",
"card": "docs/tasks/WBV2-P68-000.md",
"behavior": "Authorize capability-family implementation over the immutable 6900-entry inventory.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P68-001",
"phase": "P68",
"title": "index_capability_family_batches",
"kind": "feature",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-000"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-001",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-001.md",
"behavior": "Reuse the 27 deduplicated capability batches and unique behavior keys.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-002",
"phase": "P68",
"title": "implement_capability_family_slice",
"kind": "feature",
"owner": "IMPLEMENTATION",
"dependsOn": [
"WBV2-P68-001"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-002",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-002.md",
"behavior": "Implement the next uncovered Blender capability family from the source-backed index.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-003",
"phase": "P68",
"title": "run_capability_family_smoke",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-002"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-003",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-003.md",
"behavior": "Run source and frontend smoke without Chromium parity verification.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
}
]
}

View File

@@ -0,0 +1,34 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-002",
"operation": "IMPLEMENT_CAPABILITY_FAMILY_CONTINUATION",
"status": "PASS",
"family": "RENDER.MULTIVIEW_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",
"blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp"
],
"command": "existing source-backed workbench wiring",
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"deduplication": true
},
"verification": {
"status": "DEFERRED",
"chromium": false,
"e2eReceipts": false,
"completionOverlay": false
},
"inventory": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609
},
"nextTask": "WBV2-P68-003"
}

View File

@@ -0,0 +1,61 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-002",
"parentTask": "WBV2-P68-001",
"operation": "IMPLEMENT_CAPABILITY_FAMILY_CONTINUATION",
"status": "done",
"enablingTask": false,
"parityStateChange": false,
"runtime": "SOURCE_BACKED_CAPABILITY_FAMILY_QUEUE",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P68-001/manifest.json",
"sha256": "fdb48d95ad8ec9841e22d261acc7a81c3cc4b52519d9ec765cec65345f8b4539"
},
"source1": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
"sha256": "81f385a8a5aaa16a0d0205b98996e15010f740f0670b627671cf82fee532c9a2"
},
"source2": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
"sha256": "9ffb9e3fb8e285dae25b9cbdbb1d14564380bf0b169f4e6b8dfdce11d56ecf89"
},
"source3": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"sha256": "08261bd9d574018f91c27ec31445b32a96874ae2fb995669c1d988bdd44dac95"
},
"source4": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp",
"sha256": "676b9d7d265a5fc3cd862264c129ea986a17d28ae5b6ec7e4b6b3bd692948708"
},
"report": {
"path": "tests/golden/WBV2-P68-002/implementation-report.json",
"sha256": "88f6677bc88b241dfca118247ed1b3c33242d3d3eec78eab21fa1ab503167de9"
},
"status": {
"path": "docs/status/WBV2-P68-002.md",
"sha256": "573af833dbabd911b37c16d835ec7769655e53bb391b0ec901fe8eb92d14a0b8"
},
"plan": {
"path": "tests/golden/WBV2-P68-002/capability-continuation-plan.json",
"sha256": "1101c9a83b17e87029fda4e02e78c2a2ce6a74a942ed41e2714c24fff731077d"
},
"taskContext": {
"path": "tests/golden/WBV2-P68-002/task-context.json",
"sha256": "be3906dc7c9c8d8b04bc97534f27f9f67faab7e70cb05fc8bcbc9c4d412ec1ba"
}
},
"assertions": {
"capabilityFamily": "RENDER.MULTIVIEW_SETTINGS",
"sourceBacked": true,
"batchCount": 27,
"pendingRows": 6609,
"verificationDeferred": true,
"completionOverlayWritten": false,
"inventoryTotal": 6900,
"effectiveCompleted": 290,
"effectivePending": 6609,
"historicalReproduction": false
},
"nextTask": "WBV2-P68-003"
}

View File

@@ -0,0 +1,167 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-002",
"parentTask": "WBV2-P68-001",
"status": "planned",
"goal": "Implement the next uncovered Blender capability family from the source-backed index.",
"scope": {
"gap": "workflow:implement_capability_family_slice",
"ownerFamily": "IMPLEMENTATION",
"implementationClass": "SOURCE_BACKED"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P68-002 --write"
],
"inputPaths": [],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 3577,
"contextRemainingTokens": 893
},
"source": {
"bytes": 6327,
"tokens": 1583
},
"selected": [],
"excluded": [
{
"path": "blender-5.2.0/source/blender",
"bytes": 12546,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"bytes": 21184,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P68-002/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P68-002.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P68-002/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 0,
"bytes": 0,
"tokens": 0
}
},
"exitCriteria": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"nextTask": "WBV2-P68-003",
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P68-002.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P68-001/manifest.json",
"parentStatus": "docs/status/WBV2-P68-001.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P68-002.md",
"tests/golden/WBV2-P68-001/manifest.json",
"docs/status/WBV2-P68-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-P68-001",
"parentTask": "WBV2-P68-000",
"status": "done",
"nextTask": "WBV2-P68-002",
"artifactCount": 7
},
"statusSummary": [
"# WBV2-P68-001 status",
"- task: `WBV2-P68-001`; parent: `WBV2-P68-000`; status: `done`",
"- capability-family implementation: `PASS`; 27 deduplicated batches; 6609 pending rows",
"- Chromium, E2E receipts and completion overlay: `DEFERRED`",
"- inventory unchanged: `6900/6618`, effective `290/6609`",
"- nextTask: `WBV2-P68-002`"
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1320,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 39,
"taskTokens": 330
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P68-002.md",
"bytes": 1320,
"lines": 39,
"tokens": 330
},
{
"path": "tests/golden/WBV2-P68-001/manifest.json",
"bytes": 1887,
"lines": 54,
"tokens": 472
},
{
"path": "docs/status/WBV2-P68-001.md",
"bytes": 317,
"lines": 8,
"tokens": 80
}
],
"sourceTokens": 1583,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 1583,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2607,
"serializedContextTokens": 625,
"withinBudget": true
}
}

View File

@@ -0,0 +1,181 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_CAPABILITY_CONTINUATION_P68",
"status": "ACTIVE_CAPABILITY_FAMILY_QUEUE",
"authority": "user_authorized_implementation_first_execution",
"sourceAuthority": {
"blenderRoot": "blender-5.2.0",
"mainAuthority": "blender_main",
"externalDocs": "supplemental_toolchain_constraints_only"
},
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"dedupeBy": [
"sourceHash",
"behaviorHash",
"dedupeKey"
]
},
"inventoryPolicy": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609,
"overlayMutation": "forbidden_during_implementation_wave"
},
"tasks": [
{
"id": "WBV2-P68-000",
"phase": "P68",
"title": "authorize_capability_family_wave",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P67-003"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-000",
"gate": "G1",
"card": "docs/tasks/WBV2-P68-000.md",
"behavior": "Authorize capability-family implementation over the immutable 6900-entry inventory.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P68-001",
"phase": "P68",
"title": "index_capability_family_batches",
"kind": "feature",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-000"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-001",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-001.md",
"behavior": "Reuse the 27 deduplicated capability batches and unique behavior keys.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-002",
"phase": "P68",
"title": "implement_capability_family_slice",
"kind": "feature",
"owner": "IMPLEMENTATION",
"dependsOn": [
"WBV2-P68-001"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-002",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-002.md",
"behavior": "Implement the next uncovered Blender capability family from the source-backed index.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P68-003",
"phase": "P68",
"title": "run_capability_family_smoke",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P68-002"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p68-003",
"gate": "IMPLEMENTATION",
"card": "docs/tasks/WBV2-P68-003.md",
"behavior": "Run source and frontend smoke without Chromium parity verification.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P69-000",
"phase": "P69",
"title": "authorize_capability_family_wave",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P68-003"
],
"parityId": null,
"implementationClass": "SOURCE_BACKED",
"parallelGroup": "p69-000",
"gate": "G1",
"card": "docs/tasks/WBV2-P69-000.md",
"behavior": "Authorize the next capability-family implementation wave.",
"outputs": [
"implementation-report",
"manifest",
"status"
],
"acceptance": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": true
}
]
}

View File

@@ -0,0 +1,33 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-003",
"operation": "IMPLEMENT_CAPABILITY_FAMILY_CONTINUATION",
"status": "PASS",
"family": "IMPLEMENTATION.CAPABILITY_FAMILY_SMOKE",
"sourcePaths": [
"web/protocol/web-engine-capabilities.ts",
"web/app/src/workers/web-engine.worker.ts",
"web/app/src/vendor/blender/web_engine.wasm"
],
"command": "npm --prefix web run build",
"batching": {
"sourcePlan": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"batchCount": 27,
"pendingRows": 6609,
"deduplication": true
},
"verification": {
"status": "DEFERRED",
"chromium": false,
"e2eReceipts": false,
"completionOverlay": false
},
"inventory": {
"total": 6900,
"legacyCompleted": 281,
"legacyPending": 6618,
"effectiveCompleted": 290,
"effectivePending": 6609
},
"nextTask": "WBV2-P69-000"
}

View File

@@ -0,0 +1,57 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-003",
"parentTask": "WBV2-P68-002",
"operation": "IMPLEMENT_CAPABILITY_FAMILY_CONTINUATION",
"status": "done",
"enablingTask": false,
"parityStateChange": false,
"runtime": "SOURCE_BACKED_CAPABILITY_FAMILY_QUEUE",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P68-002/manifest.json",
"sha256": "9b95454c039ea85b94490d2e7fa0670a9bfeaccb3968609d3cdd020878fee8d6"
},
"source1": {
"path": "web/protocol/web-engine-capabilities.ts",
"sha256": "2d86f2c1a29d0a9a01e27f9243059a976d401fa2f0dcf7406f8985bb9e0220df"
},
"source2": {
"path": "web/app/src/workers/web-engine.worker.ts",
"sha256": "7e4a714867442879fb36ffbe620d6418bf482b5d8370e009d071d64f1b1be31e"
},
"source3": {
"path": "web/app/src/vendor/blender/web_engine.wasm",
"sha256": "71a2c3426410338bf3cf31779ff76e223505dfc3162b9b33c725f2c64e60a756"
},
"report": {
"path": "tests/golden/WBV2-P68-003/implementation-report.json",
"sha256": "6c5960e12b783803947a7cc732c6d70b8abbbeacd69e96cd1218e40d3714dcbf"
},
"status": {
"path": "docs/status/WBV2-P68-003.md",
"sha256": "bda9a88bc5056d5aa164b9e31c3fd3838b918ca0653c0e8df3df041f5ea82fc7"
},
"plan": {
"path": "tests/golden/WBV2-P68-003/capability-continuation-plan.json",
"sha256": "7eaf8a802680269db2ae45184762dfcba9262ef7b3b8da83572eca5b1338762a"
},
"taskContext": {
"path": "tests/golden/WBV2-P68-003/task-context.json",
"sha256": "e9fc2c07d1ef7ce691fada88dd0cc438a907c69cbc2097bd70cea41ea56113ee"
}
},
"assertions": {
"capabilityFamily": "IMPLEMENTATION.CAPABILITY_FAMILY_SMOKE",
"sourceBacked": true,
"batchCount": 27,
"pendingRows": 6609,
"verificationDeferred": true,
"completionOverlayWritten": false,
"inventoryTotal": 6900,
"effectiveCompleted": 290,
"effectivePending": 6609,
"historicalReproduction": false
},
"nextTask": "WBV2-P69-000"
}

View File

@@ -0,0 +1,167 @@
{
"schemaVersion": 1,
"task": "WBV2-P68-003",
"parentTask": "WBV2-P68-002",
"status": "planned",
"goal": "Run source and frontend smoke without Chromium parity verification.",
"scope": {
"gap": "workflow:run_capability_family_smoke",
"ownerFamily": "RELEASE",
"implementationClass": "SOURCE_BACKED"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P68-003 --write"
],
"inputPaths": [],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 3227,
"contextRemainingTokens": 805
},
"source": {
"bytes": 6677,
"tokens": 1671
},
"selected": [],
"excluded": [
{
"path": "blender-5.2.0/source/blender",
"bytes": 12546,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P27-001/verification-batch-plan.json",
"bytes": 21184,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P68-003/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P68-003.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P68-003/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 0,
"bytes": 0,
"tokens": 0
}
},
"exitCriteria": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"nextTask": "WBV2-P69-000",
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P68-003.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P68-002/manifest.json",
"parentStatus": "docs/status/WBV2-P68-002.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P68-003.md",
"tests/golden/WBV2-P68-002/manifest.json",
"docs/status/WBV2-P68-002.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-P68-002",
"parentTask": "WBV2-P68-001",
"status": "done",
"nextTask": "WBV2-P68-003",
"artifactCount": 9
},
"statusSummary": [
"# WBV2-P68-002 status",
"- task: `WBV2-P68-002`; parent: `WBV2-P68-001`; status: `done`",
"- capability-family implementation: `PASS`; 27 deduplicated batches; 6609 pending rows",
"- Chromium, E2E receipts and completion overlay: `DEFERRED`",
"- inventory unchanged: `6900/6618`, effective `290/6609`",
"- nextTask: `WBV2-P68-003`"
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1284,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 39,
"taskTokens": 321
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P68-003.md",
"bytes": 1284,
"lines": 39,
"tokens": 321
},
{
"path": "tests/golden/WBV2-P68-002/manifest.json",
"bytes": 2273,
"lines": 62,
"tokens": 569
},
{
"path": "docs/status/WBV2-P68-002.md",
"bytes": 317,
"lines": 8,
"tokens": 80
}
],
"sourceTokens": 1671,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 1671,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2695,
"serializedContextTokens": 617,
"withinBudget": true
}
}

View File

@@ -0,0 +1,162 @@
{
"schemaVersion": 1,
"task": "WBV2-P69-000",
"parentTask": "WBV2-P68-003",
"status": "in_progress",
"goal": "Authorize the next capability-family implementation wave from Blender source.",
"scope": {
"gap": "workflow:authorize_capability_family_wave",
"ownerFamily": "PROGRAM",
"implementationClass": "SOURCE_BACKED"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P69-000 --write"
],
"inputPaths": [],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 3703,
"contextRemainingTokens": 924
},
"source": {
"bytes": 6201,
"tokens": 1552
},
"selected": [],
"excluded": [
{
"path": "blender-5.2.0/source/blender",
"bytes": 12546,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P69-000/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P69-000.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P69-000/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 0,
"bytes": 0,
"tokens": 0
}
},
"exitCriteria": [
"6900 inventory remains immutable",
"capability families are deduplicated before implementation",
"real Blender source or WebEngine Main path is wired",
"verification and completion overlay remain deferred"
],
"nextTask": null,
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P69-000.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P68-003/manifest.json",
"parentStatus": "docs/status/WBV2-P68-003.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P69-000.md",
"tests/golden/WBV2-P68-003/manifest.json",
"docs/status/WBV2-P68-003.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-P68-003",
"parentTask": "WBV2-P68-002",
"status": "done",
"nextTask": "WBV2-P69-000",
"artifactCount": 8
},
"statusSummary": [
"# WBV2-P68-003 status",
"- task: `WBV2-P68-003`; parent: `WBV2-P68-002`; status: `done`",
"- capability-family implementation: `PASS`; 27 deduplicated batches; 6609 pending rows",
"- Chromium, E2E receipts and completion overlay: `DEFERRED`",
"- inventory unchanged: `6900/6618`, effective `290/6609`",
"- nextTask: `WBV2-P69-000`"
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1052,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 36,
"taskTokens": 263
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P69-000.md",
"bytes": 1052,
"lines": 36,
"tokens": 263
},
{
"path": "tests/golden/WBV2-P68-003/manifest.json",
"bytes": 2029,
"lines": 58,
"tokens": 508
},
{
"path": "docs/status/WBV2-P68-003.md",
"bytes": 317,
"lines": 8,
"tokens": 80
}
],
"sourceTokens": 1552,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 1552,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2576,
"serializedContextTokens": 619,
"withinBudget": true
}
}

View File

@@ -1,5 +1,5 @@
{"id":"WBV2-P67-000","gapId":"workflow:authorize_capability_family_wave","ownerFamily":"PROGRAM","sourceTask":"P67","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]} {"id":"WBV2-P68-000","gapId":"workflow:authorize_capability_family_wave","ownerFamily":"PROGRAM","sourceTask":"P68","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]}
{"id":"WBV2-P67-001","gapId":"workflow:index_capability_family_batches","ownerFamily":"RELEASE","sourceTask":"P67","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]} {"id":"WBV2-P68-001","gapId":"workflow:index_capability_family_batches","ownerFamily":"RELEASE","sourceTask":"P68","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]}
{"id":"WBV2-P67-002","gapId":"workflow:implement_capability_family_slice","ownerFamily":"IMPLEMENTATION","sourceTask":"P67","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]} {"id":"WBV2-P68-002","gapId":"workflow:implement_capability_family_slice","ownerFamily":"IMPLEMENTATION","sourceTask":"P68","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]}
{"id":"WBV2-P67-003","gapId":"workflow:run_capability_family_smoke","ownerFamily":"RELEASE","sourceTask":"P67","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]} {"id":"WBV2-P68-003","gapId":"workflow:run_capability_family_smoke","ownerFamily":"RELEASE","sourceTask":"P68","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]}
{"id":"WBV2-P68-000","gapId":"workflow:authorize_capability_family_wave","ownerFamily":"PROGRAM","sourceTask":"P68","state":"active","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]} {"id":"WBV2-P69-000","gapId":"workflow:authorize_capability_family_wave","ownerFamily":"PROGRAM","sourceTask":"P69","state":"active","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["6900 inventory remains immutable","capability families are deduplicated before implementation","real Blender source or WebEngine Main path is wired","verification and completion overlay remain deferred"]}

View File

@@ -1 +1 @@
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P67-003/capability-continuation-plan.json","sha256":"b08d2ea1ef682e4ab7032dca1197f82ac3ea065c9add1f7286e5e65ec6eec2dc"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"d443e760875d6cddfb14190cdf4dc9cf0c8068981d7b1fc5c23418ee7d0d1334"},"taskCount":5,"activeTask":"WBV2-P68-000","entries":{"WBV2-P67-000":{"line":0,"offset":0,"length":402,"previous":"WBV2-P66-003","next":"WBV2-P67-001"},"WBV2-P67-001":{"line":1,"offset":402,"length":401,"previous":"WBV2-P67-000","next":"WBV2-P67-002"},"WBV2-P67-002":{"line":2,"offset":803,"length":410,"previous":"WBV2-P67-001","next":"WBV2-P67-003"},"WBV2-P67-003":{"line":3,"offset":1213,"length":397,"previous":"WBV2-P67-002","next":"WBV2-P68-000"},"WBV2-P68-000":{"line":4,"offset":1610,"length":399,"previous":"WBV2-P67-003","next":null}}} {"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P68-003/capability-continuation-plan.json","sha256":"7eaf8a802680269db2ae45184762dfcba9262ef7b3b8da83572eca5b1338762a"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"5aa8665b1fa5b52da3c10162d082f21e6af239d01927e19c1f7f31b41cfe475f"},"taskCount":5,"activeTask":"WBV2-P69-000","entries":{"WBV2-P68-000":{"line":0,"offset":0,"length":402,"previous":"WBV2-P67-003","next":"WBV2-P68-001"},"WBV2-P68-001":{"line":1,"offset":402,"length":401,"previous":"WBV2-P68-000","next":"WBV2-P68-002"},"WBV2-P68-002":{"line":2,"offset":803,"length":410,"previous":"WBV2-P68-001","next":"WBV2-P68-003"},"WBV2-P68-003":{"line":3,"offset":1213,"length":397,"previous":"WBV2-P68-002","next":"WBV2-P69-000"},"WBV2-P69-000":{"line":4,"offset":1610,"length":399,"previous":"WBV2-P68-003","next":null}}}

View File

@@ -26,13 +26,13 @@ assert.equal(parent.status, "done");
assert.equal(parent.nextTask, task); assert.equal(parent.nextTask, task);
const commands = { 1: [process.execPath, "tools/web/build-wbv2-capability-implementation-index.mjs"], 2: null, 3: ["npm", "--prefix", "web", "run", "build"] }; const commands = { 1: [process.execPath, "tools/web/build-wbv2-capability-implementation-index.mjs"], 2: null, 3: ["npm", "--prefix", "web", "run", "build"] };
const files = { 1: ["tools/web/build-wbv2-capability-implementation-index.mjs", "tests/golden/WBV2-P27-001/verification-batch-plan.json"], 2: phase >= 59 ? ["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"] : phase >= 57 ? ["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"] : phase >= 56 ? ["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"] : phase >= 55 ? ["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"] : phase >= 54 ? ["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"] : phase >= 53 ? ["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"] : phase >= 52 ? ["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"] : phase >= 51 ? ["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"] : phase >= 50 ? ["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"] : phase >= 49 ? ["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"] : phase >= 47 ? ["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/app/App.tsx", "web/protocol/web-engine-capabilities.ts"], 3: ["web/protocol/web-engine-capabilities.ts", "web/app/src/workers/web-engine.worker.ts", "web/app/src/vendor/blender/web_engine.wasm"] }; const files = { 1: ["tools/web/build-wbv2-capability-implementation-index.mjs", "tests/golden/WBV2-P27-001/verification-batch-plan.json"], 2: phase >= 59 ? ["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"] : phase >= 57 ? ["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"] : phase >= 56 ? ["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"] : phase >= 55 ? ["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"] : phase >= 54 ? ["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"] : phase >= 53 ? ["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"] : phase >= 52 ? ["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"] : phase >= 51 ? ["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"] : phase >= 50 ? ["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"] : phase >= 49 ? ["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"] : phase >= 47 ? ["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/app/App.tsx", "web/protocol/web-engine-capabilities.ts"], 3: ["web/protocol/web-engine-capabilities.ts", "web/app/src/workers/web-engine.worker.ts", "web/app/src/vendor/blender/web_engine.wasm"] };
const markers = { 1: "BUILD_CAPABILITY_FAMILY_IMPLEMENTATION_INDEX", 2: phase >= 67 ? "web_engine_blend_main_set_scene_sampling_settings" : phase >= 66 ? "web_engine_blend_main_set_scene_performance_settings" : phase >= 65 ? "web_engine_blend_main_set_scene_compositor_settings" : phase >= 64 ? "web_engine_blend_main_set_scene_hair_settings" : phase >= 63 ? "web_engine_blend_main_set_scene_motion_blur" : phase >= 62 ? "web_engine_blend_main_set_scene_image_format" : phase >= 61 ? "web_engine_blend_main_set_scene_color_management" : phase >= 60 ? "web_engine_blend_main_set_scene_simplify_settings" : phase >= 59 ? "web_engine_blend_main_set_scene_border_settings" : phase >= 58 ? "web_engine_blend_main_set_scene_collection_settings" : phase >= 57 ? "web_engine_blend_main_set_scene_view_layer_settings" : phase >= 56 ? "web_engine_blend_main_set_scene_bindings" : phase >= 55 ? "web_engine_blend_main_set_scene_pipeline_settings" : phase >= 54 ? "web_engine_blend_main_set_scene_timeline_settings" : phase >= 53 ? "web_engine_blend_main_set_scene_unit_settings" : phase >= 52 ? "web_engine_blend_main_set_scene_audio_settings" : phase >= 51 ? "web_engine_blend_main_set_scene_render_settings" : phase >= 50 ? "web_engine_blend_main_set_scene_properties" : phase >= 49 ? "web_engine_blend_main_set_physics_simulation" : phase >= 47 ? "web_engine_blend_main_set_geometry_node_graph" : "capability-family-workbench", 3: "WEB_ENGINE_COMMAND_CAPABILITIES" }; const markers = { 1: "BUILD_CAPABILITY_FAMILY_IMPLEMENTATION_INDEX", 2: phase >= 68 ? "web_engine_blend_main_set_scene_multiview_settings" : phase >= 67 ? "web_engine_blend_main_set_scene_sampling_settings" : phase >= 66 ? "web_engine_blend_main_set_scene_performance_settings" : phase >= 65 ? "web_engine_blend_main_set_scene_compositor_settings" : phase >= 64 ? "web_engine_blend_main_set_scene_hair_settings" : phase >= 63 ? "web_engine_blend_main_set_scene_motion_blur" : phase >= 62 ? "web_engine_blend_main_set_scene_image_format" : phase >= 61 ? "web_engine_blend_main_set_scene_color_management" : phase >= 60 ? "web_engine_blend_main_set_scene_simplify_settings" : phase >= 59 ? "web_engine_blend_main_set_scene_border_settings" : phase >= 58 ? "web_engine_blend_main_set_scene_collection_settings" : phase >= 57 ? "web_engine_blend_main_set_scene_view_layer_settings" : phase >= 56 ? "web_engine_blend_main_set_scene_bindings" : phase >= 55 ? "web_engine_blend_main_set_scene_pipeline_settings" : phase >= 54 ? "web_engine_blend_main_set_scene_timeline_settings" : phase >= 53 ? "web_engine_blend_main_set_scene_unit_settings" : phase >= 52 ? "web_engine_blend_main_set_scene_audio_settings" : phase >= 51 ? "web_engine_blend_main_set_scene_render_settings" : phase >= 50 ? "web_engine_blend_main_set_scene_properties" : phase >= 49 ? "web_engine_blend_main_set_physics_simulation" : phase >= 47 ? "web_engine_blend_main_set_geometry_node_graph" : "capability-family-workbench", 3: "WEB_ENGINE_COMMAND_CAPABILITIES" };
for (const file of files[index]) assert.ok(fs.existsSync(abs(file)), file); for (const file of files[index]) assert.ok(fs.existsSync(abs(file)), file);
assert.match(read(files[index][0]), new RegExp(markers[index])); assert.match(read(files[index][0]), new RegExp(markers[index]));
if (commands[index]) execFileSync(commands[index][0], commands[index].slice(1), { cwd: root, stdio: "inherit" }); if (commands[index]) execFileSync(commands[index][0], commands[index].slice(1), { cwd: root, stdio: "inherit" });
const nextIndex = index + 1; const nextIndex = index + 1;
const nextTask = nextIndex <= 3 ? `WBV2-P${phase}-${String(nextIndex).padStart(3, "0")}` : `WBV2-P${phase + 1}-000`; const nextTask = nextIndex <= 3 ? `WBV2-P${phase}-${String(nextIndex).padStart(3, "0")}` : `WBV2-P${phase + 1}-000`;
const family = index === 1 ? "INVENTORY.CAPABILITY_BATCH_INDEX" : index === 2 && phase >= 67 ? "RENDER.SAMPLING_SETTINGS" : index === 2 && phase >= 66 ? "PERFORMANCE.RENDER_SETTINGS" : index === 2 && phase >= 65 ? "COMPOSITOR.EXECUTION_SETTINGS" : index === 2 && phase >= 64 ? "CORE_SCENE_GRAPH.HAIR_SETTINGS" : index === 2 && phase >= 63 ? "CORE_SCENE_GRAPH.MOTION_BLUR" : index === 2 && phase >= 62 ? "CORE_SCENE_GRAPH.IMAGE_FORMAT" : index === 2 && phase >= 61 ? "CORE_SCENE_GRAPH.COLOR_MANAGEMENT" : index === 2 && phase >= 60 ? "CORE_SCENE_GRAPH.SIMPLIFY_SETTINGS" : index === 2 && phase >= 59 ? "CORE_SCENE_GRAPH.BORDER_SETTINGS" : index === 2 && phase >= 58 ? "CORE_SCENE_GRAPH.COLLECTION_SETTINGS" : index === 2 && phase >= 57 ? "CORE_SCENE_GRAPH.VIEW_LAYER_SETTINGS" : index === 2 && phase >= 56 ? "CORE_SCENE_GRAPH.BINDINGS" : index === 2 && phase >= 55 ? "CORE_SCENE_GRAPH.PIPELINE_SETTINGS" : index === 2 && phase >= 54 ? "CORE_SCENE_GRAPH.TIMELINE_SETTINGS" : index === 2 && phase >= 53 ? "CORE_SCENE_GRAPH.UNIT_SETTINGS" : index === 2 && phase >= 52 ? "CORE_SCENE_GRAPH.AUDIO_SETTINGS" : index === 2 && phase >= 51 ? "CORE_SCENE_GRAPH.RENDER_SETTINGS" : index === 2 && phase >= 50 ? "CORE_SCENE_GRAPH.SCENE_PROPERTIES" : index === 2 && phase >= 49 ? "SIMULATION.NATIVE_MANIFEST_BINDING" : index === 2 && phase >= 47 ? "GEOMETRY_NODES.NATIVE_MATERIALIZATION" : index === 2 ? "WORKFLOW.CAPABILITY_FAMILY_WORKBENCH" : "IMPLEMENTATION.CAPABILITY_FAMILY_SMOKE"; const family = index === 1 ? "INVENTORY.CAPABILITY_BATCH_INDEX" : index === 2 && phase >= 68 ? "RENDER.MULTIVIEW_SETTINGS" : index === 2 && phase >= 67 ? "RENDER.SAMPLING_SETTINGS" : index === 2 && phase >= 66 ? "PERFORMANCE.RENDER_SETTINGS" : index === 2 && phase >= 65 ? "COMPOSITOR.EXECUTION_SETTINGS" : index === 2 && phase >= 64 ? "CORE_SCENE_GRAPH.HAIR_SETTINGS" : index === 2 && phase >= 63 ? "CORE_SCENE_GRAPH.MOTION_BLUR" : index === 2 && phase >= 62 ? "CORE_SCENE_GRAPH.IMAGE_FORMAT" : index === 2 && phase >= 61 ? "CORE_SCENE_GRAPH.COLOR_MANAGEMENT" : index === 2 && phase >= 60 ? "CORE_SCENE_GRAPH.SIMPLIFY_SETTINGS" : index === 2 && phase >= 59 ? "CORE_SCENE_GRAPH.BORDER_SETTINGS" : index === 2 && phase >= 58 ? "CORE_SCENE_GRAPH.COLLECTION_SETTINGS" : index === 2 && phase >= 57 ? "CORE_SCENE_GRAPH.VIEW_LAYER_SETTINGS" : index === 2 && phase >= 56 ? "CORE_SCENE_GRAPH.BINDINGS" : index === 2 && phase >= 55 ? "CORE_SCENE_GRAPH.PIPELINE_SETTINGS" : index === 2 && phase >= 54 ? "CORE_SCENE_GRAPH.TIMELINE_SETTINGS" : index === 2 && phase >= 53 ? "CORE_SCENE_GRAPH.UNIT_SETTINGS" : index === 2 && phase >= 52 ? "CORE_SCENE_GRAPH.AUDIO_SETTINGS" : index === 2 && phase >= 51 ? "CORE_SCENE_GRAPH.RENDER_SETTINGS" : index === 2 && phase >= 50 ? "CORE_SCENE_GRAPH.SCENE_PROPERTIES" : index === 2 && phase >= 49 ? "SIMULATION.NATIVE_MANIFEST_BINDING" : index === 2 && phase >= 47 ? "GEOMETRY_NODES.NATIVE_MATERIALIZATION" : index === 2 ? "WORKFLOW.CAPABILITY_FAMILY_WORKBENCH" : "IMPLEMENTATION.CAPABILITY_FAMILY_SMOKE";
const out = `tests/golden/${task}`; const out = `tests/golden/${task}`;
const reportPath = `${out}/implementation-report.json`; const reportPath = `${out}/implementation-report.json`;
const statusPath = `docs/status/${task}.md`; const statusPath = `docs/status/${task}.md`;

Binary file not shown.

View File

@@ -947,6 +947,7 @@ function Properties({ snapshot, selectedFaceIndices, selectedVertexIndices, grea
{activeScene?.compositorSettings ? <div className="property-section" data-testid="scene-compositor-settings-workbench"><h3>Compositor Execution</h3><output>Device {activeScene.compositorSettings.device} · Precision {activeScene.compositorSettings.precision} · Denoise {activeScene.compositorSettings.denoiseDevice} · Quality {activeScene.compositorSettings.previewQuality}/{activeScene.compositorSettings.finalQuality}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneCompositorSettings(activeScene.id, { device: activeScene.compositorSettings!.device === 0 ? 1 : 0 }))}>切换设备</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneCompositorSettings(activeScene.id, { precision: activeScene.compositorSettings!.precision === 0 ? 1 : 0 }))}>切换精度</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneCompositorSettings(activeScene.id, { denoiseDevice: ((activeScene.compositorSettings!.denoiseDevice + 1) % 3) as 0 | 1 | 2 }))}>切换降噪设备</button></div></div> : null} {activeScene?.compositorSettings ? <div className="property-section" data-testid="scene-compositor-settings-workbench"><h3>Compositor Execution</h3><output>Device {activeScene.compositorSettings.device} · Precision {activeScene.compositorSettings.precision} · Denoise {activeScene.compositorSettings.denoiseDevice} · Quality {activeScene.compositorSettings.previewQuality}/{activeScene.compositorSettings.finalQuality}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneCompositorSettings(activeScene.id, { device: activeScene.compositorSettings!.device === 0 ? 1 : 0 }))}>切换设备</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneCompositorSettings(activeScene.id, { precision: activeScene.compositorSettings!.precision === 0 ? 1 : 0 }))}>切换精度</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneCompositorSettings(activeScene.id, { denoiseDevice: ((activeScene.compositorSettings!.denoiseDevice + 1) % 3) as 0 | 1 | 2 }))}>切换降噪设备</button></div></div> : null}
{activeScene?.performanceSettings ? <div className="property-section" data-testid="scene-performance-settings-workbench"><h3>Render Performance</h3><output>{activeScene.performanceSettings.fixedThreads ? `${activeScene.performanceSettings.threads} fixed threads` : "Automatic threads"} · {activeScene.performanceSettings.persistentData ? "Persistent data" : "Transient data"} · {activeScene.performanceSettings.highQualityNormals ? "HQ normals" : "Standard normals"}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setScenePerformanceSettings(activeScene.id, { fixedThreads: !activeScene.performanceSettings!.fixedThreads }))}>切换线程模式</button><button type="button" onClick={() => onCommand(animationRenderCommands.setScenePerformanceSettings(activeScene.id, { threads: Math.min(1024, activeScene.performanceSettings!.threads + 1) }))}>增加线程</button><button type="button" onClick={() => onCommand(animationRenderCommands.setScenePerformanceSettings(activeScene.id, { persistentData: !activeScene.performanceSettings!.persistentData }))}>切换持久数据</button></div></div> : null} {activeScene?.performanceSettings ? <div className="property-section" data-testid="scene-performance-settings-workbench"><h3>Render Performance</h3><output>{activeScene.performanceSettings.fixedThreads ? `${activeScene.performanceSettings.threads} fixed threads` : "Automatic threads"} · {activeScene.performanceSettings.persistentData ? "Persistent data" : "Transient data"} · {activeScene.performanceSettings.highQualityNormals ? "HQ normals" : "Standard normals"}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setScenePerformanceSettings(activeScene.id, { fixedThreads: !activeScene.performanceSettings!.fixedThreads }))}>切换线程模式</button><button type="button" onClick={() => onCommand(animationRenderCommands.setScenePerformanceSettings(activeScene.id, { threads: Math.min(1024, activeScene.performanceSettings!.threads + 1) }))}>增加线程</button><button type="button" onClick={() => onCommand(animationRenderCommands.setScenePerformanceSettings(activeScene.id, { persistentData: !activeScene.performanceSettings!.persistentData }))}>切换持久数据</button></div></div> : null}
{activeScene?.samplingSettings ? <div className="property-section" data-testid="scene-sampling-settings-workbench"><h3>Image Sampling</h3><output>Pixel aspect {activeScene.samplingSettings.pixelAspectX.toFixed(3)} × {activeScene.samplingSettings.pixelAspectY.toFixed(3)} · Filter {activeScene.samplingSettings.filterSize.toFixed(3)} · Dither {activeScene.samplingSettings.dither.toFixed(3)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSamplingSettings(activeScene.id, { filterSize: Math.min(100, activeScene.samplingSettings!.filterSize + 0.1) }))}>增加滤镜</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSamplingSettings(activeScene.id, { dither: Math.min(100, activeScene.samplingSettings!.dither + 0.1) }))}>增加抖动</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSamplingSettings(activeScene.id, { pixelAspectX: activeScene.samplingSettings!.pixelAspectX === 1 ? 2 : 1 }))}>切换像素宽高比</button></div></div> : null} {activeScene?.samplingSettings ? <div className="property-section" data-testid="scene-sampling-settings-workbench"><h3>Image Sampling</h3><output>Pixel aspect {activeScene.samplingSettings.pixelAspectX.toFixed(3)} × {activeScene.samplingSettings.pixelAspectY.toFixed(3)} · Filter {activeScene.samplingSettings.filterSize.toFixed(3)} · Dither {activeScene.samplingSettings.dither.toFixed(3)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSamplingSettings(activeScene.id, { filterSize: Math.min(100, activeScene.samplingSettings!.filterSize + 0.1) }))}>增加滤镜</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSamplingSettings(activeScene.id, { dither: Math.min(100, activeScene.samplingSettings!.dither + 0.1) }))}>增加抖动</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneSamplingSettings(activeScene.id, { pixelAspectX: activeScene.samplingSettings!.pixelAspectX === 1 ? 2 : 1 }))}>切换像素宽高比</button></div></div> : null}
{activeScene?.multiviewSettings ? <div className="property-section" data-testid="scene-multiview-settings-workbench"><h3>Multiview</h3><output>{activeScene.multiviewSettings.enabled ? "Enabled" : "Disabled"} · Views {activeScene.multiviewSettings.viewsFormat} · Output {activeScene.multiviewSettings.imageViewsFormat} · Stereo {activeScene.multiviewSettings.stereoDisplayMode}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneMultiviewSettings(activeScene.id, { enabled: !activeScene.multiviewSettings!.enabled }))}>{activeScene.multiviewSettings.enabled ? "关闭多视图" : "启用多视图"}</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneMultiviewSettings(activeScene.id, { viewsFormat: activeScene.multiviewSettings!.viewsFormat === 0 ? 1 : 0 }))}>切换视图模式</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneMultiviewSettings(activeScene.id, { stereoDisplayMode: ((activeScene.multiviewSettings!.stereoDisplayMode + 1) % 5) as 0 | 1 | 2 | 3 | 4 }))}>切换立体显示</button></div></div> : null}
{activeScene?.renderSettings ? <div className="property-section" data-testid="scene-render-settings-workbench"><h3>Render Output</h3><output>{activeScene.renderSettings.resolutionX} × {activeScene.renderSettings.resolutionY} @ {activeScene.renderSettings.resolutionPercentage}%</output><output>Frames {activeScene.renderSettings.frameStart} - {activeScene.renderSettings.frameEnd} · {activeScene.renderSettings.outputPath}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneRenderSettings(activeScene.id, { resolutionX: Math.min(65536, activeScene.renderSettings!.resolutionX + 64), resolutionY: Math.min(65536, activeScene.renderSettings!.resolutionY + 64) }))}>增加分辨率</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneRenderSettings(activeScene.id, { resolutionPercentage: Math.min(1000, activeScene.renderSettings!.resolutionPercentage + 10) }))}>增加百分比</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneRenderSettings(activeScene.id, { frameEnd: Math.min(1000000, activeScene.renderSettings!.frameEnd + 1) }))}>延长帧范围</button></div></div> : null} {activeScene?.renderSettings ? <div className="property-section" data-testid="scene-render-settings-workbench"><h3>Render Output</h3><output>{activeScene.renderSettings.resolutionX} × {activeScene.renderSettings.resolutionY} @ {activeScene.renderSettings.resolutionPercentage}%</output><output>Frames {activeScene.renderSettings.frameStart} - {activeScene.renderSettings.frameEnd} · {activeScene.renderSettings.outputPath}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneRenderSettings(activeScene.id, { resolutionX: Math.min(65536, activeScene.renderSettings!.resolutionX + 64), resolutionY: Math.min(65536, activeScene.renderSettings!.resolutionY + 64) }))}>增加分辨率</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneRenderSettings(activeScene.id, { resolutionPercentage: Math.min(1000, activeScene.renderSettings!.resolutionPercentage + 10) }))}>增加百分比</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneRenderSettings(activeScene.id, { frameEnd: Math.min(1000000, activeScene.renderSettings!.frameEnd + 1) }))}>延长帧范围</button></div></div> : null}
{activeScene?.audioSettings ? <div className="property-section" data-testid="scene-audio-settings-workbench"><h3>Scene Audio</h3><output>Volume {activeScene.audioSettings.volume.toFixed(2)} · Speed {activeScene.audioSettings.speedOfSound.toFixed(1)} · Doppler {activeScene.audioSettings.dopplerFactor.toFixed(2)}</output><output>Distance model {activeScene.audioSettings.distanceModel} · {activeScene.audioSettings.muted ? "Muted" : "Audible"} · {activeScene.audioSettings.sync ? "Synced" : "Free"}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneAudioSettings(activeScene.id, { volume: Math.min(10, activeScene.audioSettings!.volume + 0.1) }))}>增加音量</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneAudioSettings(activeScene.id, { muted: !activeScene.audioSettings!.muted }))}>{activeScene.audioSettings.muted ? "取消静音" : "静音"}</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneAudioSettings(activeScene.id, { sync: !activeScene.audioSettings!.sync }))}>切换同步</button></div></div> : null} {activeScene?.audioSettings ? <div className="property-section" data-testid="scene-audio-settings-workbench"><h3>Scene Audio</h3><output>Volume {activeScene.audioSettings.volume.toFixed(2)} · Speed {activeScene.audioSettings.speedOfSound.toFixed(1)} · Doppler {activeScene.audioSettings.dopplerFactor.toFixed(2)}</output><output>Distance model {activeScene.audioSettings.distanceModel} · {activeScene.audioSettings.muted ? "Muted" : "Audible"} · {activeScene.audioSettings.sync ? "Synced" : "Free"}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneAudioSettings(activeScene.id, { volume: Math.min(10, activeScene.audioSettings!.volume + 0.1) }))}>增加音量</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneAudioSettings(activeScene.id, { muted: !activeScene.audioSettings!.muted }))}>{activeScene.audioSettings.muted ? "取消静音" : "静音"}</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneAudioSettings(activeScene.id, { sync: !activeScene.audioSettings!.sync }))}>切换同步</button></div></div> : null}
{activeScene?.unitSettings ? <div className="property-section" data-testid="scene-unit-settings-workbench"><h3>Scene Units</h3><output>System {activeScene.unitSettings.system} · Scale {activeScene.unitSettings.scaleLength.toFixed(4)} · Rotation {activeScene.unitSettings.rotationSystem}</output><output>Length {activeScene.unitSettings.lengthUnit} · Mass {activeScene.unitSettings.massUnit} · Time {activeScene.unitSettings.timeUnit}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneUnitSettings(activeScene.id, { system: activeScene.unitSettings!.system === 1 ? 2 : 1 }))}>切换单位系统</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneUnitSettings(activeScene.id, { scaleLength: Math.min(1000000, Math.max(0.000001, activeScene.unitSettings!.scaleLength || 1) * 1.1) }))}>调整单位缩放</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneUnitSettings(activeScene.id, { rotationSystem: activeScene.unitSettings!.rotationSystem === 2 ? 0 : 2 }))}>切换旋转单位</button></div></div> : null} {activeScene?.unitSettings ? <div className="property-section" data-testid="scene-unit-settings-workbench"><h3>Scene Units</h3><output>System {activeScene.unitSettings.system} · Scale {activeScene.unitSettings.scaleLength.toFixed(4)} · Rotation {activeScene.unitSettings.rotationSystem}</output><output>Length {activeScene.unitSettings.lengthUnit} · Mass {activeScene.unitSettings.massUnit} · Time {activeScene.unitSettings.timeUnit}</output><div className="property-actions"><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneUnitSettings(activeScene.id, { system: activeScene.unitSettings!.system === 1 ? 2 : 1 }))}>切换单位系统</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneUnitSettings(activeScene.id, { scaleLength: Math.min(1000000, Math.max(0.000001, activeScene.unitSettings!.scaleLength || 1) * 1.1) }))}>调整单位缩放</button><button type="button" onClick={() => onCommand(animationRenderCommands.setSceneUnitSettings(activeScene.id, { rotationSystem: activeScene.unitSettings!.rotationSystem === 2 ? 0 : 2 }))}>切换旋转单位</button></div></div> : null}

Binary file not shown.

View File

@@ -776,6 +776,17 @@ function assertFutureCapability(payload: Extract<WebEngineRequest["command"], {
if (properties.dither !== undefined && !boundedNumber(properties.dither, 0, 100)) throw report("RENDER_PROPERTY_INVALID", "Scene sampling dither is outside the bounded range"); if (properties.dither !== undefined && !boundedNumber(properties.dither, 0, 100)) throw report("RENDER_PROPERTY_INVALID", "Scene sampling dither is outside the bounded range");
return; return;
} }
case "setSceneMultiviewSettings": {
const scene = currentSnapshot?.scenes.find((candidate) => candidate.id === payload.dataId);
const properties = payload.properties;
if (!scene || !validPropertyKeys(properties, ["enabled", "viewsFormat", "imageViewsFormat", "stereoDisplayMode", "interlaceSwap", "sideBySideCrossed", "squeezedFrame"])) throw report("RENDER_PROPERTY_INVALID", "Scene multiview target or properties are invalid");
if (properties.enabled !== undefined && typeof properties.enabled !== "boolean") throw report("RENDER_PROPERTY_INVALID", "Scene multiview enabled must be boolean");
if (properties.viewsFormat !== undefined && ![0, 1].includes(properties.viewsFormat)) throw report("RENDER_PROPERTY_INVALID", "Scene viewsFormat is unsupported");
if (properties.imageViewsFormat !== undefined && ![0, 1, 2].includes(properties.imageViewsFormat)) throw report("RENDER_PROPERTY_INVALID", "Scene imageViewsFormat is unsupported");
if (properties.stereoDisplayMode !== undefined && ![0, 1, 2, 3, 4].includes(properties.stereoDisplayMode)) throw report("RENDER_PROPERTY_INVALID", "Scene stereoDisplayMode is unsupported");
for (const field of ["interlaceSwap", "sideBySideCrossed", "squeezedFrame"] as const) if (properties[field] !== undefined && typeof properties[field] !== "boolean") throw report("RENDER_PROPERTY_INVALID", `Scene ${field} must be boolean`);
return;
}
case "setGeometryNodeGraph": { case "setGeometryNodeGraph": {
const snapshot = currentSnapshot; const snapshot = currentSnapshot;
const availableResourceIds = new Set([ const availableResourceIds = new Set([

View File

@@ -83,4 +83,7 @@ export const animationRenderCommands = Object.freeze({
setSceneSamplingSettings(dataId: string, properties: AnimationCommand<"setSceneSamplingSettings">["properties"]): AnimationCommand<"setSceneSamplingSettings"> { setSceneSamplingSettings(dataId: string, properties: AnimationCommand<"setSceneSamplingSettings">["properties"]): AnimationCommand<"setSceneSamplingSettings"> {
return { type: "setSceneSamplingSettings", dataId, properties: { ...properties } }; return { type: "setSceneSamplingSettings", dataId, properties: { ...properties } };
}, },
setSceneMultiviewSettings(dataId: string, properties: AnimationCommand<"setSceneMultiviewSettings">["properties"]): AnimationCommand<"setSceneMultiviewSettings"> {
return { type: "setSceneMultiviewSettings", dataId, properties: { ...properties } };
},
} satisfies Record<string, (...args: never[]) => WebEngineEditCommand>); } satisfies Record<string, (...args: never[]) => WebEngineEditCommand>);

View File

@@ -580,6 +580,7 @@ export interface SceneIR {
compositorSettings?: { device: number; precision: number; denoiseDevice: number; previewQuality: number; finalQuality: number }; compositorSettings?: { device: number; precision: number; denoiseDevice: number; previewQuality: number; finalQuality: number };
performanceSettings?: { fixedThreads: boolean; threads: number; persistentData: boolean; highQualityNormals: boolean }; performanceSettings?: { fixedThreads: boolean; threads: number; persistentData: boolean; highQualityNormals: boolean };
samplingSettings?: { pixelAspectX: number; pixelAspectY: number; filterSize: number; dither: number }; samplingSettings?: { pixelAspectX: number; pixelAspectY: number; filterSize: number; dither: number };
multiviewSettings?: { enabled: boolean; viewsFormat: number; imageViewsFormat: number; stereoDisplayMode: number; interlaceSwap: boolean; sideBySideCrossed: boolean; squeezedFrame: boolean };
compositorGraph?: CompositorGraphIR; compositorGraph?: CompositorGraphIR;
compositorStatus?: "AVAILABLE" | "BLOCKED"; compositorStatus?: "AVAILABLE" | "BLOCKED";
sequencerTimeline?: SequencerTimelineIR; sequencerTimeline?: SequencerTimelineIR;
@@ -1643,6 +1644,11 @@ export function parseSceneSnapshotIR(value: unknown): SceneSnapshotIR {
if (!isRecord(scene.samplingSettings)) throw new Error(`SceneIR.scenes[${index}].samplingSettings must be an object`); if (!isRecord(scene.samplingSettings)) throw new Error(`SceneIR.scenes[${index}].samplingSettings must be an object`);
for (const field of ["pixelAspectX", "pixelAspectY", "filterSize", "dither"] as const) requireNumber(scene.samplingSettings[field], `scenes[${index}].samplingSettings.${field}`); for (const field of ["pixelAspectX", "pixelAspectY", "filterSize", "dither"] as const) requireNumber(scene.samplingSettings[field], `scenes[${index}].samplingSettings.${field}`);
} }
if (scene.multiviewSettings !== undefined) {
if (!isRecord(scene.multiviewSettings)) throw new Error(`SceneIR.scenes[${index}].multiviewSettings must be an object`);
for (const field of ["viewsFormat", "imageViewsFormat", "stereoDisplayMode"] as const) requireNumber(scene.multiviewSettings[field], `scenes[${index}].multiviewSettings.${field}`);
for (const field of ["enabled", "interlaceSwap", "sideBySideCrossed", "squeezedFrame"] as const) requireBoolean(scene.multiviewSettings[field], `scenes[${index}].multiviewSettings.${field}`);
}
if (scene.compositorStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(scene.compositorStatus as string)) { if (scene.compositorStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(scene.compositorStatus as string)) {
throw new Error(`scenes[${index}].compositorStatus is invalid`); throw new Error(`scenes[${index}].compositorStatus is invalid`);
} }

View File

@@ -97,6 +97,7 @@ export const WEB_ENGINE_COMMAND_CAPABILITIES = {
setSceneCompositorSettings: { family: "COMPOSITOR", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" }, setSceneCompositorSettings: { family: "COMPOSITOR", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
setScenePerformanceSettings: { family: "PERFORMANCE", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" }, setScenePerformanceSettings: { family: "PERFORMANCE", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
setSceneSamplingSettings: { family: "RENDER", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" }, setSceneSamplingSettings: { family: "RENDER", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
setSceneMultiviewSettings: { family: "RENDER", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
setMetaballElements: { family: "GEOMETRY", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" }, setMetaballElements: { family: "GEOMETRY", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
sculptStroke: { family: "SCULPT", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" }, sculptStroke: { family: "SCULPT", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
setSculptMeshAttributes: { family: "SCULPT", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" }, setSculptMeshAttributes: { family: "SCULPT", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },

View File

@@ -161,6 +161,7 @@ export type WebEngineEditCommand =
| { type: "setSceneCompositorSettings"; dataId: string; properties: { device?: 0 | 1; precision?: 0 | 1; denoiseDevice?: 0 | 1 | 2; previewQuality?: 0 | 1 | 2; finalQuality?: 0 | 1 | 2 } } | { type: "setSceneCompositorSettings"; dataId: string; properties: { device?: 0 | 1; precision?: 0 | 1; denoiseDevice?: 0 | 1 | 2; previewQuality?: 0 | 1 | 2; finalQuality?: 0 | 1 | 2 } }
| { type: "setScenePerformanceSettings"; dataId: string; properties: { fixedThreads?: boolean; threads?: number; persistentData?: boolean; highQualityNormals?: boolean } } | { type: "setScenePerformanceSettings"; dataId: string; properties: { fixedThreads?: boolean; threads?: number; persistentData?: boolean; highQualityNormals?: boolean } }
| { type: "setSceneSamplingSettings"; dataId: string; properties: { pixelAspectX?: number; pixelAspectY?: number; filterSize?: number; dither?: number } } | { type: "setSceneSamplingSettings"; dataId: string; properties: { pixelAspectX?: number; pixelAspectY?: number; filterSize?: number; dither?: number } }
| { type: "setSceneMultiviewSettings"; dataId: string; properties: { enabled?: boolean; viewsFormat?: 0 | 1; imageViewsFormat?: 0 | 1 | 2; stereoDisplayMode?: 0 | 1 | 2 | 3 | 4; interlaceSwap?: boolean; sideBySideCrossed?: boolean; squeezedFrame?: boolean } }
| { type: "setMetaballElements"; dataId: string; elements: Array<{ type: number; position: [number, number, number]; radius: number; scale: [number, number, number] }> } | { type: "setMetaballElements"; dataId: string; elements: Array<{ type: number; position: [number, number, number]; radius: number; scale: [number, number, number] }> }
| { type: "sculptStroke"; stroke: SculptStrokeIR } | { type: "sculptStroke"; stroke: SculptStrokeIR }
| { type: "setSculptMeshAttributes"; attributes: SculptMeshAttributesIR } | { type: "setSculptMeshAttributes"; attributes: SculptMeshAttributesIR }

View File

@@ -4,7 +4,7 @@ export const WORKBENCH_COMMAND_GROUPS = Object.freeze({
OBJECT: ["createPrimitive", "duplicateObject", "deleteObject", "setObjectTransform", "setParent", "createCollection", "moveObjectToCollection", "renameId", "applyObjectTransform", "setObjectOrigin"], OBJECT: ["createPrimitive", "duplicateObject", "deleteObject", "setObjectTransform", "setParent", "createCollection", "moveObjectToCollection", "renameId", "applyObjectTransform", "setObjectOrigin"],
MESH: ["meshEdit", "translateMeshVertices", "createUVMap", "setActiveUVMap", "unwrapUV", "setVertexColors", "setVertexWeights"], MESH: ["meshEdit", "translateMeshVertices", "createUVMap", "setActiveUVMap", "unwrapUV", "setVertexColors", "setVertexWeights"],
ANIMATION: ["setFrame", "insertObjectKeyframe", "deleteObjectKeyframe", "setFCurveInterpolation", "setConstraint", "setNLAStack"], ANIMATION: ["setFrame", "insertObjectKeyframe", "deleteObjectKeyframe", "setFCurveInterpolation", "setConstraint", "setNLAStack"],
RENDER: ["setCameraProperties", "setLightProperties", "setWorldProperties", "setSceneProperties", "setSceneRenderSettings", "setSceneAudioSettings", "setSceneUnitSettings", "setSceneTimelineSettings", "setScenePipelineSettings", "setSceneBindings", "setSceneViewLayerSettings", "setSceneCollectionSettings", "setSceneBorderSettings", "setSceneSimplifySettings", "setSceneColorManagement", "setSceneImageFormat", "setSceneMotionBlur", "setSceneHairSettings", "setSceneCompositorSettings", "setScenePerformanceSettings", "setSceneSamplingSettings"], RENDER: ["setCameraProperties", "setLightProperties", "setWorldProperties", "setSceneProperties", "setSceneRenderSettings", "setSceneAudioSettings", "setSceneUnitSettings", "setSceneTimelineSettings", "setScenePipelineSettings", "setSceneBindings", "setSceneViewLayerSettings", "setSceneCollectionSettings", "setSceneBorderSettings", "setSceneSimplifySettings", "setSceneColorManagement", "setSceneImageFormat", "setSceneMotionBlur", "setSceneHairSettings", "setSceneCompositorSettings", "setScenePerformanceSettings", "setSceneSamplingSettings", "setSceneMultiviewSettings"],
IO: ["importImage", "importVFont", "setMaterialImageNode"], IO: ["importImage", "importVFont", "setMaterialImageNode"],
} as const satisfies Record<string, readonly WebEngineCommandType[]>); } as const satisfies Record<string, readonly WebEngineCommandType[]>);