← Files Planner5D: Plan, Build, CreateARCHIVED FILE
skills/planner5d-floorplan-recheck/scripts/compare_measurements.py
3.31 KB · Oct 10, 2026 · 18:24 UTC
#!/usr/bin/env python3
"""Compare explicit same-basis length evidence; no network or scene mutation."""
import json
import math
import sys
from decimal import Decimal
from pathlib import Path
class MeasurementComparison:
BASES: frozenset[str] = frozenset({"clear_span", "wall_path", "outer_span", "opening_width"})
SOURCES: frozenset[str] = frozenset({"labeled_dimension", "user_measurement", "measured_scan"})
def assess(self, ledger: object) -> dict[str, object]:
if not isinstance(ledger, dict) or ledger.get("version") != 1:
raise ValueError("Expected measurement ledger version 1")
rows: object = ledger.get("measurements")
if not isinstance(rows, list) or not rows:
raise ValueError("Expected a nonempty measurements array")
checks: list[dict[str, object]] = [self.compare(row) for row in rows]
states: set[object] = {row["status"] for row in checks}
status: str = "passed"
if "failed" in states:
status = "failed"
elif "insufficient_evidence" in states:
status = "insufficient_evidence"
return {"version": 1, "status": status, "scope": "listed_length_measurements_only",
"target": ledger.get("target"), "checks": checks}
def compare(self, row: object) -> dict[str, object]:
if not isinstance(row, dict):
raise ValueError("Every measurement must be an object")
result: dict[str, object] = {key: row.get(key) for key in
("label", "objectId", "expectedCm", "observedCm", "toleranceCm",
"referenceBasis", "observedBasis", "sourceRef", "observedMethod")}
missing: list[str] = []
for key in ("expectedCm", "observedCm", "toleranceCm"):
value: object = row.get(key)
if not self.validNumber(value, key == "toleranceCm"):
missing.append(f"{key} must be a finite {'nonnegative' if key == 'toleranceCm' else 'positive'} number")
if row.get("referenceBasis") not in self.BASES or row.get("referenceBasis") != row.get("observedBasis"):
missing.append("matching explicit dimension bases required")
sourceRef: object = row.get("sourceRef")
if row.get("sourceKind") not in self.SOURCES or not isinstance(sourceRef, str) or not sourceRef.strip():
missing.append("reliable source provenance required")
observedMethod: object = row.get("observedMethod")
if not isinstance(observedMethod, str) or not observedMethod.strip():
missing.append("observed measurement method required")
if missing:
return {**result, "status": "insufficient_evidence", "reasons": missing}
deviation: Decimal = Decimal(str(row["observedCm"])) - Decimal(str(row["expectedCm"]))
return {**result, "deviationCm": float(deviation),
"status": "passed" if abs(deviation) <= Decimal(str(row["toleranceCm"])) else "failed"}
def validNumber(self, value: object, allowZero: bool) -> bool:
if isinstance(value, bool) or not isinstance(value, (int, float)):
return False
try:
return math.isfinite(value) and value >= 0 and (allowZero or value > 0)
except OverflowError:
return False
if __name__ == "__main__":
try:
if len(sys.argv) != 2:
raise ValueError("Usage: compare_measurements.py <ledger.json>")
payload: object = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
print(json.dumps(MeasurementComparison().assess(payload), indent=2, allow_nan=False))
except (OSError, ValueError, TypeError) as error:
print(json.dumps({"status": "invalid_input", "message": str(error)}))
sys.exit(2)
SHA-256: f1c10ce71198cdba4fc694d8eb3c5037e763b2690afd3823380e24ca7bbf02bb