From f50bf7e4943258d7f2b323cab8d55b44e4ae42a3 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 21 Sep 2026 23:56:03 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(M01):=20=EC=9D=B4=EB=A6=84=20=EA=BC=B4?= =?UTF-8?q?=20=EC=8B=9D=EC=9D=B4=20=ED=91=9C=20=EC=97=B4=EC=87=A0=20?= =?UTF-8?q?=EB=B3=84=EC=B9=AD=EC=9D=84=20=EB=B0=91=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=ED=92=80=EC=96=B4=EC=93=B0=EB=8D=98=20?= =?UTF-8?q?=ED=9D=A0=20=EA=B3=A0=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 별칭 이름이 QC001882 처럼 표 열쇠 그대로면 요소 열쇠로 읽혀 밑이름 풀어쓴 글자가 나옴. 요소 테이블(LB·EQ·MT·MP·MO)만 이름으로 풀고 그 밖은 별칭 이름 그대로. 로직 전수 1,291 — 새는 줄 0 (옛 동작과 다른 로직 196) · 값 식·계 그대로 · 시험 추가(21 통과). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj --- resources/master_data/ref/_검증_이름식.md | 5 +++++ resources/master_data/scripts/master_text.py | 5 +++++ resources/tester/test_m01_text.py | 9 +++++++++ 3 files changed, 19 insertions(+) diff --git a/resources/master_data/ref/_검증_이름식.md b/resources/master_data/ref/_검증_이름식.md index 7158999b..f3163eaf 100644 --- a/resources/master_data/ref/_검증_이름식.md +++ b/resources/master_data/ref/_검증_이름식.md @@ -24,3 +24,8 @@ ## 뺀 것 — 검증 도구 자체의 오탐(제품 결함 아님) GC000996 짝=6·7 — 별칭 값칸 이름이 「그라우팅 믹서(190×2ℓ)」처럼 **띄어쓰기가 든 값칸 키**라, 이번 검증 스크립트가 공백으로 토큰을 가르다 오탐(값칸 이름 자체는 별칭 목록의 실제 값칸과 그대로 같음 — 실제 어긋남 아님, 목록에서 뺌). + +## 고친 뒤 (2026-09-21) + +원인 — 별칭 이름이 표 열쇠 그대로(`QC001882`)면 식 읽기가 그것을 「요소 열쇠」 로 읽어 이름을 밑이름 풀어쓴 글자로 바꿈. `master_text._elem_name` 이 요소 테이블(LB·EQ·MT·MP·MO)만 이름으로 풀고 그 밖 열쇠(QC·QF…)는 별칭 이름 그대로 두게 고침. +로직 전수 1,291 — 이름 식에 별칭 목록 밖 열쇠·풀어쓴 밑이름이 새는 줄 **0**. 이전 동작과 비교하면 이름 식이 달라지는 로직은 **196**(표본 2건이 아니라 같은 꼴 196). 값 식·계는 그대로. 시험 `test_m01_text.py` 에 GC001008 추가(21 통과). diff --git a/resources/master_data/scripts/master_text.py b/resources/master_data/scripts/master_text.py index cfdf7203..f234e6c2 100644 --- a/resources/master_data/scripts/master_text.py +++ b/resources/master_data/scripts/master_text.py @@ -19,6 +19,7 @@ import master_formula as mf PLACES = Decimal("0.0001") # 화면 `formatNumber` 와 같음(소수 넷째 자리까지) PRICE_TAIL = {"인력": "노임", "기계": "손료"} # 단가 자리의 이름 꼬리(그 밖은 「단가」) +ELEM_KEYS = ("LB", "EQ", "MT", "MP", "MO") # 요소 테이블 — 그 밖의 열쇠(QC · QF …)는 별칭 이름 ELEM_TAIL = {"LB": "노임", "EQ": "손료"} # 식 안 요소 키의 이름 꼬리(그 밖은 「단가」) _PREC = {"또는": 1, "그리고": 2, "==": 3, "!=": 3, "<": 3, "<=": 3, ">": 3, ">=": 3} _PREC |= {"+": 4, "-": 4, "*": 5, "/": 5} @@ -86,6 +87,10 @@ def named(show, real, env: dict, master, depth: int = 0) -> str: def _elem_name(master, ref: str) -> str: """식 안 요소 한 줄의 이름 — 「석공노임」 꼴(같은 이름의 중간 값과 헷갈리지 않게).""" + if ( + str(ref)[:2] not in ELEM_KEYS + ): # 별칭 이름이 표 열쇠 그대로인 것(QC…) — 밑이름을 풀어쓰지 않음 + return ref try: name = mc.plain(master.get(ref).get("이름")) except mf.FormulaError: diff --git a/resources/tester/test_m01_text.py b/resources/tester/test_m01_text.py index 22479b75..4ff426c0 100644 --- a/resources/tester/test_m01_text.py +++ b/resources/tester/test_m01_text.py @@ -151,3 +151,12 @@ def test_끝수는_줄이_아니라_소계에_붙는다(client: TestClient) -> N assert group["끝수"] == "원 미만 버림" assert Decimal(str(group["소계"])) == Decimal(str(group["소계"])).to_integral_value() assert not any("버림" in one["글"] for one in group["줄"]) + + +def test_이름_꼴_찾기_별칭이_표_열쇠_그대로면_밑이름으로_풀지_않는다(client: TestClient) -> None: + """GC001008 덧줄 — 별칭 이름이 QC001882 뿐이라 이름 식도 별칭 목록의 그 이름을 씀.""" + got, _ = _both(client, "GC001008") + extra = next(one for one in _all_lines(got) if one["이름"].startswith("공구손료")) + assert "QC001882.요율 %" in extra["이름글"] + assert "잔디깎기공구손료" not in extra["이름글"] + assert any(one["이름"] == "QC001882" for one in got["별칭"]) From 60d67b310a09f8c96dede86255ac357a31c7b05a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 21 Sep 2026 23:56:59 +0900 Subject: [PATCH 2/2] =?UTF-8?q?knowledge(M01):=20=EA=B4=80=EA=B8=89=20?= =?UTF-8?q?=EB=82=A8=EC=9D=80=20=EB=AA=BB=20=EC=B1=84=EC=9B=80=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20=E2=80=94=20=EC=A4=91=EC=98=A8=20=EC=95=84=EC=8A=A4?= =?UTF-8?q?=EC=BD=98=20=C2=B7=20KP=20=EC=A0=91=ED=95=A9=EB=B6=80=EC=86=8D?= =?UTF-8?q?=20=C2=B7=20=EA=B7=B8=20=EB=B0=96=2014=EC=A4=84=20=EA=B9=8C?= =?UTF-8?q?=EB=8B=AD=20(=EC=9D=BC=EA=B0=90=2022)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8 --- .../master_data/ref/_검증_관급_가까운줄.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/resources/master_data/ref/_검증_관급_가까운줄.md b/resources/master_data/ref/_검증_관급_가까운줄.md index 9a8acd9a..4ffd0f22 100644 --- a/resources/master_data/ref/_검증_관급_가까운줄.md +++ b/resources/master_data/ref/_검증_관급_가까운줄.md @@ -80,3 +80,46 @@ - 이미 채운 회색 14줄은 나대영 최저가(엄격한 짝) — 다산 지역가와 -10~-29% 벌어짐(전북만 0%): 대구경북 -19% · 경기 -12% · 대전충남 -14% · 광주전남 -17% · 충북 U -29% · 충북 I형 6cm -28% · I형 8cm -10%. - 사용자 확정 거리: ① 지역별 다산 값(지역 조합가)과 조달청 전지역 나대영가 중 무엇을 기준으로 할지 ② 색은 나대영 U102 · U104 를 적색으로 볼지 ③ 청원 11,110 을 경기 전체에 쓸지. + +## 나머지 못 채운 줄 정리 (일감 22 · 채우지 않음 · 사용자 확정 거리) + +- 일감 21 뒤 못 채움 112줄 = 소형고압블록 49 · 접속티 4(일감 21에서 null) · 아래 59줄. 이번에 채운 줄 0 — 같은 물건이 확실한 줄이 없음. +- 아래 59줄 = 중온 아스콘 지역 없음 28 + KP 접합부속 17 + 그 밖 14(생태 3 · 본우드 3 · 아스콘 지역 묶음 3 · 전주 중온 3 · 슈퍼셀 1 · 레미콘 1). 세부는 아래. + +### ① 중온 아스콘 「지역 없음」 28줄 + +다산 지역은 시군 묶음이고, 조달청 중온 줄은 조합마다 시군을 다르게 묶음. 등급도 다름(다산은 전부 3등급 · 조달청 중온은 1등급과 3등급이 섞임). + +| 다산 지역 묶음 | 못 채운 줄 | 조달청 중온 | 못 채우는 까닭 | +|---|---|---|---| +| 세종시 · 충남(공주 · 천안 · 아산) | 10(BB-2 · 3 · 4 · MC-1 · WC-1~6) | 중온 줄 자체가 없음. 충남은 서남부(당진 · 서산 · 예산 · 홍성 · 태안 · 서천 · 부여 · 청양 · 보령)와 대전 묶음만 있고 세종 · 공주 · 천안 · 아산은 없음 | 지역 없음 | +| 전북(전주 · 완주 · 익산 · 군산) | 6(BB-3 · 4 · WC-1 · 3 · 5 · 6) | 이 시군을 묶은 중온 줄 없음. 전북 중온은 정읍 · 김제 · 고창 · 부안(서남) · 남원 · 무주 · 순창 · 임실 · 장수 · 진안(한길)뿐 | 지역 없음 | +| 전북(정읍 · 김제 · 고창 · 부안) | 6(BB-3 · 4 · WC-1 · 3 · 5 · 6) | 지역은 있음. 그러나 3등급 중온은 BB-2 · MC-1 · WC-2 · WC-4 뿐, BB-3 · WC-1 · WC-3 은 1등급만 있고 BB-4 · WC-5 · WC-6 은 아예 없음 | 지역은 맞고 그 등급 줄이 없음 | +| 전북(남원 · 무주 · 순창 · 임실 · 장수 · 진안) | 6(위와 같음) | 지역 있음 · 3등급은 BB-2 · MC-1 · WC-2 · WC-4 뿐, 1등급은 BB-2 · BB-3 · MC-1 · WC-1 · WC-3 | 같음 | + +- 등급이 다른 1등급 줄로 채우면 다른 물건 — 채우지 않음. 현재 까닭 문구 「그 지역의 중온 아스콘 줄이 없음」은 전북 정읍 · 남원 묶음 12줄에는 부정확 → 「그 지역에 그 등급(3등급) 중온 줄이 없음」으로 고칠 것(사용자 확정 뒤 데이터 반영). + +### ② KP 접합부속 17줄 (D80~D1200) + +- 다산: 관경별 「KP 접합부속」 한 줄(예 D80 17,330 · D150 26,910 · D500 89,770 · D1000 297,290 · D1200 376,620) — 접합 부품을 묶은 세트값으로 보임. +- 조달청에 그 이름의 세트는 없음. 이름이 다른 부품이 따로 있음: 「압륜」(KP메커니컬 · 단위 조) 은 동명주물 DM-80 33,800 · DM-150 45,500 · DM-250 72,500 · DM-500 220,000 · DM-700 414,000 (세계주철 등 다른 제조사 포함) · 「고무링」은 맨홀 부품뿐. +- 압륜 값이 다산 세트값의 1.7~2.5배(D80 33,800 vs 17,330 · D150 45,500 vs 26,910 · D500 220,000 vs 89,770) — 같은 물건이 아니거나 구성이 다름. D900 이상 압륜은 줄 수가 적음. +- 사용자 확정 거리: 다산 「KP 접합부속」이 압륜 한 벌인지 고무링 포함 세트인지. + +### ③ 그 밖 14줄 — 줄마다 까닭 + +| 줄 | 다산 | 조달청 | 까닭 | +|---|---|---|---| +| 아스콘 서울 · 인천 · 경기(강남 · 강동 · 송파 제외) BB-2 · WC-2 · WC-4 3등급 가열 (MT022737 · 47 · 51) | 105,500 · 131,800 · 125,770 | 그 넓은 묶음 줄은 없고 경기 시군 소묶음(조합 · 업체마다)이 많음. BB-2 는 89,590 · 100,520 · 106,670 · 107,350 이 섞여 있음 | 어느 소묶음이 다산 묶음인지 못 가림 · 최저는 다산보다 크게 낮음 | +| 아스콘 전북 전주 · 완주 · 익산 · 군산 중온 BB-2 · MC-1 · WC-2 (MT022869 · 80 · 87) | 119,500 · 134,510 · 147,760 | 그 시군 묶음 없음 · 다른 전북 묶음 값 128,110~156,860 이 +6~8% | 다른 지역 값 + 5% 밖 | +| 생태어소블록 1000×500×400 (MT007440) | 90,100 | 「어소」 품명 없음 · 생태블록은 호안 1000×1000×250(39,820) · 옹벽 1000×670×500(49,610 · 대청) | 품명 · 치수 다름 | +| 생태옹벽블록 500×500×200 · 1000×500×400 (MT007441 · 42) | 100,400 · 90,700 | 생태 옹벽 규격이 500×500 · 1000×500 인 줄 없음 | 치수 다름 | +| 합성목재(본우드) 3000×100×t16 · 3000×76×46 중공 루버 · 1200×100×100 중공 (MT014360~62) | 70,500 · 13,000 · 31,000 | 본우드 5줄 모두 2400×150×25~35 바닥재 솔리드(㎡ 단위) | 치수 · 형 · 단위 다름 | +| 콘크리트보강섬유(슈퍼셀) 셀룰로오스 0.6kg/포 (MT007635) | 14,000 | 「콘크리트보강섬유」는 내진 시트(m · ㎡) 3줄뿐 | 다른 물건 | +| 레미콘 부산 25-3-150 (MT021211) | 122,560 | 25-33-150 이 정확히 122,560(부산 소지역별 여러 제조사) · 25-30-150 은 119,000 | 다산 오기로 보이나 확정 못 함 · 강도 30 · 33 · 35 어느 것인지 다산 글자로 못 가림 · 값이 33 과 정확히 같아 오기 가능성이 큼 | + +- 사용자 확정 거리: 레미콘 25-3-150 을 25-33-150(122,560)으로 볼지 · 나머지는 조달청에 같은 물건이 없어 못 채움이 맞음. + +### 남은 수 + +- 108 → 112(일감 21의 접속티 4 추가) → 이번에 채운 것 0 → **112** = 소형고압블록 49 · 중온 아스콘 지역 없음 28 · KP 접합부속 17 · 접속티 4 · 그 밖 14. (충북 소형 회색 MT009987 1줄은 비고 없음 · 별도)