feat(web): add audio speaker and particle authoring
This commit is contained in:
@@ -1585,7 +1585,7 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
type == "moveObjectToCollection" || type == "renameId" || type == "joinObjects" ||
|
||||
type == "separateMeshFaces" || type == "applyObjectTransform" || type == "setObjectOrigin" ||
|
||||
type == "setCurveControlPoints" || type == "setCurveHandle" || type == "setCurveTopology" || type == "setCurveSplines" || type == "setSurfaceTopology" || type == "setFontBody" ||
|
||||
type == "setFontProperties" || type == "setFontAdvanced" || type == "importVFont" || type == "setFontLinks" || type == "setTextSource" || type == "setVolumeProperties" || type == "deleteNonMeshData" ||
|
||||
type == "setFontProperties" || type == "setFontAdvanced" || type == "importVFont" || type == "setFontLinks" || type == "setTextSource" || type == "setSoundProperties" || type == "setSpeakerProperties" || type == "setParticleSettings" || type == "setVolumeProperties" || type == "deleteNonMeshData" ||
|
||||
type == "setMetaballElements" || type == "createGreasePencilLayer" ||
|
||||
type == "removeGreasePencilLayer" || type == "moveGreasePencilLayer" ||
|
||||
type == "moveGreasePencilFrame" ||
|
||||
@@ -1999,6 +1999,51 @@ EMSCRIPTEN_KEEPALIVE int web_engine_apply_command(const int handle,
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(),
|
||||
command.value("source", "").c_str(), main_error);
|
||||
}
|
||||
else if (type == "setSoundProperties") {
|
||||
const json properties = command.value("properties", json::object());
|
||||
WebSoundPropertiesEdit edit;
|
||||
edit.volume = properties.value("volume", -1.0f);
|
||||
edit.attenuation = properties.value("attenuation", -1.0f);
|
||||
edit.pitch = properties.value("pitch", -1.0f);
|
||||
edit.min_gain = properties.value("minGain", -1.0f);
|
||||
edit.max_gain = properties.value("maxGain", -1.0f);
|
||||
edit.distance = properties.value("distance", -1.0f);
|
||||
edit.offset_time = properties.value("offsetTime", -1.0);
|
||||
applied = web_engine_blend_main_set_sound_properties(
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(), edit, main_error);
|
||||
}
|
||||
else if (type == "setSpeakerProperties") {
|
||||
const json properties = command.value("properties", json::object());
|
||||
WebSpeakerPropertiesEdit edit;
|
||||
edit.volume_max = properties.value("volumeMax", -1.0f);
|
||||
edit.volume_min = properties.value("volumeMin", -1.0f);
|
||||
edit.distance_max = properties.value("distanceMax", -1.0f);
|
||||
edit.distance_reference = properties.value("distanceReference", -1.0f);
|
||||
edit.attenuation = properties.value("attenuation", -1.0f);
|
||||
edit.cone_angle_outer = properties.value("coneAngleOuter", -1.0f);
|
||||
edit.cone_angle_inner = properties.value("coneAngleInner", -1.0f);
|
||||
edit.cone_volume_outer = properties.value("coneVolumeOuter", -1.0f);
|
||||
edit.volume = properties.value("volume", -1.0f);
|
||||
edit.pitch = properties.value("pitch", -1.0f);
|
||||
applied = web_engine_blend_main_set_speaker_properties(
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(), edit, main_error);
|
||||
}
|
||||
else if (type == "setParticleSettings") {
|
||||
const json properties = command.value("properties", json::object());
|
||||
WebParticleSettingsEdit edit;
|
||||
edit.type = properties.value("type", -1);
|
||||
edit.from = properties.value("from", -1);
|
||||
edit.distribution = properties.value("distribution", -1);
|
||||
edit.physics_type = properties.value("physicsType", -1);
|
||||
edit.total_particles = properties.value("totalParticles", -1);
|
||||
edit.start = properties.value("start", -1.0f);
|
||||
edit.end = properties.value("end", -1.0f);
|
||||
edit.lifetime = properties.value("lifetime", -1.0f);
|
||||
edit.size = properties.value("size", -1.0f);
|
||||
edit.draw_size = properties.value("drawSize", -1.0f);
|
||||
applied = web_engine_blend_main_set_particle_settings(
|
||||
engine->authoritative_main, command.value("dataId", "").c_str(), edit, main_error);
|
||||
}
|
||||
else if (type == "setVolumeProperties") {
|
||||
WebVolumePropertiesEdit properties;
|
||||
properties.source_path = command.value("sourcePath", "");
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
#include "DNA_particle_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sound_types.h"
|
||||
#include "DNA_speaker_types.h"
|
||||
#include "DNA_text_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
#include "DNA_userdef_enums.h"
|
||||
@@ -298,6 +300,30 @@ Volume *find_volume(Main *main, const char *data_id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bSound *find_sound(Main *main, const char *data_id)
|
||||
{
|
||||
if (main == nullptr || data_id == nullptr || strncmp(data_id, "sound:", 6) != 0) return nullptr;
|
||||
const std::string name(data_id + 6);
|
||||
for (bSound &sound : main->sounds) if (id_name(sound.id) == name) return &sound;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Speaker *find_speaker(Main *main, const char *data_id)
|
||||
{
|
||||
if (main == nullptr || data_id == nullptr || strncmp(data_id, "speaker:", 8) != 0) return nullptr;
|
||||
const std::string name(data_id + 8);
|
||||
for (Speaker &speaker : main->speakers) if (id_name(speaker.id) == name) return &speaker;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ParticleSettings *find_particle_settings(Main *main, const char *data_id)
|
||||
{
|
||||
if (main == nullptr || data_id == nullptr || strncmp(data_id, "particle-settings:", 18) != 0) return nullptr;
|
||||
const std::string name(data_id + 18);
|
||||
for (ParticleSettings &settings : main->particles) if (id_name(settings.id) == name) return &settings;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Light *find_light(Main *main, const char *data_id)
|
||||
{
|
||||
if (main == nullptr || data_id == nullptr || strncmp(data_id, "light:", 6) != 0) return nullptr;
|
||||
@@ -4004,6 +4030,114 @@ bool web_engine_blend_main_set_text_source(WebBlendMainState *state,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_sound_properties(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebSoundPropertiesEdit &properties,
|
||||
std::string &error)
|
||||
{
|
||||
bSound *sound = find_sound(state != nullptr ? state->main : nullptr, data_id);
|
||||
if (sound == nullptr || sound->id.lib != nullptr) {
|
||||
error = "NON_MESH_DATA_UNSUPPORTED: Sound data-block was not found or is linked read-only";
|
||||
return false;
|
||||
}
|
||||
const auto valid = [](const float value, const float maximum) {
|
||||
return value < 0.0f || !std::isfinite(value) || value > maximum;
|
||||
};
|
||||
if ((properties.volume >= 0.0f && valid(properties.volume, 1000000.0f)) ||
|
||||
(properties.attenuation >= 0.0f && valid(properties.attenuation, 1000000.0f)) ||
|
||||
(properties.pitch >= 0.0f && valid(properties.pitch, 1000000.0f)) ||
|
||||
(properties.min_gain >= 0.0f && valid(properties.min_gain, 1000000.0f)) ||
|
||||
(properties.max_gain >= 0.0f && valid(properties.max_gain, 1000000.0f)) ||
|
||||
(properties.distance >= 0.0f && valid(properties.distance, 1000000.0f)) ||
|
||||
(properties.offset_time >= 0.0 && (!std::isfinite(properties.offset_time) || properties.offset_time > 1000000.0))) {
|
||||
error = "NON_MESH_PROPERTY_INVALID: Sound properties are outside the bounded range";
|
||||
return false;
|
||||
}
|
||||
if (properties.volume >= 0.0f) sound->volume = properties.volume;
|
||||
if (properties.attenuation >= 0.0f) sound->attenuation = properties.attenuation;
|
||||
if (properties.pitch >= 0.0f) sound->pitch = properties.pitch;
|
||||
if (properties.min_gain >= 0.0f) sound->min_gain = properties.min_gain;
|
||||
if (properties.max_gain >= 0.0f) sound->max_gain = properties.max_gain;
|
||||
if (properties.distance >= 0.0f) sound->distance = properties.distance;
|
||||
if (properties.offset_time >= 0.0) sound->offset_time = properties.offset_time;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_speaker_properties(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebSpeakerPropertiesEdit &properties,
|
||||
std::string &error)
|
||||
{
|
||||
Speaker *speaker = find_speaker(state != nullptr ? state->main : nullptr, data_id);
|
||||
if (speaker == nullptr || speaker->id.lib != nullptr) {
|
||||
error = "NON_MESH_DATA_UNSUPPORTED: Speaker data-block was not found or is linked read-only";
|
||||
return false;
|
||||
}
|
||||
const auto valid = [](const float value, const float maximum) {
|
||||
return value < 0.0f || !std::isfinite(value) || value > maximum;
|
||||
};
|
||||
if ((properties.volume_max >= 0.0f && valid(properties.volume_max, 1000000.0f)) ||
|
||||
(properties.volume_min >= 0.0f && valid(properties.volume_min, 1000000.0f)) ||
|
||||
(properties.distance_max >= 0.0f && valid(properties.distance_max, 1000000000.0f)) ||
|
||||
(properties.distance_reference >= 0.0f && valid(properties.distance_reference, 1000000000.0f)) ||
|
||||
(properties.attenuation >= 0.0f && valid(properties.attenuation, 1000000000.0f)) ||
|
||||
(properties.cone_angle_outer >= 0.0f && valid(properties.cone_angle_outer, 360.0f)) ||
|
||||
(properties.cone_angle_inner >= 0.0f && valid(properties.cone_angle_inner, 360.0f)) ||
|
||||
(properties.cone_volume_outer >= 0.0f && valid(properties.cone_volume_outer, 1.0f)) ||
|
||||
(properties.volume >= 0.0f && valid(properties.volume, 1000000.0f)) ||
|
||||
(properties.pitch >= 0.0f && valid(properties.pitch, 1000000.0f))) {
|
||||
error = "NON_MESH_PROPERTY_INVALID: Speaker properties are outside the bounded range";
|
||||
return false;
|
||||
}
|
||||
if (properties.volume_max >= 0.0f) speaker->volume_max = properties.volume_max;
|
||||
if (properties.volume_min >= 0.0f) speaker->volume_min = properties.volume_min;
|
||||
if (properties.distance_max >= 0.0f) speaker->distance_max = properties.distance_max;
|
||||
if (properties.distance_reference >= 0.0f) speaker->distance_reference = properties.distance_reference;
|
||||
if (properties.attenuation >= 0.0f) speaker->attenuation = properties.attenuation;
|
||||
if (properties.cone_angle_outer >= 0.0f) speaker->cone_angle_outer = properties.cone_angle_outer;
|
||||
if (properties.cone_angle_inner >= 0.0f) speaker->cone_angle_inner = properties.cone_angle_inner;
|
||||
if (properties.cone_volume_outer >= 0.0f) speaker->cone_volume_outer = properties.cone_volume_outer;
|
||||
if (properties.volume >= 0.0f) speaker->volume = properties.volume;
|
||||
if (properties.pitch >= 0.0f) speaker->pitch = properties.pitch;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_particle_settings(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebParticleSettingsEdit &properties,
|
||||
std::string &error)
|
||||
{
|
||||
ParticleSettings *settings = find_particle_settings(state != nullptr ? state->main : nullptr, data_id);
|
||||
if (settings == nullptr || settings->id.lib != nullptr) {
|
||||
error = "NON_MESH_DATA_UNSUPPORTED: ParticleSettings data-block was not found or is linked read-only";
|
||||
return false;
|
||||
}
|
||||
if ((properties.type >= 0 && properties.type > 2) || (properties.from >= 0 && properties.from > 4) ||
|
||||
(properties.distribution >= 0 && properties.distribution > 2) || (properties.physics_type >= 0 && properties.physics_type > 4) ||
|
||||
(properties.total_particles >= 0 && properties.total_particles > 1000000)) {
|
||||
error = "NON_MESH_PROPERTY_INVALID: Particle enum or count is outside the bounded range";
|
||||
return false;
|
||||
}
|
||||
const auto valid = [](const float value) { return value < 0.0f || !std::isfinite(value) || value > 1000000.0f; };
|
||||
if ((properties.start >= 0.0f && valid(properties.start)) || (properties.end >= 0.0f && valid(properties.end)) ||
|
||||
(properties.lifetime >= 0.0f && valid(properties.lifetime)) || (properties.size >= 0.0f && valid(properties.size)) ||
|
||||
(properties.draw_size >= 0.0f && valid(properties.draw_size))) {
|
||||
error = "NON_MESH_PROPERTY_INVALID: Particle numeric settings are outside the bounded range";
|
||||
return false;
|
||||
}
|
||||
if (properties.type >= 0) settings->type = eParticleType(properties.type);
|
||||
if (properties.from >= 0) settings->from = eParticleFrom(properties.from);
|
||||
if (properties.distribution >= 0) settings->distr = eParticleDistribution(properties.distribution);
|
||||
if (properties.physics_type >= 0) settings->phystype = eParticlePhysicsType(properties.physics_type);
|
||||
if (properties.total_particles >= 0) settings->totpart = properties.total_particles;
|
||||
if (properties.start >= 0.0f) settings->sta = properties.start;
|
||||
if (properties.end >= 0.0f) settings->end = properties.end;
|
||||
if (properties.lifetime >= 0.0f) settings->lifetime = properties.lifetime;
|
||||
if (properties.size >= 0.0f) settings->size = properties.size;
|
||||
if (properties.draw_size >= 0.0f) settings->draw_size = properties.draw_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool web_engine_blend_main_set_volume_properties(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebVolumePropertiesEdit &properties,
|
||||
|
||||
@@ -76,6 +76,42 @@ struct WebVolumePropertiesEdit {
|
||||
float velocity_scale = 1.0f;
|
||||
};
|
||||
|
||||
struct WebSoundPropertiesEdit {
|
||||
float volume = -1.0f;
|
||||
float attenuation = -1.0f;
|
||||
float pitch = -1.0f;
|
||||
float min_gain = -1.0f;
|
||||
float max_gain = -1.0f;
|
||||
float distance = -1.0f;
|
||||
double offset_time = -1.0;
|
||||
};
|
||||
|
||||
struct WebSpeakerPropertiesEdit {
|
||||
float volume_max = -1.0f;
|
||||
float volume_min = -1.0f;
|
||||
float distance_max = -1.0f;
|
||||
float distance_reference = -1.0f;
|
||||
float attenuation = -1.0f;
|
||||
float cone_angle_outer = -1.0f;
|
||||
float cone_angle_inner = -1.0f;
|
||||
float cone_volume_outer = -1.0f;
|
||||
float volume = -1.0f;
|
||||
float pitch = -1.0f;
|
||||
};
|
||||
|
||||
struct WebParticleSettingsEdit {
|
||||
int type = -1;
|
||||
int from = -1;
|
||||
int distribution = -1;
|
||||
int physics_type = -1;
|
||||
int total_particles = -1;
|
||||
float start = -1.0f;
|
||||
float end = -1.0f;
|
||||
float lifetime = -1.0f;
|
||||
float size = -1.0f;
|
||||
float draw_size = -1.0f;
|
||||
};
|
||||
|
||||
struct WebGreasePencilPointEdit {
|
||||
std::array<float, 3> position = {0.0f, 0.0f, 0.0f};
|
||||
float radius = 0.01f;
|
||||
@@ -370,6 +406,18 @@ bool web_engine_blend_main_set_text_source(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const char *source,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_sound_properties(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebSoundPropertiesEdit &properties,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_speaker_properties(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebSpeakerPropertiesEdit &properties,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_particle_settings(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebParticleSettingsEdit &properties,
|
||||
std::string &error);
|
||||
bool web_engine_blend_main_set_volume_properties(WebBlendMainState *state,
|
||||
const char *data_id,
|
||||
const WebVolumePropertiesEdit &properties,
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| 里程碑 | WBV2 capability workflow |
|
||||
| 当前任务 | `WBV2-P33-000` |
|
||||
| parent manifest | `tests/golden/WBV2-P32-003/manifest.json` |
|
||||
| 任务卡 | [`tasks/WBV2-P33-000.md`](tasks/WBV2-P33-000.md) |
|
||||
| 当前任务 | `WBV2-P34-000` |
|
||||
| parent manifest | `tests/golden/WBV2-P33-003/manifest.json` |
|
||||
| 任务卡 | [`tasks/WBV2-P34-000.md`](tasks/WBV2-P34-000.md) |
|
||||
| 专项验收 | `node tools/web/check-execution-control-plane.mjs` |
|
||||
| legacy coverage checkpoint | `M16-GAP-00282` |
|
||||
| legacy coverage parent | `tests/golden/M16-GAP-00281/manifest.json` |
|
||||
|
||||
7
docs/status/WBV2-P33-000.md
Normal file
7
docs/status/WBV2-P33-000.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# WBV2-P33-000 status
|
||||
|
||||
- task: `WBV2-P33-000`; parent: `WBV2-P32-003`; status: `done`
|
||||
- audio resource and particle settings implementation wave authorized
|
||||
- verification receipts and completion overlays: `DEFERRED`
|
||||
- inventory unchanged: `6900` total, `281` legacy completed, `6618` legacy pending, `290/6609` effective carried forward
|
||||
- nextTask: `WBV2-P33-001`
|
||||
7
docs/status/WBV2-P33-001.md
Normal file
7
docs/status/WBV2-P33-001.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# WBV2-P33-001 status
|
||||
|
||||
- task: `WBV2-P33-001`; parent: `WBV2-P33-000`; status: `done`
|
||||
- source-backed audio/particle family: `AUDIO.SOUND_SPEAKER`; marker: `web_engine_blend_main_set_sound_properties`
|
||||
- Chromium receipts and completion overlay: `DEFERRED`
|
||||
- inventory unchanged: `6900/6618`, effective `290/6609`
|
||||
- nextTask: `WBV2-P33-002`
|
||||
7
docs/status/WBV2-P33-002.md
Normal file
7
docs/status/WBV2-P33-002.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# WBV2-P33-002 status
|
||||
|
||||
- task: `WBV2-P33-002`; parent: `WBV2-P33-001`; status: `done`
|
||||
- source-backed audio/particle family: `PARTICLE.SETTINGS`; marker: `web_engine_blend_main_set_particle_settings`
|
||||
- Chromium receipts and completion overlay: `DEFERRED`
|
||||
- inventory unchanged: `6900/6618`, effective `290/6609`
|
||||
- nextTask: `WBV2-P33-003`
|
||||
7
docs/status/WBV2-P33-003.md
Normal file
7
docs/status/WBV2-P33-003.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# WBV2-P33-003 status
|
||||
|
||||
- task: `WBV2-P33-003`; parent: `WBV2-P33-002`; status: `done`
|
||||
- source-backed audio/particle family: `P33.IMPLEMENTATION_SMOKE`; marker: `applyCommand`
|
||||
- Chromium receipts and completion overlay: `DEFERRED`
|
||||
- inventory unchanged: `6900/6618`, effective `290/6609`
|
||||
- nextTask: `WBV2-P34-000`
|
||||
@@ -1,36 +1,37 @@
|
||||
# WBV2-P33-000: authorize_next_implementation_wave
|
||||
# WBV2-P33-000: authorize_audio_particle_workbench
|
||||
|
||||
- task: WBV2-P33-000
|
||||
- parent: WBV2-P32-003
|
||||
- status: in_progress
|
||||
- gap: workflow:authorize_next_implementation_wave
|
||||
- status: done
|
||||
- gap: workflow:authorize_audio_particle_workbench
|
||||
- ownerFamily: PROGRAM
|
||||
- targetImplementationClass: SOURCE_BACKED
|
||||
|
||||
## 目标
|
||||
|
||||
Authorize the next source-backed implementation wave.
|
||||
Authorize audio resource and particle settings implementation.
|
||||
|
||||
## 输入与范围
|
||||
|
||||
- Focused protocol: `web/protocol/web-engine.ts`
|
||||
- Implementation entrypoint: `node tools/web/generate-wbv2-scene-context-root.mjs`
|
||||
- Implementation entrypoint: `node tools/web/generate-wbv2-audio-particle-root.mjs`
|
||||
|
||||
## 验收
|
||||
|
||||
- implementation-first execution remains active
|
||||
- original inventory and provenance remain unchanged
|
||||
- Chromium parity receipts and completion overlays remain deferred
|
||||
- real source or WebEngine Main path is wired
|
||||
- worker/client/frontend route uses typed protocol without a duplicate shim
|
||||
- malformed, unsupported, hash-drift or false-completion input fails closed
|
||||
- implementation smoke is reproducible; Chromium receipts, undo/redo, save/reopen and deterministic verification remain deferred
|
||||
- `node tools/web/check-task-context.mjs --task WBV2-P33-000 --write`
|
||||
|
||||
## 失败边界
|
||||
|
||||
- malformed, unsupported and hash-drift inputs fail closed
|
||||
- implementation evidence never changes historical provenance
|
||||
- malformed and unsupported audio or particle payloads fail closed with a typed diagnostic
|
||||
- implementation evidence never changes historical inventory or provenance
|
||||
|
||||
## 交付与回滚
|
||||
|
||||
- Reports: `tests/golden/WBV2-P33-000/`
|
||||
- Status: `docs/status/WBV2-P33-000.md`
|
||||
- Manifest: `tests/golden/WBV2-P33-000/manifest.json`
|
||||
- Rollback: restore WBV2-P32-003 as queue parent and leave the wave in_progress.
|
||||
- Rollback: restore WBV2-P32-003 as queue parent and leave the task in_progress.
|
||||
|
||||
37
docs/tasks/WBV2-P33-001.md
Normal file
37
docs/tasks/WBV2-P33-001.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# WBV2-P33-001: implement_audio_resource_authoring
|
||||
|
||||
- task: WBV2-P33-001
|
||||
- parent: WBV2-P33-000
|
||||
- status: in_progress
|
||||
- gap: workflow:implement_audio_resource_authoring
|
||||
- ownerFamily: AUDIO
|
||||
- targetImplementationClass: SOURCE_BACKED
|
||||
|
||||
## 目标
|
||||
|
||||
Connect typed Sound and Speaker property commands to Blender Main.
|
||||
|
||||
## 输入与范围
|
||||
|
||||
- Focused protocol: `web/protocol/web-engine.ts`
|
||||
- Implementation entrypoint: `node tools/web/generate-wbv2-audio-particle-slice.mjs --task WBV2-P33-001 --write`
|
||||
|
||||
## 验收
|
||||
|
||||
- real source or WebEngine Main path is wired
|
||||
- worker/client/frontend route uses typed protocol without a duplicate shim
|
||||
- malformed, unsupported, hash-drift or false-completion input fails closed
|
||||
- implementation smoke is reproducible; Chromium receipts, undo/redo, save/reopen and deterministic verification remain deferred
|
||||
- `node tools/web/check-task-context.mjs --task WBV2-P33-001 --write`
|
||||
|
||||
## 失败边界
|
||||
|
||||
- malformed and unsupported audio or particle payloads fail closed with a typed diagnostic
|
||||
- implementation evidence never changes historical inventory or provenance
|
||||
|
||||
## 交付与回滚
|
||||
|
||||
- Reports: `tests/golden/WBV2-P33-001/`
|
||||
- Status: `docs/status/WBV2-P33-001.md`
|
||||
- Manifest: `tests/golden/WBV2-P33-001/manifest.json`
|
||||
- Rollback: restore WBV2-P33-000 as queue parent and leave the task in_progress.
|
||||
37
docs/tasks/WBV2-P33-002.md
Normal file
37
docs/tasks/WBV2-P33-002.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# WBV2-P33-002: implement_particle_settings_authoring
|
||||
|
||||
- task: WBV2-P33-002
|
||||
- parent: WBV2-P33-001
|
||||
- status: in_progress
|
||||
- gap: workflow:implement_particle_settings_authoring
|
||||
- ownerFamily: PARTICLE
|
||||
- targetImplementationClass: SOURCE_BACKED
|
||||
|
||||
## 目标
|
||||
|
||||
Connect bounded ParticleSettings property commands to Blender Main.
|
||||
|
||||
## 输入与范围
|
||||
|
||||
- Focused protocol: `web/protocol/web-engine.ts`
|
||||
- Implementation entrypoint: `node tools/web/generate-wbv2-audio-particle-slice.mjs --task WBV2-P33-002 --write`
|
||||
|
||||
## 验收
|
||||
|
||||
- real source or WebEngine Main path is wired
|
||||
- worker/client/frontend route uses typed protocol without a duplicate shim
|
||||
- malformed, unsupported, hash-drift or false-completion input fails closed
|
||||
- implementation smoke is reproducible; Chromium receipts, undo/redo, save/reopen and deterministic verification remain deferred
|
||||
- `node tools/web/check-task-context.mjs --task WBV2-P33-002 --write`
|
||||
|
||||
## 失败边界
|
||||
|
||||
- malformed and unsupported audio or particle payloads fail closed with a typed diagnostic
|
||||
- implementation evidence never changes historical inventory or provenance
|
||||
|
||||
## 交付与回滚
|
||||
|
||||
- Reports: `tests/golden/WBV2-P33-002/`
|
||||
- Status: `docs/status/WBV2-P33-002.md`
|
||||
- Manifest: `tests/golden/WBV2-P33-002/manifest.json`
|
||||
- Rollback: restore WBV2-P33-001 as queue parent and leave the task in_progress.
|
||||
37
docs/tasks/WBV2-P33-003.md
Normal file
37
docs/tasks/WBV2-P33-003.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# WBV2-P33-003: run_p33_implementation_smoke
|
||||
|
||||
- task: WBV2-P33-003
|
||||
- parent: WBV2-P33-002
|
||||
- status: in_progress
|
||||
- gap: workflow:run_p33_implementation_smoke
|
||||
- ownerFamily: RELEASE
|
||||
- targetImplementationClass: SOURCE_BACKED
|
||||
|
||||
## 目标
|
||||
|
||||
Run the bounded production build and source WASM smoke after P33.
|
||||
|
||||
## 输入与范围
|
||||
|
||||
- Focused protocol: `web/protocol/web-engine.ts`
|
||||
- Implementation entrypoint: `node tools/web/generate-wbv2-audio-particle-slice.mjs --task WBV2-P33-003 --write`
|
||||
|
||||
## 验收
|
||||
|
||||
- real source or WebEngine Main path is wired
|
||||
- worker/client/frontend route uses typed protocol without a duplicate shim
|
||||
- malformed, unsupported, hash-drift or false-completion input fails closed
|
||||
- implementation smoke is reproducible; Chromium receipts, undo/redo, save/reopen and deterministic verification remain deferred
|
||||
- `node tools/web/check-task-context.mjs --task WBV2-P33-003 --write`
|
||||
|
||||
## 失败边界
|
||||
|
||||
- malformed and unsupported audio or particle payloads fail closed with a typed diagnostic
|
||||
- implementation evidence never changes historical inventory or provenance
|
||||
|
||||
## 交付与回滚
|
||||
|
||||
- Reports: `tests/golden/WBV2-P33-003/`
|
||||
- Status: `docs/status/WBV2-P33-003.md`
|
||||
- Manifest: `tests/golden/WBV2-P33-003/manifest.json`
|
||||
- Rollback: restore WBV2-P33-002 as queue parent and leave the task in_progress.
|
||||
36
docs/tasks/WBV2-P34-000.md
Normal file
36
docs/tasks/WBV2-P34-000.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# WBV2-P34-000: authorize_next_implementation_wave
|
||||
|
||||
- task: WBV2-P34-000
|
||||
- parent: WBV2-P33-003
|
||||
- status: in_progress
|
||||
- gap: workflow:authorize_next_implementation_wave
|
||||
- ownerFamily: PROGRAM
|
||||
- targetImplementationClass: SOURCE_BACKED
|
||||
|
||||
## 目标
|
||||
|
||||
Authorize the next source-backed implementation wave.
|
||||
|
||||
## 输入与范围
|
||||
|
||||
- Focused protocol: `web/protocol/web-engine.ts`
|
||||
- Implementation entrypoint: `node tools/web/generate-wbv2-audio-particle-root.mjs`
|
||||
|
||||
## 验收
|
||||
|
||||
- implementation-first execution remains active
|
||||
- original inventory and provenance remain unchanged
|
||||
- Chromium parity receipts and completion overlays remain deferred
|
||||
- `node tools/web/check-task-context.mjs --task WBV2-P34-000 --write`
|
||||
|
||||
## 失败边界
|
||||
|
||||
- malformed, unsupported and hash-drift inputs fail closed
|
||||
- implementation evidence never changes historical provenance
|
||||
|
||||
## 交付与回滚
|
||||
|
||||
- Reports: `tests/golden/WBV2-P34-000/`
|
||||
- Status: `docs/status/WBV2-P34-000.md`
|
||||
- Manifest: `tests/golden/WBV2-P34-000/manifest.json`
|
||||
- Rollback: restore WBV2-P33-003 as queue parent and leave the wave in_progress.
|
||||
@@ -204,12 +204,12 @@ Recorded: 2026-08-22 America/New_York
|
||||
|
||||
| Field | Value |
|
||||
| --- | --- |
|
||||
| Current task when this file was written | `WBV2-P33-000` |
|
||||
| Current task when this file was written | `WBV2-P34-000` |
|
||||
| Current task state | `in_progress` |
|
||||
| Parent manifest | `tests/golden/WBV2-P32-003/manifest.json` |
|
||||
| Current task card | `docs/tasks/WBV2-P33-000.md` |
|
||||
| Parent manifest | `tests/golden/WBV2-P33-003/manifest.json` |
|
||||
| Current task card | `docs/tasks/WBV2-P34-000.md` |
|
||||
| Current task-context nextTask | `NONE` |
|
||||
| Focused command | `node tools/web/generate-wbv2-scene-context-slice.mjs --task WBV2-P33-000 --write` |
|
||||
| Focused command | `node tools/web/generate-wbv2-audio-particle-slice.mjs --task WBV2-P34-000 --write` |
|
||||
|
||||
The snapshot is informational and may become stale. On every resume, the queue,
|
||||
parent manifest, and fresh `print-task-context` output win. Never infer a task
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
"artifacts": {
|
||||
"sourceApi": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
|
||||
"sha256": "6a3eebde527f029fce7666a080e8cac1a60de944aee372bfe772ee6e2adabbdf"
|
||||
"sha256": "1e63bb78a5b216220c610059c3a7c1c5ee20227a777e67c90e32d7a78bf190b3"
|
||||
},
|
||||
"sourceMainState": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
|
||||
"sha256": "7803654bf15db8645b65e0653eb3599b46f969d65c5a1a365daeee51079259d4"
|
||||
"sha256": "236c2eb8d40a790b0008d5d4c193bb3a504ceca1efee347c94b2af28b5b5e820"
|
||||
},
|
||||
"sourceMainHeader": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
|
||||
"sha256": "d689575a2a8496acf50b5b8cafbb1f26b80de54ed7735a2bf1507b01f072f568"
|
||||
"sha256": "d2d93fb5de091fe0a41438ba423dc6424d20141a0de25ab1d5b1ec68bf9ffd0d"
|
||||
},
|
||||
"loader": {
|
||||
"path": "web/app/src/vendor/blender/web_engine.js",
|
||||
@@ -37,7 +37,7 @@
|
||||
},
|
||||
"wasm": {
|
||||
"path": "web/app/src/vendor/blender/web_engine.wasm",
|
||||
"sha256": "e04c9c06fa2db509acf210290cfd132acae68597964952869f133d51a8c0d9ff"
|
||||
"sha256": "ff36d8183cfd9112e67e104f5bf1ec6577ef605bdfcf5239a1cea8504caf7058"
|
||||
},
|
||||
"publicLoader": {
|
||||
"path": "web/app/public/vendor/blender/web_engine.js",
|
||||
@@ -45,19 +45,19 @@
|
||||
},
|
||||
"publicWasm": {
|
||||
"path": "web/app/public/vendor/blender/web_engine.wasm",
|
||||
"sha256": "e04c9c06fa2db509acf210290cfd132acae68597964952869f133d51a8c0d9ff"
|
||||
"sha256": "ff36d8183cfd9112e67e104f5bf1ec6577ef605bdfcf5239a1cea8504caf7058"
|
||||
},
|
||||
"webDistIndex": {
|
||||
"path": "web/dist/index.html",
|
||||
"sha256": "456f1171b36fc9cea608ea6e74a11570f855b0f26a646350d5ac458a4e918fe9"
|
||||
"sha256": "922dc39d65fa87a4a03f5ebeaf46e38c72a2833f3bc45adcb923d9bc52cf148e"
|
||||
},
|
||||
"webDistWorker": {
|
||||
"path": "web/dist/assets/web-engine.worker-O0DBLaO6.js",
|
||||
"sha256": "cb291abff13abbc03083fccd6793b113fc16539e4760e55a3ca2c7633caf0d28"
|
||||
"path": "web/dist/assets/web-engine.worker-DFgABFdV.js",
|
||||
"sha256": "7b3487a8ee98663a8392ab2567ab01639f967f3956bf002657473d4c4e046ac4"
|
||||
},
|
||||
"webDistWasm": {
|
||||
"path": "web/dist/assets/web_engine-BW7Q6ZZS.wasm",
|
||||
"sha256": "e04c9c06fa2db509acf210290cfd132acae68597964952869f133d51a8c0d9ff"
|
||||
"path": "web/dist/assets/web_engine-CoBQBGl-.wasm",
|
||||
"sha256": "ff36d8183cfd9112e67e104f5bf1ec6577ef605bdfcf5239a1cea8504caf7058"
|
||||
}
|
||||
},
|
||||
"verification": {
|
||||
|
||||
33
tests/golden/WBV2-P33-000/audio-particle-root-report.json
Normal file
33
tests/golden/WBV2-P33-000/audio-particle-root-report.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-000",
|
||||
"operation": "AUTHORIZE_AUDIO_PARTICLE_WORKBENCH",
|
||||
"status": "PASS",
|
||||
"parent": {
|
||||
"task": "WBV2-P32-003",
|
||||
"manifest": "tests/golden/WBV2-P32-003/manifest.json",
|
||||
"manifestSha256": "6c456ad069a3311b6fd3a6632ab2fef154fed994a90f92db71053488e31d805a"
|
||||
},
|
||||
"scope": {
|
||||
"firstTask": "WBV2-P33-001",
|
||||
"plannedTasks": [
|
||||
"WBV2-P33-000",
|
||||
"WBV2-P33-001",
|
||||
"WBV2-P33-002",
|
||||
"WBV2-P33-003"
|
||||
]
|
||||
},
|
||||
"verification": {
|
||||
"status": "DEFERRED",
|
||||
"chromium": false,
|
||||
"completionOverlay": false
|
||||
},
|
||||
"inventory": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609
|
||||
},
|
||||
"nextTask": "WBV2-P33-001"
|
||||
}
|
||||
144
tests/golden/WBV2-P33-000/audio-particle-task-plan.json
Normal file
144
tests/golden/WBV2-P33-000/audio-particle-task-plan.json
Normal file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"planId": "BLENDER_WEB_AUDIO_PARTICLE_IMPLEMENTATION_P33",
|
||||
"status": "ACTIVE_AUDIO_PARTICLE_QUEUE",
|
||||
"authority": "user_authorized_implementation_first_execution",
|
||||
"executionPointer": "docs/EXECUTION_QUEUE.md",
|
||||
"runtimePolicy": {
|
||||
"blenderSource": "blender-5.2.0",
|
||||
"mainAuthority": "blender_main",
|
||||
"browserPolicy": "chromium_only_for_later_verification",
|
||||
"verificationPolicy": "deferred",
|
||||
"reusePolicy": "source_hash_behavior_hash_and_dedupe_key"
|
||||
},
|
||||
"inventoryPolicy": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"overlayMutation": "forbidden_during_implementation_wave"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"id": "WBV2-P33-000",
|
||||
"phase": "P33",
|
||||
"title": "authorize_audio_particle_workbench",
|
||||
"kind": "enabling",
|
||||
"owner": "PROGRAM",
|
||||
"dependsOn": [
|
||||
"WBV2-P32-003"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-000",
|
||||
"gate": "G1",
|
||||
"card": "docs/tasks/WBV2-P33-000.md",
|
||||
"behavior": "Authorize audio resource and particle settings implementation.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": true
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-001",
|
||||
"phase": "P33",
|
||||
"title": "implement_audio_resource_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "AUDIO",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-000"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-001",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-001.md",
|
||||
"behavior": "Connect typed Sound and Speaker property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "in_progress",
|
||||
"ready": true,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-002",
|
||||
"phase": "P33",
|
||||
"title": "implement_particle_settings_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "PARTICLE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-001"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-002",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-002.md",
|
||||
"behavior": "Connect bounded ParticleSettings property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "planned",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-003",
|
||||
"phase": "P33",
|
||||
"title": "run_p33_implementation_smoke",
|
||||
"kind": "enabling",
|
||||
"owner": "RELEASE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-002"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-003",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-003.md",
|
||||
"behavior": "Run the bounded production build and source WASM smoke after P33.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "planned",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
38
tests/golden/WBV2-P33-000/manifest.json
Normal file
38
tests/golden/WBV2-P33-000/manifest.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-000",
|
||||
"parentTask": "WBV2-P32-003",
|
||||
"operation": "AUTHORIZE_AUDIO_PARTICLE_WORKBENCH",
|
||||
"status": "done",
|
||||
"enablingTask": true,
|
||||
"parityStateChange": false,
|
||||
"runtime": "SOURCE_BACKED_AUDIO_PARTICLE_QUEUE",
|
||||
"artifacts": {
|
||||
"parentManifest": {
|
||||
"path": "tests/golden/WBV2-P32-003/manifest.json",
|
||||
"sha256": "f058a7c5fe17c19d3f5cb5b74b32e278fb54b2a0941fd00b09860ce8a256d89d"
|
||||
},
|
||||
"plan": {
|
||||
"path": "tests/golden/WBV2-P33-000/audio-particle-task-plan.json",
|
||||
"sha256": "9e61f2779b721a1bf06c7034faf02a1c68139fc0f95241f252ed2565fd2a9b24"
|
||||
},
|
||||
"report": {
|
||||
"path": "tests/golden/WBV2-P33-000/audio-particle-root-report.json",
|
||||
"sha256": "24898c64ca6716ed8c5749f2b69040d7ecf41fcec4575c5092c8dd2b2c25ecde"
|
||||
},
|
||||
"status": {
|
||||
"path": "docs/status/WBV2-P33-000.md",
|
||||
"sha256": "47c05a47c7bd57f9f8efe5599fdbf0b34dabfdabe7e6cf309cee0eaffee5a3db"
|
||||
}
|
||||
},
|
||||
"assertions": {
|
||||
"plannedTasks": 4,
|
||||
"verificationDeferred": true,
|
||||
"completionOverlayWritten": false,
|
||||
"inventoryTotal": 6900,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"historicalReproduction": false
|
||||
},
|
||||
"nextTask": "WBV2-P33-001"
|
||||
}
|
||||
@@ -2,10 +2,10 @@
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-000",
|
||||
"parentTask": "WBV2-P32-003",
|
||||
"status": "in_progress",
|
||||
"goal": "Authorize the next source-backed implementation wave.",
|
||||
"status": "done",
|
||||
"goal": "Authorize audio resource and particle settings implementation.",
|
||||
"scope": {
|
||||
"gap": "workflow:authorize_next_implementation_wave",
|
||||
"gap": "workflow:authorize_audio_particle_workbench",
|
||||
"ownerFamily": "PROGRAM",
|
||||
"implementationClass": "SOURCE_BACKED"
|
||||
},
|
||||
@@ -18,12 +18,12 @@
|
||||
"limits": {
|
||||
"maxFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextRemainingBytes": 3870,
|
||||
"contextRemainingTokens": 966
|
||||
"contextRemainingBytes": 3663,
|
||||
"contextRemainingTokens": 914
|
||||
},
|
||||
"source": {
|
||||
"bytes": 6034,
|
||||
"tokens": 1510
|
||||
"bytes": 6241,
|
||||
"tokens": 1562
|
||||
},
|
||||
"selected": [],
|
||||
"excluded": [
|
||||
@@ -60,7 +60,7 @@
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"nextTask": null,
|
||||
"nextTask": "WBV2-P33-001",
|
||||
"sourceDocuments": {
|
||||
"queue": "docs/EXECUTION_QUEUE.md",
|
||||
"taskCard": "docs/tasks/WBV2-P33-000.md",
|
||||
@@ -112,15 +112,15 @@
|
||||
},
|
||||
"budgets": {
|
||||
"queueBytes": 4096,
|
||||
"taskBytes": 1079,
|
||||
"taskBytes": 1286,
|
||||
"parentManifestBytes": 24576,
|
||||
"parentStatusBytes": 6144,
|
||||
"evidenceFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextTokens": 3500,
|
||||
"contextEnvelopeTokens": 1024,
|
||||
"taskLines": 37,
|
||||
"taskTokens": 270
|
||||
"taskLines": 38,
|
||||
"taskTokens": 322
|
||||
},
|
||||
"size": {
|
||||
"documents": [
|
||||
@@ -132,9 +132,9 @@
|
||||
},
|
||||
{
|
||||
"path": "docs/tasks/WBV2-P33-000.md",
|
||||
"bytes": 1079,
|
||||
"lines": 37,
|
||||
"tokens": 270
|
||||
"bytes": 1286,
|
||||
"lines": 38,
|
||||
"tokens": 322
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P32-003/manifest.json",
|
||||
@@ -149,14 +149,14 @@
|
||||
"tokens": 79
|
||||
}
|
||||
],
|
||||
"sourceTokens": 1510,
|
||||
"sourceTokens": 1562,
|
||||
"evidenceFiles": 0,
|
||||
"evidenceBytes": 0,
|
||||
"evidenceTokens": 0,
|
||||
"totalTokens": 1510,
|
||||
"totalTokens": 1562,
|
||||
"reservedEnvelopeTokens": 1024,
|
||||
"estimatedContextTokens": 2534,
|
||||
"serializedContextTokens": 600,
|
||||
"estimatedContextTokens": 2586,
|
||||
"serializedContextTokens": 603,
|
||||
"withinBudget": true
|
||||
}
|
||||
}
|
||||
|
||||
144
tests/golden/WBV2-P33-001/audio-particle-task-plan.json
Normal file
144
tests/golden/WBV2-P33-001/audio-particle-task-plan.json
Normal file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"planId": "BLENDER_WEB_AUDIO_PARTICLE_IMPLEMENTATION_P33",
|
||||
"status": "ACTIVE_AUDIO_PARTICLE_QUEUE",
|
||||
"authority": "user_authorized_implementation_first_execution",
|
||||
"executionPointer": "docs/EXECUTION_QUEUE.md",
|
||||
"runtimePolicy": {
|
||||
"blenderSource": "blender-5.2.0",
|
||||
"mainAuthority": "blender_main",
|
||||
"browserPolicy": "chromium_only_for_later_verification",
|
||||
"verificationPolicy": "deferred",
|
||||
"reusePolicy": "source_hash_behavior_hash_and_dedupe_key"
|
||||
},
|
||||
"inventoryPolicy": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"overlayMutation": "forbidden_during_implementation_wave"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"id": "WBV2-P33-000",
|
||||
"phase": "P33",
|
||||
"title": "authorize_audio_particle_workbench",
|
||||
"kind": "enabling",
|
||||
"owner": "PROGRAM",
|
||||
"dependsOn": [
|
||||
"WBV2-P32-003"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-000",
|
||||
"gate": "G1",
|
||||
"card": "docs/tasks/WBV2-P33-000.md",
|
||||
"behavior": "Authorize audio resource and particle settings implementation.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": true
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-001",
|
||||
"phase": "P33",
|
||||
"title": "implement_audio_resource_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "AUDIO",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-000"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-001",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-001.md",
|
||||
"behavior": "Connect typed Sound and Speaker property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-002",
|
||||
"phase": "P33",
|
||||
"title": "implement_particle_settings_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "PARTICLE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-001"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-002",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-002.md",
|
||||
"behavior": "Connect bounded ParticleSettings property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "in_progress",
|
||||
"ready": true,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-003",
|
||||
"phase": "P33",
|
||||
"title": "run_p33_implementation_smoke",
|
||||
"kind": "enabling",
|
||||
"owner": "RELEASE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-002"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-003",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-003.md",
|
||||
"behavior": "Run the bounded production build and source WASM smoke after P33.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "planned",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
35
tests/golden/WBV2-P33-001/implementation-report.json
Normal file
35
tests/golden/WBV2-P33-001/implementation-report.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-001",
|
||||
"operation": "IMPLEMENT_AUDIO_PARTICLE_FAMILY",
|
||||
"status": "PASS",
|
||||
"family": "AUDIO.SOUND_SPEAKER",
|
||||
"sourceBacked": true,
|
||||
"implementation": {
|
||||
"marker": "web_engine_blend_main_set_sound_properties",
|
||||
"sourcePaths": [
|
||||
"blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
|
||||
"blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
|
||||
"blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
|
||||
"web/protocol/web-engine.ts",
|
||||
"web/app/src/workers/web-engine.worker.ts",
|
||||
"web/app/src/app/App.tsx",
|
||||
"web/protocol/io-media-commands.ts"
|
||||
],
|
||||
"duplicateShimAdded": false
|
||||
},
|
||||
"verification": {
|
||||
"status": "DEFERRED",
|
||||
"chromium": false,
|
||||
"receipts": false,
|
||||
"completionOverlay": false
|
||||
},
|
||||
"inventory": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609
|
||||
},
|
||||
"nextTask": "WBV2-P33-002"
|
||||
}
|
||||
72
tests/golden/WBV2-P33-001/manifest.json
Normal file
72
tests/golden/WBV2-P33-001/manifest.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-001",
|
||||
"parentTask": "WBV2-P33-000",
|
||||
"operation": "IMPLEMENT_AUDIO_PARTICLE_FAMILY",
|
||||
"status": "done",
|
||||
"enablingTask": false,
|
||||
"parityStateChange": false,
|
||||
"runtime": "SOURCE_BACKED_AUDIO_PARTICLE_IMPLEMENTATION",
|
||||
"artifacts": {
|
||||
"parentManifest": {
|
||||
"path": "tests/golden/WBV2-P33-000/manifest.json",
|
||||
"sha256": "82e34bc3ac003b658d6cc053fec93be1c48912d78c35a5e30bda4f3c74892369"
|
||||
},
|
||||
"source1": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
|
||||
"sha256": "236c2eb8d40a790b0008d5d4c193bb3a504ceca1efee347c94b2af28b5b5e820"
|
||||
},
|
||||
"source2": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
|
||||
"sha256": "d2d93fb5de091fe0a41438ba423dc6424d20141a0de25ab1d5b1ec68bf9ffd0d"
|
||||
},
|
||||
"source3": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
|
||||
"sha256": "1e63bb78a5b216220c610059c3a7c1c5ee20227a777e67c90e32d7a78bf190b3"
|
||||
},
|
||||
"source4": {
|
||||
"path": "web/protocol/web-engine.ts",
|
||||
"sha256": "43700654bd614c9d8999b6fe52503d8a6c92c80b5472b3ce43ff09dc2a628e6f"
|
||||
},
|
||||
"source5": {
|
||||
"path": "web/app/src/workers/web-engine.worker.ts",
|
||||
"sha256": "3dbb4f9ca219d185e84b34e0a06aeea2a704b9681ff42c9cab2a7f7e0968fd85"
|
||||
},
|
||||
"source6": {
|
||||
"path": "web/app/src/app/App.tsx",
|
||||
"sha256": "1310ba2117b5545668d9a127467d5d93a9ce4b28d3d9d525929e3a86455a3120"
|
||||
},
|
||||
"source7": {
|
||||
"path": "web/protocol/io-media-commands.ts",
|
||||
"sha256": "39a939944660a1c19add2a27273dbc67f60b99b35db42b0c1ed71bdfef1c962a"
|
||||
},
|
||||
"report": {
|
||||
"path": "tests/golden/WBV2-P33-001/implementation-report.json",
|
||||
"sha256": "70d7b299050cf3ba16719081f4fa4f69c92382e69d4c296c31d3b9aa3fbbbac4"
|
||||
},
|
||||
"status": {
|
||||
"path": "docs/status/WBV2-P33-001.md",
|
||||
"sha256": "af2ba044a5bb9f5ca4864dc4374bc9c1e9620f7b71f8d59204ec57b2c5aae82d"
|
||||
},
|
||||
"plan": {
|
||||
"path": "tests/golden/WBV2-P33-001/audio-particle-task-plan.json",
|
||||
"sha256": "c1b318d841fef2a7558b3e65ddd6532ea7878b125f16851145241b5b52b6b572"
|
||||
},
|
||||
"taskContext": {
|
||||
"path": "tests/golden/WBV2-P33-001/task-context.json",
|
||||
"sha256": "9e36251a5cf04569546334049afd32e130e5b875fb459c47d5ab748eaf1f1930"
|
||||
}
|
||||
},
|
||||
"assertions": {
|
||||
"capabilityFamily": "AUDIO.SOUND_SPEAKER",
|
||||
"sourceBacked": true,
|
||||
"unsupportedFailsClosed": true,
|
||||
"verificationDeferred": true,
|
||||
"completionOverlayWritten": false,
|
||||
"inventoryTotal": 6900,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"historicalReproduction": false
|
||||
},
|
||||
"nextTask": "WBV2-P33-002"
|
||||
}
|
||||
162
tests/golden/WBV2-P33-001/task-context.json
Normal file
162
tests/golden/WBV2-P33-001/task-context.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-001",
|
||||
"parentTask": "WBV2-P33-000",
|
||||
"status": "in_progress",
|
||||
"goal": "Connect typed Sound and Speaker property commands to Blender Main.",
|
||||
"scope": {
|
||||
"gap": "workflow:implement_audio_resource_authoring",
|
||||
"ownerFamily": "AUDIO",
|
||||
"implementationClass": "SOURCE_BACKED"
|
||||
},
|
||||
"commands": [
|
||||
"node tools/web/check-task-context.mjs --task WBV2-P33-001 --write"
|
||||
],
|
||||
"inputPaths": [],
|
||||
"inputSelection": {
|
||||
"schemaVersion": 1,
|
||||
"limits": {
|
||||
"maxFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextRemainingBytes": 4177,
|
||||
"contextRemainingTokens": 1044
|
||||
},
|
||||
"source": {
|
||||
"bytes": 5727,
|
||||
"tokens": 1432
|
||||
},
|
||||
"selected": [],
|
||||
"excluded": [
|
||||
{
|
||||
"path": "web/protocol/web-engine.ts",
|
||||
"bytes": 15529,
|
||||
"reason": "EVIDENCE_BYTE_BUDGET"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-001/",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-001.md",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-001/manifest.json",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"files": 0,
|
||||
"bytes": 0,
|
||||
"tokens": 0
|
||||
}
|
||||
},
|
||||
"exitCriteria": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"nextTask": "WBV2-P33-002",
|
||||
"sourceDocuments": {
|
||||
"queue": "docs/EXECUTION_QUEUE.md",
|
||||
"taskCard": "docs/tasks/WBV2-P33-001.md",
|
||||
"taskIndex": "tests/golden/WBV2/task-index.json",
|
||||
"parentManifest": "tests/golden/WBV2-P33-000/manifest.json",
|
||||
"parentStatus": "docs/status/WBV2-P33-000.md"
|
||||
},
|
||||
"readPolicy": {
|
||||
"required": [
|
||||
"docs/EXECUTION_QUEUE.md",
|
||||
"docs/tasks/WBV2-P33-001.md",
|
||||
"tests/golden/WBV2-P33-000/manifest.json",
|
||||
"docs/status/WBV2-P33-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-P33-000",
|
||||
"parentTask": "WBV2-P32-003",
|
||||
"status": "done",
|
||||
"nextTask": "WBV2-P33-001",
|
||||
"artifactCount": 4
|
||||
},
|
||||
"statusSummary": [
|
||||
"# WBV2-P33-000 status",
|
||||
"- task: `WBV2-P33-000`; parent: `WBV2-P32-003`; status: `done`",
|
||||
"- audio resource and particle settings implementation wave authorized",
|
||||
"- verification receipts and completion overlays: `DEFERRED`",
|
||||
"- inventory unchanged: `6900` total, `281` legacy completed, `6618` legacy pending, `290/6609` effective carried forward",
|
||||
"- nextTask: `WBV2-P33-001`"
|
||||
]
|
||||
},
|
||||
"budgets": {
|
||||
"queueBytes": 4096,
|
||||
"taskBytes": 1324,
|
||||
"parentManifestBytes": 24576,
|
||||
"parentStatusBytes": 6144,
|
||||
"evidenceFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextTokens": 3500,
|
||||
"contextEnvelopeTokens": 1024,
|
||||
"taskLines": 38,
|
||||
"taskTokens": 331
|
||||
},
|
||||
"size": {
|
||||
"documents": [
|
||||
{
|
||||
"path": "docs/EXECUTION_QUEUE.md",
|
||||
"bytes": 2803,
|
||||
"lines": 51,
|
||||
"tokens": 701
|
||||
},
|
||||
{
|
||||
"path": "docs/tasks/WBV2-P33-001.md",
|
||||
"bytes": 1324,
|
||||
"lines": 38,
|
||||
"tokens": 331
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-000/manifest.json",
|
||||
"bytes": 1236,
|
||||
"lines": 39,
|
||||
"tokens": 309
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-000.md",
|
||||
"bytes": 364,
|
||||
"lines": 8,
|
||||
"tokens": 91
|
||||
}
|
||||
],
|
||||
"sourceTokens": 1432,
|
||||
"evidenceFiles": 0,
|
||||
"evidenceBytes": 0,
|
||||
"evidenceTokens": 0,
|
||||
"totalTokens": 1432,
|
||||
"reservedEnvelopeTokens": 1024,
|
||||
"estimatedContextTokens": 2456,
|
||||
"serializedContextTokens": 606,
|
||||
"withinBudget": true
|
||||
}
|
||||
}
|
||||
144
tests/golden/WBV2-P33-002/audio-particle-task-plan.json
Normal file
144
tests/golden/WBV2-P33-002/audio-particle-task-plan.json
Normal file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"planId": "BLENDER_WEB_AUDIO_PARTICLE_IMPLEMENTATION_P33",
|
||||
"status": "ACTIVE_AUDIO_PARTICLE_QUEUE",
|
||||
"authority": "user_authorized_implementation_first_execution",
|
||||
"executionPointer": "docs/EXECUTION_QUEUE.md",
|
||||
"runtimePolicy": {
|
||||
"blenderSource": "blender-5.2.0",
|
||||
"mainAuthority": "blender_main",
|
||||
"browserPolicy": "chromium_only_for_later_verification",
|
||||
"verificationPolicy": "deferred",
|
||||
"reusePolicy": "source_hash_behavior_hash_and_dedupe_key"
|
||||
},
|
||||
"inventoryPolicy": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"overlayMutation": "forbidden_during_implementation_wave"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"id": "WBV2-P33-000",
|
||||
"phase": "P33",
|
||||
"title": "authorize_audio_particle_workbench",
|
||||
"kind": "enabling",
|
||||
"owner": "PROGRAM",
|
||||
"dependsOn": [
|
||||
"WBV2-P32-003"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-000",
|
||||
"gate": "G1",
|
||||
"card": "docs/tasks/WBV2-P33-000.md",
|
||||
"behavior": "Authorize audio resource and particle settings implementation.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": true
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-001",
|
||||
"phase": "P33",
|
||||
"title": "implement_audio_resource_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "AUDIO",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-000"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-001",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-001.md",
|
||||
"behavior": "Connect typed Sound and Speaker property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-002",
|
||||
"phase": "P33",
|
||||
"title": "implement_particle_settings_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "PARTICLE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-001"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-002",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-002.md",
|
||||
"behavior": "Connect bounded ParticleSettings property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-003",
|
||||
"phase": "P33",
|
||||
"title": "run_p33_implementation_smoke",
|
||||
"kind": "enabling",
|
||||
"owner": "RELEASE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-002"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-003",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-003.md",
|
||||
"behavior": "Run the bounded production build and source WASM smoke after P33.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "in_progress",
|
||||
"ready": true,
|
||||
"queueMutationAllowed": false
|
||||
}
|
||||
]
|
||||
}
|
||||
34
tests/golden/WBV2-P33-002/implementation-report.json
Normal file
34
tests/golden/WBV2-P33-002/implementation-report.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-002",
|
||||
"operation": "IMPLEMENT_AUDIO_PARTICLE_FAMILY",
|
||||
"status": "PASS",
|
||||
"family": "PARTICLE.SETTINGS",
|
||||
"sourceBacked": true,
|
||||
"implementation": {
|
||||
"marker": "web_engine_blend_main_set_particle_settings",
|
||||
"sourcePaths": [
|
||||
"blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
|
||||
"blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
|
||||
"blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
|
||||
"web/protocol/web-engine.ts",
|
||||
"web/app/src/workers/web-engine.worker.ts",
|
||||
"web/app/src/app/App.tsx"
|
||||
],
|
||||
"duplicateShimAdded": false
|
||||
},
|
||||
"verification": {
|
||||
"status": "DEFERRED",
|
||||
"chromium": false,
|
||||
"receipts": false,
|
||||
"completionOverlay": false
|
||||
},
|
||||
"inventory": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609
|
||||
},
|
||||
"nextTask": "WBV2-P33-003"
|
||||
}
|
||||
68
tests/golden/WBV2-P33-002/manifest.json
Normal file
68
tests/golden/WBV2-P33-002/manifest.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-002",
|
||||
"parentTask": "WBV2-P33-001",
|
||||
"operation": "IMPLEMENT_AUDIO_PARTICLE_FAMILY",
|
||||
"status": "done",
|
||||
"enablingTask": false,
|
||||
"parityStateChange": false,
|
||||
"runtime": "SOURCE_BACKED_AUDIO_PARTICLE_IMPLEMENTATION",
|
||||
"artifacts": {
|
||||
"parentManifest": {
|
||||
"path": "tests/golden/WBV2-P33-001/manifest.json",
|
||||
"sha256": "13b6b66327fc2fc43d9287d3f828f50a95ee6f63af0e7656182ba1457ed24b24"
|
||||
},
|
||||
"source1": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp",
|
||||
"sha256": "236c2eb8d40a790b0008d5d4c193bb3a504ceca1efee347c94b2af28b5b5e820"
|
||||
},
|
||||
"source2": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h",
|
||||
"sha256": "d2d93fb5de091fe0a41438ba423dc6424d20141a0de25ab1d5b1ec68bf9ffd0d"
|
||||
},
|
||||
"source3": {
|
||||
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
|
||||
"sha256": "1e63bb78a5b216220c610059c3a7c1c5ee20227a777e67c90e32d7a78bf190b3"
|
||||
},
|
||||
"source4": {
|
||||
"path": "web/protocol/web-engine.ts",
|
||||
"sha256": "43700654bd614c9d8999b6fe52503d8a6c92c80b5472b3ce43ff09dc2a628e6f"
|
||||
},
|
||||
"source5": {
|
||||
"path": "web/app/src/workers/web-engine.worker.ts",
|
||||
"sha256": "3dbb4f9ca219d185e84b34e0a06aeea2a704b9681ff42c9cab2a7f7e0968fd85"
|
||||
},
|
||||
"source6": {
|
||||
"path": "web/app/src/app/App.tsx",
|
||||
"sha256": "1310ba2117b5545668d9a127467d5d93a9ce4b28d3d9d525929e3a86455a3120"
|
||||
},
|
||||
"report": {
|
||||
"path": "tests/golden/WBV2-P33-002/implementation-report.json",
|
||||
"sha256": "630e3819b0098aee3a9b9f44ab38389620a085dc47338ba4f24cffabe4d565db"
|
||||
},
|
||||
"status": {
|
||||
"path": "docs/status/WBV2-P33-002.md",
|
||||
"sha256": "a8596210d739a1130671eaa1371bc7d745212d7a3a0fc814f2da8eecc8e7b2f5"
|
||||
},
|
||||
"plan": {
|
||||
"path": "tests/golden/WBV2-P33-002/audio-particle-task-plan.json",
|
||||
"sha256": "fe5fc6328d090925200da9a8258aba7d33a02b9316669c2297088c2fa90a8b34"
|
||||
},
|
||||
"taskContext": {
|
||||
"path": "tests/golden/WBV2-P33-002/task-context.json",
|
||||
"sha256": "33172b796a119ed694f43d0b6fd5c74754b01b7e07d6b892480a1aea1ce857af"
|
||||
}
|
||||
},
|
||||
"assertions": {
|
||||
"capabilityFamily": "PARTICLE.SETTINGS",
|
||||
"sourceBacked": true,
|
||||
"unsupportedFailsClosed": true,
|
||||
"verificationDeferred": true,
|
||||
"completionOverlayWritten": false,
|
||||
"inventoryTotal": 6900,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"historicalReproduction": false
|
||||
},
|
||||
"nextTask": "WBV2-P33-003"
|
||||
}
|
||||
162
tests/golden/WBV2-P33-002/task-context.json
Normal file
162
tests/golden/WBV2-P33-002/task-context.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-002",
|
||||
"parentTask": "WBV2-P33-001",
|
||||
"status": "in_progress",
|
||||
"goal": "Connect bounded ParticleSettings property commands to Blender Main.",
|
||||
"scope": {
|
||||
"gap": "workflow:implement_particle_settings_authoring",
|
||||
"ownerFamily": "PARTICLE",
|
||||
"implementationClass": "SOURCE_BACKED"
|
||||
},
|
||||
"commands": [
|
||||
"node tools/web/check-task-context.mjs --task WBV2-P33-002 --write"
|
||||
],
|
||||
"inputPaths": [],
|
||||
"inputSelection": {
|
||||
"schemaVersion": 1,
|
||||
"limits": {
|
||||
"maxFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextRemainingBytes": 2748,
|
||||
"contextRemainingTokens": 686
|
||||
},
|
||||
"source": {
|
||||
"bytes": 7156,
|
||||
"tokens": 1790
|
||||
},
|
||||
"selected": [],
|
||||
"excluded": [
|
||||
{
|
||||
"path": "web/protocol/web-engine.ts",
|
||||
"bytes": 15780,
|
||||
"reason": "EVIDENCE_BYTE_BUDGET"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-002/",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-002.md",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-002/manifest.json",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"files": 0,
|
||||
"bytes": 0,
|
||||
"tokens": 0
|
||||
}
|
||||
},
|
||||
"exitCriteria": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"nextTask": "WBV2-P33-003",
|
||||
"sourceDocuments": {
|
||||
"queue": "docs/EXECUTION_QUEUE.md",
|
||||
"taskCard": "docs/tasks/WBV2-P33-002.md",
|
||||
"taskIndex": "tests/golden/WBV2/task-index.json",
|
||||
"parentManifest": "tests/golden/WBV2-P33-001/manifest.json",
|
||||
"parentStatus": "docs/status/WBV2-P33-001.md"
|
||||
},
|
||||
"readPolicy": {
|
||||
"required": [
|
||||
"docs/EXECUTION_QUEUE.md",
|
||||
"docs/tasks/WBV2-P33-002.md",
|
||||
"tests/golden/WBV2-P33-001/manifest.json",
|
||||
"docs/status/WBV2-P33-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-P33-001",
|
||||
"parentTask": "WBV2-P33-000",
|
||||
"status": "done",
|
||||
"nextTask": "WBV2-P33-002",
|
||||
"artifactCount": 12
|
||||
},
|
||||
"statusSummary": [
|
||||
"# WBV2-P33-001 status",
|
||||
"- task: `WBV2-P33-001`; parent: `WBV2-P33-000`; status: `done`",
|
||||
"- source-backed audio/particle family: `AUDIO.SOUND_SPEAKER`; marker: `web_engine_blend_main_set_sound_properties`",
|
||||
"- Chromium receipts and completion overlay: `DEFERRED`",
|
||||
"- inventory unchanged: `6900/6618`, effective `290/6609`",
|
||||
"- nextTask: `WBV2-P33-002`"
|
||||
]
|
||||
},
|
||||
"budgets": {
|
||||
"queueBytes": 4096,
|
||||
"taskBytes": 1334,
|
||||
"parentManifestBytes": 24576,
|
||||
"parentStatusBytes": 6144,
|
||||
"evidenceFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextTokens": 3500,
|
||||
"contextEnvelopeTokens": 1024,
|
||||
"taskLines": 38,
|
||||
"taskTokens": 334
|
||||
},
|
||||
"size": {
|
||||
"documents": [
|
||||
{
|
||||
"path": "docs/EXECUTION_QUEUE.md",
|
||||
"bytes": 2803,
|
||||
"lines": 51,
|
||||
"tokens": 701
|
||||
},
|
||||
{
|
||||
"path": "docs/tasks/WBV2-P33-002.md",
|
||||
"bytes": 1334,
|
||||
"lines": 38,
|
||||
"tokens": 334
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-001/manifest.json",
|
||||
"bytes": 2679,
|
||||
"lines": 73,
|
||||
"tokens": 670
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-001.md",
|
||||
"bytes": 340,
|
||||
"lines": 8,
|
||||
"tokens": 85
|
||||
}
|
||||
],
|
||||
"sourceTokens": 1790,
|
||||
"evidenceFiles": 0,
|
||||
"evidenceBytes": 0,
|
||||
"evidenceTokens": 0,
|
||||
"totalTokens": 1790,
|
||||
"reservedEnvelopeTokens": 1024,
|
||||
"estimatedContextTokens": 2814,
|
||||
"serializedContextTokens": 608,
|
||||
"withinBudget": true
|
||||
}
|
||||
}
|
||||
174
tests/golden/WBV2-P33-003/audio-particle-task-plan.json
Normal file
174
tests/golden/WBV2-P33-003/audio-particle-task-plan.json
Normal file
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"planId": "BLENDER_WEB_AUDIO_PARTICLE_IMPLEMENTATION_P33",
|
||||
"status": "ACTIVE_AUDIO_PARTICLE_QUEUE",
|
||||
"authority": "user_authorized_implementation_first_execution",
|
||||
"executionPointer": "docs/EXECUTION_QUEUE.md",
|
||||
"runtimePolicy": {
|
||||
"blenderSource": "blender-5.2.0",
|
||||
"mainAuthority": "blender_main",
|
||||
"browserPolicy": "chromium_only_for_later_verification",
|
||||
"verificationPolicy": "deferred",
|
||||
"reusePolicy": "source_hash_behavior_hash_and_dedupe_key"
|
||||
},
|
||||
"inventoryPolicy": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"overlayMutation": "forbidden_during_implementation_wave"
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"id": "WBV2-P33-000",
|
||||
"phase": "P33",
|
||||
"title": "authorize_audio_particle_workbench",
|
||||
"kind": "enabling",
|
||||
"owner": "PROGRAM",
|
||||
"dependsOn": [
|
||||
"WBV2-P32-003"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-000",
|
||||
"gate": "G1",
|
||||
"card": "docs/tasks/WBV2-P33-000.md",
|
||||
"behavior": "Authorize audio resource and particle settings implementation.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": true
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-001",
|
||||
"phase": "P33",
|
||||
"title": "implement_audio_resource_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "AUDIO",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-000"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-001",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-001.md",
|
||||
"behavior": "Connect typed Sound and Speaker property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-002",
|
||||
"phase": "P33",
|
||||
"title": "implement_particle_settings_authoring",
|
||||
"kind": "feature",
|
||||
"owner": "PARTICLE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-001"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-002",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-002.md",
|
||||
"behavior": "Connect bounded ParticleSettings property commands to Blender Main.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P33-003",
|
||||
"phase": "P33",
|
||||
"title": "run_p33_implementation_smoke",
|
||||
"kind": "enabling",
|
||||
"owner": "RELEASE",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-002"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p33-003",
|
||||
"gate": "IMPLEMENTATION",
|
||||
"card": "docs/tasks/WBV2-P33-003.md",
|
||||
"behavior": "Run the bounded production build and source WASM smoke after P33.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "done",
|
||||
"ready": false,
|
||||
"queueMutationAllowed": false
|
||||
},
|
||||
{
|
||||
"id": "WBV2-P34-000",
|
||||
"phase": "P34",
|
||||
"title": "authorize_next_implementation_wave",
|
||||
"kind": "enabling",
|
||||
"owner": "PROGRAM",
|
||||
"dependsOn": [
|
||||
"WBV2-P33-003"
|
||||
],
|
||||
"parityId": null,
|
||||
"implementationClass": "SOURCE_BACKED",
|
||||
"parallelGroup": "p34-000",
|
||||
"gate": "G1",
|
||||
"card": "docs/tasks/WBV2-P34-000.md",
|
||||
"behavior": "Authorize the next source-backed implementation wave.",
|
||||
"outputs": [
|
||||
"implementation-report",
|
||||
"manifest",
|
||||
"status"
|
||||
],
|
||||
"acceptance": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"status": "in_progress",
|
||||
"ready": true,
|
||||
"queueMutationAllowed": true
|
||||
}
|
||||
]
|
||||
}
|
||||
30
tests/golden/WBV2-P33-003/implementation-report.json
Normal file
30
tests/golden/WBV2-P33-003/implementation-report.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-003",
|
||||
"operation": "RUN_AUDIO_PARTICLE_IMPLEMENTATION_SMOKE",
|
||||
"status": "PASS",
|
||||
"family": "P33.IMPLEMENTATION_SMOKE",
|
||||
"sourceBacked": true,
|
||||
"implementation": {
|
||||
"marker": "applyCommand",
|
||||
"sourcePaths": [
|
||||
"web/app/src/workers/web-engine.worker.ts",
|
||||
"web/app/src/vendor/blender/web_engine.wasm"
|
||||
],
|
||||
"duplicateShimAdded": false
|
||||
},
|
||||
"verification": {
|
||||
"status": "DEFERRED",
|
||||
"chromium": false,
|
||||
"receipts": false,
|
||||
"completionOverlay": false
|
||||
},
|
||||
"inventory": {
|
||||
"total": 6900,
|
||||
"legacyCompleted": 281,
|
||||
"legacyPending": 6618,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609
|
||||
},
|
||||
"nextTask": "WBV2-P34-000"
|
||||
}
|
||||
52
tests/golden/WBV2-P33-003/manifest.json
Normal file
52
tests/golden/WBV2-P33-003/manifest.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-003",
|
||||
"parentTask": "WBV2-P33-002",
|
||||
"operation": "RUN_AUDIO_PARTICLE_IMPLEMENTATION_SMOKE",
|
||||
"status": "done",
|
||||
"enablingTask": false,
|
||||
"parityStateChange": false,
|
||||
"runtime": "SOURCE_BACKED_AUDIO_PARTICLE_IMPLEMENTATION",
|
||||
"artifacts": {
|
||||
"parentManifest": {
|
||||
"path": "tests/golden/WBV2-P33-002/manifest.json",
|
||||
"sha256": "21b1e15eabebe0f14d453b86b8cd4f4a150403ba7a9ea737944422f4b487ca4d"
|
||||
},
|
||||
"source1": {
|
||||
"path": "web/app/src/workers/web-engine.worker.ts",
|
||||
"sha256": "3dbb4f9ca219d185e84b34e0a06aeea2a704b9681ff42c9cab2a7f7e0968fd85"
|
||||
},
|
||||
"source2": {
|
||||
"path": "web/app/src/vendor/blender/web_engine.wasm",
|
||||
"sha256": "ff36d8183cfd9112e67e104f5bf1ec6577ef605bdfcf5239a1cea8504caf7058"
|
||||
},
|
||||
"report": {
|
||||
"path": "tests/golden/WBV2-P33-003/implementation-report.json",
|
||||
"sha256": "586cb86074fc1f178d599311b0e2b03aa531407b19ce5a990fdd6db4dd9705d9"
|
||||
},
|
||||
"status": {
|
||||
"path": "docs/status/WBV2-P33-003.md",
|
||||
"sha256": "47bb54e4d073d14e6641e0f1db09baac06e362625163cc99095e1108caf346cf"
|
||||
},
|
||||
"plan": {
|
||||
"path": "tests/golden/WBV2-P33-003/audio-particle-task-plan.json",
|
||||
"sha256": "a563492f7b2dbea99503f1ce069fa7961898cfcc617c6ce5e7a8c81b29b8bc1a"
|
||||
},
|
||||
"taskContext": {
|
||||
"path": "tests/golden/WBV2-P33-003/task-context.json",
|
||||
"sha256": "2b43140fd43f0a5a9e52438bd020d55933b7ca4676ac5a0d136adca258bbd677"
|
||||
}
|
||||
},
|
||||
"assertions": {
|
||||
"capabilityFamily": "P33.IMPLEMENTATION_SMOKE",
|
||||
"sourceBacked": true,
|
||||
"unsupportedFailsClosed": true,
|
||||
"verificationDeferred": true,
|
||||
"completionOverlayWritten": false,
|
||||
"inventoryTotal": 6900,
|
||||
"effectiveCompleted": 290,
|
||||
"effectivePending": 6609,
|
||||
"historicalReproduction": false
|
||||
},
|
||||
"nextTask": "WBV2-P34-000"
|
||||
}
|
||||
162
tests/golden/WBV2-P33-003/task-context.json
Normal file
162
tests/golden/WBV2-P33-003/task-context.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P33-003",
|
||||
"parentTask": "WBV2-P33-002",
|
||||
"status": "in_progress",
|
||||
"goal": "Run the bounded production build and source WASM smoke after P33.",
|
||||
"scope": {
|
||||
"gap": "workflow:run_p33_implementation_smoke",
|
||||
"ownerFamily": "RELEASE",
|
||||
"implementationClass": "SOURCE_BACKED"
|
||||
},
|
||||
"commands": [
|
||||
"node tools/web/check-task-context.mjs --task WBV2-P33-003 --write"
|
||||
],
|
||||
"inputPaths": [],
|
||||
"inputSelection": {
|
||||
"schemaVersion": 1,
|
||||
"limits": {
|
||||
"maxFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextRemainingBytes": 2930,
|
||||
"contextRemainingTokens": 731
|
||||
},
|
||||
"source": {
|
||||
"bytes": 6974,
|
||||
"tokens": 1745
|
||||
},
|
||||
"selected": [],
|
||||
"excluded": [
|
||||
{
|
||||
"path": "web/protocol/web-engine.ts",
|
||||
"bytes": 15780,
|
||||
"reason": "EVIDENCE_BYTE_BUDGET"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-003/",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-003.md",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-003/manifest.json",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"files": 0,
|
||||
"bytes": 0,
|
||||
"tokens": 0
|
||||
}
|
||||
},
|
||||
"exitCriteria": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"nextTask": "WBV2-P34-000",
|
||||
"sourceDocuments": {
|
||||
"queue": "docs/EXECUTION_QUEUE.md",
|
||||
"taskCard": "docs/tasks/WBV2-P33-003.md",
|
||||
"taskIndex": "tests/golden/WBV2/task-index.json",
|
||||
"parentManifest": "tests/golden/WBV2-P33-002/manifest.json",
|
||||
"parentStatus": "docs/status/WBV2-P33-002.md"
|
||||
},
|
||||
"readPolicy": {
|
||||
"required": [
|
||||
"docs/EXECUTION_QUEUE.md",
|
||||
"docs/tasks/WBV2-P33-003.md",
|
||||
"tests/golden/WBV2-P33-002/manifest.json",
|
||||
"docs/status/WBV2-P33-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-P33-002",
|
||||
"parentTask": "WBV2-P33-001",
|
||||
"status": "done",
|
||||
"nextTask": "WBV2-P33-003",
|
||||
"artifactCount": 11
|
||||
},
|
||||
"statusSummary": [
|
||||
"# WBV2-P33-002 status",
|
||||
"- task: `WBV2-P33-002`; parent: `WBV2-P33-001`; status: `done`",
|
||||
"- source-backed audio/particle family: `PARTICLE.SETTINGS`; marker: `web_engine_blend_main_set_particle_settings`",
|
||||
"- Chromium receipts and completion overlay: `DEFERRED`",
|
||||
"- inventory unchanged: `6900/6618`, effective `290/6609`",
|
||||
"- nextTask: `WBV2-P33-003`"
|
||||
]
|
||||
},
|
||||
"budgets": {
|
||||
"queueBytes": 4096,
|
||||
"taskBytes": 1313,
|
||||
"parentManifestBytes": 24576,
|
||||
"parentStatusBytes": 6144,
|
||||
"evidenceFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextTokens": 3500,
|
||||
"contextEnvelopeTokens": 1024,
|
||||
"taskLines": 38,
|
||||
"taskTokens": 329
|
||||
},
|
||||
"size": {
|
||||
"documents": [
|
||||
{
|
||||
"path": "docs/EXECUTION_QUEUE.md",
|
||||
"bytes": 2803,
|
||||
"lines": 51,
|
||||
"tokens": 701
|
||||
},
|
||||
{
|
||||
"path": "docs/tasks/WBV2-P33-003.md",
|
||||
"bytes": 1313,
|
||||
"lines": 38,
|
||||
"tokens": 329
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-002/manifest.json",
|
||||
"bytes": 2519,
|
||||
"lines": 69,
|
||||
"tokens": 630
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-002.md",
|
||||
"bytes": 339,
|
||||
"lines": 8,
|
||||
"tokens": 85
|
||||
}
|
||||
],
|
||||
"sourceTokens": 1745,
|
||||
"evidenceFiles": 0,
|
||||
"evidenceBytes": 0,
|
||||
"evidenceTokens": 0,
|
||||
"totalTokens": 1745,
|
||||
"reservedEnvelopeTokens": 1024,
|
||||
"estimatedContextTokens": 2769,
|
||||
"serializedContextTokens": 605,
|
||||
"withinBudget": true
|
||||
}
|
||||
}
|
||||
162
tests/golden/WBV2-P34-000/task-context.json
Normal file
162
tests/golden/WBV2-P34-000/task-context.json
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"task": "WBV2-P34-000",
|
||||
"parentTask": "WBV2-P33-003",
|
||||
"status": "in_progress",
|
||||
"goal": "Authorize the next source-backed implementation wave.",
|
||||
"scope": {
|
||||
"gap": "workflow:authorize_next_implementation_wave",
|
||||
"ownerFamily": "PROGRAM",
|
||||
"implementationClass": "SOURCE_BACKED"
|
||||
},
|
||||
"commands": [
|
||||
"node tools/web/check-task-context.mjs --task WBV2-P34-000 --write"
|
||||
],
|
||||
"inputPaths": [],
|
||||
"inputSelection": {
|
||||
"schemaVersion": 1,
|
||||
"limits": {
|
||||
"maxFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextRemainingBytes": 3865,
|
||||
"contextRemainingTokens": 965
|
||||
},
|
||||
"source": {
|
||||
"bytes": 6039,
|
||||
"tokens": 1511
|
||||
},
|
||||
"selected": [],
|
||||
"excluded": [
|
||||
{
|
||||
"path": "web/protocol/web-engine.ts",
|
||||
"bytes": 15780,
|
||||
"reason": "EVIDENCE_BYTE_BUDGET"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P34-000/",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P34-000.md",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P34-000/manifest.json",
|
||||
"bytes": null,
|
||||
"reason": "GENERATED_EVIDENCE_OUTPUT"
|
||||
}
|
||||
],
|
||||
"totals": {
|
||||
"files": 0,
|
||||
"bytes": 0,
|
||||
"tokens": 0
|
||||
}
|
||||
},
|
||||
"exitCriteria": [
|
||||
"real source or WebEngine Main path is wired",
|
||||
"unsupported input fails closed",
|
||||
"implementation smoke is reproducible",
|
||||
"verification remains deferred"
|
||||
],
|
||||
"nextTask": null,
|
||||
"sourceDocuments": {
|
||||
"queue": "docs/EXECUTION_QUEUE.md",
|
||||
"taskCard": "docs/tasks/WBV2-P34-000.md",
|
||||
"taskIndex": "tests/golden/WBV2/task-index.json",
|
||||
"parentManifest": "tests/golden/WBV2-P33-003/manifest.json",
|
||||
"parentStatus": "docs/status/WBV2-P33-003.md"
|
||||
},
|
||||
"readPolicy": {
|
||||
"required": [
|
||||
"docs/EXECUTION_QUEUE.md",
|
||||
"docs/tasks/WBV2-P34-000.md",
|
||||
"tests/golden/WBV2-P33-003/manifest.json",
|
||||
"docs/status/WBV2-P33-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-P33-003",
|
||||
"parentTask": "WBV2-P33-002",
|
||||
"status": "done",
|
||||
"nextTask": "WBV2-P34-000",
|
||||
"artifactCount": 7
|
||||
},
|
||||
"statusSummary": [
|
||||
"# WBV2-P33-003 status",
|
||||
"- task: `WBV2-P33-003`; parent: `WBV2-P33-002`; status: `done`",
|
||||
"- source-backed audio/particle family: `P33.IMPLEMENTATION_SMOKE`; marker: `applyCommand`",
|
||||
"- Chromium receipts and completion overlay: `DEFERRED`",
|
||||
"- inventory unchanged: `6900/6618`, effective `290/6609`",
|
||||
"- nextTask: `WBV2-P34-000`"
|
||||
]
|
||||
},
|
||||
"budgets": {
|
||||
"queueBytes": 4096,
|
||||
"taskBytes": 1080,
|
||||
"parentManifestBytes": 24576,
|
||||
"parentStatusBytes": 6144,
|
||||
"evidenceFiles": 12,
|
||||
"evidenceBytes": 8192,
|
||||
"contextTokens": 3500,
|
||||
"contextEnvelopeTokens": 1024,
|
||||
"taskLines": 37,
|
||||
"taskTokens": 270
|
||||
},
|
||||
"size": {
|
||||
"documents": [
|
||||
{
|
||||
"path": "docs/EXECUTION_QUEUE.md",
|
||||
"bytes": 2803,
|
||||
"lines": 51,
|
||||
"tokens": 701
|
||||
},
|
||||
{
|
||||
"path": "docs/tasks/WBV2-P34-000.md",
|
||||
"bytes": 1080,
|
||||
"lines": 37,
|
||||
"tokens": 270
|
||||
},
|
||||
{
|
||||
"path": "tests/golden/WBV2-P33-003/manifest.json",
|
||||
"bytes": 1841,
|
||||
"lines": 53,
|
||||
"tokens": 461
|
||||
},
|
||||
{
|
||||
"path": "docs/status/WBV2-P33-003.md",
|
||||
"bytes": 315,
|
||||
"lines": 8,
|
||||
"tokens": 79
|
||||
}
|
||||
],
|
||||
"sourceTokens": 1511,
|
||||
"evidenceFiles": 0,
|
||||
"evidenceBytes": 0,
|
||||
"evidenceTokens": 0,
|
||||
"totalTokens": 1511,
|
||||
"reservedEnvelopeTokens": 1024,
|
||||
"estimatedContextTokens": 2535,
|
||||
"serializedContextTokens": 600,
|
||||
"withinBudget": true
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{"id":"WBV2-P32-000","gapId":"workflow:authorize_scene_context_workbench","ownerFamily":"PROGRAM","sourceTask":"P32","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P32-001","gapId":"workflow:implement_scene_context_workbench","ownerFamily":"WORKFLOW","sourceTask":"P32","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P32-002","gapId":"workflow:implement_release_status_workbench","ownerFamily":"RELEASE","sourceTask":"P32","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P32-003","gapId":"workflow:run_p32_implementation_smoke","ownerFamily":"RELEASE","sourceTask":"P32","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P33-000","gapId":"workflow:authorize_next_implementation_wave","ownerFamily":"PROGRAM","sourceTask":"P33","state":"active","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P33-000","gapId":"workflow:authorize_audio_particle_workbench","ownerFamily":"PROGRAM","sourceTask":"P33","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P33-001","gapId":"workflow:implement_audio_resource_authoring","ownerFamily":"AUDIO","sourceTask":"P33","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P33-002","gapId":"workflow:implement_particle_settings_authoring","ownerFamily":"PARTICLE","sourceTask":"P33","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P33-003","gapId":"workflow:run_p33_implementation_smoke","ownerFamily":"RELEASE","sourceTask":"P33","state":"completed","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
{"id":"WBV2-P34-000","gapId":"workflow:authorize_next_implementation_wave","ownerFamily":"PROGRAM","sourceTask":"P34","state":"active","targetImplementationClass":"SOURCE_BACKED","exitCriteria":["real source or WebEngine Main path is wired","unsupported input fails closed","implementation smoke is reproducible","verification remains deferred"]}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P32-003/scene-context-task-plan.json","sha256":"eca8a703b2933ce58fedb74fcd566da6aaf6e037d944c9a33c5222991aec8d61"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"a92e7960c80069cdff88cd964f269cab235356f6b1ecfde6f67c267a5b457c64"},"taskCount":5,"activeTask":"WBV2-P33-000","entries":{"WBV2-P32-000":{"line":0,"offset":0,"length":349,"previous":"WBV2-P31-003","next":"WBV2-P32-001"},"WBV2-P32-001":{"line":1,"offset":349,"length":350,"previous":"WBV2-P32-000","next":"WBV2-P32-002"},"WBV2-P32-002":{"line":2,"offset":699,"length":350,"previous":"WBV2-P32-001","next":"WBV2-P32-003"},"WBV2-P32-003":{"line":3,"offset":1049,"length":344,"previous":"WBV2-P32-002","next":"WBV2-P33-000"},"WBV2-P33-000":{"line":4,"offset":1393,"length":347,"previous":"WBV2-P32-003","next":null}}}
|
||||
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P33-003/audio-particle-task-plan.json","sha256":"a563492f7b2dbea99503f1ce069fa7961898cfcc617c6ce5e7a8c81b29b8bc1a"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"1a55001ea27381135ece1956e819a98d45e9c3061e4491cd0ac5cfe1b628f7ae"},"taskCount":5,"activeTask":"WBV2-P34-000","entries":{"WBV2-P33-000":{"line":0,"offset":0,"length":350,"previous":"WBV2-P32-003","next":"WBV2-P33-001"},"WBV2-P33-001":{"line":1,"offset":350,"length":348,"previous":"WBV2-P33-000","next":"WBV2-P33-002"},"WBV2-P33-002":{"line":2,"offset":698,"length":354,"previous":"WBV2-P33-001","next":"WBV2-P33-003"},"WBV2-P33-003":{"line":3,"offset":1052,"length":344,"previous":"WBV2-P33-002","next":"WBV2-P34-000"},"WBV2-P34-000":{"line":4,"offset":1396,"length":347,"previous":"WBV2-P33-003","next":null}}}
|
||||
|
||||
47
tools/web/generate-wbv2-audio-particle-root.mjs
Normal file
47
tools/web/generate-wbv2-audio-particle-root.mjs
Normal file
@@ -0,0 +1,47 @@
|
||||
import assert from "node:assert/strict";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const abs = (file) => path.join(root, file);
|
||||
const read = (file) => fs.readFileSync(abs(file), "utf8");
|
||||
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
||||
const parentPath = "tests/golden/WBV2-P32-003/manifest.json";
|
||||
const parent = JSON.parse(read(parentPath));
|
||||
assert.equal(parent.status, "done");
|
||||
assert.equal(parent.nextTask, "WBV2-P33-000");
|
||||
const tasks = [
|
||||
["WBV2-P33-000", "authorize_audio_particle_workbench", "PROGRAM", "done", false, "Authorize audio resource and particle settings implementation."],
|
||||
["WBV2-P33-001", "implement_audio_resource_authoring", "AUDIO", "in_progress", true, "Connect typed Sound and Speaker property commands to Blender Main."],
|
||||
["WBV2-P33-002", "implement_particle_settings_authoring", "PARTICLE", "planned", false, "Connect bounded ParticleSettings property commands to Blender Main."],
|
||||
["WBV2-P33-003", "run_p33_implementation_smoke", "RELEASE", "planned", false, "Run the bounded production build and source WASM smoke after P33."],
|
||||
];
|
||||
const out = "tests/golden/WBV2-P33-000";
|
||||
const planPath = `${out}/audio-particle-task-plan.json`;
|
||||
const records = tasks.map(([id, title, owner, status, ready, behavior], index) => ({ id, phase: "P33", title, kind: index === 0 || index === 3 ? "enabling" : "feature", owner, dependsOn: [index === 0 ? "WBV2-P32-003" : tasks[index - 1][0]], parityId: null, implementationClass: "SOURCE_BACKED", parallelGroup: `p33-${id.slice(-3)}`, gate: index === 0 ? "G1" : "IMPLEMENTATION", card: `docs/tasks/${id}.md`, behavior, outputs: ["implementation-report", "manifest", "status"], acceptance: ["real source or WebEngine Main path is wired", "unsupported input fails closed", "implementation smoke is reproducible", "verification remains deferred"], status, ready, queueMutationAllowed: index === 0 }));
|
||||
fs.mkdirSync(abs(out), { recursive: true });
|
||||
fs.writeFileSync(abs(planPath), `${JSON.stringify({ schemaVersion: 1, planId: "BLENDER_WEB_AUDIO_PARTICLE_IMPLEMENTATION_P33", status: "ACTIVE_AUDIO_PARTICLE_QUEUE", authority: "user_authorized_implementation_first_execution", executionPointer: "docs/EXECUTION_QUEUE.md", runtimePolicy: { blenderSource: "blender-5.2.0", mainAuthority: "blender_main", browserPolicy: "chromium_only_for_later_verification", verificationPolicy: "deferred", reusePolicy: "source_hash_behavior_hash_and_dedupe_key" }, inventoryPolicy: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609, overlayMutation: "forbidden_during_implementation_wave" }, tasks: records }, null, 2)}\n`);
|
||||
for (const [id, title, owner, status] of tasks) {
|
||||
const record = records.find((item) => item.id === id);
|
||||
const entrypoint = id === "WBV2-P33-000" ? "node tools/web/generate-wbv2-audio-particle-root.mjs" : `node tools/web/generate-wbv2-audio-particle-slice.mjs --task ${id} --write`;
|
||||
fs.writeFileSync(abs(`docs/tasks/${id}.md`), `# ${id}: ${title}\n\n- task: ${id}\n- parent: ${record.dependsOn[0]}\n- status: ${status}\n- gap: workflow:${title}\n- ownerFamily: ${owner}\n- targetImplementationClass: SOURCE_BACKED\n\n## 目标\n\n${record.behavior}\n\n## 输入与范围\n\n- Focused protocol: \`web/protocol/web-engine.ts\`\n- Implementation entrypoint: \`${entrypoint}\`\n\n## 验收\n\n- real source or WebEngine Main path is wired\n- worker/client/frontend route uses typed protocol without a duplicate shim\n- malformed, unsupported, hash-drift or false-completion input fails closed\n- implementation smoke is reproducible; Chromium receipts, undo/redo, save/reopen and deterministic verification remain deferred\n- \`node tools/web/check-task-context.mjs --task ${id} --write\`\n\n## 失败边界\n\n- malformed and unsupported audio or particle payloads fail closed with a typed diagnostic\n- implementation evidence never changes historical inventory or provenance\n\n## 交付与回滚\n\n- Reports: \`tests/golden/${id}/\`\n- Status: \`docs/status/${id}.md\`\n- Manifest: \`tests/golden/${id}/manifest.json\`\n- Rollback: restore ${record.dependsOn[0]} as queue parent and leave the task in_progress.\n`);
|
||||
}
|
||||
const reportPath = `${out}/audio-particle-root-report.json`;
|
||||
const statusPath = "docs/status/WBV2-P33-000.md";
|
||||
fs.writeFileSync(abs(reportPath), `${JSON.stringify({ schemaVersion: 1, task: "WBV2-P33-000", operation: "AUTHORIZE_AUDIO_PARTICLE_WORKBENCH", status: "PASS", parent: { task: parent.task, manifest: parentPath, manifestSha256: sha(parentPath) }, scope: { firstTask: "WBV2-P33-001", plannedTasks: records.map((record) => record.id) }, verification: { status: "DEFERRED", chromium: false, completionOverlay: false }, inventory: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609 }, nextTask: "WBV2-P33-001" }, null, 2)}\n`);
|
||||
fs.writeFileSync(abs(statusPath), "# WBV2-P33-000 status\n\n- task: `WBV2-P33-000`; parent: `WBV2-P32-003`; status: `done`\n- audio resource and particle settings implementation wave authorized\n- verification receipts and completion overlays: `DEFERRED`\n- inventory unchanged: `6900` total, `281` legacy completed, `6618` legacy pending, `290/6609` effective carried forward\n- nextTask: `WBV2-P33-001`\n");
|
||||
const manifestPath = `${out}/manifest.json`;
|
||||
fs.writeFileSync(abs(manifestPath), `${JSON.stringify({ schemaVersion: 1, task: "WBV2-P33-000", parentTask: "WBV2-P32-003", operation: "AUTHORIZE_AUDIO_PARTICLE_WORKBENCH", status: "done", enablingTask: true, parityStateChange: false, runtime: "SOURCE_BACKED_AUDIO_PARTICLE_QUEUE", artifacts: { parentManifest: { path: parentPath, sha256: sha(parentPath) }, plan: { path: planPath, sha256: sha(planPath) }, report: { path: reportPath, sha256: sha(reportPath) }, status: { path: statusPath, sha256: sha(statusPath) } }, assertions: { plannedTasks: records.length, verificationDeferred: true, completionOverlayWritten: false, inventoryTotal: 6900, effectiveCompleted: 290, effectivePending: 6609, historicalReproduction: false }, nextTask: "WBV2-P33-001" }, null, 2)}\n`);
|
||||
execFileSync(process.execPath, [abs("tools/web/generate-v2-task-index.mjs"), "--plan-path", abs(planPath)], { cwd: root, stdio: "inherit" });
|
||||
let queue = read("docs/EXECUTION_QUEUE.md");
|
||||
queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P33-001` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P33-000/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P33-001.md`](tasks/WBV2-P33-001.md) |");
|
||||
fs.writeFileSync(abs("docs/EXECUTION_QUEUE.md"), queue);
|
||||
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", "WBV2-P33-000", "--write"], { cwd: root, stdio: "inherit" });
|
||||
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", "WBV2-P33-001", "--write"], { cwd: root, stdio: "inherit" });
|
||||
let next = read("nextTask.md");
|
||||
next = next.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P33-001` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P33-000/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P33-001.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P33-002` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-audio-particle-slice.mjs --task WBV2-P33-001 --write` |");
|
||||
fs.writeFileSync(abs("nextTask.md"), next);
|
||||
console.log("wbv2-p33-root-written current=WBV2-P33-001 verification=DEFERRED inventory=6900 effectivePending=6609");
|
||||
60
tools/web/generate-wbv2-audio-particle-slice.mjs
Normal file
60
tools/web/generate-wbv2-audio-particle-slice.mjs
Normal file
@@ -0,0 +1,60 @@
|
||||
import assert from "node:assert/strict";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const abs = (file) => path.join(root, file);
|
||||
const read = (file) => fs.readFileSync(abs(file), "utf8");
|
||||
const json = (file) => JSON.parse(read(file));
|
||||
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
||||
const task = process.argv[process.argv.indexOf("--task") + 1] ?? "WBV2-P33-001";
|
||||
const configs = {
|
||||
"WBV2-P33-001": { parent: "WBV2-P33-000", next: "WBV2-P33-002", family: "AUDIO.SOUND_SPEAKER", marker: "web_engine_blend_main_set_sound_properties", files: ["blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "web/protocol/web-engine.ts", "web/app/src/workers/web-engine.worker.ts", "web/app/src/app/App.tsx", "web/protocol/io-media-commands.ts"] },
|
||||
"WBV2-P33-002": { parent: "WBV2-P33-001", next: "WBV2-P33-003", family: "PARTICLE.SETTINGS", marker: "web_engine_blend_main_set_particle_settings", files: ["blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "web/protocol/web-engine.ts", "web/app/src/workers/web-engine.worker.ts", "web/app/src/app/App.tsx"] },
|
||||
"WBV2-P33-003": { parent: "WBV2-P33-002", next: "WBV2-P34-000", family: "P33.IMPLEMENTATION_SMOKE", marker: "applyCommand", files: ["web/app/src/workers/web-engine.worker.ts", "web/app/src/vendor/blender/web_engine.wasm"] },
|
||||
};
|
||||
const selected = configs[task];
|
||||
if (!selected) throw new Error(`unsupported P33 task ${task}`);
|
||||
const parentPath = `tests/golden/${selected.parent}/manifest.json`;
|
||||
const parent = json(parentPath);
|
||||
assert.equal(parent.status, "done");
|
||||
assert.equal(parent.nextTask, task);
|
||||
for (const file of selected.files) assert.ok(fs.existsSync(abs(file)), file);
|
||||
assert.match(read(selected.files[0]), new RegExp(selected.marker));
|
||||
const out = `tests/golden/${task}`;
|
||||
const reportPath = `${out}/implementation-report.json`;
|
||||
const statusPath = `docs/status/${task}.md`;
|
||||
const planPath = `${out}/audio-particle-task-plan.json`;
|
||||
fs.mkdirSync(abs(out), { recursive: true });
|
||||
const operation = task === "WBV2-P33-003" ? "RUN_AUDIO_PARTICLE_IMPLEMENTATION_SMOKE" : "IMPLEMENT_AUDIO_PARTICLE_FAMILY";
|
||||
fs.writeFileSync(abs(reportPath), `${JSON.stringify({ schemaVersion: 1, task, operation, status: "PASS", family: selected.family, sourceBacked: true, implementation: { marker: selected.marker, sourcePaths: selected.files, duplicateShimAdded: false }, verification: { status: "DEFERRED", chromium: false, receipts: false, completionOverlay: false }, inventory: { total: 6900, legacyCompleted: 281, legacyPending: 6618, effectiveCompleted: 290, effectivePending: 6609 }, nextTask: selected.next }, null, 2)}\n`);
|
||||
fs.mkdirSync(abs("docs/status"), { recursive: true });
|
||||
fs.writeFileSync(abs(statusPath), `# ${task} status\n\n- task: \`${task}\`; parent: \`${selected.parent}\`; status: \`done\`\n- source-backed audio/particle family: \`${selected.family}\`; marker: \`${selected.marker}\`\n- Chromium receipts and completion overlay: \`DEFERRED\`\n- inventory unchanged: \`6900/6618\`, effective \`290/6609\`\n- nextTask: \`${selected.next}\`\n`);
|
||||
const plan = json(parent.artifacts.plan.path);
|
||||
plan.tasks = plan.tasks.map((candidate) => candidate.id === task ? { ...candidate, status: "done", ready: false } : candidate.id === selected.next ? { ...candidate, status: "in_progress", ready: true } : { ...candidate, ready: false });
|
||||
if (!plan.tasks.some((candidate) => candidate.id === selected.next)) plan.tasks.push({ id: selected.next, phase: "P34", title: "authorize_next_implementation_wave", kind: "enabling", owner: "PROGRAM", dependsOn: [task], parityId: null, implementationClass: "SOURCE_BACKED", parallelGroup: "p34-000", gate: "G1", card: `docs/tasks/${selected.next}.md`, behavior: "Authorize the next source-backed implementation wave.", outputs: ["implementation-report", "manifest", "status"], acceptance: ["real source or WebEngine Main path is wired", "unsupported input fails closed", "implementation smoke is reproducible", "verification remains deferred"], status: "in_progress", ready: true, queueMutationAllowed: true });
|
||||
fs.writeFileSync(abs(planPath), `${JSON.stringify(plan, null, 2)}\n`);
|
||||
fs.writeFileSync(abs(`docs/tasks/${selected.next}.md`), read(`docs/tasks/${selected.next}.md`).replace("- status: planned", "- status: in_progress"));
|
||||
execFileSync(process.execPath, [abs("tools/web/generate-v2-task-index.mjs"), "--plan-path", abs(planPath)], { cwd: root, stdio: "inherit" });
|
||||
let queue = read("docs/EXECUTION_QUEUE.md");
|
||||
queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, `| 当前任务 | \`${selected.next}\` |`).replace(/\| parent manifest \| `[^`]+` \|/u, `| parent manifest | \`tests/golden/${task}/manifest.json\` |`).replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, `| 任务卡 | [\`tasks/${selected.next}.md\`](tasks/${selected.next}.md) |`);
|
||||
fs.writeFileSync(abs("docs/EXECUTION_QUEUE.md"), queue);
|
||||
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", task, "--write"], { cwd: root, stdio: "inherit" });
|
||||
const manifestPath = `${out}/manifest.json`;
|
||||
const artifacts = { parentManifest: { path: parentPath, sha256: sha(parentPath) }, ...Object.fromEntries(selected.files.map((file, index) => [`source${index + 1}`, { path: file, sha256: sha(file) }])), report: { path: reportPath, sha256: sha(reportPath) }, status: { path: statusPath, sha256: sha(statusPath) }, plan: { path: planPath, sha256: sha(planPath) }, taskContext: { path: `${out}/task-context.json`, sha256: sha(`${out}/task-context.json`) } };
|
||||
fs.writeFileSync(abs(manifestPath), `${JSON.stringify({ schemaVersion: 1, task, parentTask: selected.parent, operation, status: "done", enablingTask: false, parityStateChange: false, runtime: "SOURCE_BACKED_AUDIO_PARTICLE_IMPLEMENTATION", artifacts, assertions: { capabilityFamily: selected.family, sourceBacked: true, unsupportedFailsClosed: true, verificationDeferred: true, completionOverlayWritten: false, inventoryTotal: 6900, effectiveCompleted: 290, effectivePending: 6609, historicalReproduction: false }, nextTask: selected.next }, null, 2)}\n`);
|
||||
execFileSync(process.execPath, [abs("tools/web/check-task-context.mjs"), "--task", selected.next, "--write"], { cwd: root, stdio: "inherit" });
|
||||
let next = read("nextTask.md");
|
||||
const nextContext = configs[selected.next]?.next ?? "NONE";
|
||||
const tick = String.fromCharCode(96);
|
||||
next = next.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | " + tick + selected.next + tick + " |")
|
||||
.replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | " + tick + "in_progress" + tick + " |")
|
||||
.replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | " + tick + "tests/golden/" + task + "/manifest.json" + tick + " |")
|
||||
.replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | " + tick + "docs/tasks/" + selected.next + ".md" + tick + " |")
|
||||
.replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | " + tick + nextContext + tick + " |")
|
||||
.replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | " + tick + "node tools/web/generate-wbv2-audio-particle-slice.mjs --task " + selected.next + " --write" + tick + " |");
|
||||
fs.writeFileSync(abs("nextTask.md"), next);
|
||||
console.log(`wbv2-audio-particle-slice-written task=${task} family=${selected.family} next=${selected.next} verification=DEFERRED`);
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const ids = ["WBV2-P24-003", "WBV2-P25-000", "WBV2-P25-001", "WBV2-P25-002", "WBV2-P25-003", "WBV2-P25-004", "WBV2-P25-005", "WBV2-P25-006", "WBV2-P25-007", "WBV2-P25-008", "WBV2-P26-000", "WBV2-P26-001", "WBV2-P26-002", "WBV2-P26-003", "WBV2-P26-004", "WBV2-P26-005", "WBV2-P26-006", "WBV2-P27-000", "WBV2-P27-001", "WBV2-P27-002", "WBV2-P28-000", "WBV2-P28-001", "WBV2-P28-002", "WBV2-P28-003", "WBV2-P28-004", "WBV2-P28-005", "WBV2-P29-000", "WBV2-P29-001", "WBV2-P29-002", "WBV2-P29-003", "WBV2-P29-004", "WBV2-P30-000", "WBV2-P30-001", "WBV2-P30-002", "WBV2-P30-003", "WBV2-P30-004", "WBV2-P31-000", "WBV2-P31-001", "WBV2-P31-002", "WBV2-P31-003"];
|
||||
const ids = ["WBV2-P24-003", "WBV2-P25-000", "WBV2-P25-001", "WBV2-P25-002", "WBV2-P25-003", "WBV2-P25-004", "WBV2-P25-005", "WBV2-P25-006", "WBV2-P25-007", "WBV2-P25-008", "WBV2-P26-000", "WBV2-P26-001", "WBV2-P26-002", "WBV2-P26-003", "WBV2-P26-004", "WBV2-P26-005", "WBV2-P26-006", "WBV2-P27-000", "WBV2-P27-001", "WBV2-P27-002", "WBV2-P28-000", "WBV2-P28-001", "WBV2-P28-002", "WBV2-P28-003", "WBV2-P28-004", "WBV2-P28-005", "WBV2-P29-000", "WBV2-P29-001", "WBV2-P29-002", "WBV2-P29-003", "WBV2-P29-004", "WBV2-P30-000", "WBV2-P30-001", "WBV2-P30-002", "WBV2-P30-003", "WBV2-P30-004", "WBV2-P31-000", "WBV2-P31-001", "WBV2-P31-002", "WBV2-P31-003", "WBV2-P32-000", "WBV2-P32-001", "WBV2-P32-002", "WBV2-P32-003", "WBV2-P33-000", "WBV2-P33-001", "WBV2-P33-002", "WBV2-P33-003"];
|
||||
const abs = (file) => path.join(root, file);
|
||||
const sha = (file) => crypto.createHash("sha256").update(fs.readFileSync(abs(file))).digest("hex");
|
||||
for (let pass = 0; pass < ids.length; pass += 1) {
|
||||
|
||||
BIN
web/app/public/vendor/blender/web_engine.wasm
vendored
BIN
web/app/public/vendor/blender/web_engine.wasm
vendored
Binary file not shown.
@@ -703,6 +703,9 @@ function Properties({ snapshot, selectedFaceIndices, selectedVertexIndices, grea
|
||||
const activeCurve = activeNode?.dataId ? snapshot?.nonMeshData?.find((data) => data.id === activeNode.dataId && data.type === "CURVE") : undefined;
|
||||
const activeFont = activeNode?.dataId ? snapshot?.nonMeshData?.find((data) => data.id === activeNode.dataId && data.type === "FONT") : undefined;
|
||||
const activeText = activeNode?.dataId ? snapshot?.texts?.find((data) => data.id === activeNode.dataId) : undefined;
|
||||
const activeSound = activeNode?.dataId ? snapshot?.sounds?.find((data) => data.id === activeNode.dataId) : undefined;
|
||||
const activeSpeaker = activeNode?.dataId ? snapshot?.speakers?.find((data) => data.id === activeNode.dataId) : undefined;
|
||||
const activeParticleSettings = activeNode?.dataId ? snapshot?.particleSettings?.find((data) => data.id === activeNode.dataId) : undefined;
|
||||
const activeVolume = activeNode?.dataId ? snapshot?.nonMeshData?.find((data) => data.id === activeNode.dataId && data.type === "VOLUME") : undefined;
|
||||
const activeMetaball = activeNode?.dataId ? snapshot?.nonMeshData?.find((data) => data.id === activeNode.dataId && data.type === "METABALL") : undefined;
|
||||
const activeGreasePencil = activeNode?.dataId ? snapshot?.greasePencils?.find((data) => data.id === activeNode.dataId) : undefined;
|
||||
@@ -907,6 +910,9 @@ function Properties({ snapshot, selectedFaceIndices, selectedVertexIndices, grea
|
||||
{packedImages.length > 0 ? <div className="property-section" data-testid="resource-workbench"><h3>Resources</h3><output>{packedImages.length} packed image assets</output>{packedImages.map((image) => <button key={image.assetId} type="button" onClick={() => onRequestAsset(image.assetId)}>加载 {image.name}</button>)}</div> : null}
|
||||
{(snapshot?.vfonts?.length ?? 0) > 0 || (snapshot?.sounds?.length ?? 0) > 0 || (snapshot?.speakers?.length ?? 0) > 0 || (snapshot?.texts?.length ?? 0) > 0 || (snapshot?.textures?.length ?? 0) > 0 || (snapshot?.particleSettings?.length ?? 0) > 0 ? <div className="property-section" data-testid="resource-scene-workbench"><h3>Scene Resources</h3><output data-testid="resource-scene-counts">VFonts {snapshot?.vfonts?.length ?? 0} · Sounds {snapshot?.sounds?.length ?? 0} · Speakers {snapshot?.speakers?.length ?? 0} · Texts {snapshot?.texts?.length ?? 0} · Textures {snapshot?.textures?.length ?? 0} · Particles {snapshot?.particleSettings?.length ?? 0}</output>{snapshot?.vfonts?.map((font) => <output key={font.id} data-resource-id={font.id}>VFont: {font.name} {font.packed ? "(packed)" : "(external)"}</output>)}{snapshot?.sounds?.map((sound) => <output key={sound.id} data-resource-id={sound.id}>Sound: {sound.name} · {sound.audioChannels}ch @ {sound.sampleRate}Hz</output>)}{snapshot?.speakers?.map((speaker) => <output key={speaker.id} data-resource-id={speaker.id}>Speaker: {speaker.name} · volume {speaker.volume.toFixed(2)}</output>)}{snapshot?.texts?.map((text) => <output key={text.id} data-resource-id={text.id}>Text: {text.name} · {text.lineCount} lines{ text.internal ? " (internal)" : ""}</output>)}{snapshot?.textures?.map((texture) => <output key={texture.id} data-resource-id={texture.id}>Texture: {texture.name}</output>)}{snapshot?.particleSettings?.map((settings) => <output key={settings.id} data-resource-id={settings.id}>Particles: {settings.name} · {settings.totalParticles} total</output>)}</div> : null}
|
||||
{activeText ? <div className="property-section" data-testid="text-datablock-workbench"><h3>Text Data-Block</h3><output>{activeText.name} · {activeText.lineCount} lines · {activeText.byteLength} bytes</output><textarea aria-label="Text source" value={textSource} maxLength={1_048_576} onChange={(event) => setTextSource(event.target.value)} /><div className="property-actions"><button type="button" disabled={textSource === activeText.source || new TextEncoder().encode(textSource).byteLength > 1_048_576} onClick={() => onCommand({ type: "setTextSource", dataId: activeText.id, source: textSource })}>Apply Text Source</button></div></div> : null}
|
||||
{activeSound ? <div className="property-section" data-testid="audio-workbench"><h3>Sound</h3><output>{activeSound.name} · {activeSound.audioChannels}ch @ {activeSound.sampleRate}Hz</output><output>Volume {activeSound.volume.toFixed(2)} · Pitch {activeSound.pitch.toFixed(2)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(ioMediaCommands.setSoundProperties(activeSound.id, { volume: Math.min(1000000, activeSound.volume + 0.1) }))}>Increase Volume</button><button type="button" onClick={() => onCommand(ioMediaCommands.setSoundProperties(activeSound.id, { pitch: Math.min(1000000, activeSound.pitch + 0.05) }))}>Increase Pitch</button></div></div> : null}
|
||||
{activeSpeaker ? <div className="property-section" data-testid="speaker-workbench"><h3>Speaker</h3><output>{activeSpeaker.name} · {activeSpeaker.soundId ?? "No sound"}</output><output>Volume {activeSpeaker.volume.toFixed(2)} · Pitch {activeSpeaker.pitch.toFixed(2)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(ioMediaCommands.setSpeakerProperties(activeSpeaker.id, { volume: Math.min(1000000, activeSpeaker.volume + 0.1) }))}>Increase Volume</button><button type="button" onClick={() => onCommand(ioMediaCommands.setSpeakerProperties(activeSpeaker.id, { coneVolumeOuter: Math.max(0, Math.min(1, activeSpeaker.coneVolumeOuter - 0.05)) }))}>Reduce Cone</button></div></div> : null}
|
||||
{activeParticleSettings ? <div className="property-section" data-testid="particle-settings-workbench"><h3>Particle Settings</h3><output>{activeParticleSettings.name} · {activeParticleSettings.totalParticles} particles</output><output>Lifetime {activeParticleSettings.lifetime.toFixed(2)} · Size {activeParticleSettings.size.toFixed(3)}</output><div className="property-actions"><button type="button" onClick={() => onCommand(ioMediaCommands.setParticleSettings(activeParticleSettings.id, { totalParticles: Math.min(1000000, activeParticleSettings.totalParticles + 100) }))}>Increase Count</button><button type="button" onClick={() => onCommand(ioMediaCommands.setParticleSettings(activeParticleSettings.id, { size: Math.min(1000000, activeParticleSettings.size + 0.01) }))}>Increase Size</button></div></div> : null}
|
||||
{activeCamera ? <div className="property-section" data-testid="camera-workbench"><h3>Camera</h3><output>{activeCamera.projection} · {activeCamera.lensMm.toFixed(1)}mm</output><button type="button" onClick={() => onCommand(animationRenderCommands.setCameraProperties(activeCamera.id, { projection: activeCamera.projection === "ORTHOGRAPHIC" ? "PERSPECTIVE" : "ORTHOGRAPHIC" }))}>切换投影</button><button type="button" onClick={() => onCommand(animationRenderCommands.setCameraProperties(activeCamera.id, { lensMm: Math.min(10000, activeCamera.lensMm + 5) }))}>增加焦距</button></div> : null}
|
||||
{activeLight ? <div className="property-section" data-testid="light-workbench"><h3>Light</h3><output>{activeLight.energy.toFixed(1)} energy</output><button type="button" onClick={() => onCommand(animationRenderCommands.setLightProperties(activeLight.id, { energy: Math.min(1e9, activeLight.energy + 10) }))}>增加能量</button><button type="button" onClick={() => onCommand(animationRenderCommands.setLightProperties(activeLight.id, { castsShadow: !(activeLight.castsShadow ?? true) }))}>切换阴影</button></div> : null}
|
||||
{activeWorld ? <div className="property-section" data-testid="world-workbench"><h3>World</h3><output>Exposure {activeWorld.exposure.toFixed(2)}</output><button type="button" onClick={() => onCommand(animationRenderCommands.setWorldProperties(activeWorld.id, { exposure: Math.max(-20, Math.min(20, activeWorld.exposure + 0.5)) }))}>增加曝光</button></div> : null}
|
||||
|
||||
BIN
web/app/src/vendor/blender/web_engine.wasm
vendored
BIN
web/app/src/vendor/blender/web_engine.wasm
vendored
Binary file not shown.
@@ -420,6 +420,33 @@ function assertFutureCapability(payload: Extract<WebEngineRequest["command"], {
|
||||
if (typeof payload.source !== "string" || new TextEncoder().encode(payload.source).byteLength > 1_048_576) throw report("NON_MESH_PROPERTY_INVALID", "Text source must be valid UTF-8 within the 1 MiB budget");
|
||||
return;
|
||||
}
|
||||
case "setSoundProperties": {
|
||||
const sound = currentSnapshot?.sounds?.find((candidate) => candidate.id === payload.dataId);
|
||||
if (!sound) throw report("NON_MESH_DATA_UNSUPPORTED", `Sound data block is unavailable: ${payload.dataId}`);
|
||||
if (!validPropertyKeys(payload.properties, ["volume", "attenuation", "pitch", "minGain", "maxGain", "distance", "offsetTime"])) throw report("NON_MESH_PROPERTY_INVALID", "Sound properties are empty or contain unsupported fields");
|
||||
for (const value of Object.values(payload.properties)) if (!boundedNumber(value, 0, 1_000_000)) throw report("NON_MESH_PROPERTY_INVALID", "Sound properties are outside the bounded range");
|
||||
return;
|
||||
}
|
||||
case "setSpeakerProperties": {
|
||||
const speaker = currentSnapshot?.speakers?.find((candidate) => candidate.id === payload.dataId);
|
||||
if (!speaker) throw report("NON_MESH_DATA_UNSUPPORTED", `Speaker data block is unavailable: ${payload.dataId}`);
|
||||
if (!validPropertyKeys(payload.properties, ["volumeMax", "volumeMin", "distanceMax", "distanceReference", "attenuation", "coneAngleOuter", "coneAngleInner", "coneVolumeOuter", "volume", "pitch"])) throw report("NON_MESH_PROPERTY_INVALID", "Speaker properties are empty or contain unsupported fields");
|
||||
for (const [key, value] of Object.entries(payload.properties)) {
|
||||
const maximum = key.startsWith("coneAngle") ? 360 : key === "coneVolumeOuter" ? 1 : 1_000_000;
|
||||
if (!boundedNumber(value, 0, maximum)) throw report("NON_MESH_PROPERTY_INVALID", "Speaker properties are outside the bounded range");
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "setParticleSettings": {
|
||||
const settings = currentSnapshot?.particleSettings?.find((candidate) => candidate.id === payload.dataId);
|
||||
if (!settings) throw report("NON_MESH_DATA_UNSUPPORTED", `ParticleSettings data block is unavailable: ${payload.dataId}`);
|
||||
if (!validPropertyKeys(payload.properties, ["type", "from", "distribution", "physicsType", "totalParticles", "start", "end", "lifetime", "size", "drawSize"])) throw report("NON_MESH_PROPERTY_INVALID", "Particle settings are empty or contain unsupported fields");
|
||||
for (const [key, value] of Object.entries(payload.properties)) {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1_000_000) throw report("NON_MESH_PROPERTY_INVALID", `Particle setting ${key} is outside the bounded range`);
|
||||
if (["type", "from", "distribution", "physicsType", "totalParticles"].includes(key) && !Number.isSafeInteger(value)) throw report("NON_MESH_PROPERTY_INVALID", `Particle setting ${key} must be an integer`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "setVolumeProperties": {
|
||||
const data = currentSnapshot?.nonMeshData?.find((candidate) => candidate.id === payload.dataId);
|
||||
if (!data || data.type !== "VOLUME") throw report("NON_MESH_DATA_UNSUPPORTED", `N-015 Volume data block is unavailable: ${payload.dataId}`);
|
||||
|
||||
@@ -10,4 +10,13 @@ export const ioMediaCommands = Object.freeze({
|
||||
setMaterialImageNode(materialId: string, imageId: string, usage: IOCommand<"setMaterialImageNode">["usage"], uvMap?: string): IOCommand<"setMaterialImageNode"> {
|
||||
return { type: "setMaterialImageNode", materialId, imageId, usage, ...(uvMap ? { uvMap } : {}) };
|
||||
},
|
||||
setSoundProperties(dataId: string, properties: IOCommand<"setSoundProperties">["properties"]): IOCommand<"setSoundProperties"> {
|
||||
return { type: "setSoundProperties", dataId, properties: { ...properties } };
|
||||
},
|
||||
setSpeakerProperties(dataId: string, properties: IOCommand<"setSpeakerProperties">["properties"]): IOCommand<"setSpeakerProperties"> {
|
||||
return { type: "setSpeakerProperties", dataId, properties: { ...properties } };
|
||||
},
|
||||
setParticleSettings(dataId: string, properties: IOCommand<"setParticleSettings">["properties"]): IOCommand<"setParticleSettings"> {
|
||||
return { type: "setParticleSettings", dataId, properties: { ...properties } };
|
||||
},
|
||||
} satisfies Record<string, (...args: never[]) => WebEngineEditCommand>);
|
||||
|
||||
@@ -62,6 +62,9 @@ export const WEB_ENGINE_COMMAND_CAPABILITIES = {
|
||||
importVFont: { family: "FONT", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
setFontLinks: { family: "FONT", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
setTextSource: { family: "IO", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
setSoundProperties: { family: "AUDIO", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
setSpeakerProperties: { family: "AUDIO", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
setParticleSettings: { family: "PARTICLE", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
setVolumeProperties: { family: "VOLUME", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
createGreasePencilLayer: { family: "GREASE_PENCIL", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
removeGreasePencilLayer: { family: "GREASE_PENCIL", route: "MAIN_AUTHORITATIVE", implementation: "SOURCE_BACKED" },
|
||||
|
||||
@@ -126,6 +126,9 @@ export type WebEngineEditCommand =
|
||||
| { type: "importVFont"; schemaVersion: 1; projectId: string; assetId: string; assetPath: string; sourcePath: string; name: string; format: "TTF" | "OTF" | "PFB"; mimeType: string; byteLength: number; sha256: string; base64: string }
|
||||
| { type: "setFontLinks"; dataId: string; links: NonMeshFontLinksIR }
|
||||
| { type: "setTextSource"; dataId: string; source: string }
|
||||
| { type: "setSoundProperties"; dataId: string; properties: { volume?: number; attenuation?: number; pitch?: number; minGain?: number; maxGain?: number; distance?: number; offsetTime?: number } }
|
||||
| { type: "setSpeakerProperties"; dataId: string; properties: { volumeMax?: number; volumeMin?: number; distanceMax?: number; distanceReference?: number; attenuation?: number; coneAngleOuter?: number; coneAngleInner?: number; coneVolumeOuter?: number; volume?: number; pitch?: number } }
|
||||
| { type: "setParticleSettings"; dataId: string; properties: { type?: number; from?: number; distribution?: number; physicsType?: number; totalParticles?: number; start?: number; end?: number; lifetime?: number; size?: number; drawSize?: number } }
|
||||
| { type: "setVolumeProperties"; dataId: string; sourcePath: string; displayDensity: number; interpolation: "NEAREST" | "LINEAR"; stepSize: number; velocityGrid?: string; velocityScale?: number }
|
||||
| { type: "createGreasePencilLayer"; dataId: string; name: string }
|
||||
| { type: "removeGreasePencilLayer"; dataId: string; layerId: string }
|
||||
|
||||
Reference in New Issue
Block a user