feat: add S-52 production pipeline v2

This commit is contained in:
OpenAI Codex
2026-09-18 07:33:17 +08:00
parent a7c9812bd8
commit b9c24ff5c7
5 changed files with 357 additions and 7 deletions

View File

@@ -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,