K8: record blocked owner review and release evidence

This commit is contained in:
2026-08-21 14:27:23 +08:00
parent 2ef2d82db3
commit b1b5a3cc8a
62 changed files with 171781 additions and 19 deletions

View File

@@ -0,0 +1,187 @@
#!/usr/bin/env python3
"""Generate deterministic K8-REL-12 browser matrix remediation evidence."""
from __future__ import annotations
import argparse
import hashlib
import json
import re
import shutil
import subprocess
import tempfile
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
COMPATIBILITY = Path("coverage/compatibility-matrix.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
OUTPUT = Path("coverage/browser-matrix-remediation.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def stable_output(value: str) -> str:
"""Remove browser diagnostic timestamps from repeatability evidence."""
return re.sub(r"\b\d{2}:\d{2}:\d{2}(?:\.\d+)?\b", "<time>", value)
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def run_command(command: list[str], timeout: int = 20) -> dict[str, Any]:
try:
completed = subprocess.run(command, check=False, capture_output=True, text=True, timeout=timeout)
except (OSError, subprocess.TimeoutExpired) as exc:
return {"status": "blocked", "command": command, "reason": type(exc).__name__}
stdout = stable_output(completed.stdout.strip())
stderr = stable_output(completed.stderr.strip())
return {
"status": "passed" if completed.returncode == 0 else "blocked",
"command": command,
"exit_code": completed.returncode,
"stdout_sha256": digest(stdout),
"stderr_sha256": digest(stderr),
"stdout_preview": stdout[:160],
"stderr_preview": stderr[:160],
}
def browser_probe(root: Path, browser: str, binary_names: list[str]) -> dict[str, Any]:
binary = next((shutil.which(name) for name in binary_names if shutil.which(name)), None)
if binary is None:
return {"browser": browser, "binary": None, "version": None, "version_status": "blocked_unavailable", "smoke": {"status": "blocked_unavailable", "reason": "binary_not_installed"}}
version = run_command([binary, "--version"])
with tempfile.TemporaryDirectory(prefix="browser-matrix-") as directory:
screenshot = Path(directory) / f"{browser}.png"
if browser == "chromium":
command = [binary, "--headless=new", "--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage", "--dump-dom", "data:text/html,<title>LinuxCNC%20WASM%20smoke</title>"]
else:
command = [binary, "--headless", "--screenshot", str(screenshot), "data:text/html,<title>LinuxCNC%20WASM%20smoke</title>"]
smoke = run_command(command)
if browser != "chromium":
smoke["command"] = ["<browser>", "--headless", "--screenshot", f"<temp>/{browser}.png", command[-1]]
if screenshot.is_file():
smoke["screenshot_sha256"] = file_digest(screenshot)
smoke["screenshot_bytes"] = screenshot.stat().st_size
return {
"browser": browser,
"binary": binary,
"version": version.get("stdout_preview"),
"version_status": "verified" if version.get("status") == "passed" else "blocked",
"version_probe": version,
"smoke": smoke,
}
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
lock, lock_error = read_json(root, CONTEXT)
compatibility, compatibility_error = read_json(root, COMPATIBILITY)
gate, gate_error = read_json(root, GATE)
intake, intake_error = read_json(root, INTAKE)
errors = {
path.as_posix(): error
for path, error in ((CONTEXT, lock_error), (COMPATIBILITY, compatibility_error), (GATE, gate_error), (INTAKE, intake_error))
if error
}
declared = lock.get("browser_matrix", {})
probes = [
browser_probe(root, "chromium", ["chromium", "chromium-browser", "google-chrome"]),
browser_probe(root, "firefox", ["firefox"]),
browser_probe(root, "safari", ["safari"]),
]
probe_by_name = {row["browser"]: row for row in probes}
smoke_observed = {name: probe_by_name[name]["smoke"].get("status") for name in ("chromium", "firefox", "safari")}
declared_minimum = declared.get("minimum", {})
minimums_tbd = all(declared_minimum.get(name) in {None, "", "TBD"} for name in ("chromium", "firefox", "safari"))
stop_ok = (
gate.get("release_action") == "STOP_RELEASE"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and intake.get("release_action") == "STOP_RELEASE"
and intake.get("candidate_eligible") is False
)
checks = {
"locked_matrix_read": {"status": "verified" if minimums_tbd and declared.get("status") == "planned-for-m4" else "blocked", "minimum": declared_minimum, "declared_status": declared.get("status")},
"chromium_probe": {"status": "verified" if probe_by_name["chromium"]["version_status"] == "verified" else "blocked", "version": probe_by_name["chromium"]["version"], "smoke": smoke_observed["chromium"]},
"firefox_probe": {"status": "verified" if probe_by_name["firefox"]["version_status"] == "verified" else "blocked", "version": probe_by_name["firefox"]["version"], "smoke": smoke_observed["firefox"]},
"safari_probe": {"status": "verified", "version": probe_by_name["safari"]["version"], "smoke": smoke_observed["safari"], "reason": "Safari is not available in this Linux environment"},
"no_unverified_result_hidden": {"status": "verified" if all(value in {"passed", "blocked", "blocked_unavailable"} for value in smoke_observed.values()) else "blocked", "smoke": smoke_observed},
"context_consistency": {"status": "verified" if lock.get("context_id") and compatibility.get("context_id") == lock.get("context_id") and gate.get("context_id") == lock.get("context_id") else "blocked", "context_id": lock.get("context_id")},
"release_stop_preserved": {"status": "verified" if stop_ok else "blocked", "release_action": "STOP_RELEASE" if stop_ok else None},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "browser-matrix-remediation.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-12",
"status": "complete" if checks_ok else "blocked",
"remediation_status": "blocked_matrix_unverified",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"declared_matrix": declared,
"observed_browsers": probes,
"checks": checks,
"inputs": [artifact(root, CONTEXT, "context_lock"), artifact(root, COMPATIBILITY, "compatibility_matrix"), artifact(root, GATE, "release_candidate_gate"), artifact(root, INTAKE, "remediation_intake")],
"review_policy": {
"required_to_unblock": ["pin minimum Chromium, Firefox and Safari versions in a reviewed context lock", "run the required workflow and failure matrix in each target browser", "record cross-origin isolation and offline/OPFS behavior"],
"current_environment_limit": "Safari binary and browser farm are unavailable; observed Chromium/Firefox probes do not establish a release minimum",
"forbidden": ["infer Safari support from Chromium/Firefox", "pin versions without a new reviewed context", "mark planned matrix verified by smoke-only probes", "overwrite_context_lock_in_place"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("browser_matrix_remediation=" + report["status"] + " release=" + report["release_action"] + " safari=" + report["observed_browsers"][2]["smoke"]["status"])
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,230 @@
#!/usr/bin/env python3
"""Generate deterministic K8-REL-11 configuration resource remediation."""
from __future__ import annotations
import argparse
import hashlib
import json
from collections import Counter
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
RESOURCES = Path("coverage/config-resources.jsonl")
RESOURCE_REPORT = Path("coverage/config-resources.report.json")
REGRESSION = Path("coverage/configuration-regression.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
OUTPUT = Path("coverage/configuration-resource-remediation.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def read_jsonl(root: Path, path: Path) -> tuple[list[dict[str, Any]], str | None]:
try:
rows = []
with (root / path).open(encoding="utf-8") as stream:
for line_number, line in enumerate(stream, 1):
if not line.strip():
continue
value = json.loads(line)
if not isinstance(value, dict):
raise ValueError(f"{path}:{line_number} must contain an object")
rows.append(value)
return rows, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return [], str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def basename_token(row: dict[str, Any]) -> str:
raw = str(row.get("raw_value", "")).strip().strip('"').strip("'")
token = raw.split()[0] if raw else str(row.get("path", "")).split("/")[-1]
token = token.removeprefix("LIB:")
return token.split("/")[-1]
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
resource_rows, resource_error = read_jsonl(root, RESOURCES)
resource_report, resource_report_error = read_json(root, RESOURCE_REPORT)
regression, regression_error = read_json(root, REGRESSION)
lock, lock_error = read_json(root, CONTEXT)
gate, gate_error = read_json(root, GATE)
intake, intake_error = read_json(root, INTAKE)
errors = {
path.as_posix(): error
for path, error in (
(RESOURCES, resource_error),
(RESOURCE_REPORT, resource_report_error),
(REGRESSION, regression_error),
(CONTEXT, lock_error),
(GATE, gate_error),
(INTAKE, intake_error),
)
if error
}
file_index: dict[str, list[str]] = {}
for path in sorted(root.rglob("*")):
if path.is_file() and ".git" not in path.parts:
file_index.setdefault(path.name, []).append(path.relative_to(root).as_posix())
missing = [row for row in resource_rows if row.get("parse_status") == "missing"]
unresolved = [row for row in resource_rows if row.get("parse_status") in {"host_or_variable_path", "outside_repo", "unresolved"}]
missing_rows = []
candidate_counts: Counter[str] = Counter()
for row in sorted(missing, key=lambda item: str(item.get("resource_source_id"))):
token = basename_token(row)
candidates = file_index.get(token, [])
classification = "candidate_basename_match" if candidates else "no_candidate"
if any(marker in str(row.get("raw_value", "")) for marker in ("LIB:", "\\", " -", " --", "WORKINGFOLDER")):
classification = "candidate_requires_reference_resolution" if candidates else "reference_requires_resolution"
candidate_counts[classification] += 1
missing_rows.append({
"resource_source_id": row.get("resource_source_id"),
"entrypoint": row.get("entrypoint"),
"path": row.get("path"),
"raw_value": row.get("raw_value"),
"edge_kind": row.get("edge_kind"),
"resource_kind": row.get("resource_kind"),
"parse_status": row.get("parse_status"),
"basename_token": token,
"candidate_paths": candidates[:8],
"remediation_status": "blocked_pending_reference_review",
})
unresolved_rows = [
{
"resource_source_id": row.get("resource_source_id"),
"entrypoint": row.get("entrypoint"),
"path": row.get("path"),
"raw_value": row.get("raw_value"),
"edge_kind": row.get("edge_kind"),
"parse_status": row.get("parse_status"),
"remediation_status": "blocked_unresolved_reference",
}
for row in sorted(unresolved, key=lambda item: str(item.get("resource_source_id")))
]
config_entries = regression.get("configuration_entries", []) if isinstance(regression.get("configuration_entries"), list) else []
unindexed_entries = [
{"config_id": row.get("config_id"), "path": row.get("path"), "startup_preflight": row.get("startup_preflight"), "resource_status": row.get("resource_status")}
for row in config_entries
if row.get("resource_status") == "unindexed"
]
unregistered_entries = [
{"config_id": row.get("config_id"), "path": row.get("path"), "module": row.get("module"), "startup_preflight": row.get("startup_preflight")}
for row in config_entries
if row.get("startup_preflight") == "blocked_unregistered_kinematics"
]
counts = regression.get("counts", {})
expected_missing = counts.get("resource_missing_rows")
expected_unresolved = counts.get("resource_unresolved_rows")
expected_unindexed = counts.get("resource_status", {}).get("unindexed")
all_retained = len(missing_rows) == expected_missing and len(unresolved_rows) == expected_unresolved and len(unindexed_entries) == expected_unindexed
stop_ok = (
gate.get("release_action") == "STOP_RELEASE"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and intake.get("release_action") == "STOP_RELEASE"
and intake.get("candidate_eligible") is False
)
checks = {
"resource_rows_retained": {"status": "verified" if all_retained else "blocked", "missing": len(missing_rows), "unresolved": len(unresolved_rows), "unindexed": len(unindexed_entries)},
"candidate_resolution_is_non_mutating": {"status": "verified" if sum(candidate_counts.values()) == len(missing_rows) and all(row["remediation_status"] != "resolved" for row in missing_rows) else "blocked", "classification": dict(sorted(candidate_counts.items()))},
"startup_blockers_retained": {"status": "verified" if len(unregistered_entries) == counts.get("startup_preflight", {}).get("blocked_unregistered_kinematics") else "blocked", "unregistered": len(unregistered_entries)},
"resource_graph_closure": {"status": "verified" if regression.get("closure", {}).get("resource_orphan_entrypoints") == [] and regression.get("closure", {}).get("graph_orphan_entry_ids") == [] else "blocked"},
"context_consistency": {"status": "verified" if lock.get("context_id") and regression.get("context_id") == lock.get("context_id") else "blocked", "context_id": lock.get("context_id")},
"release_stop_preserved": {"status": "verified" if stop_ok else "blocked", "release_action": "STOP_RELEASE" if stop_ok else None},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "configuration-resource-remediation.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-11",
"status": "complete" if checks_ok else "blocked",
"remediation_status": "blocked_resource_gaps",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"inputs": [
artifact(root, CONTEXT, "context_lock"),
artifact(root, RESOURCES, "config_resources"),
artifact(root, RESOURCE_REPORT, "config_resources_report"),
artifact(root, REGRESSION, "configuration_regression"),
artifact(root, GATE, "release_candidate_gate"),
artifact(root, INTAKE, "remediation_intake"),
],
"counts": {
"resource_rows": len(resource_rows),
"missing_rows": len(missing_rows),
"unresolved_rows": len(unresolved_rows),
"unindexed_configuration_entries": len(unindexed_entries),
"unregistered_startup_entries": len(unregistered_entries),
"candidate_basename_matches": sum(value for key, value in candidate_counts.items() if "candidate" in key),
"resolved_by_this_artifact": 0,
},
"candidate_classification": dict(sorted(candidate_counts.items())),
"missing_rows": missing_rows,
"unresolved_rows": unresolved_rows,
"unindexed_entries": sorted(unindexed_entries, key=lambda row: str(row.get("config_id"))),
"unregistered_entries": sorted(unregistered_entries, key=lambda row: str(row.get("config_id"))),
"checks": checks,
"review_policy": {
"required_to_unblock": ["resolve LIB/command/variable references against an approved search path", "restore or explicitly remove missing resource references with source review", "index every include/template entrypoint", "register or explicitly block each kinematics module"],
"forbidden": ["drop_missing_rows", "replace_missing_with_same_basename_without_contract", "reclassify_as_REAL-EXCLUDED", "promote_blocked_startup_to_ready", "overwrite_context_lock_in_place"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("configuration_resource_remediation=" + report["status"] + " release=" + report["release_action"] + " missing=" + str(report["counts"]["missing_rows"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""Generate deterministic K8-REL-13 implementation license remediation."""
from __future__ import annotations
import argparse
import hashlib
import json
import re
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
LICENSE_REPORT = Path("coverage/license-closure.report.json")
LICENSE_INDEX = Path("coverage/license-source-index.jsonl")
DECISION = Path("docs/linuxcnc-web-wasm-license-decision.md")
GATE = Path("coverage/release-candidate-gate.report.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
OUTPUT = Path("coverage/implementation-license-remediation.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def read_jsonl(root: Path, path: Path) -> tuple[list[dict[str, Any]], str | None]:
try:
rows = []
with (root / path).open(encoding="utf-8") as stream:
for line_number, line in enumerate(stream, 1):
if not line.strip():
continue
value = json.loads(line)
if not isinstance(value, dict):
raise ValueError(f"{path}:{line_number} must contain an object")
rows.append(value)
return rows, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return [], str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def source_declaration(root: Path, relative: str) -> dict[str, Any]:
path = root / relative
text = path.read_text(encoding="utf-8", errors="replace") if path.is_file() else ""
spdx = sorted(set(re.findall(r"SPDX-License-Identifier:\s*([^\s*]+)", text)))
notice = bool(re.search(r"\bNOTICE\b|copyright", text, re.IGNORECASE))
return {"spdx_identifiers": spdx, "copyright_or_notice_text": notice, "status": "declared" if spdx else "unassigned"}
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
lock, lock_error = read_json(root, CONTEXT)
license_report, license_report_error = read_json(root, LICENSE_REPORT)
gate, gate_error = read_json(root, GATE)
intake, intake_error = read_json(root, INTAKE)
license_rows, license_index_error = read_jsonl(root, LICENSE_INDEX)
errors = {
path.as_posix(): error
for path, error in ((CONTEXT, lock_error), (LICENSE_REPORT, license_report_error), (GATE, gate_error), (INTAKE, intake_error), (LICENSE_INDEX, license_index_error))
if error
}
implementation = [row for row in license_rows if row.get("source_root") in {"wasm-core", "web"}]
declarations = {row.get("source_path"): source_declaration(root, str(row.get("source_path"))) for row in implementation}
root_license_files = [path.relative_to(root).as_posix() for path in sorted(root.glob("LICENSE*")) if path.is_file()]
root_notice_files = [path.relative_to(root).as_posix() for path in sorted(root.glob("NOTICE*")) if path.is_file()]
source_hash_ok = all(row.get("source_hash_status") == "verified" for row in implementation)
all_unassigned = all(row.get("license_status") == "blocked_unassigned" and row.get("license_spdx") is None for row in implementation)
no_declarations = not root_license_files and not root_notice_files and all(not value["spdx_identifiers"] for value in declarations.values())
stop_ok = (
gate.get("release_action") == "STOP_RELEASE"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and intake.get("release_action") == "STOP_RELEASE"
and intake.get("candidate_eligible") is False
)
checks = {
"implementation_entry_coverage": {"status": "verified" if len(implementation) == 57 else "blocked", "entries": len(implementation)},
"source_hashes": {"status": "verified" if source_hash_ok else "blocked", "verified": sum(row.get("source_hash_status") == "verified" for row in implementation)},
"unassigned_status_preserved": {"status": "verified" if all_unassigned else "blocked", "blocked_unassigned": sum(row.get("license_status") == "blocked_unassigned" for row in implementation)},
"no_unapproved_declaration": {"status": "verified" if no_declarations else "blocked", "root_license_files": root_license_files, "root_notice_files": root_notice_files, "files_with_spdx": sum(bool(value["spdx_identifiers"]) for value in declarations.values())},
"upstream_not_inherited": {"status": "verified" if all(row.get("owner_source") == "implementation_license_decision" for row in implementation) else "blocked"},
"context_consistency": {"status": "verified" if lock.get("context_id") and license_report.get("context_id") == lock.get("context_id") and gate.get("context_id") == lock.get("context_id") else "blocked", "context_id": lock.get("context_id")},
"release_stop_preserved": {"status": "verified" if stop_ok else "blocked", "release_action": "STOP_RELEASE" if stop_ok else None},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
rows = [
{
"id": row.get("id"),
"source": row.get("source"),
"source_path": row.get("source_path"),
"source_sha256": row.get("source_sha256"),
"owner": row.get("owner"),
"review_owner": "license-audit-reviewer",
"license_status": row.get("license_status"),
"license_spdx": row.get("license_spdx"),
"declaration_audit": declarations.get(row.get("source_path")),
"remediation_status": "blocked_pending_owner_decision",
}
for row in sorted(implementation, key=lambda value: str(value.get("id")))
]
report: dict[str, Any] = {
"schema": "implementation-license-remediation.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-13",
"status": "complete" if checks_ok else "blocked",
"remediation_status": "blocked_pending_owner_decision",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"counts": {"implementation_entries": len(rows), "blocked_unassigned": sum(row["license_status"] == "blocked_unassigned" for row in rows), "approved_spdx": sum(bool(row["license_spdx"]) for row in rows), "approved_by_this_artifact": 0},
"checks": checks,
"inputs": [artifact(root, CONTEXT, "context_lock"), artifact(root, LICENSE_REPORT, "license_closure"), artifact(root, LICENSE_INDEX, "license_source_index"), artifact(root, DECISION, "license_decision"), artifact(root, GATE, "release_candidate_gate"), artifact(root, INTAKE, "remediation_intake")],
"entries": rows,
"decision_policy": {
"required_to_unblock": ["repository owner decision", "approved SPDX expression", "copyright/NOTICE policy", "distribution obligations review", "new context if metadata changes"],
"current_decision": "do not inherit LinuxCNC license declarations for wasm-core/web",
"forbidden": ["infer_upstream_license", "add_unapproved_spdx", "promote_blocked_unassigned", "delete_entries", "overwrite_context_lock_in_place"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("implementation_license_remediation=" + report["status"] + " release=" + report["release_action"] + " blocked=" + str(report["counts"]["blocked_unassigned"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,174 @@
#!/usr/bin/env python3
"""Generate the deterministic K8 milestone closeout record.
Closeout completion means the evidence package was audited and frozen with an
explicit release stop. It does not turn the blocked package into a candidate.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
AUDIT = Path("coverage/post-release-audit.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
CLOSURE = Path("coverage/release-closure.report.json")
INDEX = Path("coverage/release-evidence-index.json")
OUTPUT = Path("coverage/k8-milestone-closeout.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> dict[str, Any]:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
errors: dict[str, str] = {}
documents: dict[Path, dict[str, Any]] = {}
for path in (CONTEXT, AUDIT, GATE, CLOSURE, INDEX):
try:
documents[path] = read_json(root, path)
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
documents[path] = {}
errors[path.as_posix()] = str(exc)
lock = documents[CONTEXT]
audit = documents[AUDIT]
gate = documents[GATE]
closure = documents[CLOSURE]
index = documents[INDEX]
context_id = lock.get("context_id")
hash_rows = []
for path in (CONTEXT, AUDIT, GATE, CLOSURE, INDEX):
actual = file_digest(root / path)
hash_rows.append({"path": path.as_posix(), "sha256": actual, "status": "verified" if actual else "blocked"})
hash_ok = all(row["status"] == "verified" for row in hash_rows)
audit_report_hash = audit.get("report_sha256")
audit_report_hash_ok = bool(audit_report_hash) and audit_report_hash == digest({key: value for key, value in audit.items() if key != "report_sha256"})
stop_ok = (
gate.get("release_action") == "STOP_RELEASE"
and gate.get("release_decision") == "blocked_not_release_candidate"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and audit.get("release_action") == "STOP_RELEASE"
and audit.get("candidate_eligible") is False
and audit.get("blocked_count") == 6
)
context_ok = context_id and all(
report.get("context_id") in {None, context_id}
for report in (audit, gate, closure, index)
)
schema_versions = lock.get("schema_versions", {})
schema_ok = bool(schema_versions) and all(value == 1 for value in schema_versions.values())
audit_checks = audit.get("checks", {})
audit_checks_ok = all(value.get("status") == "verified" for value in audit_checks.values())
blocker_ids = {row.get("id") for row in audit.get("blockers", [])}
blocker_ok = len(blocker_ids) == 6 and all(row.get("status") == "blocked" for row in audit.get("blockers", []))
checks = {
"input_hashes": {"status": "verified" if hash_ok else "blocked", "artifacts": hash_rows},
"audit_self_hash": {"status": "verified" if audit_report_hash_ok else "blocked", "declared": audit_report_hash},
"context_consistency": {"status": "verified" if context_ok else "blocked", "context_id": context_id},
"locked_schema_contracts": {"status": "verified" if schema_ok else "blocked", "schema_versions": schema_versions},
"audit_checks": {"status": "verified" if audit_checks_ok else "blocked", "checks": {key: value.get("status") for key, value in audit_checks.items()}},
"stop_decision": {"status": "verified" if stop_ok else "blocked", "blocked_count": gate.get("blocked_count")},
"blocker_preservation": {"status": "verified" if blocker_ok else "blocked", "count": len(audit.get("blockers", [])), "ids": sorted(str(value) for value in blocker_ids)},
}
checks_ok = all(value["status"] == "verified" for value in checks.values()) and not errors
report: dict[str, Any] = {
"schema": "k8-milestone-closeout.v1",
"context_id": context_id,
"milestone": "K8",
"task_id": "K8-REL-06",
"status": "complete" if checks_ok else "blocked",
"milestone_status": "closed_with_release_blockers" if checks_ok else "closeout_blocked",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"source_baseline": {
"linuxcnc_version": lock.get("linuxcnc_version"),
"linuxcnc_source_sha": lock.get("linuxcnc_source_sha"),
"context_lock": artifact(root, CONTEXT, "context_lock"),
},
"inputs": [
artifact(root, AUDIT, "post_release_audit"),
artifact(root, GATE, "release_candidate_gate"),
artifact(root, CLOSURE, "release_closure"),
artifact(root, INDEX, "release_evidence_index"),
artifact(root, CONTEXT, "context_lock"),
],
"checks": checks,
"blockers": audit.get("blockers", []),
"blocked_count": len(audit.get("blockers", [])),
"rebuild": {
"commands": [
"python3 scripts/generate_release_closure.py",
"python3 scripts/generate_post_release_audit.py",
"python3 scripts/generate_k8_milestone_closeout.py",
"node web/worker/test_replay.mjs",
"node web/workspace/test_recovery.mjs",
"node web/workspace/test_migration.mjs",
"python3 -m unittest discover -s scripts -p 'test_*.py' -v",
],
"deterministic_inputs": [CONTEXT.as_posix(), AUDIT.as_posix(), GATE.as_posix(), CLOSURE.as_posix(), INDEX.as_posix()],
},
"failure_policy": {
"on_missing_input": "STOP_RELEASE",
"on_hash_mismatch": "STOP_RELEASE",
"forbidden": ["delete_samples", "lower_checks", "reclassify_as_REAL-EXCLUDED", "promote_blocked_to_accepted"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("k8_closeout=" + report["status"] + " action=" + report["release_action"] + " blockers=" + str(report["blocked_count"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,273 @@
#!/usr/bin/env python3
"""Generate deterministic ownership assignments for unassigned manifest seeds.
This report is deliberately additive. Manifest v1 has no owner field, so the
assignment is a reviewable workstream proposal and does not mutate the locked
manifest or context. Release eligibility remains blocked until the proposal
is reviewed and encoded in a new, explicitly versioned context.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
SOURCE_INDEX = Path("coverage/source-index.jsonl")
MANIFEST = Path("coverage/manifest.jsonl")
GATE = Path("coverage/release-candidate-gate.report.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
OUTPUT = Path("coverage/manifest-ownership-remediation.report.json")
OWNER_POLICIES = {
"ws-0-baseline-owner": {
"workstream": "WS-0",
"review_owner": "release-closure-owner",
"basis": "baseline, source inventory, or documentation path",
},
"ws-1-core-runtime-owner": {
"workstream": "WS-1",
"review_owner": "native-wasm-reviewer",
"basis": "core interpreter, task, TP, posemath, motion, or kinematics path",
},
"ws-2-worker-runtime-owner": {
"workstream": "WS-2",
"review_owner": "worker-runtime-reviewer",
"basis": "HAL, IO, virtual-device, or Worker path",
},
"ws-3-workspace-owner": {
"workstream": "WS-3",
"review_owner": "workspace-recovery-reviewer",
"basis": "workspace, journal, migration, or recovery path",
},
"ws-4-python-compat-owner": {
"workstream": "WS-4",
"review_owner": "python-security-reviewer",
"basis": "Python, remap, filter, or VCP compatibility path",
},
"ws-5-frontend-owner": {
"workstream": "WS-5",
"review_owner": "frontend-compatibility-reviewer",
"basis": "frontend or browser workflow path",
},
"ws-6-reference-test-owner": {
"workstream": "WS-6",
"review_owner": "reference-test-reviewer",
"basis": "test or unit-test path",
},
"ws-7-release-owner": {
"workstream": "WS-7",
"review_owner": "release-gate-owner",
"basis": "release-only evidence path",
},
}
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def read_jsonl(root: Path, path: Path) -> tuple[list[dict[str, Any]], str | None]:
try:
rows = []
with (root / path).open(encoding="utf-8") as stream:
for line_number, line in enumerate(stream, 1):
if not line.strip():
continue
value = json.loads(line)
if not isinstance(value, dict):
raise ValueError(f"{path}:{line_number} must contain an object")
rows.append(value)
return rows, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return [], str(exc)
def classify(source: str, kind: str) -> tuple[str, str]:
path = source.split(":", 1)[1] if ":" in source else source
if source.startswith(("build:", "doc:")):
return "ws-0-baseline-owner", "build/doc source prefix"
if source.startswith(("test:", "unit_test:")) or kind == "test":
return "ws-6-reference-test-owner", "test source prefix"
if path.startswith("wasm-core/"):
return "ws-1-core-runtime-owner", "wasm-core source prefix"
if path.startswith("web/worker/"):
return "ws-2-worker-runtime-owner", "web/worker source prefix"
if path.startswith("web/workspace/"):
return "ws-3-workspace-owner", "web/workspace source prefix"
if path.startswith("web/"):
return "ws-5-frontend-owner", "web source prefix"
if "/python/" in path or "/remap/" in path or "/vcp/" in path or path.startswith("linuxcnc/src/emc/python/"):
return "ws-4-python-compat-owner", "Python/remap/VCP path"
if (
path.startswith("linuxcnc/src/hal/")
or "/iotask/" in path
or "/io/" in path
or "/motion/" in path
or "/motioncontrol/" in path
):
return "ws-2-worker-runtime-owner", "HAL/IO/motion virtual-device path"
if path.startswith("linuxcnc/src/emc/") or path.startswith("linuxcnc/src/libnml/"):
return "ws-1-core-runtime-owner", "LinuxCNC core path"
if path.startswith("linuxcnc/src/"):
return "ws-1-core-runtime-owner", "LinuxCNC source path"
if path.startswith("linuxcnc/" ):
return "ws-0-baseline-owner", "LinuxCNC non-runtime path"
return "ws-7-release-owner", "unmatched release evidence path"
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
lock, lock_error = read_json(root, CONTEXT)
gate, gate_error = read_json(root, GATE)
intake, intake_error = read_json(root, INTAKE)
source_rows, source_error = read_jsonl(root, SOURCE_INDEX)
manifest_rows, manifest_error = read_jsonl(root, MANIFEST)
errors = {
path.as_posix(): error
for path, error in (
(CONTEXT, lock_error),
(GATE, gate_error),
(INTAKE, intake_error),
(SOURCE_INDEX, source_error),
(MANIFEST, manifest_error),
)
if error
}
source_by_id = {str(row.get("source_id")): row for row in source_rows}
rows: list[dict[str, Any]] = []
owner_counts: dict[str, int] = {}
all_valid = not errors and len(source_rows) == len(manifest_rows)
for manifest in manifest_rows:
if manifest.get("mapping_status") != "needs_owner":
continue
source = str(manifest.get("source", ""))
owner, rule = classify(source, str(manifest.get("kind", "")))
policy = OWNER_POLICIES[owner]
source_row = source_by_id.get(source)
source_match = bool(source_row) and source_row.get("sha256") == manifest.get("source_sha")
valid = bool(manifest.get("id")) and bool(source_row) and source_match
row = {
"id": manifest.get("id"),
"source": source,
"source_sha": manifest.get("source_sha"),
"kind": manifest.get("kind"),
"owner": owner,
"owner_type": "workstream_role",
"workstream": policy["workstream"],
"review_owner": policy["review_owner"],
"assignment_rule": rule,
"assignment_basis": policy["basis"],
"original_mapping_status": manifest.get("mapping_status"),
"assignment_status": "proposed_blocked_review" if valid else "blocked_invalid_source",
"release_status": "blocked",
"evidence_status": "source_hash_verified" if valid else "blocked",
}
rows.append(row)
owner_counts[owner] = owner_counts.get(owner, 0) + 1
all_valid = all_valid and valid
rows.sort(key=lambda row: str(row["id"]))
expected_ids = sorted(str(row.get("id")) for row in manifest_rows if row.get("mapping_status") == "needs_owner")
observed_ids = sorted(str(row.get("id")) for row in rows)
coverage_ok = expected_ids == observed_ids and len(observed_ids) == len(set(observed_ids))
stop_ok = (
gate.get("release_action") == "STOP_RELEASE"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and intake.get("release_action") == "STOP_RELEASE"
and intake.get("candidate_eligible") is False
)
checks = {
"manifest_source_coverage": {"status": "verified" if coverage_ok else "blocked", "expected": len(expected_ids), "observed": len(observed_ids)},
"source_hashes": {"status": "verified" if all_valid else "blocked", "verified": sum(row["evidence_status"] == "source_hash_verified" for row in rows)},
"deterministic_owner_policy": {"status": "verified" if all(row["owner"] in OWNER_POLICIES for row in rows) else "blocked", "owners": owner_counts},
"context_consistency": {"status": "verified" if lock.get("context_id") and intake.get("context_id") == lock.get("context_id") else "blocked", "context_id": lock.get("context_id")},
"release_stop_preserved": {"status": "verified" if stop_ok else "blocked", "release_action": "STOP_RELEASE" if stop_ok else None},
"manifest_unchanged": {"status": "verified", "reason": "manifest v1 has no owner field; proposal is additive and requires review before encoding"},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "manifest-ownership-remediation.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-08",
"status": "complete" if checks_ok else "blocked",
"remediation_status": "blocked_pending_manifest_review",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"source_baseline": {"linuxcnc_version": lock.get("linuxcnc_version"), "linuxcnc_source_sha": lock.get("linuxcnc_source_sha")},
"inputs": [
artifact(root, CONTEXT, "context_lock"),
artifact(root, SOURCE_INDEX, "source_index"),
artifact(root, MANIFEST, "manifest_seed"),
artifact(root, GATE, "release_candidate_gate"),
artifact(root, INTAKE, "remediation_intake"),
],
"counts": {"manifest_total": len(manifest_rows), "needs_owner": len(rows), "mapped": len(rows), "accepted_by_this_artifact": 0},
"owner_counts": dict(sorted(owner_counts.items())),
"checks": checks,
"assignments": rows,
"review_policy": {
"owner_semantics": "workstream role proposal; not a named human approval",
"required_before_manifest_update": ["feature owner confirmation", "feature_id/test_id/oracle evidence", "new context_id if manifest hash changes"],
"forbidden": ["promote_to_accepted", "delete_unassigned_rows", "reclassify_as_REAL-EXCLUDED", "overwrite_context_lock_in_place"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("manifest_ownership_remediation=" + report["status"] + " release=" + report["release_action"] + " mapped=" + str(report["counts"]["mapped"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,170 @@
#!/usr/bin/env python3
"""Audit locked official kinematics/recovery oracle inputs for K8-REL-10."""
from __future__ import annotations
import argparse
import hashlib
import json
import subprocess
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
KIN_CLOSURE = Path("coverage/kinematics-source-closure.report.json")
KIN_ORACLE = Path("coverage/kinematics-oracle.report.json")
RECOVERY = Path("coverage/workspace-recovery.report.json")
COMPATIBILITY = Path("coverage/compatibility-matrix.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
OUTPUT = Path("coverage/official-oracle-remediation.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def locked_path_exists(root: Path, relative: str) -> bool:
try:
result = subprocess.run(
["git", "-C", str(root / "linuxcnc"), "cat-file", "-e", f"HEAD:{relative}"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
check=False,
)
except OSError:
return False
return result.returncode == 0
def locked_head(root: Path) -> str | None:
try:
return subprocess.check_output(["git", "-C", str(root / "linuxcnc"), "rev-parse", "HEAD"], text=True).strip()
except (OSError, subprocess.CalledProcessError):
return None
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
paths = (CONTEXT, KIN_CLOSURE, KIN_ORACLE, RECOVERY, COMPATIBILITY, GATE, INTAKE)
documents: dict[Path, dict[str, Any]] = {}
errors: dict[str, str] = {}
for path in paths:
documents[path], error = read_json(root, path)
if error:
errors[path.as_posix()] = error
lock = documents[CONTEXT]
closure = documents[KIN_CLOSURE]
oracle = documents[KIN_ORACLE]
recovery = documents[RECOVERY]
compatibility = documents[COMPATIBILITY]
gate = documents[GATE]
intake = documents[INTAKE]
context_id = lock.get("context_id")
source_sha = lock.get("linuxcnc_source_sha")
actual_head = locked_head(root)
kin_root = "linuxcnc/unit_tests/kinematics"
recovery_roots = ["linuxcnc/unit_tests/recovery", "linuxcnc/tests/recovery"]
kin_present = locked_path_exists(root, kin_root)
recovery_present = {path: locked_path_exists(root, path) for path in recovery_roots}
matrixkins = closure.get("tests", {}).get("files", []) if isinstance(closure.get("tests"), dict) else []
matrixkins_candidate = [
{"path": row.get("path"), "sha256": row.get("sha256"), "official_unit_test": row.get("official_unit_test")}
for row in matrixkins
]
recovery_oracle = recovery.get("oracle", {})
checks = {
"locked_source_commit": {"status": "verified" if source_sha and actual_head == source_sha else "blocked", "expected": source_sha, "actual": actual_head},
"kinematics_official_root": {"status": "verified" if not kin_present and kin_root in closure.get("missing_required_test_roots", []) else "blocked", "path": kin_root, "present": kin_present},
"recovery_official_root": {"status": "verified" if not any(recovery_present.values()) and recovery_oracle.get("status") == "blocked" else "blocked", "paths": recovery_present},
"candidate_tests_not_promoted": {"status": "verified" if matrixkins_candidate and all(row.get("official_unit_test") is False for row in matrixkins_candidate) else "blocked", "count": len(matrixkins_candidate)},
"no_official_goldens_generated": {"status": "verified" if oracle.get("ready_count") == 0 and oracle.get("status") == "blocked" else "blocked", "ready_count": oracle.get("ready_count"), "oracle_status": oracle.get("status")},
"release_stop_preserved": {"status": "verified" if gate.get("release_action") == "STOP_RELEASE" and gate.get("candidate_eligible") is False and gate.get("blocked_count") == 6 and intake.get("release_action") == "STOP_RELEASE" else "blocked", "release_action": "STOP_RELEASE" if gate.get("release_action") == "STOP_RELEASE" else None},
"context_consistency": {"status": "verified" if context_id and compatibility.get("context_id") == context_id and gate.get("context_id") == context_id else "blocked", "context_id": context_id},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "official-oracle-remediation.v1",
"context_id": context_id,
"task_id": "K8-REL-10",
"status": "complete" if checks_ok else "blocked",
"remediation_status": "blocked_missing_locked_inputs",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"locked_source": {
"linuxcnc_source_sha": source_sha,
"actual_head": actual_head,
"kinematics_root": {"path": kin_root, "present": kin_present},
"recovery_roots": recovery_present,
},
"oracle_inventory": {
"kinematics_samples": oracle.get("sample_count", 0),
"kinematics_ready": oracle.get("ready_count", 0),
"kinematics_blocked": oracle.get("blocked_count", 0),
"recovery_blocked_samples": recovery_oracle.get("blocked_samples", []),
"matrixkins_candidate_files": matrixkins_candidate,
"official_inputs_added": 0,
"official_goldens_added": 0,
},
"checks": checks,
"inputs": [artifact(root, path, path.stem.replace("-", "_")) for path in paths],
"review_policy": {
"required_to_unblock": ["official kinematics unit-test root in a locked source", "official recovery oracle inputs or approved contract replacement", "native/WASM comparison rerun", "new context_id if source or schema changes"],
"forbidden": ["promote_matrixkins_to_official", "generate_fake_goldens", "delete_blocked_samples", "lower_tolerances", "overwrite_context_lock_in_place"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("official_oracle_remediation=" + report["status"] + " release=" + report["release_action"] + " added=" + str(report["oracle_inventory"]["official_inputs_added"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""Record the K8-REL-15 owner-review gate refresh and fail closed if inputs are absent."""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
ROUNDUP = Path("coverage/remediation-evidence-roundup.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
AUDIT = Path("coverage/post-release-audit.report.json")
OUTPUT = Path("coverage/owner-review-gate-refresh.report.json")
DECISIONS = (
("manifest_seed_unassigned", "approve manifest ownership mapping and any new context"),
("accepted_entries_missing", "supply acceptance evidence with a ready official oracle"),
("official_oracle_missing", "add or approve locked kinematics and recovery oracle inputs"),
("configuration_resources_missing", "review and resolve configuration resource candidates"),
("browser_matrix_unverified", "approve minimums and execute the three-browser matrix"),
("license_closure_incomplete", "approve SPDX/NOTICE policy for Web/WASM implementation"),
)
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
lock, lock_error = read_json(root, CONTEXT)
roundup, roundup_error = read_json(root, ROUNDUP)
gate, gate_error = read_json(root, GATE)
audit, audit_error = read_json(root, AUDIT)
errors = {path.as_posix(): error for path, error in ((CONTEXT, lock_error), (ROUNDUP, roundup_error), (GATE, gate_error), (AUDIT, audit_error)) if error}
blocker_ids = {row.get("id") for row in audit.get("blockers", []) if isinstance(row, dict)}
decisions = [
{"blocker": blocker, "required_action": action, "owner_input": "missing", "status": "blocked"}
for blocker, action in DECISIONS
]
checks = {
"roundup_complete": {"status": "verified" if roundup.get("status") == "complete" and roundup.get("roundup_status") == "blocked_pending_owner_actions" else "blocked"},
"six_decisions_located": {"status": "verified" if len(decisions) == 6 and blocker_ids == {row["blocker"] for row in decisions} else "blocked", "count": len(decisions)},
"owner_inputs_present": {"status": "blocked", "present": 0, "required": 6, "reason": "no owner approval or new locked input is present in the workspace"},
"gate_refresh_allowed": {"status": "blocked", "reason": "refresh is forbidden until owner inputs and any new context are reviewed"},
"release_stop_preserved": {"status": "verified" if gate.get("release_action") == "STOP_RELEASE" and audit.get("release_action") == "STOP_RELEASE" and gate.get("candidate_eligible") is False and audit.get("candidate_eligible") is False else "blocked", "release_action": "STOP_RELEASE" if gate.get("release_action") == "STOP_RELEASE" else None},
"context_consistency": {"status": "verified" if lock.get("context_id") and roundup.get("context_id") == lock.get("context_id") else "blocked", "context_id": lock.get("context_id")},
}
report: dict[str, Any] = {
"schema": "owner-review-gate-refresh.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-15",
"status": "blocked",
"review_status": "owner_input_required",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"inputs": [artifact(root, CONTEXT, "context_lock"), artifact(root, ROUNDUP, "remediation_roundup"), artifact(root, GATE, "release_candidate_gate"), artifact(root, AUDIT, "post_release_audit")],
"checks": checks,
"decisions": decisions,
"next_transition": "collect owner decisions, create a new context when locked inputs change, then regenerate closure/audit/gate",
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("owner_review_gate_refresh=" + report["status"] + " action=" + report["release_action"] + " decisions=" + str(len(report["decisions"])))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,422 @@
#!/usr/bin/env python3
"""Generate the deterministic K8-REL-05 post-release audit.
The audit is deliberately additive. It reads the K8-REL-04 gate and its
inputs, compares every recorded artifact hash with the current workspace,
and records drift as a blocker. It never rewrites release evidence.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
GATE = Path("coverage/release-candidate-gate.report.json")
AUDIT = Path("coverage/post-release-audit.report.json")
BLOCKER_METADATA: dict[str, dict[str, Any]] = {
"manifest_seed_unassigned": {
"owner": "manifest-feature-ownership",
"review_owner": "release-closure-owner",
"evidence": [
"coverage/release-evidence-index.json",
"coverage/manifest.jsonl",
],
"remediation": "assign an accountable feature owner to every needs_owner manifest seed and regenerate the evidence index",
"review_trigger": "manifest mapping changes or the release closure is regenerated",
},
"accepted_entries_missing": {
"owner": "release-acceptance-owner",
"review_owner": "release-gate-owner",
"evidence": [
"coverage/release-evidence-index.json",
"coverage/release-candidate-gate.report.json",
],
"remediation": "complete acceptance evidence for eligible entries; do not promote blocked or derived entries by relabeling",
"review_trigger": "any entry changes to accepted or the acceptance policy changes",
},
"official_oracle_missing": {
"owner": "upstream-oracle-owner",
"review_owner": "kinematics-recovery-reviewer",
"evidence": [
"coverage/compatibility-matrix.report.json",
"coverage/kinematics-oracle.report.json",
"coverage/workspace-recovery.report.json",
],
"remediation": "add the locked official kinematics and recovery oracle inputs, then rerun the native/WASM comparison",
"review_trigger": "the locked source gains or changes an official oracle root",
},
"configuration_resources_missing": {
"owner": "configuration-closure-owner",
"review_owner": "configuration-regression-reviewer",
"evidence": [
"coverage/compatibility-matrix.report.json",
"coverage/configuration-regression.report.json",
],
"remediation": "resolve missing and unindexed configuration resources and unregistered startup references without dropping rows",
"review_trigger": "configuration graph or startup preflight counts change",
},
"browser_matrix_unverified": {
"owner": "browser-compatibility-owner",
"review_owner": "release-gate-owner",
"evidence": [
"coverage/compatibility-matrix.report.json",
"context-lock.json",
],
"remediation": "pin minimum Chromium, Firefox and Safari versions in the locked browser matrix and execute the required checks",
"review_trigger": "browser minimums or cross-origin isolation policy changes",
},
"license_closure_incomplete": {
"owner": "implementation-license-owner",
"review_owner": "license-audit-reviewer",
"evidence": [
"coverage/license-closure.report.json",
"coverage/license-source-index.jsonl",
"docs/linuxcnc-web-wasm-license-decision.md",
],
"remediation": "approve SPDX/NOTICE metadata for all 57 Web/WASM implementation entries; upstream declarations do not substitute for it",
"review_trigger": "implementation license metadata or source-root ownership changes",
},
}
REQUIRED_CONTEXT_REPORTS = (
GATE,
Path("coverage/release-closure.report.json"),
Path("coverage/release-evidence-index.json"),
Path("coverage/compatibility-matrix.report.json"),
Path("coverage/license-closure.report.json"),
Path("coverage/workspace-recovery.report.json"),
Path("coverage/workspace-migration.report.json"),
)
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> dict[str, Any]:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value
def try_read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
return read_json(root, path), None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
actual = file_digest(full)
if actual is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {
"path": path.as_posix(),
"role": role,
"status": "present",
"bytes": full.stat().st_size,
"sha256": actual,
}
def report_hash_check(path: Path, report: dict[str, Any], error: str | None) -> dict[str, Any]:
declared = report.get("report_sha256")
if error is None and declared is None and report:
return {
"path": path.as_posix(),
"declared": None,
"actual": None,
"status": "verified",
"hash_policy": "not_declared_by_legacy_schema",
}
actual = digest({key: value for key, value in report.items() if key != "report_sha256"}) if report else None
status = "verified" if error is None and declared and declared == actual else "blocked"
return {
"path": path.as_posix(),
"declared": declared,
"actual": actual,
"status": status,
**({"error": error} if error else {}),
}
def compare_gate_inputs(root: Path, gate: dict[str, Any]) -> tuple[list[dict[str, Any]], bool]:
if not gate or not isinstance(gate.get("inputs"), list):
return [], False
comparisons: list[dict[str, Any]] = []
all_match = True
for expected in gate.get("inputs", []):
path_text = expected.get("path")
if not isinstance(path_text, str):
comparisons.append({"path": None, "status": "blocked", "reason": "gate input has no path"})
all_match = False
continue
path = Path(path_text)
full = root / path
actual_sha = file_digest(full)
actual_bytes = full.stat().st_size if full.is_file() else None
matches = (
actual_sha is not None
and actual_sha == expected.get("sha256")
and actual_bytes == expected.get("bytes")
)
comparison = {
"path": path.as_posix(),
"role": expected.get("role"),
"expected_sha256": expected.get("sha256"),
"actual_sha256": actual_sha,
"expected_bytes": expected.get("bytes"),
"actual_bytes": actual_bytes,
"status": "verified" if matches else "blocked",
}
comparisons.append(comparison)
all_match = all_match and matches
return comparisons, all_match
def context_check(root: Path, lock: dict[str, Any], reports: dict[Path, dict[str, Any]]) -> dict[str, Any]:
context_id = lock.get("context_id")
observations = []
all_match = bool(context_id)
for path in REQUIRED_CONTEXT_REPORTS:
report = reports.get(path, {})
observed = report.get("context_id")
declared = observed is not None
matches = not declared or observed == context_id
observations.append({
"path": path.as_posix(),
"context_id": observed,
"context_declared": declared,
"status": "verified" if matches else "blocked",
})
all_match = all_match and matches
return {
"context_id": context_id,
"reports": observations,
"status": "verified" if all_match else "blocked",
"all_declared_context_ids_match": all_match,
"absent_context_id_policy": "allowed only for legacy reports covered by the K8-REL-04 gate",
}
def cross_reference_check(
root: Path,
lock: dict[str, Any],
gate: dict[str, Any],
closure: dict[str, Any],
index: dict[str, Any],
compatibility: dict[str, Any],
license_report: dict[str, Any],
migration: dict[str, Any],
) -> dict[str, Any]:
checks: list[dict[str, Any]] = []
def check(name: str, expected: Any, actual: Any, evidence: str) -> None:
checks.append({
"name": name,
"expected": expected,
"actual": actual,
"evidence": evidence,
"status": "verified" if expected == actual else "blocked",
})
check("gate_context_id", lock.get("context_id"), gate.get("context_id"), GATE.as_posix())
check("closure_context_id", lock.get("context_id"), closure.get("context_id"), "coverage/release-closure.report.json")
check("evidence_index_context_id", lock.get("context_id"), index.get("context_id"), "coverage/release-evidence-index.json")
check("compatibility_context_id", lock.get("context_id"), compatibility.get("context_id"), "coverage/compatibility-matrix.report.json")
check("license_context_id", lock.get("context_id"), license_report.get("context_id"), "coverage/license-closure.report.json")
check("migration_context_id", lock.get("context_id"), migration.get("context_id"), "coverage/workspace-migration.report.json")
check("context_lock_hash", file_digest(root / CONTEXT), index.get("context_lock", {}).get("sha256"), "coverage/release-evidence-index.json")
check("closure_compatibility_report_hash", compatibility.get("report_sha256"), closure.get("compatibility", {}).get("sha256"), "coverage/release-closure.report.json")
check("closure_license_report_hash", license_report.get("report_sha256"), closure.get("license", {}).get("sha256"), "coverage/release-closure.report.json")
check("closure_evidence_index_report_hash", index.get("report_sha256"), closure.get("evidence_index", {}).get("sha256"), "coverage/release-closure.report.json")
check("index_compatibility_report_hash", compatibility.get("report_sha256"), index.get("compatibility_report", {}).get("sha256"), "coverage/release-evidence-index.json")
check("index_license_report_hash", license_report.get("report_sha256"), index.get("license_report", {}).get("sha256"), "coverage/release-evidence-index.json")
check("index_migration_report_hash", file_digest(root / Path("coverage/workspace-migration.report.json")), index.get("migration_report", {}).get("sha256"), "coverage/release-evidence-index.json")
check("recovery_hash_lock", lock.get("workspace_recovery_report_sha256"), file_digest(root / Path("coverage/workspace-recovery.report.json")), GATE.as_posix())
check("gate_release_action", "STOP_RELEASE", gate.get("release_action"), GATE.as_posix())
check("gate_candidate_eligible", False, gate.get("candidate_eligible"), GATE.as_posix())
check("gate_release_decision", "blocked_not_release_candidate", gate.get("release_decision"), GATE.as_posix())
check("gate_blocked_count", 6, gate.get("blocked_count"), GATE.as_posix())
status = "verified" if all(item["status"] == "verified" for item in checks) else "blocked"
return {"status": status, "checks": checks}
def blocker_review(root: Path, gate: dict[str, Any]) -> tuple[list[dict[str, Any]], dict[str, Any]]:
blockers = []
all_locatable = True
gate_blockers = gate.get("blockers", [])
for blocker in gate_blockers:
blocker_id = blocker.get("id")
metadata = BLOCKER_METADATA.get(blocker_id, {})
evidence = metadata.get("evidence", [])
evidence_status = all((root / Path(path)).is_file() for path in evidence)
row = {
"id": blocker_id,
"count": blocker.get("count"),
"status": blocker.get("status"),
"reason": blocker.get("reason"),
"owner": metadata.get("owner"),
"review_owner": metadata.get("review_owner"),
"evidence": [
{"path": path, "status": "present" if (root / Path(path)).is_file() else "missing"}
for path in evidence
],
"remediation": metadata.get("remediation"),
"review_trigger": metadata.get("review_trigger"),
"status_check": "verified" if blocker.get("status") == "blocked" else "blocked",
"evidence_check": "verified" if evidence_status else "blocked",
}
blockers.append(row)
all_locatable = all_locatable and bool(blocker_id) and blocker.get("status") == "blocked" and bool(metadata) and evidence_status
expected_ids = set(BLOCKER_METADATA)
actual_ids = {row.get("id") for row in gate_blockers}
identity_preserved = len(gate_blockers) == 6 and actual_ids == expected_ids
return blockers, {
"status": "verified" if all_locatable and identity_preserved else "blocked",
"all_blockers_locatable": all_locatable,
"identity_preserved": identity_preserved,
"expected_count": 6,
"observed_count": len(gate_blockers),
"observed_ids": sorted(str(value) for value in actual_ids),
}
def generate(root: Path, output: Path = AUDIT) -> dict[str, Any]:
root = root.resolve()
gate, gate_error = try_read_json(root, GATE)
lock, lock_error = try_read_json(root, CONTEXT)
reports: dict[Path, dict[str, Any]] = {}
report_errors: dict[Path, str | None] = {}
for path in REQUIRED_CONTEXT_REPORTS:
reports[path], report_errors[path] = try_read_json(root, path)
closure = reports.get(Path("coverage/release-closure.report.json"), {})
index = reports.get(Path("coverage/release-evidence-index.json"), {})
compatibility = reports.get(Path("coverage/compatibility-matrix.report.json"), {})
license_report = reports.get(Path("coverage/license-closure.report.json"), {})
migration = reports.get(Path("coverage/workspace-migration.report.json"), {})
input_comparisons, inputs_match = compare_gate_inputs(root, gate)
context = context_check(root, lock, reports)
cross_refs = cross_reference_check(root, lock, gate, closure, index, compatibility, license_report, migration)
blocker_rows, blocker_checks = blocker_review(root, gate)
report_hashes = [
report_hash_check(path, reports[path], report_errors[path])
for path in REQUIRED_CONTEXT_REPORTS
] + [report_hash_check(GATE, gate, gate_error)]
report_hashes_ok = all(item["status"] == "verified" for item in report_hashes)
gate_checks = gate.get("checks", {}) if gate else {}
gate_check_integrity = {
"context_consistency": gate_checks.get("context_consistency", {}).get("status") == "verified",
"locked_schema_contracts": gate_checks.get("locked_schema_contracts", {}).get("status") == "verified",
"evidence_integrity": gate_checks.get("evidence_integrity", {}).get("status") == "verified",
"license_source_index": gate_checks.get("license_source_index", {}).get("status") == "verified",
"migration_rollback_offline": gate_checks.get("migration_rollback_offline", {}).get("status") == "verified",
"release_prerequisites_blocked": gate_checks.get("release_prerequisites", {}).get("status") == "blocked",
}
gate_check_status = "verified" if all(gate_check_integrity.values()) else "blocked"
generated_at = lock.get("generated_at") if lock else None
checks = {
"input_hashes": {
"status": "verified" if inputs_match else "blocked",
"all_match": inputs_match,
"comparisons": input_comparisons,
},
"report_self_hashes": {
"status": "verified" if report_hashes_ok else "blocked",
"reports": report_hashes,
},
"context_consistency": context,
"cross_references": cross_refs,
"gate_checks": {
"status": gate_check_status,
"checks": gate_check_integrity,
},
"blocker_review": blocker_checks,
}
check_statuses = [value.get("status") for value in checks.values()]
audit_checks_pass = not any(value != "verified" for value in check_statuses)
gate_stop = gate.get("release_action") == "STOP_RELEASE" or gate.get("candidate_eligible") is False
status = "blocked" if not audit_checks_pass or gate_stop else "passed"
report: dict[str, Any] = {
"schema": "post-release-audit.v1",
"context_id": lock.get("context_id"),
"audit_id": "K8-REL-05",
"generated_at": generated_at,
"status": status,
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"source_baseline": {
"linuxcnc_version": lock.get("linuxcnc_version"),
"linuxcnc_source_sha": lock.get("linuxcnc_source_sha"),
"context_lock": artifact(root, CONTEXT, "context_lock"),
},
"inputs": [artifact(root, GATE, "release_candidate_gate"), artifact(root, CONTEXT, "context_lock")],
"input_hash_comparison": input_comparisons,
"checks": checks,
"blockers": blocker_rows,
"blocked_count": len(blocker_rows),
"rebuild": {
"commands": [
"python3 scripts/generate_post_release_audit.py",
"python3 scripts/generate_release_closure.py",
"node web/worker/test_replay.mjs",
"node web/workspace/test_recovery.mjs",
"node web/workspace/test_migration.mjs",
"python3 -m unittest discover -s scripts -p 'test_*.py' -v",
],
"deterministic_inputs": [path.as_posix() for path in REQUIRED_CONTEXT_REPORTS]
+ [GATE.as_posix(), CONTEXT.as_posix(), "coverage/license-source-index.jsonl", "coverage/workspace-rollback.package.json", "coverage/offline-cache.package.json", "docs/linuxcnc-web-wasm-license-decision.md"],
},
"failure_policy": {
"on_missing_input": "STOP_RELEASE",
"on_hash_mismatch": "STOP_RELEASE",
"on_context_drift": "STOP_RELEASE",
"forbidden": ["delete_samples", "lower_checks", "reclassify_as_REAL-EXCLUDED", "promote_blocked_to_accepted"],
},
"errors": {path.as_posix(): error for path, error in [(GATE, gate_error), (CONTEXT, lock_error), *report_errors.items()] if error},
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=AUDIT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("post_release_audit=" + report["status"] + " action=" + report["release_action"] + " blockers=" + str(report["blocked_count"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,202 @@
#!/usr/bin/env python3
"""Generate deterministic acceptance-readiness evidence for K8-REL-09."""
from __future__ import annotations
import argparse
import hashlib
import json
from collections import Counter
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
MANIFEST = Path("coverage/manifest.jsonl")
INDEX = Path("coverage/release-evidence-index.json")
GATE = Path("coverage/release-candidate-gate.report.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
OWNERSHIP = Path("coverage/manifest-ownership-remediation.report.json")
OUTPUT = Path("coverage/release-acceptance-remediation.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def read_jsonl(root: Path, path: Path) -> tuple[list[dict[str, Any]], str | None]:
try:
rows = []
with (root / path).open(encoding="utf-8") as stream:
for line_number, line in enumerate(stream, 1):
if not line.strip():
continue
value = json.loads(line)
if not isinstance(value, dict):
raise ValueError(f"{path}:{line_number} must contain an object")
rows.append(value)
return rows, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return [], str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
lock, lock_error = read_json(root, CONTEXT)
index, index_error = read_json(root, INDEX)
gate, gate_error = read_json(root, GATE)
intake, intake_error = read_json(root, INTAKE)
ownership, ownership_error = read_json(root, OWNERSHIP)
manifest, manifest_error = read_jsonl(root, MANIFEST)
errors = {
path.as_posix(): error
for path, error in (
(CONTEXT, lock_error),
(INDEX, index_error),
(GATE, gate_error),
(INTAKE, intake_error),
(OWNERSHIP, ownership_error),
(MANIFEST, manifest_error),
)
if error
}
affected = index.get("affected_manifest_entries", []) if isinstance(index.get("affected_manifest_entries"), list) else []
manifest_accepted = [
row for row in manifest
if row.get("sim_status") == "accepted" or row.get("web_status") == "accepted"
]
readiness_reasons: Counter[str] = Counter()
ready_rows = []
blocked_rows = []
for row in affected:
reasons = []
if not row.get("owner"):
reasons.append("owner_missing")
if not row.get("inputs"):
reasons.append("inputs_missing")
if not row.get("outputs"):
reasons.append("outputs_missing")
if not row.get("test_id"):
reasons.append("test_missing")
if row.get("oracle_status") != "ready":
reasons.append("oracle_blocked")
if row.get("context_id") != lock.get("context_id"):
reasons.append("context_missing_or_mismatch")
if reasons:
blocked_rows.append({"id": row.get("id"), "reasons": reasons})
readiness_reasons.update(reasons)
else:
ready_rows.append(row.get("id"))
unassigned = sum(1 for row in manifest if row.get("mapping_status") == "needs_owner")
ownership_count = ownership.get("counts", {}).get("mapped")
coverage_ok = (
len(manifest) == 8053
and len(affected) == 1804
and unassigned == 6249
and ownership_count == 6249
and len(ready_rows) == 0
and len(blocked_rows) == len(affected)
)
stop_ok = (
gate.get("release_action") == "STOP_RELEASE"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and intake.get("release_action") == "STOP_RELEASE"
and intake.get("candidate_eligible") is False
)
no_promotion = len(manifest_accepted) == 0 and all(row.get("oracle_status") == "blocked" for row in affected)
checks = {
"input_shape": {"status": "verified" if coverage_ok else "blocked", "manifest_total": len(manifest), "affected": len(affected)},
"acceptance_readiness": {"status": "verified" if len(ready_rows) == 0 else "blocked", "eligible_count": len(ready_rows), "blocked_count": len(blocked_rows), "reasons": dict(sorted(readiness_reasons.items()))},
"no_promotion": {"status": "verified" if no_promotion else "blocked", "manifest_accepted": len(manifest_accepted), "affected_oracle_blocked": all(row.get("oracle_status") == "blocked" for row in affected)},
"ownership_dependency": {"status": "verified" if ownership_count == 6249 and ownership.get("remediation_status") == "blocked_pending_manifest_review" else "blocked", "mapped": ownership_count},
"context_consistency": {"status": "verified" if lock.get("context_id") and index.get("context_id") == lock.get("context_id") else "blocked", "context_id": lock.get("context_id")},
"release_stop_preserved": {"status": "verified" if stop_ok else "blocked", "release_action": "STOP_RELEASE" if stop_ok else None},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "release-acceptance-remediation.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-09",
"status": "complete" if checks_ok else "blocked",
"remediation_status": "blocked_no_eligible_entries",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"inputs": [
artifact(root, CONTEXT, "context_lock"),
artifact(root, MANIFEST, "manifest_seed"),
artifact(root, INDEX, "release_evidence_index"),
artifact(root, OWNERSHIP, "manifest_ownership_remediation"),
artifact(root, GATE, "release_candidate_gate"),
artifact(root, INTAKE, "remediation_intake"),
],
"counts": {
"manifest_total": len(manifest),
"manifest_accepted": len(manifest_accepted),
"manifest_needs_owner": unassigned,
"affected_entries": len(affected),
"eligible_for_acceptance": len(ready_rows),
"blocked_for_acceptance": len(blocked_rows),
},
"blocked_reason_counts": dict(sorted(readiness_reasons.items())),
"blocked_entry_ids": sorted(str(row["id"]) for row in blocked_rows),
"checks": checks,
"acceptance_policy": {
"required": ["owner", "inputs", "outputs", "test_id", "ready oracle", "matching context_id", "implementation and difference evidence"],
"forbidden": ["promote_blocked_to_accepted", "promote_derived_to_accepted", "delete_samples", "lower_checks", "reclassify_as_REAL-EXCLUDED"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("release_acceptance_remediation=" + report["status"] + " release=" + report["release_action"] + " eligible=" + str(report["counts"]["eligible_for_acceptance"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,729 @@
#!/usr/bin/env python3
"""Build deterministic K8 compatibility, license and release evidence reports.
The reports intentionally distinguish a verified implementation slice from a
release-acceptable result. Missing upstream oracles, source metadata, browser
coverage and unassigned manifest seeds stay visible blockers; no derived
configuration result is promoted to an accepted golden.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import re
from collections import Counter
from fnmatch import fnmatchcase
from pathlib import Path
from typing import Any, Iterable
CONTEXT = Path("context-lock.json")
SOURCE_INDEX = Path("coverage/source-index.jsonl")
MANIFEST = Path("coverage/manifest.jsonl")
CONFIGURATION = Path("coverage/configuration-regression.report.json")
PYTHON_MANIFEST = Path("python-runtime/manifest.json")
PYTHON_REPORT = Path("coverage/python-runtime.report.json")
DOWNLOAD_INDEX = Path("vendor/downloads/index.jsonl")
FULL_PORT_DOC = Path("docs/linuxcnc-web-wasm-full-port-implementation.md")
LICENSE_INDEX = Path("coverage/license-source-index.jsonl")
IMPLEMENTATION_LICENSE_DECISION = Path("docs/linuxcnc-web-wasm-license-decision.md")
REPORT_PATHS = (
"coverage/configuration-regression.report.json",
"coverage/corexy-hal.report.json",
"coverage/coupled-kinematics.report.json",
"coverage/delta-kinematics.report.json",
"coverage/fiveaxis-kinematics.report.json",
"coverage/golden-schema.json",
"coverage/genhex-kinematics.report.json",
"coverage/genser-kinematics.report.json",
"coverage/hal-runtime.report.json",
"coverage/interpreter-runtime.report.json",
"coverage/io-runtime.report.json",
"coverage/kinematics-abi-contract.json",
"coverage/kinematics-feedback.report.json",
"coverage/kinematics-golden-schema.json",
"coverage/kinematics-home-limit.report.json",
"coverage/kinematics-motion.report.json",
"coverage/kinematics-mapping-contract.json",
"coverage/kinematics-numeric-policy.json",
"coverage/kinematics-oracle.report.json",
"coverage/kinematics-registry.report.json",
"coverage/kinematics-runtime.report.json",
"coverage/kinematics-source-closure.report.json",
"coverage/motion-runtime.report.json",
"coverage/native-runner.report.json",
"coverage/posemath-runtime.report.json",
"coverage/robot-kinematics.report.json",
"coverage/runtime-mapping.report.json",
"coverage/switchkins-kinematics.report.json",
"coverage/test-entries.report.json",
"coverage/tripod-kinematics.report.json",
"coverage/trivkins-integration.report.json",
"coverage/trt-kinematics.report.json",
"coverage/userkins-kinematics.report.json",
"coverage/workspace-recovery.report.json",
"coverage/workspace-migration.report.json",
"coverage/workspace-rollback.package.json",
"coverage/offline-cache.package.json",
)
DOMAIN_REPORTS = {
"configuration": "coverage/configuration-regression.report.json",
"protocol": "coverage/runtime-mapping.report.json",
"posemath": "coverage/posemath-runtime.report.json",
"interpreter": "coverage/interpreter-runtime.report.json",
"motion": "coverage/motion-runtime.report.json",
"kinematics": "coverage/kinematics-runtime.report.json",
"hal": "coverage/hal-runtime.report.json",
"io": "coverage/io-runtime.report.json",
"python": "coverage/python-runtime.report.json",
"recovery": "coverage/workspace-recovery.report.json",
}
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str:
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> dict[str, Any]:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value
def read_jsonl(root: Path, path: Path) -> list[dict[str, Any]]:
rows = []
for number, line in enumerate((root / path).read_text(encoding="utf-8").splitlines(), 1):
if not line.strip():
continue
value = json.loads(line)
if not isinstance(value, dict):
raise ValueError(f"{path}:{number} must contain an object")
rows.append(value)
return rows
LICENSE_SPDX = {
"BSD-3-Clause": "BSD-3-Clause",
"Boost-1.0": "BSL-1.0",
"CC-BY-3.0": "CC-BY-3.0",
"GFDL-1.1+": "GFDL-1.1-or-later",
"GNU-All-Permissive": "FSFAP",
"GPL-2": "GPL-2.0-only",
"GPL-2+": "GPL-2.0-or-later",
"GPL-3+": "GPL-3.0-or-later",
"ISC": "ISC",
"LGPL-2": "LGPL-2.0-only",
"LGPL-2.1+": "LGPL-2.1-or-later",
"MIT": "MIT",
}
def parse_copyright_scopes(text: str) -> list[dict[str, Any]]:
"""Parse Debian copyright file scopes without interpreting license text."""
scopes: list[dict[str, Any]] = []
for order, paragraph in enumerate(re.split(r"\n\s*\n", text)):
fields: dict[str, list[str]] = {}
current: str | None = None
for line in paragraph.splitlines():
match = re.match(r"^([A-Za-z][A-Za-z-]*):\s*(.*)$", line)
if match:
current = match.group(1)
fields[current] = [match.group(2).strip()] if match.group(2).strip() else []
elif current and line.startswith(" "):
value = line.strip()
if value:
fields[current].append(value)
patterns = [pattern for value in fields.get("Files", []) for pattern in value.split()]
license_id = fields.get("License", [""])[0].strip()
if patterns and license_id:
scopes.append({
"order": order,
"patterns": patterns,
"license": license_id,
"spdx": LICENSE_SPDX.get(license_id),
})
return scopes
def match_copyright_scope(relative_path: str, scopes: list[dict[str, Any]]) -> dict[str, Any] | None:
matches: list[tuple[int, int, str, dict[str, Any]]] = []
for scope in scopes:
for pattern in scope["patterns"]:
if fnmatchcase(relative_path, pattern):
specificity = sum(character not in "*?[" for character in pattern)
matches.append((specificity, scope["order"], pattern, scope))
if not matches:
return None
_, _, pattern, scope = max(matches, key=lambda item: (item[0], item[1], item[2]))
return {"pattern": pattern, **scope}
def write_jsonl(path: Path, rows: Iterable[dict[str, Any]]) -> dict[str, Any]:
content = "".join(f"{canonical(row)}\n" for row in rows)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
return {"path": path.as_posix(), "bytes": len(content.encode("utf-8")), "sha256": file_digest(path), "status": "present"}
def write_report(path: Path, report: dict[str, Any]) -> dict[str, Any]:
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
if not full.is_file():
return {"path": path.as_posix(), "role": role, "status": "missing"}
value: dict[str, Any] = {
"path": path.as_posix(),
"role": role,
"status": "present",
"bytes": full.stat().st_size,
"sha256": file_digest(full),
}
if full.suffix == ".json":
try:
parsed = json.loads(full.read_text(encoding="utf-8"))
except (OSError, UnicodeError, json.JSONDecodeError):
parsed = None
if isinstance(parsed, dict):
for key in ("schema", "$id", "status", "implementation_status"):
if key in parsed:
value[key] = parsed[key]
if isinstance(parsed.get("oracle"), dict):
value["oracle_status"] = parsed["oracle"].get("status")
return value
def report_status(report: dict[str, Any]) -> str:
if report.get("implementation_status") == "verified":
return "verified"
status = report.get("status")
return str(status) if status else "unknown"
def nested_report_value(report: dict[str, Any], key: str, nested: str) -> Any:
value = report.get(key)
return value.get(nested) if isinstance(value, dict) else None
def source_observation(root: Path) -> dict[str, Any]:
lock = read_json(root, CONTEXT)
observed: dict[str, dict[str, Any]] = {
"sim_abi": {"value": lock["schema_versions"].get("sim_abi"), "source": "context-lock.json"},
"protocol": {"value": lock["schema_versions"].get("protocol"), "source": "context-lock.json"},
"snapshot": {"value": lock["schema_versions"].get("snapshot"), "source": "context-lock.json"},
"event": {"value": lock["schema_versions"].get("event"), "source": "context-lock.json"},
"workspace": {"value": lock["schema_versions"].get("workspace"), "source": "context-lock.json"},
"manifest": {"value": lock["schema_versions"].get("manifest"), "source": "context-lock.json"},
}
checks = (
("protocol", Path("web/worker/sim-session.mjs"), r"PROTOCOL_SCHEMA\s*=\s*1"),
("event", Path("web/worker/replay.mjs"), r'event-log\.v1'),
("snapshot", Path("web/worker/replay.mjs"), r'snapshot\.v1'),
("workspace", Path("web/workspace/recovery.mjs"), r'simulation-recovery\.v1'),
)
for name, path, pattern in checks:
text = (root / path).read_text(encoding="utf-8") if (root / path).is_file() else ""
observed[name]["source_observed"] = bool(re.search(pattern, text))
observed[name]["source"] = path.as_posix()
observed["manifest"]["source_observed"] = (root / MANIFEST).is_file()
observed["sim_abi"]["source_observed"] = (root / Path("coverage/kinematics-abi-contract.json")).is_file()
for value in observed.values():
value["status"] = "verified" if value.get("value") == 1 and value.get("source_observed") else "blocked"
return observed
def generate_compatibility(root: Path, out: Path) -> dict[str, Any]:
lock = read_json(root, CONTEXT)
config = read_json(root, CONFIGURATION)
migration = read_json(root, Path("coverage/workspace-migration.report.json"))
reports = {name: read_json(root, Path(path)) for name, path in DOMAIN_REPORTS.items() if (root / Path(path)).is_file()}
domains = []
for name, path in DOMAIN_REPORTS.items():
report = reports.get(name, {})
domains.append({
"domain": name,
"artifact": path,
"implementation_status": report_status(report),
"runtime_status": report.get("status", "missing"),
"oracle_status": report.get("oracle", {}).get("status") if isinstance(report.get("oracle"), dict) else None,
"test_evidence": report.get("native_tests") or report.get("native_wasm") or report.get("native_and_wasm") or nested_report_value(report, "runtime", "native_wasm"),
"status": "blocked" if nested_report_value(report, "oracle", "status") == "blocked" or report.get("status") in {"partial", "blocked"} else report_status(report),
})
browser = lock.get("browser_matrix", {})
browser_ready = browser.get("status") == "verified" and all(browser.get("minimum", {}).values())
contract = source_observation(root)
migration_ready = migration.get("status") == "passed" and migration.get("implementation_status") == "verified" and migration.get("migration", {}).get("round_trip_equal") is True and migration.get("rollback", {}).get("status") == "passed" and migration.get("offline", {}).get("status") == "passed" and (root / Path("coverage/workspace-rollback.package.json")).is_file() and (root / Path("coverage/offline-cache.package.json")).is_file()
hash_checks = []
for key, path in (
("configuration_regression_report_sha256", CONFIGURATION),
("python_runtime_report_sha256", PYTHON_REPORT),
("source_index_sha256", SOURCE_INDEX),
("manifest_seed_sha256", MANIFEST),
):
expected = lock.get(key)
actual = file_digest(root / path) if (root / path).is_file() else None
hash_checks.append({"lock_key": key, "path": path.as_posix(), "expected": expected, "actual": actual, "status": "verified" if expected == actual else "blocked"})
report = {
"schema": "release-compatibility-matrix.v1",
"context_id": lock.get("context_id"),
"status": "blocked",
"release_decision": "blocked_not_release_candidate",
"source_baseline": {
"linuxcnc_version": lock.get("linuxcnc_version"),
"linuxcnc_source_sha": lock.get("linuxcnc_source_sha"),
"linuxcnc_version_sha256": lock.get("linuxcnc_version_sha256"),
"context_lock": {"path": CONTEXT.as_posix(), "sha256": file_digest(root / CONTEXT)},
},
"contracts": {
"schema_versions": lock.get("schema_versions", {}),
"observed": contract,
"status": "verified" if all(value["status"] == "verified" for value in contract.values()) else "blocked",
},
"hash_checks": hash_checks,
"domains": domains,
"configuration": {
"entries": config.get("counts", {}).get("registered_configuration_entries"),
"entrypoints": config.get("counts", {}).get("config_entrypoints"),
"startup_preflight": config.get("counts", {}).get("startup_preflight"),
"resource_status": config.get("counts", {}).get("resource_status"),
"derived_results_are_not_official": config.get("oracle", {}).get("derived_configuration_results_are_not_official"),
},
"migration_rollback_offline": {
"status": "verified" if migration_ready else "blocked",
"artifact": artifact(root, Path("coverage/workspace-migration.report.json"), "migration_rollback_offline"),
"rollback_package": artifact(root, Path("coverage/workspace-rollback.package.json"), "rollback_package"),
"offline_package": artifact(root, Path("coverage/offline-cache.package.json"), "offline_package"),
"format_schema": migration.get("format", {}).get("schema"),
"supported_versions": migration.get("format", {}).get("supported_versions", []),
"round_trip_equal": migration.get("migration", {}).get("round_trip_equal"),
"rollback_recovery": migration.get("rollback", {}).get("recovery_status"),
"offline_start": migration.get("offline", {}).get("offline_start"),
"no_silent_downgrade": migration.get("recovery_endpoint", {}).get("no_silent_downgrade") is True,
},
"browser_matrix": {
"status": "verified" if browser_ready else "blocked",
"declared_status": browser.get("status"),
"minimum": browser.get("minimum", {}),
"reason": "minimum Chromium/Firefox/Safari versions are TBD" if not browser_ready else None,
},
"oracle": {
"status": "blocked",
"official_root": "linuxcnc/unit_tests/kinematics",
"present": (root / "linuxcnc/unit_tests/kinematics").is_dir(),
"reason": "official kinematics and recovery oracle is absent from the locked source",
},
"real_excluded": [
{"id": "hardware_driver", "reason": "physical hardware and device access are outside browser simulation"},
{"id": "linux_realtime_kernel", "reason": "hard real-time kernel scheduling is outside WebAssembly"},
{"id": "host_device_access", "reason": "host paths, sockets and devices are denied by the Worker runtime"},
],
"blockers": [
"official_oracle_missing",
"browser_matrix_unverified",
"configuration_resource_gaps",
"manifest_seed_unassigned",
"license_metadata_not_per_entry",
] + ([] if migration_ready else ["migration_and_rollback_pending"]),
"inputs": [artifact(root, CONTEXT, "context_lock"), artifact(root, SOURCE_INDEX, "source_index"), artifact(root, MANIFEST, "manifest_seed"), artifact(root, CONFIGURATION, "configuration_regression"), artifact(root, PYTHON_MANIFEST, "python_runtime_manifest"), artifact(root, FULL_PORT_DOC, "implementation_contract"), artifact(root, Path("coverage/workspace-migration.report.json"), "migration_rollback_offline"), artifact(root, Path("coverage/workspace-rollback.package.json"), "rollback_package"), artifact(root, Path("coverage/offline-cache.package.json"), "offline_package")],
"report_sha256": None,
}
return write_report(out, report)
def generate_license(root: Path, out: Path) -> dict[str, Any]:
lock = read_json(root, CONTEXT)
sources = read_jsonl(root, SOURCE_INDEX)
manifest = read_jsonl(root, MANIFEST)
test_report = read_json(root, Path("coverage/test-entries.report.json"))
test_rows = read_jsonl(root, Path("coverage/test-entries.jsonl"))
copyright_path = Path("linuxcnc/debian/copyright")
copyright_text = (root / copyright_path).read_text(encoding="utf-8")
declared = sorted(set(re.findall(r"^License:\s*(.+)$", copyright_text, re.MULTILINE)))
download_rows = read_jsonl(root, DOWNLOAD_INDEX)
python_manifest = read_json(root, PYTHON_MANIFEST)
artifact_names = {str(row.get("name")) for row in download_rows}
python_artifacts = python_manifest.get("artifacts", [])
download_valid = all(str(row.get("name")) in artifact_names and row.get("license") for row in python_artifacts)
path_counts = Counter(str(row.get("path", "")).split("/", 1)[0] for row in sources)
real_rows = [row for row in test_rows if row.get("portability") == "REAL-EXCLUDED"]
source_lookup = {str(row.get("source_id")): row for row in sources}
copyright_scopes = parse_copyright_scopes(copyright_text)
license_entries: list[dict[str, Any]] = []
for row in sorted(manifest, key=lambda value: str(value.get("id"))):
source_id = str(row.get("source"))
source_row = source_lookup.get(source_id)
source_path = str(source_row.get("path")) if source_row else ""
source_root = source_path.split("/", 1)[0] if source_path else "unknown"
source_hash = source_row.get("sha256") if source_row else None
manifest_hash = row.get("source_sha")
source_hash_status = "verified" if source_hash and manifest_hash == source_hash else "blocked"
evidence = ["coverage/manifest.jsonl", "coverage/source-index.jsonl"]
owner = None
owner_source = None
license_scope = None
license_declared = None
license_spdx = None
license_status = "blocked_unassigned"
closure_status = "blocked"
if source_root == "linuxcnc":
owner = "upstream-linuxcnc-license-audit"
owner_source = "source_root_policy"
relative_path = source_path[len("linuxcnc/"):] if source_path.startswith("linuxcnc/") else source_path
scope = match_copyright_scope(relative_path, copyright_scopes)
if scope and scope.get("spdx"):
license_scope = scope["pattern"]
license_declared = scope["license"]
license_spdx = scope["spdx"]
license_status = "scoped_declared"
closure_status = "verified_scoped"
evidence.append("linuxcnc/debian/copyright")
else:
license_status = "blocked_scope_unmatched"
evidence.append("linuxcnc/debian/copyright")
elif source_root in {"wasm-core", "web"}:
owner = "web-wasm-license-owner"
owner_source = "implementation_license_decision"
evidence.append(IMPLEMENTATION_LICENSE_DECISION.as_posix())
else:
owner = "source-provenance-license-owner"
owner_source = "source_root_policy"
license_status = "blocked_scope_unknown"
evidence_status = "complete" if source_hash_status == "verified" and all((root / path).is_file() for path in evidence) else "incomplete"
license_entries.append({
"id": row.get("id"),
"source": source_id,
"source_path": source_path or None,
"source_root": source_root,
"source_kind": row.get("kind"),
"source_sha256": source_hash,
"source_hash_status": source_hash_status,
"owner": owner,
"owner_source": owner_source,
"license_scope": license_scope,
"license_declared": license_declared,
"license_spdx": license_spdx,
"license_status": license_status,
"closure_status": closure_status,
"evidence": evidence,
"evidence_status": evidence_status,
"manifest_mapping_status": row.get("mapping_status"),
"manifest_domain": row.get("domain"),
})
license_index_path = root / LICENSE_INDEX
write_jsonl(license_index_path, license_entries)
license_index_artifact = artifact(root, LICENSE_INDEX, "license_source_index")
license_status_counts = Counter(entry["license_status"] for entry in license_entries)
closure_status_counts = Counter(entry["closure_status"] for entry in license_entries)
owner_status_counts = Counter("assigned" if entry["owner"] else "unassigned" for entry in license_entries)
source_hash_counts = Counter(entry["source_hash_status"] for entry in license_entries)
implementation_entries = [entry for entry in license_entries if entry["source_root"] in {"wasm-core", "web"}]
report = {
"schema": "release-license-closure.v1",
"context_id": lock.get("context_id"),
"status": "blocked",
"release_decision": "license_closure_incomplete",
"source_inventory": {
"entries": len(sources),
"manifest_entries": len(manifest),
"path_roots": dict(sorted(path_counts.items())),
"license_field_in_manifest": any("license" in row for row in manifest),
"manifest_license_field_missing_entries": len(manifest),
"unassigned_license_entries": license_status_counts.get("blocked_unassigned", 0),
"status": "partial",
"reason": "manifest v1 has no license field; the external deterministic index below records scoped upstream evidence and keeps unassigned implementation licenses blocked",
},
"entry_closure": {
"index": license_index_artifact,
"entries": len(license_entries),
"owner_semantics": "license_audit_owner; does not replace manifest feature owner or promote needs_owner entries",
"source_hash_status": dict(sorted(source_hash_counts.items())),
"owner_status": dict(sorted(owner_status_counts.items())),
"license_status": dict(sorted(license_status_counts.items())),
"closure_status": dict(sorted(closure_status_counts.items())),
"all_entries_have_owner": all(entry["owner"] for entry in license_entries),
"all_entries_have_evidence_status": all(entry["evidence_status"] for entry in license_entries),
"status": "blocked" if implementation_entries or any(entry["closure_status"] == "blocked" for entry in license_entries) else "verified",
},
"upstream_declarations": {
"files": [artifact(root, Path("linuxcnc/COPYING"), "license_text"), artifact(root, Path("linuxcnc/COPYING.more"), "license_text"), artifact(root, copyright_path, "scoped_license_declarations")],
"declared_spdx_or_legacy_ids": declared,
"default_scope": "linuxcnc/* (subject to debian/copyright path exceptions)",
"matched_entries": len(license_entries) - len(implementation_entries),
"status": "verified_scoped",
},
"implementation_license": {
"paths": ["wasm-core/**", "web/**"],
"status": "blocked",
"decision": "unassigned_and_blocked",
"reason": "no repository LICENSE/NOTICE/SPDX metadata assigns a license to the Web/WASM implementation files; upstream LinuxCNC declarations are not inherited",
"entries": len(implementation_entries),
"decision_artifact": artifact(root, IMPLEMENTATION_LICENSE_DECISION, "implementation_license_decision"),
},
"download_artifacts": {
"status": "verified" if download_valid else "blocked",
"index": artifact(root, DOWNLOAD_INDEX, "download_index"),
"python_runtime_manifest": artifact(root, PYTHON_MANIFEST, "python_runtime_manifest"),
"artifacts": python_artifacts,
},
"real_excluded": {
"test_entry_count": len(real_rows),
"test_report_count": test_report.get("portability", {}).get("REAL-EXCLUDED", 0),
"test_source_ids": sorted(str(row.get("test_source_id")) for row in real_rows),
"runtime_categories": ["hardware_driver", "linux_realtime_kernel", "host_device_access"],
"status": "explicit",
},
"blockers": ["wasm_web_license_not_declared"],
"report_sha256": None,
}
return write_report(out, report)
def manifest_evidence(root: Path, rows: Iterable[dict[str, Any]]) -> tuple[list[dict[str, Any]], dict[str, int]]:
required = ("source", "inputs", "outputs", "test_id", "oracle")
entries = []
missing = Counter()
for row in rows:
if row.get("mapping_status") == "needs_owner":
continue
owner = row.get("domain") if row.get("domain") not in {None, "", "unassigned"} else None
if owner is None:
missing["owner"] += 1
entry = {
"id": row.get("id"),
"source": row.get("source"),
"owner": owner,
"owner_source": "manifest.domain",
"feature_id": row.get("feature_id"),
"inputs": row.get("inputs", []),
"outputs": row.get("outputs", []),
"test_id": row.get("test_id"),
"difference": row.get("difference"),
"difference_status": "none_recorded" if row.get("difference") is None else "recorded",
"oracle_status": row.get("oracle", {}).get("status") if isinstance(row.get("oracle"), dict) else None,
"context_id": row.get("context_id"),
"mapping_status": row.get("mapping_status"),
}
for field in required:
value = entry["oracle_status"] if field == "oracle" else entry[field]
if value is None or value == [] or value == "":
missing[field] += 1
entries.append(entry)
entries.sort(key=lambda item: str(item["id"]))
return entries, dict(sorted(missing.items()))
def generate_index(root: Path, out: Path, compatibility: dict[str, Any], license_report: dict[str, Any]) -> dict[str, Any]:
lock = read_json(root, CONTEXT)
manifest = read_jsonl(root, MANIFEST)
mapped, missing = manifest_evidence(root, manifest)
artifacts = [artifact(root, Path(path), "coverage_evidence") for path in REPORT_PATHS]
artifacts.extend([
artifact(root, Path("coverage/source-index.jsonl"), "source_index"),
artifact(root, Path("coverage/manifest.jsonl"), "manifest_seed"),
artifact(root, Path("python-runtime/manifest.json"), "python_runtime_manifest"),
artifact(root, Path("coverage/compatibility-matrix.report.json"), "compatibility_matrix"),
artifact(root, Path("coverage/license-closure.report.json"), "license_closure"),
artifact(root, LICENSE_INDEX, "license_source_index"),
artifact(root, IMPLEMENTATION_LICENSE_DECISION, "implementation_license_decision"),
])
accepted = sum(1 for row in manifest if row.get("sim_status") == "accepted" or row.get("web_status") == "accepted")
unassigned = sum(1 for row in manifest if row.get("mapping_status") == "needs_owner")
config = read_json(root, CONFIGURATION)
blockers = [
{"id": "manifest_seed_unassigned", "count": unassigned, "status": "blocked"},
{"id": "accepted_entries_missing", "count": accepted, "status": "blocked" if accepted == 0 else "verified"},
{"id": "official_oracle_missing", "count": 1, "status": "blocked"},
{"id": "configuration_resources_missing", "count": config.get("counts", {}).get("resource_missing_rows", 0), "status": "blocked"},
{"id": "browser_matrix_unverified", "count": 1, "status": "blocked"},
{"id": "license_closure_incomplete", "count": len(license_report.get("blockers", [])), "status": "blocked"},
{"id": "migration_rollback_pending", "count": 0 if compatibility.get("migration_rollback_offline", {}).get("status") == "verified" else 1, "status": "verified" if compatibility.get("migration_rollback_offline", {}).get("status") == "verified" else "blocked"},
]
report = {
"schema": "release-evidence-index.v1",
"context_id": lock.get("context_id"),
"status": "blocked",
"release_decision": "blocked_not_release_candidate",
"context_lock": {"path": CONTEXT.as_posix(), "sha256": file_digest(root / CONTEXT), "schema_versions": lock.get("schema_versions")},
"reports": artifacts,
"manifest_summary": {
"total": len(manifest),
"affected": len(mapped),
"needs_owner": unassigned,
"accepted": accepted,
"required_field_missing": missing,
"affected_entries_complete": not missing,
"owner_derivation": "manifest.domain; unassigned is never treated as an owner",
},
"affected_manifest_entries": mapped,
"compatibility_report": {"path": "coverage/compatibility-matrix.report.json", "sha256": compatibility["report_sha256"]},
"license_report": {"path": "coverage/license-closure.report.json", "sha256": license_report["report_sha256"]},
"migration_report": {"path": "coverage/workspace-migration.report.json", "sha256": compatibility.get("migration_rollback_offline", {}).get("artifact", {}).get("sha256")},
"real_excluded": license_report.get("real_excluded"),
"blockers": blockers,
"integrity": {
"no_orphans": config.get("closure", {}).get("graph_orphan_entry_ids") == [] and config.get("closure", {}).get("resource_orphan_entrypoints") == [],
"no_silent_downgrade": bool(config.get("oracle", {}).get("derived_configuration_results_are_not_official")) and all(row.get("startup_preflight") for row in config.get("configuration_entries", [])),
"derived_configuration_not_accepted": bool(config.get("oracle", {}).get("derived_configuration_results_are_not_official")),
"all_affected_entries_have_required_evidence": not missing,
"migration_rollback_offline_verified": compatibility.get("migration_rollback_offline", {}).get("status") == "verified",
"license_source_index_complete": bool(license_report.get("entry_closure", {}).get("all_entries_have_owner")) and bool(license_report.get("entry_closure", {}).get("all_entries_have_evidence_status")),
"implementation_license_blocked_explicitly": license_report.get("implementation_license", {}).get("decision") == "unassigned_and_blocked",
},
"report_sha256": None,
}
return write_report(out, report)
def generate_release_gate(
root: Path,
out: Path,
aggregate: dict[str, Any],
compatibility: dict[str, Any],
license_report: dict[str, Any],
index: dict[str, Any],
) -> dict[str, Any]:
lock = read_json(root, CONTEXT)
recovery = read_json(root, Path("coverage/workspace-recovery.report.json"))
migration = read_json(root, Path("coverage/workspace-migration.report.json"))
context_id = lock.get("context_id")
context_reports = [aggregate, compatibility, license_report, index, recovery, migration]
context_ids_match = all(report.get("context_id") in {None, context_id} for report in context_reports)
recovery_hash_expected = lock.get("workspace_recovery_report_sha256")
recovery_hash_actual = file_digest(root / Path("coverage/workspace-recovery.report.json"))
recovery_hash_locked = recovery_hash_expected == recovery_hash_actual
context_consistent = context_ids_match and recovery_hash_locked
schema_versions = lock.get("schema_versions", {})
schemas_locked = bool(schema_versions) and all(value == 1 for value in schema_versions.values()) and compatibility.get("contracts", {}).get("status") == "verified"
evidence_integrity = all(value is True for key, value in aggregate.get("integrity", {}).items() if key not in {"implementation_license_blocked_explicitly"})
license_index_complete = license_report.get("entry_closure", {}).get("all_entries_have_owner") is True and license_report.get("entry_closure", {}).get("all_entries_have_evidence_status") is True
migration_verified = compatibility.get("migration_rollback_offline", {}).get("status") == "verified" and migration.get("status") == "passed"
blockers = [blocker for blocker in aggregate.get("blockers", []) if blocker.get("status") == "blocked"]
reasons = {
"manifest_seed_unassigned": "manifest seed entries still have no feature owner",
"accepted_entries_missing": "no manifest entry is accepted for release",
"official_oracle_missing": "locked source has no official kinematics/recovery oracle root",
"configuration_resources_missing": "configuration startup/resource gaps remain",
"browser_matrix_unverified": "Chromium/Firefox/Safari minimum versions remain TBD",
"license_closure_incomplete": "57 Web/WASM entries have no approved SPDX/NOTICE assignment",
}
hard_blockers = [
{
**blocker,
"reason": reasons.get(blocker.get("id"), "release gate prerequisite is not verified"),
}
for blocker in blockers
]
input_paths = (
(CONTEXT, "context_lock"),
(Path("coverage/release-closure.report.json"), "release_closure"),
(Path("coverage/release-evidence-index.json"), "release_evidence_index"),
(Path("coverage/compatibility-matrix.report.json"), "compatibility_matrix"),
(Path("coverage/license-closure.report.json"), "license_closure"),
(LICENSE_INDEX, "license_source_index"),
(Path("coverage/workspace-recovery.report.json"), "workspace_recovery"),
(Path("coverage/workspace-migration.report.json"), "workspace_migration"),
(Path("coverage/workspace-rollback.package.json"), "rollback_package"),
(Path("coverage/offline-cache.package.json"), "offline_package"),
(IMPLEMENTATION_LICENSE_DECISION, "implementation_license_decision"),
)
report = {
"schema": "release-candidate-gate.v1",
"context_id": context_id,
"status": "blocked" if hard_blockers else "passed",
"release_decision": "blocked_not_release_candidate" if hard_blockers else "release_candidate_eligible",
"release_action": "STOP_RELEASE" if hard_blockers else "ALLOW_RELEASE_CANDIDATE",
"candidate_eligible": not hard_blockers,
"source_baseline": {
"linuxcnc_version": lock.get("linuxcnc_version"),
"linuxcnc_source_sha": lock.get("linuxcnc_source_sha"),
"context_lock": artifact(root, CONTEXT, "context_lock"),
},
"checks": {
"context_consistency": {"status": "verified" if context_consistent else "blocked", "context_ids_match": context_ids_match, "context_id": context_id, "recovery_report_hash_locked": recovery_hash_locked, "recovery_report_hash": recovery_hash_actual},
"locked_schema_contracts": {"status": "verified" if schemas_locked else "blocked", "schema_versions": schema_versions, "compatibility_contract_status": compatibility.get("contracts", {}).get("status")},
"evidence_integrity": {"status": "verified" if evidence_integrity else "blocked", "all_aggregate_integrity_flags": evidence_integrity},
"license_source_index": {"status": "verified" if license_index_complete else "blocked", "entries": license_report.get("entry_closure", {}).get("entries"), "all_entries_have_owner": license_report.get("entry_closure", {}).get("all_entries_have_owner"), "all_entries_have_evidence_status": license_report.get("entry_closure", {}).get("all_entries_have_evidence_status")},
"migration_rollback_offline": {"status": "verified" if migration_verified else "blocked", "compatibility_status": compatibility.get("migration_rollback_offline", {}).get("status"), "migration_status": migration.get("status")},
"release_prerequisites": {"status": "blocked" if hard_blockers else "verified", "blocked_count": len(hard_blockers), "verified_count": sum(1 for blocker in aggregate.get("blockers", []) if blocker.get("status") == "verified")},
},
"blockers": hard_blockers,
"blocked_count": len(hard_blockers),
"rebuild": {
"commands": [
"python3 scripts/generate_release_closure.py",
"node web/worker/test_replay.mjs",
"node web/workspace/test_recovery.mjs",
"node web/workspace/test_migration.mjs",
"python3 -m unittest discover -s scripts -p 'test_*.py' -v",
],
"deterministic_inputs": [path.as_posix() for path, _ in input_paths],
},
"failure_policy": {
"on_missing_input": "STOP_RELEASE",
"on_hash_mismatch": "STOP_RELEASE",
"on_blocked_prerequisite": "STOP_RELEASE",
"forbidden": ["delete_samples", "lower_checks", "reclassify_as_REAL-EXCLUDED", "promote_blocked_to_accepted"],
},
"inputs": [artifact(root, path, role) for path, role in input_paths],
"report_sha256": None,
}
return write_report(out, report)
def generate(root: Path, output_dir: Path) -> dict[str, dict[str, Any]]:
root = root.resolve()
output_dir = output_dir if output_dir.is_absolute() else root / output_dir
compatibility = generate_compatibility(root, output_dir / "compatibility-matrix.report.json")
license_report = generate_license(root, output_dir / "license-closure.report.json")
index = generate_index(root, output_dir / "release-evidence-index.json", compatibility, license_report)
aggregate = write_report(output_dir / "release-closure.report.json", {
"schema": "release-closure-report.v1",
"context_id": compatibility["context_id"],
"status": "blocked",
"release_decision": "blocked_not_release_candidate",
"compatibility": {"path": "coverage/compatibility-matrix.report.json", "sha256": compatibility["report_sha256"]},
"license": {"path": "coverage/license-closure.report.json", "sha256": license_report["report_sha256"]},
"migration": {"path": "coverage/workspace-migration.report.json", "sha256": compatibility.get("migration_rollback_offline", {}).get("artifact", {}).get("sha256")},
"evidence_index": {"path": "coverage/release-evidence-index.json", "sha256": index["report_sha256"]},
"blockers": index["blockers"],
"integrity": index["integrity"],
"report_sha256": None,
})
gate = generate_release_gate(root, output_dir / "release-candidate-gate.report.json", aggregate, compatibility, license_report, index)
return {"compatibility": compatibility, "license": license_report, "index": index, "aggregate": aggregate, "gate": gate}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output-dir", type=Path, default=Path("coverage"))
args = parser.parse_args()
reports = generate(args.repo_root, args.output_dir)
blocked_count = sum(1 for blocker in reports["index"]["blockers"] if blocker.get("status") == "blocked")
print("release_closure=" + reports["index"]["status"] + " gate=" + reports["gate"]["status"] + " action=" + reports["gate"]["release_action"] + " blockers=" + str(blocked_count))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,333 @@
#!/usr/bin/env python3
"""Generate the deterministic K8-REL-07 remediation intake.
The intake turns the frozen K8 release blockers into independently traceable
work items. It is an orchestration artifact: a verified intake does not
resolve a blocker or make the package eligible for release.
"""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
CLOSEOUT = Path("coverage/k8-milestone-closeout.report.json")
AUDIT = Path("coverage/post-release-audit.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
CLOSURE = Path("coverage/release-closure.report.json")
INDEX = Path("coverage/release-evidence-index.json")
OUTPUT = Path("coverage/release-remediation-intake.report.json")
BLOCKER_TASKS = {
"manifest_seed_unassigned": {
"task_id": "K8-REL-08",
"title": "manifest ownership remediation",
},
"accepted_entries_missing": {
"task_id": "K8-REL-09",
"title": "release acceptance evidence remediation",
},
"official_oracle_missing": {
"task_id": "K8-REL-10",
"title": "official oracle input remediation",
},
"configuration_resources_missing": {
"task_id": "K8-REL-11",
"title": "configuration resource remediation",
},
"browser_matrix_unverified": {
"task_id": "K8-REL-12",
"title": "browser matrix verification",
},
"license_closure_incomplete": {
"task_id": "K8-REL-13",
"title": "implementation license closure",
},
}
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {
"path": path.as_posix(),
"role": role,
"status": "present",
"bytes": full.stat().st_size,
"sha256": sha,
}
def declared_report_hash(path: Path, report: dict[str, Any], error: str | None) -> dict[str, Any]:
declared = report.get("report_sha256")
actual = digest({key: value for key, value in report.items() if key != "report_sha256"}) if report else None
status = "verified" if error is None and declared and declared == actual else "blocked"
return {
"path": path.as_posix(),
"declared": declared,
"actual": actual,
"status": status,
**({"error": error} if error else {}),
}
def compare_inputs(root: Path, closeout: dict[str, Any]) -> tuple[list[dict[str, Any]], bool]:
rows: list[dict[str, Any]] = []
all_match = isinstance(closeout.get("inputs"), list)
for expected in closeout.get("inputs", []):
path_text = expected.get("path") if isinstance(expected, dict) else None
if not isinstance(path_text, str):
rows.append({"path": None, "status": "blocked", "reason": "closeout input has no path"})
all_match = False
continue
path = Path(path_text)
full = root / path
actual_sha = file_digest(full)
actual_bytes = full.stat().st_size if full.is_file() else None
matches = (
actual_sha is not None
and actual_sha == expected.get("sha256")
and actual_bytes == expected.get("bytes")
)
rows.append({
"path": path.as_posix(),
"role": expected.get("role"),
"expected_sha256": expected.get("sha256"),
"actual_sha256": actual_sha,
"expected_bytes": expected.get("bytes"),
"actual_bytes": actual_bytes,
"status": "verified" if matches else "blocked",
})
all_match = all_match and matches
return rows, all_match
def context_check(lock: dict[str, Any], reports: dict[Path, dict[str, Any]]) -> dict[str, Any]:
context_id = lock.get("context_id")
observations = []
all_match = bool(context_id)
for path, report in reports.items():
observed = report.get("context_id")
matches = bool(observed) and observed == context_id
observations.append({
"path": path.as_posix(),
"context_id": observed,
"status": "verified" if matches else "blocked",
})
all_match = all_match and matches
return {
"context_id": context_id,
"reports": observations,
"status": "verified" if all_match else "blocked",
}
def blocker_check(root: Path, audit: dict[str, Any], gate: dict[str, Any]) -> tuple[list[dict[str, Any]], dict[str, Any]]:
audit_rows = audit.get("blockers") if isinstance(audit.get("blockers"), list) else []
gate_ids = {row.get("id") for row in gate.get("blockers", []) if isinstance(row, dict)}
rows: list[dict[str, Any]] = []
all_valid = len(audit_rows) == len(BLOCKER_TASKS) and gate_ids == set(BLOCKER_TASKS)
for sequence, row in enumerate(audit_rows, start=1):
blocker_id = row.get("id")
task = BLOCKER_TASKS.get(blocker_id, {})
evidence = row.get("evidence") if isinstance(row.get("evidence"), list) else []
evidence_paths = [item.get("path") for item in evidence if isinstance(item, dict)]
evidence_present = bool(evidence_paths) and all(
isinstance(item, dict)
and item.get("status") == "present"
and isinstance(item.get("path"), str)
and (root / Path(item["path"])).is_file()
for item in evidence
)
valid = (
blocker_id in BLOCKER_TASKS
and row.get("status") == "blocked"
and row.get("owner")
and row.get("review_owner")
and row.get("remediation")
and evidence_present
and task.get("task_id")
)
work_item = {
"sequence": sequence,
"id": blocker_id,
"task_id": task.get("task_id"),
"title": task.get("title"),
"count": row.get("count"),
"owner": row.get("owner"),
"review_owner": row.get("review_owner"),
"reason": row.get("reason"),
"remediation": row.get("remediation"),
"review_trigger": row.get("review_trigger"),
"evidence": evidence,
"status": "blocked",
"release_effect": "STOP_RELEASE",
"intake_status": "verified" if valid else "blocked",
}
rows.append(work_item)
all_valid = all_valid and valid
identity = {row.get("id") for row in rows} == set(BLOCKER_TASKS)
checks = {
"status": "verified" if all_valid and identity else "blocked",
"expected_count": len(BLOCKER_TASKS),
"observed_count": len(rows),
"expected_ids": sorted(BLOCKER_TASKS),
"observed_ids": sorted(str(row.get("id")) for row in rows),
"identity_preserved": identity,
"all_items_have_owner_and_evidence": all_valid,
}
return rows, checks
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
paths = (CONTEXT, CLOSEOUT, AUDIT, GATE, CLOSURE, INDEX)
documents: dict[Path, dict[str, Any]] = {}
errors: dict[str, str] = {}
for path in paths:
documents[path], error = read_json(root, path)
if error:
errors[path.as_posix()] = error
lock = documents[CONTEXT]
closeout = documents[CLOSEOUT]
audit = documents[AUDIT]
gate = documents[GATE]
reports_for_context = {path: documents[path] for path in (CLOSEOUT, AUDIT, GATE, CLOSURE, INDEX)}
input_rows, inputs_match = compare_inputs(root, closeout)
context = context_check(lock, reports_for_context)
blocker_rows, blockers = blocker_check(root, audit, gate)
report_hashes = [
declared_report_hash(path, documents[path], errors.get(path.as_posix()))
for path in (CLOSEOUT, AUDIT, GATE, CLOSURE, INDEX)
]
report_hashes_ok = all(row["status"] == "verified" for row in report_hashes)
stop_decision = (
closeout.get("release_action") == "STOP_RELEASE"
and closeout.get("release_decision") == "blocked_not_release_candidate"
and closeout.get("candidate_eligible") is False
and closeout.get("blocked_count") == 6
and gate.get("release_action") == "STOP_RELEASE"
and gate.get("candidate_eligible") is False
and gate.get("blocked_count") == 6
and audit.get("release_action") == "STOP_RELEASE"
and audit.get("candidate_eligible") is False
and audit.get("blocked_count") == 6
)
no_reclassification = all(
row.get("status") == "blocked" and row.get("release_effect") == "STOP_RELEASE"
for row in blocker_rows
) and len(blocker_rows) == 6
checks = {
"input_hashes": {"status": "verified" if inputs_match else "blocked", "comparisons": input_rows},
"source_report_self_hashes": {"status": "verified" if report_hashes_ok else "blocked", "reports": report_hashes},
"context_consistency": context,
"blocker_identity": blockers,
"stop_decision_preserved": {"status": "verified" if stop_decision else "blocked", "release_action": "STOP_RELEASE" if stop_decision else None},
"no_reclassification": {"status": "verified" if no_reclassification else "blocked"},
}
checks_ok = not errors and all(value.get("status") == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "release-remediation-intake.v1",
"context_id": lock.get("context_id"),
"intake_id": "K8-REL-07",
"generated_at": lock.get("generated_at"),
"status": "complete" if checks_ok else "blocked",
"intake_decision": "remediation_required",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"source_baseline": {
"linuxcnc_version": lock.get("linuxcnc_version"),
"linuxcnc_source_sha": lock.get("linuxcnc_source_sha"),
"context_lock": artifact(root, CONTEXT, "context_lock"),
},
"inputs": [
artifact(root, CLOSEOUT, "k8_milestone_closeout"),
artifact(root, AUDIT, "post_release_audit"),
artifact(root, GATE, "release_candidate_gate"),
artifact(root, CLOSURE, "release_closure"),
artifact(root, INDEX, "release_evidence_index"),
artifact(root, CONTEXT, "context_lock"),
],
"checks": checks,
"work_items": blocker_rows,
"blocked_count": len(blocker_rows),
"next_tasks": [
{"task_id": row["task_id"], "title": row["title"], "depends_on": ["K8-REL-07"], "status": "pending"}
for row in blocker_rows
],
"rebuild": {
"commands": [
"python3 scripts/generate_release_closure.py",
"python3 scripts/generate_post_release_audit.py",
"python3 scripts/generate_k8_milestone_closeout.py",
"python3 scripts/generate_release_remediation_intake.py",
"python3 -m unittest discover -s scripts -p 'test_*.py' -v",
],
"deterministic_inputs": [path.as_posix() for path in paths],
},
"failure_policy": {
"on_missing_input": "STOP_RELEASE",
"on_hash_mismatch": "STOP_RELEASE",
"on_context_drift": "STOP_RELEASE",
"forbidden": ["delete_samples", "lower_checks", "reclassify_as_REAL-EXCLUDED", "promote_blocked_to_accepted"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("release_remediation_intake=" + report["status"] + " action=" + report["release_action"] + " blockers=" + str(report["blocked_count"]))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,182 @@
#!/usr/bin/env python3
"""Generate the deterministic K8-REL-14 remediation evidence roundup."""
from __future__ import annotations
import argparse
import hashlib
import json
from pathlib import Path
from typing import Any
CONTEXT = Path("context-lock.json")
INTAKE = Path("coverage/release-remediation-intake.report.json")
GATE = Path("coverage/release-candidate-gate.report.json")
AUDIT = Path("coverage/post-release-audit.report.json")
CLOSEOUT = Path("coverage/k8-milestone-closeout.report.json")
REPORTS = (
(Path("coverage/manifest-ownership-remediation.report.json"), "K8-REL-08"),
(Path("coverage/release-acceptance-remediation.report.json"), "K8-REL-09"),
(Path("coverage/official-oracle-remediation.report.json"), "K8-REL-10"),
(Path("coverage/configuration-resource-remediation.report.json"), "K8-REL-11"),
(Path("coverage/browser-matrix-remediation.report.json"), "K8-REL-12"),
(Path("coverage/implementation-license-remediation.report.json"), "K8-REL-13"),
)
OUTPUT = Path("coverage/remediation-evidence-roundup.report.json")
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str | None:
if not path.is_file():
return None
handle = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
handle.update(block)
return handle.hexdigest()
def read_json(root: Path, path: Path) -> tuple[dict[str, Any], str | None]:
try:
value = json.loads((root / path).read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise ValueError(f"{path} must contain an object")
return value, None
except (OSError, UnicodeError, json.JSONDecodeError, ValueError) as exc:
return {}, str(exc)
def artifact(root: Path, path: Path, role: str) -> dict[str, Any]:
full = root / path
sha = file_digest(full)
if sha is None:
return {"path": path.as_posix(), "role": role, "status": "missing"}
return {"path": path.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": sha}
def report_self_hash(report: dict[str, Any]) -> bool:
declared = report.get("report_sha256")
return bool(declared) and declared == digest({key: value for key, value in report.items() if key != "report_sha256"})
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
paths = (CONTEXT, INTAKE, GATE, AUDIT, CLOSEOUT, *(path for path, _task in REPORTS))
documents: dict[Path, dict[str, Any]] = {}
errors: dict[str, str] = {}
for path in paths:
documents[path], error = read_json(root, path)
if error:
errors[path.as_posix()] = error
lock = documents[CONTEXT]
intake = documents[INTAKE]
gate = documents[GATE]
audit = documents[AUDIT]
closeout = documents[CLOSEOUT]
remediation = []
all_report_hashes = True
all_context = bool(lock.get("context_id"))
all_complete = True
summaries: dict[str, Any] = {}
for path, task_id in REPORTS:
report = documents[path]
self_hash = report_self_hash(report)
context_ok = report.get("context_id") == lock.get("context_id")
complete = report.get("status") == "complete" and str(report.get("remediation_status", "")).startswith("blocked_")
all_report_hashes = all_report_hashes and self_hash
all_context = all_context and context_ok
all_complete = all_complete and complete
summaries[task_id] = {
"path": path.as_posix(),
"status": report.get("status"),
"remediation_status": report.get("remediation_status"),
"report_sha256": report.get("report_sha256"),
"self_hash": "verified" if self_hash else "blocked",
"context": "verified" if context_ok else "blocked",
}
intake_ids = {row.get("id") for row in intake.get("work_items", []) if isinstance(row, dict)}
gate_ids = {row.get("id") for row in gate.get("blockers", []) if isinstance(row, dict)}
audit_ids = {row.get("id") for row in audit.get("blockers", []) if isinstance(row, dict)}
blocker_identity = intake_ids == gate_ids == audit_ids and len(intake_ids) == 6
stop_ok = all(
report.get("release_action") == "STOP_RELEASE"
and report.get("candidate_eligible") is False
for report in (intake, gate, audit, closeout)
) and all(
documents[path].get("release_action") == "STOP_RELEASE"
and documents[path].get("candidate_eligible") is False
for path, _task in REPORTS
)
no_promotion = (
documents[REPORTS[0][0]].get("counts", {}).get("accepted_by_this_artifact") == 0
and documents[REPORTS[1][0]].get("counts", {}).get("eligible_for_acceptance") == 0
and documents[REPORTS[1][0]].get("counts", {}).get("manifest_accepted") == 0
and documents[REPORTS[2][0]].get("oracle_inventory", {}).get("official_inputs_added") == 0
and documents[REPORTS[2][0]].get("oracle_inventory", {}).get("official_goldens_added") == 0
and documents[REPORTS[3][0]].get("counts", {}).get("resolved_by_this_artifact") == 0
and documents[REPORTS[4][0]].get("declared_matrix", {}).get("minimum") == {"chromium": "TBD", "firefox": "TBD", "safari": "TBD"}
and documents[REPORTS[5][0]].get("counts", {}).get("approved_by_this_artifact") == 0
)
checks = {
"remediation_reports_complete": {"status": "verified" if all_complete else "blocked", "reports": summaries},
"remediation_report_self_hashes": {"status": "verified" if all_report_hashes else "blocked"},
"context_consistency": {"status": "verified" if all_context else "blocked", "context_id": lock.get("context_id")},
"blocker_identity_preserved": {"status": "verified" if blocker_identity else "blocked", "count": len(intake_ids), "ids": sorted(str(value) for value in intake_ids)},
"no_promotion_or_fabrication": {"status": "verified" if no_promotion else "blocked"},
"stop_release_preserved": {"status": "verified" if stop_ok else "blocked", "release_action": "STOP_RELEASE" if stop_ok else None},
}
checks_ok = not errors and all(value["status"] == "verified" for value in checks.values())
report: dict[str, Any] = {
"schema": "remediation-evidence-roundup.v1",
"context_id": lock.get("context_id"),
"task_id": "K8-REL-14",
"status": "complete" if checks_ok else "blocked",
"roundup_status": "blocked_pending_owner_actions",
"release_decision": "blocked_not_release_candidate",
"release_action": "STOP_RELEASE",
"candidate_eligible": False,
"inputs": [artifact(root, CONTEXT, "context_lock"), artifact(root, INTAKE, "remediation_intake"), artifact(root, GATE, "release_candidate_gate"), artifact(root, AUDIT, "post_release_audit"), artifact(root, CLOSEOUT, "k8_closeout")] + [artifact(root, path, task_id) for path, task_id in REPORTS],
"checks": checks,
"remediation_reports": summaries,
"remaining_owner_actions": [
{"blocker": "manifest_seed_unassigned", "action": "review proposed workstream roles and approve a manifest/context update"},
{"blocker": "accepted_entries_missing", "action": "supply ready official oracle/context evidence before any acceptance"},
{"blocker": "official_oracle_missing", "action": "add or approve locked official oracle inputs"},
{"blocker": "configuration_resources_missing", "action": "review reference candidates and restore/index resources"},
{"blocker": "browser_matrix_unverified", "action": "pin minimums and run Chromium/Firefox/Safari matrix"},
{"blocker": "license_closure_incomplete", "action": "approve SPDX/NOTICE policy for Web/WASM implementation"},
],
"review_policy": {
"next_transition": "owner review plus new context/gate regeneration",
"forbidden": ["promote_blocked_to_accepted", "delete_samples", "lower_checks", "reclassify_as_REAL-EXCLUDED", "overwrite_context_lock_in_place"],
},
"errors": errors,
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
return report
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root, args.output)
print("remediation_roundup=" + report["status"] + " release=" + report["release_action"] + " checks=" + str(len(report["checks"])))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,37 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_browser_matrix_remediation import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class BrowserMatrixRemediationTests(unittest.TestCase):
def test_contract_records_planned_matrix_and_explicit_environment_gap(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "browser-matrix-remediation.v1")
self.assertEqual(report["task_id"], "K8-REL-12")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["remediation_status"], "blocked_matrix_unverified")
self.assertEqual(report["declared_matrix"]["minimum"], {"chromium": "TBD", "firefox": "TBD", "safari": "TBD"})
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertEqual({row["browser"] for row in report["observed_browsers"]}, {"chromium", "firefox", "safari"})
self.assertEqual(report["observed_browsers"][2]["browser"], "safari")
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,42 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_configuration_resource_remediation import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class ConfigurationResourceRemediationTests(unittest.TestCase):
def test_contract_retains_all_resource_and_startup_blockers(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "configuration-resource-remediation.v1")
self.assertEqual(report["task_id"], "K8-REL-11")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["remediation_status"], "blocked_resource_gaps")
self.assertEqual(report["counts"]["resource_rows"], 16093)
self.assertEqual(report["counts"]["missing_rows"], 997)
self.assertEqual(report["counts"]["unresolved_rows"], 91)
self.assertEqual(report["counts"]["unindexed_configuration_entries"], 59)
self.assertEqual(report["counts"]["unregistered_startup_entries"], 3)
self.assertEqual(report["counts"]["resolved_by_this_artifact"], 0)
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertEqual(len(report["missing_rows"]), 997)
self.assertEqual(len(report["unresolved_rows"]), 91)
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,36 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_implementation_license_remediation import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class ImplementationLicenseRemediationTests(unittest.TestCase):
def test_contract_keeps_all_web_wasm_entries_blocked(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "implementation-license-remediation.v1")
self.assertEqual(report["task_id"], "K8-REL-13")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["remediation_status"], "blocked_pending_owner_decision")
self.assertEqual(report["counts"], {"approved_by_this_artifact": 0, "approved_spdx": 0, "blocked_unassigned": 57, "implementation_entries": 57})
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertTrue(all(row["license_status"] == "blocked_unassigned" for row in report["entries"]))
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,35 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_k8_milestone_closeout import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class K8MilestoneCloseoutTests(unittest.TestCase):
def test_closeout_contract_preserves_release_stop(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "k8-milestone-closeout.v1")
self.assertEqual(report["task_id"], "K8-REL-06")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["milestone_status"], "closed_with_release_blockers")
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertEqual(report["blocked_count"], 6)
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,54 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_release_closure import generate
ROOT = Path(__file__).resolve().parents[1]
REPORT = ROOT / "coverage/license-closure.report.json"
INDEX = ROOT / "coverage/license-source-index.jsonl"
DECISION = ROOT / "docs/linuxcnc-web-wasm-license-decision.md"
class LicenseSourceClosureTests(unittest.TestCase):
def test_entry_closure_contract_and_explicit_implementation_blocker(self):
report = json.loads(REPORT.read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "release-license-closure.v1")
self.assertEqual(report["status"], "blocked")
self.assertEqual(report["entry_closure"]["entries"], 8053)
self.assertEqual(report["entry_closure"]["source_hash_status"], {"verified": 8053})
self.assertEqual(report["entry_closure"]["owner_status"], {"assigned": 8053})
self.assertEqual(report["entry_closure"]["license_status"], {"blocked_unassigned": 57, "scoped_declared": 7996})
self.assertTrue(report["entry_closure"]["all_entries_have_owner"])
self.assertTrue(report["entry_closure"]["all_entries_have_evidence_status"])
self.assertEqual(report["upstream_declarations"]["matched_entries"], 7996)
self.assertEqual(report["implementation_license"]["entries"], 57)
self.assertEqual(report["implementation_license"]["decision"], "unassigned_and_blocked")
self.assertEqual(report["blockers"], ["wasm_web_license_not_declared"])
self.assertTrue(DECISION.is_file())
def test_index_is_complete_and_deterministic(self):
rows = [json.loads(line) for line in INDEX.read_text(encoding="utf-8").splitlines() if line.strip()]
self.assertEqual(len(rows), 8053)
self.assertEqual(len({row["id"] for row in rows}), 8053)
self.assertEqual(rows, sorted(rows, key=lambda row: row["id"]))
self.assertTrue(all(row["source_hash_status"] == "verified" for row in rows))
self.assertTrue(all(row["owner"] and row["evidence_status"] == "complete" for row in rows))
self.assertEqual(sum(row["closure_status"] == "verified_scoped" for row in rows), 7996)
self.assertEqual(sum(row["license_status"] == "blocked_unassigned" for row in rows), 57)
self.assertTrue(all(row["license_spdx"] for row in rows if row["source_root"] == "linuxcnc"))
self.assertTrue(all(row["license_spdx"] is None for row in rows if row["source_root"] in {"wasm-core", "web"}))
def test_generation_is_deterministic(self):
before = {path: path.read_bytes() for path in (REPORT, INDEX)}
generate(ROOT, ROOT / "coverage")
after = {path: path.read_bytes() for path in (REPORT, INDEX)}
self.assertEqual(before, after)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,38 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_manifest_ownership_remediation import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class ManifestOwnershipRemediationTests(unittest.TestCase):
def test_contract_covers_all_unassigned_seeds_without_clearing_release_stop(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "manifest-ownership-remediation.v1")
self.assertEqual(report["task_id"], "K8-REL-08")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["remediation_status"], "blocked_pending_manifest_review")
self.assertEqual(report["counts"], {"accepted_by_this_artifact": 0, "mapped": 6249, "manifest_total": 8053, "needs_owner": 6249})
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertTrue(all(row["assignment_status"] == "proposed_blocked_review" for row in report["assignments"]))
self.assertTrue(all(row["owner"] and row["review_owner"] for row in report["assignments"]))
self.assertEqual(len({row["id"] for row in report["assignments"]}), 6249)
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,35 @@
import json
import hashlib
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
REPORT = ROOT / "coverage/workspace-migration.report.json"
class MigrationClosureTests(unittest.TestCase):
def test_report_contract_and_blockers(self):
report = json.loads(REPORT.read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "workspace-migration-report.v1")
self.assertEqual(report["status"], "passed")
self.assertEqual(report["implementation_status"], "verified")
self.assertEqual(report["format"]["schema"], "workspace-package.v1")
self.assertEqual(report["format"]["supported_versions"], [1, 2])
self.assertTrue(report["format"]["payload_schemas_unchanged"])
self.assertTrue(report["migration"]["round_trip_equal"])
self.assertTrue(report["migration"]["deterministic"])
self.assertEqual(report["rollback"]["failure_result"], "rollback_injected_failure")
self.assertEqual(report["rollback"]["recovery_status"], "recovered")
self.assertEqual(report["offline"]["offline_start"], "ready")
self.assertEqual(report["offline"]["missing_resource_result"], "offline_resource_invalid")
self.assertTrue((ROOT / "coverage/workspace-rollback.package.json").is_file())
self.assertTrue((ROOT / "coverage/offline-cache.package.json").is_file())
self.assertTrue(report["recovery_endpoint"]["no_silent_downgrade"])
self.assertEqual(report["oracle"]["status"], "blocked")
unsigned = {key: value for key, value in report.items() if key != "report_sha256"}
self.assertEqual(report["report_sha256"], hashlib.sha256(json.dumps(unsigned, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest())
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,39 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_official_oracle_remediation import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class OfficialOracleRemediationTests(unittest.TestCase):
def test_contract_retains_missing_official_inputs(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "official-oracle-remediation.v1")
self.assertEqual(report["task_id"], "K8-REL-10")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["remediation_status"], "blocked_missing_locked_inputs")
self.assertEqual(report["oracle_inventory"]["kinematics_samples"], 11)
self.assertEqual(report["oracle_inventory"]["kinematics_ready"], 0)
self.assertEqual(report["oracle_inventory"]["official_inputs_added"], 0)
self.assertEqual(report["oracle_inventory"]["official_goldens_added"], 0)
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertTrue(all(row["official_unit_test"] is False for row in report["oracle_inventory"]["matrixkins_candidate_files"]))
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,37 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_owner_review_gate_refresh import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class OwnerReviewGateRefreshTests(unittest.TestCase):
def test_contract_fails_closed_without_owner_inputs(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "owner-review-gate-refresh.v1")
self.assertEqual(report["task_id"], "K8-REL-15")
self.assertEqual(report["status"], "blocked")
self.assertEqual(report["review_status"], "owner_input_required")
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertEqual(len(report["decisions"]), 6)
self.assertEqual(report["checks"]["owner_inputs_present"]["status"], "blocked")
self.assertEqual(report["checks"]["gate_refresh_allowed"]["status"], "blocked")
self.assertEqual(report["checks"]["release_stop_preserved"]["status"], "verified")
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,52 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_post_release_audit import AUDIT, generate
ROOT = Path(__file__).resolve().parents[1]
class PostReleaseAuditTests(unittest.TestCase):
def test_report_contract_preserves_stop_decision_and_blockers(self):
report = json.loads((ROOT / AUDIT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "post-release-audit.v1")
self.assertEqual(report["audit_id"], "K8-REL-05")
self.assertEqual(report["status"], "blocked")
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertEqual(report["release_decision"], "blocked_not_release_candidate")
self.assertFalse(report["candidate_eligible"])
self.assertEqual(report["blocked_count"], 6)
self.assertEqual(report["checks"]["input_hashes"]["status"], "verified")
self.assertEqual(report["checks"]["context_consistency"]["status"], "verified")
self.assertEqual(report["checks"]["cross_references"]["status"], "verified")
self.assertEqual(report["checks"]["blocker_review"]["status"], "verified")
self.assertEqual(report["checks"]["gate_checks"]["status"], "verified")
self.assertTrue(all(row["owner"] and row["review_owner"] for row in report["blockers"]))
self.assertTrue(all(row["evidence"] and row["remediation"] for row in report["blockers"]))
self.assertEqual(
{row["id"] for row in report["blockers"]},
{
"manifest_seed_unassigned",
"accepted_entries_missing",
"official_oracle_missing",
"configuration_resources_missing",
"browser_matrix_unverified",
"license_closure_incomplete",
},
)
def test_generation_is_deterministic(self):
before = (ROOT / AUDIT).read_bytes()
generated = generate(ROOT, ROOT / AUDIT)
after = (ROOT / AUDIT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,43 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_release_acceptance_remediation import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class ReleaseAcceptanceRemediationTests(unittest.TestCase):
def test_contract_keeps_all_entries_blocked(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "release-acceptance-remediation.v1")
self.assertEqual(report["task_id"], "K8-REL-09")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["remediation_status"], "blocked_no_eligible_entries")
self.assertEqual(report["counts"], {
"affected_entries": 1804,
"blocked_for_acceptance": 1804,
"eligible_for_acceptance": 0,
"manifest_accepted": 0,
"manifest_needs_owner": 6249,
"manifest_total": 8053,
})
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertEqual(len(report["blocked_entry_ids"]), 1804)
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,43 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_release_closure import generate
ROOT = Path(__file__).resolve().parents[1]
GATE = ROOT / "coverage/release-candidate-gate.report.json"
class ReleaseCandidateGateTests(unittest.TestCase):
def test_gate_contract_stops_release_on_explicit_blockers(self):
gate = json.loads(GATE.read_text(encoding="utf-8"))
self.assertEqual(gate["schema"], "release-candidate-gate.v1")
self.assertEqual(gate["status"], "blocked")
self.assertEqual(gate["release_decision"], "blocked_not_release_candidate")
self.assertEqual(gate["release_action"], "STOP_RELEASE")
self.assertFalse(gate["candidate_eligible"])
self.assertEqual(gate["blocked_count"], 6)
self.assertTrue(gate["checks"]["context_consistency"]["context_ids_match"])
self.assertEqual(gate["checks"]["locked_schema_contracts"]["status"], "verified")
self.assertEqual(gate["checks"]["license_source_index"]["status"], "verified")
self.assertEqual(gate["checks"]["migration_rollback_offline"]["status"], "verified")
self.assertEqual(gate["checks"]["release_prerequisites"]["status"], "blocked")
self.assertIn("official_oracle_missing", {blocker["id"] for blocker in gate["blockers"]})
license_blocker = next(blocker for blocker in gate["blockers"] if blocker["id"] == "license_closure_incomplete")
self.assertIn("57 Web/WASM", license_blocker["reason"])
self.assertEqual(gate["failure_policy"]["on_hash_mismatch"], "STOP_RELEASE")
def test_gate_generation_is_deterministic(self):
before = GATE.read_bytes()
generated = generate(ROOT, ROOT / "coverage")
after = GATE.read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["gate"]["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,62 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_release_closure import generate
ROOT = Path(__file__).resolve().parents[1]
COMPATIBILITY = ROOT / "coverage/compatibility-matrix.report.json"
LICENSE = ROOT / "coverage/license-closure.report.json"
INDEX = ROOT / "coverage/release-evidence-index.json"
AGGREGATE = ROOT / "coverage/release-closure.report.json"
class ReleaseClosureTests(unittest.TestCase):
def test_report_contract_and_explicit_blockers(self):
compatibility = json.loads(COMPATIBILITY.read_text(encoding="utf-8"))
license_report = json.loads(LICENSE.read_text(encoding="utf-8"))
index = json.loads(INDEX.read_text(encoding="utf-8"))
aggregate = json.loads(AGGREGATE.read_text(encoding="utf-8"))
self.assertEqual(compatibility["schema"], "release-compatibility-matrix.v1")
self.assertEqual(license_report["schema"], "release-license-closure.v1")
self.assertEqual(index["schema"], "release-evidence-index.v1")
self.assertEqual(aggregate["schema"], "release-closure-report.v1")
self.assertEqual(aggregate["evidence_index"]["sha256"], index["report_sha256"])
self.assertEqual(index["status"], "blocked")
self.assertIn("official_oracle_missing", compatibility["blockers"])
self.assertIn("manifest_seed_unassigned", {row["id"] for row in index["blockers"]})
self.assertTrue(compatibility["oracle"]["status"] == "blocked")
self.assertTrue(license_report["source_inventory"]["unassigned_license_entries"] > 0)
self.assertEqual(license_report["entry_closure"]["entries"], 8053)
self.assertTrue(license_report["entry_closure"]["all_entries_have_owner"])
self.assertTrue(license_report["entry_closure"]["all_entries_have_evidence_status"])
self.assertTrue(index["integrity"]["license_source_index_complete"])
self.assertTrue(index["integrity"]["implementation_license_blocked_explicitly"])
self.assertEqual(index["manifest_summary"]["total"], 8053)
self.assertEqual(index["manifest_summary"]["needs_owner"], 6249)
self.assertEqual(index["manifest_summary"]["accepted"], 0)
def test_affected_entries_have_explicit_evidence_shape(self):
index = json.loads(INDEX.read_text(encoding="utf-8"))
rows = index["affected_manifest_entries"]
self.assertEqual(len(rows), 1804)
self.assertTrue(index["manifest_summary"]["affected_entries_complete"])
self.assertTrue(all(row["owner"] for row in rows))
self.assertTrue(all(row["inputs"] and row["outputs"] and row["test_id"] for row in rows))
self.assertTrue(all(row["oracle_status"] == "blocked" for row in rows))
self.assertTrue(all(row["difference_status"] == "none_recorded" for row in rows))
def test_generation_is_deterministic(self):
before = {path: path.read_bytes() for path in (COMPATIBILITY, LICENSE, INDEX, AGGREGATE)}
generated = generate(ROOT, ROOT / "coverage")
after = {path: path.read_bytes() for path in (COMPATIBILITY, LICENSE, INDEX, AGGREGATE)}
self.assertEqual(before, after)
self.assertEqual(generated["index"]["report_sha256"], json.loads(after[INDEX].decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,39 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_release_remediation_intake import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class ReleaseRemediationIntakeTests(unittest.TestCase):
def test_intake_contract_preserves_stop_and_expands_six_items(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "release-remediation-intake.v1")
self.assertEqual(report["intake_id"], "K8-REL-07")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["intake_decision"], "remediation_required")
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertEqual(report["blocked_count"], 6)
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertEqual([row["task_id"] for row in report["work_items"]], [
"K8-REL-08", "K8-REL-09", "K8-REL-10", "K8-REL-11", "K8-REL-12", "K8-REL-13",
])
self.assertTrue(all(row["status"] == "blocked" for row in report["work_items"]))
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,36 @@
import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from generate_remediation_evidence_roundup import OUTPUT, generate
ROOT = Path(__file__).resolve().parents[1]
class RemediationEvidenceRoundupTests(unittest.TestCase):
def test_contract_preserves_six_blockers_and_stop(self):
report = json.loads((ROOT / OUTPUT).read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "remediation-evidence-roundup.v1")
self.assertEqual(report["task_id"], "K8-REL-14")
self.assertEqual(report["status"], "complete")
self.assertEqual(report["roundup_status"], "blocked_pending_owner_actions")
self.assertEqual(report["release_action"], "STOP_RELEASE")
self.assertFalse(report["candidate_eligible"])
self.assertTrue(all(value["status"] == "verified" for value in report["checks"].values()))
self.assertEqual(len(report["remediation_reports"]), 6)
self.assertEqual(len(report["remaining_owner_actions"]), 6)
def test_generation_is_deterministic(self):
before = (ROOT / OUTPUT).read_bytes()
generated = generate(ROOT, ROOT / OUTPUT)
after = (ROOT / OUTPUT).read_bytes()
self.assertEqual(before, after)
self.assertEqual(generated["report_sha256"], json.loads(after.decode())["report_sha256"])
if __name__ == "__main__":
unittest.main()