113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from collections import Counter
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def parse_args():
|
|
p = argparse.ArgumentParser()
|
|
p.add_argument("--report-root", default="build/pbf-reports")
|
|
p.add_argument("--profile", choices=["delivery", "engineering"], default="delivery")
|
|
p.add_argument("--output", default="cm95_pbf_build_reports_audit_v1.json")
|
|
return p.parse_args()
|
|
|
|
|
|
def main():
|
|
a = parse_args()
|
|
root = Path(a.report_root) / a.profile
|
|
files = sorted(
|
|
p for p in root.rglob("*.json")
|
|
if not p.name.endswith(".trace.json")
|
|
)
|
|
|
|
layer_counts = Counter()
|
|
unmapped = Counter()
|
|
hard_gate = []
|
|
total_input = 0
|
|
total_output = 0
|
|
relation_groups = 0
|
|
standalone_lights = 0
|
|
named_from_direct_source = 0
|
|
name_conflict_groups = 0
|
|
quantization_fallbacks = 0
|
|
quantization_omissions = 0
|
|
quantization_omission_layers = Counter()
|
|
encoder_dropped_features = []
|
|
planned_output = 0
|
|
|
|
for p in files:
|
|
obj = json.loads(p.read_text(encoding="utf-8"))
|
|
total_input += int(obj.get("input_feature_count") or 0)
|
|
total_output += int(obj.get("output_feature_count") or 0)
|
|
planned_output += int(obj.get("planned_output_feature_count") or obj.get("output_feature_count") or 0)
|
|
layer_counts.update(obj.get("output_layer_counts") or {})
|
|
unmapped.update(obj.get("unmapped_class_counts") or {})
|
|
nav = obj.get("navigation_composites") or {}
|
|
relation_groups += int(nav.get("groups") or 0)
|
|
standalone_lights += int(nav.get("standalone_lights") or 0)
|
|
named_from_direct_source += int(nav.get("named_from_direct_source") or 0)
|
|
name_conflict_groups += int(nav.get("name_conflict_groups") or 0)
|
|
quantization_fallbacks += len(obj.get("quantization_fallbacks") or [])
|
|
omissions = obj.get("quantization_omissions") or []
|
|
quantization_omissions += len(omissions)
|
|
for item in omissions:
|
|
if isinstance(item, dict):
|
|
quantization_omission_layers[str(item.get("layer") or "UNKNOWN")] += 1
|
|
for item in obj.get("encoder_dropped_features") or []:
|
|
encoder_dropped_features.append({"file": str(p), **item})
|
|
for item in obj.get("hard_gate_unmapped") or []:
|
|
hard_gate.append({"file": str(p), **item})
|
|
|
|
result = {
|
|
"schema": "navsea.cm95.build-report-audit/v1",
|
|
"profile": a.profile,
|
|
"report_file_count": len(files),
|
|
"input_rows_considered": total_input,
|
|
"planned_output_features": planned_output,
|
|
"output_features": total_output,
|
|
"output_layer_counts": dict(layer_counts),
|
|
"unmapped_class_counts": dict(unmapped),
|
|
"navigation_relation_groups": relation_groups,
|
|
"standalone_lights": standalone_lights,
|
|
"nav_named_from_direct_source": named_from_direct_source,
|
|
"nav_name_conflict_groups": name_conflict_groups,
|
|
"quantization_fallbacks": quantization_fallbacks,
|
|
"quantization_omissions": quantization_omissions,
|
|
"quantization_omission_layers": dict(sorted(quantization_omission_layers.items())),
|
|
"encoder_dropped_features": encoder_dropped_features,
|
|
"hard_gate_unmapped": hard_gate,
|
|
"failure_count": len(hard_gate) + name_conflict_groups + len(encoder_dropped_features) + (1 if planned_output != total_output else 0),
|
|
"overall": (
|
|
"PASS"
|
|
if not hard_gate and name_conflict_groups == 0 and not encoder_dropped_features and planned_output == total_output
|
|
else "FAIL"
|
|
),
|
|
}
|
|
|
|
Path(a.output).write_text(
|
|
json.dumps(result, ensure_ascii=False, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
|
|
print(f"Reports : {len(files)}")
|
|
print(f"Input rows : {total_input}")
|
|
print(f"Planned output : {planned_output}")
|
|
print(f"Output features : {total_output}")
|
|
print(f"Navigation composites : {relation_groups}")
|
|
print(f"Standalone LIGHTS : {standalone_lights}")
|
|
print(f"Direct nav names : {named_from_direct_source}")
|
|
print(f"Nav name conflicts : {name_conflict_groups}")
|
|
print(f"Hard-gate unmapped : {len(hard_gate)}")
|
|
print(f"Quantization fallback : {quantization_fallbacks}")
|
|
print(f"Quantization omissions : {quantization_omissions}")
|
|
print(f"Encoder dropped : {len(encoder_dropped_features)}")
|
|
print(f"OVERALL : {result['overall']}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|