Files
workinf_Blender_Wasm/my-tools/activate_operator_route_phase.py
mes123456 e2e81c7c00
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
feat(web): classify and route complete Blender inventory
2026-09-06 21:10:31 +08:00

172 lines
12 KiB
Python

#!/usr/bin/env python3
"""Activate the source-unit route completion phase after product workflows."""
from __future__ import annotations
import hashlib
import json
import re
import subprocess
from pathlib import Path
from wbv2_runtime import CONTROL_ROOT, INDEX, QUEUE, ROOT
CURRENT = "WBV2-P1422-001"
ROOT_TASK = "WBV2-P1423-000"
TASK = "WBV2-P1423-001"
def read_json(path: Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def write_json(path: Path, value: object) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
def write_text(path: Path, value: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(value, encoding="utf-8")
def sha(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
TASKS = [
{
"id": "SERVER-OPERATOR-JOB", "module": "RUNTIME", "title": "Execute background-safe Blender operators through server jobs",
"commands": ["submitServerOperatorJob", "cancelServerOperatorJob", "readServerOperatorResult"],
"ownedPaths": ["web/protocol/server-operator-job.ts", "web/protocol/blender-operator.ts", "web/app/src/engine-client/WebEngineClient.ts", "web/app/src/workers/web-engine.worker.ts", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "tools/web/server-operator-job.py", "tools/web/server-job-process.mjs"],
"implementation": "Add a bounded, hash-bound server operator job contract for the SERVER_NATIVE route. Run Blender background operators in an isolated workspace with typed properties, cancellation, resource budgets and result binding; reject UI/window/file-browser context.",
},
{
"id": "OPERATOR-ROUTE-PALETTE", "module": "WORKSPACE", "title": "Expose every classified operator route in the browser palette",
"commands": ["listFeatureRoutes", "invokeFeatureRoute"],
"ownedPaths": ["web/protocol/blender-operator.ts", "web/protocol/web-engine.ts", "web/app/src/app/App.tsx", "web/app/src/engine-client/WebEngineClient.ts", "web/app/src/workers/web-engine.worker.ts", "web/app/src/capabilities/blender-feature-route-catalog.json"],
"implementation": "Load the complete source-unit route catalog, merge WEB_MAIN operators with server-job and browser-equivalent entries in F3, and show an explicit route/reason badge. Invoke only typed native or server-job routes.",
},
{
"id": "OPERATOR-MACRO-COMPOSER", "module": "RUNTIME", "title": "Decompose and execute operator macros as native command plans",
"commands": ["listBlenderMacros", "invokeBlenderMacro"],
"ownedPaths": ["web/protocol/blender-operator.ts", "web/protocol/web-engine.ts", "web/app/src/app/App.tsx", "web/app/src/workers/web-engine.worker.ts", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp"],
"implementation": "Represent the 58 macro units as bounded, source-backed command plans. Reuse existing Main transactions where possible, otherwise submit a server-native plan; reject context-dependent macro steps before mutation.",
},
{
"id": "RNA-REFLECTION-EXTENDED", "module": "RUNTIME", "title": "Extend RNA reflection to arrays, enums and nested collections",
"commands": ["readRNAPropertySchema", "setRNAArrayProperty", "setRNAEnumProperty", "readRNACollection"],
"ownedPaths": ["web/protocol/web-engine.ts", "web/protocol/scene-ir.ts", "web/app/src/app/App.tsx", "web/app/src/engine-client/WebEngineClient.ts", "web/app/src/workers/web-engine.worker.ts", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.h"],
"implementation": "Expand the bounded RNA route beyond primitive scalars to validated arrays, enums and nested collection reads/writes, keeping pointer, ID-link, context-only and arbitrary execution paths fail-closed.",
},
{
"id": "FEATURE-COVERAGE-DASHBOARD", "module": "WORKSPACE", "title": "Publish complete source-unit route coverage and gap dashboard",
"commands": ["featureRouteCoverage", "featureRouteGaps"],
"ownedPaths": ["web/app/src/app/App.tsx", "web/app/src/capabilities/blender-feature-route-catalog.json", "my-tools/show_blender_web_scheduler.py", "docs/WEB_FULL_FEATURE_GAP_INVENTORY.md"],
"implementation": "Add a route-aware dashboard and scheduler summary for all 3745 units, broken down by WEB_MAIN, SERVER_NATIVE, BROWSER_EQUIVALENT and UNAVAILABLE, with explicit unverified behavioral evidence and no false completion claims.",
},
]
def main() -> int:
backlog_path = CONTROL_ROOT / "web-product-backlog.json"
backlog = read_json(backlog_path)
existing = {task.get("id") for task in backlog.get("tasks", [])}
for task in TASKS:
item = {**task, "attempts": 0, "status": "pending", "resultPath": f"tests/golden/WBV2/product-migration/{task['id']}-result.json"}
if task["id"] not in existing:
backlog.setdefault("tasks", []).append(item)
else:
for current in backlog["tasks"]:
if current.get("id") == task["id"]:
current.update(item)
by_module = {}
for item in backlog["tasks"]:
by_module.setdefault(item.get("module"), []).append(item["id"])
for module in backlog.get("workflowModules", []):
added = by_module.get(module.get("id"), [])
if added:
module["taskIds"] = list(dict.fromkeys([*module.get("taskIds", []), *added]))
module["status"] = "partial"
backlog.update({"previousQueueTask": CURRENT, "rootTask": ROOT_TASK, "queueTask": TASK, "strategy": "implementation_first_route_complete", "routeCatalog": "web/app/src/capabilities/blender-feature-route-catalog.json"})
write_json(backlog_path, backlog)
current_manifest_path = ROOT / "tests/golden" / CURRENT / "manifest.json"
current_manifest = read_json(current_manifest_path)
current_manifest["nextTask"] = ROOT_TASK
write_json(current_manifest_path, current_manifest)
current_status_path = ROOT / "docs/status" / f"{CURRENT}.md"
if current_status_path.is_file():
text = re.sub(r"- nextTask: `[^`]+`", f"- nextTask: `{ROOT_TASK}`", current_status_path.read_text(encoding="utf-8"))
write_text(current_status_path, text)
if isinstance(current_manifest.get("artifacts", {}).get("status"), dict):
current_manifest["artifacts"]["status"]["sha256"] = sha(current_status_path)
write_json(current_manifest_path, current_manifest)
root_dir = ROOT / "tests/golden" / ROOT_TASK
plan_path = root_dir / "operator-route-implementation-plan.json"
base_plan = read_json(ROOT / "tests/golden/WBV2-P1422-000/product-implementation-plan.json")
root_record = {"id": ROOT_TASK, "phase": "1423", "title": "authorize source-unit route completion", "kind": "enabling", "owner": "PROGRAM", "dependsOn": [CURRENT], "implementationClass": "QUEUE_ONLY", "card": f"docs/tasks/{ROOT_TASK}.md", "commands": [], "status": "done", "ready": False, "queueMutationAllowed": True}
task_record = {"id": TASK, "phase": "1423", "title": "complete source-unit route completion", "kind": "product-module", "owner": "WEB_PRODUCT", "dependsOn": [ROOT_TASK], "implementationClass": "PRODUCT_WORKFLOW", "card": f"docs/tasks/{TASK}.md", "commands": ["python3 my-tools/run_web_product_migration.py"], "status": "in_progress", "ready": True, "queueMutationAllowed": True, "productBacklog": "tests/golden/WBV2/web-product-backlog.json", "module": {"sourcePaths": list(dict.fromkeys(path for item in TASKS for path in item["ownedPaths"]))}}
write_json(plan_path, {**base_plan, "planId": "BLENDER_WEB_ROUTE_COMPLETION_P1423", "status": "ACTIVE_ROUTE_COMPLETION", "tasks": [*base_plan.get("tasks", []), root_record, task_record]})
write_text(ROOT / "docs/tasks" / f"{ROOT_TASK}.md", f"# {ROOT_TASK}: authorize source-unit route completion\n\n- task: {ROOT_TASK}\n- parent: {CURRENT}\n- status: done\n- nextTask: {TASK}\n- route catalog: `web/app/src/capabilities/blender-feature-route-catalog.json`\n")
write_text(ROOT / "docs/tasks" / f"{TASK}.md", f"""# {TASK}: complete source-unit route completion
- task: {TASK}
- parent: {ROOT_TASK}
- status: in_progress
- targetImplementationClass: PRODUCT_WORKFLOW
- implementation entrypoint: `python3 my-tools/run_web_product_migration.py`
- node tools/web/print-task-context.mjs
- route catalog: `web/app/src/capabilities/blender-feature-route-catalog.json`
## 目标
Complete execution routes for every classified Blender source unit. WEB_MAIN uses typed Main/WASM, SERVER_NATIVE uses bounded background Blender jobs, BROWSER_EQUIVALENT uses browser workflows, and UNAVAILABLE remains explicit.
## 输入与范围
- `docs/WEB_FULL_FEATURE_GAP_INVENTORY.md`
- `web/app/src/capabilities/blender-feature-route-catalog.json`
- pending tasks in `tests/golden/WBV2/web-product-backlog.json`
- each task's owned source/protocol/Worker/UI paths
## 验收
- every route is typed, bounded and source-backed
- no JavaScript simulation replaces Blender Main or a declared server job
- browser-only context is represented by an explicit equivalent route
- verification remains incremental and deferred to user operation
## 失败边界
- unsupported context, unsafe RNA pointer, missing server capability or malformed job fails closed
- failed turns remain pending and are retried
- route catalog never marks behavioral verification as complete by classification alone
## 交付与回滚
- result artifacts: `tests/golden/WBV2/product-migration/*-result.json`
- aggregate report: `tests/golden/{TASK}/product-implementation-report.json`
- rollback: stop the product runner and retain the last completed route task
""")
root_report = root_dir / "operator-route-authorization.json"
write_json(root_report, {"schemaVersion": 1, "task": ROOT_TASK, "operation": "AUTHORIZE_SOURCE_UNIT_ROUTE_COMPLETION", "status": "PASS", "routeCatalog": "web/app/src/capabilities/blender-feature-route-catalog.json", "pendingTaskCount": len(TASKS), "nextTask": TASK})
root_status = ROOT / "docs/status" / f"{ROOT_TASK}.md"
write_text(root_status, f"# {ROOT_TASK} status\n\n- status: `done`\n- nextTask: `{TASK}`\n- route catalog: `web/app/src/capabilities/blender-feature-route-catalog.json`\n")
root_manifest = root_dir / "manifest.json"
write_json(root_manifest, {"schemaVersion": 1, "task": ROOT_TASK, "parentTask": CURRENT, "operation": "AUTHORIZE_SOURCE_UNIT_ROUTE_COMPLETION", "status": "done", "nextTask": TASK, "artifacts": {"parentManifest": {"path": f"tests/golden/{CURRENT}/manifest.json", "sha256": sha(current_manifest_path)}, "backlog": {"path": str(backlog_path.relative_to(ROOT)), "sha256": sha(backlog_path)}, "plan": {"path": str(plan_path.relative_to(ROOT)), "sha256": sha(plan_path)}, "routeCatalog": {"path": "web/app/src/capabilities/blender-feature-route-catalog.json", "sha256": sha(ROOT / "web/app/src/capabilities/blender-feature-route-catalog.json")}}})
queue = QUEUE.read_text(encoding="utf-8")
queue = re.sub(r"\| 当前任务 \| `[^`]+` \|", f"| 当前任务 | `{TASK}` |", queue, count=1)
queue = re.sub(r"\| parent manifest \| `[^`]+` \|", f"| parent manifest | `tests/golden/{ROOT_TASK}/manifest.json` |", queue, count=1, flags=re.IGNORECASE)
queue = re.sub(r"\| 任务卡 \| \[[^\]]+\]\([^\)]+\) \|", f"| 任务卡 | [`tasks/{TASK}.md`](tasks/{TASK}.md) |", queue, count=1)
write_text(QUEUE, queue)
subprocess.run(["node", "tools/web/generate-v2-task-index.mjs", "--plan-path", str(plan_path.relative_to(ROOT))], cwd=ROOT, check=True)
subprocess.run(["node", "tools/web/check-task-context.mjs", "--task", TASK, "--write"], cwd=ROOT, check=True)
print(f"operator-route-phase-activated task={TASK} pending={len(TASKS)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())