Files
Aislo/resources/tester/diag_structures.py
T
eomsangdonandClaude Opus 5 0ef32b5279 chore(tester): 시험을 resources/tester/ 로 옮김 — 창끼리 건너가게
⚠ **뿌리** — `tmp/` 는 창 사이에 안 건너감(실측 확인: 상대 창이 놓은 `tmp/_sync_probe.txt`
가 시간을 두고 두 번 봐도 안 보임). 그래서 **정본(등록부 스키마)만 건너가고 그것을 읽는
시험은 안 건너가** 오늘 두 번, 같은 시험이 **연 창은 통과·받은 창은 실패**가 됐음.

- `tmp/tests/*` 를 `resources/tester/` 로 **복사**(127 파일). 내용은 **한 줄도 안 고침**
- `tmp/tests` 는 **남겨 둠** — 되돌릴 자리(사용자 지시)
- 실행: `./venv/Scripts/python.exe -m pytest resources/tester/ -q`
  옮기기 전과 **같은 수**: 617 통과 / 22 건너뜀 / 실패 0

⇒ 이제 시험·예외·까닭이 **정본과 함께** 움직임. 오늘 세운 「예외는 정본 스키마에」와 짝임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 17:12:30 +09:00

102 lines
4.3 KiB
Python

# -*- coding: utf-8 -*-
"""신규 프로젝트에서 구조물이 안 보이는 원인 진단 — 읽기 전용.
실행: ./venv/Scripts/python.exe tmp/tests/diag_structures.py [프로젝트UUID]
인자를 생략하면 storage 아래에서 **가장 최근에 만들어진** 프로젝트를 고른다.
자동설계 체인이 남겨야 할 것을 한 줄씩 대조한다:
1. 배관 정본(edits/pipe_points.json) — 관·세월교·BOX 지정
2. 종단 정본 stations[].structure — 구조물 측점 표식
3. 횡단 정본 cross_*.json 의 structure — 측점 파일
4. B06 읽기 경로(load_culvert_sets) — 실제로 세트가 붙는가
5. 초기값 스냅샷 — 체인 직후 상태가 떠졌는가
"""
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
def newest_project() -> Path | None:
candidates = [p for p in (ROOT / "storage").glob("*/*/*") if (p / "project_manifest.json").is_file()]
return max(candidates, key=lambda p: p.stat().st_mtime) if candidates else None
def read_json(path: Path):
try:
return json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return None
def main() -> int:
if len(sys.argv) > 1:
matches = [p for p in (ROOT / "storage").glob(f"*/*/{sys.argv[1]}")]
project = matches[0] if matches else None
else:
project = newest_project()
if project is None or not project.is_dir():
print("프로젝트를 찾지 못했습니다.")
return 1
print(f"프로젝트: {project}")
# 1) 배관 정본
pipes_path = project / "B04_PreProcess" / "drainage" / "edits" / "pipe_points.json"
pipes = read_json(pipes_path)
points = (pipes or {}).get("points") or []
print(f"1) pipe_points.json 존재={pipes_path.is_file()} 관={len(points)}건")
for point in points:
print(
f" - {point.get('chainage_m')}m facility={point.get('facility') or 'pipe'}"
f" options={list((point.get('options') or {}).keys())}"
)
if pipes:
print(f" route_signature={str(pipes.get('route_signature'))[:16]}…")
# 2) 종단 정본 구조물 표식
long_path = project / "B06_Section" / "longitudinal" / "longitudinal.json"
longitudinal = read_json(long_path) or {}
stations = longitudinal.get("stations") or []
marked = [s for s in stations if s.get("structure")]
print(f"2) longitudinal.json 측점={len(stations)} 구조물 표식={len(marked)}건")
for station in marked:
print(f" - {station.get('chainage_m')}m {station.get('structure')} kind={station.get('kind')}")
# 3) 횡단 정본 파일
cross_dir = project / "B06_Section" / "cross_sections"
files = sorted(cross_dir.glob("cross_*.json")) if cross_dir.is_dir() else []
with_structure = [(p.name, read_json(p).get("structure")) for p in files if (read_json(p) or {}).get("structure")]
print(f"3) cross_*.json 파일={len(files)}개 구조물 표식={len(with_structure)}{with_structure}")
# 4) B06 읽기 경로 — 실제로 세트가 붙는가
from B06_Section.B06_Section_Engine_Culvert import load_culvert_sets
sets = load_culvert_sets(project)
print(f"4) load_culvert_sets 세트={len(sets)}건")
for chainage, spec in sorted(sets.items()):
print(f" - {chainage}m kind={spec.get('kind')}")
# 측점과 붙을 수 있는가 (허용오차 0.02m)
chainages = [float(s.get("chainage_m", -1)) for s in stations]
for chainage in sorted(sets):
hit = any(abs(chainage - c) <= 0.02 for c in chainages)
if not hit:
print(f" ⚠ {chainage}m 에 붙을 측점이 없다 — 횡단도에 구조물이 안 뜬다")
# 5) 초기값 스냅샷
snapshot = project / "initial_snapshot"
snap_pipes = read_json(snapshot / "B04_PreProcess__drainage__edits" / "pipe_points.json")
print(
f"5) initial_snapshot 존재={snapshot.is_dir()}"
f" 스냅샷 관={len((snap_pipes or {}).get('points') or [])}건"
)
lock = project / "initial_design.lock"
print(f" initial_design.lock(체인 진행 중 표시)={lock.exists()}")
return 0
if __name__ == "__main__":
raise SystemExit(main())