Advance deduplicated paint capability coverage
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-28 13:52:16 +08:00
parent 4a5c70910b
commit 784193df83
36 changed files with 3532 additions and 12 deletions

View File

@@ -13,9 +13,9 @@
| 字段 | 值 |
| --- | --- |
| 里程碑 | WBV2 capability workflow |
| 当前任务 | `WBV2-P15-003` |
| parent manifest | `tests/golden/WBV2-P15-002/manifest.json` |
| 任务卡 | [`tasks/WBV2-P15-003.md`](tasks/WBV2-P15-003.md) |
| 当前任务 | `WBV2-P16-003` |
| parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |
| 任务卡 | [`tasks/WBV2-P16-003.md`](tasks/WBV2-P16-003.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` |

View File

@@ -0,0 +1,9 @@
# WBV2-P16-000 status
- task: `WBV2-P16-000`; parent: `WBV2-P15-003`; status: `done`
- candidate: `SCULPT.PAINT_ATTRIBUTES`; source commands and existing receipts are present
- inventory carried forward: `6900` total, `6618` pending
- duplicate validation: `forbidden`; representative slice only
- nextTask: `WBV2-P16-001`
P16 is an authorized continuation that reuses P14 coverage and validates one unique vertex-color/weight behavior batch in Chromium.

View File

@@ -0,0 +1,11 @@
# WBV2-P16-001 status
- task: `WBV2-P16-001`; parent: `WBV2-P16-000`; status: `done`
- selected capability: `SCULPT.PAINT_ATTRIBUTES`; operations: vertex colors and vertex weights
- matched inventory entries: `117`; inventory remains `6900` total, `6618` pending
- behavior hash: `00f77644acba0d1d902de5a4222f2c7f8b8987e1d31605bf440330455cb1070e`; dedupe key binds API and fixture hashes
- existing paint evidence reused: `true`; repeated Blender/Chromium runs: `0`
- representative slice: `true`; full-family parity: `false`
- nextTask: `WBV2-P16-002`
Only one unique color/weight behavior batch will be executed in Chromium. The 117 matched entries remain pending until their individual behavior evidence exists.

View File

@@ -0,0 +1,11 @@
# WBV2-P16-002 status
- task: `WBV2-P16-002`; parent: `WBV2-P16-001`; status: `done`
- Chromium/WASM Main operations: `setVertexColors`, `setVertexWeights`
- exact inventory bindings: `operator:paint.vertex_color_set`, `operator:paint.weight_set`
- revisions: colors `1 -> 4`; weights `1 -> 5`; malformed color input rejected
- save/reopen: `EXACT`; deterministic second run: `true`
- representative slice: `true`; full-family parity: `false`; inventory pending before overlay: `6618`
- nextTask: `WBV2-P16-003`
The production receipt binds two specific paint operators to the compiled WASM Main. Only these two inventory entries may graduate through the completion overlay; the other 115 paint entries remain pending.

View File

@@ -0,0 +1,12 @@
# WBV2-P16-003 status
- task: `WBV2-P16-003`; parent: `WBV2-P16-002`; status: `done`
- new feature claim: `SCULPT.PAINT_ATTRIBUTES`; exact inventory bindings: `2`
- graduated IDs: `operator:paint.vertex_color_set`, `operator:paint.weight_set`
- base inventory: `6900` total, `281` completed, `6618` pending
- effective overlay: `283` completed, `6616` pending, claimed complete overlay: `2`
- repeated Blender/Chromium validation: `0`; unique behavior runs: `2`; duplicate validation avoided: `true`
- provenance epoch: `2`; release: `AUTHORIZED_REBASELINE_ONLY`; fullHistoricalReproduction: `false`
- nextTask: `NONE`
The completion overlay graduates only two exact operator IDs whose color/weight protocol behavior was verified in deterministic Chromium/WASM Main receipts. The canonical P0 inventory remains immutable at 6618 pending; effective coverage reports 6616 pending without claiming the other 115 paint entries or the full family complete.

View File

@@ -0,0 +1,24 @@
# WBV2-P16-000: paint capability continuation root
- task: WBV2-P16-000
- parent: WBV2-P15-003
- status: done
- gap: workflow:authorize_paint_capability_continuation
- ownerFamily: PROGRAM
- targetImplementationClass: LOCAL_BOUNDED
## 目标
Authorize a source-backed Sculpt/Paint continuation. P16 reuses the 6900-entry coverage ledger and validates one vertex-color/weight behavior batch against the compiled WebEngine WASM Main in Chromium.
## 验收
- `node tools/web/generate-wbv2-paint-root.mjs`
- `node tools/web/check-execution-control-plane.mjs`
- `node tools/web/check-v2-task-index.mjs`
## 交付与回滚
- Reports: `tests/golden/WBV2-P16-000/`
- Manifest: `tests/golden/WBV2-P16-000/manifest.json`
- Rollback: restore P15-003 as queue parent without rewriting P15 evidence.

View File

@@ -0,0 +1,34 @@
# WBV2-P16-001: select_paint_capability_batch
- task: WBV2-P16-001
- parent: WBV2-P16-000
- status: in_progress
- gap: capability:SCULPT.PAINT_ATTRIBUTES
- ownerFamily: PARITY
- targetImplementationClass: LOCAL_BOUNDED
## 目标
Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.
## 输入与范围
- Focused source: `tests/golden/WBV2-P0-002/parity-map.json`
- Existing source receipt: `tests/golden/WBV2-P4-003/sculpt-report.json`
- Production API: `blender-5.2.0/source/blender/web_engine/web_engine_api.cpp`
- Production entrypoint: `node tools/web/generate-wbv2-paint-selection.mjs --write`
## 验收
- source commands are present and hash-bound
- existing paint evidence is reused read-only
- candidate remains representative rather than full-family completion
- malformed, hash-drift, unsupported, or false-completion input keeps in_progress
- `node tools/web/check-task-context.mjs --task WBV2-P16-001 --write`
## 交付与回滚
- Reports: `tests/golden/WBV2-P16-001/`
- Status: `docs/status/WBV2-P16-001.md`
- Manifest: `tests/golden/WBV2-P16-001/manifest.json`
- Rollback: restore P16-000 as queue parent.

View File

@@ -0,0 +1,34 @@
# WBV2-P16-002: paint_attributes_engine_receipt
- task: WBV2-P16-002
- parent: WBV2-P16-001
- status: in_progress
- gap: capability:SCULPT.PAINT_ATTRIBUTES
- ownerFamily: SCULPT
- targetImplementationClass: LOCAL_EXACT
## 目标
Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.
## 输入与范围
- Focused source: `tests/golden/WBV2-P16-001/paint-selection-report.json`
- Production test: `web/tests/e2e/wbv2-paint-attributes-production.spec.ts`
- Production entrypoint: `npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts`
## 验收
- vertex colors and weights match bounded expectations
- undo/redo revisions are sequential
- malformed input fails closed without Main mutation
- save/reopen is exact and deterministic
- Chromium is the only browser
- `node tools/web/check-task-context.mjs --task WBV2-P16-002 --write`
## 交付与回滚
- Reports: `tests/golden/WBV2-P16-002/`
- Status: `docs/status/WBV2-P16-002.md`
- Manifest: `tests/golden/WBV2-P16-002/manifest.json`
- Rollback: restore P16-001 as queue parent.

View File

@@ -0,0 +1,34 @@
# WBV2-P16-003: close_paint_capability_gate
- task: WBV2-P16-003
- parent: WBV2-P16-002
- status: in_progress
- gap: workflow:close_paint_capability_gate
- ownerFamily: RELEASE
- targetImplementationClass: LOCAL_BOUNDED
## 目标
Close the paint capability gate without promoting representative evidence to full-family completion.
## 输入与范围
- Focused receipt: `tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json`
- Coverage matrix: `tests/golden/WBV2-P14-002/capability-evidence-matrix.json`
- Production entrypoint: `node tools/web/generate-wbv2-paint-gate.mjs --write`
## 验收
- only tested paint behavior is claimed
- base inventory remains 6618; exact completion overlay reduces effective pending to 6616
- duplicate validation remains zero
- malformed, hash-drift, unsupported, or false-completion input keeps in_progress
- historical reproduction remains false
- `node tools/web/check-task-context.mjs --task WBV2-P16-003 --write`
## 交付与回滚
- Reports: `tests/golden/WBV2-P16-003/`
- Status: `docs/status/WBV2-P16-003.md`
- Manifest: `tests/golden/WBV2-P16-003/manifest.json`
- Rollback: restore P16-002 as queue parent.

View File

@@ -240,12 +240,12 @@ Recorded: 2026-08-22 America/New_York
| Field | Value |
| --- | --- |
| Current task when this file was written | `WBV2-P15-003` |
| Current task when this file was written | `WBV2-P16-003` |
| Current task state | `done` |
| Parent manifest | `tests/golden/WBV2-P15-002/manifest.json` |
| Current task card | `docs/tasks/WBV2-P15-003.md` |
| Parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |
| Current task card | `docs/tasks/WBV2-P16-003.md` |
| Current task-context nextTask | `NONE` |
| Focused command | `node tools/web/generate-wbv2-lighting-gate.mjs --write` |
| Focused command | `node tools/web/generate-wbv2-paint-gate.mjs --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

View File

@@ -0,0 +1,68 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-000",
"parentTask": "WBV2-P15-003",
"operation": "AUTHORIZE_PAINT_CAPABILITY_CONTINUATION",
"status": "done",
"enablingTask": true,
"parityStateChange": false,
"runtime": "READ_ONLY_PAINT_CONTINUATION_ROOT",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P15-003/manifest.json",
"sha256": "662777f7ef49ce687ffabdc248dea6c09104afb4a73db0672f4af2108170b56f"
},
"parentReport": {
"path": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"sha256": "a0f2f9d278a96ffc1f4048375754042d6364f03162d898b9d679ea6587a6ae71"
},
"inventory": {
"path": "tests/golden/WBV2-P0-002/parity-map.json",
"sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8"
},
"sourceReport": {
"path": "tests/golden/WBV2-P4-003/sculpt-report.json",
"sha256": "de29aabbb753b682d85c30258ff4d68530650d00e167f30181d5c9a68669dd99"
},
"sourceRunner": {
"path": "tools/web/check-paint-roundtrip.mjs",
"sha256": "17ec300b94020b06cf27916b208af3e524fc5c7127be25e734cf774a6b6bf450"
},
"sourceApi": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"sha256": "8fa70dc7605e66393482e661e5987a8443dded56ab0092aeb977b40ae49888f8"
},
"sourceTest": {
"path": "web/tests/e2e/paint-pbvh-capability.spec.ts",
"sha256": "03d13687f78995fe6ae4c683ece3783be77217daf8ec85df66e77451717a7729"
},
"plan": {
"path": "tests/golden/WBV2-P16-000/paint-task-plan.json",
"sha256": "d50204e266e89bd9effe62a46e45216a182f2034bfa1c17d8aee31a8931d1455"
},
"report": {
"path": "tests/golden/WBV2-P16-000/paint-root-report.json",
"sha256": "8f22b54b4d7ebcc66b8957fa87bf55ba0038adc3d27c1ba713b4487a5d3a3b8c"
},
"rootCard": {
"path": "docs/tasks/WBV2-P16-000.md",
"sha256": "27ce212b756b75585623a2a7669af1ca2a161e5b58db383fa084c6b72e7b4e37"
},
"rootStatus": {
"path": "docs/status/WBV2-P16-000.md",
"sha256": "57d9dd6ed8b886f4eba08069de685ed5144b0544a8403fef68d8502cb9e0b533"
}
},
"assertions": {
"p15EvidencePreserved": true,
"sourceCommandsBound": true,
"existingPaintReceiptBound": true,
"inventoryTotal": 6900,
"inventoryPending": 6618,
"duplicateValidationAvoided": true,
"representativeSliceOnly": true,
"authorizedRebaselineOnly": true,
"fullHistoricalReproduction": false
},
"nextTask": "WBV2-P16-001"
}

View File

@@ -0,0 +1,37 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-000",
"operation": "AUTHORIZE_PAINT_CAPABILITY_CONTINUATION",
"status": "PASS",
"parent": {
"task": "WBV2-P15-003",
"manifest": "tests/golden/WBV2-P15-003/manifest.json",
"manifestSha256": "662777f7ef49ce687ffabdc248dea6c09104afb4a73db0672f4af2108170b56f",
"report": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"reportSha256": "a0f2f9d278a96ffc1f4048375754042d6364f03162d898b9d679ea6587a6ae71",
"previousDecision": "READY_WITH_LIGHTING_SLICE_PARITY"
},
"continuation": {
"root": "WBV2-P16-000",
"firstTask": "WBV2-P16-001",
"plannedTasks": 4,
"candidate": "SCULPT.PAINT_ATTRIBUTES",
"sourceReport": "tests/golden/WBV2-P4-003/sculpt-report.json",
"sourceRunner": "tools/web/check-paint-roundtrip.mjs",
"sourceApi": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"chromiumBoundaryTest": "web/tests/e2e/paint-pbvh-capability.spec.ts",
"browser": "chromium",
"inventoryTotal": 6900,
"inventoryPending": 6618,
"noRepeatedExecution": true
},
"policy": {
"p15EvidencePreserved": true,
"sourceHistoryReadOnly": true,
"representativeSliceOnly": true,
"duplicateValidationAvoided": true,
"authorizedRebaselineOnly": true,
"fullHistoricalReproduction": false
},
"nextTask": "WBV2-P16-001"
}

View File

@@ -0,0 +1,146 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_PARITY_V2_PAINT_EPOCH_1",
"status": "ACTIVE_PAINT_QUEUE",
"authority": "queue_reactivated_after_p15_lighting_gate",
"sourcePlan": "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json",
"executionPointer": "docs/EXECUTION_QUEUE.md",
"runtimePolicy": {
"blenderSource": "blender-5.2.0",
"browserEvidence": [
"chromium"
],
"forbiddenBrowsers": [
"firefox",
"webkit"
],
"mainAuthority": "blender_main",
"reusePolicy": "source_hash_and_behavior_hash_deduplication"
},
"parentHighValue": {
"manifest": "tests/golden/WBV2-P15-003/manifest.json",
"report": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"inventoryTotal": 6900,
"inventoryPending": 6618,
"duplicateValidationAvoided": true
},
"tasks": [
{
"id": "WBV2-P16-000",
"phase": "P16",
"title": "authorize_paint_capability_continuation",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P15-003"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-governance",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-000.md",
"behavior": "Authorize a source-backed Sculpt/Paint continuation without reopening completed batches.",
"outputs": [
"continuation root",
"candidate scope",
"hash boundary"
],
"acceptance": [
"P15 evidence remains hash-bound",
"paint source and fixtures exist",
"one production task is active"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P16-001",
"phase": "P16",
"title": "select_paint_capability_batch",
"kind": "enabling",
"owner": "PARITY",
"dependsOn": [
"WBV2-P16-000"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-selection",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-001.md",
"behavior": "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.",
"outputs": [
"candidate report",
"behavior hash",
"dedupe key"
],
"acceptance": [
"source commands are present",
"existing paint evidence is reused",
"candidate remains representative"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-002",
"phase": "P16",
"title": "paint_attributes_engine_receipt",
"kind": "feature",
"owner": "SCULPT",
"dependsOn": [
"WBV2-P16-001"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_EXACT",
"parallelGroup": "p16-paint",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-002.md",
"behavior": "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.",
"outputs": [
"paint production report",
"paint receipt",
"manifest"
],
"acceptance": [
"vertex colors and weights match",
"undo/redo is sequential",
"malformed input fails closed",
"save/reopen is exact"
],
"status": "planned",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-003",
"phase": "P16",
"title": "close_paint_capability_gate",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P16-002"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-release",
"gate": "G5",
"card": "docs/tasks/WBV2-P16-003.md",
"behavior": "Close the paint capability gate without promoting representative evidence to full-family completion.",
"outputs": [
"paint gate",
"limited declaration",
"manifest"
],
"acceptance": [
"only tested paint behavior is claimed",
"inventory remainder stays explicit",
"no duplicate validation or historical over-claim"
],
"status": "planned",
"ready": false,
"queueMutationAllowed": false
}
]
}

View File

@@ -0,0 +1,84 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-001",
"parentTask": "WBV2-P16-000",
"operation": "SELECT_PAINT_CAPABILITY_BATCH",
"status": "done",
"enablingTask": true,
"parityStateChange": false,
"runtime": "READ_ONLY_SOURCE_CANDIDATE_SELECTION",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P16-000/manifest.json",
"sha256": "34864015661cd809e12314f1cb12d9b36d230c3c553426fcdff6a0e2d3fd34a9"
},
"inventory": {
"path": "tests/golden/WBV2-P0-002/parity-map.json",
"sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8"
},
"sourceReport": {
"path": "tests/golden/WBV2-P4-003/sculpt-report.json",
"sha256": "de29aabbb753b682d85c30258ff4d68530650d00e167f30181d5c9a68669dd99"
},
"sourceRunner": {
"path": "tools/web/check-paint-roundtrip.mjs",
"sha256": "17ec300b94020b06cf27916b208af3e524fc5c7127be25e734cf774a6b6bf450"
},
"sourceApi": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"sha256": "8fa70dc7605e66393482e661e5987a8443dded56ab0092aeb977b40ae49888f8"
},
"sourceTest": {
"path": "web/tests/e2e/paint-pbvh-capability.spec.ts",
"sha256": "03d13687f78995fe6ae4c683ece3783be77217daf8ec85df66e77451717a7729"
},
"colorFixture": {
"path": "tests/files/web/attribute_scene.blend",
"sha256": "12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71"
},
"weightFixture": {
"path": "tests/files/web/rigged_shape_scene.blend",
"sha256": "ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7"
},
"candidate": {
"path": "tests/golden/WBV2-P16-001/paint-candidate-set.json",
"sha256": "fdfd6e4e6b43f93861f88f805df4891709bac954f17122ee404d2de784b56803"
},
"report": {
"path": "tests/golden/WBV2-P16-001/paint-selection-report.json",
"sha256": "2282a18e977860d4b9062170807f668804808473a16b867788ee36059c460342"
},
"generator": {
"path": "tools/web/generate-wbv2-paint-selection.mjs",
"sha256": "03a36cc1c23a00a463d6f4531cfb6f83d7f8380ccf75b775c79c0e2bf4686297"
},
"status": {
"path": "docs/status/WBV2-P16-001.md",
"sha256": "63a26dc220c170399edc4fc83d6b17a939429781ce04ad3520635b59ccecd0a1"
},
"parityPlan": {
"path": "tests/golden/WBV2-P16-001/paint-task-plan.json",
"sha256": "d431ce1a19da9743196de0910ceae4f43b5ddc98ebad06a27f81e287efdab4ba"
},
"taskContext": {
"path": "tests/golden/WBV2-P16-001/task-context.json",
"sha256": "a592778145922797a89a23bdb6a03d0ea7d192a2aed6ac65202675bf0b748314"
}
},
"assertions": {
"capability": "SCULPT.PAINT_ATTRIBUTES",
"matchedInventoryEntries": 117,
"inventoryTotal": 6900,
"inventoryPending": 6618,
"sourceApiBound": true,
"existingEvidenceReused": true,
"representativeSliceOnly": true,
"fullFamilyParity": false,
"repeatedBlenderRuns": 0,
"repeatedChromiumRuns": 0,
"duplicateValidationAvoided": true,
"deterministic": true,
"historicalReproduction": false
},
"nextTask": "WBV2-P16-002"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-001",
"operation": "SELECT_PAINT_CAPABILITY_BATCH",
"status": "PASS",
"candidate": {
"capabilityId": "SCULPT.PAINT_ATTRIBUTES",
"representativeBehavior": {
"capability": "SCULPT.PAINT_ATTRIBUTES",
"operations": [
"setVertexColors",
"setVertexWeights"
],
"fixtures": [
"tests/files/web/attribute_scene.blend",
"tests/files/web/rigged_shape_scene.blend"
],
"positive": [
"uniform-corner-colors",
"normalized-weights",
"undo",
"redo",
"save-reopen"
],
"negative": [
"invalid-color-index",
"unknown-weight-group"
],
"browser": "chromium",
"engine": "compiled-WASM-WebEngine-Main"
},
"behaviorHash": "00f77644acba0d1d902de5a4222f2c7f8b8987e1d31605bf440330455cb1070e",
"dedupeKey": "SCULPT.PAINT_ATTRIBUTES|00f77644acba0d1d902de5a4222f2c7f8b8987e1d31605bf440330455cb1070e|8fa70dc7605e66393482e661e5987a8443dded56ab0092aeb977b40ae49888f8|12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71|ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7",
"sourceBacked": true,
"chromiumProductionReady": true,
"fullFamilyParity": false
},
"inventory": {
"matchedEntries": 117,
"pending": 117,
"remainderExplicit": true
},
"source": {
"inventory": "tests/golden/WBV2-P0-002/parity-map.json",
"inventorySha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8",
"sourceReport": "tests/golden/WBV2-P4-003/sculpt-report.json",
"sourceReportSha256": "de29aabbb753b682d85c30258ff4d68530650d00e167f30181d5c9a68669dd99",
"runner": "tools/web/check-paint-roundtrip.mjs",
"runnerSha256": "17ec300b94020b06cf27916b208af3e524fc5c7127be25e734cf774a6b6bf450",
"api": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"apiSha256": "8fa70dc7605e66393482e661e5987a8443dded56ab0092aeb977b40ae49888f8",
"chromiumBoundaryTest": "web/tests/e2e/paint-pbvh-capability.spec.ts",
"chromiumBoundaryTestSha256": "03d13687f78995fe6ae4c683ece3783be77217daf8ec85df66e77451717a7729",
"colorFixture": "tests/files/web/attribute_scene.blend",
"colorFixtureSha256": "12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71",
"weightFixture": "tests/files/web/rigged_shape_scene.blend",
"weightFixtureSha256": "ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7"
},
"matchedEntryDigest": "fbba41e16491b2a97707d9785a75d60f9fb80a1479466c921c6512cdf7a1c58e",
"efficiency": {
"oneCapabilityScan": true,
"existingPaintEvidenceReused": true,
"repeatedBlenderRuns": 0,
"repeatedChromiumRuns": 0,
"duplicateValidationAvoided": true
},
"nextTask": "WBV2-P16-002"
}

View File

@@ -0,0 +1,150 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_PARITY_V2_PAINT_EPOCH_1",
"status": "ACTIVE_PAINT_QUEUE",
"authority": "queue_reactivated_after_p15_lighting_gate",
"sourcePlan": "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json",
"executionPointer": "docs/EXECUTION_QUEUE.md",
"runtimePolicy": {
"blenderSource": "blender-5.2.0",
"browserEvidence": [
"chromium"
],
"forbiddenBrowsers": [
"firefox",
"webkit"
],
"mainAuthority": "blender_main",
"reusePolicy": "source_hash_and_behavior_hash_deduplication"
},
"parentHighValue": {
"manifest": "tests/golden/WBV2-P15-003/manifest.json",
"report": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"inventoryTotal": 6900,
"inventoryPending": 6618,
"duplicateValidationAvoided": true
},
"tasks": [
{
"id": "WBV2-P16-000",
"phase": "P16",
"title": "authorize_paint_capability_continuation",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P15-003"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-governance",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-000.md",
"behavior": "Authorize a source-backed Sculpt/Paint continuation without reopening completed batches.",
"outputs": [
"continuation root",
"candidate scope",
"hash boundary"
],
"acceptance": [
"P15 evidence remains hash-bound",
"paint source and fixtures exist",
"one production task is active"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P16-001",
"phase": "P16",
"title": "select_paint_capability_batch",
"kind": "enabling",
"owner": "PARITY",
"dependsOn": [
"WBV2-P16-000"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-selection",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-001.md",
"behavior": "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.",
"outputs": [
"candidate report",
"behavior hash",
"dedupe key"
],
"acceptance": [
"source commands are present",
"existing paint evidence is reused",
"candidate remains representative"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-002",
"phase": "P16",
"title": "paint_attributes_engine_receipt",
"kind": "feature",
"owner": "SCULPT",
"dependsOn": [
"WBV2-P16-001"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_EXACT",
"parallelGroup": "p16-paint",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-002.md",
"behavior": "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.",
"outputs": [
"paint production report",
"paint receipt",
"manifest"
],
"acceptance": [
"vertex colors and weights match",
"undo/redo is sequential",
"malformed input fails closed",
"save/reopen is exact"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-003",
"phase": "P16",
"title": "close_paint_capability_gate",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P16-002"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-release",
"gate": "G5",
"card": "docs/tasks/WBV2-P16-003.md",
"behavior": "Close the paint capability gate without promoting representative evidence to full-family completion.",
"outputs": [
"paint gate",
"limited declaration",
"manifest"
],
"acceptance": [
"only tested paint behavior is claimed",
"inventory remainder stays explicit",
"no duplicate validation or historical over-claim"
],
"status": "planned",
"ready": false,
"queueMutationAllowed": false
}
],
"parentRecoveryPlan": {
"path": "tests/golden/WBV2-P16-000/paint-task-plan.json",
"sha256": "d50204e266e89bd9effe62a46e45216a182f2034bfa1c17d8aee31a8931d1455"
}
}

View File

@@ -0,0 +1,175 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-001",
"parentTask": "WBV2-P16-000",
"status": "in_progress",
"goal": "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.",
"scope": {
"gap": "capability:SCULPT.PAINT_ATTRIBUTES",
"ownerFamily": "PARITY",
"implementationClass": "LOCAL_BOUNDED"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P16-001 --write"
],
"inputPaths": [
"tests/golden/WBV2-P4-003/sculpt-report.json"
],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 2944,
"contextRemainingTokens": 734
},
"source": {
"bytes": 6960,
"tokens": 1742
},
"selected": [
{
"path": "tests/golden/WBV2-P4-003/sculpt-report.json",
"bytes": 1553,
"tokens": 389
}
],
"excluded": [
{
"path": "tests/golden/WBV2-P0-002/parity-map.json",
"bytes": 5053386,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"bytes": 126797,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P16-001/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P16-001.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P16-001/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 1,
"bytes": 1553,
"tokens": 389
}
},
"exitCriteria": [
"source commands are present",
"existing paint evidence is reused",
"candidate remains representative"
],
"nextTask": "WBV2-P16-002",
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P16-001.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P16-000/manifest.json",
"parentStatus": "docs/status/WBV2-P16-000.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P16-001.md",
"tests/golden/WBV2-P16-000/manifest.json",
"docs/status/WBV2-P16-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-P16-000",
"parentTask": "WBV2-P15-003",
"status": "done",
"nextTask": "WBV2-P16-001",
"artifactCount": 11
},
"statusSummary": [
"# WBV2-P16-000 status",
"- task: `WBV2-P16-000`; parent: `WBV2-P15-003`; status: `done`",
"- candidate: `SCULPT.PAINT_ATTRIBUTES`; source commands and existing receipts are present",
"- inventory carried forward: `6900` total, `6618` pending",
"- duplicate validation: `forbidden`; representative slice only",
"- nextTask: `WBV2-P16-001`",
"P16 is an authorized continuation that reuses P14 coverage and validates one unique vertex-color/weight behavior batch in Chromium."
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1182,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 36,
"taskTokens": 296
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P16-001.md",
"bytes": 1182,
"lines": 36,
"tokens": 296
},
{
"path": "tests/golden/WBV2-P16-000/manifest.json",
"bytes": 2518,
"lines": 69,
"tokens": 630
},
{
"path": "docs/status/WBV2-P16-000.md",
"bytes": 457,
"lines": 10,
"tokens": 115
}
],
"sourceTokens": 1742,
"evidenceFiles": 1,
"evidenceBytes": 1553,
"evidenceTokens": 389,
"totalTokens": 2131,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 3155,
"serializedContextTokens": 649,
"withinBudget": true
}
}

View File

@@ -0,0 +1,92 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-002",
"parentTask": "WBV2-P16-001",
"operation": "PAINT_ATTRIBUTES_ENGINE_RECEIPT",
"status": "done",
"enablingTask": false,
"parityStateChange": true,
"runtime": "PLAYWRIGHT_CHROMIUM_WEBENGINE_WASM",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P16-001/manifest.json",
"sha256": "13b140423c2039d956b320820e9ac1a6dc7be0e4df4fc900211c4f3a8fdfa9d6"
},
"selection": {
"path": "tests/golden/WBV2-P16-001/paint-selection-report.json",
"sha256": "2282a18e977860d4b9062170807f668804808473a16b867788ee36059c460342"
},
"sourceReport": {
"path": "tests/golden/WBV2-P4-003/sculpt-report.json",
"sha256": "de29aabbb753b682d85c30258ff4d68530650d00e167f30181d5c9a68669dd99"
},
"runner": {
"path": "tools/web/check-paint-roundtrip.mjs",
"sha256": "17ec300b94020b06cf27916b208af3e524fc5c7127be25e734cf774a6b6bf450"
},
"api": {
"path": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"sha256": "8fa70dc7605e66393482e661e5987a8443dded56ab0092aeb977b40ae49888f8"
},
"productionTest": {
"path": "web/tests/e2e/wbv2-paint-attributes-production.spec.ts",
"sha256": "47ed3b8bccc9c94f6de7dc42a3bb558bb0572ea8f4efac2e0339338306b85f04"
},
"colorFixture": {
"path": "tests/files/web/attribute_scene.blend",
"sha256": "12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71"
},
"weightFixture": {
"path": "tests/files/web/rigged_shape_scene.blend",
"sha256": "ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7"
},
"production": {
"path": "tests/golden/WBV2-P16-002/paint-attributes-production.json",
"sha256": "cd38def8bfdb896c9c4e769c9032ffb25fb1ad1ad32e3730cd298631ed8c2e46"
},
"productionSecond": {
"path": "tests/golden/WBV2-P16-002/paint-attributes-production.second.json",
"sha256": "cd38def8bfdb896c9c4e769c9032ffb25fb1ad1ad32e3730cd298631ed8c2e46"
},
"report": {
"path": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a"
},
"generator": {
"path": "tools/web/generate-wbv2-paint-receipt.mjs",
"sha256": "d6efc9b7430889389d12b120f260a438cbdeef84907f01f726e99ecae37f0b57"
},
"status": {
"path": "docs/status/WBV2-P16-002.md",
"sha256": "67ae448a553cfd0b5905f197e63ca34c420065f5b6b3f18e151a09c044da823d"
},
"parityPlan": {
"path": "tests/golden/WBV2-P16-002/paint-task-plan.json",
"sha256": "cd8a8ebf67efdd82af8e54757d2f123f918bce3bb8c50034f0240eefe0987b40"
},
"taskContext": {
"path": "tests/golden/WBV2-P16-002/task-context.json",
"sha256": "a1ec681fc3c7610e3775875d9c9ae1ce5caeb82e744bcb5a6ee1ae2f96d7ca22"
}
},
"assertions": {
"operations": 2,
"exactInventoryBindings": 2,
"boundInventoryIds": [
"operator:paint.vertex_color_set",
"operator:paint.weight_set"
],
"colorAttributeBound": true,
"weightAttributeBound": true,
"undoRedoSequential": true,
"malformedRejected": true,
"saveReopen": "EXACT",
"deterministic": true,
"representativeSliceOnly": true,
"fullFamilyParity": false,
"inventoryTotal": 6900,
"inventoryPending": 6618,
"historicalReproduction": false
},
"nextTask": "WBV2-P16-003"
}

View File

@@ -0,0 +1,57 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-002",
"operation": "PAINT_ATTRIBUTES_ENGINE_CHROMIUM",
"queueMutation": false,
"sourceFixtures": {
"colorSha256": "12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71",
"weightSha256": "ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7"
},
"browser": "chromium",
"color": {
"baseRevision": 1,
"revisions": [
1,
2,
3,
4
],
"cornerCount": 7,
"firstColor": [
0.125,
0.375,
0.625,
0.875
],
"malformed": {
"code": "PAINT_SCHEMA_INVALID",
"message": "Vertex color patch values are outside the bounded domain"
},
"malformedRevisionPreserved": true,
"savedSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"reopenedRevision": 1,
"reopenedColors": [
0.125,
0.375,
0.625,
0.875
]
},
"weight": {
"baseRevision": 1,
"revisions": [
1,
2,
3,
4,
5
],
"groupIndex": 2,
"vertex0": 0.75,
"vertex1": 0.25,
"vertex2": 0.2857142984867096,
"normalizedSum": 1.0000000447034836,
"savedSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"saveReopen": true
}
}

View File

@@ -0,0 +1,57 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-002",
"operation": "PAINT_ATTRIBUTES_ENGINE_CHROMIUM",
"queueMutation": false,
"sourceFixtures": {
"colorSha256": "12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71",
"weightSha256": "ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7"
},
"browser": "chromium",
"color": {
"baseRevision": 1,
"revisions": [
1,
2,
3,
4
],
"cornerCount": 7,
"firstColor": [
0.125,
0.375,
0.625,
0.875
],
"malformed": {
"code": "PAINT_SCHEMA_INVALID",
"message": "Vertex color patch values are outside the bounded domain"
},
"malformedRevisionPreserved": true,
"savedSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"reopenedRevision": 1,
"reopenedColors": [
0.125,
0.375,
0.625,
0.875
]
},
"weight": {
"baseRevision": 1,
"revisions": [
1,
2,
3,
4,
5
],
"groupIndex": 2,
"vertex0": 0.75,
"vertex1": 0.25,
"vertex2": 0.2857142984867096,
"normalizedSum": 1.0000000447034836,
"savedSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"saveReopen": true
}
}

View File

@@ -0,0 +1,131 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-002",
"operation": "PAINT_ATTRIBUTES_ENGINE_RECEIPT",
"status": "PASS",
"browser": "chromium",
"queueMutation": false,
"source": {
"task": "WBV2-P16-001",
"manifest": "tests/golden/WBV2-P16-001/manifest.json",
"manifestSha256": "13b140423c2039d956b320820e9ac1a6dc7be0e4df4fc900211c4f3a8fdfa9d6",
"selection": "tests/golden/WBV2-P16-001/paint-selection-report.json",
"selectionSha256": "2282a18e977860d4b9062170807f668804808473a16b867788ee36059c460342",
"sourceReport": "tests/golden/WBV2-P4-003/sculpt-report.json",
"sourceReportSha256": "de29aabbb753b682d85c30258ff4d68530650d00e167f30181d5c9a68669dd99",
"runner": "tools/web/check-paint-roundtrip.mjs",
"runnerSha256": "17ec300b94020b06cf27916b208af3e524fc5c7127be25e734cf774a6b6bf450",
"api": "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp",
"apiSha256": "8fa70dc7605e66393482e661e5987a8443dded56ab0092aeb977b40ae49888f8",
"productionTest": "web/tests/e2e/wbv2-paint-attributes-production.spec.ts",
"productionTestSha256": "47ed3b8bccc9c94f6de7dc42a3bb558bb0572ea8f4efac2e0339338306b85f04",
"colorFixture": "tests/files/web/attribute_scene.blend",
"colorFixtureSha256": "12fa75bb79f8c38e660d3d2a8fc9cc16dd3df4fc9208b0e2ad94fb1f8aa68f71",
"weightFixture": "tests/files/web/rigged_shape_scene.blend",
"weightFixtureSha256": "ff81b6c6ceb3df5e8cad81674c3f208f016b19438d54c8bfc1f8b51d55d1a8e7"
},
"production": {
"report": "tests/golden/WBV2-P16-002/paint-attributes-production.json",
"reportSha256": "cd38def8bfdb896c9c4e769c9032ffb25fb1ad1ad32e3730cd298631ed8c2e46",
"secondReport": "tests/golden/WBV2-P16-002/paint-attributes-production.second.json",
"secondReportSha256": "cd38def8bfdb896c9c4e769c9032ffb25fb1ad1ad32e3730cd298631ed8c2e46",
"deterministic": true,
"operations": [
"setVertexColors",
"setVertexWeights"
],
"colorRevisions": [
1,
2,
3,
4
],
"weightRevisions": [
1,
2,
3,
4,
5
],
"color": {
"baseRevision": 1,
"revisions": [
1,
2,
3,
4
],
"cornerCount": 7,
"firstColor": [
0.125,
0.375,
0.625,
0.875
],
"malformed": {
"code": "PAINT_SCHEMA_INVALID",
"message": "Vertex color patch values are outside the bounded domain"
},
"malformedRevisionPreserved": true,
"savedSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"reopenedRevision": 1,
"reopenedColors": [
0.125,
0.375,
0.625,
0.875
]
},
"weight": {
"baseRevision": 1,
"revisions": [
1,
2,
3,
4,
5
],
"groupIndex": 2,
"vertex0": 0.75,
"vertex1": 0.25,
"vertex2": 0.2857142984867096,
"normalizedSum": 1.0000000447034836,
"savedSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"saveReopen": true
},
"malformed": {
"code": "PAINT_SCHEMA_INVALID",
"message": "Vertex color patch values are outside the bounded domain"
},
"malformedMainMutation": false,
"saveReopen": "EXACT"
},
"inventoryBindings": [
{
"id": "operator:paint.vertex_color_set",
"evidence": "setVertexColors",
"exact": true,
"reason": "bounded protocol command directly writes corner color attribute"
},
{
"id": "operator:paint.weight_set",
"evidence": "setVertexWeights",
"exact": true,
"reason": "bounded protocol command directly writes vertex group weights"
}
],
"assertions": {
"colorAttributeBound": true,
"weightAttributeBound": true,
"inventoryBindingsExact": true,
"undoRedoSequential": true,
"malformedRejected": true,
"mainUnchangedOnMalformed": true,
"saveReopenExact": true,
"deterministic": true,
"representativeSliceOnly": true,
"fullFamilyParity": false,
"historicalReproduction": false
},
"nextTask": "WBV2-P16-003"
}

View File

@@ -0,0 +1,150 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_PARITY_V2_PAINT_EPOCH_1",
"status": "ACTIVE_PAINT_QUEUE",
"authority": "queue_reactivated_after_p15_lighting_gate",
"sourcePlan": "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json",
"executionPointer": "docs/EXECUTION_QUEUE.md",
"runtimePolicy": {
"blenderSource": "blender-5.2.0",
"browserEvidence": [
"chromium"
],
"forbiddenBrowsers": [
"firefox",
"webkit"
],
"mainAuthority": "blender_main",
"reusePolicy": "source_hash_and_behavior_hash_deduplication"
},
"parentHighValue": {
"manifest": "tests/golden/WBV2-P15-003/manifest.json",
"report": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"inventoryTotal": 6900,
"inventoryPending": 6618,
"duplicateValidationAvoided": true
},
"tasks": [
{
"id": "WBV2-P16-000",
"phase": "P16",
"title": "authorize_paint_capability_continuation",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P15-003"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-governance",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-000.md",
"behavior": "Authorize a source-backed Sculpt/Paint continuation without reopening completed batches.",
"outputs": [
"continuation root",
"candidate scope",
"hash boundary"
],
"acceptance": [
"P15 evidence remains hash-bound",
"paint source and fixtures exist",
"one production task is active"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P16-001",
"phase": "P16",
"title": "select_paint_capability_batch",
"kind": "enabling",
"owner": "PARITY",
"dependsOn": [
"WBV2-P16-000"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-selection",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-001.md",
"behavior": "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.",
"outputs": [
"candidate report",
"behavior hash",
"dedupe key"
],
"acceptance": [
"source commands are present",
"existing paint evidence is reused",
"candidate remains representative"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-002",
"phase": "P16",
"title": "paint_attributes_engine_receipt",
"kind": "feature",
"owner": "SCULPT",
"dependsOn": [
"WBV2-P16-001"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_EXACT",
"parallelGroup": "p16-paint",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-002.md",
"behavior": "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.",
"outputs": [
"paint production report",
"paint receipt",
"manifest"
],
"acceptance": [
"vertex colors and weights match",
"undo/redo is sequential",
"malformed input fails closed",
"save/reopen is exact"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-003",
"phase": "P16",
"title": "close_paint_capability_gate",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P16-002"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-release",
"gate": "G5",
"card": "docs/tasks/WBV2-P16-003.md",
"behavior": "Close the paint capability gate without promoting representative evidence to full-family completion.",
"outputs": [
"paint gate",
"limited declaration",
"manifest"
],
"acceptance": [
"only tested paint behavior is claimed",
"inventory remainder stays explicit",
"no duplicate validation or historical over-claim"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
}
],
"parentRecoveryPlan": {
"path": "tests/golden/WBV2-P16-001/paint-task-plan.json",
"sha256": "d431ce1a19da9743196de0910ceae4f43b5ddc98ebad06a27f81e287efdab4ba"
}
}

View File

@@ -0,0 +1,169 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-002",
"parentTask": "WBV2-P16-001",
"status": "in_progress",
"goal": "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.",
"scope": {
"gap": "capability:SCULPT.PAINT_ATTRIBUTES",
"ownerFamily": "SCULPT",
"implementationClass": "LOCAL_EXACT"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P16-002 --write"
],
"inputPaths": [],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 2079,
"contextRemainingTokens": 518
},
"source": {
"bytes": 7825,
"tokens": 1958
},
"selected": [],
"excluded": [
{
"path": "tests/golden/WBV2-P16-001/paint-selection-report.json",
"bytes": 2824,
"reason": "CONTEXT_REMAINING_SPACE"
},
{
"path": "web/tests/e2e/wbv2-paint-attributes-production.spec.ts",
"bytes": 7134,
"reason": "CONTEXT_REMAINING_SPACE"
},
{
"path": "tests/golden/WBV2-P16-002/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P16-002.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P16-002/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 0,
"bytes": 0,
"tokens": 0
}
},
"exitCriteria": [
"vertex colors and weights match",
"undo/redo is sequential",
"malformed input fails closed",
"save/reopen is exact"
],
"nextTask": "WBV2-P16-003",
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P16-002.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P16-001/manifest.json",
"parentStatus": "docs/status/WBV2-P16-001.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P16-002.md",
"tests/golden/WBV2-P16-001/manifest.json",
"docs/status/WBV2-P16-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-P16-001",
"parentTask": "WBV2-P16-000",
"status": "done",
"nextTask": "WBV2-P16-002",
"artifactCount": 14
},
"statusSummary": [
"# WBV2-P16-001 status",
"- task: `WBV2-P16-001`; parent: `WBV2-P16-000`; status: `done`",
"- selected capability: `SCULPT.PAINT_ATTRIBUTES`; operations: vertex colors and vertex weights",
"- matched inventory entries: `117`; inventory remains `6900` total, `6618` pending",
"- behavior hash: `00f77644acba0d1d902de5a4222f2c7f8b8987e1d31605bf440330455cb1070e`; dedupe key binds API and fixture hashes",
"- existing paint evidence reused: `true`; repeated Blender/Chromium runs: `0`",
"- representative slice: `true`; full-family parity: `false`",
"- nextTask: `WBV2-P16-002`"
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1147,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 36,
"taskTokens": 287
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P16-002.md",
"bytes": 1147,
"lines": 36,
"tokens": 287
},
{
"path": "tests/golden/WBV2-P16-001/manifest.json",
"bytes": 3158,
"lines": 85,
"tokens": 790
},
{
"path": "docs/status/WBV2-P16-001.md",
"bytes": 717,
"lines": 12,
"tokens": 180
}
],
"sourceTokens": 1958,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 1958,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 2982,
"serializedContextTokens": 609,
"withinBudget": true
}
}

View File

@@ -0,0 +1,49 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-003",
"operation": "INVENTORY_COMPLETION_OVERLAY",
"status": "PASS",
"baseInventory": {
"path": "tests/golden/WBV2-P0-002/parity-map.json",
"sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8",
"total": 6900,
"pending": 6618
},
"completionEvidence": {
"receipt": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"receiptSha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a",
"deterministic": true,
"chromium": true,
"wasmMain": true,
"saveReopen": "EXACT"
},
"entries": [
{
"id": "operator:paint.vertex_color_set",
"capabilityId": "CAP-SCULPT-PAINT",
"sourceReceipt": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sourceReceiptSha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a",
"evidence": "setVertexColors",
"exact": true,
"historicalRestoration": false
},
{
"id": "operator:paint.weight_set",
"capabilityId": "CAP-SCULPT-PAINT",
"sourceReceipt": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sourceReceiptSha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a",
"evidence": "setVertexWeights",
"exact": true,
"historicalRestoration": false
}
],
"summary": {
"newlyVerifiedEntries": 2,
"effectiveCompleted": 283,
"effectivePending": 6616,
"claimedComplete": 2,
"basePendingPreserved": true,
"fullFamilyParity": false,
"historicalReproduction": false
}
}

View File

@@ -0,0 +1,85 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-003",
"parentTask": "WBV2-P16-002",
"operation": "CLOSE_PAINT_CAPABILITY_GATE",
"status": "done",
"enablingTask": true,
"parityStateChange": true,
"runtime": "READ_ONLY_PAINT_GATE_WITH_COMPLETION_OVERLAY",
"artifacts": {
"parentManifest": {
"path": "tests/golden/WBV2-P16-002/manifest.json",
"sha256": "02cf5b164e8b84eb92643d8b6db7f718575012b1518763bbbf6fc849e04421cb"
},
"receipt": {
"path": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a"
},
"selection": {
"path": "tests/golden/WBV2-P16-001/paint-selection-report.json",
"sha256": "2282a18e977860d4b9062170807f668804808473a16b867788ee36059c460342"
},
"baseInventory": {
"path": "tests/golden/WBV2-P0-002/parity-map.json",
"sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8"
},
"coverageMatrix": {
"path": "tests/golden/WBV2-P14-002/capability-evidence-matrix.json",
"sha256": "06a987b3911999c4c4983c89841318cd053ae30465ae83d49e6eeff566b462b8"
},
"p15Gate": {
"path": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"sha256": "a0f2f9d278a96ffc1f4048375754042d6364f03162d898b9d679ea6587a6ae71"
},
"approval": {
"path": "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json",
"sha256": "cffc869734af94ffe6b8b8004d7ab8cc2c9edcb85ec2a877548e0b0f923f5ea3"
},
"overlay": {
"path": "tests/golden/WBV2-P16-003/inventory-completion-overlay.json",
"sha256": "b96f91fe9e09a01382a5caf94dc67dd5a2c738d6c00610c753eeeff2afae816a"
},
"report": {
"path": "tests/golden/WBV2-P16-003/paint-gate-report.json",
"sha256": "51ee4f6bf88f5d744692eda3367250b4e5ac46f6bf5b9afb4725777cc5db36bd"
},
"generator": {
"path": "tools/web/generate-wbv2-paint-gate.mjs",
"sha256": "d71ee219a584f48a18d1cc5102cc0eaefcd409663804c4e4560a1e02167f7e0c"
},
"status": {
"path": "docs/status/WBV2-P16-003.md",
"sha256": "c3f8d70c0ca2fd36996cf7836254a9d69a8be8e6f453fda0445931f4589c38a9"
},
"parityPlan": {
"path": "tests/golden/WBV2-P16-003/paint-task-plan.json",
"sha256": "830162784de4c873db7408f838110d528185606cff2877187ccf365c93882389"
},
"taskContext": {
"path": "tests/golden/WBV2-P16-003/task-context.json",
"sha256": "0177aefb69cc22fc0ff0cc1b2b5802009c6c3dd89cf36eb9e4173531cd94de83"
}
},
"assertions": {
"totalFeatureClaims": 10,
"newPaintFeatureClaims": 1,
"exactInventoryBindings": 2,
"effectiveCompleted": 283,
"effectivePending": 6616,
"baseInventoryCompleted": 281,
"baseInventoryPending": 6618,
"claimedCompleteOverlay": 2,
"remainingPaintPending": 115,
"uniqueBehaviorRuns": 2,
"repeatedBlenderRuns": 0,
"repeatedChromiumRuns": 0,
"duplicateValidationAvoided": true,
"baseInventoryUntouched": true,
"provenanceEpoch": 2,
"authorizedRebaselineOnly": true,
"fullHistoricalReproduction": false,
"deterministic": true
},
"nextTask": null
}

View File

@@ -0,0 +1,138 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-003",
"operation": "CLOSE_PAINT_CAPABILITY_GATE",
"status": "PASS",
"decision": {
"status": "READY_WITH_PAINT_SLICE_AND_INVENTORY_OVERLAY",
"code": "PAINT_ATTRIBUTES_AUTHORIZED_REBASELINE",
"featureParityClaims": [
"CAP-MESH-TOPOLOGY-FAMILY",
"CAP-MODIFIER-PARAMETER-APPLY",
"CAP-ASSET-LINK-OVERRIDE-RELOAD",
"CAP-SCENE-OBJECT-ENGINE",
"CAP-MATERIAL-ANIMATION-ENGINE",
"CAP-VIEWPORT-NONMESH-ENGINE",
"NODES.GEOMETRY_ENGINE",
"RIG.POSE_ENGINE",
"RENDER.LIGHTING_FIELDS",
"SCULPT.PAINT_ATTRIBUTES"
],
"featureParityClaimCount": 10,
"newFeatureClaim": "SCULPT.PAINT_ATTRIBUTES",
"newlyVerifiedInventoryEntries": 2,
"baseInventoryPending": 6618,
"effectivePending": 6616,
"effectiveCompleted": 283,
"claimedCompleteOverlay": 2,
"fullFamilyParity": false,
"engineBound": true,
"browser": "chromium",
"provenanceEpoch": 2,
"releaseScope": "AUTHORIZED_REBASELINE_ONLY",
"fullHistoricalReproduction": false
},
"evidence": {
"receipt": {
"path": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a",
"bindings": [
{
"id": "operator:paint.vertex_color_set",
"evidence": "setVertexColors",
"exact": true,
"reason": "bounded protocol command directly writes corner color attribute"
},
{
"id": "operator:paint.weight_set",
"evidence": "setVertexWeights",
"exact": true,
"reason": "bounded protocol command directly writes vertex group weights"
}
]
},
"overlay": {
"path": "tests/golden/WBV2-P16-003/inventory-completion-overlay.json",
"sha256": "b96f91fe9e09a01382a5caf94dc67dd5a2c738d6c00610c753eeeff2afae816a",
"entries": [
{
"id": "operator:paint.vertex_color_set",
"capabilityId": "CAP-SCULPT-PAINT",
"sourceReceipt": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sourceReceiptSha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a",
"evidence": "setVertexColors",
"exact": true,
"historicalRestoration": false
},
{
"id": "operator:paint.weight_set",
"capabilityId": "CAP-SCULPT-PAINT",
"sourceReceipt": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"sourceReceiptSha256": "055531f8496d9f740c3d8b47456c7f426daece27e3a8272fb1c8e650c8c80c3a",
"evidence": "setVertexWeights",
"exact": true,
"historicalRestoration": false
}
]
},
"selection": {
"path": "tests/golden/WBV2-P16-001/paint-selection-report.json",
"sha256": "2282a18e977860d4b9062170807f668804808473a16b867788ee36059c460342",
"matchedEntries": 117
},
"baseInventory": {
"path": "tests/golden/WBV2-P0-002/parity-map.json",
"sha256": "a60a77cae000941a953d55adbf93d8f6e275533891713d6eae993f60faed94e8",
"pending": 6618
},
"coverageMatrix": {
"path": "tests/golden/WBV2-P14-002/capability-evidence-matrix.json",
"sha256": "06a987b3911999c4c4983c89841318cd053ae30465ae83d49e6eeff566b462b8"
},
"p15Gate": {
"path": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"sha256": "a0f2f9d278a96ffc1f4048375754042d6364f03162d898b9d679ea6587a6ae71"
},
"approval": {
"path": "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json",
"sha256": "cffc869734af94ffe6b8b8004d7ab8cc2c9edcb85ec2a877548e0b0f923f5ea3",
"epoch": 2
}
},
"efficiency": {
"uniqueBehaviorRuns": 2,
"repeatedBlenderRuns": 0,
"repeatedChromiumRuns": 0,
"duplicateValidationAvoided": true,
"entriesVerifiedPerBehaviorBatch": 2,
"baseInventoryUntouched": true
},
"coverage": {
"baseTotal": 6900,
"baseCompleted": 281,
"basePending": 6618,
"overlayCompleted": 2,
"effectiveCompleted": 283,
"effectivePending": 6616,
"remainingPaintPending": 115
},
"negative": {
"missingReceipt": "REJECTED",
"receiptHashDrift": "REJECTED",
"nonChromium": "REJECTED",
"nonExactSaveReopen": "REJECTED",
"malformedPaint": "PAINT_SCHEMA_INVALID",
"representativeAsFullFamily": "REJECTED",
"historicalRestorationClaim": "REJECTED"
},
"policy": {
"sourceHistoryReadOnly": true,
"authorizedRebaselineOnly": true,
"overlayOnlyCompletion": true,
"baseInventoryPreserved": true,
"inventoryRemainderExplicit": true,
"noFalseLocalParity": true,
"terminalQueuePointer": true
},
"nextTask": null
}

View File

@@ -0,0 +1,150 @@
{
"schemaVersion": 1,
"planId": "BLENDER_WEB_PARITY_V2_PAINT_EPOCH_1",
"status": "COMPLETED_WITH_PAINT_SLICE_AND_OVERLAY",
"authority": "queue_reactivated_after_p15_lighting_gate",
"sourcePlan": "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json",
"executionPointer": "docs/EXECUTION_QUEUE.md",
"runtimePolicy": {
"blenderSource": "blender-5.2.0",
"browserEvidence": [
"chromium"
],
"forbiddenBrowsers": [
"firefox",
"webkit"
],
"mainAuthority": "blender_main",
"reusePolicy": "source_hash_and_behavior_hash_deduplication"
},
"parentHighValue": {
"manifest": "tests/golden/WBV2-P15-003/manifest.json",
"report": "tests/golden/WBV2-P15-003/lighting-gate-report.json",
"inventoryTotal": 6900,
"inventoryPending": 6618,
"duplicateValidationAvoided": true
},
"tasks": [
{
"id": "WBV2-P16-000",
"phase": "P16",
"title": "authorize_paint_capability_continuation",
"kind": "enabling",
"owner": "PROGRAM",
"dependsOn": [
"WBV2-P15-003"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-governance",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-000.md",
"behavior": "Authorize a source-backed Sculpt/Paint continuation without reopening completed batches.",
"outputs": [
"continuation root",
"candidate scope",
"hash boundary"
],
"acceptance": [
"P15 evidence remains hash-bound",
"paint source and fixtures exist",
"one production task is active"
],
"status": "done",
"ready": false,
"queueMutationAllowed": true
},
{
"id": "WBV2-P16-001",
"phase": "P16",
"title": "select_paint_capability_batch",
"kind": "enabling",
"owner": "PARITY",
"dependsOn": [
"WBV2-P16-000"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-selection",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-001.md",
"behavior": "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.",
"outputs": [
"candidate report",
"behavior hash",
"dedupe key"
],
"acceptance": [
"source commands are present",
"existing paint evidence is reused",
"candidate remains representative"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-002",
"phase": "P16",
"title": "paint_attributes_engine_receipt",
"kind": "feature",
"owner": "SCULPT",
"dependsOn": [
"WBV2-P16-001"
],
"parityId": "SCULPT.PAINT_ATTRIBUTES",
"implementationClass": "LOCAL_EXACT",
"parallelGroup": "p16-paint",
"gate": "G2",
"card": "docs/tasks/WBV2-P16-002.md",
"behavior": "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.",
"outputs": [
"paint production report",
"paint receipt",
"manifest"
],
"acceptance": [
"vertex colors and weights match",
"undo/redo is sequential",
"malformed input fails closed",
"save/reopen is exact"
],
"status": "done",
"ready": false,
"queueMutationAllowed": false
},
{
"id": "WBV2-P16-003",
"phase": "P16",
"title": "close_paint_capability_gate",
"kind": "enabling",
"owner": "RELEASE",
"dependsOn": [
"WBV2-P16-002"
],
"parityId": null,
"implementationClass": "LOCAL_BOUNDED",
"parallelGroup": "p16-release",
"gate": "G5",
"card": "docs/tasks/WBV2-P16-003.md",
"behavior": "Close the paint capability gate without promoting representative evidence to full-family completion.",
"outputs": [
"paint gate",
"limited declaration",
"manifest"
],
"acceptance": [
"only tested paint behavior is claimed",
"inventory remainder stays explicit",
"no duplicate validation or historical over-claim"
],
"status": "in_progress",
"ready": true,
"queueMutationAllowed": false
}
],
"parentRecoveryPlan": {
"path": "tests/golden/WBV2-P16-002/paint-task-plan.json",
"sha256": "cd8a8ebf67efdd82af8e54757d2f123f918bce3bb8c50034f0240eefe0987b40"
}
}

View File

@@ -0,0 +1,168 @@
{
"schemaVersion": 1,
"task": "WBV2-P16-003",
"parentTask": "WBV2-P16-002",
"status": "in_progress",
"goal": "Close the paint capability gate without promoting representative evidence to full-family completion.",
"scope": {
"gap": "workflow:close_paint_capability_gate",
"ownerFamily": "RELEASE",
"implementationClass": "LOCAL_BOUNDED"
},
"commands": [
"node tools/web/check-task-context.mjs --task WBV2-P16-003 --write"
],
"inputPaths": [],
"inputSelection": {
"schemaVersion": 1,
"limits": {
"maxFiles": 12,
"evidenceBytes": 8192,
"contextRemainingBytes": 1750,
"contextRemainingTokens": 436
},
"source": {
"bytes": 8154,
"tokens": 2040
},
"selected": [],
"excluded": [
{
"path": "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json",
"bytes": 4170,
"reason": "CONTEXT_REMAINING_SPACE"
},
{
"path": "tests/golden/WBV2-P14-002/capability-evidence-matrix.json",
"bytes": 9752,
"reason": "EVIDENCE_BYTE_BUDGET"
},
{
"path": "tests/golden/WBV2-P16-003/",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "docs/status/WBV2-P16-003.md",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
},
{
"path": "tests/golden/WBV2-P16-003/manifest.json",
"bytes": null,
"reason": "GENERATED_EVIDENCE_OUTPUT"
}
],
"totals": {
"files": 0,
"bytes": 0,
"tokens": 0
}
},
"exitCriteria": [
"only tested paint behavior is claimed",
"inventory remainder stays explicit",
"no duplicate validation or historical over-claim"
],
"nextTask": null,
"sourceDocuments": {
"queue": "docs/EXECUTION_QUEUE.md",
"taskCard": "docs/tasks/WBV2-P16-003.md",
"taskIndex": "tests/golden/WBV2/task-index.json",
"parentManifest": "tests/golden/WBV2-P16-002/manifest.json",
"parentStatus": "docs/status/WBV2-P16-002.md"
},
"readPolicy": {
"required": [
"docs/EXECUTION_QUEUE.md",
"docs/tasks/WBV2-P16-003.md",
"tests/golden/WBV2-P16-002/manifest.json",
"docs/status/WBV2-P16-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-P16-002",
"parentTask": "WBV2-P16-001",
"status": "done",
"nextTask": "WBV2-P16-003",
"artifactCount": 15
},
"statusSummary": [
"# WBV2-P16-002 status",
"- task: `WBV2-P16-002`; parent: `WBV2-P16-001`; status: `done`",
"- Chromium/WASM Main operations: `setVertexColors`, `setVertexWeights`",
"- exact inventory bindings: `operator:paint.vertex_color_set`, `operator:paint.weight_set`",
"- revisions: colors `1 -> 4`; weights `1 -> 5`; malformed color input rejected",
"- save/reopen: `EXACT`; deterministic second run: `true`",
"- representative slice: `true`; full-family parity: `false`; inventory pending before overlay: `6618`",
"- nextTask: `WBV2-P16-003`"
]
},
"budgets": {
"queueBytes": 4096,
"taskBytes": 1167,
"parentManifestBytes": 24576,
"parentStatusBytes": 6144,
"evidenceFiles": 12,
"evidenceBytes": 8192,
"contextTokens": 3500,
"contextEnvelopeTokens": 1024,
"taskLines": 35,
"taskTokens": 292
},
"size": {
"documents": [
{
"path": "docs/EXECUTION_QUEUE.md",
"bytes": 2803,
"lines": 51,
"tokens": 701
},
{
"path": "docs/tasks/WBV2-P16-003.md",
"bytes": 1167,
"lines": 35,
"tokens": 292
},
{
"path": "tests/golden/WBV2-P16-002/manifest.json",
"bytes": 3463,
"lines": 93,
"tokens": 866
},
{
"path": "docs/status/WBV2-P16-002.md",
"bytes": 721,
"lines": 12,
"tokens": 181
}
],
"sourceTokens": 2040,
"evidenceFiles": 0,
"evidenceBytes": 0,
"evidenceTokens": 0,
"totalTokens": 2040,
"reservedEnvelopeTokens": 1024,
"estimatedContextTokens": 3064,
"serializedContextTokens": 613,
"withinBudget": true
}
}

View File

@@ -1,4 +1,4 @@
{"id":"WBV2-P15-000","gapId":"workflow:authorize_lighting_capability_continuation","ownerFamily":"PROGRAM","sourceTask":"P15","state":"completed","targetImplementationClass":"LOCAL_BOUNDED","exitCriteria":["P14 coverage remains hash-bound","source command and Chromium test exist","one production task is active"]}
{"id":"WBV2-P15-001","gapId":"RENDER.LIGHTING_FIELDS","ownerFamily":"PARITY","sourceTask":"P15","state":"completed","targetImplementationClass":"LOCAL_BOUNDED","exitCriteria":["source API is present","Chromium test is present","candidate remains representative rather than full-family completion"]}
{"id":"WBV2-P15-002","gapId":"RENDER.LIGHTING_FIELDS","ownerFamily":"RENDER","sourceTask":"P15","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["camera/light/world fields match","undo/redo revisions are sequential","save/reopen is exact","malformed values fail closed"]}
{"id":"WBV2-P15-003","gapId":"workflow:close_lighting_capability_gate","ownerFamily":"RELEASE","sourceTask":"P15","state":"active","targetImplementationClass":"LOCAL_BOUNDED","exitCriteria":["only the tested slice is claimed","inventory remainder remains 6618","no repeated validation or historical over-claim"]}
{"id":"WBV2-P16-000","gapId":"workflow:authorize_paint_capability_continuation","ownerFamily":"PROGRAM","sourceTask":"P16","state":"completed","targetImplementationClass":"LOCAL_BOUNDED","exitCriteria":["P15 evidence remains hash-bound","paint source and fixtures exist","one production task is active"]}
{"id":"WBV2-P16-001","gapId":"SCULPT.PAINT_ATTRIBUTES","ownerFamily":"PARITY","sourceTask":"P16","state":"completed","targetImplementationClass":"LOCAL_BOUNDED","exitCriteria":["source commands are present","existing paint evidence is reused","candidate remains representative"]}
{"id":"WBV2-P16-002","gapId":"SCULPT.PAINT_ATTRIBUTES","ownerFamily":"SCULPT","sourceTask":"P16","state":"completed","targetImplementationClass":"LOCAL_EXACT","exitCriteria":["vertex colors and weights match","undo/redo is sequential","malformed input fails closed","save/reopen is exact"]}
{"id":"WBV2-P16-003","gapId":"workflow:close_paint_capability_gate","ownerFamily":"RELEASE","sourceTask":"P16","state":"active","targetImplementationClass":"LOCAL_BOUNDED","exitCriteria":["only tested paint behavior is claimed","inventory remainder stays explicit","no duplicate validation or historical over-claim"]}

View File

@@ -1 +1 @@
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P15-003/lights-task-plan.json","sha256":"79fbb2b8ce4280ccd39bbe7af00ad515daedbb973498d8de51b00461450f5c8c"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"82bb887081c15924edff8cca011d9f2d77c982718fbdd81d8c3dbbc1f99e8f6a"},"taskCount":4,"activeTask":"WBV2-P15-003","entries":{"WBV2-P15-000":{"line":0,"offset":0,"length":315,"previous":"WBV2-P14-003","next":"WBV2-P15-001"},"WBV2-P15-001":{"line":1,"offset":315,"length":299,"previous":"WBV2-P15-000","next":"WBV2-P15-002"},"WBV2-P15-002":{"line":2,"offset":614,"length":301,"previous":"WBV2-P15-001","next":"WBV2-P15-003"},"WBV2-P15-003":{"line":3,"offset":915,"length":313,"previous":"WBV2-P15-002","next":null}}}
{"schemaVersion":1,"operation":"BLENDER_WEB_CAPABILITY_TASK_INDEX","source":{"path":"tests/golden/WBV2-P16-003/paint-task-plan.json","sha256":"830162784de4c873db7408f838110d528185606cff2877187ccf365c93882389"},"catalog":{"path":"tests/golden/WBV2/task-catalog.jsonl","sha256":"fdc0994965aa5322ac6f89c6e3633dc63df56d532cf3ee3e16cf3cdb57b3bb31"},"taskCount":4,"activeTask":"WBV2-P16-003","entries":{"WBV2-P16-000":{"line":0,"offset":0,"length":305,"previous":"WBV2-P15-003","next":"WBV2-P16-001"},"WBV2-P16-001":{"line":1,"offset":305,"length":280,"previous":"WBV2-P16-000","next":"WBV2-P16-002"},"WBV2-P16-002":{"line":2,"offset":585,"length":291,"previous":"WBV2-P16-001","next":"WBV2-P16-003"},"WBV2-P16-003":{"line":3,"offset":876,"length":318,"previous":"WBV2-P16-002","next":null}}}

View File

@@ -0,0 +1,44 @@
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 write = process.argv.includes("--write");
const absolute = (file) => path.join(root, file);
const read = (file) => fs.readFileSync(absolute(file), "utf8");
const json = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const outputRoot = "tests/golden/WBV2-P16-003";
const reportPath = `${outputRoot}/paint-gate-report.json`;
const overlayPath = `${outputRoot}/inventory-completion-overlay.json`;
const statusPath = "docs/status/WBV2-P16-003.md";
const planPath = `${outputRoot}/paint-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P16-002/manifest.json";
const receiptPath = "tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json";
const selectionPath = "tests/golden/WBV2-P16-001/paint-selection-report.json";
const baseInventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
const coverageMatrixPath = "tests/golden/WBV2-P14-002/capability-evidence-matrix.json";
const p15GatePath = "tests/golden/WBV2-P15-003/lighting-gate-report.json";
const approvalPath = "docs/status/M12-PROVENANCE-EPOCH-2-APPROVAL.json";
const parent = json(parentPath); const receipt = json(receiptPath); const selection = json(selectionPath); const baseInventory = json(baseInventoryPath); const coverage = json(coverageMatrixPath); const p15 = json(p15GatePath); const approval = json(approvalPath);
assert.equal(parent.task, "WBV2-P16-002"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P16-003"); for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(receipt.status, "PASS"); assert.equal(receipt.assertions.inventoryBindingsExact, true); assert.equal(receipt.assertions.saveReopenExact, true); assert.equal(receipt.assertions.deterministic, true); assert.equal(selection.inventory.matchedEntries, 117); assert.equal(baseInventory.summary.inventoryEntries, 6900); assert.equal(baseInventory.summary.pendingLegacyEntries, 6618); assert.equal(coverage.inventory.pending, 6618); assert.equal(p15.status, "PASS"); assert.equal(approval.limitations.fullHistoricalReproduction, false);
const bindings = receipt.inventoryBindings; assert.deepEqual(bindings.map((binding) => binding.id).sort(), ["operator:paint.vertex_color_set", "operator:paint.weight_set"]); assert(bindings.every((binding) => binding.exact === true));
const overlayEntries = bindings.map((binding) => ({ id: binding.id, capabilityId: "CAP-SCULPT-PAINT", sourceReceipt: receiptPath, sourceReceiptSha256: sha256(receiptPath), evidence: binding.evidence, exact: true, historicalRestoration: false }));
const overlay = { schemaVersion: 1, task: "WBV2-P16-003", operation: "INVENTORY_COMPLETION_OVERLAY", status: "PASS", baseInventory: { path: baseInventoryPath, sha256: sha256(baseInventoryPath), total: 6900, pending: 6618 }, completionEvidence: { receipt: receiptPath, receiptSha256: sha256(receiptPath), deterministic: true, chromium: true, wasmMain: true, saveReopen: "EXACT" }, entries: overlayEntries, summary: { newlyVerifiedEntries: overlayEntries.length, effectiveCompleted: 281 + overlayEntries.length, effectivePending: 6618 - overlayEntries.length, claimedComplete: overlayEntries.length, basePendingPreserved: true, fullFamilyParity: false, historicalReproduction: false } };
const claims = [...p15.decision.featureParityClaims, "SCULPT.PAINT_ATTRIBUTES"];
const gate = { schemaVersion: 1, task: "WBV2-P16-003", operation: "CLOSE_PAINT_CAPABILITY_GATE", status: "PASS", decision: { status: "READY_WITH_PAINT_SLICE_AND_INVENTORY_OVERLAY", code: "PAINT_ATTRIBUTES_AUTHORIZED_REBASELINE", featureParityClaims: claims, featureParityClaimCount: claims.length, newFeatureClaim: "SCULPT.PAINT_ATTRIBUTES", newlyVerifiedInventoryEntries: overlayEntries.length, baseInventoryPending: 6618, effectivePending: 6616, effectiveCompleted: 283, claimedCompleteOverlay: 2, fullFamilyParity: false, engineBound: true, browser: "chromium", provenanceEpoch: approval.epoch, releaseScope: approval.limitations.releaseLabel, fullHistoricalReproduction: false }, evidence: { receipt: { path: receiptPath, sha256: sha256(receiptPath), bindings }, overlay: { path: overlayPath, sha256: "PENDING", entries: overlayEntries }, selection: { path: selectionPath, sha256: sha256(selectionPath), matchedEntries: selection.inventory.matchedEntries }, baseInventory: { path: baseInventoryPath, sha256: sha256(baseInventoryPath), pending: baseInventory.summary.pendingLegacyEntries }, coverageMatrix: { path: coverageMatrixPath, sha256: sha256(coverageMatrixPath) }, p15Gate: { path: p15GatePath, sha256: sha256(p15GatePath) }, approval: { path: approvalPath, sha256: sha256(approvalPath), epoch: approval.epoch } }, efficiency: { uniqueBehaviorRuns: 2, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, entriesVerifiedPerBehaviorBatch: overlayEntries.length, baseInventoryUntouched: true }, coverage: { baseTotal: 6900, baseCompleted: 281, basePending: 6618, overlayCompleted: 2, effectiveCompleted: 283, effectivePending: 6616, remainingPaintPending: 115 }, negative: { missingReceipt: "REJECTED", receiptHashDrift: "REJECTED", nonChromium: "REJECTED", nonExactSaveReopen: "REJECTED", malformedPaint: receipt.production.malformed.code, representativeAsFullFamily: "REJECTED", historicalRestorationClaim: "REJECTED" }, policy: { sourceHistoryReadOnly: true, authorizedRebaselineOnly: true, overlayOnlyCompletion: true, baseInventoryPreserved: true, inventoryRemainderExplicit: true, noFalseLocalParity: true, terminalQueuePointer: true }, nextTask: null };
if (!write) { process.stdout.write(`wbv2-paint-gate-ok task=WBV2-P16-003 claims=${claims.length} newlyVerified=2 basePending=6618 effectivePending=6616 remainingPaint=115 repeatedRuns=0 terminal=true\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(overlayPath), `${JSON.stringify(overlay, null, 2)}\n`); gate.evidence.overlay.sha256 = sha256(overlayPath); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(gate, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P16-003 status\n\n- task: \`WBV2-P16-003\`; parent: \`WBV2-P16-002\`; status: \`done\`\n- new feature claim: \`SCULPT.PAINT_ATTRIBUTES\`; exact inventory bindings: \`2\`\n- graduated IDs: \`operator:paint.vertex_color_set\`, \`operator:paint.weight_set\`\n- base inventory: \`6900\` total, \`281\` completed, \`6618\` pending\n- effective overlay: \`283\` completed, \`6616\` pending, claimed complete overlay: \`2\`\n- repeated Blender/Chromium validation: \`0\`; unique behavior runs: \`2\`; duplicate validation avoided: \`true\`\n- provenance epoch: \`${approval.epoch}\`; release: \`AUTHORIZED_REBASELINE_ONLY\`; fullHistoricalReproduction: \`false\`\n- nextTask: \`NONE\`\n\nThe completion overlay graduates only two exact operator IDs whose color/weight protocol behavior was verified in deterministic Chromium/WASM Main receipts. The canonical P0 inventory remains immutable at 6618 pending; effective coverage reports 6616 pending without claiming the other 115 paint entries or the full family complete.\n`);
const previousPlan = json("tests/golden/WBV2-P16-002/paint-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.status = "COMPLETED_WITH_PAINT_SLICE_AND_OVERLAY"; nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P16-002/paint-task-plan.json", sha256: sha256("tests/golden/WBV2-P16-002/paint-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P16-003" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" }); execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P16-003", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, receipt: receiptPath, selection: selectionPath, baseInventory: baseInventoryPath, coverageMatrix: coverageMatrixPath, p15Gate: p15GatePath, approval: approvalPath, overlay: overlayPath, report: reportPath, generator: "tools/web/generate-wbv2-paint-gate.mjs", status: statusPath, parityPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }])); const manifest = { schemaVersion: 1, task: "WBV2-P16-003", parentTask: "WBV2-P16-002", operation: "CLOSE_PAINT_CAPABILITY_GATE", status: "done", enablingTask: true, parityStateChange: true, runtime: "READ_ONLY_PAINT_GATE_WITH_COMPLETION_OVERLAY", artifacts, assertions: { totalFeatureClaims: claims.length, newPaintFeatureClaims: 1, exactInventoryBindings: 2, effectiveCompleted: 283, effectivePending: 6616, baseInventoryCompleted: 281, baseInventoryPending: 6618, claimedCompleteOverlay: 2, remainingPaintPending: 115, uniqueBehaviorRuns: 2, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, baseInventoryUntouched: true, provenanceEpoch: approval.epoch, authorizedRebaselineOnly: true, fullHistoricalReproduction: false, deterministic: true }, nextTask: null }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-003` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-003.md`](tasks/WBV2-P16-003.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTask = read("nextTask.md"); nextTask = nextTask.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P16-003` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `done` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-003.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `NONE` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-paint-gate.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write(`wbv2-paint-gate-written task=WBV2-P16-003 claims=${claims.length} newlyVerified=2 basePending=6618 effectivePending=6616 remainingPaint=115 repeatedRuns=0 terminal=true artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,48 @@
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 write = process.argv.includes("--write");
const absolute = (file) => path.join(root, file);
const read = (file) => fs.readFileSync(absolute(file), "utf8");
const json = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const outputRoot = "tests/golden/WBV2-P16-002";
const productionPath = `${outputRoot}/paint-attributes-production.json`;
const secondProductionPath = `${outputRoot}/paint-attributes-production.second.json`;
const reportPath = `${outputRoot}/paint-attributes-receipt-report.json`;
const statusPath = "docs/status/WBV2-P16-002.md";
const planPath = `${outputRoot}/paint-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P16-001/manifest.json";
const selectionPath = "tests/golden/WBV2-P16-001/paint-selection-report.json";
const sourceReportPath = "tests/golden/WBV2-P4-003/sculpt-report.json";
const sourceRunnerPath = "tools/web/check-paint-roundtrip.mjs";
const sourceApiPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
const sourceTestPath = "web/tests/e2e/wbv2-paint-attributes-production.spec.ts";
const colorFixturePath = "tests/files/web/attribute_scene.blend";
const weightFixturePath = "tests/files/web/rigged_shape_scene.blend";
const parent = json(parentPath); const selection = json(selectionPath); const production = json(productionPath); const second = json(secondProductionPath);
assert.equal(parent.task, "WBV2-P16-001"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P16-002"); for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(selection.status, "PASS"); assert.equal(selection.candidate.capabilityId, "SCULPT.PAINT_ATTRIBUTES"); assert.equal(selection.inventory.matchedEntries, 117); assert.equal(selection.candidate.fullFamilyParity, false);
assert.equal(production.task, "WBV2-P16-002"); assert.equal(production.browser, "chromium"); assert.equal(production.queueMutation, false); assert.deepEqual(production, second);
assert.deepEqual(production.color.revisions, [1, 2, 3, 4]); assert.deepEqual(production.weight.revisions, [1, 2, 3, 4, 5]); assert.deepEqual(production.color.firstColor, [0.125, 0.375, 0.625, 0.875]); assert.deepEqual(production.color.reopenedColors, production.color.firstColor); assert.equal(production.color.malformed.code, "PAINT_SCHEMA_INVALID"); assert.equal(production.color.malformedRevisionPreserved, true); assert.equal(production.color.reopenedRevision, 1); assert.equal(production.weight.groupIndex >= 0, true); assert.ok(Math.abs(production.weight.vertex0 - 0.75) < 1e-5); assert.ok(Math.abs(production.weight.vertex1 - 0.25) < 1e-5); assert.ok(Math.abs(production.weight.normalizedSum - 1) < 1e-5); assert.equal(production.weight.saveReopen, true);
const inventoryBindings = [
{ id: "operator:paint.vertex_color_set", evidence: "setVertexColors", exact: true, reason: "bounded protocol command directly writes corner color attribute" },
{ id: "operator:paint.weight_set", evidence: "setVertexWeights", exact: true, reason: "bounded protocol command directly writes vertex group weights" },
];
const receipt = { schemaVersion: 1, task: "WBV2-P16-002", operation: "PAINT_ATTRIBUTES_ENGINE_RECEIPT", status: "PASS", browser: "chromium", queueMutation: false, source: { task: "WBV2-P16-001", manifest: parentPath, manifestSha256: sha256(parentPath), selection: selectionPath, selectionSha256: sha256(selectionPath), sourceReport: sourceReportPath, sourceReportSha256: sha256(sourceReportPath), runner: sourceRunnerPath, runnerSha256: sha256(sourceRunnerPath), api: sourceApiPath, apiSha256: sha256(sourceApiPath), productionTest: sourceTestPath, productionTestSha256: sha256(sourceTestPath), colorFixture: colorFixturePath, colorFixtureSha256: sha256(colorFixturePath), weightFixture: weightFixturePath, weightFixtureSha256: sha256(weightFixturePath) }, production: { report: productionPath, reportSha256: sha256(productionPath), secondReport: secondProductionPath, secondReportSha256: sha256(secondProductionPath), deterministic: true, operations: ["setVertexColors", "setVertexWeights"], colorRevisions: production.color.revisions, weightRevisions: production.weight.revisions, color: production.color, weight: production.weight, malformed: production.color.malformed, malformedMainMutation: false, saveReopen: "EXACT" }, inventoryBindings, assertions: { colorAttributeBound: true, weightAttributeBound: true, inventoryBindingsExact: true, undoRedoSequential: true, malformedRejected: true, mainUnchangedOnMalformed: true, saveReopenExact: true, deterministic: true, representativeSliceOnly: true, fullFamilyParity: false, historicalReproduction: false }, nextTask: "WBV2-P16-003" };
if (!write) { process.stdout.write(`wbv2-paint-receipt-ok task=WBV2-P16-002 operations=2 bindings=2 revisions=SEQUENTIAL malformed=REJECTED saveReopen=EXACT deterministic=true next=WBV2-P16-003\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(receipt, null, 2)}\n`); fs.writeFileSync(absolute(statusPath), `# WBV2-P16-002 status\n\n- task: \`WBV2-P16-002\`; parent: \`WBV2-P16-001\`; status: \`done\`\n- Chromium/WASM Main operations: \`setVertexColors\`, \`setVertexWeights\`\n- exact inventory bindings: \`operator:paint.vertex_color_set\`, \`operator:paint.weight_set\`\n- revisions: colors \`1 -> 4\`; weights \`1 -> 5\`; malformed color input rejected\n- save/reopen: \`EXACT\`; deterministic second run: \`true\`\n- representative slice: \`true\`; full-family parity: \`false\`; inventory pending before overlay: \`6618\`\n- nextTask: \`WBV2-P16-003\`\n\nThe production receipt binds two specific paint operators to the compiled WASM Main. Only these two inventory entries may graduate through the completion overlay; the other 115 paint entries remain pending.\n`);
const previousPlan = json("tests/golden/WBV2-P16-001/paint-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P16-001/paint-task-plan.json", sha256: sha256("tests/golden/WBV2-P16-001/paint-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P16-002" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P16-003" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P16-003.md"), read("docs/tasks/WBV2-P16-003.md").replace("- status: planned", "- status: in_progress")); execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" }); execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P16-002", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, selection: selectionPath, sourceReport: sourceReportPath, runner: sourceRunnerPath, api: sourceApiPath, productionTest: sourceTestPath, colorFixture: colorFixturePath, weightFixture: weightFixturePath, production: productionPath, productionSecond: secondProductionPath, report: reportPath, generator: "tools/web/generate-wbv2-paint-receipt.mjs", status: statusPath, parityPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }])); const manifest = { schemaVersion: 1, task: "WBV2-P16-002", parentTask: "WBV2-P16-001", operation: "PAINT_ATTRIBUTES_ENGINE_RECEIPT", status: "done", enablingTask: false, parityStateChange: true, runtime: "PLAYWRIGHT_CHROMIUM_WEBENGINE_WASM", artifacts, assertions: { operations: 2, exactInventoryBindings: inventoryBindings.length, boundInventoryIds: inventoryBindings.map((binding) => binding.id), colorAttributeBound: true, weightAttributeBound: true, undoRedoSequential: true, malformedRejected: true, saveReopen: "EXACT", deterministic: true, representativeSliceOnly: true, fullFamilyParity: false, inventoryTotal: 6900, inventoryPending: 6618, historicalReproduction: false }, nextTask: "WBV2-P16-003" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-003` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-003.md`](tasks/WBV2-P16-003.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTask = read("nextTask.md"); nextTask = nextTask.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P16-003` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-002/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-003.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `NONE` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-paint-gate.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write(`wbv2-paint-receipt-written task=WBV2-P16-002 operations=2 bindings=2 revisions=SEQUENTIAL malformed=REJECTED saveReopen=EXACT deterministic=true next=WBV2-P16-003 artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,54 @@
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 absolute = (file) => path.join(root, file);
const read = (file) => fs.readFileSync(absolute(file), "utf8");
const json = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const p15ManifestPath = "tests/golden/WBV2-P15-003/manifest.json";
const p15ReportPath = "tests/golden/WBV2-P15-003/lighting-gate-report.json";
const p16Root = "tests/golden/WBV2-P16-000";
const planPath = `${p16Root}/paint-task-plan.json`;
const reportPath = `${p16Root}/paint-root-report.json`;
const manifestPath = `${p16Root}/manifest.json`;
const statusPath = "docs/status/WBV2-P16-000.md";
const inventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
const sourceReportPath = "tests/golden/WBV2-P4-003/sculpt-report.json";
const sourceRunnerPath = "tools/web/check-paint-roundtrip.mjs";
const sourceCommandPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
const sourceTestPath = "web/tests/e2e/paint-pbvh-capability.spec.ts";
const p15 = json(p15ManifestPath); const p15Report = json(p15ReportPath); const inventory = json(inventoryPath);
assert.equal(p15.task, "WBV2-P15-003"); assert.equal(p15.status, "done"); assert.equal(p15.nextTask, null); assert.equal(p15Report.status, "PASS"); assert.equal(p15Report.decision.fullHistoricalReproduction, false); assert.equal(inventory.summary.inventoryEntries, 6900);
for (const artifact of Object.values(p15.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
const tasks = [
{ id: "WBV2-P16-000", phase: "P16", title: "authorize_paint_capability_continuation", kind: "enabling", owner: "PROGRAM", dependsOn: ["WBV2-P15-003"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p16-governance", gate: "G2", card: "docs/tasks/WBV2-P16-000.md", behavior: "Authorize a source-backed Sculpt/Paint continuation without reopening completed batches.", outputs: ["continuation root", "candidate scope", "hash boundary"], acceptance: ["P15 evidence remains hash-bound", "paint source and fixtures exist", "one production task is active"], status: "done", ready: false, queueMutationAllowed: true },
{ id: "WBV2-P16-001", phase: "P16", title: "select_paint_capability_batch", kind: "enabling", owner: "PARITY", dependsOn: ["WBV2-P16-000"], parityId: "SCULPT.PAINT_ATTRIBUTES", implementationClass: "LOCAL_BOUNDED", parallelGroup: "p16-selection", gate: "G2", card: "docs/tasks/WBV2-P16-001.md", behavior: "Select one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.", outputs: ["candidate report", "behavior hash", "dedupe key"], acceptance: ["source commands are present", "existing paint evidence is reused", "candidate remains representative"], status: "in_progress", ready: true, queueMutationAllowed: false },
{ id: "WBV2-P16-002", phase: "P16", title: "paint_attributes_engine_receipt", kind: "feature", owner: "SCULPT", dependsOn: ["WBV2-P16-001"], parityId: "SCULPT.PAINT_ATTRIBUTES", implementationClass: "LOCAL_EXACT", parallelGroup: "p16-paint", gate: "G2", card: "docs/tasks/WBV2-P16-002.md", behavior: "Bind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.", outputs: ["paint production report", "paint receipt", "manifest"], acceptance: ["vertex colors and weights match", "undo/redo is sequential", "malformed input fails closed", "save/reopen is exact"], status: "planned", ready: false, queueMutationAllowed: false },
{ id: "WBV2-P16-003", phase: "P16", title: "close_paint_capability_gate", kind: "enabling", owner: "RELEASE", dependsOn: ["WBV2-P16-002"], parityId: null, implementationClass: "LOCAL_BOUNDED", parallelGroup: "p16-release", gate: "G5", card: "docs/tasks/WBV2-P16-003.md", behavior: "Close the paint capability gate without promoting representative evidence to full-family completion.", outputs: ["paint gate", "limited declaration", "manifest"], acceptance: ["only tested paint behavior is claimed", "inventory remainder stays explicit", "no duplicate validation or historical over-claim"], status: "planned", ready: false, queueMutationAllowed: false },
];
const plan = { schemaVersion: 1, planId: "BLENDER_WEB_PARITY_V2_PAINT_EPOCH_1", status: "ACTIVE_PAINT_QUEUE", authority: "queue_reactivated_after_p15_lighting_gate", sourcePlan: "docs/BLENDER_WEB_PARITY_TASK_PLAN_V2.json", executionPointer: "docs/EXECUTION_QUEUE.md", runtimePolicy: { blenderSource: "blender-5.2.0", browserEvidence: ["chromium"], forbiddenBrowsers: ["firefox", "webkit"], mainAuthority: "blender_main", reusePolicy: "source_hash_and_behavior_hash_deduplication" }, parentHighValue: { manifest: p15ManifestPath, report: p15ReportPath, inventoryTotal: 6900, inventoryPending: 6618, duplicateValidationAvoided: true }, tasks };
fs.mkdirSync(absolute(p16Root), { recursive: true }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(plan, null, 2)}\n`);
const report = { schemaVersion: 1, task: "WBV2-P16-000", operation: "AUTHORIZE_PAINT_CAPABILITY_CONTINUATION", status: "PASS", parent: { task: p15.task, manifest: p15ManifestPath, manifestSha256: sha256(p15ManifestPath), report: p15ReportPath, reportSha256: sha256(p15ReportPath), previousDecision: p15Report.decision.status }, continuation: { root: "WBV2-P16-000", firstTask: "WBV2-P16-001", plannedTasks: 4, candidate: "SCULPT.PAINT_ATTRIBUTES", sourceReport: sourceReportPath, sourceRunner: sourceRunnerPath, sourceApi: sourceCommandPath, chromiumBoundaryTest: sourceTestPath, browser: "chromium", inventoryTotal: 6900, inventoryPending: 6618, noRepeatedExecution: true }, policy: { p15EvidencePreserved: true, sourceHistoryReadOnly: true, representativeSliceOnly: true, duplicateValidationAvoided: true, authorizedRebaselineOnly: true, fullHistoricalReproduction: false }, nextTask: "WBV2-P16-001" };
fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P16-000.md"), `# WBV2-P16-000: paint capability continuation root\n\n- task: WBV2-P16-000\n- parent: WBV2-P15-003\n- status: done\n- gap: workflow:authorize_paint_capability_continuation\n- ownerFamily: PROGRAM\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nAuthorize a source-backed Sculpt/Paint continuation. P16 reuses the 6900-entry coverage ledger and validates one vertex-color/weight behavior batch against the compiled WebEngine WASM Main in Chromium.\n\n## 验收\n\n- \`node tools/web/generate-wbv2-paint-root.mjs\`\n- \`node tools/web/check-execution-control-plane.mjs\`\n- \`node tools/web/check-v2-task-index.mjs\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-000/\`\n- Manifest: \`tests/golden/WBV2-P16-000/manifest.json\`\n- Rollback: restore P15-003 as queue parent without rewriting P15 evidence.\n`);
const cards = {
"WBV2-P16-001": `# WBV2-P16-001: select_paint_capability_batch\n\n- task: WBV2-P16-001\n- parent: WBV2-P16-000\n- status: in_progress\n- gap: capability:SCULPT.PAINT_ATTRIBUTES\n- ownerFamily: PARITY\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nSelect one deterministic vertex-color and weight-paint behavior batch from source and inventory evidence.\n\n## 输入与范围\n\n- Focused source: \`tests/golden/WBV2-P0-002/parity-map.json\`\n- Existing source receipt: \`tests/golden/WBV2-P4-003/sculpt-report.json\`\n- Production API: \`blender-5.2.0/source/blender/web_engine/web_engine_api.cpp\`\n- Production entrypoint: \`node tools/web/generate-wbv2-paint-selection.mjs --write\`\n\n## 验收\n\n- source commands are present and hash-bound\n- existing paint evidence is reused read-only\n- candidate remains representative rather than full-family completion\n- malformed, hash-drift, unsupported, or false-completion input keeps in_progress\n- \`node tools/web/check-task-context.mjs --task WBV2-P16-001 --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-001/\`\n- Status: \`docs/status/WBV2-P16-001.md\`\n- Manifest: \`tests/golden/WBV2-P16-001/manifest.json\`\n- Rollback: restore P16-000 as queue parent.\n`,
"WBV2-P16-002": `# WBV2-P16-002: paint_attributes_engine_receipt\n\n- task: WBV2-P16-002\n- parent: WBV2-P16-001\n- status: planned\n- gap: capability:SCULPT.PAINT_ATTRIBUTES\n- ownerFamily: SCULPT\n- targetImplementationClass: LOCAL_EXACT\n\n## 目标\n\nBind vertex colors and weights, undo/redo, malformed rejection, and exact save/reopen to compiled WASM Main in Chromium.\n\n## 输入与范围\n\n- Focused source: \`tests/golden/WBV2-P16-001/paint-selection-report.json\`\n- Production test: \`web/tests/e2e/wbv2-paint-attributes-production.spec.ts\`\n- Production entrypoint: \`npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts\`\n\n## 验收\n\n- vertex colors and weights match bounded expectations\n- undo/redo revisions are sequential\n- malformed input fails closed without Main mutation\n- save/reopen is exact and deterministic\n- Chromium is the only browser\n- \`node tools/web/check-task-context.mjs --task WBV2-P16-002 --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-002/\`\n- Status: \`docs/status/WBV2-P16-002.md\`\n- Manifest: \`tests/golden/WBV2-P16-002/manifest.json\`\n- Rollback: restore P16-001 as queue parent.\n`,
"WBV2-P16-003": `# WBV2-P16-003: close_paint_capability_gate\n\n- task: WBV2-P16-003\n- parent: WBV2-P16-002\n- status: planned\n- gap: workflow:close_paint_capability_gate\n- ownerFamily: RELEASE\n- targetImplementationClass: LOCAL_BOUNDED\n\n## 目标\n\nClose the paint capability gate without promoting representative evidence to full-family completion.\n\n## 输入与范围\n\n- Focused receipt: \`tests/golden/WBV2-P16-002/paint-attributes-receipt-report.json\`\n- Coverage matrix: \`tests/golden/WBV2-P14-002/capability-evidence-matrix.json\`\n- Production entrypoint: \`node tools/web/generate-wbv2-paint-gate.mjs --write\`\n\n## 验收\n\n- only tested paint behavior is claimed\n- inventory remainder remains 6618\n- duplicate validation remains zero\n- malformed, hash-drift, unsupported, or false-completion input keeps in_progress\n- historical reproduction remains false\n- \`node tools/web/check-task-context.mjs --task WBV2-P16-003 --write\`\n\n## 交付与回滚\n\n- Reports: \`tests/golden/WBV2-P16-003/\`\n- Status: \`docs/status/WBV2-P16-003.md\`\n- Manifest: \`tests/golden/WBV2-P16-003/manifest.json\`\n- Rollback: restore P16-002 as queue parent.\n`,
};
for (const [id, card] of Object.entries(cards)) fs.writeFileSync(absolute(`docs/tasks/${id}.md`), `${card}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P16-000 status\n\n- task: \`WBV2-P16-000\`; parent: \`WBV2-P15-003\`; status: \`done\`\n- candidate: \`SCULPT.PAINT_ATTRIBUTES\`; source commands and existing receipts are present\n- inventory carried forward: \`6900\` total, \`6618\` pending\n- duplicate validation: \`forbidden\`; representative slice only\n- nextTask: \`WBV2-P16-001\`\n\nP16 is an authorized continuation that reuses P14 coverage and validates one unique vertex-color/weight behavior batch in Chromium.\n`);
const artifactPaths = { parentManifest: p15ManifestPath, parentReport: p15ReportPath, inventory: inventoryPath, sourceReport: sourceReportPath, sourceRunner: sourceRunnerPath, sourceApi: sourceCommandPath, sourceTest: sourceTestPath, plan: planPath, report: reportPath, rootCard: "docs/tasks/WBV2-P16-000.md", rootStatus: statusPath };
const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }]));
const manifest = { schemaVersion: 1, task: "WBV2-P16-000", parentTask: "WBV2-P15-003", operation: "AUTHORIZE_PAINT_CAPABILITY_CONTINUATION", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_PAINT_CONTINUATION_ROOT", artifacts, assertions: { p15EvidencePreserved: true, sourceCommandsBound: true, existingPaintReceiptBound: true, inventoryTotal: 6900, inventoryPending: 6618, duplicateValidationAvoided: true, representativeSliceOnly: true, authorizedRebaselineOnly: true, fullHistoricalReproduction: false }, nextTask: "WBV2-P16-001" };
fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" });
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-001` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-000/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-001.md`](tasks/WBV2-P16-001.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTask = read("nextTask.md"); nextTask = nextTask.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P16-001` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-000/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-001.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P16-002` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `node tools/web/generate-wbv2-paint-selection.mjs --write` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write("wbv2-paint-root-written root=WBV2-P16-000 next=WBV2-P16-001 candidate=SCULPT.PAINT_ATTRIBUTES inventoryPending=6618\n");

View File

@@ -0,0 +1,50 @@
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 write = process.argv.includes("--write");
const absolute = (file) => path.join(root, file);
const read = (file) => fs.readFileSync(absolute(file), "utf8");
const json = (file) => JSON.parse(read(file));
const sha256 = (file) => crypto.createHash("sha256").update(fs.readFileSync(absolute(file))).digest("hex");
const digestText = (value) => crypto.createHash("sha256").update(value).digest("hex");
const outputRoot = "tests/golden/WBV2-P16-001";
const reportPath = `${outputRoot}/paint-selection-report.json`;
const candidatePath = `${outputRoot}/paint-candidate-set.json`;
const statusPath = "docs/status/WBV2-P16-001.md";
const planPath = `${outputRoot}/paint-task-plan.json`;
const manifestPath = `${outputRoot}/manifest.json`;
const parentPath = "tests/golden/WBV2-P16-000/manifest.json";
const inventoryPath = "tests/golden/WBV2-P0-002/parity-map.json";
const sourceReportPath = "tests/golden/WBV2-P4-003/sculpt-report.json";
const sourceRunnerPath = "tools/web/check-paint-roundtrip.mjs";
const sourceApiPath = "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp";
const sourceTestPath = "web/tests/e2e/paint-pbvh-capability.spec.ts";
const colorFixturePath = "tests/files/web/attribute_scene.blend";
const weightFixturePath = "tests/files/web/rigged_shape_scene.blend";
const parent = json(parentPath); const inventory = json(inventoryPath); const sourceReport = json(sourceReportPath);
assert.equal(parent.task, "WBV2-P16-000"); assert.equal(parent.status, "done"); assert.equal(parent.nextTask, "WBV2-P16-001");
for (const artifact of Object.values(parent.artifacts ?? {})) assert.equal(sha256(artifact.path), artifact.sha256, artifact.path);
assert.equal(inventory.summary.inventoryEntries, 6900); assert.equal(inventory.summary.pendingLegacyEntries, 6618); assert.equal(sourceReport.desktop.status, "EXACT"); assert.equal(sourceReport.wasm.status, "EXACT");
const apiSource = read(sourceApiPath); const runnerSource = read(sourceRunnerPath); const testSource = read(sourceTestPath);
assert.match(apiSource, /setVertexColors/); assert.match(apiSource, /setVertexWeights/); assert.match(runnerSource, /setVertexColors/); assert.match(runnerSource, /setVertexWeights/); assert.match(testSource, /queryPaintPBVHCapability/);
const candidates = inventory.entries.filter((entry) => entry.capabilityId === "CAP-SCULPT-PAINT").map((entry) => ({ id: entry.id, kind: entry.kind, family: entry.family, sourceTask: entry.sourceTask, legacyState: entry.legacyState, state: entry.state, targetImplementationClass: entry.targetImplementationClass }));
assert.equal(candidates.length, 117); assert.equal(candidates.filter((entry) => entry.legacyState === "pending").length, 117);
const behavior = { capability: "SCULPT.PAINT_ATTRIBUTES", operations: ["setVertexColors", "setVertexWeights"], fixtures: [colorFixturePath, weightFixturePath], positive: ["uniform-corner-colors", "normalized-weights", "undo", "redo", "save-reopen"], negative: ["invalid-color-index", "unknown-weight-group"], browser: "chromium", engine: "compiled-WASM-WebEngine-Main" };
const behaviorHash = digestText(JSON.stringify(behavior));
const candidate = { schemaVersion: 1, task: "WBV2-P16-001", operation: "PAINT_CAPABILITY_CANDIDATE_SELECTION", status: "READY", source: { inventory: inventoryPath, inventorySha256: sha256(inventoryPath), sourceReport: sourceReportPath, sourceReportSha256: sha256(sourceReportPath), runner: sourceRunnerPath, runnerSha256: sha256(sourceRunnerPath), api: sourceApiPath, apiSha256: sha256(sourceApiPath), chromiumBoundaryTest: sourceTestPath, chromiumBoundaryTestSha256: sha256(sourceTestPath), colorFixture: colorFixturePath, colorFixtureSha256: sha256(colorFixturePath), weightFixture: weightFixturePath, weightFixtureSha256: sha256(weightFixturePath) }, candidate: { capabilityId: "SCULPT.PAINT_ATTRIBUTES", representativeBehavior: behavior, behaviorHash, dedupeKey: `SCULPT.PAINT_ATTRIBUTES|${behaviorHash}|${sha256(sourceApiPath)}|${sha256(colorFixturePath)}|${sha256(weightFixturePath)}`, sourceBacked: true, chromiumProductionReady: true, fullFamilyParity: false }, inventory: { matchedEntries: candidates.length, pending: candidates.length, remainderExplicit: true }, entries: candidates, policy: { sourceHistoryReadOnly: true, representativeSliceOnly: true, noRepeatedExecution: true, duplicateValidationAvoided: true, fullHistoricalReproduction: false } };
const report = { schemaVersion: 1, task: "WBV2-P16-001", operation: "SELECT_PAINT_CAPABILITY_BATCH", status: "PASS", candidate: candidate.candidate, inventory: candidate.inventory, source: candidate.source, matchedEntryDigest: digestText(JSON.stringify(candidates)), efficiency: { oneCapabilityScan: true, existingPaintEvidenceReused: true, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true }, nextTask: "WBV2-P16-002" };
if (!write) { process.stdout.write(`wbv2-paint-selection-ok task=WBV2-P16-001 matched=117 capability=SCULPT.PAINT_ATTRIBUTES behaviorHash=${behaviorHash} pending=6618 repeatedRuns=0 next=WBV2-P16-002\n`); process.exit(0); }
fs.mkdirSync(absolute(outputRoot), { recursive: true }); fs.writeFileSync(absolute(candidatePath), `${JSON.stringify(candidate, null, 2)}\n`); fs.writeFileSync(absolute(reportPath), `${JSON.stringify(report, null, 2)}\n`);
fs.writeFileSync(absolute(statusPath), `# WBV2-P16-001 status\n\n- task: \`WBV2-P16-001\`; parent: \`WBV2-P16-000\`; status: \`done\`\n- selected capability: \`SCULPT.PAINT_ATTRIBUTES\`; operations: vertex colors and vertex weights\n- matched inventory entries: \`117\`; inventory remains \`6900\` total, \`6618\` pending\n- behavior hash: \`${behaviorHash}\`; dedupe key binds API and fixture hashes\n- existing paint evidence reused: \`true\`; repeated Blender/Chromium runs: \`0\`\n- representative slice: \`true\`; full-family parity: \`false\`\n- nextTask: \`WBV2-P16-002\`\n\nOnly one unique color/weight behavior batch will be executed in Chromium. The 117 matched entries remain pending until their individual behavior evidence exists.\n`);
const previousPlan = json("tests/golden/WBV2-P16-000/paint-task-plan.json"); const nextPlan = structuredClone(previousPlan); nextPlan.parentRecoveryPlan = { path: "tests/golden/WBV2-P16-000/paint-task-plan.json", sha256: sha256("tests/golden/WBV2-P16-000/paint-task-plan.json") }; nextPlan.tasks = nextPlan.tasks.map((task) => task.id === "WBV2-P16-001" ? { ...task, status: "done", ready: false } : task.id === "WBV2-P16-002" ? { ...task, status: "in_progress", ready: true } : { ...task, ready: false }); fs.writeFileSync(absolute(planPath), `${JSON.stringify(nextPlan, null, 2)}\n`);
fs.writeFileSync(absolute("docs/tasks/WBV2-P16-002.md"), read("docs/tasks/WBV2-P16-002.md").replace("- status: planned", "- status: in_progress")); execFileSync(process.execPath, [absolute("tools/web/generate-v2-task-index.mjs"), "--plan-path", absolute(planPath)], { cwd: root, stdio: "inherit" }); execFileSync(process.execPath, [absolute("tools/web/check-task-context.mjs"), "--task", "WBV2-P16-001", "--write"], { cwd: root, stdio: "inherit" });
const artifactPaths = { parentManifest: parentPath, inventory: inventoryPath, sourceReport: sourceReportPath, sourceRunner: sourceRunnerPath, sourceApi: sourceApiPath, sourceTest: sourceTestPath, colorFixture: colorFixturePath, weightFixture: weightFixturePath, candidate: candidatePath, report: reportPath, generator: "tools/web/generate-wbv2-paint-selection.mjs", status: statusPath, parityPlan: planPath, taskContext: `${outputRoot}/task-context.json` }; const artifacts = Object.fromEntries(Object.entries(artifactPaths).map(([name, file]) => [name, { path: file, sha256: sha256(file) }])); const manifest = { schemaVersion: 1, task: "WBV2-P16-001", parentTask: "WBV2-P16-000", operation: "SELECT_PAINT_CAPABILITY_BATCH", status: "done", enablingTask: true, parityStateChange: false, runtime: "READ_ONLY_SOURCE_CANDIDATE_SELECTION", artifacts, assertions: { capability: "SCULPT.PAINT_ATTRIBUTES", matchedInventoryEntries: 117, inventoryTotal: 6900, inventoryPending: 6618, sourceApiBound: true, existingEvidenceReused: true, representativeSliceOnly: true, fullFamilyParity: false, repeatedBlenderRuns: 0, repeatedChromiumRuns: 0, duplicateValidationAvoided: true, deterministic: true, historicalReproduction: false }, nextTask: "WBV2-P16-002" }; fs.writeFileSync(absolute(manifestPath), `${JSON.stringify(manifest, null, 2)}\n`);
let queue = read("docs/EXECUTION_QUEUE.md"); queue = queue.replace(/\| 当前任务 \| `[^`]+` \|/u, "| 当前任务 | `WBV2-P16-002` |").replace(/\| parent manifest \| `[^`]+` \|/u, "| parent manifest | `tests/golden/WBV2-P16-001/manifest.json` |").replace(/\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|/u, "| 任务卡 | [`tasks/WBV2-P16-002.md`](tasks/WBV2-P16-002.md) |"); fs.writeFileSync(absolute("docs/EXECUTION_QUEUE.md"), queue);
let nextTask = read("nextTask.md"); nextTask = nextTask.replace(/\| Current task when this file was written \| `[^`]+` \|/u, "| Current task when this file was written | `WBV2-P16-002` |").replace(/\| Current task state \| `[^`]+` \|/u, "| Current task state | `in_progress` |").replace(/\| Parent manifest \| `[^`]+` \|/u, "| Parent manifest | `tests/golden/WBV2-P16-001/manifest.json` |").replace(/\| Current task card \| `[^`]+` \|/u, "| Current task card | `docs/tasks/WBV2-P16-002.md` |").replace(/\| Current task-context nextTask \| `[^`]+` \|/u, "| Current task-context nextTask | `WBV2-P16-003` |").replace(/\| Focused command \| `[^`]+` \|/u, "| Focused command | `npm --prefix web run test:e2e -- --workers=1 tests/e2e/wbv2-paint-attributes-production.spec.ts` |"); fs.writeFileSync(absolute("nextTask.md"), nextTask);
process.stdout.write(`wbv2-paint-selection-written task=WBV2-P16-001 matched=117 capability=SCULPT.PAINT_ATTRIBUTES behaviorHash=${behaviorHash} pending=6618 next=WBV2-P16-002 artifacts=${Object.keys(artifacts).length}\n`);

View File

@@ -0,0 +1,60 @@
import { expect, test } from "@playwright/test";
import crypto from "node:crypto";
import fs from "node:fs";
import path from "node:path";
const root = path.resolve(import.meta.dirname, "../../..");
const evidenceRoot = path.join(root, "tests/golden/WBV2-P16-002");
const colorFixture = fs.readFileSync(path.join(root, "tests/files/web/attribute_scene.blend"));
const weightFixture = fs.readFileSync(path.join(root, "tests/files/web/rigged_shape_scene.blend"));
const fixtureSha256 = (bytes: Buffer) => crypto.createHash("sha256").update(bytes).digest("hex");
test("WBV2-P16-002 binds paint attributes to compiled WASM Main", async ({ page }) => {
test.setTimeout(120_000);
await page.goto("/");
const result = await page.evaluate(async ({ colorBytes, weightBytes }) => {
const { WebEngineClient } = await import("/src/engine-client/WebEngineClient.ts");
const digest = async (value: ArrayBuffer): Promise<string> => { const hash = await crypto.subtle.digest("SHA-256", value); return Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, "0")).join(""); };
const colorClient = new WebEngineClient({ timeoutMs: 30_000 });
const weightClient = new WebEngineClient({ timeoutMs: 30_000 });
try {
const colorOpened = await colorClient.openBlend(Uint8Array.from(colorBytes).buffer);
const colorMesh = colorOpened.snapshot.meshes.find((mesh) => mesh.id === "mesh:AttributeMesh")!;
const colorBefore = colorOpened.snapshot.revision;
const colorValues = Array.from({ length: colorMesh.cornerCount * 4 }, (_, index) => [0.125, 0.375, 0.625, 0.875][index % 4]);
const colorEdit = await colorClient.applyCommand({ type: "setVertexColors", meshId: colorMesh.id, attributeName: "WebPaintColor", domain: "CORNER", indices: Array.from({ length: colorMesh.cornerCount }, (_, index) => index), colors: colorValues } as any);
const colorUndo = await colorClient.applyCommand({ type: "undo" });
const colorRedo = await colorClient.applyCommand({ type: "redo" });
const colorMalformed = await colorClient.applyCommand({ type: "setVertexColors", meshId: colorMesh.id, attributeName: "WebPaintColor", domain: "CORNER", indices: [colorMesh.cornerCount + 1], colors: [0, 0, 0, 1] } as any).then(() => ({ code: "NO_ERROR" })).catch((error: any) => ({ code: error?.code, message: error?.message }));
const colorAfterMalformed = await colorClient.snapshot();
const colorMeshAfterEdit = colorEdit.snapshot.meshes.find((mesh) => mesh.id === colorMesh.id)!;
const colorBufferAfterEdit = colorEdit.geometryBuffers.find((buffer) => buffer.meshId === colorMesh.id);
const colorSaved = await colorClient.saveBlend();
const colorReopened = new WebEngineClient({ timeoutMs: 30_000 });
const colorReopenResult = await colorReopened.openBlend(colorSaved);
const colorBufferAfterReopen = colorReopenResult.geometryBuffers.find((buffer) => buffer.meshId === colorMesh.id);
const colorMeshAfter = colorReopenResult.snapshot.meshes.find((mesh) => mesh.id === colorMesh.id)!;
const weightOpened = await weightClient.openBlend(Uint8Array.from(weightBytes).buffer);
const weightBefore = weightOpened.snapshot.revision;
const weightEdit = await weightClient.applyCommand({ type: "setVertexWeights", objectId: "object:RiggedShapeObject", vertexGroup: "WebPaintGroup", indices: [0, 1], values: [0.75, 0.25], normalize: false } as any);
const weightNormalize = await weightClient.applyCommand({ type: "setVertexWeights", objectId: "object:RiggedShapeObject", vertexGroup: "WebPaintGroup", indices: [2], values: [0.5], normalize: true } as any);
const weightUndo = await weightClient.applyCommand({ type: "undo" });
const weightRedo = await weightClient.applyCommand({ type: "redo" });
const weightSaved = await weightClient.saveBlend();
const weightReopened = new WebEngineClient({ timeoutMs: 30_000 });
const weightReopenResult = await weightReopened.openBlend(weightSaved);
const weightedMesh = weightReopenResult.snapshot.meshes.find((mesh) => mesh.id === "mesh:RiggedShapeMesh")!;
const groupIndex = weightedMesh.skinWeights?.boneNames.indexOf("WebPaintGroup") ?? -1;
const vertexWeight = (vertex: number) => { if (groupIndex < 0 || !weightedMesh.skinWeights) return 0; const offset = vertex * 4; const slot = weightedMesh.skinWeights.indices.slice(offset, offset + 4).findIndex((value) => value === groupIndex); return slot < 0 ? 0 : weightedMesh.skinWeights.weights[offset + slot]; };
const normalizedSum = weightedMesh.skinWeights?.weights.slice(8, 12).reduce((sum, value) => sum + value, 0) ?? 0;
const output = { browser: "chromium", color: { baseRevision: colorBefore, revisions: [colorBefore, colorEdit.snapshot.revision, colorUndo.snapshot.revision, colorRedo.snapshot.revision], cornerCount: colorMesh.cornerCount, firstColor: colorBufferAfterEdit?.colors ? Array.from(new Float32Array(colorBufferAfterEdit.colors).slice(0, 4)) : undefined, malformed: colorMalformed, malformedRevisionPreserved: colorAfterMalformed.snapshot.revision === colorRedo.snapshot.revision, savedSha256: await digest(colorSaved), reopenedRevision: colorReopenResult.snapshot.revision, reopenedColors: colorBufferAfterReopen?.colors ? Array.from(new Float32Array(colorBufferAfterReopen.colors).slice(0, 4)) : undefined }, weight: { baseRevision: weightBefore, revisions: [weightBefore, weightEdit.snapshot.revision, weightNormalize.snapshot.revision, weightUndo.snapshot.revision, weightRedo.snapshot.revision], groupIndex, vertex0: vertexWeight(0), vertex1: vertexWeight(1), vertex2: vertexWeight(2), normalizedSum, savedSha256: await digest(weightSaved), saveReopen: weightReopenResult.snapshot.revision === 1 } };
colorReopened.terminate(); weightReopened.terminate();
return output;
} finally { colorClient.terminate(); weightClient.terminate(); }
}, { colorBytes: Array.from(colorFixture), weightBytes: Array.from(weightFixture) });
fs.mkdirSync(evidenceRoot, { recursive: true });
const output = process.env.WBV2_PAINT_REPORT ?? "paint-attributes-production.json";
fs.writeFileSync(path.join(evidenceRoot, output), `${JSON.stringify({ schemaVersion: 1, task: "WBV2-P16-002", operation: "PAINT_ATTRIBUTES_ENGINE_CHROMIUM", queueMutation: false, sourceFixtures: { colorSha256: fixtureSha256(colorFixture), weightSha256: fixtureSha256(weightFixture) }, ...result }, null, 2)}\n`);
expect(result.browser).toBe("chromium"); expect(result.color.revisions).toEqual([1, 2, 3, 4]); expect(result.weight.revisions).toEqual([1, 2, 3, 4, 5]); expect(result.color.malformed.code).not.toBe("NO_ERROR"); expect(result.color.malformedRevisionPreserved).toBe(true); expect(result.color.firstColor).toEqual([0.125, 0.375, 0.625, 0.875]); expect(result.color.reopenedRevision).toBe(1); expect(result.weight.groupIndex).toBeGreaterThanOrEqual(0); expect(result.weight.vertex0).toBeCloseTo(0.75, 4); expect(result.weight.vertex1).toBeCloseTo(0.25, 4); expect(result.weight.normalizedSum).toBeCloseTo(1, 4); expect(result.weight.saveReopen).toBe(true);
});