#!/usr/bin/env python3 """Regression tests for scheduler optimizations that must preserve gate behavior.""" from __future__ import annotations import importlib.util import contextlib import io import json import os import sys import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT / "tools")) def load_module(name: str, relative: str): spec = importlib.util.spec_from_file_location(name, ROOT / relative) if spec is None or spec.loader is None: raise RuntimeError(relative) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module packet = load_module("implementation_packet", "tools/prepare_module_implementation_packet.py") pipeline = load_module("module_pipeline", "tools/run_module_batch_pipeline.py") deferred_flush = load_module("deferred_build_flush", "tools/flush_deferred_module_builds.py") planner = load_module("module_planner", "tools/prepare_full_parity_module_batch.py") scheduler = load_module("scheduler", "tools/run_freecad_web_scheduler.py") preflight = load_module("batch_preflight", "tools/preflight_current_module_batch.py") feature_planner = load_module("feature_planner", "tools/prepare_feature_capability_batch.py") capability_generator = load_module("capability_generator", "tools/generate_feature_capability_registry.py") implementation_first = load_module("implementation_first_state", "tools/implementation_first.py") continuation = load_module("continuation", "tools/continue_web_task_cycle.py") class GateSelectionTests(unittest.TestCase): def assert_gate(self, module: str, tier: str, family: str, expected: str) -> None: slug = "".join(value for value in module.lower() if value.isalnum()) selected = packet.select_module_gate(module, slug, tier, family) self.assertIsNotNone(selected) self.assertEqual(selected.name, expected) def test_draft_generic_gate(self) -> None: self.assert_gate("Draft", "tier-3-stateful", "document-graph", "run_p6_draft_module_batch_gate.mjs") def test_material_nonstandard_gate_name(self) -> None: for family in ("generic-object", "property", "serialization"): self.assert_gate("Material", "tier-3-stateful", family, "run_p6_material_object_module_batch_gate.mjs") def test_selector_rejects_incompatible_mesh_object_gate(self) -> None: self.assertIsNone(packet.select_module_gate("Mesh", "mesh", "tier-2-pure", "pure-function")) def test_feature_batch_selects_split_desktop_target(self) -> None: hint = packet.build_hint("Part", packet.probe_sources("Part"), "feature-workflow", "desktop-command-command") self.assertEqual(hint.get("target"), "FreeCADWebPartDesktopCommandProbe") def test_mesh_desktop_batch_prefers_runtime_target(self) -> None: hint = packet.build_hint("Mesh", packet.probe_sources("Mesh"), "feature-workflow", "desktop-command-command") self.assertEqual(hint.get("target"), "FreeCADWebMeshRuntimeProbe") def test_packet_derives_configured_build_tree_before_first_artifact(self) -> None: hint = packet.build_hint("MeshPart", packet.probe_sources("MeshPart"), "feature-workflow", "desktop-command-mixed") self.assertEqual(hint.get("target"), "FreeCADWebMeshPartRuntimeProbe") self.assertEqual(hint.get("tree"), "freecad-source/build-web/configure") self.assertTrue(hint.get("runtime", "").endswith("FreeCADWebMeshPartRuntimeProbe.js")) class BuildReuseTests(unittest.TestCase): def test_deferred_build_flush_syncs_before_receipt(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) (root / "build/bin").mkdir(parents=True) previous = ( deferred_flush.ROOT, deferred_flush.PENDING_PATH, deferred_flush.OUTPUT_PATH, deferred_flush.run, deferred_flush.record_implementation_batch, ) calls: list[str] = [] def fake_run(command: list[str], _timeout: int) -> dict[str, object]: if command[0] == "cmake": (root / "build/bin/target.js").write_text("js", encoding="ascii") (root / "build/bin/target.wasm").write_bytes(b"wasm") calls.append("build") elif command[0] == "node": calls.append("sync") elif command[-1].endswith("generate_web_business_completion_audit.py"): calls.append("audit") else: calls.append("preflight") return {"command": command, "seconds": 0.0, "exitCode": 0, "stdout": "", "stderr": ""} def fake_receipt(*_args: object, **_kwargs: object) -> dict[str, object]: calls.append("receipt") return {} try: deferred_flush.ROOT = root deferred_flush.PENDING_PATH = root / "pending.json" deferred_flush.OUTPUT_PATH = root / "report.json" deferred_flush.run = fake_run deferred_flush.record_implementation_batch = fake_receipt deferred_flush.PENDING_PATH.write_text(json.dumps({ "schema": "freecad-web-module-build-pending/v1", "targets": {"build:target": [{"batchId": "b1"}]}, }), encoding="utf-8") with contextlib.redirect_stdout(io.StringIO()): self.assertEqual(deferred_flush.main([]), 0) self.assertEqual(calls, ["preflight", "build", "sync", "receipt", "audit"]) state = json.loads(deferred_flush.PENDING_PATH.read_text(encoding="utf-8")) self.assertEqual(state["targets"], {}) finally: ( deferred_flush.ROOT, deferred_flush.PENDING_PATH, deferred_flush.OUTPUT_PATH, deferred_flush.run, deferred_flush.record_implementation_batch, ) = previous def test_deferred_build_flush_honors_retry_backoff_without_subprocess(self) -> None: with tempfile.TemporaryDirectory() as directory: previous_pending = deferred_flush.PENDING_PATH previous_output = deferred_flush.OUTPUT_PATH previous_run = deferred_flush.run try: deferred_flush.PENDING_PATH = Path(directory) / "pending.json" deferred_flush.OUTPUT_PATH = Path(directory) / "report.json" deferred_flush.PENDING_PATH.write_text(json.dumps({ "schema": "freecad-web-module-build-pending/v1", "targets": {"build:target": [{"batchId": "b1", "nextAttemptAt": 32503680000}]}, }), encoding="utf-8") deferred_flush.run = lambda *_args, **_kwargs: self.fail("backoff target launched a subprocess") with contextlib.redirect_stdout(io.StringIO()): self.assertEqual(deferred_flush.main([]), 0) report = json.loads(deferred_flush.OUTPUT_PATH.read_text(encoding="utf-8")) self.assertEqual(report["status"], "retry_backoff") self.assertEqual(report["skippedTargets"], 1) finally: deferred_flush.PENDING_PATH = previous_pending deferred_flush.OUTPUT_PATH = previous_output deferred_flush.run = previous_run def test_scheduler_flushes_deferred_builds_before_idle(self) -> None: source = (ROOT / "tools/run_freecad_web_scheduler.py").read_text(encoding="utf-8") flush = source.index('run_local("tools/flush_deferred_module_builds.py", "--json")') wait = source.index('status="waiting_for_batch"', flush) self.assertLess(flush, wait) def test_feature_link_batching_only_defers_when_same_family_remains(self) -> None: batch = { "selected": {"module": "Sketcher", "family": "desktop-command-command", "recordCount": 16}, "queue": [{"module": "Sketcher", "family": "desktop-command-command", "unresolved": 30}], } self.assertTrue(pipeline.feature_has_more_same_family(batch)) self.assertTrue(pipeline.should_defer_feature_build(batch, implementation_first=True, pending_count=0, artifacts_exist=True)) self.assertFalse(pipeline.should_defer_feature_build(batch, implementation_first=True, pending_count=1, artifacts_exist=True)) self.assertFalse(pipeline.should_defer_feature_build(batch, implementation_first=True, pending_count=0, artifacts_exist=False)) batch["selected"]["family"] = "runtime-issue" self.assertFalse(pipeline.should_defer_feature_build(batch, implementation_first=True, pending_count=0, artifacts_exist=True)) batch["selected"]["family"] = "desktop-command-command" batch["queue"][0]["unresolved"] = 16 self.assertFalse(pipeline.feature_has_more_same_family(batch)) def test_pending_build_state_round_trips(self) -> None: with tempfile.TemporaryDirectory() as directory: previous = pipeline.PENDING_BUILD_PATH try: pipeline.PENDING_BUILD_PATH = Path(directory) / "pending.json" state = {"schema": "freecad-web-module-build-pending/v1", "targets": {"tree:target": [{"batchId": "b1"}]}} pipeline.save_pending_builds(state) self.assertEqual(pipeline.load_pending_builds()["targets"]["tree:target"][0]["batchId"], "b1") finally: pipeline.PENDING_BUILD_PATH = previous def test_pending_build_status_advances_planner_without_closing_runtime_issue(self) -> None: source = (ROOT / "tools/implementation_first.py").read_text(encoding="utf-8") self.assertIn('"implementation_pending_build"', source) self.assertIn('status == "implementation_ready"', source) def test_file_signature_reuses_metadata_but_detects_content_change(self) -> None: with tempfile.TemporaryDirectory(dir=ROOT / "docs/current") as directory: path = Path(directory) / "input.txt" path.write_text("same", encoding="ascii") first, first_hit = pipeline.file_signature(path) second, second_hit = pipeline.file_signature(path, first) self.assertFalse(first_hit) self.assertTrue(second_hit) self.assertEqual(first["sha256"], second["sha256"]) path.write_text("diff", encoding="ascii") os.utime(path, ns=(int(first["mtimeNs"]) + 1, int(first["mtimeNs"]) + 1)) changed, changed_hit = pipeline.file_signature(path, first) self.assertFalse(changed_hit) self.assertNotEqual(first["sha256"], changed["sha256"]) def test_failed_step_compaction_preserves_error_tail(self) -> None: value = "configure\n" + ("noise\n" * 1000) + "fatal compiler error" compacted = pipeline.compact(value, 400, preserve_tail=True) self.assertIn("configure", compacted) self.assertIn("fatal compiler error", compacted) self.assertIn("failure tail follows", compacted) def test_draft_direct_link_closure_is_tracked(self) -> None: tree = ROOT / "freecad-source/build-web/configure" dependencies = pipeline.direct_link_dependencies(tree, "FreeCADWebDraftRuntimeProbe") self.assertGreaterEqual(len(dependencies), 40) self.assertTrue(all(path.suffix == ".a" and path.is_file() for path in dependencies)) def test_part_desktop_cache_tracks_only_target_sources(self) -> None: tree = ROOT / "freecad-source/build-web/configure" sources = pipeline.target_source_dependencies(tree, "FreeCADWebPartDesktopCommandProbe") names = {path.name for path in sources} self.assertTrue({"PartDesktopCommandProbe.cpp", "PartDesktopCommands.cpp"}.issubset(names)) self.assertNotIn("PartBoxProbe.cpp", names) def test_incomplete_feature_batch_is_not_build_ready(self) -> None: batch = {"records": [["Part:desktop:A"], ["Part:desktop:B"]]} capabilities = {"records": [ {"id": "Part:desktop:A", "implementationStatus": "routed"}, {"id": "Part:desktop:B", "implementationStatus": "implementation_required"}, ]} readiness = pipeline.static_readiness(batch, capabilities) self.assertEqual(readiness["ready"], 1) self.assertEqual(readiness["missingIds"], ["Part:desktop:B"]) def test_rejected_native_marker_reason_reaches_static_readiness(self) -> None: batch = { "selected": {"module": "Mesh"}, "records": [["Mesh:desktop:A", "A"], ["Mesh:desktop:B", "B"]], } capabilities = { "records": [ {"id": "Mesh:desktop:A", "implementationStatus": "implementation_required"}, {"id": "Mesh:desktop:B", "implementationStatus": "implementation_required"}, ], "diagnostics": { "rejectedDesktopMarkers": {"Mesh": ["A"]}, "rejectedMarkerReason": "requires command-specific exposed branch", }, } readiness = pipeline.static_readiness(batch, capabilities) self.assertEqual(readiness["rejectedMarkers"], [{ "id": "Mesh:desktop:A", "command": "A", "reason": "requires command-specific exposed branch", }]) def test_pipeline_allows_real_partial_batch_but_does_not_defer_its_build(self) -> None: source = (ROOT / "tools/run_module_batch_pipeline.py").read_text(encoding="utf-8") self.assertIn('readiness["missing"] and not readiness["ready"]', source) self.assertIn('and not readiness.get("missing")', source) class DesktopCommandArchitectureTests(unittest.TestCase): def test_probe_module_resolution_uses_canonical_longest_prefix(self) -> None: known = {"Fem", "Mesh", "MeshPart", "Part", "PartDesign"} self.assertEqual(capability_generator.canonical_probe_module("FemGenericFamilyProbe", known), "Fem") self.assertEqual(capability_generator.canonical_probe_module("MeshPartRuntimeProbe", known), "MeshPart") self.assertEqual(capability_generator.canonical_probe_module("PartDesignRuntimeProbe", known), "PartDesign") def test_implemented_marker_requires_command_specific_exposed_branch(self) -> None: source = ''' FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("Real") FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("First") FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("QtStyle") FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("CommandVariable") FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("Combined") FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("Boundary") FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("GenericOnly") if (FC_WEB_DESKTOP_COMMAND("Real")) { result.insert("status", "not_implemented"); } if (FC_WEB_DESKTOP_COMMAND("First")) { result.insert("status", "exposed"); } else if (name == QStringLiteral("QtStyle")) { result.insert(QStringLiteral("status"), QStringLiteral("exposed")); } else if (command == QStringLiteral("CommandVariable")) { result.insert(QStringLiteral("status"), QStringLiteral("exposed")); } else if (commandName == QStringLiteral("Combined") || commandName == QStringLiteral("Sibling")) { result.insert(QStringLiteral("status"), QStringLiteral("exposed")); } else if (FC_WEB_DESKTOP_COMMAND("Real")) { result.insert("status", "exposed"); } else if (FC_WEB_DESKTOP_COMMAND("Boundary")) { result.insert("status", "not_implemented"); } ''' self.assertEqual(capability_generator.implemented_desktop_commands(source), {"Combined", "CommandVariable", "First", "QtStyle", "Real"}) def test_part_desktop_commands_are_parameter_driven_and_split(self) -> None: workbench = (ROOT / "web/src/workbench-shell.tsx").read_text(encoding="utf-8") dispatcher = (ROOT / "web/src/desktop-command-dispatcher.ts").read_text(encoding="utf-8") cmake = (ROOT / "freecad-source/src/WebAssembly/FreeCADCoreProbe/CMakeLists.txt").read_text(encoding="utf-8") native = (ROOT / "freecad-source/src/WebAssembly/FreeCADCoreProbe/PartDesktopCommands.cpp").read_text(encoding="utf-8") sync = (ROOT / "web/tools/sync-assets.mjs").read_text(encoding="utf-8") self.assertNotIn('"ShapeA"', workbench) self.assertNotIn('"ShapeB"', workbench) self.assertIn("DesktopCommandDispatcher", workbench) self.assertIn("record.sourcePath", dispatcher) self.assertIn("PartDesktopCommands.cpp", cmake) self.assertIn("args.shapes", native) self.assertIn("FC_WEB_DESKTOP_COMMAND", native) self.assertIn("FreeCADWeb[A-Za-z0-9]+DesktopCommandProbe", sync) def test_desktop_routes_are_generated_from_native_ownership(self) -> None: routes = json.loads((ROOT / "web/public/api/desktop-command-routes.json").read_text(encoding="utf-8")) by_id = {row["id"]: row for row in routes["records"]} self.assertEqual(by_id["PartDesign:desktop:PartDesign_AdditiveHelix"]["transport"], "direct-command") self.assertEqual(by_id["PartDesign:desktop:PartDesign_AdditiveHelix"]["worker"], "partdesign-python.worker.ts") self.assertEqual(by_id["Part:desktop:Boolean"]["transport"], "ui-container") self.assertEqual(by_id["Part:desktop:Part_ColorPerFace"]["transport"], "family-batch") self.assertEqual(by_id["Sketcher:desktop:Sketcher_CarbonCopy"]["module"], "Sketcher") self.assertNotIn("PARTDESIGN_DESKTOP_DEFAULT_ARGS", (ROOT / "web/src/workbench-shell.tsx").read_text(encoding="utf-8")) def test_registry_generator_has_no_module_specific_desktop_branch(self) -> None: source = (ROOT / "tools/generate_web_module_registry.py").read_text(encoding="utf-8") self.assertNotIn('if module == "PartDesign"', source) self.assertIn("native_desktop_commands(module)", source) def test_feature_registry_scans_implemented_markers_in_split_adapter(self) -> None: source = (ROOT / "tools/generate_feature_capability_registry.py").read_text(encoding="utf-8") desktop_loop = source[source.index('glob("*DesktopCommands.cpp")'):source.index('glob("*Probe.cpp")')] self.assertIn("implemented_desktop_commands(text)", desktop_loop) def test_feature_registry_scans_implemented_markers_in_inventory_api(self) -> None: source = (ROOT / "tools/generate_feature_capability_registry.py").read_text(encoding="utf-8") self.assertIn('glob("*InventoryApi.cpp")', source) inventory = (ROOT / "freecad-source/src/WebAssembly/FreeCADCoreProbe/RobotInventoryApi.cpp").read_text(encoding="utf-8") self.assertTrue( { "Robot_CreateTrajectory", "Robot_Edge2Trac", "Robot_InsertWaypoint", "Robot_InsertWaypointPreselect", }.issubset(capability_generator.implemented_desktop_commands(inventory)) ) def test_implemented_marker_accepts_desktop_name_branch(self) -> None: source = ''' if (desktopName == QStringLiteral("MeshPart_Mesher")) { FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("MeshPart_Mesher"); result.insert(QStringLiteral("status"), QStringLiteral("exposed")); } ''' self.assertEqual( capability_generator.implemented_desktop_commands(source), {"MeshPart_Mesher"}, ) def test_implemented_marker_accepts_record_status_object(self) -> None: source = ''' if (name == QStringLiteral("TemplatePyMod_Cmd1")) { FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("TemplatePyMod_Cmd1"); record.insert(QStringLiteral("status"), QStringLiteral("exposed")); } ''' self.assertEqual( capability_generator.implemented_desktop_commands(source), {"TemplatePyMod_Cmd1"}, ) def test_implemented_marker_accepts_start_ostringstream_status(self) -> None: source = (ROOT / "freecad-source/src/WebAssembly/FreeCADCoreProbe/StartRuntimeProbe.cpp").read_text(encoding="utf-8") self.assertIn("Start_Start", capability_generator.implemented_desktop_commands(source)) def test_implemented_marker_accepts_command_specific_native_execution_helper(self) -> None: source = ''' #define FC_WEB_IMPLEMENTED_DESKTOP_COMMAND(name) FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("FEM_Analysis") if (command == QStringLiteral("FEM_Analysis")) { return executeObjectCommand(command, QStringLiteral("Fem::FemAnalysis"), args, result); } ''' self.assertEqual(capability_generator.implemented_desktop_commands(source), {"FEM_Analysis"}) def test_implemented_marker_accepts_single_statement_native_execution_helper(self) -> None: source = ''' #define FC_WEB_IMPLEMENTED_DESKTOP_COMMAND(name) FC_WEB_IMPLEMENTED_DESKTOP_COMMAND("FEM_SolverZ88") if (command == QStringLiteral("FEM_SolverZ88")) return executeObjectCommand(command, QStringLiteral("Fem::FemSolverObject"), args, result); ''' self.assertEqual(capability_generator.implemented_desktop_commands(source), {"FEM_SolverZ88"}) def test_start_direct_worker_synthesizes_route_without_duplicate_registry_entry(self) -> None: source = (ROOT / "tools/generate_feature_capability_registry.py").read_text(encoding="utf-8") self.assertIn('if exact is None and module not in desktop_adapter_modules:', source) self.assertIn('"uiStatus": "generic-command-entry"', source) routes = json.loads((ROOT / "web/public/api/desktop-command-routes.json").read_text(encoding="utf-8")) start = next((row for row in routes.get("records", []) if row.get("id") == "Start:desktop:Start_Start"), None) if start is not None: self.assertEqual(start.get("transport"), "direct-command") self.assertEqual(start.get("worker"), "start.worker.ts") def test_templatepymod_desktop_contract_includes_final_command(self) -> None: source = (ROOT / "web/src/templatepymod-python-family-facade.ts").read_text(encoding="utf-8") declaration = next(line for line in source.splitlines() if "TEMPLATEPYMOD_DESKTOP_COMMANDS" in line) self.assertIn('"TemplatePyMod_Cmd5"', declaration) def test_workbench_groups_are_ui_containers_but_leaf_commands_are_not(self) -> None: self.assertTrue(capability_generator.is_ui_container({ "command": "Constraints", "sourcePath": "src/Mod/Sketcher/Gui/Workbench.cpp", "sourceLine": 82, })) self.assertTrue(capability_generator.is_ui_container({ "command": "Boolean", "sourcePath": "src/Mod/Part/Gui/Workbench.cpp", "sourceLine": 93, })) self.assertFalse(capability_generator.is_ui_container({ "command": "Part_ColorPerFace", "sourcePath": "src/Mod/Part/Gui/Workbench.cpp", "sourceLine": 165, })) self.assertTrue(capability_generator.is_ui_container({ "command": "BIM_ArcTools", "sourcePath": "src/Mod/BIM/InitGui.py", "sourceLine": 390, })) self.assertTrue(capability_generator.is_ui_container({ "command": "Arch_RebarTools", "sourcePath": "src/Mod/BIM/InitGui.py", "sourceLine": 424, })) def test_desktop_transport_does_not_inflate_business_inventory(self) -> None: registry = json.loads((ROOT / "docs/current/feature-capability-registry.json").read_text(encoding="utf-8")) self.assertFalse(any(row["id"].endswith(".desktopCommand") for row in registry["records"])) def test_implementation_packet_has_multiple_native_edit_anchors(self) -> None: path = ROOT / "freecad-source/src/WebAssembly/FreeCADCoreProbe/SketcherProbe.cpp" regions = packet.editable_excerpts(path, path.read_text(encoding="utf-8"), ["command-not-yet-registered"]) roles = {row["role"] for row in regions} self.assertIn("desktop-handler", roles) self.assertIn("command-registration", roles) self.assertIn("unified-dispatch", roles) def test_feature_packet_focuses_native_edits_on_dispatch_owner(self) -> None: source = (ROOT / "tools/prepare_module_implementation_packet.py").read_text(encoding="utf-8") self.assertIn("unified_dispatch_paths", source) self.assertIn("path not in unified_dispatch_paths", source) packet_payload = json.loads((ROOT / "docs/current/module-implementation-packet.json").read_text(encoding="utf-8")) if packet_payload.get("module") == "Surface" and packet_payload.get("family", "").startswith("desktop-command"): omitted = set(packet_payload.get("omittedStableSupport", [])) self.assertIn("freecad-source/src/WebAssembly/FreeCADCoreProbe/SurfaceRuntimeProbe.cpp", omitted) def test_module_without_desktop_handler_keeps_family_or_abi_anchor(self) -> None: path = ROOT / "freecad-source/src/WebAssembly/FreeCADCoreProbe/AssemblyRuntimeProbe.cpp" regions = packet.editable_excerpts(path, path.read_text(encoding="utf-8"), ["Assembly_CommandNotRegistered"]) roles = {row["role"] for row in regions} self.assertTrue(roles & {"family-record-handler", "family-dispatch", "unified-dispatch"}) def test_probe_discovery_is_case_insensitive_for_bim(self) -> None: self.assertIn("BimRuntimeProbe.cpp", {path.name for path in packet.probe_sources("BIM")}) def test_probe_discovery_includes_suffixed_robot_native_units(self) -> None: names = {path.name for path in packet.probe_sources("Robot")} self.assertIn("RobotRuntimeProbeFixed.cpp", names) self.assertIn("RobotInventoryApi.cpp", names) def test_cpp_command_excerpt_resolves_activated_semantics(self) -> None: path = ROOT / "freecad-source/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp" line, excerpt = packet.cpp_command_excerpt(path, "Sketcher_BSplineConvertToNURBS", 112) self.assertGreater(line, 112) self.assertIn("CmdSketcherConvertToNURBS::activated", excerpt) self.assertIn("convertToNURBS", excerpt) class BatchPreflightTests(unittest.TestCase): def test_feature_batch_uses_feature_identity_and_ids(self) -> None: batch = { "schema": preflight.FEATURE_SCHEMA, "strategy": "feature-first-deferred-validation", } ids = ["Sketcher:desktop:Sketcher_EditSketch"] self.assertEqual( preflight.batch_identity_parts(batch, "Sketcher", "feature-workflow", "desktop-command-command", ids), ["Sketcher", "desktop-command-command", *ids], ) self.assertTrue(preflight.record_belongs_to_batch(batch, "Sketcher", ids[0])) def test_legacy_batch_retains_tier_and_prefixed_ids(self) -> None: batch = {"schema": "freecad-web-module-batch/v1"} ids = ["py:Draft:Vector.add"] self.assertEqual( preflight.batch_identity_parts(batch, "Draft", "tier-2-pure", "geometry-value", ids), ["Draft", "tier-2-pure", "geometry-value", *ids], ) self.assertTrue(preflight.record_belongs_to_batch(batch, "Draft", ids[0])) self.assertFalse(preflight.record_belongs_to_batch(batch, "Part", ids[0])) class AdaptiveBatchTests(unittest.TestCase): def test_routed_record_without_receipt_remains_schedulable(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) previous = ( feature_planner.REGISTRY, feature_planner.ISSUES, feature_planner.STATE, feature_planner.OUTPUT, feature_planner.PIPELINE, feature_planner.capability_source_fingerprint, feature_planner.implementation_ready_ids, ) try: feature_planner.REGISTRY = root / "capabilities.json" feature_planner.ISSUES = root / "issues.json" feature_planner.STATE = root / "state.json" feature_planner.OUTPUT = root / "batch.json" feature_planner.PIPELINE = root / "pipeline.json" feature_planner.capability_source_fingerprint = lambda: "fingerprint" feature_planner.implementation_ready_ids = lambda: set() feature_planner.REGISTRY.write_text(json.dumps({"records": [{ "id": "Start:desktop:Start_Start", "module": "Start", "command": "Start_Start", "implementationStatus": "routed", "uiStatus": "generic-command-entry", "sourcePath": "src/Mod/Start/Gui/Manipulator.cpp", "sourceLine": 42, }]}), encoding="utf-8") feature_planner.ISSUES.write_text('{"issues":[]}', encoding="utf-8") feature_planner.STATE.write_text('{"active_task":"FW-P6-FPA-Y"}', encoding="utf-8") with contextlib.redirect_stdout(io.StringIO()): self.assertEqual(feature_planner.main(), 0) batch = json.loads(feature_planner.OUTPUT.read_text(encoding="utf-8")) self.assertEqual(batch["status"], "ready") self.assertEqual(batch["records"][0][0], "Start:desktop:Start_Start") finally: ( feature_planner.REGISTRY, feature_planner.ISSUES, feature_planner.STATE, feature_planner.OUTPUT, feature_planner.PIPELINE, feature_planner.capability_source_fingerprint, feature_planner.implementation_ready_ids, ) = previous def test_feature_batch_size_is_bounded_and_runtime_issues_stay_small(self) -> None: self.assertGreater(feature_planner.FEATURE_BATCH_SIZE, 8) self.assertLessEqual(feature_planner.FEATURE_BATCH_SIZE, 32) self.assertLessEqual(feature_planner.RUNTIME_ISSUE_BATCH_SIZE, feature_planner.FEATURE_BATCH_SIZE) def test_small_desktop_families_are_packed_within_one_module(self) -> None: ordered = [ (("Sketcher", "desktop-command-a"), [{"id": "a1"}]), (("Sketcher", "desktop-command-b"), [{"id": "b1"}, {"id": "b2"}]), (("TechDraw", "desktop-command-c"), [{"id": "c1"}]), ] module, family, rows, source_families = feature_planner.select_group_batch(ordered) self.assertEqual(module, "Sketcher") self.assertEqual(family, "desktop-command-mixed") self.assertEqual([row["id"] for row in rows], ["a1", "b1", "b2"]) self.assertEqual(source_families, ["desktop-command-a", "desktop-command-b"]) def test_mixed_feature_batch_caps_heterogeneous_records(self) -> None: ordered = [ (("CAM", "desktop-command-a"), [{"id": f"a{index}"} for index in range(4)]), (("CAM", "desktop-command-b"), [{"id": f"b{index}"} for index in range(8)]), ] module, family, rows, source_families = feature_planner.select_group_batch(ordered) self.assertEqual(module, "CAM") self.assertEqual(family, "desktop-command-mixed") self.assertEqual(len(rows), feature_planner.MIXED_FEATURE_BATCH_SIZE) self.assertEqual(source_families, ["desktop-command-a", "desktop-command-b"]) def test_runtime_issue_batch_is_never_mixed(self) -> None: ordered = [ (("Part", "runtime-issue"), [{"id": "issue"}]), (("Part", "desktop-command-a"), [{"id": "a1"}]), ] _, family, rows, source_families = feature_planner.select_group_batch(ordered) self.assertEqual(family, "runtime-issue") self.assertEqual([row["id"] for row in rows], ["issue"]) self.assertEqual(source_families, ["runtime-issue"]) def test_feature_batch_deduplicates_records_at_final_boundary(self) -> None: ordered = [ (("Part", "runtime-issue"), [{"id": "same"}, {"id": "same"}, {"id": "first"}]), (("Part", "desktop-command-a"), [{"id": "same"}, {"id": "second"}]), ] _, family, rows, _ = feature_planner.select_group_batch(ordered, 4) self.assertEqual(family, "runtime-issue") self.assertEqual([row["id"] for row in rows], ["same", "first"]) def test_stalled_zero_ready_feature_batch_shrinks_to_four(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) previous_output = feature_planner.OUTPUT previous_pipeline = feature_planner.PIPELINE previous_continuation_pipeline = continuation.MODULE_PIPELINE previous_override = os.environ.get("FREECAD_IMPLEMENTATION_FIRST") try: feature_planner.OUTPUT = root / "batch.json" feature_planner.PIPELINE = root / "pipeline.json" continuation.MODULE_PIPELINE = feature_planner.PIPELINE os.environ["FREECAD_IMPLEMENTATION_FIRST"] = "1" old = "2020-01-01T00:00:00+00:00" batch = { "status": "ready", "strategy": "feature-first-deferred-validation", "batchId": "stalled", "generatedAt": old, "selected": {"recordCount": 16}, } pipeline_state = { "status": "implementation_incomplete", "batchId": "stalled", "staticReadiness": {"ready": 0, "missing": 16}, } feature_planner.OUTPUT.write_text(json.dumps(batch), encoding="utf-8") feature_planner.PIPELINE.write_text(json.dumps(pipeline_state), encoding="utf-8") self.assertEqual(feature_planner.stalled_batch_limit(), 4) self.assertEqual(continuation.feature_batch_replan_size(batch), 4) ordered = [(('Mesh', 'desktop-command-command'), [{"id": str(index)} for index in range(16)])] self.assertEqual(len(feature_planner.select_group_batch(ordered, 4)[2]), 4) pipeline_state["staticReadiness"]["ready"] = 1 feature_planner.PIPELINE.write_text(json.dumps(pipeline_state), encoding="utf-8") self.assertIsNone(feature_planner.stalled_batch_limit()) self.assertIsNone(continuation.feature_batch_replan_size(batch)) finally: feature_planner.OUTPUT = previous_output feature_planner.PIPELINE = previous_pipeline continuation.MODULE_PIPELINE = previous_continuation_pipeline if previous_override is None: os.environ.pop("FREECAD_IMPLEMENTATION_FIRST", None) else: os.environ["FREECAD_IMPLEMENTATION_FIRST"] = previous_override def test_existing_oversized_mixed_batch_replans_immediately(self) -> None: previous_override = os.environ.get("FREECAD_IMPLEMENTATION_FIRST") try: os.environ["FREECAD_IMPLEMENTATION_FIRST"] = "1" batch = { "status": "ready", "strategy": "feature-first-deferred-validation", "selected": {"family": "desktop-command-mixed", "recordCount": 16}, } self.assertEqual(continuation.feature_batch_replan_size(batch), continuation.MIXED_FEATURE_BATCH_SIZE) finally: if previous_override is None: os.environ.pop("FREECAD_IMPLEMENTATION_FIRST", None) else: os.environ["FREECAD_IMPLEMENTATION_FIRST"] = previous_override def setUp(self) -> None: self.directory = tempfile.TemporaryDirectory() planner.SCHEDULER_TIMING = Path(self.directory.name) / "timing.json" planner.SCHEDULER_STATUS = Path(self.directory.name) / "status.json" planner.SCHEDULER_STATUS.write_text("{}", encoding="ascii") def tearDown(self) -> None: self.directory.cleanup() def write_samples(self, durations: list[int], failed: bool = False) -> None: planner.SCHEDULER_TIMING.write_text(json.dumps({"cycles": [ {"effectiveCycleSeconds": duration, "batch": {"module": "Draft", "tier": "tier-2-pure", "family": "geometry-value", "records": 24}, "activity": {"commandFailures": 1 if failed and index == 0 else 0}} for index, duration in enumerate(durations) ]}), encoding="utf-8") def test_fast_family_grows_within_cap(self) -> None: self.write_samples([60, 65, 70]) self.assertEqual(planner.adaptive_target_size(None, "tier-2-pure", "Draft", "geometry-value")[0], 32) def test_failure_halves_batch(self) -> None: self.write_samples([100, 110, 120], failed=True) self.assertEqual(planner.adaptive_target_size(None, "tier-2-pure", "Draft", "geometry-value")[0], 12) def test_slow_family_shrinks_gradually(self) -> None: self.write_samples([450, 460, 470]) self.assertEqual(planner.adaptive_target_size(None, "tier-2-pure", "Draft", "geometry-value")[0], 20) class SessionTests(unittest.TestCase): def test_prompt_context_has_a_hard_byte_limit(self) -> None: prompt = "rules\n" + ("source excerpt 数据\n" * 10_000) + "batchId=current-batch\n" compacted = scheduler.bound_prompt_context(prompt, 12_000) self.assertLessEqual(len(compacted.encode("utf-8")), 12_000) self.assertIn("[CONTEXT_COMPACTED by unattended scheduler:", compacted) self.assertIn("batchId=current-batch", compacted) def test_provider_failure_discards_resumed_session(self) -> None: with tempfile.TemporaryDirectory() as directory: previous_path = scheduler.SESSION_CACHE_PATH try: scheduler.SESSION_CACHE_PATH = Path(directory) / "session.json" scheduler.SESSION_CACHE_PATH.write_text(json.dumps({ "module": "Part", "threadId": "old-thread", "lastBatchId": "batch", }), encoding="utf-8") metadata = { "threadId": "old-thread", "streamFailed": True, "providerFailureReason": "servers are currently overloaded", } scheduler.save_session_cache("Part", "batch", metadata, None, False) self.assertFalse(scheduler.SESSION_CACHE_PATH.exists()) self.assertTrue(metadata["contextRotatedAfterProviderFailure"]) finally: scheduler.SESSION_CACHE_PATH = previous_path def test_partial_native_routing_replans_only_remaining_feature_records(self) -> None: with tempfile.TemporaryDirectory() as directory: previous_capability = continuation.CAPABILITY_REGISTRY try: continuation.CAPABILITY_REGISTRY = Path(directory) / "capability.json" continuation.CAPABILITY_REGISTRY.write_text(json.dumps({ "records": [ {"id": "ReverseEngineering:desktop:Implemented", "implementationStatus": "routed"}, {"id": "ReverseEngineering:desktop:Remaining", "implementationStatus": "implementation_required"}, ] }), encoding="utf-8") batch = { "strategy": "feature-first-deferred-validation", "records": [ ["ReverseEngineering:desktop:Implemented", "Implemented"], ["ReverseEngineering:desktop:Remaining", "Remaining"], ], } self.assertEqual( continuation.selected_routed_ids(batch), {"ReverseEngineering:desktop:Implemented"}, ) finally: continuation.CAPABILITY_REGISTRY = previous_capability def test_stale_receipt_is_not_ready_when_capability_route_is_revoked(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) previous_registry = implementation_first.REGISTRY_PATH previous_capability = implementation_first.CAPABILITY_PATH previous_override = os.environ.get("FREECAD_IMPLEMENTATION_FIRST") try: implementation_first.REGISTRY_PATH = root / "registry.json" implementation_first.CAPABILITY_PATH = root / "capability.json" os.environ["FREECAD_IMPLEMENTATION_FIRST"] = "1" implementation_first.REGISTRY_PATH.write_text(json.dumps({ "schema": "freecad-web-implementation-first-registry/v1", "records": { "Mesh:desktop:Real": {"status": "implementation_ready"}, "Mesh:desktop:Revoked": {"status": "implementation_ready"}, }, }), encoding="utf-8") implementation_first.CAPABILITY_PATH.write_text(json.dumps({"records": [ {"id": "Mesh:desktop:Real", "implementationStatus": "routed"}, {"id": "Mesh:desktop:Revoked", "implementationStatus": "implementation_required"}, ]}), encoding="utf-8") self.assertEqual(implementation_first.implementation_ready_ids(), {"Mesh:desktop:Real"}) finally: implementation_first.REGISTRY_PATH = previous_registry implementation_first.CAPABILITY_PATH = previous_capability if previous_override is None: os.environ.pop("FREECAD_IMPLEMENTATION_FIRST", None) else: os.environ["FREECAD_IMPLEMENTATION_FIRST"] = previous_override def test_rg_no_match_is_not_a_scheduler_failure(self) -> None: command = "/bin/bash -lc \"rg -n 'Missing|StillMissing' file.cpp\"" self.assertTrue(scheduler.exploratory_no_match(command, 1, "")) self.assertTrue(scheduler.exploratory_no_match('/bin/bash -lc "sed -n 1,20p file.cpp; rg Missing file.cpp"', 1, "source excerpt")) self.assertFalse(scheduler.exploratory_no_match(command, 2, "")) self.assertFalse(scheduler.exploratory_no_match('/bin/bash -lc "rg Missing file.cpp && build"', 1, "")) def test_old_rg_no_match_failure_is_normalized(self) -> None: state = {"failures": {"old": {"command": "rg Missing file.cpp", "lastExitCode": 1, "firstError": "", "resolved": False}}} self.assertEqual(scheduler.normalize_exploratory_no_match_failures(state), 1) self.assertFalse(state["failures"]["old"]["resolved"]) self.assertEqual(state["failures"]["old"]["diagnosticReview"], "rg_no_match") scope_state = {"failures": {"scope": {"command": "rg Pattern web/src", "lastExitCode": 64, "firstError": "SCHEDULER_SEARCH_SCOPE_REJECTED", "resolved": False}}} self.assertEqual(scheduler.normalize_exploratory_no_match_failures(scope_state), 1) self.assertFalse(scope_state["failures"]["scope"]["resolved"]) self.assertEqual(scope_state["failures"]["scope"]["diagnosticReview"], "rg_scope") compat_state = {"failures": {"compat": {"command": "python3 tools/fast_source_search.py P --paths web", "lastExitCode": 2, "firstError": "unrecognized arguments: --paths web", "resolved": False}}} self.assertEqual(scheduler.normalize_exploratory_no_match_failures(compat_state), 1) self.assertFalse(compat_state["failures"]["compat"]["resolved"]) self.assertEqual(compat_state["failures"]["compat"]["diagnosticReview"], "tool_compat") def test_scheduler_rg_rejects_directories_and_normalizes_no_match(self) -> None: source = (ROOT / "tools/scheduler-bin/rg").read_text(encoding="utf-8") self.assertIn('-d "$argument"', source) self.assertIn("SCHEDULER_RG_NO_MATCH", source) self.assertIn("SCHEDULER_SEARCH_SCOPE_SKIPPED", source) self.assertIn("--max-columns 240 --max-columns-preview", source) self.assertIn("SCHEDULER_SOURCE_BUDGET_REACHED", source) scheduler_source = (ROOT / "tools/run_freecad_web_scheduler.py").read_text(encoding="utf-8") self.assertIn('environment["BASH_ENV"]', scheduler_source) fast_source = (ROOT / "tools/fast_source_search.py").read_text(encoding="utf-8") self.assertIn("output_lines[:global_limit]", fast_source) self.assertIn('"--max-count", "--max-results"', fast_source) self.assertIn('os.environ.get("FREECAD_SOURCE_BUDGET_MARKER"', fast_source) def test_feature_read_budget_is_soft_until_edit_or_hard_limit(self) -> None: self.assertFalse(scheduler.source_read_should_stop(4, 0, 4, 5)) self.assertTrue(scheduler.source_read_should_stop(5, 0, 4, 5)) self.assertTrue(scheduler.source_read_should_stop(5, 1, 4, 5)) def test_source_budget_marks_search_boundary(self) -> None: self.assertTrue(scheduler.source_read_should_stop(5, 0, 4, 5)) self.assertTrue(scheduler.source_read_should_stop(6, 0, 4, 5)) self.assertFalse(scheduler.source_read_should_stop(3, 0, 4, 5)) def test_token_prediction_rotates_before_limit(self) -> None: with tempfile.TemporaryDirectory() as directory: scheduler.SESSION_CACHE_PATH = Path(directory) / "session.json" first_metadata = {"threadId": "thread", "usage": {"input_tokens": 150_000, "cached_input_tokens": 100_000}} scheduler.save_session_cache("Draft", "b1", first_metadata, None, True) first = scheduler.load_session_cache() self.assertEqual(first["predictedNextInputTokens"], 300_000) second_metadata = {"threadId": "thread", "usage": {"input_tokens": 330_000, "cached_input_tokens": 200_000}} scheduler.save_session_cache("Draft", "b2", second_metadata, first, True) second = scheduler.load_session_cache() self.assertEqual(second["predictedNextInputTokens"], 510_000) self.assertIsNotNone(scheduler.resumable_session("Draft")) second["predictedNextInputTokens"] = scheduler.SESSION_INPUT_TOKEN_LIMIT scheduler.SESSION_CACHE_PATH.write_text(json.dumps(second), encoding="utf-8") self.assertIsNone(scheduler.resumable_session("Draft")) def test_pipeline_policy_keeps_budget_stopped_edits_eligible(self) -> None: source = (ROOT / "tools/run_freecad_web_scheduler.py").read_text(encoding="utf-8") self.assertIn("pipeline_eligible = return_code == 0 and not any((timed_out, stream_failed, agent_idle_stopped))", source) self.assertIn("pipeline_eligible and session_clean if feature_turn", source) self.assertIn('status="batch_static_pipeline_complete"', source) def test_feature_session_reuses_only_same_batch(self) -> None: with tempfile.TemporaryDirectory() as directory: scheduler.SESSION_CACHE_PATH = Path(directory) / "session.json" metadata = {"threadId": "feature-thread", "usage": {"input_tokens": 10_000}} scheduler.save_session_cache("PartDesign", "batch-a", metadata, None, True) self.assertIsNotNone(scheduler.resumable_session("PartDesign", "batch-a", same_batch_only=True)) self.assertIsNone(scheduler.resumable_session("PartDesign", "batch-b", same_batch_only=True)) def test_compile_recovery_reuses_same_batch_session(self) -> None: source = (ROOT / "tools/run_freecad_web_scheduler.py").read_text(encoding="utf-8") self.assertIn("same_batch_only=compile_recovery or feature_turn", source) self.assertGreaterEqual(scheduler.COMPILE_RECOVERY_IDLE_LIMIT_SECONDS, 20.0) self.assertGreaterEqual(scheduler.POST_EDIT_FINALIZE_SECONDS, 15.0) def test_implementation_turn_blocks_wrapped_validation_commands(self) -> None: self.assertTrue(scheduler.forbidden_implementation_command( "/bin/bash -lc 'git diff --check -- file && npx --prefix web tsc --noEmit -p web/tsconfig.json'", "source/read", )) self.assertTrue(scheduler.forbidden_implementation_command( "npm --prefix web run build", "source/read", )) self.assertTrue(scheduler.forbidden_implementation_command( "git status --short -- web/src/module.ts", "source/read", )) def test_failed_pipeline_skip_requires_unchanged_support_files(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) pipeline_path = root / "pipeline.json" packet_path = root / "packet.json" support = root / "Probe.cpp" support.write_text("source", encoding="ascii") pipeline_path.write_text(json.dumps({ "status": "failed", "batchId": "batch-a", "failedStage": "build", }), encoding="ascii") packet_path.write_text(json.dumps({ "batchId": "batch-a", "supportFiles": [{"path": "Probe.cpp"}], }), encoding="ascii") previous_pipeline = scheduler.MODULE_PIPELINE_PATH previous_root = scheduler.ROOT try: scheduler.MODULE_PIPELINE_PATH = pipeline_path scheduler.ROOT = root self.assertTrue(scheduler.failed_pipeline_is_unchanged("batch-a", json.loads(packet_path.read_text(encoding="ascii")))) support.write_text("changed", encoding="ascii") os.utime(support, ns=(pipeline_path.stat().st_mtime_ns + 1, pipeline_path.stat().st_mtime_ns + 1)) self.assertFalse(scheduler.failed_pipeline_is_unchanged("batch-a", json.loads(packet_path.read_text(encoding="ascii")))) finally: scheduler.MODULE_PIPELINE_PATH = previous_pipeline scheduler.ROOT = previous_root def test_resumed_feature_turn_uses_low_reasoning(self) -> None: source = (ROOT / "tools/run_freecad_web_scheduler.py").read_text(encoding="utf-8") self.assertIn('"low" if feature_turn or batch_has_completed_evidence(batch)', source) self.assertLess(scheduler.FEATURE_SOURCE_READS_PER_TURN, scheduler.MAX_SOURCE_READS_PER_TURN) self.assertGreater(scheduler.FEATURE_SOURCE_READS_HARD_LIMIT, scheduler.FEATURE_SOURCE_READS_PER_TURN) self.assertEqual(scheduler.FEATURE_PATCH_CONFLICT_LIMIT, 1) def test_packet_resolves_plain_module_worker(self) -> None: source = (ROOT / "tools/prepare_module_implementation_packet.py").read_text(encoding="utf-8") self.assertIn('f"web/src/{slug}.worker.ts"', source) self.assertIn("relative in worker_paths", source) self.assertIn('glob(f"{slug}*python*family*facade.ts")', source) self.assertIn('r"PythonFamily(?:Batch)?Request"', source) self.assertIn("relative in facade_paths", source) def test_packet_recommends_splitting_oversized_desktop_adapter(self) -> None: source = (ROOT / "tools/prepare_module_implementation_packet.py").read_text(encoding="utf-8") self.assertIn("DESKTOP_ADAPTER_SPLIT_BYTES", source) self.assertIn('"desktopAdapterRecommended"', source) self.assertIn('"oversizedNativeSources"', source) self.assertIn('"desktopAdapterAction"', source) self.assertIn('"desktopAdapterActive"', source) self.assertIn("path != desktop_adapter", source) def test_resumed_feature_prompt_reuses_thread_packet(self) -> None: with tempfile.TemporaryDirectory() as directory: previous_batch = scheduler.MODULE_BATCH_PATH previous_pipeline = scheduler.MODULE_PIPELINE_PATH try: scheduler.MODULE_BATCH_PATH = Path(directory) / "batch.json" scheduler.MODULE_PIPELINE_PATH = Path(directory) / "pipeline.json" batch = { "status": "ready", "batchId": "resume-batch", "selected": {"module": "Start", "family": "desktop-command", "recordCount": 1}, "records": [["Start:desktop:Start_Start", "Start_Start"]], } scheduler.MODULE_BATCH_PATH.write_text(json.dumps(batch), encoding="utf-8") scheduler.MODULE_PIPELINE_PATH.write_text("{}", encoding="utf-8") prompt = scheduler.build_prompt("FW-P6-FPA-Y", failures=[], resumed=True) self.assertIn(str(batch["batchId"]), prompt) self.assertIn("上一轮的完整工作包", prompt) self.assertNotIn("official source excerpts", prompt) self.assertNotIn("editable excerpts:", prompt) self.assertLess(len(prompt.encode("utf-8")), 4_000) finally: scheduler.MODULE_BATCH_PATH = previous_batch scheduler.MODULE_PIPELINE_PATH = previous_pipeline def test_conflicted_feature_session_is_not_reused(self) -> None: source = (ROOT / "tools/run_freecad_web_scheduler.py").read_text(encoding="utf-8") self.assertIn('not int(turn_metadata.get("patchConflicts", 0) or 0)', source) self.assertIn('"custom tool call output is missing" in lowered', source) self.assertIn('session_clean = bool(turn_metadata.get("turnCompleted"))', source) self.assertIn("source_budget_reached_event.set()", source) self.assertNotIn('turn_metadata.get("safeBudgetStop")', source) def test_status_liveness_checks_process_identity(self) -> None: status_source = (ROOT / "tools/show_freecad_web_scheduler.py").read_text(encoding="utf-8") self.assertIn("def process_matches", status_source) self.assertIn("observedState: stale", status_source) class EvidenceTests(unittest.TestCase): def test_draft_compile_cache_does_not_replace_native_gate(self) -> None: candidates = [] for path in (ROOT / "docs/p6").glob("draft-module-batch-*-runtime.json"): try: value = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): continue if isinstance(value.get("gateTiming"), dict) and value["gateTiming"].get("compileCacheHit") is True: candidates.append(value) self.assertTrue(candidates) evidence = candidates[-1] self.assertIn(evidence.get("status"), {"pass", "pass_with_boundaries"}) self.assertTrue(evidence.get("resources", {}).get("resourcesReleased")) self.assertGreater(float(evidence["gateTiming"].get("workerReadySeconds", 0)), 0) self.assertGreater(float(evidence["gateTiming"].get("dispatchSeconds", 0)), 0) if __name__ == "__main__": unittest.main(verbosity=2)