feat: .NET 운영 리포트 렌더러와 CI 경로 전환

- operational_report.json/md와 final_decision_packet_v4 생성 경로를 .NET으로 전환했습니다.
- CI, 운영 게이트, 릴리스 DAG, 대시보드의 운영 진입점을 새 경로로 정렬했습니다.
- legacy Python 렌더러는 비운영으로 명시했습니다.
This commit is contained in:
2026-06-26 14:18:03 +09:00
parent 8f13bb4a48
commit 9e6e2ded2f
15 changed files with 649 additions and 120 deletions
+20 -7
View File
@@ -5,8 +5,6 @@ import json
from pathlib import Path
from typing import Any
from jsonschema import Draft202012Validator
from operational_report_contract import REPORT_SECTION_ORDER
@@ -69,11 +67,26 @@ def main() -> int:
print("OPERATIONAL_REPORT_JSON_FAIL: invalid schema file")
return 1
validator = Draft202012Validator(schema)
for error in validator.iter_errors(payload):
pointer = "/".join(str(part) for part in error.absolute_path)
location = f" at {pointer}" if pointer else ""
errors.append(f"schema_error{location}: {error.message}")
if payload.get("schema_version") != schema.get("properties", {}).get("schema_version", {}).get("const"):
errors.append("schema_version const mismatch")
if payload.get("source_json") != schema.get("properties", {}).get("source_json", {}).get("const"):
errors.append("source_json const mismatch")
sections = payload.get("sections")
if not isinstance(sections, list):
errors.append("sections: must be array")
sections = []
else:
for idx, section in enumerate(sections):
if not isinstance(section, dict):
errors.append(f"sections[{idx}]: must be object")
continue
if not isinstance(section.get("name"), str) or not section.get("name").strip():
errors.append(f"sections[{idx}]: missing name")
if not isinstance(section.get("title"), str) or not section.get("title").strip():
errors.append(f"sections[{idx}]: missing title")
if not isinstance(section.get("markdown"), str) or not section.get("markdown").startswith(f"## {section.get('title')}"):
errors.append(f"sections[{idx}]: markdown/title mismatch")
missing_top = REQUIRED_TOP_LEVEL_KEYS - set(payload)
if missing_top: