#!/usr/bin/env python3 """Register the existing native NLA Timeline workflow for local acceptance.""" import copy import json from wbv2_autopilot import Autopilot, ROOT, contained, queue_context, read_json, write_json def main(): runner = Autopilot() context = queue_context(ROOT) identifier = "WEBUI-NLA-STRIP" job = next(job for job in runner.jobs(context) if job["id"] == identifier) base = read_json(runner.directory / "local-plans/SERVER-OPERATOR-HTTP-PROVIDER.json") if base["task"] != context["task"] or base["parentSha256"] != context["parentSha256"]: raise ValueError("existing build contract is not bound to the current task") build = copy.deepcopy(next(check for check in base["result"]["checks"] if check["id"] == "wasm-source-build")) web = copy.deepcopy(next(check for check in base["result"]["checks"] if check["id"] == "web-build")) behavior = ["positive", "negative", "undo_redo", "save_reopen", "determinism"] source_references = [ "blender-5.2.0/source/blender/makesrna/intern/rna_nla.cc", "blender-5.2.0/source/blender/web_engine/web_engine_api.cpp", "blender-5.2.0/source/blender/web_engine/web_engine_main_state.cpp", ] test = "web/tests/e2e/nla-strip-ui-production.spec.ts" fixture_reader = "web/tests/fixtures/nla-main-snapshots.py" fixture = "tests/files/web/nla_time_mapping_scene.blend" result = { "status": "ready", "summary": "Existing native NLA strip movement with Timeline UI and fresh native Main acceptance receipts", "workflow": "Select an NLA track and strip, edit frame start, reject overlapping strips, undo/redo and save/reopen the native Main", "sourceUnits": ["rna-struct:NlaStrip"], "routeIds": ["rna-struct:NlaStrip"], "sourceReferences": source_references, "changedFiles": [test, fixture_reader], "dependencies": sorted(set(job["ownedPaths"] + source_references + [ test, fixture_reader, fixture, "web/app/src/engine-client/WebEngineClient.ts", "web/app/src/workers/web-engine.worker.ts", "web/app/src/capabilities/blender-feature-route-catalog.json", "web/protocol/web-engine.ts", "web/protocol/scene-ir.ts", "web/app/vite.config.ts", "web/playwright.config.ts", "web/tsconfig.json", "web/package.json", "tools/web/incremental-web-build.mjs", "tools/web/run-incremental-typecheck.mjs", "tools/web/web-build-fingerprint.mjs", "build_web_blender6/CMakeCache.txt", ".emscripten-web", "my-tools/prepare_wbv2_nla_workflow.py", ])), "artifacts": ["build_blender_native/bin/blender", "build_web_blender6/bin/web_engine.wasm", "build_web_blender6/bin/web_engine.js", "web/app/public/vendor/blender/web_engine.wasm"], "checks": [build, web, { "id": "nla-ui-lint", "kinds": ["lint"], "argv": ["node", "node_modules/eslint/bin/eslint.js", "app/src/app/App.tsx"], "cwd": "web", "timeoutSeconds": 60, "continueOnFailure": True, }, { "id": "chromium-nla-ui", "kinds": ["chromium", *behavior], "argv": ["env", "BLENDER_BIN=" + str(ROOT / "build_blender_native/bin/blender"), "WEB_TEST_PORT=5337", "node", "node_modules/@playwright/test/cli.js", "test", "--config", "playwright.config.ts", "tests/e2e/nla-strip-ui-production.spec.ts", "--workers=1", "--max-failures=1"], "cwd": "web", "dependsOn": [build["id"], web["id"]], "timeoutSeconds": 120, "continueOnFailure": True, }], "cases": [{"id": "nla-strip-" + kind, "kind": kind, "checkId": "chromium-nla-ui", "receipt": "unallocated/nla-strip-" + kind + ".json", "unitIds": ["rna-struct:NlaStrip"]} for kind in behavior], } for path in result["dependencies"] + result["artifacts"]: if not contained(ROOT, path).is_file(): raise ValueError("required local dependency missing: " + path) probe = runner.directory / "nla-contract-validation" validated = copy.deepcopy(result) for case in validated["cases"]: case["receipt"] = str((probe / "cases" / (case["id"] + ".json")).relative_to(ROOT)) runner.validate_result(validated, probe) contract = {"schemaVersion": 1, "task": context["task"], "job": identifier, "parentSha256": context["parentSha256"], "acceptance": "pending native Main and Chromium validation", "result": result} destination = ROOT / "my-tools/local-workflows" / (identifier + ".json") write_json(destination, contract) print(json.dumps({"job": identifier, "contract": str(destination.relative_to(ROOT)), "checks": len(result["checks"]), "modelRequests": 0})) if __name__ == "__main__": main()