#!/usr/bin/env python3 """Step 3 cross-check of the lining deliverables (Task 6). Re-reads the raw DXF texts (04-004..009 and 03-001) with a plain text search, independent of extract_lining_spec.py, and compares them with the report and the model meta. Prints PASS/FAIL per check with population counts. Usage: verify_lining.py """ import glob import json import os import re import sys import ezdxf from ezdxf import recover RAG, DOC_LIN, DOC_STD, META = sys.argv[1:5] RESULTS = [] def check(name, ok, detail): RESULTS.append((name, ok, detail)) print(f"[{'PASS' if ok else 'FAIL'}] {name}: {detail}") def all_texts(path): try: doc = ezdxf.readfile(path) except Exception: doc, _ = recover.readfile(path) out = [] for e in doc.modelspace(): if e.dxftype() == "TEXT": out.append(e.dxf.text) elif e.dxftype() == "MTEXT": out.append(e.plain_text()) return out sheets = sorted(glob.glob(os.path.join(RAG, "04_본선터널기타", "C0060304-00[4-9]*.dxf"))) std = glob.glob(os.path.join(RAG, "03_본선터널굴착", "C0060303-001*.dxf")) raw = {os.path.basename(p)[:14]: all_texts(p) for p in sheets} doc_lin = open(DOC_LIN, encoding="utf-8").read() doc_std = open(DOC_STD, encoding="utf-8").read() meta = json.load(open(META, encoding="utf-8")) # C1 common values present in every sheet (population = 6 sheets) common = {"fck=27MPa": "fck 27", "fy=400MPa": "SD400", "최대치수 Ø25": "Ø25", "R1=6.892": "R1 6.892", "R2=3,712": "R2 3,712", "R2'=3,910": "R2' 3,910", "EL.-0.367": "EL -0.367", "EL. 0.000": "EL 0.000"} for token, label in common.items(): hits = [k for k, t in raw.items() if any(token in s for s in t)] check(f"C1 {label} in all sheets", len(hits) == len(raw), f"{len(hits)}/{len(raw)} sheets (표본 아님, 전수)") # C2 temperature-not-considered detail appears on 3 sheets (005, 006, 007) temp = [k for k, t in raw.items() if any("온도미고려" in s for s in t)] check("C2 온도미고려 detail sheets", sorted(temp) == sorted([k for k in raw if k[9:12] in ("005", "006", "007")]), f"{len(temp)} sheets: {[k[9:12] for k in sorted(temp)]} (전수)") # C3 pattern-group count in raw texts equals report rows (9) groups = [s for t in raw.values() for s in t if "패턴" in s and "주철근 조립도" in s or (("패턴)" in s) and ("입출구부" in s or "온도미고려" in s))] rows = len([l for l in doc_lin.splitlines() if l.startswith("| C0060304-")]) check("C3 pattern-detail count = report rows", len(groups) == rows, f"raw {len(groups)} vs report {rows} (전수)") # C4 R1 cross-check against the standard section drawing and the report table std_txt = all_texts(std[0]) if std else [] std_has = any(("6.982" in s or "6982" in s or "6,982" in s) for s in std_txt) check("C4 R1 6.982 in standard section (03-001 raw)", std_has, f"03-001 raw texts scanned: {len(std_txt)}") check("C4b standard table DOC states R1 6,982", "6,982" in doc_std, "설계_표준단면치수표 본문 대조") check("C4c report records decision", "6.982 m 유지" in doc_lin, "R1 결정 문구 존재") # C5 thickness arithmetic: outer R 7.282 m minus inner R t982 = round(7.282 - 6.982, 3); t892 = round(7.282 - 6.892, 3) check("C5 thickness arithmetic", t982 == 0.300 and t892 == 0.390, f"7.282-6.982={t982} m (matches 300 mm), 7.282-6.892={t892} m (does not match)") # C6 V9 existence + name version + key content of OUTPUT name = os.path.basename(DOC_LIN) m = re.match(r"^설계_콘크리트라이닝상세_(\d{4}-\d{2}-\d{2})_v(\d+\.\d+\.\d{2})\.md$", name) ver_hdr = re.search(r"\| (v\d+\.\d+\.\d{2}) \|", doc_lin) check("C6 file name pattern and version", bool(m) and ver_hdr is not None and ver_hdr.group(1) == "v" + m.group(2), f"name v{m.group(2) if m else '?'} vs header {ver_hdr.group(1) if ver_hdr else '?'}") check("C6b OUTPUT key items present", all(k in doc_lin for k in ["fck", "SD400", "입출구부", "확정 2026-10-21"]), "fck, SD400, 입출구부, 결정 문구") # C7 meta: lining reference and open items lr = meta.get("lining_reference", {}) check("C7 meta lining_reference 9 groups", sum(len(s["groups"]) for s in lr.get("sheets", [])) == 9, f"{sum(len(s['groups']) for s in lr.get('sheets', []))} groups, status={lr.get('summary', '')[:40]}...") check("C7b meta open records decision", any("확정 2026-10-21" in o for o in meta.get("open", [])), "open[] 결정 문구") # C8 scripts never write to the RAG source tree writes = [] for sc in glob.glob("scripts/*lining*.py"): txt = open(sc, encoding="utf-8").read() if re.search(r"open\([^)]*RAG[^)]*['\"]w", txt): writes.append(sc) check("C8 no script writes into RAG", not writes, f"scanned {len(glob.glob('scripts/*lining*.py'))} scripts") n_fail = sum(1 for r in RESULTS if not r[1]) print(f"SUMMARY: {len(RESULTS) - n_fail} PASS / {n_fail} FAIL of {len(RESULTS)}")