"""Concept-level planning for practical construction-standard questions. The retrieval stack is intentionally code-centric, but real field questions often start from practical terms that do not appear as a standard title. This module maps those terms to a conservative bundle of likely standards and to an answer contract that clients can expose before making final judgments. """ from __future__ import annotations from typing import Any from src.standard_codes import canonical_doc_type, normalize_standard_code TRANSFER_BEAM_CODES = [ { "code": "KDS 14 20 24", "title": "콘크리트구조 스트럿-타이모델 기준", "role": "D-region, 깊은보, 하중 불연속부의 힘 전달 모델 검토", "parent_doc_score": 0.88, }, { "code": "KDS 14 20 22", "title": "콘크리트구조 전단 및 비틀림 설계기준", "role": "전단, 사인장 균열, 전단보강 검토", "parent_doc_score": 0.84, }, { "code": "KDS 14 20 20", "title": "콘크리트구조 휨 및 압축 설계기준", "role": "휨, 압축, 단면 강도 및 사용성 검토", "parent_doc_score": 0.82, }, { "code": "KDS 14 20 50", "title": "콘크리트구조 철근상세 설계기준", "role": "전이부 철근 상세, 보강근 배치, 피복 검토", "parent_doc_score": 0.78, }, { "code": "KDS 14 20 52", "title": "콘크리트구조 정착 및 이음 설계기준", "role": "주근 정착, 이음 위치, 정착 성능 검토", "parent_doc_score": 0.76, }, { "code": "KDS 41 17 00", "title": "건축물 내진설계기준", "role": "전이층, 수직 불연속, 내진 성능 검토", "parent_doc_score": 0.72, }, { "code": "KDS 17 10 00", "title": "내진설계 일반", "role": "내진 일반 원칙 및 중요도 검토", "parent_doc_score": 0.69, }, { "code": "KCS 14 20 11", "title": "철근공사 표준시방", "role": "철근 조립, 배근 간격, 정착·이음 시공 검측", "parent_doc_score": 0.66, }, { "code": "KCS 14 20 12", "title": "거푸집 및 동바리공사 표준시방", "role": "전이보 하부 동바리, 측압, 해체 전 강도 확인", "parent_doc_score": 0.64, }, { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "타설, 다짐, 양생, 시공이음 및 품질관리", "parent_doc_score": 0.62, }, ] WEATHER_CONCRETE_CODES = [ { "code": "KCS 14 20 40", "title": "한중 콘크리트 표준시방", "role": "한중 콘크리트 보온양생, 초기동해 방지, 온도관리", "parent_doc_score": 0.88, }, { "code": "KCS 14 20 41", "title": "서중 콘크리트 표준시방", "role": "서중 콘크리트 최고온도, 재료 온도 저감, 습윤양생", "parent_doc_score": 0.86, }, { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "일반 타설, 다짐, 양생 및 품질관리", "parent_doc_score": 0.78, }, { "code": "KCS 10 40 00", "title": "건설공사 시험기준", "role": "콘크리트 품질시험 및 검사 절차", "parent_doc_score": 0.68, }, ] CONCRETE_DEFECT_CODES = [ { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "균열, 재료분리, 곰보 등 시공 결함의 조사와 보수 시방", "parent_doc_score": 0.88, }, { "code": "KCS 10 40 00", "title": "건설공사 시험기준", "role": "코어, 비파괴, 강도 및 품질시험 절차", "parent_doc_score": 0.74, }, { "code": "KCS 10 10 15", "title": "품질관리", "role": "부적합, 품질기록, 재검측 및 승인 절차", "parent_doc_score": 0.72, }, { "code": "KDS 14 20 90", "title": "기존 콘크리트구조물의 안전성 평가기준", "role": "강도 미달 또는 손상 구조물의 안전성 평가", "parent_doc_score": 0.7, }, { "code": "KDS 14 20 10", "title": "콘크리트구조 해석과 설계 원칙", "role": "구조 성능 재평가가 필요한 경우의 설계 원칙", "parent_doc_score": 0.66, }, ] CONCRETE_CRACK_CODES = [ { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "균열 조사, 보수, 재시공 판단의 기본 시방", "parent_doc_score": 0.88, }, { "code": "KDS 14 20 30", "title": "콘크리트구조 사용성 설계기준", "role": "허용균열폭, 사용성, 내구성 검토", "parent_doc_score": 0.78, }, { "code": "KDS 14 20 90", "title": "기존 콘크리트구조물의 안전성 평가기준", "role": "구조 균열 또는 손상 부재의 안전성 평가", "parent_doc_score": 0.74, }, { "code": "KCS 10 40 00", "title": "건설공사 시험기준", "role": "균열 깊이, 비파괴, 코어 등 시험 절차", "parent_doc_score": 0.68, }, { "code": "KCS 10 10 15", "title": "품질관리", "role": "부적합, 재시험, 보수 승인 기록", "parent_doc_score": 0.64, }, { "code": "KCS 41 40 17", "title": "누수보수 공사", "role": "누수 균열일 때의 차수·주입 보수", "parent_doc_score": 0.56, }, ] CONCRETE_HONEYCOMB_CODES = [ { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "재료분리, 표면결함, 곰보 보수 판단", "parent_doc_score": 0.88, }, { "code": "KCS 14 20 12", "title": "거푸집 및 동바리공사 표준시방", "role": "거푸집, 타설면, 탈형 후 결함 원인 확인", "parent_doc_score": 0.72, }, { "code": "EXCS 14 20 13", "title": "일반콘크리트(부대시설편)", "role": "고속도로 부대시설 콘크리트 결함 보수", "parent_doc_score": 0.66, }, { "code": "KCS 14 20 30", "title": "수밀 콘크리트", "role": "누수·수밀성이 관련된 결함 보수", "parent_doc_score": 0.6, }, { "code": "KCS 14 20 23", "title": "폴리머 시멘트 콘크리트", "role": "폴리머 시멘트계 보수재를 쓰는 경우", "parent_doc_score": 0.56, }, ] CONCRETE_STRENGTH_SHORTFALL_CODES = [ { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "압축강도 품질시험, 강도 미달 시 조치", "parent_doc_score": 0.88, }, { "code": "KDS 14 20 90", "title": "기존 콘크리트구조물의 안전성 평가기준", "role": "강도 미달 부재의 구조 안전성 평가", "parent_doc_score": 0.82, }, { "code": "KDS 14 20 20", "title": "콘크리트구조 휨 및 압축 설계기준", "role": "부재 휨·압축 내력 재검토", "parent_doc_score": 0.74, }, { "code": "KDS 14 20 10", "title": "콘크리트구조 해석과 설계 원칙", "role": "재평가 해석과 설계 원칙", "parent_doc_score": 0.7, }, { "code": "KCS 10 40 00", "title": "건설공사 시험기준", "role": "코어, 비파괴, 재시험 절차", "parent_doc_score": 0.66, }, { "code": "KCS 10 10 15", "title": "품질관리", "role": "부적합 처리, 시험성적서, 승인 기록", "parent_doc_score": 0.62, }, ] CONCRETE_WINTER_DAMAGE_CODES = [ { "code": "KCS 14 20 40", "title": "한중 콘크리트 표준시방", "role": "초기동해, 보온양생, 가열설비 중단 대응", "parent_doc_score": 0.9, }, { "code": "KCS 14 20 10", "title": "일반콘크리트 표준시방", "role": "일반 양생, 결함 보수, 품질관리", "parent_doc_score": 0.78, }, { "code": "KCS 10 40 00", "title": "건설공사 시험기준", "role": "동해 피해 깊이와 강도 저하 시험", "parent_doc_score": 0.68, }, { "code": "KCS 10 10 15", "title": "품질관리", "role": "부적합, 재시험, 보수 승인 절차", "parent_doc_score": 0.64, }, { "code": "KDS 14 20 90", "title": "기존 콘크리트구조물의 안전성 평가기준", "role": "동해로 구조 성능 저하가 의심되는 경우", "parent_doc_score": 0.62, }, { "code": "EXCS 14 20 40", "title": "한중 콘크리트", "role": "고속도로 한중 콘크리트 현장", "parent_doc_score": 0.58, }, { "code": "EXCS 14 20 45", "title": "한중콘크리트(부대시설편)", "role": "고속도로 부대시설 한중 콘크리트 현장", "parent_doc_score": 0.56, }, ] EARTH_RETAINING_EMERGENCY_CODES = [ { "code": "KDS 21 30 00", "title": "가설흙막이 설계기준", "role": "가설흙막이 안정성, 배면 침하, 구조 재검토", "parent_doc_score": 0.88, }, { "code": "KCS 21 30 00", "title": "가설흙막이공사 표준시방", "role": "굴착 중 계측, 시공관리, 이상 발생 시 조치", "parent_doc_score": 0.8, }, { "code": "KCS 11 30 45", "title": "지반 그라우팅 표준시방", "role": "차수 주입, 보강 그라우팅, 주입재 품질관리", "parent_doc_score": 0.76, }, { "code": "KDS 11 10 15", "title": "지반계측", "role": "지반계측 설계, 관리기준치, 계측 계획", "parent_doc_score": 0.72, }, { "code": "KCS 11 10 15", "title": "시공 중 지반계측", "role": "시공 중 계측, 경보, 한계치 초과 대응", "parent_doc_score": 0.7, }, { "code": "KCS 10 10 15", "title": "품질관리", "role": "비상조치 기록, 감리 보고, 재검측 절차", "parent_doc_score": 0.64, }, ] CAST_IN_PLACE_PILE_CODES = [ { "code": "KCS 11 50 10", "title": "현장타설 콘크리트말뚝 표준시방", "role": "굴착 바닥 슬라임 제거, 콘크리트 타설, 두부정리", "parent_doc_score": 0.88, }, { "code": "EXCS 11 50 10", "title": "현장타설 콘크리트 말뚝(전문)", "role": "고속도로 현장타설말뚝 슬라임 검사 및 품질관리", "parent_doc_score": 0.82, }, { "code": "KDS 11 50 15", "title": "깊은기초 설계기준", "role": "말뚝 지지력과 선단 지지 조건의 설계 재검토", "parent_doc_score": 0.72, }, { "code": "KCS 10 40 00", "title": "건설공사 시험기준", "role": "슬라임, 콘크리트 품질 및 검측 시험", "parent_doc_score": 0.64, }, { "code": "KCS 14 20 43", "title": "수중 콘크리트", "role": "트레미, 안정액, 수중 타설 품질관리", "parent_doc_score": 0.6, }, { "code": "KCS 11 50 40", "title": "말뚝재하시험", "role": "지지력 확인과 재하시험 계획", "parent_doc_score": 0.56, }, ] BOLT_CONNECTION_DEFECT_CODES = [ { "code": "KCS 14 31 25", "title": "볼트접합 및 핀 연결 표준시방", "role": "고장력볼트 조임, 재체결, 불량 볼트 교체", "parent_doc_score": 0.88, }, { "code": "KCS 41 31 25", "title": "건축물 강구조공사 고장력볼트 접합 및 연결", "role": "건축 철골 고장력볼트 체결 검사와 조임 관리", "parent_doc_score": 0.82, }, { "code": "KDS 14 31 25", "title": "강구조 연결 설계기준", "role": "체결력 부족 또는 교체 시 접합부 구조 안전성 검토", "parent_doc_score": 0.72, }, { "code": "KCS 14 31 05", "title": "강구조공사 일반사항", "role": "강구조 조립, 시공오차, 검사 일반사항", "parent_doc_score": 0.66, }, ] CONCEPT_PACKS: list[dict[str, Any]] = [ { "id": "transfer_beam", "title": "전이보/전이부재 기준 검토", "triggers": [ "전이보", "전이 보", "전이부재", "전이 부재", "전이층", "하중전이", "하중 전이", "transfer beam", "transfer girder", ], "canonical_terms": [ "전이보", "전이부재", "깊은보", "D-region", "스트럿-타이모델", "수직 불연속", "하중 전달", ], "code_bundle": TRANSFER_BEAM_CODES, "missing_conditions": [ "상부 기둥·벽체의 축력, 전단력, 모멘트와 하중 조합", "전이보 경간, 폭, 춤, 지점 조건과 전이층 위치", "전이보가 깊은보 또는 D-region으로 볼 수 있는 기하 조건", "콘크리트 설계기준압축강도와 철근 항복강도", "주근 정착 가능 길이, 이음 위치, 절곡·폐쇄스터럽 상세", "건축물 내진등급, 수직 불연속 여부, 중요도 계수", "시공 중 동바리 존치 계획, 타설 순서, 시공이음 위치", ], "compliance_checklist": [ "전이보를 단순 보가 아니라 하중 전달 경로가 급변하는 부재로 보고 load path를 먼저 확인", "깊은보/D-region이면 스트럿-타이모델 적용 필요성을 별도로 판단", "전단 파괴가 지배하지 않도록 전단보강, 절점부 압축, 스트럿 압축응력을 확인", "주근과 보강근의 정착·이음이 전이부 위험 단면에 몰리지 않도록 상세 검토", "전이층이 내진상 수직 불연속을 만들면 내진 기준의 추가 검토를 수행", "대단면 타설, 온도균열, 다짐, 양생, 동바리 해체 전 강도 확인을 시공계획에 반영", ], "high_risk": True, }, { "id": "weather_concrete", "title": "한중/서중 콘크리트 온도관리", "triggers": [ "한중 콘크리트", "한중콘크리트", "서중 콘크리트", "서중콘크리트", "공구리", "동해", "초기동해", "보온양생", "열풍기", "쇄빙", "얼음물", "35도", "최고 온도", "최고온도", "습윤양생", ], "canonical_terms": [ "한중콘크리트", "서중콘크리트", "보온양생", "초기동해", "최고온도", "습윤양생", "재료 온도", ], "code_bundle": WEATHER_CONCRETE_CODES, "missing_conditions": [ "콘크리트 타설 시 외기 온도, 콘크리트 온도, 풍속과 상대습도", "보온 또는 냉각 양생 방법과 유지 시간", "배합, 시멘트 종류, 혼화제 사용 여부", "초기 강도 발현 확인용 공시체 또는 현장 양생 시험 결과", "동해 또는 고온 피해가 의심되는 표면 깊이와 강도 저하 범위", ], "compliance_checklist": [ "한중/서중 여부를 먼저 분류하고 해당 특수 콘크리트 시방을 우선 적용", "타설 전 재료 온도, 운반 시간, 현장 온도 조건을 기록", "보온양생 또는 습윤양생 계획을 품질시험 계획과 연결", "동해·고온 피해가 의심되면 임의 보수 전에 강도 및 깊이 조사를 수행", "온도 관련 수치 기준은 검색된 조항 근거가 있을 때만 단정", ], "high_risk": True, }, { "id": "concrete_crack_response", "title": "콘크리트 균열 조사/보수 대응", "triggers": [ "균열", "균열보수", "균열 보수", "균열폭", "허용균열폭", "소성수축", "건조수축", "크랙", "에폭시 주입", "수지 주입", "초음파", ], "canonical_terms": [ "균열", "균열보수", "균열폭", "허용균열폭", "비파괴시험", "품질시험", "안전성 평가", ], "code_bundle": CONCRETE_CRACK_CODES, "missing_conditions": [ "최대 균열폭, 길이, 깊이와 진행성 여부", "균열 위치, 구조 부재 여부, 누수 동반 여부", "재령, 양생 조건, 온도 이력과 수축 가능성", "초음파, 코어, 반발경도 등 시험 결과", "보수재 종류, 주입 가능 균열폭, 바탕 건조 상태", ], "compliance_checklist": [ "균열을 표면 하자, 누수 균열, 구조 균열로 먼저 분류", "균열 지도와 폭·깊이 측정 기록을 확보", "구조 균열 또는 진행성 균열이면 KDS 안전성 평가로 확대", "누수 균열은 누수보수 시방 적용 여부를 별도 확인", "보수 후 재검측과 감리 승인 기록을 남김", ], "high_risk": True, }, { "id": "concrete_honeycomb_response", "title": "콘크리트 곰보/재료분리 하자 대응", "triggers": [ "곰보", "허니컴", "honeycomb", "재료분리", "재료 분리", "표면결함", "표면 결함", "자갈 노출", "자갈이 노출", "탈형 후", "보수용 모르타르", "무수축 모르타르", ], "canonical_terms": [ "재료분리", "표면결함", "다지기", "거푸집", "보수용 모르타르", "품질관리", ], "code_bundle": CONCRETE_HONEYCOMB_CODES, "missing_conditions": [ "결함 깊이, 면적과 철근 노출 또는 피복 손실 여부", "내력 부재인지 비구조 마감인지의 구분", "수밀성 또는 누수와 관련된 부위인지 여부", "거푸집, 다짐, 타설 높이와 재료분리 원인 기록", "보수 모르타르의 요구 강도와 접착 성능", ], "compliance_checklist": [ "결함 깊이가 철근까지 도달했는지 먼저 확인", "내력 부재 또는 누수 부위이면 임의 패칭 전에 구조·방수 검토로 확대", "불량부 제거, 바탕 처리, 보수재 충전, 양생 계획을 시방과 연결", "보수 후 재검측과 사진대지, 승인 기록을 남김", ], "high_risk": True, }, { "id": "concrete_strength_shortfall_response", "title": "콘크리트 압축강도 미달/재평가 대응", "triggers": [ "압축강도", "설계기준압축강도", "강도 미달", "강도미달", "코어 강도", "코어강도", "코어", "비파괴", "슈미트", "슈미트해머", "fck", "불합격", "부적합", "재시험", ], "canonical_terms": [ "압축강도", "설계기준압축강도", "코어강도", "비파괴시험", "부적합", "재시험", "안전성 평가", ], "code_bundle": CONCRETE_STRENGTH_SHORTFALL_CODES, "missing_conditions": [ "표준양생 또는 현장양생 공시체 구분", "코어 개수, 직경, 채취 위치와 시험 재령", "비파괴시험 보정식과 코어 강도 보정값", "강도 미달이 국부인지 동일 타설 로트 전체인지 여부", "해당 부재의 실제 하중 부담과 구조 안전성 재평가 조건", ], "compliance_checklist": [ "강도 미달은 단순 보수 문제가 아니라 품질 부적합으로 기록", "시험 방법과 공시체 조건을 먼저 검증", "주요 구조 부재이면 KDS 안전성 평가 및 부재 내력 재검토로 확대", "비파괴시험만으로 합격 판정을 단정하지 않고 코어 등 보정 근거를 확인", "보강·철거·사용제한 판단은 책임기술자 승인 절차로 처리", ], "high_risk": True, }, { "id": "concrete_winter_damage_response", "title": "콘크리트 동해 피해/한중 양생 사고 대응", "triggers": [ "동해", "동해 피해", "초기동해", "한중 콘크리트", "한중콘크리트", "보온양생", "양생온도", "가열설비", "열풍기", "동결", "공기연행", "5 MPa", ], "canonical_terms": [ "한중콘크리트", "초기동해", "동해 피해", "보온양생", "양생온도", "압축강도", "품질시험", ], "code_bundle": CONCRETE_WINTER_DAMAGE_CODES, "missing_conditions": [ "타설 일시, 외기 온도, 콘크리트 온도와 보온 중단 시간", "양생 방법, 가열설비 상태와 급열 중단 기록", "초기 강도 또는 적산온도 등 성숙도 근거", "혼화제, 공기량, 물-결합재비와 배합 조건", "동해 의심 깊이, 현재 코어/비파괴 강도 결과", ], "compliance_checklist": [ "동해 의심 구간의 후속 공정을 중지하고 온도 이력부터 확보", "한중 콘크리트 시방의 보온양생과 초기 강도 기준을 우선 확인", "피해 깊이와 강도 저하 범위는 시험 근거로 판단", "구조 성능 저하 가능성이 있으면 KDS 안전성 평가로 확대", "보수재 주입 또는 표면 보수는 피해 깊이 판정 후 승인 절차로 처리", ], "high_risk": True, }, { "id": "concrete_defect_response", "title": "콘크리트 균열/곰보/강도미달 하자 대응", "triggers": [ "곰보", "재료분리", "재료 분리", "honeycomb", "균열", "크랙", "소성수축", "강도 미달", "강도미달", "코어 강도", "슈미트", "비파괴", "하자보수", "보수 절차", "에폭시 주입", "수지 주입", ], "canonical_terms": [ "콘크리트 결함", "재료분리", "균열보수", "코어강도", "비파괴시험", "품질관리", "안전성 평가", ], "code_bundle": CONCRETE_DEFECT_CODES, "missing_conditions": [ "결함의 위치, 폭, 깊이, 면적과 철근 노출 여부", "구조 부재인지 비구조 마감인지의 구분", "재령, 양생 조건, 표준/현장 양생 공시체 강도", "코어 채취, 반발경도, 초음파 등 시험 방법과 보정값", "보수재 종류, 요구 강도, 접착성, 주입 가능 균열폭", "감리 지적, 불합격 판정, 사용 제한 등 현장 조치 상태", ], "compliance_checklist": [ "하자 부위 사용 또는 후속 공정을 멈추고 구조 영향 가능성을 먼저 판단", "균열폭·깊이·진행성 및 재료분리 깊이를 기록하고 사진대지를 확보", "강도 미달이나 주요 부재 손상이면 KDS 안전성 평가 기준까지 확대", "보수재 시공 전 바탕 처리, 건조 상태, 주입성, 양생 조건을 확인", "보수 후 재검측과 승인 기록을 남기고 임의 합격 판정을 피함", ], "high_risk": True, }, { "id": "earth_retaining_emergency", "title": "가설흙막이 침하/싱크홀/비상 차수 대응", "required_any": [ "흙막이", "가설흙막이", "굴착", "배면", "지반", "차수", "계측", ], "triggers": [ "흙막이", "가설흙막이", "씽크홀", "싱크홀", "지반침하", "지반 침하", "배면침하", "배면 침하", "계측기", "변형계", "위험 단계", "비상차수", "차수 주입", "붕괴", ], "canonical_terms": [ "가설흙막이", "배면침하", "지반침하", "계측관리", "차수 그라우팅", "안전성 재검토", ], "code_bundle": EARTH_RETAINING_EMERGENCY_CODES, "missing_conditions": [ "굴착 깊이, 벽체 형식, 지보공 단계와 굴착 진행률", "침하 위치, 크기, 진행 속도와 계측기 한계치 초과 여부", "지하수위 변화, 누수량, 토사 유실 또는 공동 발생 여부", "인접 구조물 기초 형식, 이격거리, 균열 상태", "긴급 차수 주입재, 주입 압력, 주입 범위와 안전 통제 계획", ], "compliance_checklist": [ "인명과 교통 안전을 먼저 통제하고 굴착 및 인접 작업을 중지", "계측값, 침하 균열, 지하수 유출량을 시간대별로 기록", "가설흙막이 구조 안정성은 KDS, 현장 조치와 계측 관리는 KCS로 분리 검토", "차수 주입은 지반 그라우팅 시방의 재료·압력·품질관리와 연결", "응급 복구 후 재굴착 전 책임기술자 승인과 추가 계측 계획을 확보", ], "high_risk": True, }, { "id": "cast_in_place_pile_slime", "title": "현장타설말뚝 슬라임/RCD 품질관리", "required_any": [ "말뚝", "현장타설", "RCD", "rcd", "슬라임", ], "triggers": [ "현장타설말뚝", "현장타설 말뚝", "RCD", "rcd", "슬라임", "선단슬라임", "선단 슬라임", "두부정리", "말뚝 두부", "바닥굴착", ], "canonical_terms": [ "현장타설 콘크리트말뚝", "선단 슬라임", "굴착 바닥", "콘크리트 타설", "두부정리", "검측", ], "code_bundle": CAST_IN_PLACE_PILE_CODES, "missing_conditions": [ "말뚝 직경, 깊이, 지지층과 RCD/올케이싱 등 굴착 공법", "슬라임 측정 방법, 측정 시점, 허용 두께 판단 근거", "공벽 안정액 사용 여부와 안정액 품질", "콘크리트 타설 전 청소 방법과 검측 기록", "두부정리 높이, 철근망 손상 여부, 재하시험 계획", ], "compliance_checklist": [ "굴착 완료 후 콘크리트 타설 전 슬라임 제거와 검측을 먼저 확인", "고속도로 현장이면 EXCS 전문시방 적용 여부를 계약 기준으로 확인", "선단 지지력 의심 시 설계기준의 지지력 검토와 시험 계획으로 확대", "두부정리 중 철근·말뚝 본체 손상 여부를 기록하고 보수 승인 절차를 둠", ], "high_risk": True, }, { "id": "bolt_connection_defect", "title": "고장력볼트 체결불량/재체결 대응", "required_any": [ "볼트", "고장력", "핀테일", "체결", "조임", "나사산", ], "triggers": [ "고장력 볼트", "고장력볼트", "T/S 볼트", "T/S볼트", "ts볼트", "핀테일", "체결력 부족", "체결력부족", "조임토크", "본조임", "재체결", "야마", "나사산", "볼트 교체", ], "canonical_terms": [ "고장력볼트", "볼트접합", "조임토크", "체결검사", "재체결", "접합부 안전성", ], "code_bundle": BOLT_CONNECTION_DEFECT_CODES, "missing_conditions": [ "볼트 종류, 강도 등급, 마찰접합/지압접합 구분", "핀테일 파단 상태, 토크렌치 검교정, 체결 순서", "나사산 손상, 와셔 상태, 재사용 여부", "접합면 마찰면 처리와 구멍 오차", "교체 중 임시 지지와 주변 볼트 응력 재분배 검토 필요성", ], "compliance_checklist": [ "불량 체결부를 표시하고 추가 하중이 걸리는 작업을 통제", "시공 시방의 검사·재체결·교체 기준과 설계기준의 접합부 안전성을 분리 검토", "재사용 금지 대상과 체결 장비 검교정 상태를 확인", "교체 후 전수 또는 표본 검사 범위를 감리 승인 절차로 확정", ], "high_risk": True, }, ] def detect_query_concepts(query: str, scenario: str | None = None) -> list[dict[str, Any]]: """Return concept packs whose practical trigger terms appear in the query.""" text = f"{query or ''} {scenario or ''}".lower() detected: list[dict[str, Any]] = [] for pack in CONCEPT_PACKS: if pack.get("id") == "concrete_defect_response": continue required_any = [term.lower() for term in pack.get("required_any", [])] if required_any and not any(term in text for term in required_any): continue hits = [term for term in pack["triggers"] if term.lower() in text] if not hits: continue detected.append({ "id": pack["id"], "title": pack["title"], "matched_terms": hits, "canonical_terms": list(pack["canonical_terms"]), "code_bundle": [dict(item) for item in pack["code_bundle"]], "missing_conditions": list(pack["missing_conditions"]), "compliance_checklist": list(pack["compliance_checklist"]), "high_risk": bool(pack.get("high_risk")), }) return detected def concept_code_bundle(concepts: list[dict[str, Any]]) -> list[dict[str, Any]]: """Flatten concept code bundles, preserving first occurrence order.""" bundle: list[dict[str, Any]] = [] seen: set[str] = set() for concept in concepts: for entry in concept.get("code_bundle", []): code = normalize_standard_code(entry.get("code")) if not code or code in seen: continue seen.add(code) item = dict(entry) item["code"] = code item["concept_id"] = concept.get("id", "") item["concept_title"] = concept.get("title", "") bundle.append(item) return bundle def augment_parent_candidates( parent_candidates: list[dict[str, Any]], query: str, *, parent_limit: int, scenario: str | None = None, ) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: """Prepend concept-derived standard candidates for recognized practical terms.""" concepts = detect_query_concepts(query, scenario) if not concepts: return parent_candidates[:parent_limit], [] augmented: list[dict[str, Any]] = [] seen: set[str] = set() rank = 1 for entry in concept_code_bundle(concepts): code = entry["code"] if code in seen: continue seen.add(code) augmented.append({ "code": code, "doc_type": canonical_doc_type(code, entry.get("doc_type", "")), "name": entry.get("title", ""), "parent_rank": rank, "parent_doc_score": float(entry.get("parent_doc_score", 0.7)), "concept_id": entry.get("concept_id", ""), "concept_title": entry.get("concept_title", ""), "concept_role": entry.get("role", ""), }) rank += 1 if augmented: return augmented[:parent_limit], concepts for item in parent_candidates: code = normalize_standard_code(item.get("code")) if not code or code in seen: continue seen.add(code) copied = dict(item) copied["code"] = code copied["parent_rank"] = rank augmented.append(copied) rank += 1 if len(augmented) >= parent_limit: break return augmented[:parent_limit], concepts def expand_query_for_concepts(query: str, concepts: list[dict[str, Any]]) -> str: """Append canonical concept terms so clause search can find standard wording.""" terms: list[str] = [] for concept in concepts: for term in concept.get("canonical_terms", []): if term not in terms: terms.append(term) if not terms: return query tail = " ".join(terms) return f"{query} {tail}".strip() def build_answer_contract( query: str, scenario: str | None, results: list[dict[str, Any]], ) -> dict[str, Any]: """Build a user-facing practical review contract from concepts and evidence.""" concepts = detect_query_concepts(query, scenario) if not concepts: return { "query_concepts": [], "basis_review_plan": [], "missing_conditions": [], "compliance_checklist": [], "evidence_expectation": {"expected_code_bundle": [], "covered_codes": [], "missing_bundle_codes": []}, "basis_evidence": [], "answer_outline": { "standard_priority": [], "required_inputs": [], "compliance_workflow": [], "evidence_cautions": ["검색된 조항 근거가 없으므로 기준명, 수치, 적합성 판단을 확정하지 않습니다."], }, } expected_bundle = concept_code_bundle(concepts) expected_codes = [entry["code"] for entry in expected_bundle] covered_codes = [] for result in results: code = normalize_standard_code(result.get("code")) if code and code in expected_codes and code not in covered_codes: covered_codes.append(code) missing_conditions: list[str] = [] compliance_checklist: list[str] = [] for concept in concepts: for item in concept.get("missing_conditions", []): if item not in missing_conditions: missing_conditions.append(item) for item in concept.get("compliance_checklist", []): if item not in compliance_checklist: compliance_checklist.append(item) basis_review_plan = [ f"{entry['code']} - {entry.get('role') or entry.get('title', '')}" for entry in expected_bundle[:8] ] covered_code_set = set(covered_codes) missing_bundle_codes = [code for code in expected_codes if code not in covered_code_set] from src.standard_links import resolve_standard_link basis_evidence = [] for entry in expected_bundle: link_fields = resolve_standard_link(entry["code"]) basis_evidence.append({ "code": entry["code"], "title": entry.get("title", ""), "role": entry.get("role", ""), "evidence_status": "covered" if entry["code"] in covered_code_set else "missing", **link_fields, }) evidence_cautions = [] if missing_bundle_codes: evidence_cautions.append( "검색 trace가 없는 후보 기준은 최종 수치나 적합성 판단에 사용하지 말고 추가 조항 검색으로 보강합니다." ) evidence_cautions.append( f"추가 확인 후보: {', '.join(missing_bundle_codes[:8])}" ) else: evidence_cautions.append("concept 기준 묶음의 주요 후보가 모두 검색 trace로 확인되었습니다.") return { "query_concepts": [ { "id": concept["id"], "title": concept["title"], "matched_terms": concept["matched_terms"], "canonical_terms": concept["canonical_terms"], "high_risk": concept["high_risk"], } for concept in concepts ], "basis_review_plan": basis_review_plan, "missing_conditions": missing_conditions, "compliance_checklist": compliance_checklist, "evidence_expectation": { "expected_code_bundle": expected_codes, "covered_codes": covered_codes, "missing_bundle_codes": missing_bundle_codes, }, "basis_evidence": basis_evidence, "answer_outline": { "standard_priority": basis_review_plan, "required_inputs": missing_conditions, "compliance_workflow": compliance_checklist, "evidence_cautions": evidence_cautions, }, }