Commit Graph
21 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 b3c6f29684 refactor(B09): 불도저를 딴 파일로 분리, 장비 붙이는 자리를 한 켤레로 맞춤
- B09_Estimation_MachineProductivity_Dozer.py 신설 (8-2-1 전용).
  굴착기(8-1-4)와 한 파일에 두면 700줄을 넘고, 두 식이 섞여 읽힘.
- 굴착기 쪽 장비 붙이기를 attach_machine_share 로 올려 불도저 쪽
  attach_dozer_share 와 같은 모양으로 맞춤 — 자리를 나눠 쓰는 것이 눈에 보이게.
- 줄수: UnitPrice 652 · MachineProductivity 360 · Dozer 398.
- 224건 통과 (동작 변화 없음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 11:54:12 +09:00
eomsangdonandClaude Opus 5 b97eb042b6 feat(B09): 불도저 표(8-2-1) 읽어 갈래별 단가 세움
- FP-10-11 불도저 운반이 굴착기 식(8-1-4)으로 읽혀 「K·Cm 없음」으로 잘못
  진단되던 것을 8-2-1 식으로 읽게 함. 갈래 셋(토사·파쇄암·발파암) 각각 섬
  (1,439.7 / 3,289.3 / 3,959.4 원/㎥).
- 표가 기종 이름을 안 적어 삽날 용량 q゚ 3.2㎥ + 속도 55/70(2단)으로
  불도저(무한궤도) 19톤을 되짚음. 하나로 안 좁혀지면 안 고름.
- 공식표에만 나오는 기종을 시간당 사용료 층에 넣음 — 안 넣으면 공식이 다 서고도
  붙을 사용료가 없어 빈 일위대가가 남았음.
- 아무것도 안 붙은 제목은 걷어 냄 (화면에서 「조립 불가」로 터지던 자리).
- 시험 6건 추가, 224건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 11:47:51 +09:00
eomsangdonandClaude Opus 5 dd23c9d04f feat(B09): 기계만 쓰는 공종이 공식만으로 서게 함 — 층따기 살아남
「미판정 77건」을 훑다 나온 것 — 그중 일부는 **미판정이 아니라 시공능력 공식표**였음
```
F0287 9-18 층따기        굴착기 0.7㎥ · K 0.9 · f 1/1.3 · E 0.7 · Cm 22
F0328 11-4 쇄석·혼합석 부설  같은 모양
```
- ⚠ **자원 줄이 하나도 없으면 조립 반복문이 그 공종을 아예 안 보고 있었음** —
  표에 인력 줄이 없는 기계 전용 공종이 그 자리. 공식이 온전하면 세우게 고침
- 층따기 **1,550.9원/㎡** · 쇄석 부설 **3,549.5원/㎡** 로 섬 (일위대가 203 → 206)
- 내역서(2f940d8a) 합계 **2,149,464 → 6,252,172원** —
  층따기 2,645.21㎡ × 1,550.9 = 4,102,708 이 실제로 붙음
- ⚠ 짝 시험 — 자원도 공식도 없으면 **여전히 안 섬**(0 원 일위대가 금지).
  그 문이 넓으면 빈 제목이 무더기로 서고 화면이 「단가가 있다」고 거짓말함

검증: pytest 215 통과(신규 2)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 10:37:50 +09:00
eomsangdonandClaude Opus 5 6aa8001780 fix(B09): 「성분이 빠져 못 세움」을 「일위대가 없음」과 갈라 냄
메인 창이 물음 — 종단배수 셋이 같은 모양(밑수 1 m)인데 맹암거만 금액이 서고
산마루측구·소단측구는 안 서는 까닭

**표 성격이 달랐음** — 맹암거(F0345)는 수량이 실제로 적힌 소요량표라 자원 4줄이
붙어 25,492.1원/m 로 섬. 나머지 둘은 **수량 칸이 비어 있고 참조로만** 적힘
```
FP-12-09-02  철근가공조립 | ton | (빈칸) | 「철근가공조립(간단)의 30%」
FP-12-09-03  거 푸 집    | 회  | (빈칸)
```
⇒ 값을 지어낼 수 없어 **금액을 안 만드는 것이 맞음**(지금 방침 그대로)

- 다만 화면 사유가 **「일위대가 없음」으로 뭉뚱그려지고** 있었음 — 「아직 안 만든 것」과
  「성분이 빠져 못 세운 것」은 **할 일이 다름**. 사유를 갈라 적음:
  「성분이 빠져 단가를 못 세웠습니다 — 철근가공조립 줄을 못 풀었습니다」
- `UnitPriceBuild.component_gaps` 로 자원 축의 사유를 화면까지 나름
- 짝 시험 — 성분 빠진 쪽은 금액 없음 + 사유 표시, **맹암거는 그대로 금액이 섬**

검증: pytest 213 통과(신규 1). 맹암거 40m × 25,492.1 = 1,019,685원 —
메인 값과 일치

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 10:32:37 +09:00
eomsangdonandClaude Opus 5 52d76a9286 fix(B09): 제잡비 밑수 = 직접노무비 + 안 불리던 가드 잇기 + 700줄 분리
메인 창이 B09 를 읽기 전용으로 교차검토해 낸 지적을 처리

제잡비 밑수 — **사람 품(직접노무비)만**으로 바꿈. 기계 안의 조종원 노임은 안 셈
- 근거 셋을 주석에 인용: 산림품셈 13-6-2 [주]③ 「노무비의 합계액」 ·
  건설품셈 제8장 「잡재료 등 손료 : **직접노무비**에 …」 ·
  같은 장에서 기계를 넣을 때는 「노무비, 기계손료 및 운전경비의 합」이라 **따로 적음**
- 뜻으로도 그쪽 — 제잡비는 **본 자원에 안 선 잔 기계 손료**를 사람 품에 비례해
  얹는 자리인데 그 표엔 굴착기가 이미 본 자원으로 서 있음
- 찰쌓기 60~80 기준 ㎡당 2,565.90 → **2,098.46** (제잡비 붙는 17줄 전부 걸림)
- ⚠ 잠정 — 사용자 확정 대기. 조종원 포함이면 약 +22 %

안 불리던 가드 둘 (「있다」와 「돈다」는 다름)
- ㉥ 물빼기 파이프 — **조판에서 실제로 부름**. 지금은 늘 아랫단이라 안 걸리되
  설계 조건이 실리는 날 그 값만 바꾸면 바로 걸림
- ㉢ 배합 분해 — 부를 자리가 아직 없음. **그 사실과 부를 위치를 코드에 적음**

700줄 제한 (CLAUDE.md 4장) — 셋을 나눔
- `_UnitPrice_View`(화면용 조회) · `_ResourceAxis_Sources`(자료 적재·셀 파싱) ·
  `_BillOfQuantities_Rows`(줄 만들기). 가르는 금을 각 파일 머리말에 적음
- 부르는 쪽이 어디서 오는지 신경 쓰지 않게 재수출

물결표 목록을 `RANGE_DASHES` 한 곳으로 모음 — 네 파일에 따로 적혀 서로 달랐음
(지금 물리는 것은 없었으나 같은 목록이 네 벌이면 언젠가 하나만 고쳐짐)

검증: pytest 206 통과, 700줄 초과 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 05:39:47 +09:00
eomsangdonandClaude Opus 5 db0b38d826 feat(B09): 갈래 키를 이쪽에서 만듦 — 물결표 통일 + 구간 판정
두 창 합의 — B08 은 **의미**만 보내고(`work_item_code` + 저장 제원 원본값),
품셈 원문 표기를 키로 옮기는 것은 **원문을 읽는 이쪽 몫**

- 품셈이 물결표를 두 종류로 섞어 씀(`∼` U+223C 26건 · `~` U+FF5E 8건) —
  같은 뜻인데 키가 두 벌이었음. 키에서만 한 종류로 모으고 **원문 문구는 이름에 보존**
- ⚠ 규칙은 둘뿐 — **내부 공백 제거 + 물결표 통일**. 키에 쓰인 글자를 세어
  그 밖에는 소수점·괄호뿐임을 확인(하이픈·곱셈표 없음)
- 「60~80」은 「직경60㎝이상~80㎝미만」 **안에 없어**(사이에 「㎝이상」이 낌)
  글자 포함으로는 못 맞춤 → **수의 짝**으로 견줌
- 저장 제원이 한 값으로 오는 경우(뒷길이 45㎝)는 **그 값을 담는 가장 좁은 구간**을
  고름 — 45 → `#55cm이하`, 25 → `#35cm이하`
- ⚠ 담을 갈래가 없으면 `None` — **가까운 것을 임의로 고르지 않음**(95 → 없음)
- 조판이 `variant_axis`·`variant_value` 를 받아 코드를 고르고, 못 고르면
  종전대로 후보를 보임

검증: pytest 198 통과(신규 5 — 짝 시험 포함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 04:56:51 +09:00
eomsangdonandClaude Opus 5 c2a8f7cc41 feat(B09): 제잡비를 경비로 붙임 + ㉥ 물빼기 파이프 가드 + 성분 빠짐 차단 확대
제잡비 (품셈 13-6-1·13-7-1 [주]③, 원문은 메인이 찾아 줌)
- **노무비 합계 × 비율이 경비(J)로** 붙음. 재료·노무가 아님
- 기본은 **아랫단**(물빼기 파이프 미설치). 「상한」이라 산출근거에 그 사실을 적음
- `PriceDetail.percent_of_labor` 신설 — 밑수가 3분할 전체인 `percent_of_parent` 와
  다름. 비율 줄은 참조를 풀기 전에 처리(자기 자신을 가리켜 순환으로 잡혔음)
- 표시 합계에도 넣음 — 안 넣으면 화면 합계와 실제 단가가 어긋남

㉥ 가드 신설 — 제잡비 윗단(파이프 설치)을 쓰면서 물구멍을 자재로 또 실으면 멈춤
  (원문이 「상단에는 파이프 설치의 노무비·재료비를 포함한다」고 명시).
  짝 시험 4건 — 아랫단·파이프 없음·비슷한 이름은 안 걸림

성분 빠짐 차단 확대
- 시간·대수로 세는 줄(장비 몫)을 못 맞추면 그 공종 금액을 안 만듦.
  초본류 시비가 「트럭(2.5t) 2.6시간」을 빼고 33.1원/㎡ 로 서 있었음
- 자재 줄(kg·매)은 이미 알려진 미결이라 막지 않고 드러내기만 함
- 요약의 「의심 저가」에서 막아 둔 공종은 제외 — 새로 살펴야 할 것과 섞이지 않게

뭉친 표 두 곳 수정
- 칸 전체를 한 이름으로 먼저 시도 — 「굴착기 (무한궤도)」가 안 풀려 찰쌓기 13-6-2 의
  장비 몫이 빠지고 공종이 막혀 있었음
- ⚠ 라벨 줄 판정에 **순수 숫자 칸** 검사 추가 — 「자재 | 종자 | kg | 0.025」를
  라벨 줄로 오해해 씨앗뿜어붙이기 표를 가로챘음(회귀, 시험이 잡음)

결과: 자원 축 354 → 418, 일위대가 176 → 203, 막힌 공종 32
  찰쌓기 13-6-2 = 118,794.9원/㎡ (노무 + 굴착기 0.48h + 제잡비 3 %)

검증: pytest 190 통과(신규 6)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 04:22:56 +09:00
eomsangdonandClaude Opus 5 15bdf6bd64 feat(B09): 뭉친 이름+갈래 열 표 읽기 — 돌쌓기 계열 성립
메인이 `reference` 오판 41건을 되살려(bc4b6837) 돌쌓기(장비)가 마스터에
들어왔으나, 그 표는 **이름도 값도 뭉쳐 오고 열이 규격 갈래**인 또 다른 모양이라
여전히 안 섰음 (「석공 보통인부 | 0.09 0.05 | 0.08 0.04 | 0.07 0.03」)

- 뭉친 이름·값을 갈래 열에 짝지어 읽음. 개수가 어긋나면 표째 버림
- 「굴착기+부착용 집게」는 **두 기종 조합**으로 보아 같은 시간을 둘 다 붙임
  (TODO(미결) 해석 잠정 — 사용자 확인 대기)
- 규격이 **옆 칸**에 있고 갈래(무한궤도)가 안 적힌 기종은 규격 일치 + 무한궤도
  우선으로 잠정 채택. 카탈로그 규격이 범위(0.6∼0.8)면 그 안에 드는지로 판정
- ⚠ 「1.04(1.17)」 괄호값은 **조건 시공 시 대안값**임이 원문에서 확인됨
  (13-6-1 [주]② 흡출방지재 시공 시 ( ) 값). 기본은 괄호 밖, 대안값은
  `alternative_amount` 로 남겨 화면에 「시공 시 다름」으로 보이게 함
- 라벨 줄 판정을 **모든 칸**으로 — 첫 칸만 보면 기초잡석 12-25 를 라벨 줄로
  오해해 표째 가로챘음(그 탓에 기초잡석이 한때 다시 막혔음)
- 갈래 키를 **공백 없는 것**으로 통일(`#보통`), 원문 문구는 이름에 보존
  (두 창 합의)

결과: 자원 축 259 → 354, 일위대가 145 → 176
  돌쌓기(찰) 35cm이하 58,166.7 / 55cm이하 52,938.7 / 75cm이하 46,892.7 원/㎡
  메쌓기·찰쌓기·붙이기 계열도 직경 3갈래로 섬

검증: pytest 184 통과(신규 1). 화면 실측 — 지금 인계 자료에 구조물 줄이 없어
표에는 아직 안 뜸(B08 이 갈래를 골라 보내면 그대로 금액이 섬)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 02:04:42 +09:00
eomsangdonandClaude Opus 5 7591670e93 fix(B09): 값 못 읽은 자원 줄이 있는 공종은 금액을 막음
기초잡석 12-25 를 붙이다 발견 — `소할(30%) | 할석공(인) | 0.2 × 30%` 를
못 읽어 **부설다짐 0.6인만으로 107,145원**이 서고 있었음. 값이 그럴듯해
어떤 검사에도 안 걸림(「부분 성공이 가장 위험」)

- 이름 칸 판정을 **낱말 목록이 아니라 「풀리는지」**로 바꿈 — 첫 칸이 공정 이름인
  표(기초잡석)가 딱지 목록에 없어 통째로 못 맞추고 있었음. 자원 축 231 → 243
- **자원은 알아봤는데 값을 못 읽은 줄**이 있으면 그 공종을 `partial_items` 로
  표시하고 일위대가 금액을 만들지 않음. 그런 공종이 **28건** 있었고,
  그중 23건이 조용히 성분 빠진 단가로 서 있었음
- 못 읽은 줄은 `unmatched` 에 사유째 남김

검증: pytest 172 통과(신규 2 — 표시되는지 + 실제로 막는지 짝)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 01:14:47 +09:00
eomsangdonandClaude Opus 5 d78f59ba5c feat(B09): 밑수 반영 재생성 + 밑수 미확보 줄 차단 + ㉡ 무대 가드 가동
B08 이 밑수(「10㎡당」 같은 기준 수량)를 본문에서 찾아 181표를 채움.
그 위에서 자원 축·일위대가를 다시 냄

- **떼채취 평떼 1,032,408 → 10,324원/㎡** — 100 배 부풀어 있던 것이 교정됨.
  「100매당일 것」이라던 의심이 실제로 `100㎡당`이었음
- 기준 미상 122 → 40, 100만원 초과 10 → 2 건. 중앙값 73,989 → 48,961
- 파생물 지문이 새 마스터(`fe454c56…`)로 따라 바뀜 — 낡음 감지 장치가
  처음으로 실제 갱신에서 동작 확인됨

밑수 미확보 표(`basis_missing` 144건 → 26 공종)
- 1 단위당으로 단정하면 곱셈이 10배·100배 틀리므로 **곱하지 않음**.
  내역서에 「밑수를 못 찾은 표입니다 — 곱하지 않았습니다. 원문 4-4. 가지정리」로 뜸

㉡ 무대 가드 가동 (B08 이 운반을 실물로 내기 시작)
- 인계에서 `haul_distance_m`·`haul_equipment` 를 받아 조판에서 실제로 호출
- 무대(20 m 이내)는 줄로 서되 금액 없음. 운반토량 합이 총 절취량을 넘는지도 검사
- 짝 시험 — 무대에 단가가 붙으면 멈추고, **암 운반·덤프 줄은 안 걸림**

검증: pytest 170 통과(신규 3)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 01:11:32 +09:00
eomsangdonandClaude Opus 5 2ad66dce5d feat(B09): 열이 자원인 표(전치형) 읽기 + 오독 3종 차단
품셈에는 자원이 행이 아니라 **열 머리**에 오는 표가 39건 있음
(「구 분 | 콘크리트공(인) | 보통인부(인)」, 행은 무근·철근·소형구조물).
행-자원으로 읽어 콘크리트 타설(12-1)이 하나도 안 서고 있었음

- 갈래(variant)마다 따로 세움 — 품이 달라 뭉치면 어느 것도 안 맞음.
  코드는 `B-FP-12-01-01#무근구조물`, 이름에 갈래를 적어 사람이 고를 수 있음
- 레디믹스트콘크리트 타설: 무근 58,635.0 / 철근 65,826.4 / 소형 117,270.0 원

읽다가 잡은 오독 3종 — 전부 **고쳐 읽지 않고 버림** (자리를 단정할 수 없음)
- 병합 셀로 한 칸 밀린 행: 목재틀흙막이가 등급 글자를 건축목공 자리에 두어
  단가 503만원으로 섰음
- 좌우 두 판이 붙은 표: 소운반에서 거리값 60 이 「보통인부 60인」으로 읽혀
  1,553만원이 섰음. 열 머리가 되풀이되면 표째 버림
- 같은 갈래 이름 중복: 목재틀흙막이 「상」이 8.760 + 13.767 로 합산돼
  667만원이 섰음. 그 줄들을 버림
- 갈래 이름에 자원용 머리글 필터를 쓰던 것도 고침 — 「중」·「상」 등급이
  통째로 지워지고 있었음. 합계 줄만 걸러 냄

기준 단위 미상 드러내기 (막지 않음 — 막으면 125 중 122 가 멈춤)
- `unknown_basis` 122건, 그중 100만원 넘는 10건을 목록으로 냄
  (떼채취 평떼 1,032,408원 등 — 「100매당」류 묶음 기준 의심)
- 내역서 줄 비고에도 「기준 단위가 표에 없습니다 — 수량 단위와 같다고 보고
  곱했습니다」를 적음. 반영률 문구를 덮지 않고 이어 붙임

700줄 제한으로 전치형 처리를 `_Transposed.py` 로 분리 (647 + 138줄)

검증: pytest 163 통과(신규 5). 자원 축 198줄·갈래 54,
일위대가 85 → 125, 분포 최소 233.4 · 중앙 72,268.5 · 최대 5,030,954.6

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 00:53:58 +09:00
eomsangdonandClaude Opus 5 8076731f01 feat(B09): 기계 시공능력 공식으로 토공 장비 몫 조립
- 품셈 8-1-4 `Q = 3600÷Cm · q · K · f · E` 구현. 계수는 품셈 표에서 읽고
  q(버킷 용량)는 기종 규격에서 옴. 수량 1단위당 기계 소요시간 = 1÷Q
- 「유압식백호우 (무한궤도,0.7㎥)」를 카탈로그 굴착기(무한궤도) 0.7 로 이음.
  이름·규격이 둘 다 맞을 때만 고름
- 배분율 표는 각 몫을 그 비율만큼만 셈 — 인력 0.23인 × 10 %, 장비 1/Q × 90 %.
  종전엔 인력 원단위가 전량에 곱해져 9 배 부풀 자리였음
- 범위 표기(「0.55∼0.45」)는 확정값이 아니므로 가운데값을 취하지 않고
  `FactorGap` 으로 드러냄. 계수 16 표 성립 / 못 세운 것은 목록으로 남김
- 산출근거 문구를 줄에 적어 사람이 검산 가능
  (예 `Q = 3600 ÷ 18 × 0.7 × 0.9 × 0.77 × 0.60`)

결과: 배분율 미완 25 → 13 공종. 측구터파기 토사 5,288.4원/㎥
(인력 3,957.5 + 장비 1,330.9). 실물 인계자료 내역서 합계 478,680원

㉣ 오탐 방지: 이 모듈은 `reject_efficiency_in_hourly_rate` 를 부르지 않음.
E 는 품셈이 작업량 쪽에 넣으라는 값이라 여기서 막으면 정상 계산이 멈춤.
짝 시험 3건으로 못 박음 — Q 의 E 는 통과 / 사용료의 E 는 차단 /
같은 E 가 두 번 곱해지지 않았는지 금액으로 대조

검증: pytest 158 통과(신규 12). 공식은 손계산과 일치(58.212㎥/hr)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 00:43:11 +09:00
eomsangdonandClaude Opus 5 a71031b1f0 feat(B09): ④ 예산내역서 조판 + 배분율 표 오독 차단
조판
- B08 인계 응답을 계층 선 내역서로 접음. 계층·정렬은 공종 마스터의
  `parent_code`·`sort_order`(256 간격)에서 옴 — 코드 글자수로 깊이 안 셈
- ITEM NO. 를 가지치기 나무에서 매김. 머리글 줄은 수량·금액 없음
- `in_bill=false`(보정량계)는 수량만 보이고 금액 안 붙임.
  `check_excluded_rows_not_priced()` 가 수치로 막음 (㉡ 확장)
- 단가 없는 줄·공급 구분 미정 자재는 0 으로 안 때우고 `missing` 에 이름째 남김
- 잎에 일위대가가 없고 하위에 있으면 **후보만 보임** — 임의로 고르지 않음
- 반영률은 적기만 함(B08 이 이미 곱함) — 여기서 또 곱하면 두 배

배분율 표 오독 차단 (2026-09-08 실측으로 발견)
- 분류 딱지가 「인력(10%)」처럼 비율을 달고 오면 판정이 빗나가 자원이 통째로
  빠지고 있었음. 측구터파기(FP-09-12-01)는 자원 줄이 0 개였음
- 비율 꼬리표만 떼고 정확 일치 유지 — 「보통인부(인)」·「인력운반공」은 안 걸림
- 자원 축 119 → 144 줄, 일위대가 73 → 85. 기존 줄 변경 0·삭제 0
- ⚠ 그 표들은 인력 몫만 붙음(장비 몫은 시공능력 공식). 그대로 두면
  인력 10 % 몫 단가가 전량에 곱해져 **조용히 틀림** — 25 공종을
  `partial_ratio` 로 표시하고 내역서에서 금액을 안 붙임

검증: pytest 146 통과(신규 10). 가드는 일부러 어겨 멈추는 것까지 확인,
오탐 짝 시험 포함. 실물 인계자료(프로젝트 5cff3920)로 조판 실행 —
14 줄·검산줄 1·미확보 14 건이 이름째 뜸

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 00:31:17 +09:00
eomsangdonandClaude Opus 5 ca881fbb18 feat(B09): 원가계산 화면에 공종 수량 연결
- 공종 수량(코드=수량)을 일위대가에 곱해 직접비 3분할 생성, ⑤ 원가계산서
  밑수로 투입 — 뭉치지 않고 재료·노무·경비 성분 그대로 전달
- 단가 없는 공종은 0 으로 안 때우고 `missing_unit_prices` 로 화면 노출
- 계산 원천을 화면에 표시 (「수량 원천: 손입력 / 직접 입력」)
- ⑤ 표에 찍히는 값은 자원 집계표 규칙(반올림)으로 절단 — 소수점 유출 제거
- 일위대가 요약에 총액 분포(최소·중앙·최대)·의심 저가 목록 추가

검증: pytest 136 통과, 공용 브라우저(5174) 실측 — 수량 입력 후 재계산 시
재료비 10,478,189 · 순공사원가 84,454,045 · 총공사비 113,652,213,
미매칭 공종 1건 화면 표시 확인

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 00:09:27 +09:00
eomsangdonandClaude Opus 5 2faca7ac09 feat(B09): ⑤↔③ 연결 — 일위대가 3분할을 직접비로 접어 넣음 (뭉치지 않음)
**⚠ 일위대가 합계를 순공사비로 뭉쳐 넣으면 ⑤ 의 밑수가 전부 틀림**(8-9 규칙 2) —
산재·고용은 노무비, 건강·연금은 직접노무비, 기타경비는 재료비+노무비를 봄.
일위대가가 3분할을 이미 들고 있으므로 **성분별로 접어 넣음**.

- `direct_cost_from_quantities({공종코드: 수량})` → **직접비 3분할**.
  단가가 없는 공종은 **0 으로 안 때우고** `missing` 에 남김 — 수량이 있는데 단가가
  없으면 그 공종이 총액에서 조용히 빠짐.
- `cost_input_from_quantities()` → 성분이 그대로 `direct_material/labor/expense_krw` 로 감.
- **뭉치면 틀린다는 것을 수치로 보이는 시험**을 둠 — 같은 총액을 노무비 한 덩어리로
  넣으면 건강보험료가 커짐(`test_lumping_would_break_the_bases`).
- ⇒ ④예산내역서 없이도 **수량만 있으면 ⑤ 가 실물로 도는 경로**가 생김.

**자재 잠정(㉡) 화면 표시** — 「사급 자재 단가는 설계자가 직접 넣습니다(6번 슬롯
「적용 단가」) — 유료 물가지 미구독 … (잠정 — 구독하면 1~5번 슬롯에 꽂습니다)」.
화면 실측으로 3줄 다 뜨는 것 확인(일위대가 67건).
- 곁가지 — 화면은 평문이라 `**강조**` 별표가 그대로 보였음. 내보내기 직전에 벗김.

자체검증 — 신규 4건 포함 `pytest tmp/tests/ -q` **133 passed** · ruff 통과 ·
백엔드 재시작 후 화면 클릭 검증.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:45:56 +09:00
eomsangdonandClaude Opus 5 0df6acb57d feat(B09): 자재 카탈로그 — 관급/사급 분리, 그리고 ⚠ 임도 자재가 관급에 없다는 발견
**`B09_Estimation_MaterialCatalog.py` 신설** — 두 창이 맞춘 이름을 그대로 씀:
`supply_type` = `owner_supplied` / `contractor_supplied` ·
`owner_supplied_install_by` = `contractor` / `owner` / `None`.

- 관급 = 나라장터 **6,999건**(`vat_basis: 부가가치세별도` → 부가세 제외 단가).
- **설치 주체는 지어내지 않음** — 원천에 없으므로 전부 `None`(미지정)으로 두고 **세어서
  알림**. 안전관리비 대상액이 관급 전액이 아니라 **도급자설치분**을 쓰므로(8-10)
  잘못 찍으면 금액이 조용히 틀리는 자리임.
- **규격 필수** — 같은 품명에 규격이 수백 개(「연돌」 410 · 「육각볼트」 323). 이름만
  맞추면 엉뚱한 규격 단가가 붙음.
- 매칭 카탈로그에 자재를 붙이면서 **이름 색인**을 넣음(7,700건이라 매번 훑으면 느림).

**⚠ 붙여 보고 알아낸 것 — 관급 목록에 임도 자재가 거의 없음**
- 나라장터 목록이 **건축·설비 자재 중심**(덕트·밸브·복공판·스피커…)이고,
  **시멘트·모래·자갈·레미콘·철근·파형강관이 한 건도 없음**.
- 까닭 둘 — ① 철근·레미콘·아스콘은 그 파일이 `excluded_named_groups` 로 **명시적으로
  빼 둠**(쇼핑몰 스냅샷 미보관) ② **시멘트·모래·자갈은 애초에 사급**임. 실무 울진에서
  관급은 **파형강관 Ø800/Ø1000 뿐**이었음.
- ⇒ **자재 매칭 0건.** 억지로 이름을 느슨하게 맞추지 않음 — 그렇게 하면 엉뚱한
  건축 자재 단가가 임도 공종에 붙음.
- **이 사실을 시험으로 못 박음**(`test_forest_road_materials_are_absent_from_owner_catalog`)
  — 나중에 「자재가 왜 안 붙나」를 다시 파는 일이 없도록.

**화면 요약 문구를 실측대로 갈아 끼움** — 「자재 카탈로그가 없어서」가 아니라
「관급 6,999건을 붙였으나 임도 자재가 거의 없고, **사급 단가가 미결**이라 구조물 계열이
안 섬」으로. 설치 주체 미지정 건수도 함께 냄.

자체검증 — 신규 6건 포함 `pytest tmp/tests/ -q` **129 passed** · ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:40:02 +09:00
eomsangdonandClaude Opus 5 3762a06b25 fix(B09): 넓은 필터가 정상 자원 70건을 지우고 있었음 — 조회 우선으로 바꿈
메인의 `막자갈`→배합 `자갈` 오탐 사례를 전해 듣고 내 필터를 재 봤더니 **같은 병이 있었음.**

- **실측** — `is_non_resource_label()` 이 머리글 낱말을 **부분일치**로 보고 있어
  `건설기계운전사`·`일반기계운전사`·`작업반장`·`인력운반공`·`비계공`·`계장공` 등
  **정상 자원 70 / 745** 를 「자원 아님」으로 지우고 있었음(「계」·「작업」·「인력」에 걸림).
  그 탓에 **매칭 14건이 조용히 없어졌음**.
- **고침 둘**
  ① 머리글 판정을 **정확 일치 + 머리글 낱말 조합**(「단위작업별」·「위치및면적」)으로 좁힘.
  ② **카탈로그 조회를 필터보다 먼저** 함 — 카탈로그에 있는 이름은 **정의상 자원**이라,
     필터가 넓어져도 정상 자원이 안 사라지는 구조가 됨.
- **결과** — 매칭 91 → **106**(노무 100 · 기종 6). 산출 파일 다시 냄.

**오탐 짝 시험을 함께 넣음** (「걸려야 한다」 + **「걸리면 안 된다」**)
- 머리글 필터 — 정상 자원 8종은 안 먹고 머리글 7종은 잡는지.
- ㉡ 무대 — 이름에 「운반」이 든 `도자운반`·`덤프운반` 줄은 **안 걸리는지**
  (판정을 이름이 아니라 `equipment` 정확 일치로 하는 근거).
- ㉣ 효율 — 손료계수 0.0002085·조종원 0.125 처럼 **0~1 이지만 효율이 아닌 값**은
  안 걸리는지(효율 자리로 들어올 때만 막는 근거).

**덤으로 잡은 것** — 상세가 하나도 안 붙는 일위대가가 **제목만 서서** 「상세 줄이 없어
단가를 못 조립」하는 상태가 있었음. **붙을 상세를 먼저 모으고 없으면 제목도 안 세움**
(일위대가 67 · 건너뜀 1). 전수 시험(`모든 일위대가 총액 > 0`)이 이걸 잡았음.

PLAN 9-6 에 ㉤(열 방향 검사, 이중계상 규칙이 아니라 표 정합 검사)과 이번 필터 교훈 기록.

자체검증 — `pytest tmp/tests/ -q` **123 passed** · ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:33:42 +09:00
eomsangdonandClaude Opus 5 f2d12afef7 feat(B09): ㉤ 열 방향 검사 추가 — 행 검사로 안 잡히는 이중 합산
배분 창이 보고 숫자를 더해 보고 **노무 열만 5,162 어긋남**을 짚음. 확인 결과:

- **값은 멀쩡했음. 내 보고가 줄 하나를 빠뜨린 것**(「제근」 본표는 보통인부 줄이 **둘**임 —
  굴착기 규격 2종에 각각 붙음). 실제 열 합은 재료 20,956.3 · 노무 54,943.2 ·
  경비 22,393.4 · 합계 98,292.9 로 표시와 **전건 일치**.
- **다만 지적한 「열 방향 검사가 비어 있다」는 실재했음.** `TC = NC + GC + JC` 는
  **행 방향** 검사라, 같은 성분을 두 층에서 세는 어긋남(행마다는 다 맞고 열 합만 갈림)을
  못 잡음. 예 — 기계 줄 안에 든 조종원 노무가 별도 노무 줄로도 서는 경우.

- `check_column_sums()` 추가하고 `detail_of()` 에서 **실제로 호출**. 표시 합계가 상세 줄의
  열별 합과 다르면 멈춤.
- 테스트 둘 — ① 노무 열만 부푼 모양을 만들어 **행 검사가 통과하는데 열 검사가 잡는지**
  확인 ② 실제 「제근」 본표가 열 검사를 통과하고 보통인부 줄이 둘인지 확인.

⇒ 이중계상 감시가 넷(㉠할증·㉡무대·㉢배합·㉣작업효율) + **방향 검사 ㉤** 로 늘어남.

자체검증 — 신규 2건 포함 `pytest tmp/tests/ -q` 118 passed · ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:26:35 +09:00
eomsangdonandClaude Opus 5 29cf61f4ad feat(B09): 일위대가 금액 0.1원 버림 — 자리 규칙 적용 + 끝자리 차이를 화면에 드러냄
- `OutputPlace.UNIT_PRICE_ROW` 추가 — **0.1원 미만 버림**(품셈 1-2-2 「일위대가 금액란
  0.1원 미만 버림」). 계산은 전정밀, **표 그리는 자리에서만** 자름(단수는 출력 위치에 붙음).
- **행 합계 = 자른 성분 셋의 합** — 그래야 표에서 `TC = NC+GC+JC` 가 섬. 전정밀 합을
  따로 자르면 성분과 합계가 어긋나 보임. 표 전체 합계도 **행별로 자른 값을 더함**
  (`단수처리_규칙.md` §2 「행별 처리(합계 후 아님)」).
- ⚠ **행별 절사로 생기는 끝자리 차이를 숨기지 않음** — 화면에 「행별로 0.1원 미만을 버려
  합계 끝자리가 다릅니다 (정상). 자르기 전 합계: …」를 띄움. 숨기면 나중에 「합계가 안
  맞는다」며 계산을 고치려 듦.

**화면 실측(5174)** — 일위대가 탭 → 목록 64건 → 「제근」 본표 →
`▸ 굴착기(무한궤도) 0.2 | 기계경비(105) | hr | 0.8 | 8,936.5 | 28,329.7 | 11,098.5 | 48,364.7`
→ 기계 줄 클릭 → **시간당 사용료 본표로 파고듦**(손료 13,873.1 · 경유 11,170.6 ·
건설기계운전사 35,412.1 = 60,455.9). 합계 98,292.9 / 자르기 전 98,293.2 표시.
산출 요약 2줄(자재 미확보로 구조물 계열 안 섬)도 탭 상단에 뜸.

⚠ 검증 함정 기록 — 해시 라우트에 쿼리를 붙일 때 `#/b09-estimation?v=2` 는 라우트가
안 잡힘. **`?v=2#/b09-estimation` 처럼 해시 앞에** 붙여야 함.

자체검증 — `pytest tmp/tests/ -q` 116 passed · ruff 통과 · tsc(B09) 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:23:09 +09:00
eomsangdonandClaude Opus 5 6c4d0251db feat(B09): 일위대가 탭 — 목록표+본표 2단, 원천 표시, 층 파고들기
**API 2종** (`B09_Estimation_Router.py`)
- `GET …/estimation/unit-prices` — **목록표** + **산출 요약**. 요약을 같이 보내는 까닭은
  사용자가 「무엇이 안 선 상태인가」를 화면에서 알아야 하기 때문임(자재 카탈로그
  미확보로 구조물 계열이 안 섬).
- `GET …/estimation/unit-prices/{code}` — **본표**. 줄마다 원천(자재5·노임6·기계경비105·
  일위대가103·단가산출104)과 **파고들기 가능 여부**가 붙음. 없는 코드는 404.
- 품셈 3 MB 를 요청마다 다시 안 읽게 `cached_build()` 로 한 번만 조립.

**화면** (`B09_Estimation_UI_Page.ts`)
- 일위대가 탭 활성화. **목록표(위) + 본표(아래) 2단** — 9-3 「제목+상세 한 쌍」이 화면에도
  그대로 섬.
- 본표 줄마다 `원천(번호)` 표시, **기계 줄을 누르면 그 시간당 사용료 본표로 파고듦**
  (거기서 취득가·연료·조종원까지 보임). 값을 못 믿을 때 사람이 하는 일이 이것임.
- **재료·노무·경비 3분할 + 합계 줄**, `TC = NC + GC + JC` 성립 여부를 화면 문구로 냄.
- **산출 요약을 화면에 표시** — 자재가 없어 구조물 계열이 못 선다는 것을 그 자리에 적음.

locale 은 **B09 키만** 추가(16줄), 공용 파일 다른 줄 무수정.

⚠ 화면 조작 검증은 다음 단계 — `tsc` 는 통과했고(남은 오류 1건은 메인 창 B08 파일),
백엔드 재시작·클릭 검증은 이어서 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:13:20 +09:00
eomsangdonandClaude Opus 5 856be1f45b feat(B09): ③단가산출·일위대가 조립 + 네 번째 이중계상 규칙(㉣) 가드
**㉣ 작업효율을 두 곳에 넣지 않는다 — 계획서에 없던 네 번째 규칙**
- 품셈은 작업효율 `E` 를 **작업량 산정**에 넣음(`Q = n·q·f·E`, 8-1-4). 시간당 사용료는
  **1일 8시간**으로 나눔(8-1-6 「관리비는 1일 8시간 초과해도 8시간으로 계산」).
  **양쪽에 넣으면 같은 효율이 두 번 곱해짐.**
- 실무 관측이 효율을 사용료 쪽에 미리 넣어 두어(굴착기 0.7㎥ 노무 55,700/hr =
  일당 ÷ 5.09h), 그 값을 보고 나눗수를 고치는 사고가 정확히 이 자리에서 남.
- `reject_efficiency_in_hourly_rate()` · `check_operator_hours_basis()` 추가하고
  **`hourly_machine_cost()` 안에서 실제로 호출** — 함수만 있고 안 부르면 없는 것과 같음.
- PLAN 9-6 의 금지 규칙을 셋 → **넷**으로 늘리고 근거·경위 기록.
  기계 사용료 11 % 차이는 **「설명된 차이」**임을 표로 못 박음(맞추려 손대지 말 것).

**`B09_Estimation_UnitPrice.py` 신설 — 층을 실제로 쌓음**
- `S 취득가 · L 노임 · M 연료 → X 시간당 사용료 → B 일위대가`.
  **시간당 사용료를 미리 계산해 넣지 않음** — 쌓아야 화면이 「무엇으로 이루어졌나」를
  보일 수 있음(8-13 계산 과정을 감추지 않음).
- 조종원 수량 = `인/일 ÷ 8` 로 상세에 들어가 ㉣이 데이터로도 드러남.
- 자원이 하나도 안 붙은 공종은 **빈 줄로 안 세움** — 0 원 일위대가가 내역에 서면 안 됨.
- ㉠ 가드를 `verify_surcharge_once()` 로 실제 호출 — 일위대가 재료비는 **할증 전** 값.

산출 — 제목 **189**(일위대가 64 · 기계 층 3 · 노임·연료), 건너뛴 공종 0.
실측 `X-0201-0070` 굴착기 0.7㎥ = 재 26,130 + 노 35,412 + 경 24,554.

자체검증 — 신규 5건 포함 `pytest tmp/tests/ -q` **116 passed** · ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:58:11 +09:00