#!/usr/bin/env python3 """Generate the reproducible LinuxCNC source and coverage seed indexes. The source index is deliberately mechanical: every file in a declared input root is recorded with its size and digest. The coverage seed is not an implementation claim; entries remain ``planned`` until an owner assigns a feature, adapter, test and oracle. """ from __future__ import annotations import argparse import hashlib import json import re from pathlib import Path from typing import Iterable ROOTS = ( ("doc", Path("linuxcnc/docs")), ("source", Path("linuxcnc/src")), ("config", Path("linuxcnc/configs/sim")), ("test", Path("linuxcnc/tests")), ("unit_test", Path("linuxcnc/unit_tests")), ("implementation", Path("wasm-core")), ("implementation", Path("web")), ) BUILD_FILES = ( Path("linuxcnc/VERSION"), Path("linuxcnc/meson.build"), ) KINEMATICS_CONFIG_RE = re.compile( r"(?:^|\s)KINEMATICS\s*=|\bloadrt\s+(?:\[KINS\]KINEMATICS|[^\s#;]*(?:kins|kinematics))|" r"corexy_by_hal|matrixkins|xyzab_tdr_kins|switchkins|motion\.switchkins-type", re.IGNORECASE, ) def sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: for block in iter(lambda: handle.read(1024 * 1024), b""): digest.update(block) return digest.hexdigest() def source_kind(root_kind: str, path: Path) -> str: if root_kind == "implementation": if path.suffix in {".h", ".hpp"}: return "web_wasm_interface" if path.suffix in {".c", ".cc", ".cpp", ".mjs", ".js"}: return "web_wasm_implementation" return "web_wasm_build_or_test" if root_kind == "doc": return "documentation" if root_kind in {"test", "unit_test"}: return "test" if root_kind == "config": return "simulation_config" if path.name.endswith(".comp"): return "hal_component_source" return "source" def iter_files(repo_root: Path) -> Iterable[tuple[str, Path]]: for root_kind, relative_root in ROOTS: root = repo_root / relative_root if not root.is_dir(): raise FileNotFoundError(f"required inventory root is missing: {relative_root}") for path in sorted(path for path in root.rglob("*") if path.is_file()): yield root_kind, path for relative_path in BUILD_FILES: path = repo_root / relative_path if not path.is_file(): raise FileNotFoundError(f"required build source is missing: {relative_path}") yield "build", path def make_entry(repo_root: Path, root_kind: str, path: Path) -> dict[str, object]: relative = path.relative_to(repo_root).as_posix() source_id = f"{root_kind}:{relative}" return { "source_id": source_id, "path": relative, "kind": source_kind(root_kind, path), "bytes": path.stat().st_size, "sha256": sha256(path), } def make_manifest_entry(source: dict[str, object], repo_root: Path | None = None) -> dict[str, object]: source_id = str(source["source_id"]) entry = { "id": f"seed:{source_id}", "feature_id": None, "source": source_id, "source_sha": source["sha256"], "domain": "unassigned", "kind": source["kind"], "adaptation": None, "dependencies": [], "inputs": [source["path"]], "outputs": [], "errors": [], "sim_status": "planned", "web_status": "planned", "test_id": None, "oracle": None, "golden": None, "difference": None, "coverage_dimensions": [], "context_id": None, "exclusion_reason": None, "mapping_status": "needs_owner", } source_path = str(source["path"]) is_kinematics_source = source_path.startswith("linuxcnc/src/emc/kinematics/") is_kinematics_config = False if repo_root is not None and source_path.startswith(("linuxcnc/configs/sim/", "linuxcnc/tests/")) and Path(source_path).suffix.lower() in {".ini", ".inc", ".hal"}: path = repo_root / source_path if path.is_file(): is_kinematics_config = bool(KINEMATICS_CONFIG_RE.search(path.read_text(encoding="utf-8", errors="strict"))) if source_path == "linuxcnc/configs/sim/axis/pentapod/kinematics.hal": is_kinematics_config = True is_kinematics_abi = source_path in {"wasm-core/include/sim_kinematics.h", "wasm-core/src/sim_kinematics.c", "wasm-core/src/sim_switchkins.c", "wasm-core/src/sim_userkins.c", "wasm-core/src/sim_kinematics_registry.c", "wasm-core/tests/sim_kinematics_test.c", "wasm-core/tests/sim_kinematics_test_main.c", "wasm-core/tests/sim_switchkins_test.c", "wasm-core/tests/sim_userkins_test.c", "wasm-core/tests/sim_kinematics_registry_test.c"} is_switchkins_source = source_path in { "linuxcnc/src/emc/kinematics/switchkins.c", "linuxcnc/src/emc/kinematics/switchkins.h", "linuxcnc/src/emc/kinematics/xyzac-trt-kins.c", "wasm-core/src/sim_switchkins.c", } is_switchkins_config = source_path in { "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini", "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins_postgui.hal", } is_userkins_source = source_path in { "linuxcnc/src/emc/kinematics/userkfuncs.c", "linuxcnc/src/emc/kinematics/ugenserkins.c", } is_userkins_config = source_path in { "linuxcnc/configs/sim/axis/vismach/scara/scara.ini", "linuxcnc/configs/sim/axis/vismach/puma/puma560.ini", } is_userkins_implementation = source_path in { "wasm-core/src/sim_userkins.c", "wasm-core/tests/sim_userkins_test.c", } is_registry_implementation = source_path in { "wasm-core/src/sim_kinematics_registry.c", "wasm-core/tests/sim_kinematics_registry_test.c", } is_motion_implementation = source_path in { "wasm-core/include/sim_kinematics_motion.h", "wasm-core/src/sim_kinematics_motion.c", "wasm-core/tests/sim_kinematics_motion_test.c", } is_feedback_implementation = source_path in { "wasm-core/include/sim_kinematics_feedback.h", "wasm-core/src/sim_kinematics_feedback.c", "wasm-core/tests/sim_kinematics_feedback_test.c", } is_home_limit_implementation = source_path in { "wasm-core/include/sim_kinematics_home_limit.h", "wasm-core/src/sim_kinematics_home_limit.c", "wasm-core/tests/sim_kinematics_home_limit_test.c", } is_io_implementation = source_path in { "wasm-core/include/sim_io.h", "wasm-core/src/sim_io.c", "wasm-core/tests/sim_io_test.c", } is_io_source = source_path in { "linuxcnc/src/emc/iotask/ioControl.cc", "linuxcnc/src/emc/iotask/ioControl_v2.cc", "linuxcnc/src/hal/components/sim_spindle.comp", } is_delta_source = source_path.startswith("linuxcnc/src/emc/kinematics/lineardelta") or source_path.startswith("linuxcnc/src/emc/kinematics/rotarydelta") is_delta_config = is_kinematics_config and any(token in source_path.lower() for token in ("ldelta", "rdelta")) is_delta_implementation = is_kinematics_abi and source_path in {"wasm-core/include/sim_kinematics.h", "wasm-core/src/sim_kinematics.c", "wasm-core/tests/sim_kinematics_test.c", "wasm-core/tests/sim_kinematics_test_main.c"} is_tripod_source = source_path == "linuxcnc/src/emc/kinematics/tripodkins.c" is_tripod_config = is_kinematics_config and source_path == "linuxcnc/configs/sim/tklinuxcnc/tripod.ini" is_genhex_source = source_path in {"linuxcnc/src/emc/kinematics/genhexkins.c", "linuxcnc/src/emc/kinematics/genhexkins.h"} is_genhex_config = is_kinematics_config and source_path == "linuxcnc/configs/sim/axis/vismach/hexapod-sim/hexapod.ini" is_genhex_hal = source_path == "linuxcnc/configs/sim/axis/vismach/hexapod-sim/kinematics.hal" is_penta_source = source_path in {"linuxcnc/src/emc/kinematics/pentakins.c", "linuxcnc/src/emc/kinematics/pentakins.h"} is_penta_config = is_kinematics_config and source_path == "linuxcnc/configs/sim/axis/pentapod/pentapod.ini" is_penta_hal = source_path == "linuxcnc/configs/sim/axis/pentapod/kinematics.hal" is_penta_implementation = is_kinematics_abi is_recovery_implementation = source_path in { "wasm-core/include/sim_event.h", "wasm-core/src/sim_event.c", "wasm-core/tests/sim_event_test.c", "web/worker/replay.mjs", "web/worker/sim-session.mjs", "web/worker/test_replay.mjs", "web/workspace/journal.mjs", "web/workspace/recovery.mjs", "web/workspace/test_recovery.mjs", } is_corexy_hal = source_path in { "linuxcnc/src/hal/components/corexy_by_hal.comp", "linuxcnc/configs/sim/axis/corexy/corexy_by_hal.ini", "linuxcnc/configs/sim/axis/corexy/corexy_by_hal.hal", "linuxcnc/configs/sim/axis/corexy/corexy_by_kins.ini", "wasm-core/include/sim_hal.h", "wasm-core/src/sim_hal.c", "wasm-core/tests/sim_hal_test.c", "wasm-core/tests/sim_hal_test_main.c", } is_sim_configuration = source_path.startswith("linuxcnc/configs/sim/") if is_recovery_implementation: entry.update({ "domain": "recovery", "feature_id": "feature:recovery-k7-replay", "dependencies": ["coverage/workspace-recovery.report.json", "coverage/io-runtime.report.json", "coverage/kinematics-motion.report.json", "coverage/kinematics-feedback.report.json"], "outputs": ["coverage/workspace-recovery.report.json"], "errors": ["blocked:official recovery oracle is absent from locked source"], "test_id": "audit:K7-RECOVERY-01", "oracle": {"status": "blocked", "report": "coverage/workspace-recovery.report.json"}, "mapping_status": "verified_partial", }) if is_io_implementation or is_io_source: entry.update({ "domain": "io", "feature_id": "feature:io-k6-spindle-tool-probe", "dependencies": ["coverage/io-runtime.report.json", "coverage/hal-runtime.report.json", "coverage/kinematics-feedback.report.json"], "outputs": ["coverage/io-runtime.report.json"], "errors": ["blocked:official IO/kinematics oracle is absent from locked source"], "test_id": "audit:K6-IO-01", "oracle": {"status": "blocked", "report": "coverage/io-runtime.report.json"}, "mapping_status": "verified_partial", }) if is_kinematics_source or is_kinematics_config or is_kinematics_abi or is_corexy_hal or is_switchkins_source or is_switchkins_config or is_userkins_source or is_userkins_config or is_userkins_implementation or is_motion_implementation or is_feedback_implementation or is_home_limit_implementation: # K0-INV-01 audits are source-closure evidence, not an implementation # claim. Keep the seed planned while linking every kinematics source # to the deterministic report and its explicit blocked oracle. entry.update({ "domain": "hal" if is_corexy_hal else "kinematics", "feature_id": "feature:kinematics-k6-home" if is_home_limit_implementation else "feature:kinematics-k6-feedback" if is_feedback_implementation else "feature:kinematics-k6-motion" if is_motion_implementation else "feature:kinematics-k5-cfg" if is_registry_implementation else "feature:kinematics-k5-userkins" if (is_userkins_source or is_userkins_config or is_userkins_implementation) else "feature:kinematics-k5-switchkins" if (is_switchkins_source or is_switchkins_config) else "feature:kinematics-k2-hal" if is_corexy_hal else "feature:kinematics-k4-tripod" if (is_tripod_source or is_tripod_config) else "feature:kinematics-k4-genhex" if (is_genhex_source or is_genhex_config or is_genhex_hal) else "feature:kinematics-k4-pentapod" if (is_penta_source or is_penta_config or is_penta_hal or is_penta_implementation) else "feature:kinematics-k4-delta" if (is_delta_source or is_delta_config or is_delta_implementation) else "feature:kinematics-k0" if not is_kinematics_abi else "feature:kinematics-k1-contract", "dependencies": ["coverage/kinematics-home-limit.report.json", "coverage/kinematics-feedback.report.json", "coverage/kinematics-registry.report.json"] if is_home_limit_implementation else ["coverage/kinematics-feedback.report.json", "coverage/kinematics-motion.report.json", "coverage/kinematics-registry.report.json"] if is_feedback_implementation else ["coverage/kinematics-motion.report.json", "coverage/motion-runtime.report.json", "coverage/kinematics-registry.report.json"] if is_motion_implementation else ["coverage/kinematics-registry.report.json", "coverage/kinematics-abi-contract.json", "coverage/kinematics-numeric-policy.json"] if is_registry_implementation else ["coverage/userkins-kinematics.report.json", "coverage/genser-kinematics.report.json"] if (is_userkins_source or is_userkins_config or is_userkins_implementation) else ["coverage/switchkins-kinematics.report.json", "coverage/kinematics-source-closure.report.json"] if (is_switchkins_source or is_switchkins_config) else ["coverage/coupled-kinematics.report.json", "coverage/config-resources.jsonl"] if is_corexy_hal else ["coverage/tripod-kinematics.report.json", "coverage/delta-kinematics.report.json"] if (is_tripod_source or is_tripod_config) else ["coverage/genhex-kinematics.report.json", "coverage/kinematics-source-closure.report.json"] if (is_genhex_source or is_genhex_config or is_genhex_hal) else ["coverage/pentapod-kinematics.report.json", "coverage/kinematics-source-closure.report.json"] if (is_penta_source or is_penta_config or is_penta_hal or is_penta_implementation) else ["coverage/delta-kinematics.report.json", "coverage/kinematics-source-closure.report.json"] if (is_delta_source or is_delta_config or is_delta_implementation) else ["coverage/source-index.jsonl", "coverage/source-symbols.jsonl"] if is_kinematics_source else ["coverage/kinematics-source-closure.report.json", "coverage/config-resources.jsonl"] if is_kinematics_config else ["wasm-core/include/sim_kinematics.h", "wasm-core/CMakeLists.txt"], "outputs": ["coverage/kinematics-home-limit.report.json"] if is_home_limit_implementation else ["coverage/kinematics-feedback.report.json"] if is_feedback_implementation else ["coverage/kinematics-motion.report.json"] if is_motion_implementation else ["coverage/kinematics-registry.report.json"] if is_registry_implementation else ["coverage/userkins-kinematics.report.json"] if (is_userkins_source or is_userkins_config or is_userkins_implementation) else ["coverage/switchkins-kinematics.report.json"] if (is_switchkins_source or is_switchkins_config) else ["coverage/corexy-hal.report.json"] if is_corexy_hal else ["coverage/tripod-kinematics.report.json"] if (is_tripod_source or is_tripod_config) else ["coverage/genhex-kinematics.report.json"] if (is_genhex_source or is_genhex_config or is_genhex_hal) else ["coverage/pentapod-kinematics.report.json"] if (is_penta_source or is_penta_config or is_penta_hal) else ["coverage/kinematics-abi-contract.json", "coverage/kinematics-mapping-contract.json", "coverage/kinematics-numeric-policy.json"] if is_penta_implementation else ["coverage/delta-kinematics.report.json"] if (is_delta_source or is_delta_config or is_delta_implementation) else ["coverage/kinematics-source-closure.report.json", "coverage/trivkins-integration.report.json", "coverage/coupled-kinematics.report.json", "coverage/fiveaxis-kinematics.report.json", "coverage/trt-kinematics.report.json", "coverage/robot-kinematics.report.json", "coverage/genser-kinematics.report.json"] if is_kinematics_source else ["coverage/kinematics-config-graph.report.json", "coverage/kinematics-oracle-samples.jsonl", "coverage/kinematics-oracle.report.json", "coverage/kinematics-golden-schema.json", "coverage/coupled-kinematics.report.json", "coverage/fiveaxis-kinematics.report.json", "coverage/trt-kinematics.report.json", "coverage/robot-kinematics.report.json", "coverage/genser-kinematics.report.json"] if is_kinematics_config else ["coverage/kinematics-abi-contract.json", "coverage/kinematics-mapping-contract.json", "coverage/kinematics-numeric-policy.json", "coverage/coupled-kinematics.report.json", "coverage/fiveaxis-kinematics.report.json", "coverage/trt-kinematics.report.json", "coverage/robot-kinematics.report.json", "coverage/genser-kinematics.report.json"], "errors": ["blocked:linuxcnc/unit_tests/kinematics missing from locked source"], "test_id": "audit:K6-HOME-01" if is_home_limit_implementation else "audit:K6-MOTION-02" if is_feedback_implementation else "audit:K6-MOTION-01" if is_motion_implementation else "audit:K5-CFG-01" if is_registry_implementation else "audit:K5-USER-01" if (is_userkins_source or is_userkins_config or is_userkins_implementation) else "audit:K5-SWITCH-01" if (is_switchkins_source or is_switchkins_config) else "audit:K2-HAL-01" if is_corexy_hal else "audit:K4-TRIPOD-01" if (is_tripod_source or is_tripod_config) else "audit:K4-HEX-01" if (is_genhex_source or is_genhex_config or is_genhex_hal) else "audit:K4-PENTA-01" if (is_penta_source or is_penta_config or is_penta_hal or is_penta_implementation) else "audit:K4-DELTA-01" if (is_delta_source or is_delta_config or is_delta_implementation) else "audit:K0-INV-01" if is_kinematics_source else "audit:K0-INV-02" if is_kinematics_config else "audit:K1-CONTRACT-01", "oracle": {"status": "blocked", "report": "coverage/kinematics-home-limit.report.json" if is_home_limit_implementation else "coverage/kinematics-feedback.report.json" if is_feedback_implementation else "coverage/kinematics-motion.report.json" if is_motion_implementation else "coverage/kinematics-registry.report.json" if is_registry_implementation else "coverage/userkins-kinematics.report.json" if (is_userkins_source or is_userkins_config or is_userkins_implementation) else "coverage/switchkins-kinematics.report.json" if (is_switchkins_source or is_switchkins_config) else "coverage/corexy-hal.report.json" if is_corexy_hal else "coverage/tripod-kinematics.report.json" if (is_tripod_source or is_tripod_config) else "coverage/genhex-kinematics.report.json" if (is_genhex_source or is_genhex_config or is_genhex_hal) else "coverage/pentapod-kinematics.report.json" if (is_penta_source or is_penta_config or is_penta_hal or is_penta_implementation) else "coverage/delta-kinematics.report.json" if (is_delta_source or is_delta_config or is_delta_implementation) else "coverage/kinematics-source-closure.report.json"}, "mapping_status": "audited_blocked" if not is_corexy_hal else "verified_partial", }) if is_sim_configuration: # K8 covers every simulation resource, including configs that do not # declare KINEMATICS. Keep the family-specific owner above, but link # the shared preflight and its explicit blocked oracle as a second # evidence edge. entry["dependencies"] = list(dict.fromkeys([ *[str(value) for value in entry.get("dependencies", [])], "coverage/configuration-regression.report.json", "coverage/config-resources.jsonl", "coverage/kinematics-config-graph.report.json", ])) entry["outputs"] = list(dict.fromkeys([ *[str(value) for value in entry.get("outputs", [])], "coverage/configuration-regression.report.json", ])) entry["coverage_dimensions"] = list(dict.fromkeys([ *[str(value) for value in entry.get("coverage_dimensions", [])], "configuration_startup_preflight", "configuration_resource_graph", "configuration_kinematics_entry", ])) entry["configuration_regression"] = { "feature_id": "feature:configuration-k8-regression", "test_id": "audit:K8-REG-01", "report": "coverage/configuration-regression.report.json", "oracle": "blocked:official LinuxCNC kinematics/recovery oracle is absent from locked source", } if not (is_kinematics_source or is_kinematics_config or is_kinematics_abi or is_corexy_hal or is_switchkins_source or is_switchkins_config or is_userkins_source or is_userkins_config or is_userkins_implementation or is_motion_implementation or is_feedback_implementation or is_home_limit_implementation): entry.update({ "domain": "configuration", "feature_id": "feature:configuration-k8-regression", "errors": ["blocked:configuration preflight retains missing resources and official oracle gap"], "test_id": "audit:K8-REG-01", "oracle": {"status": "blocked", "report": "coverage/configuration-regression.report.json"}, "mapping_status": "verified_partial", }) return entry def write_jsonl(path: Path, entries: Iterable[dict[str, object]]) -> None: path.parent.mkdir(parents=True, exist_ok=True) with path.open("w", encoding="utf-8", newline="\n") as handle: for entry in entries: handle.write(json.dumps(entry, ensure_ascii=False, sort_keys=True, separators=(",", ":"))) handle.write("\n") def generate(repo_root: Path, source_index: Path, manifest: Path) -> tuple[int, int]: sources = [make_entry(repo_root, kind, path) for kind, path in iter_files(repo_root)] sources.sort(key=lambda item: str(item["source_id"])) write_jsonl(source_index, sources) write_jsonl(manifest, (make_manifest_entry(source, repo_root) for source in sources)) return len(sources), len(sources) def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1]) parser.add_argument("--source-index", type=Path, default=Path("coverage/source-index.jsonl")) parser.add_argument("--manifest", type=Path, default=Path("coverage/manifest.jsonl")) args = parser.parse_args() source_count, manifest_count = generate( args.repo_root.resolve(), args.repo_root.resolve() / args.source_index, args.repo_root.resolve() / args.manifest, ) print(f"source_index={source_count} manifest_seed={manifest_count}") return 0 if __name__ == "__main__": raise SystemExit(main())