feat: add S-52 production pipeline v2
This commit is contained in:
@@ -336,6 +336,22 @@ def finalize_release(
|
||||
decoded_features = 0
|
||||
decoded_layers = Counter()
|
||||
duplicate_feature_ids = []
|
||||
|
||||
s52_plan = dict(plan.get("s52") or {})
|
||||
s52_runtime_enabled = bool(s52_plan.get("enabled")) and s52_plan.get("mariner_mode") == "runtime"
|
||||
s52_runtime_failures: list[str] = []
|
||||
s52_runtime_csp_counts = Counter()
|
||||
s52_runtime_layer_counts = Counter()
|
||||
s52_runtime_dependent_count = 0
|
||||
s52_runtime_leaks = Counter()
|
||||
s52_runtime_fact_counts = Counter()
|
||||
s52_dynamic_final_fields = {
|
||||
"s52_is_safety_contour",
|
||||
"s52_sounding_prefix",
|
||||
"s52_sounding_is_shallow",
|
||||
"s52_isolated_danger",
|
||||
"s52_display_base_promoted",
|
||||
}
|
||||
for path in pbf_files:
|
||||
raw = path.read_bytes()
|
||||
decoded = mapbox_vector_tile.decode(raw)
|
||||
@@ -348,12 +364,45 @@ def finalize_release(
|
||||
pbf_rel = str(path.relative_to(pbf_root)).replace("\\", "/")
|
||||
for feat in feats:
|
||||
fid = feat.get("id")
|
||||
props = feat.get("properties") or {}
|
||||
if s52_runtime_enabled:
|
||||
if props.get("s52_mariner_dependent") == 1:
|
||||
s52_runtime_dependent_count += 1
|
||||
s52_runtime_layer_counts[layer] += 1
|
||||
csp = str(props.get("s52_runtime_csp") or "")
|
||||
if not csp:
|
||||
s52_runtime_failures.append(f"{pbf_rel}:{layer}:{fid} missing s52_runtime_csp")
|
||||
else:
|
||||
s52_runtime_csp_counts[csp] += 1
|
||||
for key in s52_dynamic_final_fields:
|
||||
if key in props:
|
||||
s52_runtime_leaks[key] += 1
|
||||
if csp in {"DEPARE01", "DEPARE02"}:
|
||||
if "depth_min_m" not in props:
|
||||
s52_runtime_failures.append(f"{pbf_rel}:{layer}:{fid} {csp} missing depth_min_m")
|
||||
if "s52_area_color" in props:
|
||||
s52_runtime_leaks["DEPARE:s52_area_color"] += 1
|
||||
elif csp == "DEPCNT02" and "contour_depth_m" not in props:
|
||||
s52_runtime_failures.append(f"{pbf_rel}:{layer}:{fid} DEPCNT02 missing contour_depth_m")
|
||||
elif csp == "SOUNDG02" and "s52_sounding_depth_m" not in props:
|
||||
s52_runtime_failures.append(f"{pbf_rel}:{layer}:{fid} SOUNDG02 missing s52_sounding_depth_m")
|
||||
elif csp in {"OBSTRN04", "WRECKS02"} and "s52_hazard_depth_m" not in props:
|
||||
s52_runtime_failures.append(f"{pbf_rel}:{layer}:{fid} {csp} missing s52_hazard_depth_m")
|
||||
elif "s52_runtime_csp" in props:
|
||||
s52_runtime_failures.append(f"{pbf_rel}:{layer}:{fid} runtime CSP without mariner-dependent marker")
|
||||
for key in (
|
||||
"depth_min_m", "depth_max_m", "contour_depth_m",
|
||||
"s52_sounding_depth_m", "s52_hazard_depth_m",
|
||||
"s52_surrounding_max_drval1_m", "s52_surrounding_min_drval2_m",
|
||||
):
|
||||
if key in props:
|
||||
s52_runtime_fact_counts[key] += 1
|
||||
_observe_nav_name_conflict_feature(
|
||||
nav_name_conflict_state,
|
||||
pbf_rel,
|
||||
layer,
|
||||
fid,
|
||||
feat.get("properties") or {},
|
||||
props,
|
||||
)
|
||||
if fid is None:
|
||||
continue
|
||||
@@ -402,6 +451,20 @@ def finalize_release(
|
||||
nav_name_conflict_state
|
||||
)
|
||||
|
||||
if s52_runtime_leaks:
|
||||
s52_runtime_failures.append(f"dynamic final state leaked into runtime PBF: {dict(s52_runtime_leaks)}")
|
||||
s52_runtime_contract = {
|
||||
"status": ("PASS" if not s52_runtime_failures else "FAIL") if s52_runtime_enabled else "NOT_APPLICABLE",
|
||||
"enabled": s52_runtime_enabled,
|
||||
"mariner_dependent_count": s52_runtime_dependent_count,
|
||||
"runtime_csp_counts": dict(sorted(s52_runtime_csp_counts.items())),
|
||||
"runtime_layer_counts": dict(sorted(s52_runtime_layer_counts.items())),
|
||||
"fact_counts": dict(sorted(s52_runtime_fact_counts.items())),
|
||||
"dynamic_final_leaks": dict(sorted(s52_runtime_leaks.items())),
|
||||
"failure_count": len(s52_runtime_failures),
|
||||
"failure_examples": s52_runtime_failures[:100],
|
||||
}
|
||||
|
||||
failures = []
|
||||
if hard_gate:
|
||||
failures.append("hard_gate_unmapped")
|
||||
@@ -417,6 +480,8 @@ def finalize_release(
|
||||
failures.append("duplicate_feature_ids_within_tile_layer")
|
||||
if style_contract is not None and style_contract.get("overall") != "PASS":
|
||||
failures.append("style_or_sprite_contract")
|
||||
if s52_runtime_enabled and s52_runtime_contract.get("status") != "PASS":
|
||||
failures.append("s52_runtime_contract")
|
||||
|
||||
result = {
|
||||
"schema": RELEASE_SCHEMA,
|
||||
@@ -431,6 +496,10 @@ def finalize_release(
|
||||
"mapping_sha256": plan["mapping_sha256"],
|
||||
"policy_sha256": plan["policy_sha256"],
|
||||
"builder_contract_version": plan.get("builder_contract_version"),
|
||||
"production_pipeline_version": plan.get("production_pipeline_version"),
|
||||
"s52": plan.get("s52"),
|
||||
"aoi": plan.get("aoi"),
|
||||
"s52_runtime_contract": s52_runtime_contract,
|
||||
"style_sha256": style_sha,
|
||||
"sprite_json_sha256": sprite_sha,
|
||||
"gap_disposition_sha256": gap_disposition_sha,
|
||||
|
||||
Reference in New Issue
Block a user