Commit Graph
1226 Commits
Author SHA1 Message Date
eomsangdon e52f18769c auto: 2026-09-07 23:47 (EOMSANGDON-HOME) 2026-09-07 23:47:47 +09:00
eomsangdonandClaude Opus 5 6a487fc6e3 feat(B08): 자재총괄 — 할증이 붙는 유일한 자리
구조물 원단위의 `destination == "material"` 성분만 모아 자재별 합산 후
할증률을 한 번만 적용. 열은 순수량·할증률·합계 + 관급구분·설치주체·비고이며
금액은 없음(B09 경계).

- 할증률은 코드가 아니라 데이터 — `resources/data_material_surcharge/`
  (품셈 1-3-1 재료 할증률 19종 + sha256 매니페스트). 실무 관측값은
  `observed_practice` 로 분리(법대로 원칙).
- 표에 없는 자재는 0 % 로 넘기지 않고 「할증률 미확보」로 표시.
  이름 조회는 정확 일치 — 부분일치면 `막자갈` 이 `자갈` 할증을 뭄.
- 이중계상 방어 ㉠ — 앞 단계 `surcharge_applied` 깃발을 실제로 읽어 경고.
  자재총괄 응답은 `True`, 원단위표는 `False` 로 어느 쪽 값인지 명시.
- 관급/사급 이름은 B09 와 동일(`owner_supplied`/`contractor_supplied`).
  관급 줄에만 설치 주체(`install_by`)를 붙이고, 미지정은 기본값으로
  때우지 않고 드러냄 — 안전관리비 대상액이 「도급자설치 관급금액」이라서임.
- 라우터 `GET /quantity/material-summary` 신설, 화면에 「구조물 원단위」·
  「자재총괄」 탭 추가. `design_owner` 가 붙은 타입(측구)은 중복 계상 방지로 제외.

검증 — 전용 테스트 23건 통과, 전체 회귀 473 passed(기존 B05 깨짐 1건 제외).
공용 브라우저 실조작으로 탭 5장·머리글·값 4줄·미확보 안내 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:43:46 +09:00
eomsangdonandClaude Opus 5 fc40265dbe feat(B08): 구조물 원단위 전개식 — 치수에서 성분 물량
일감 6 엔진. PLAN 8-6·8-8·8-15.

식을 발명하지 않음 — 실무 원본을 옮김
  울진 설계원본 5. 구조도(기번3).xlsx 에 구조물 31종 계산식이 살아 있는 수식으로
  남아 있음(8-15). 그 식을 옮기되 식 안에 상수로 박혀 있던 값(돌 뒷길이 0.45 ·
  고임돌 0.15 · 돌중량 0.88 등)은 **계수표로 뺌** — 뒷길이가 바뀌어도 식을 안 고침.
  실무 방식의 약점을 여기서 고친 자리.

치수 정본은 하나 — structures.json 의 type_id·options 를 읽어 계산.
  자기 치수표를 따로 들지 않음(도면은 H=1.5 인데 수량은 옛 치수로 도는 사고 방지).

⚠⚠ 이중계상 셋을 코드로 막음
  ㉢ 배합을 분해하지 않음 — 콘크리트 ㎥·모르터 ㎥ 에서 멈춤. 시멘트·모래로 쪼개는
     것은 B09 일위대가 몫이고 양쪽이 쪼개면 시멘트가 두 배가 됨.
     verify_no_mix_components() 가 산출물에 배합 성분이 나타나면 알림.
     ⚠ 정확히 같은 이름으로만 봄 — 부분문자열로 재니 「막자갈」(뒤채움 재료)이 배합
     「자갈」로 오탐됐음. 개발 중 실제로 걸린 자리라 시험에도 박음.
  ㉠ 할증을 안 붙임 — surcharge_applied=False 로 응답에 못 박음. 할증은 자재총괄 한 곳뿐.
  · 성분마다 destination 을 담 — earthwork(토공 대분류로 합산) / material(자재총괄) /
    unit_price(일위대가 재료비). 울진 토적집계 D12~D14 가 구조물 터파기 1,248/30㎥ ·
    되메우기 739㎥ 를 개별 줄이 아니라 토공으로 합산한 것이 근거.

⚠ 공제 규칙을 주석에 원문째 — 품셈 1-2-1 「물구멍·이음줄눈·모따기·철근은 공제하지
  않음」. 치수를 곧이곧대로 빼면 실무값과 어긋남. 빼는 것은 관 통과 단면처럼 실제로
  비어 있는 자리뿐.

원본에 없는 칸은 지어내지 않음 — 뒷길이 60㎝ 돌중량이 원본 표에 비어 있어 야면석을
  내지 않고 그 사실을 notes 로 알림(8-8 ㉮).

⚠ 실무값과 0.012 차이 — 우리 쪽이 맞음
  터파기 1.5375 vs 실무 1.55. 평균두께가 0.825 인데 실무 시트는 표기값 0.83 으로
  다시 계산해 1.545 가 됨. 품셈 1-2-2 는 표기 규칙이고 계산은 전정밀(8-16).
  맞추려고 식을 비틀지 않고 허용오차를 그 차이만큼 둠.

검증 — 17건 통과. 배합 금지·할증 금지·행선지 표시·계수표 교체·빈 칸 미생성을 각각 못 박음.
  실데이터(route 150 의 돌쌓기(찰) H=2.5·L=10)로 확인 — 성분 10개, 배합 위반 0.
  전체 회귀 450 passed (실패 1건은 B05 코리도 기존 깨짐).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:25:34 +09:00
eomsangdonandClaude Opus 5 564cb11103 feat(B08): 수량산출 화면 — 탭 3장·산출 조건 입력·[저장]
일감 4·5 화면 마무리. 앞 `auto:` 커밋(4756f0fe)은 토적표 그리드·로케일 배선분임.

우측 — 실무 산출서 시트를 탭으로
  토적표 · 토공집계 · 운반거리. 탭을 눌러 갈아 끼움.
  토공집계 열은 거창 실무 시트 그대로(구분·공종·규격·단위·계·비고).
  운반계획이 아직 없으면 빈 표 대신 「종단설계에서 확정하면 생김」을 보임.

좌측 — 산출 조건 입력
  ⚠ 암 갈래 칸 수를 코드에 안 박음 — 프로젝트 세트가 정함(지금 거창5 = 5칸).
  반영률 4칸, 기본 100 %. 실무 관측 80/50/80 은 기본값 아님(PLAN 8-11 · 법대로).
  반영률 이름을 사람 말로 보임 — 서버 키(fill_slope_compaction)를 그대로 띄우면
  설계자가 못 읽음. 로케일 키 4개 추가.

[저장] 신설 (CLAUDE.md 5장 데이터 3층)
  조작은 캐시에만 쌓이고 [저장]에서만 정본(project_settings.json)으로 감.
  자동저장 안 만듦. quantity 구획만 감 — estimation 은 B09 것이고 서버가 막고 있음.
  저장 뒤 표를 다시 받아 그림 — 조건이 바뀌면 집계·운반 값이 달라짐.
  저장 안 한 변경이 있으면 나갈 때 알림(beforeunload).
  ⚠ [초기화]는 안 달았음 — 5장의 [초기화]는 초기값을 작업본에 덮어쓰는 것인데
  설정에는 대응 초기값이 없어 재계산 단추로 오해될 자리임. TODO(미결) 주석으로 남김.

검증 — 공용 브라우저 실화면, 타입검사 0.
  탭 3장 · 입력칸 9개(암 5 + 반영률 4) · 단추 [저장][확정].
  토공집계 10행, 값 일치 — 흙깎기 토사 2,526.99 · 측구 90.51 · 보정량계 6,511.06.
  [저장] 실제로 눌러 확인 — 연암 60·보통암 40 을 넣으니 암 3,512.09 가
  2,107.25 / 1,404.83 으로 갈리고(60:40 안분), 성토면다짐 80 % 를 넣으니
  13,518.6 → 10,814.9 로 바뀌며 비고에 「성토면 80 % 반영」이 남음.
  ⚠ 넣었던 값은 전부 원래대로(0·0·100) 되돌려 놓았고 화면도 사용자가 보던 주소로 복귀.
  ⚠ 개발 중 발견 — vite 가 옛 모듈을 물고 있어 첫 확인이 옛 화면이었음.
  쿼리를 붙여 새로 물린 뒤 재확인(계획서 7-2 의 그 함정).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:18:10 +09:00
eomsangdon c0cd398eea Merge remote-tracking branch 'origin/main_laptop_1' into main_desktop_1 2026-09-07 23:12:53 +09:00
eomsangdon 4756f0fe72 auto: 2026-09-07 23:12 (EOMSANGDON-HOME) 2026-09-07 23:12:41 +09:00
eomsangdonandClaude Opus 5 1789b26563 feat(B08): 토공집계표·운반거리 그리드 모듈 신설 (아직 미등록)
일감 4·5 화면의 표 부품. 이 커밋 시점에는 **아무 데서도 import 하지 않음** —
「신규 파일 먼저, 등록 줄 나중」 두 걸음 규칙(공용 파일 동시 편집 사고 예방).

토공집계표 — 열은 거창 실무 시트 그대로(구분·공종·규격·단위·계·비고).
  같은 구분이 이어지면 한 번만 적음(실무 시트가 병합해 두는 자리).
  비고에는 설계자가 정한 값만 남음 — 반영률을 바꿨을 때, 비율 합이 100 이 아닐 때.
  기본값 그대로면 비움. 안내가 매번 뜨면 잡음이 됨.

운반거리 — 내역 줄(가중평균)과 근거 구간 수를 함께 보임.
  ⚠ 무대 줄에 「내역 제외」 표시 + 「품셈 1-2-7 소운반 20m 이내는 품에 포함」을 적음.
  「제외」만 있으면 빠뜨린 것으로 오해됨. 규칙이 코드에만 있으면 잊히므로 화면에 남김.
  운반계획이 아직 없으면(=[확정] 전) 빈 표 대신 「종단설계에서 확정하면 생김」을 보임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 23:12:32 +09:00
eomsangdon 0262b0f3be Merge remote-tracking branch 'origin/sub_desktop_1' into main_laptop_1 2026-09-07 21:59:08 +09:00
eomsangdonandClaude Opus 5 28e4aed499 feat(B08): 토공집계표·운반표를 API 에 붙이고 산출 조건 저장 자리 신설
일감 4·5 의 API 덩어리.

한 응답에 실음
  earthwork-table 이 토적표(체적) · slope(사면 4계열) · haul(운반 가중평균) ·
  summary(토공집계표) · settings 를 함께 냄. 실무 산출서가 한 벌로 움직이는 값이라
  나눠 부르면 같은 측점 목록을 여러 벌 들게 됨.

운반계획이 없으면 빈 표가 정직함
  운반계획은 [저장]·[확정]에서 정본에 남는 값임(longitudinal.data.mass_haul).
  아직 안 돌린 프로젝트는 없음 — haul_available 로 알려 화면이 「확정하면 생김」을
  말할 수 있게 함. 지어내지 않음.

산출 조건 저장 — PUT /quantity/settings
  ⚠ 자동저장이 아님(CLAUDE.md 5장). 조작은 캐시에 쌓이고 여기서만 작업본으로 넘어감.
  ⚠ quantity 구획만 씀 — estimation 은 B09 것이고 모듈이 구조로 막고 있음.
  보내지 않은 칸은 저장분을 그대로 둠.
  프로젝트 경로를 못 찾아도 조회는 기본값으로 서게 함 — 설정은 계산을 거드는 값이지
  없으면 못 도는 값이 아님.

암 비율 안분을 비고에 드러냄 (조율 창 지적)
  설계자가 60/30 을 넣으면 총량 보존을 위해 66.7/33.3 으로 안분됨. 값이 말없이
  바뀌는 것이라 「입력 합 90 % → 100 % 로 안분」을 비고에 남김. 합이 100 이면
  비고를 비움 — 제대로 넣었는데 안내가 뜨면 잡음이 됨.

검증 — 회귀 433 passed (실패 1건은 B05 코리도 기존 깨짐).
  엔드포인트 3종 등록 확인(earthwork-table 2 + settings 1).
  안분 비고는 시험으로 못 박음(합 90 이면 비고 있음 · 100 이면 없음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:58:34 +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
eomsangdonandClaude Opus 5 9badcbf80e feat(B08): 토공집계표·운반 가중평균 엔진 + 프로젝트 설정 자리
일감 4·5 의 엔진 덩어리. PLAN 8-11·8-3·8-7.

프로젝트 설정 (common_util/common_util_project_settings.py)
  자리 = <project_root>/project_settings.json, 루트의 project_manifest.json 옆.
  매니페스트 stages 는 단계 산출물 목록이고 설정은 두 페이지가 함께 읽는
  프로젝트 값이라 단계 폴더에 넣으면 주인이 애매해짐.
  구획 quantity(B08) · estimation(B09) — 남의 구획은 읽기만.
  ⚠ 경계를 코드로 막음 — save_section() 이 이름 붙은 한 구획만 갈아 끼우고
  통째로 쓰는 함수를 두지 않음. 두 페이지가 같은 파일을 쓰므로 통째로 덮으면
  상대 값이 사라짐(오늘 main.py 에서 같은 모양의 사고를 이미 겪음).
  ⚠ *_override 기본은 None — 「안 정했으면 config 정본을 씀」. 기본값을 복사해
  넣으면 정본이 바뀌어도 옛 프로젝트가 안 따라옴.
  ⚠ dataset_versions 는 기록이지 정본이 아님 — 되살릴 때 쓰는 정본은 프로젝트
  스냅샷이고 어긋나면 스냅샷이 이김.
  estimation.rate_dataset 은 「연도」가 아니라 판을 가리킴 — 제비율은 연중에도
  개정됨(현행판 2026-04-13). B09 확정 반영.

토공집계표 (열 = 구분·공종·규격·단위·계·비고, 거창 실무 시트 그대로)
  ⚠ 암 갈래 개수를 코드에 안 박음 — 울진 2 · 거창 5 · BOM 1 로 공사마다 다름.
  프로젝트 설정의 세트를 받아 그만큼 줄을 냄. 비율이 아직 없으면 지어내지 않고
  「암」 한 줄로 냄. 비율 합이 100 이 아니어도 준 비율끼리 안분해 총량 보존.
  ⚠ 반영률 기본 100 % — 실무 관측 80/50/80 은 참고이지 기본값 아님(법대로).
  바꾼 경우에만 비고에 「80 % 반영」이 남음 — 누가 정한 값인지 보이게.

운반 가중평균 ((운반수단 x 지반유형)별 1줄)
  실무 울진이 도자 토사/암 · 덤프 토사/암 4줄을 올림. 가중평균 = Σ(토량x거리)/Σ토량
  으로 단순평균이 아님. 개별 구간은 근거로 함께 냄 — 어느 구간이 그 평균을
  만들었는지 되짚게.
  입력은 이미 있는 HaulPlan — 띠·장거리이동에 equipment·haul_distance_m·
  지반유형별 물량(ea/rr/br)이 다 있어 다시 세지 않음.
  ⚠ 무대(free_haul)는 in_bill=False — 품셈 1-2-7 로 품에 포함이고 인력운반 10-6
  도 「소운반 20m 초과분」이라 붙일 단가가 없음. 값은 내되 내역 줄만 뺌 —
  「무대+도자+덤프 = 총 운반토량」 검산에 씀.

검증 — 28건 통과 (토공집계·설정 19 + 운반 9).
  가중평균이 단순평균과 다름을 못 박음(도자 토사 600@40+400@50 → 44m, 45 아님).
  울진2·거창5 두 세트가 같은 코드로 서는 것, 무대가 내역 줄이 아닌 것,
  구획을 따로 저장해도 상대 값이 안 지워지는 것을 각각 시험함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:54:23 +09:00
eomsangdonandClaude Opus 5 c7554d8333 fix(B09): 조종원 노임 나눗수 8시간을 품셈 근거로 못 박음
배분 창이 「관측 55,700 ÷ 일당 283,297 = 5.09시간」을 짚어 확인함. 품셈을 뒤진 결과:

- **8시간이 맞음** — 품셈 8-1-6 기계손료 단서 「관리비는 1일 8시간 초과해도 8시간으로
  계산」이 1일을 8시간으로 잡고, 노임표도 `hours_per_day: 8` 임.
- **관측이 짧은 나눗수를 쓴 것으로 보임** — 작업효율 `E`(실작업시간율)를 시간당
  사용료에 미리 반영한 것. 품셈에서 작업효율은 **작업량 산정**(`Q = n·q·f·E`, 8-1-4)에
  들어가지 시간당 사용료에 안 들어감. **관측에 맞추려 나눗수를 바꾸지 않음**(★법대로).
- ⇒ **조종원 직종 의문은 해소됨** — 직종(건설기계운전사)은 맞고 나눗수만 달랐음.
  잠정 표시는 「직종명이 품셈 8-4 표에 없음」 사유로만 남김.
- 근거·경위를 상수 주석에 적고 테스트로 박음(`OPERATOR_HOURS_PER_DAY == 8`,
  관측값보다 작다는 것까지 확인).

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:53:14 +09:00
eomsangdonandClaude Opus 5 4e6e588b9b feat(B09): 운전경비(연료·잡재료·조종원)를 품셈 8-4 에서 뽑아 시간당 사용료 완성
**빈 두 성분을 채움** — `mach_fuel_rate`·`mach_operator_map` 0건이라 시간당 중기사용료의
재료비·노무비가 비어 있던 자리(손료만 있으면 실제의 4분의 1). 건설품셈 **8-4 운전경비
산정** 표에서 뽑아 **92 기종** 확보.

⚠ **표가 열 단위로 뭉쳐 옴** — PDF 추출 탓에 `분류번호` 한 칸에 코드 31개,
`주연료` 한 칸에 값 31개가 공백으로 이어 붙어 있음. **위치로 짝짓되 개수가 안 맞으면
그 줄을 통째로 버림**(10건 버림, 목록으로 남김). 어긋난 채 짝지으면 **다른 기종의
연료값이 조용히 붙는** 자리라 억지로 안 맞춤.
- 코드는 앞자리를 이어받음 — `0201-0012 0020 0040` → `0201-0020`·`0201-0040`.
- ⚠ **이름 칸은 못 씀** — 표 전체 기종명이 한 덩어리로 옴. **코드로 613 기종
  카탈로그에서 이름·규격을 가져옴**(카탈로그에 없는 코드는 버리고 목록에).

**검증(굴착기 무한궤도 0.7㎥)** — 주연료 11.6 ℓ/hr · 잡재료 22 % · 조종원 1인/일.
시간당 = 재료 26,130(연료 21,418 + 잡재료 4,712) + 노무 35,412 + 경비 24,554 = **86,096**.
STC 2024 관측 96,829 과 **11 % 차** — 손료·재료는 근사하고 **노무가 갈림**
(관측 55,700/hr = 445,600/일로 어느 직종보다 높음). **맞추려 손대지 않음** — 관측값은
대조용이고 우리는 법대로 감. ⚠ 조종원 직종 확인 항목으로 올림.

- **잠정 표시** — 조종원 **직종명이 품셈 8-4 에 없어** `aliases` 기반 규칙(트럭 계열 =
  화물차운전사, 그 밖 = 건설기계운전사)으로 매김. 결과에 `operator_mapping_is_provisional`
  로 드러남. TODO(미결 9-6).
- **유가는 전국평균 잠정**, 지역 파라미터 자리(`region`)만 뚫어 둠 (품셈 8-1-7 5호).
- **파생 파일로 냄** — `resources/data_cost_machine_operating/`, 기준자료 안 건드림.
  `derived_from` 에 `mach_base` 판의 세 쪽을 적어 낡으면 드러나게 함.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:49:50 +09:00
eomsangdon 33331e4364 Merge remote-tracking branch 'origin/sub_desktop_1' into main_desktop_1 2026-09-07 20:45:34 +09:00
eomsangdon 4226bf5bd6 Merge remote-tracking branch 'origin/main_laptop_1' into main_desktop_1 2026-09-07 20:45:32 +09:00
eomsangdonandClaude Opus 5 0cc3c1bd5e fix(B08): 잘림 안내를 「주의 + 접히는 목록」으로 — 늘 뜨는 경고라
B06 담당(랩탑) 실측 회신 반영. 미교차는 드문 예외가 아니라 상시임 —
route 169 는 22/105(21 %), 이 노선은 17/65(26 %). 매번 요란하면 곧 무시당함.

고친 것 셋
  · 붉은 오류 → **주의 표시**(테두리를 danger 에서 muted 로). 잘린 줄 표시도 같게.
  · 목록을 `details` 로 **접어 둠**. 필요할 때만 폄.
  · 문구를 **한 덩어리**로 묶음 — 절·성토 면적 · 사면길이 · 사면적이 전부 같은 사유로
    잘리므로 항목마다 따로 띄우지 않음.

안 넓히는 까닭 (주석에 남김)
  미교차 절반 이상이 계곡·절벽처럼 지형이 설계 사면에서 멀어지는 자리라 반폭을 늘려도
  영원히 안 닫힘. 닫히는 쪽도 중앙값 +3m 인데 꼬리가 +292m 이라 전역 확대는 값이 안 남.
  2026-09-03 사용자 확정 「경고로 대체」가 그대로 유효함.

정본 키 대조 — StationSlope.unclosed 가 design.slope_unclosed 에서 나오는 것 확인
  (B06_Section_Engine_Design.py:807 이 내는 그 값).

검증 — 공용 브라우저 실화면. 타입검사 오류 0.
  접힌 상태 `details[open=false]` · 요약 문구 한 줄 · 측점 단추 17개.
  펴면 목록이 보이고, 첫 단추(NO.13)를 누르면 그 줄로 가서 강조됨.
  조작한 화면은 사용자가 보던 주소로 되돌려 놓음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:45:20 +09:00
eomsangdonandClaude Opus 5 fbd7380b83 feat(B08): 토적표에 사면 4계열 열·잘림 경고 붙임
일감 3 의 API·화면 덩어리. 토적표 오른쪽 절반(실무 V~AI)이 화면에 섬.

한 응답으로 냄
  실무 토적표가 한 장이라 화면도 한 장임. 나눠 부르면 두 번 왕복하고 같은 측점
  목록을 두 벌로 들게 됨. earthwork-table 응답에 slope 를 함께 실음.

열 구성 — 계열 4 x 성토면/절토면 = (거리, 면적) 7쌍
  층따기[성토면] · 면고르기 · 법면보호공(종자파종) · 지장목제거.
  거리 = 그 측점 사면길이, 면적은 토적표와 같은 평균단면적법.
  합계행은 면적만 — 거리(사면길이)는 합이 뜻이 없음(실무 시트도 비움).

⚠ 잘린 측점을 감추지 않음 (PLAN 8-4b)
  사면이 원지반을 못 만난 측점은 사면길이·면적이 그 지점에서 잘려 있음.
  경고 문구에 **무엇이 잘렸는지**를 적고(「실제 값은 이보다 큼」), 측점 단추를
  누르면 그 줄로 가서 잠깐 강조됨 — 17곳을 눈으로 찾게 하지 않음.
  잘린 줄은 측점 칸 왼쪽에 표시가 남음.

검증 — 공용 브라우저 실화면. 타입검사 오류 0.
  머리글 3단 13/12/28셀, 대분류에 층따기·면고르기·법면보호공·지장목제거,
  3단에 거리/면적 쌍. 본문 65행 x 34열(토공 20 + 사면 14).
  NO.1 사면값 6.4/64.4 · 3.5/93.0 등이 엔진값과 일치.
  잘린 줄 17개 표시 · 경고 문구 · 측점 단추 17개 확인.
  합계 면고르기 성토 13,518.6㎡ · 절토 5,433.7㎡ 로 엔진 합계와 같음.
  회귀 404 passed (실패 1건은 B05 코리도 기존 깨짐).
  조작한 화면은 사용자가 보던 주소로 되돌려 놓음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:43:20 +09:00
eomsangdonandClaude Opus 5 34d90a14d1 feat(B09): 기계경비(S→X) + 기종 카탈로그 매칭 (PLAN 9-3)
**`B09_Estimation_MachineCost.py` 신설 — 취득가 → 시간당 사용료 두 단계**
- `mach_base_2026.json` 실사: `mach_price` **613 기종**(`machine_code`+`specification`),
  `mach_loss_coef` 387건(시간당 손료계수·내용시간·연간표준시간).
- **시간당 손료 = 취득가 × 손료계수.** 취득가가 **천원 단위**라 환산을 놓치면 1,000배
  틀리는 자리 — 테스트로 박음. 굴착기(무한궤도) 0.7㎥ → **24,554원/hr**
  (STC 2024 관측 23,128 과 같은 자릿수, 취득가 판 차이로 설명됨).
- ⚠ **빠진 성분을 0 으로 안 때움** — `mach_fuel_rate`·`mach_operator_map` 이 **0건**이라
  연료(재료비)·운전사(노무비)를 못 채움. `HourlyMachineCost.gaps` 로 **공백을 알림**.
  실측 비중이 노무 53·재료 20·경비 27 % 라 손료만 쓰면 **4분의 1**이 됨 — 조용히
  총액에 섞이면 안 되는 자리.
- 손료계수 없는 기종 **230건**도 0 으로 안 때우고 멈춤.

**자원 축에 기종 매칭 추가**
- 기종 셀은 괄호 안에 **형식과 규격이 섞여** 있음 — 「굴착기(무한궤도, 0.7㎥)」는
  이름 `굴착기(무한궤도)` + 규격 `0.7`. 형식은 이름의 일부이고 숫자 조각만 규격임.
- **규격이 옆 칸에 있는 표**가 많아(`['굴착기 (무한궤도)','굴착기(무한궤도,0.2㎥)','hr',…])
  뒷 칸에서 규격 후보를 찾아 고름. 규격 없이 매칭 성공으로 치지 않는 규칙은 그대로.
- 산출 갱신 — 매칭 86 → **91행**(노무 86 + 기종 5), 미매칭 274 → **269건**.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:43:19 +09:00
eomsangdonandClaude Opus 5 6e7570eba6 feat(B09): 자원 축 매칭 — 공종 축에 자원을 붙여 별도 파일로 냄 (PLAN 8-6·9-3)
메인 창의 공종 축(`resources/data_work_item_master/`)은 **읽기만** 하고, 결과는
**내 소관 경로** `resources/data_cost_resource_axis/` 에 냄 — 메인이 품셈을 다시
돌리면 그 폴더가 덮이므로 안에 섞으면 사라짐.

- ⚠ **`pum_form` 을 먼저 봄** — `productivity` = 1 ÷ 값 · `requirement` = 값 ÷ 기준수량.
  **뒤집으면 20배 틀림.** 형태를 모르는 표(`undetermined`)는 **값을 안 씀**, 한쪽으로
  단정하지 않고 멈춤. 테스트가 뒤집힘을 자릿수로 잡음.
- `coefficient`(19)·`reference`(94)는 공종이 아니므로 **일위대가 항목으로 안 세움**.
- **규격이 없으면 매칭 성공으로 안 침** — 「굴착기」와 「굴착기 0.7㎥」는 단가가 다름.
  이름이 여럿이면 규격 없이는 못 고르고 `unmatched` 로 감.
- **못 맞춘 것은 빈칸이 아니라 목록** — 다만 표 머리글·소계·기호(`f`·`E`)·규격 구간
  (`10∼12`·`50이상`)·절번호는 자원이 아니므로 먼저 걷어냄. 안 걸렀을 때 1,550건이던
  목록이 **274건의 실제 공백**으로 줄어 쓸 수 있는 목록이 됨.

산출 — 매칭 **86행**(노무, 7직종: 보통인부 59·특별인부 19·조경공 4 등) ·
못 맞춘 **274건**(상위: 치즐소모량·자재·굴착기(무한궤도) 등).
⚠ **노임 카탈로그만 있어 노무만 맞음** — 기계·자재 카탈로그가 아직 없어 그 계열은
전부 못 맞춘 목록으로 감. 사유 문구에 그 사실을 적어 「이름이 틀림」과 구분함.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:36:59 +09:00
eomsangdonandClaude Opus 5 6e4cfc7dd2 feat(B08): 사면길이 유도·사면 4계열 면적 엔진
PLAN 8-4b 의 「사면적 없음」 구멍을 메움. 일감 3 의 엔진 덩어리.

⚠ B06 무접촉 — 저장분만으로 유도
  설계 엔진이 cut_slope_segments 를 내기는 하나 **정본에 저장되지 않음**
  (실측: route 150 측점 20.0 의 저장 design 키 33개에 그 키 없음. 저장되는 것은
  화면이 보낸 설계 지정이고 조회는 저장분을 그대로 실음). 그 값을 원천으로 쓰면
  사면적이 조용히 0 이 됨.
  대신 design_line + 저장된 경사비로 유도함 — 노체 끝 바깥으로 나아가며 기울기가
  설계 경사비와 맞는 연속 구간이 사면이고, 원지반은 경사비가 안 맞아 저절로 끊김.
  성토도 같은 원리로 잡힘(원지반선이 없어도 됨). 2단 사면(암/토사)은 경사비가
  달라 그대로 갈림.

⚠ 측구를 사면으로 세지 않음 — 개발 중 실제로 났던 결함
  측구 벽 경사가 n=1.0 으로 토사 절토비와 같아 그대로 걸렸음. 사면 시작점을
  노체 끝이 아니라 **측구 바깥 끝**(road_edges ± ditch.top_width_m)으로 옮겨 고침.
  그 형상을 실측 그대로 시험에 세워 재발을 막음.

사면 4계열 x 성토면/절토면 = (거리, 면적) 7쌍
  층따기[성토면만] · 면고르기 · 법면보호공 · 지장목제거.
  거리 = 그 측점 사면길이, 면적 = 토적표와 **같은 평균단면적법**(계산을 두 벌로 안 짬).
  법면보호공은 면고르기를 참조하되 끊을 수 있게 둠 — 실무 시트가 값이 같았던 것은
  엑셀 복사였고 오솔길 산출에는 보호공 4열이 0 이었음.

반영률은 법정값 아님 — 기본 100 %, 설계자 입력(PLAN 8-11 · 8-10 법대로).
  TODO(미결) — 실무 관측 80/50/80 중 지장목제거는 밑수가 안 맞아(14,061 != 10,782)
  쫓지 않고 100 % 로 둠.

잘린 측점을 감추지 않음 — slope_unclosed 를 물고 와 unclosed_stations 목록으로 냄.
  사면이 원지반을 못 만나면 사면길이도 잘려 있으므로 화면이 드러내야 함.

검증 — tmp/tests/test_b08_slope_area.py 15건 통과.
  실측 설계선을 그대로 세워 측구 제외·2단 암토사 분리·성토 유도·원지반 끊김을 못 박음.
  실데이터(route 150, 65측점) — 면적이 있는데 사면길이가 0 인 경우 0건,
  잘린 측점 17곳 검출.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:31:35 +09:00
eomsangdon 7d919c423d Merge remote-tracking branch 'origin/sub_desktop_1' into main_laptop_1 2026-09-07 20:30:59 +09:00
eomsangdon 123599db1a Merge remote-tracking branch 'origin/main_desktop_1' into main_laptop_1 2026-09-07 20:30:59 +09:00
eomsangdon 4d56f00acf Merge remote-tracking branch 'origin/main_laptop_1' into sub_desktop_1 2026-09-07 20:30:38 +09:00
eomsangdon af47523fc9 Merge remote-tracking branch 'origin/main_desktop_1' into sub_desktop_1 2026-09-07 20:30:37 +09:00
eomsangdon 690d6b418c auto: 2026-09-07 20:29 (ESD_LAPTOP) 2026-09-07 20:29:26 +09:00
eomsangdonandClaude Opus 5 33aa07f782 docs(B06): cut_slope_segments 는 지금 읽는 곳이 없음을 코드에 명시
데스크탑 창이 「법정 경사 검사가 빈 값을 볼 수 있다」고 알려 와 확인함. **검사 자체가 없어
문제 없음** — 별표2 검사는 오늘 폐기됐고(`cc428d7e`, 암질을 횡단도에서 안 고르기로 사용자
확정), 지금 이 값을 읽는 코드는 **한 곳도 없음**(계산해 내보내기만 함).

같이 확인한 사실 — 저장분에도 안 들어감. 실측(공용 DB) `cross_sections.data.design` **33키**에
`cut_slope_segments` 없음(같은 자리에 `cut_area_m2` 는 있음). 저장되는 것은 화면이 보낸
**설계 지정값**이라 엔진 출력 전체가 아님.

그런데 주석 셋이 아직 「법정 경사 검사가 읽는다」로 남아 있어 **다음 사람이 저장분에서 읽으면
된다고 오해**할 자리였음. 그 셋을 고쳐 ① 지금 읽는 곳 없음 ② 저장분에도 없음 ③ 남겨 두는
까닭은 소단 기하가 이 셈 위에 서 있어서 ④ **되살릴 때는 저장분에서 읽지 말고 계산해서 쓸 것**
을 적음. 코드는 한 줄도 안 바뀜(주석만).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:29:25 +09:00
eomsangdonandClaude Opus 5 76b302be3a feat(B09): 단가 계층·단수 자리·프로젝트 스냅샷 (PLAN 9-2·9-3·9-4)
**단수 처리를 「출력 위치」에 바인딩** (`B09_Estimation_Rounding.py`)
- `단수처리_규칙.md` §1 — 같은 수량×단가라도 **내역서 본체는 절사, 집계표는 반올림**.
  함수가 항목이 아니라 **표 종류**에 붙음. 자리를 안 대고 부르는 길을 안 둠(기본값 없음).
- ⚠ **집계표와 본체의 합이 어긋나는 것이 정상** — 「합계가 1원 틀린다」에 계산을 고치지
  않도록 `summary_vs_body_gap()` 으로 차이를 값으로 드러내고 화면 문구를 상수로 둠.
- 계산은 전정밀, 자르는 것은 표 그리는 자리에서. 값은 원문에서 복사 안 하고 문서를 가리킴.

**단가 계층 — 표를 세 벌 만들지 않음** (`B09_Estimation_PriceBook.py`)
- 「제목 + 상세」 한 쌍 + 종류 구분. 층은 `S 중기취득가 → X 시간당사용료 → B 일위대가 →
  D 단가산출`, 바닥은 `M 자재`·`L 노임`, `W 일식·견적`은 **단가 0**(무대처리, 8-7 ㉡).
- 금액은 어느 층이든 **재료·노무·경비 3분할**, 합계 = 셋의 합.
- **단가 슬롯 6개** — 번호 고정, **이름은 프로젝트 설정**. 기본 채택 6번(`JUKNM=6`).
  슬롯별 **근거 쪽수**(STC `PG_` 열) 자리도 둠.
- 안전장치: 채택 슬롯이 비면 **0 으로 안 때우고 멈춤** · 없는 코드는 `unmatched_codes()`
  로 **목록으로 냄** · 참조 순환 감지.

**프로젝트 스냅샷** (`B09_Estimation_Storage.py`)
- 채택 단가를 `<project_root>/B09_Estimation/v1/` 에 사본으로. 기준자료가 갱신돼도
  **옛 프로젝트 결과가 안 바뀜**. `dataset_version` 은 `dataset_id`+`effective_date`+
  `sha256` **세 쪽**. 사본이 바뀌면 지문 불일치로 멈춤. 차수(당초·1~3차) 자리 비워 둠.

자체검증 — 신규 13건 포함 `pytest tmp/tests/ -q` **85 passed** · ruff 통과 ·
파일 최대 534줄. 중기 실측값(`X00005` 96,829 = 노 55,700 + 재 18,001 + 경 23,128)으로
3분할 유지·층 쌓임 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:28:57 +09:00
eomsangdonandClaude Opus 5 a48770d11d fix(B09): 관급 입력은 「순자재대」 — 조달수수료 차감 옵션 제거
`단수처리_규칙.md` §3 원문을 읽다 **입력 의미를 잘못 잡은 것**을 찾음.
실무 서류의 「관급자재대 69,850,000」은 이미
`ROUNDUP(순자재대 69,474,220 + 조달수수료 375,160, −3)` 한 값인데,
그 합계를 순자재대 자리에 넣고 있었음. 그래서 안전관리비 관급항이 부풀었고,
그 어긋남을 「조달수수료 차감 옵션」으로 덮고 있었음.

- **입력을 순자재대·수수료로 나눠 넣는 것으로 정정.** 그러면 ㉮ 관급자재대 천원 올림
  ㉯ 안전관리비 관급항 `순자재대 ÷ 1.1` 이 **둘 다 저절로 맞음**.
- ⇒ `deduct_procurement_fee_for_safety` **옵션 제거**(엔진·법정경비·라우터).
  8-10 의 「차감은 규정 문구가 아님」과 결론은 같되 이유가 더 단순함 —
  **애초에 수수료는 관급금액에 안 들어감.**
- 잘못 넣는 사고를 테스트로 박음 — `test_owner_supplied_input_is_net_material_not_total`
  (합계를 넣으면 안전관리비가 8,629 원 = 375,160 ÷ 1.1 × 2.53 % 커짐).
- 필드 주석에 「실무 서류의 관급자재대를 그대로 넣지 말 것」 경고 추가.

자체검증 — **관행 옵션 없이 기본값만으로** 두 벌 재현:
2024 요율 → 안전 16,586,996 · 총공사비 1,201,879,000 / 현행 요율 → 안전 **18,586,091**.
화면 실측(5174) — 안전관리비 A 18,586,091 채택 · 관급자재대 69,850,000.
pytest 72 passed · ruff 통과 · tsc 통과 · 백엔드 재시작 후 200.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:23:16 +09:00
eomsangdonandClaude Opus 5 9575ce230f merge: sub_desktop_1 되받기 — main.py 라우터 등록 충돌 해소
B08 토적표 라우터와 B09 원가계산 라우터가 main.py 의 같은 자리(import 블록·
include_router 목록)를 각자 한 줄씩 늘려 충돌함. 둘 다 필요한 줄이라 양쪽을
그대로 살림 — 어느 쪽도 버리지 않음.

확인 — 충돌 표시 0건, 앱 import 성공, 두 라우터 경로가 모두 등록됨
(quantity 3건 · estimation 3건).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:19:09 +09:00
eomsangdon aa3bfe76ba Merge remote-tracking branch 'origin/main_laptop_1' into main_desktop_1 2026-09-07 20:17:54 +09:00
eomsangdonandClaude Opus 5 25f8da652d feat(B08): 토적표 화면 — 실무 3단 머리글 그리드
PLAN 8-4b 열 명세를 화면에 세움. 일감 2 의 마지막 덩어리(엔진 → API → 화면).

왜 실무 서식 그대로인가
  이 화면의 첫 사용자는 「프로그램이 맞나」를 확인하려는 설계자임. 보기 좋게
  재배치하면 실무 산출서와 눈으로 대조를 못 함. 열 순서·머리글 문구를 실무
  토적표(= 오솔길 1.BOM 36열)에 맞춤.

소수 자리는 표기 규칙일 뿐 (PLAN 8-16)
  서버는 전정밀 값을 주고 자르는 것은 화면뿐임. 실무 시트 관측대로
  단면적·체적 2자리 · 보정량계·유용토·차인·누가 1자리 · 거리 정수.
  원가 쪽(줄마다 원 단위 절사)과 규칙이 반대라 그 코드를 옮기지 말 것.

구성
  좌측 = 산출 조건 읽기 전용(산출법·토량환산계수). 계수는 서버 상수가 유일
  정의처라 화면이 값을 다시 적지 않음.
  우측 = 시트 탭 + 표. 지금 서는 장은 토적표 하나, 나머지 6장은 차례로 붙임.
  표는 한 번만 받아 좌측·우측이 함께 씀(중복 호출 없음).
  측점 열·머리글은 sticky — 가로로 굴러도 어느 줄인지 보임.

locale 은 B08 키 8개만 추가 (다른 창과 겹치는 파일이라 기존 줄 무접촉).

검증 — 공용 브라우저 실화면.
  타입검사 오류 0. 탭 「토적표」, 3단 머리글 3행(9/5/14셀), 본문 65행 x 20열,
  합계행 표시. 둘째 줄이 API 값과 일치: NO.1 거리 20 · 절토토사 1.96/22.34/20.10
  · 암 2.54/25.43/29.24 · 측구 0.08/2.58/2.33 + 0.10/1.02/1.17 · 보정량계 52.8
  · 성토 4.82/48.79 · 유용 48.8 · 차인 4.0 · 누가 4.0.
  ⚠ 어두운 테마에서 머리글이 묻히던 것을 프로젝트 테마 변수로 바꿔 고침 —
  대비 실측 머리글 10.51:1 · 본문 11.32:1 (기준 4.5:1).
  조작으로 바꾼 화면은 사용자가 보던 주소로 되돌려 놓음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:17:42 +09:00
eomsangdonandClaude Opus 5 ec23f87f83 fix(B09): 산출근거 문구 괄호 정정 · 진행단계 라벨도 「원가계산」으로
화면 실측에서 드러난 표기 오류 셋 (공용 브라우저 5174 조작 확인):
- **이윤 밑수가 뒤바뀌어 읽힘** — `(순공사원가+일반관리비) − 재료비 × 15%` 로 나와
  재료비에만 15 %를 곱하는 것처럼 보였음. 밑수가 합·차면 괄호를 씌우도록 고쳐
  `((순공사원가+일반관리비) − 재료비) × 15.0%` 로 나옴.
- **안전관리비 B 산출근거에 밑수 설명 문장이 통째로 박혀** 식이 안 읽혔음.
  밑수 라벨을 「재료비+직접노무비 (관급 제외)」로 줄이고 ×1.2 는 대괄호로 감쌈.
- **채택 요약 줄에 요율이 한 번 더 붙던 것** 제거 — 산식은 A·B 줄에 이미 있음.
- `WF_Step_Estimation` 라벨도 「설계도서」→「원가계산」 (페이지명과 어긋나 있었음).
- `F402` 정리: 구간 지문 루프 변수가 `dataclasses.field` 를 가리던 것 이름 변경.

자체검증 — 브라우저 실측 29줄 렌더 · 요율 판(2026-04-13 / 지문 250b1e4d…) 표시 ·
안전관리비 A 채택/B 취소선 · 환경보전비 「미확정」 경고 표시 ·
목표 도급공사비 1,192,000,000 입력 시 필요 조정액 **394,456** 제안(적용은 안 함) ·
`(1,192,433,902 − 1,192,000,000) ÷ 1.1 = 394,456` 손검산 일치.
pytest 32 passed · ruff 통과 · tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:16:22 +09:00
eomsangdon 79275ed070 Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-07 20:14:46 +09:00
eomsangdon 188b9be696 Merge remote-tracking branch 'origin/main_desktop_1' into main_laptop_1 2026-09-07 20:14:43 +09:00
eomsangdon e46b89df11 auto: 2026-09-07 20:14 (ESD_LAPTOP) 2026-09-07 20:14:11 +09:00
eomsangdonandClaude Opus 5 f659aec8a1 feat(B05): 평면(지도)에도 구간형 구조물을 띠로 — 종단과 같은 자료
사용자 지시(2026-09-07). 계획서 3-6 마지막 항목 — 산마루측구·도수로·옹벽처럼 **구간**으로
놓이는 시설이 종단에는 띠로 보이는데 **평면(배수유역도)에는 아무 표시가 없었음**.

**「부품이 없어 새로 짜야 함」이 사실이 아니었음** — 계획선 표본(`strengthSamples`)이 **1m 간격**
이라 **배열 인덱스가 곧 누가거리**임(`resampleRoute`). 구간 → 화면 선은 그 토막을 잘라 굵게
긋기만 하면 됨. 새 파일 하나(88줄)로 끝남.

- `B05_Profile_UI_Drainage_Spans.ts` — 띠 그리기(`drawRouteSpans`)와 자료 만들기
  (`routeSpansFromStructures`). 구간형만 띠가 되고, 색은 **레지스트리 표시색**을 그대로 씀.
- 그리는 자리 — **계획선 바로 위, 강도 색칠·마커 아래**. 굵기 7px·투명도 0.45 라 계획선을
  덮지 않음. 이름은 안 적음(종단에 이미 있고, 지도 글자는 눈금·유역 번호와 겹침).
- 목록이 바뀌면 따라옴 — `setStructures`·`setStructureTypes` 가 띠를 다시 넘김.
- 저장분에 노선보다 긴 구간이 남아 있어도 잘라서 그리고, 시작=끝인 구간도 한 칸은 보임.

⚠ 프로필 패널이 이미 700줄을 넘겨 있어(843) **매핑 로직은 띠 모듈로 뺐음** — 패널에는 3줄만
남김(827줄). 그 파일의 초과는 이전부터임.

시험 5건 — 부품 존재 · 범위 밖 구간 안전 · **쌓는 순서**(계획선 → 띠 → 강도 색칠) ·
종단과 같은 자료에서 뽑는지 · 목록 변화가 따라오는지.

⚠ 실화면 확인은 아직임 — 공용 브라우저가 소단 무한루프(별건, `80db17d4` 로 고침) 로 멈춰 있어
사용자 새로고침 대기 중임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:14:09 +09:00
eomsangdon fe92941d7b auto: 2026-09-07 20:12 (EOMSANGDON-HOME) 2026-09-07 20:12:02 +09:00
eomsangdonandClaude Opus 5 b48ab7047c feat(B08): 토적표 엔진·API — 평균단면적법 체적화
PLAN 8-4b 열 명세대로. B06 이 이미 낸 측점별 단면적을 다시 재지 않고
체적화만 함 — 새 수량을 낳지 않으므로 캐시·조작 경로 불필요(CLAUDE.md 5장).

열 구성 (실무 토적표 = 오솔길 1.BOM 36열과 1:1)
  측점·거리·절토[토사·암 각 단면적/입적/보정량]·측구터파기[토사·암 각 3칸]
  ·보정량계·성토[단면적/입적]·유용토·차인토량·누가토량.
  사면 계열(층따기·면고르기·법면보호공·지장목제거)은 사면길이가 아직 없어 일감 3.

계산 규칙
  체적 = (앞 단면적 + 현 단면적)/2 x 거리. 첫 측점은 앞이 없어 체적 없음.
  보정량 = 체적 x 다짐 환산계수 — 정의처는 EARTHWORK_CONVERSION_FACTORS 한 곳,
  여기서 값을 다시 적지 않음(토사 0.90 / 리핑암 1.15 / 발파암 1.30).
  값을 자르지 않음 — 품셈 1-2-2 는 표기 규칙이고 절사는 화면 몫(PLAN 8-16).
  원가 쪽(줄마다 원 단위 절사)과 규칙이 반대라 섞지 말 것.

TODO(미결 · PLAN 8-4b) — 설계가 측구를 토사·암으로 안 나눠 줌(ditch_area_m2 한 값).
  잠정으로 그 측점 절토 토사:암 면적비로 안분함. 측구는 절토부에 파므로 같은
  지반을 만난다는 것이 근거. 설계가 측구 지반을 따로 내면 _split_ditch 만 교체.

API — GET /api/projects/{id}/quantity/{route_id}/earthwork-table,
  경로 생략형은 워크플로 최신 노선으로. main.py 는 자기 두 줄만 추가.

검증 — tmp/tests/test_b08_earthwork_table.py 14건 통과.
  거창 실무 BOM 실측값 재현(단면적 1.89 → 체적 9.45 → 보정 8.505,
  다음 측점 18.10 → 16.29, 측구 0.18㎡ → 10m당 1.80 → 1.62).
  공용 브라우저에서 실 API 호출로 route 150·측점 65곳 확인 — 측점 20 에서
  (0.2723+1.9615)/2x20 = 22.338, x0.9 = 20.1042, 암 25.427 x1.15 = 29.24105,
  측구 안분 0.0784+0.1016 = 0.18 로 전건 일치.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:11:53 +09:00
eomsangdonandClaude Opus 5 2a21f99ba4 feat(B09): 원가계산 라우터·화면 신설, 페이지명 「원가계산」으로 변경
- `B09_Estimation_Router.py` 신설 — 무상태 계산 엔드포인트 3종.
  · `POST …/estimation/cost` 원가계산서 한 장(줄마다 비목·금액·요율·산출근거)
  · `GET …/estimation/items` 비목 정의 목록
  · `POST …/estimation/confirm` stage 6 완료 전이
  요율 구간을 못 고르면 500 이 아니라 **422 + 사유**로 알림 (기본값으로 안 때움).
  `target_contract_amount_krw` 를 주면 필요한 이윤 조정액을 **보여만 줌**(★법대로 8-10).
- `B09_Estimation_UI_Page.ts` — 셸에서 실제 화면으로. 3단 레이아웃, 좌측 입력 4군
  (공사조건·요율 판 읽기전용·관급자재·이윤 조정) + 우측 탭 8장(원가계산서 활성).
  원가계산서 표는 **네 칸 + 비고**이고 **안전관리비 A·B 두 줄이 나란히**, 채택 줄은
  강조·미채택 줄은 취소선.
- `main.py` — B09 라우터 import·등록 **자기 줄만** 추가.
- `ui_template_locale_b2.ts` — B09 키 추가, `B09_Estimation_Title` 을
  「설계도서」→**「원가계산」**으로 변경 (PLAN 9-1 사용자 승인).
- 자체검증: `tsc --noEmit` 통과 · 백엔드 재시작 후 `openapi.json` 에 3개 경로 등록 확인 ·
  `/api/health` 200. 화면 조작 검증은 다음 단계(브라우저 창이 닫혀 재기동 필요).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:11:15 +09:00
eomsangdonandClaude Opus 5 c044e33dab fix(B09): 규모 구간을 추정가격 반복 수렴으로 판정
- 근거 = 국가계약법 시행령 제7조 1호 「공사계약의 경우에는 **관급자재로 공급될 부분의
  가격을 제외한 금액**」. 우리 계산의 그 값은 **총원가**(부가세 전·관급 밖)임.
- 씨앗은 직접공사비로 두되 **거기서 멈추지 않음** — 나온 총원가로 구간을 다시 판정해
  구간 지문이 굳을 때까지 되풀이(최대 5회). 진동하면 **높은 쪽 구간 채택**하고
  결과 `notes` 에 남김. `estimated_price_krw` 명시 시 반복 없음.
- 구간 지문 = 일반관리비·이윤·고용보험·하도급보증 구간 + 적용 하한(환경·퇴직) 충족 여부.
- ⚠ 잠재 결함 하나 같이 고침 — 하도급보증 30억 이상 구간이 공종(토목·산업설비/건축)으로
  갈려 **구간 2개가 겹쳐 멈추던 자리**. `select_bracket(prefer_suffix=…)` 로 공종을
  부르는 쪽이 대게 함 (조용한 기본값 아님).
- 자체검증: 32 passed. 씨앗 47억(8 %) → 총원가 50억 초과 → **6.5 % 로 재판정**되는
  경계 넘기 사례를 테스트로 박음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:06:03 +09:00
eomsangdonandClaude Opus 5 50871e60b9 feat(B09): 원가계산 엔진 완성 — 법정경비 분리·이중계상 감시·재현 검산
- `B09_Estimation_Statutory.py` 신설(법정경비 14비목) — 700줄 제한 대비 분리.
  **비목 목록을 코드에 안 박음**: 그 해 요율 데이터에 변수가 있는 것만 유효(8-13·8-14).
- `B09_Estimation_Guards.py` 신설 — 이중계상 거울 테스트 3종을 함수로 둠(8-7 ㉠㉡㉢).
  할증 두 번 · 무대 줄 단가 · 배합 두 번 쪼개기를 **수치로 잡아 멈춤**.
- 엔진: 이윤 3줄(조정 전·조정액·조정 후) · 관급자재대 천원 올림 · 폐기물처리비 실비 슬롯 ·
  `formula_text`(줄마다 제 산식 — 실무 원문의 A식 복사 오류를 안 따라감) ·
  `proposed_profit_adjustment`(필요액을 보여만 주고 적용은 명시로, ★법대로 8-10).
- 요율 로더에 `load_rate_dataset_from_path` 추가 — 옛 연도 재현 검산 전용, 지문이 없어
  정본이 아님이 결과에 드러남.
- 검산 고정값 두 벌(`tmp/tests`, git 밖):
  · 2024 요율 → 울진 공통 금액 사슬 **전건 재현**(안전 16,586,996 · 이윤 108,109,955 ·
    총원가 1,029,117,273 · 총공사비 1,201,879,000)
  · 현행 요율 → 안전 18,586,091. **같은 입력·같은 코드, 요율만 교체** — 연도 교체 구조 증명
  · 거창 A/B min **양방향**(울진 A 채택 · 거창 B 채택)
- 자체검증: `pytest tmp/tests/ -q` **68 passed** · `ruff check` 통과 · 파일 최대 441줄.
- 잠정 반영(TODO 주석 + 계획서 항목번호): 환경보전비 임도 요율 0.9 % 잠정 ·
  폐기물처리비 자리 미확정 · 조달수수료 차감은 기본 꺼짐(옛 서류 재현용 옵션).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:01:08 +09:00
eomsangdonandClaude Opus 5 3497486bed feat(B08): 산림사업 표준품셈 476표 → 공종 마스터 정규화 (공종 축)
PLAN 8-5·8-6·8-7 의 B08 일감 1번. B09 의 ③단가산출을 여는 선행 작업임.

공종의 정체 = 품셈 절 번호
  「9-3-1. 인력」처럼 절 제목이 공종이고 표의 행은 조건별 변형(토질·암종·규격)임.
  계층·정렬은 목차표(F0001)에서 나오고 표가 그 절에 붙음. 목차 477노드,
  표 456/475 귀속(미귀속 19 는 절번호 없는 부록·경과조치).

pum_form — 뒤집히면 값이 조용히 반대가 되는 자리
  productivity(작업능력, 품=1÷값) 16 · requirement(소요량, 품=값÷밑수) 244 ·
  coefficient(시공능력 공식 K·f·E) 19 · reference(1장 적용기준·할증·참조지시) 94 ·
  undetermined 83.
  ⚠ 판정 순서가 뜻을 가짐 — 「작업능력(㎥/hr)」 표의 비고에 「보통인부 1인/일」이
  흔히 붙어 있어 직종을 먼저 보면 생산량형이 소요량형으로 뒤집힘. 생산량형 표지를
  직종보다 앞에 둠.

담당 경계 (PLAN 8-7)
  공종 축만 만들고 자원 축(resource_kind·resource_code·amount)은 안 채움 — B09 몫.
  대신 원문 셀 raw_row 를 그대로 실어 B09 가 476표를 다시 열지 않게 함.
  판정 실패분은 빈칸이 아니라 form_undetermined_*.json 목록으로 냄.

산출 (resources/data_work_item_master/)
  work_item_master_2026-01-01.json · form_undetermined_2026-01-01.json · _manifest.json.
  dataset_version 에 dataset_id·effective_date·sha256 세 쪽 기록 — 재현성.
  공종코드 FP-09-03-01 형식, sort_order 는 STmate 관례대로 256 간격.

검증 — tmp/tests/test_b08_work_item_master.py 14건 전건 통과.
  생산량형이 비고의 직종에 뒤집히지 않는 것, 직종이 둘째 열에 있어도 잡는 것,
  raw_row 보존, 자원 축 미혼입, 미판정의 목록 등재를 각각 못 박음.
  전체 회귀 382 passed (실패 3건은 B05 구조물·코리도 기존 깨짐, 본 변경과 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:01:02 +09:00
eomsangdon bf895fb056 Merge remote-tracking branch 'origin/sub_desktop_1' into sub_laptop_1 2026-09-07 19:58:20 +09:00
eomsangdon ee16ee21d9 Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_1 2026-09-07 19:58:19 +09:00
eomsangdonandClaude Opus 5 80db17d463 fix(소단): 제자리 무릎이 되풀이돼 화면이 멈추던 것 — 앞으로 갈 때만 무릎 인정
**실사고(2026-09-07)** — 사용자 공용 브라우저에서 **소단을 한 건 놓자 화면이 25분 넘게 멈춤**
(렌더러가 1.4코어를 계속 태움). 서버(파이썬)로 같은 측점을 돌리면 0.01초에 끝나 **서버는
멀쩡**했고 화면만 물렸음.

**원인** — `cut_profile_points` 의 무릎(암 경계 교차) 가지에서 **제자리 뒤집기**.
암 경계선의 기울기가 **암 경사와 토사 경사 사이**면
· 토사로 바꾸면 다음 걸음이 경계 **아래** → 「다시 암」
· 암으로 바꾸면 다음 걸음이 경계 **위** → 「다시 토사」
가 되고, 이때 보간 비율 `share` 가 0 이라 `knee_dist == dist` — **한 걸음도 안 나감.**
`while dist < limit` 이 끝나지 않음. `multi_knee` 는 **소단이 있으면 항상 참**이라 소단이 지뢰였음.

**고침 둘**(파이썬·TS **같은 모양**)
1. **앞으로 나아가는 무릎만 인정** — 직전 무릎 자리를 들고 있다가 같은 자리(1e-9 이내)면
   뒤집지 않고 한 걸음 감. **첫 무릎은 종전대로 인정**되므로 `multi_knee=False`(소단 없는
   경로)는 한 비트도 안 바뀜 — 그쪽은 첫 뒤집기 뒤 가지 자체가 닫힘.
2. **걸음 수 상한 40,000**(정상 최대 4,000의 10배). 넘으면 **조용히 자르지 않고 경고**를 남김 —
   조용히 자르면 절토선이 짧아진 채 값이 나가 또 조용히 틀림(25 지적).

**시험 5건**(`tmp/tests/test_berm_knee_progress.py`) — 경계 기울기를 두 경사 사이에 둔 재현으로
① 8초 안에 끝나는지 ② 거리가 뒤로 안 가는지 ③ 소단 없는 경로가 종전 그대로인지
④ 두 파일이 같은 규칙을 쓰는지 ⑤ **TS 를 실제로 돌려 파이썬과 꼭짓점 수·끝점이 같은지**.
고치기 전에는 ①이 무한 대기였음. 전체 **491 passed · 17 skipped**, `tsc --noEmit` 통과.

버그를 낸 창(25)과 확인하고 진행함 — 겹치는 작업 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 19:57:44 +09:00
eomsangdon 128a40d8f0 Merge remote-tracking branch 'origin/main_laptop_1' into sub_desktop_1 2026-09-07 19:49:14 +09:00
eomsangdon 0799e733ab Merge remote-tracking branch 'origin/main_desktop_1' into sub_desktop_1 2026-09-07 19:49:12 +09:00
eomsangdon 197b00aef1 Merge remote-tracking branch 'origin/main_desktop_1' into sub_laptop_1 2026-09-07 19:49:10 +09:00
eomsangdon 9406551544 Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-07 19:49:01 +09:00
eomsangdonandClaude Opus 5 8b7325a28e feat(B09): 원가계산 엔진·요율 로더 뼈대 추가
- `B09_Estimation_Rates.py` — 요율 데이터(`resources/data_cost_input_value/rates_*.json`)
  로더 + 구간 조회. 요율을 코드에 안 박음. 구간 라벨의 `billion` = 십억 원.
  구간 판정 실패 시 기본값으로 안 때우고 `RateLookupError` 로 멈춤.
- `B09_Estimation_Engine_Cost.py` — ⑤ 공사원가계산서 계산. 순공사비를 받아
  법정경비·일반관리비·이윤·부가세를 얹음. 수량·단가와 무관하게 홀로 돎.
- 지킨 것 (PLAN 8-9·8-10, 실무 원가계산서 재현으로 확인된 것만)
  · 모든 줄 원 단위 버림 · 밑수가 항목마다 갈림(직노 / 직노+간노 / 건강보험료 / …)
  · 안전관리비 A·B 두 값 중 작은 쪽 — 대상액이 구간 경계를 넘으면 A 가 더 커짐
  · 이윤 수동 조정액은 설계자 명시 입력일 때만 · 비목 목록을 코드에 안 박음
- 검사 16건 별도(`tmp/tests/test_b09_cost_engine.py`, git 밖) 전건 통과.
  실무 실측 두 방향(울진 A 채택 · 거창 B 채택)을 고정값으로 씀.
- 기존 파일 무수정 · DB 미사용(기준자료는 파일, PLAN 8-5·9-2).

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