sync: 4환경 수렴본 main 반영 (2026-09-08) #11

Open
eomsangdon wants to merge 590 commits from sub_laptop_1 into main
Owner

4환경(데스크탑 메인·보조 / 랩탑 메인·보조)이 2026-09-02 이후 쌓은 작업을 main 에 반영.

실리는 것

  • 커밋 588(머지 제외 441) · 558 파일 · +117,095 / −10,189
  • PR 범위 = 한 창의 작업이 아님 — git sync 되받기로 네 브랜치가 서로를 흡수해
    네 환경의 합집합이 실림. 작성자는 전부 umsangdon.

네 브랜치 상태 (병합 직전 실측)

내용은 완전히 같음 — 네 브랜치의 트리 해시가 모두 b772f6e7.
끝점 SHA 만 다르고, 벌어진 커밋 다섯은 전부 머지 커밋(파일 변경 0).
sub_laptop_1 이 나머지 셋을 모두 조상으로 품어 이 브랜치를 head 로 삼음.

sub_laptop_1     003b69bf   ← head (나머지 셋을 다 품음)
sub_desktop_1    6a90bc10
main_laptop_1    6a90bc10
main_desktop_1   8e99b8a7
main             1a994742   (2026-09-02)

주요 변경 (폴더별 파일 수)

resources/(지식DB·품셈 원문) 146   B05_Profile 87   B06_Section 51
B07_DesignDetail 47   common_util 34   B04_PreProcess 30
B09_Estimation 27   B08_Quantity 24   B03_FileInput 24   B01_Dashboard 19

굵직한 것 — B08 수량산출·B09 원가계산의 품셈 원문 대조(밑수 단위·자릿수·이중계상 가드),
B05 배수유역·코리도, B06 횡단 구조물, B07 도면, 지식DB 기술문서 보강.

확인한 것

  • 네 창 모두 git sync미push 0 · 미커밋 0 · 충돌 0
  • 회귀: 데스크탑 메인 741 passed / 1 failed, 데스크탑 보조 254 통과,
    랩탑 메인 513 passed, 랩탑 보조 551~556 passed (tsc --noEmit 통과)
  • 남은 실패 둘은 B05 코리도 기존 깨짐삭제된 프로젝트 파일을 실경로로 읽는 시험
    (자료 문제, 코드 무관). 둘 다 별도 손질 대상.

🤖 Generated with Claude Code

4환경(데스크탑 메인·보조 / 랩탑 메인·보조)이 2026-09-02 이후 쌓은 작업을 `main` 에 반영. ## 실리는 것 - 커밋 **588**(머지 제외 **441**) · **558 파일** · +117,095 / −10,189 - ⚠ **PR 범위 = 한 창의 작업이 아님** — git sync 되받기로 네 브랜치가 서로를 흡수해 **네 환경의 합집합**이 실림. 작성자는 전부 `umsangdon`. ## 네 브랜치 상태 (병합 직전 실측) **내용은 완전히 같음** — 네 브랜치의 트리 해시가 모두 `b772f6e7`. 끝점 SHA 만 다르고, 벌어진 커밋 다섯은 **전부 머지 커밋**(파일 변경 0). `sub_laptop_1` 이 나머지 셋을 모두 조상으로 품어 이 브랜치를 head 로 삼음. ``` sub_laptop_1 003b69bf ← head (나머지 셋을 다 품음) sub_desktop_1 6a90bc10 main_laptop_1 6a90bc10 main_desktop_1 8e99b8a7 main 1a994742 (2026-09-02) ``` ## 주요 변경 (폴더별 파일 수) ``` resources/(지식DB·품셈 원문) 146 B05_Profile 87 B06_Section 51 B07_DesignDetail 47 common_util 34 B04_PreProcess 30 B09_Estimation 27 B08_Quantity 24 B03_FileInput 24 B01_Dashboard 19 ``` 굵직한 것 — B08 수량산출·B09 원가계산의 품셈 원문 대조(밑수 단위·자릿수·이중계상 가드), B05 배수유역·코리도, B06 횡단 구조물, B07 도면, 지식DB 기술문서 보강. ## 확인한 것 - 네 창 모두 `git sync` 후 **미push 0 · 미커밋 0 · 충돌 0** - 회귀: 데스크탑 메인 741 passed / 1 failed, 데스크탑 보조 254 통과, 랩탑 메인 513 passed, 랩탑 보조 551~556 passed (`tsc --noEmit` 통과) - 남은 실패 둘은 **B05 코리도 기존 깨짐**과 **삭제된 프로젝트 파일을 실경로로 읽는 시험** (자료 문제, 코드 무관). 둘 다 별도 손질 대상. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
eomsangdon added 588 commits 2026-09-08 17:19:43 +09:00
- 상태막대 `명령행` 토글의 초기 상태를 `useState(true)` → `useState(false)` 로 변경
- 진입 시 `--cad-command-height` 가 `0px` 로 잡혀 캔버스 세로 공간 확보
- 토글 동작·명령행 구현 자체는 불변

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
증상: 파일 입력 직후 초기 계산값과 B05 [초기화] 결과가 다름.

원인
- 자동설계 체인이 5단계까지 전부 성공해야만 `save_initial_snapshot()` 호출.
  중간에 깨지면 `initial_snapshot/` 미생성 → [초기화]가 복원 대신 재계산 폴백.
- 재계산 폴백의 지표면 기준이 체인과 다름 — 체인은 stage 1 확정값
  (`get_surface_confirmation_params`), [초기화]는 config 기본값
  (`surface_confirmation_defaults`). 실측: 프로젝트 stage1 `classification`/5m 대
  config `csf`/1m.
- 체인이 깨져도 WF1 은 초기 분석 완료 메일을 그대로 발송.

수정 (2026-09-02 사용자 확정 — 부분 결과는 분석 안 됨과 다르지 않으므로 부분
스냅샷은 만들지 않음)
- `initial_design.failed` 마커 신설 — 프로젝트 루트(스냅샷 4트리 밖), 실패 사유 기록.
  체인 진입 시 옛 마커 제거, 실패 5지점 + 스냅샷 저장 실패에서 기록.
- WF1 이 마커를 읽어 완료 메일 대신 `send_initial_design_failed_email()` 발송
  (관리자 주소 `ADMIN_EMAIL`, 없으면 주소 없이 안내).
- B05 [초기화]: 스냅샷 있으면 복원, 실패 마커 있으면 409 `initial_design_failed`
  로 거부(DELETE 앞에서 반환 — 데이터 무변경), 옛 프로젝트만 종전 재계산 폴백.
- 재계산 폴백의 지표면 기준을 `get_surface_confirmation_params()` 로 통일.

자체검증: `pytest tmp/tests/ -q` 366 passed / 14 skipped / 0 failed (+4).
공용 브라우저 실측 — 실패 프로젝트 [초기화] 409 응답·`routes` 행 무변경 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 자산 모달 서명 칸에 마우스 그리기 판 신설 — pointer 이벤트 + setPointerCapture,
  getBoundingClientRect 로 CSS 크기 → 캔버스 픽셀 환산, [지우기] 1개
- 올릴 때 canvas.toBlob('image/png') → signature.png 로 기존 업로드 통로
  (POST /company/assets) 재사용 — 백엔드·DB 변경 없음
- 파일을 안 고르면 그린 서명을 대신 실어 보냄, 로고 칸에는 캔버스 없음
- 검증(5174 공용 브라우저): 좌표 환산 실측 x 98–381 · y 38–111(요청 100–380 · 40–110),
  [지우기] 후 잉크 0, 저장 PNG 480×160 RGBA 5,250 bytes,
  프로젝트 signature_asset_id 2→3 반영 확인 후 원복. pytest 143 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 편집 띠를 CAD 위 절대배치에서 도면 목록 하단 액션 칸으로 옮김 —
  1행 편집 띠, 2행 [도각 편집]·[현재 도면 확정] (리본과 겹쳐 문구·버튼이 찌그러지던 문제)
- `drawImage` 가 'broken' 상태 그림에서 던지던 예외로 렌더 루프가 끊겨
  이후 모든 도면이 백지로 남던 결함 해소 — 못 읽은 그림은 건너뜀
- `ImageEntity` 가 자리표시자(`{{회사로고}}`)를 절대 URL 로 굳히던 저장 경로 수정 —
  원본 주소를 보관해 그대로 돌려주고, 자리표시자는 요청조차 하지 않음
- 버튼 줌(ZOOMIN·ZOOMOUT)이 배율만 바꿔 도면이 화면 밖으로 밀리던 것을
  화면 중심 고정으로 수정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-02) — 이름이 들어가는 자리는 서명도 받고, 담당자 선택에 신규 등록
항목을 두며, 회사 로고는 회사 등록 단계에서 받아 이후 변경.

- 014_company_logo.sql: companies.logo_asset_id 추가 (서명은 company_assets.user_id 로
  이미 표현되어 컬럼 없음). 공유 DB 적용 완료
- 사용자 수정 모달에 「서명 (도면 표제란)」 칸 — createAssetField 에 owner(주인 못박기)·
  onChange(즉시 반영) 추가로 재사용, 주인 고정 시 물리기 체크 잠금
- 담당자 select 3개에 「+ 신규 등록…」 — 계정 생성 모달 뒤 세 select 에 항목 삽입·자동 선택
- POST /admin/members 가 이름·직위·부서 수신, 계정 없으면 status=PENDING 으로 생성
  (로그인 불가 비밀번호). 700줄 제한으로 B01_Dashboard_Repository_Members.py 분리
- 회사 등록 모달에 로고 파일 칸, PUT /company/logo 신설, 회사 패널·회사 목록에서 변경
- 프로젝트 수정 모달의 「설계자 서명」 칸 제거 — signature_asset_id 는 null 로 고정 저장
- 검증(5174 실조작): 신규 등록 구성원 2→3(id 6 PENDING)·select 자동 선택, 서명 자산
  [4,'검증신규 서명',user_id 6] 생성, 회사 logo_asset_id None→1, 검증 자산·계정 정리.
  pytest 143 passed, tsc·ruff·prettier 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 서명: `projects.signature_asset_id` 대신 설계자(`designer_user_id`, 없으면 소유자)
  계정의 `company_assets` SIGNATURE 자산을 따라감 (여러 벌이면 최신 1건)
- 로고: 프로젝트가 고른 것 우선, 없으면 `companies.logo_asset_id` (014) 로 폴백
- `projects.signature_asset_id` 는 컬럼만 남기고 더 읽지 않음 — B01 이 항상 null 저장

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`94883733` 이 자동 폴백 커밋(`auto: …`)으로 묶여 나가 내용 설명이 빠짐. 이력 재작성
금지(CLAUDE.md 6장)라 amend 대신 이 빈 커밋으로 남김. 그 커밋의 실제 변경:

- `resources/template_2dDrawing/00_template_A1.json` — Image 자리 2개 추가.
  `{{과업책임자서명}}`(x 536.89~578.89) · `{{분야별책임자서명}}`(x 587.91~629.91),
  둘 다 y 17.5~25.5. 설계자 서명과 같은 폭 42·높이 8이고, 표제란 세로선
  (531.87 / 583.91 / 633.91) 이 만드는 칸 안에서 좌우 여백 4로 가운데 배치.
- `B07_DesignDetail_Router.py` `_title_block_fields` — 두 자리 값을
  `pm_user_id`·`field_lead_user_id` 계정의 `company_assets` SIGNATURE 자산에서 읽음
  (설계자와 같은 최신 1건 서브쿼리). 서명을 안 올린 사람 자리는 종전대로 엔티티째 빠짐.

자체검증: `frame-template` 응답이 Image 4건(회사로고+서명 3)으로 자리·좌표 확인,
`tmp/tests/test_b07_title_block_signatures.py` 3건 신설, `pytest tmp/tests/ -q` 15 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- `00_template_cover.json` 에 Image 자리 추가 — `{{회사로고}}`,
  x 57.40~137.40 · y 64.06~104.06 (폭 80 · 높이 40)
- 자리는 오른쪽 아래 `{{시행청}}`(기준점 784.35, 84.06)과 좌우로 마주 보게 잡음.
  왼쪽 여백은 `{{연도기번}}`(x 57.4)과 맞추고 세로는 시행청 글자줄에 맞춤
- 값 공급은 도각과 같은 통로 — `build_cover_drawing` 이 이미 `_fill_placeholders` 를
  태우므로 로고를 못 구하면 종전대로 엔티티째 빠짐

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-02) — 프로젝트 등록에서도 수정 모달과 같은 항목 수신.

- 시행청·연도기번·사업량·설계일자·과업책임자·분야별책임자·설계자·회사 로고 8칸 추가.
  담당자는 select + 「신규 등록…」(관리자만), 로고는 회사 대표 로고가 기본값
- 담당자·자산 회사 경계 검사를 check_project_refs(company_id, data) 로 옮겨 B01 수정과 공용
- GET /admin/members 문턱을 require_company 로 — 일반 사용자도 담당자 선택 필요.
  _scope_company 가 남의 회사를 막고 쓰기는 관리자 그대로
- fix: road_type 스키마가 옛 값(branch·stream)을 받고 화면 선택지 work 를 막아
  「작업임도」 등록이 422 로 떨어지던 것 수정 — ^(main|fire|work)$
- 검증(5174 실조작): 등록 칸 14개로 수정 모달과 동일, 등록된 행에 8칸 그대로 저장
  (road_type=work, logo_asset_id=1, designer=3), 해당 프로젝트 표제란 12칸 전부 채워짐.
  pytest 151 passed (신규 test_b02_register_schema.py 8건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 사용자 지시 9건 반영. 화면 실조작 검증은 다음 세션 몫 (사용자 지시로
코딩까지만 진행).

1. 초기 계획선 = 전체 측점 폴리라인 — `design_ground_following_profile()` 신설.
   모든 측점을 변화점으로 잡고 계획고 = 원지반고, 라운드는 R을 지정한 자리에만
   (`build_curves(only_explicit=)`·`build_alignment(only_explicit_curves=)`).
   basis `ground_polyline`. 관 정착 선형은 폴백으로 내림.
2. 구간 쉬프트(⬆⬇) 삭제.
3. [직선화] 신설 — `B05_Profile_UI_Profile_Straighten.ts`. 두 측점의 라운드에 탄젠트한
   직선으로 대체하고 사이 라운드 삭제. 직선 틸팅 시 가운데 라운드 + 양측 탄젠트 재구성.
4. [쉬프트] 신설 — 직선 구간을 기하에서 되읽어(`detectStraightRun`) 복수 선택,
   최외곽 라운드 중심 기준 상·하 평행이동.
5. 방향키 조작 — 상하 0.1m 계획고, 좌우 0.1m 누가거리(구조물·비정규 측점 한정).
6. undo/redo 신설 — B05·B06 조작 세션 키 묶음 스냅샷(`_Profile_History.ts`).
   버튼은 요약줄 맨 앞(최대 기울기 좌측), 21x17px. Ctrl+Z / Ctrl+Shift+Z.
7. 종단 요약줄의 횡단배수 최소고 표시 삭제(산식·편집 차단은 유지).
8. [편집 되돌리기] 버튼 삭제 — undo/redo로 대체.
9. 지형 구분 기본값 특수지형 — 패널 셀렉트와 백엔드 기본값(스키마·체인 폴백) 일치.

700줄 제한 — 패널을 `_Profile_Panel_Tools` · `_Profile_Preview` 로 분리하고 측점↔구조물
짝짓기를 `_Profile_Structures` 로 이관(842줄 → 696줄).

검증: tsc --noEmit 오류 0, ruff format/check 통과,
pytest tmp/tests/ -q → 366 passed / 14 skipped / 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 화면 검증에서 나온 미해결 2건 처리.

- 최소고 가드: `blocksMinCover` 가 `_Profile_Render` 측점 끌기 한 곳에만 있어
  [직선화]·[쉬프트]·틸팅·방향키가 그냥 지나감. 판정 로직을
  `_Profile_MinCover.blocksMinCover()` 로 옮기고 모든 편집이 지나는
  `_Profile_Panel.applyEdits` 한 곳에서만 호출. 화면 모듈의 사본·죽은 배선
  (`enforceMinCover` ctx 필드, 미사용 import)은 제거.
- 되돌리기 범위: 이력이 `b05:`·`b05-`·`b06:`·`b06-` 세션 키만 스냅샷하는데
  구조물(관) 위치는 세션 밖이라 undo 가 계획선만 되돌림. `_Profile_Panel_Tools`
  가 기록 직전에 관 목록을 `b05:pipes` 로 흘리고 복원 뒤 되읽어 반영.
  사용자 확정 ⑥ 「범위는 B05 페이지 조작 전부」 충족.

검증(공용 브라우저, 용화 검증 프로젝트 route_id 126):
- 최소고 강제 켠 상태로 관 측점 264.060 방향키 ↓ → 편집 미적용 + 경고
  "배수관 Ø800 — 최소 계획고(지반 +1.3m) 아래로 내려갈 수 없습니다."
- 구조물 측점 264.060 → 263.960 이동 후 ↶ 1회 → 264.060 복귀,
  `b05:pipes` 목록도 264.06 으로 복귀.
- `tsc --noEmit` 0, prettier 통과, pytest 366 passed / 17 skipped / 0 failed.
- 파일 줄수: Panel 699 · Panel_Tools 197 · Render 350 · MinCover 188 (700줄 제한 준수).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
관 끝단 두 꼭짓점을 마감면(I형 벽 안쪽 변) 선분 안으로 자를 때, 원지반이 벽 상단
위라 관 시작점이 벽 상단에 붙으면 위·아래 교점이 같은 끝점으로 접혀 관 단면이
삼각형으로 그려짐. 비스듬히 자른 끝단 길이는 항상 관경 이상이므로, 그보다 짧으면
접힌 것으로 보고 축 직각 마감으로 되돌림.

검증 — 공용 브라우저 B06 단면 8개 실측: 유입측 끝단 길이 0.0px → 18.7~58.4px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
평형선·장비 띠·물량 balloon 이 안 생기는 노선에서 그 이유를 화면에서 읽을 수 있게,
곡선 끝의 누가토량을 요약 칩으로 드러냄. 0에 가까울수록 절·성토 균형이며 곡선이
0선을 넘지 않으면 평형선이 서지 않는다는 설명을 툴팁에 담음. 판정·조정은 사용자
몫이라 자동 보정 로직은 두지 않음(2026-09-03 사용자 확정).

B05 종단 패널과 B06 횡단 화면이 같은 함수를 쓰므로 양쪽에 함께 반영됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실무 유토곡선 원본 6건(.MASS · EARTH.DAT) 파싱 관측 수록 — 최종 누가토량 +49~+324㎥,
0선 교차 3~17회, 장비 한계거리 전 건 무대 20.0 / 도자 60.0 m. 평형선 자동 선정·극값
무시 임계·balloon 표기 관행은 현행 근거 공백임을 명시하고 미결 20 으로 등재. 도자
한계거리 60m(실무) vs 70m(현행 구현) 채택은 미결 21.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 자동설계 체인이 초기값 스냅샷에 `planned_route.csv` 를 함께 남김. 값은 체인이
  이미 만든 정점(사업지 좌표계·트림·조밀화 후)이라 재계산 없음.
- `load_design_route()` 는 surface_params 가 주어진 호출에 한해 그 CSV 정본을 읽음.
  트림 전 원본이 필요한 호출(도엽 범위)은 종전 경로 유지. 지표면·노선이 바뀌면
  `discard_initial_snapshot()` 이 폴더째 지워 경로가 저절로 닫힘.
- `run_sheet_surface_analysis()` 가 노선을 원본 좌표계로 읽어 도엽 서피스를 딴 자리에
  만들던 문제 교정 — `load_design_route()` 로 창구 통일, 도엽 확보 PRJ 탐색도 지형
  PRJ 폴더로 교정. shapefile 노선(5179) + 지형 PRJ(5176) 조합에서 트림이 노선을
  통째로 지우던 원인.

검증: tmp/tests 158 passed(신규 4건 포함), 공용 브라우저 실사용 경로로 용화 shapefile
한 벌 업로드 → 자동 체인 완주 → CSV 정본 643점, 원본 경로와 최대 좌표차 0.00007m.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
① 저장된 횡단이 지금 계획선과 어긋나면(재계산 예약 상태) 유토곡선을 그리지 않고
「횡단을 지금 계획선에 맞춰 다시 계산하는 중입니다」만 띄움. 옛 계획고로 만든 면적이
2초간 보였다가 정본으로 갈아 끼워지던 것을 없앰(2026-09-03 사용자 확정 「새 값만
보여주기」). 용화 실측 — 65측점 중 56개가 낡음, 계획고 차 −9.36~+5.83m,
저장분 성토 42,050㎥ ↔ 정본 14,881㎥.

② 사면이 계산 반폭 끝까지 원지반과 만나지 않아 면적이 잘린 측점에 카드 경고 표기.
판정은 면적을 내는 엔진 한 곳(B06_Section_Engine_Design)에서 `slope_unclosed` 로
내려 화면·수량·도면이 같은 기준을 봄. 계산은 손대지 않음(2026-09-03 사용자 확정
「영원히 못 만나는 지형이 있을 수 있으니 경고로 대체」).

검증 — 공용 브라우저 B06 실측: 2.6초 재계산 안내만 표시(옛 값 미노출), 4.4초 정본
표시, 사면 미교차 경고 13/65측점. pytest 366 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
옛 방식은 한 칸 이웃만 보는 국소 하강이라 1m 간격 계획고의 미세 요철에 걸려 멈췄다.
용화 실측: 측점 2,138개 중 1,898개(88.8%)가 저점에 갇혀 흐름이 아니라 누가거리
최근접으로 관에 붙었고, 그 결과 도로 셀 43.2%가 자기보다 높은 관에 배정됐다
(최대 6.82m 오르막).

이웃한 두 관 사이의 최고점(마루)을 분수령으로 삼아 왼쪽은 앞 관, 오른쪽은 뒤 관이
받게 바꿈. 1차원에서 물은 마루를 넘지 못하므로 물리적으로 정확하고 미세 요철에 면역.
첫 관 앞·마지막 관 뒤는 그 관이 받는다. 관 순서는 호출자가 준 그대로 보존.

검증: 단위 5건 신규(전체 163 passed), 실측 오르막 배정 43.2% → 17.6%(최대 4.15m),
잔여 1,993셀은 전부 사그 저류 후 더 낮은 장벽으로 넘치는 경우(어긋남 0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 데이터를 두 화면에 보여 주는 기능인데 세 곳이 갈려 값이 달랐다(실측: 절토(자연)
B06 3,704.6㎥ ↔ B05 4,526.8㎥).

① 보는 노선 — B05는 최신 경로, B06은 최신 **확정** 경로를 열어 노선을 다시 탐색한
   프로젝트에서 서로 다른 노선을 봤다(route 126 DRAFT ↔ 125 CONFIRMED, 같은 20m
   측점 성토 4.82㎡ ↔ 85.9㎡). `get_workflow_route_context()`(최신 경로) 신설해 B06
   화면 context가 그것을 쓴다. 납품 도면(B07)이 쓰는 확정 전용 창구는 그대로 둔다.

② 횡단 재계산 — 호출이 두 벌이라 인자가 갈렸다(B06만 표준 단면값·암 경계 오프셋 전달,
   보존하는 사용자 부속값도 2개 ↔ 7개). `B06_Section_Cross_Refresh.refreshCrossDesigns()`
   한 창구로 모으고 세션 편집값은 저장소에서 직접 읽어 패널 없는 B05도 같은 값을 보낸다.

③ 낡음 판정 — 「옛 암 2단계 필드 누락」 조건이 B06 페이지에만 있어 B05는 재계산을
   건너뛰었다. 공용 `staleDesignChainages()` 안으로 옮겨 두 화면이 같은 시점에 같은
   조치를 한다.

검증 — 공용 브라우저 실측: 두 화면 모두 route 126, 요약줄 문자열 완전 일치
(`절토(자연) 4,526.8㎥ · 성토 14,881.8㎥ · 토취 10,213.3㎥ · 최종 누가토량 −10,213.3㎥`).
pytest 370 passed·17 skipped(일원화 검사 4건 신설), typecheck·prettier·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
뷰어 좌표 규약이 `x, 높이, -y` 라 세계 북쪽은 -z 다. 카메라 오프셋(카메라 − 타깃)의
수평 성분으로 도북이 화면에서 몇 도 돌아갔는지 계산해(atan2(offset.x, offset.z)) 바늘을
돌린다. 뷰어 우하단 — 축척 막대(좌하단)의 반대편에 둔다.

뷰어 파일이 이미 946줄이라 콤파스는 별도 모듈로 분리(700줄 제한). 애니메이션 루프에서
0.5° 이상 움직였을 때만 transform 을 다시 쓴다.

검증: typecheck 통과. 공용 브라우저 실측 — [상단] 시점 0°(바늘이 북쪽=화면 위),
[사시도] 41.6°, 캔버스 220px 드래그 시 218.6° 로 카메라와 함께 회전.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
이 토글은 LAS 카드의 필수 여부를 바꾸는데(isSlotRequired) change 핸들러가
updateUploadButton() 을 부르지 않아, 파일을 먼저 고르고 토글을 나중에 켜면 필수 조건이
채워졌는데도 [파일 업로드] 가 잠긴 채 남았다. 새로고침하거나 파일을 하나 더 골라야
풀렸다.

검증: 공용 브라우저에서 저장된 토글 표시를 지워 첫 진입 상태로 재현 — 파일 7개만 고른
상태는 비활성(안내: LAS/LAZ 필요), 토글을 켠 직후 즉시 활성, 다시 끄면 즉시 비활성.
typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
관 하단 자리는 벽 계류측 변과 원지반의 교점인데, 원지반이 벽 상단보다 높은 자리에서는
교점이 벽 상단으로 밀려 관이 벽 위에 얹혔다(측벽과 배관이 만나지 않음). ㄴ·ㄷ형은 관이
바닥판 윗면에서 시작해 벽 안에 물리는 것과 대비된다.

교점을 벽 상단에서 관경+여유(0.5m)만큼 아래로 제한한다. 원지반이 그보다 낮으면 종전대로
교점을 그대로 쓴다. 벽을 키우는 방향은 벽이 1:0.3으로 기울어 base가 계류측으로 밀리며
지반 교점이 함께 올라가 벽이 7.5m까지 자라 폐기했다.

검증 — 공용 브라우저 B06 I형 8개 단면 실측: 관 유입측 끝단과 벽의 세로 겹침
18.1~56.4px(수정 전 0 — 벽 위로 이탈). ㄴ형 대조(13+4.1을 조정창에서 ㄴ형으로 바꿔 확인)
겹침 유지, 확인 후 세션값 원복. pytest 370 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
단일 링 자료형이 곧 중첩·빈공간이었다. 아래 유역이 위 유역을 감싸면 구멍이 사라져 위
유역을 통째로 덮고(합성 실측 256㎡ 전량), 한 관의 유역이 두 조각이면 작은 쪽이 사라져
빈공간이 됐다(144㎡).

- `polygon_parts()` 신설 — 조각마다 [외곽 링, 구멍 링...], 넓은 조각부터.
- `WatershedBasin.boundary_parts` 로 교체. `boundary_xy`(가장 넓은 조각의 외곽)와
  `boundary_rings`(편 링 목록)는 파생 속성이라 옛 소비처는 그대로 동작한다.
- API 에 `polygon_rings_lonlat` 추가. 저장 GeoJSON 은 구멍을 가진 Polygon, 조각이
  여럿이면 MultiPolygon.
- 캔버스 4곳(B04 유역화면 채움·선택, B05 배수유역도 채움·선택)은 even-odd 로 한 번에
  채우고 `pointInRings()` 로 판정 — 구멍 안을 눌러도 바깥 유역이 잡히지 않는다.
  중복이던 지역 `pointInRing` 은 삭제하고 공용 것으로 통일.

검증: 단위 5건 신규(도넛 구멍 보존·조각 2개 보존·파생 속성·빈 경계·조립 경로 전체에서
링 2개), 전체 168 passed, typecheck 통과. 브라우저 — API 가 유역 22개에 링 목록을 실어
보내고, 캔버스 even-odd 실측(가운데 알파 0 / 고리 255)으로 구멍이 실제로 뚫린다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
100㎡ 미만 유역은 `polygonize_labels` 의 최소면적 필터에 걸려 폴리곤이 아예 만들어지지
않았다. 유역 목록에는 있는데 지도에는 없는 상태 — 실측에서 용화 22개 중 1개(64㎡),
S자 48개 중 1개가 그랬다. 링 목록이 조각을 싣게 된 뒤로는 버릴 이유가 없다.

실측: 폴리곤 면적 오차(셀 면적 대비 평균) 용화 5.76%→1.86%, S자 3.56%→1.42%,
경계 없는 유역 1개→0개. 좌표점은 583→622 · 806→829 로 거의 그대로다.
1차 전체 배수유역 등 다른 호출부의 기본값(100㎡)은 그대로 둔다.

S자 실사례 검증: 용화 지형 위에 스위치백 3구간 합성 노선(정점 439·연장 4,528m)으로
신규 프로젝트를 만들어 자동 체인까지 완주 — 관 48개·세부유역 48개, 경계 없는 유역 0개.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 폴백 사다리가 네 곳에 서로 다른 모양으로 흩어져 있었고, 그중 배수유역 라우터
`_route_center_lonlat` 은 노선 CSV 의 `crs_epsg` **라벨**을 그대로 변환에 썼다(라벨과
실좌표계가 다른 사례 실측 — 2026-09-01 용화 라벨 5179 / 실제 5176).

`common_util_crs.resolve_project_crs()` 신설 — 사다리는 ① 노선 crs_input ② 파일 라벨
(원본 좌표를 읽는 자리만) ③ 지형 PRJ(작업 좌표계 정본) ④ DB epsg ⑤ EPSG:5186.
작업 좌표계는 **지형 PRJ 우선으로 확정**(2026-09-03 사용자 결정 — 서피스 격자가 모델좌표의
주인이라 현행 유지). `project_epsg_from_prj()` 도 이 창구로 위임.

더해 지표면 트림이 노선을 통째로 지울 때 노선·지표면 bbox 를 함께 로그에 남긴다 —
"겹치지 않습니다" 만으로는 좌표계 문제인지 측량 범위 문제인지 갈리지 않았다.

검증 — `tmp/tests/test_project_crs_resolution.py` 5건 신설(사다리 4·진단 1),
전체 375 passed·17 skipped, ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
노견 → 벽 상단 접근선 구간이 패치에서 빠져 있어 좁은 좌측 패치 사이로 원지반이 드러나
보였다(2026-09-03 사용자 확정: 「패치로 덮기」). 접근선은 벽보다 위라 덮어도 관 구멍·L자
통로를 막지 않는다 — 벽 전면·유로는 종전대로 리본에 담지 않는다(2026-08-25 사용자 ②).

접근선 줄을 `patchPoints` 앞에 담고 `fillRuns` 에 한 장으로 실어 「구간 1줄 = 리본 1장」
규칙을 그대로 따른다.

검증 — typecheck·prettier 통과. 3D 육안 확인은 카메라 조작이 필요해 다음 화면 검증
묶음에서 함께 수행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
축척 — 노선 연장에 맞춰 **한 장에 들어가는 가장 큰 그림**을 고른다(2026-09-03 사용자 결정).
후보는 도면 관행 축척(1:500~1:6,000, `DRAWING_SCALE_MASSHAUL_H_CANDIDATES`)이고 A1 작도영역
가용 폭 700mm 를 기준으로 판정한다. 실측 — 40m 노선 1:500 · 용화 1,106m 1:2,000 ·
3,465m 1:5,000. 세로는 종이 1mm=50㎥ 고정(도면끼리 비교하려면 같아야 한다).

표기 8행(사용자 확정) — ① 장비명 무대→종무대 ② 값 표기 `Q= 162.41M3`(등호 뒤 한 칸)
③ 지시선 계단형·balloon 모서리 접점 ④ 평형선·띠 경계현 빨강 ⑤ 측점 `120+ 0.0`
⑥ 표 눈금 신설(정규 빨강·추가 회색) ⑦ 행 이름 3.2mm·자간 벌림 ⑧ M.N 소수 2자리 `0+16.90`.

`MM_H` 상수를 없애고 `mm_h` 를 그리기 함수에 넘긴다 — 축척이 노선마다 달라졌기 때문.

검증 — `tmp/tests/test_b07_masshaul_basin.py` 갱신·신설(축척 3건·표기 8행·지시선·눈금),
전체 378 passed·17 skipped, ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
해칭 — 수확기가 `g[clip-path]` 를 통째로 건너뛰어 기슭막이 형태 해칭(돌쌓기·콘크리트·
돌망태·통나무·바자)이 CAD 도면에 하나도 실리지 않았다. 클립을 쓰는 대신 **경계로 잘라서**
싣는다(2026-09-03 사용자 결정). 선분–폴리곤 교차로 안쪽 조각만 남기고, 클립 안 원(통나무
마구리)은 36각 폴리선으로 펴서 같은 방식으로 자른다. 문자는 중심점이 안일 때만 싣는다.

서명 — SVG 로 올라온 자산만 CAD 폴리선으로 바꾼다(2026-09-03 사용자 결정). DXF 로 나가도
선으로 남고 확대해도 깨지지 않는다. `B07_DesignDetail_Engine_Cad_Svg` 신설(path M·L·H·V·
C·Q·S·T·Z 지원, 곡선은 16분할, viewBox 비율 유지·y 뒤집기). PNG·JPG 는 그릴 선이 없으므로
종전대로 ImageEntity, 읽기 실패도 원래 그림을 그대로 둔다.

검증 — `tmp/tests/test_b07_signature_vector.py` 5건 신설(파싱·비율·엔티티 교체·래스터 유지·
손상 SVG), 전체 383 passed·17 skipped. typecheck·prettier·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`_UI_Section_View` 751줄 → 689줄. 곡선 계산 → 차트 → 범례 → 요약줄까지 한 덩어리를
`_UI_Section_View_MassHaul` 로 옮기고, 뷰 컨트롤러는 **붙일 자리**만 정한다(차트는 종단면도와
같은 부모의 형제, 범례는 스크롤 컨테이너 밖). 낡음 판정·계산은 옮긴 자리에서도 공용 모듈
그대로라 동작이 바뀌지 않는다.

검증 — 공용 브라우저 B06 실측: 요약줄 문자열 동일
(`절토(자연) 4,526.8㎥ … 최종 누가토량 −10,213.3㎥`), 범례 1·차트 1·카드 65·상태줄 빈 문자열.
pytest 383 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`_UI_Cross_View` 784줄 → 698줄. 도면과 무관한 제목행·하단 정보행을 `_UI_Cross_Card_Chrome`
으로 옮기고, 실효 표시 반폭 계산은 순수 계산이라 `_UI_Cross_View_Metrics` 로, 측점별 줌·팬
상태 맵은 임자인 `_UI_Cross_View_Zoom` 으로 옮겼다. 계산·판정 규칙은 그대로다.

검증 — 공용 브라우저 B06 실측: 카드 65·제목행 65·하단행 65·단면유형 pill 65·사면 미교차
경고 13, 첫 카드 제목행 `0+0.0 / 0.0m / 토사·리핑암·발파암 / 편측 성토 / BP` 로 종전과 동일.
pytest 383 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
장(여러 측점을 담은 횡단 도면)에는 측점 단위 지반·계획 값이 없는데도 제목이
「측점 3장 (220~264m)」으로 달려 어느 측점 값인지 오해됐다. 장이면 제목을 「장」으로 바꾸고
「이 장은 측점 여러 개를 담습니다. 지반·계획 정보는 측점 도면에서 봅니다」로 안내한다.

판정은 도면 id(`cross_s…` = 장) 로 한다 — `chainage_m` 은 장에도 첫 측점 값이 실려 와
그것으로는 갈리지 않는다(실측).

검증 — 공용 브라우저 B07: 3장(220~264m) 선택 시 `장 3장 (220~264m) · 잠정 · 이 장은 측점
여러 개를 담습니다…`, 종단도 선택 시 패널 없음(종전과 같음). typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`_UI_Structures_Panel` 1,078줄 → 1,024줄. 화면 요소를 세우는 몫만 `_UI_Structures_Form`
으로 옮기고 패널은 값·검증·저장·목록을 맡는다. 배치 규칙(행 순서·구분선·버튼 묶음)은
사용자 지시로 굳은 것이라 그대로 옮겼다.

아직 제한을 넘는다 — 남은 큰 덩어리는 `commit()` 약 200줄과 옵션 필드 렌더·시설 폼
로드 약 170줄이다. 둘 다 폼 상태를 깊게 만지므로 [추가]·[삭제] 실동작 검증을 붙여
따로 옮긴다.

검증 — 공용 브라우저 B05 「구조물 배치」 실측: 제목·측점 행·메모 칸·목록 1개,
버튼 [추가]·[삭제]·[리셋], 구조물군 7항목 그대로. pytest 383 passed·17 skipped,
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
유역 격자가 1m(DRAINAGE_GRID_SIZE_M)라 경계는 1m 계단이다. 허용오차를 격자 한 칸에
맞추면 형상 손실이 격자 오차 안으로 들어가고, 유역별로 따로 단순화해 생기던 공유 경계
어긋남도 줄어든다.

실측(min_area=0 상태, 용화/S자):
- 좌표점        622·829   → 1,749·1,987
- 면적오차      1.86%·1.42% → 1.01%·0.67%
- 유역끼리 중첩 1,043㎡·1,373㎡ → 243㎡·373㎡
- 틈            1,184㎡·2,579㎡ → 369㎡·668㎡
0.5m 이하는 1m 계단 점을 지우지 못해 좌표점만 6배(10,215)로 튄다.

브라우저 실측도 같은 값(API 좌표점 1,750·1,987, 경계 없는 유역 0개)이고 확대해도 계단이
도드라지지 않는다. 테스트 159 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
토적도만 납품 표기(`120+ 0.0`)로 바꿔 두어 유역도 정보표는 `No.6` 으로 남아 있었다
(2026-09-03 사용자 지시로 통일). `station_plus_label()` 을 토적도 전용 모듈에서 공용
`_Engine_Cad` 로 올려 두 도면이 같은 함수를 쓴다. 종단도 표·횡단도 제목의 `No.n` 표기는
그대로 둔다 — 이번 지시 범위가 아니다.

검증 — 유역도 정보표 첫 줄 `(1) No.6` → `(1) 6+ 0.0`. pytest 383 passed·17 skipped,
ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
장 단위 확정 흐름을 실측하다 드러난 것들이다(2026-09-03, 용화 검증본 3장).

① **측점 구분 없이 역추출** — `_table_values_from_cells()` 가 도면의 표를 전부 훑어
   마지막 값을 모든 측점에 넣었다(실측: 4개 측점 전부 지반고 837.21, 도면에는
   840.87·840.33·836.45·837.21 로 제대로 그려져 있었음). 표 엔티티 id 가
   `uuid5("{도면id}:qtable")` 이라 측점을 되짚을 수 있어 그 표만 읽는다. 옛 도면은
   id 가 안 맞으므로 종전처럼 전부 훑는 폴백을 남긴다.

② **계획고가 빈 채로 나감** — 장 배치 입력의 원본에는 계획고가 없어 계획고·절토고·성토고
   세 칸이 통째로 비었다(21개 항목 중 지반고 하나만 채워짐). `_quantity_table()` 이
   횡단 설계(`design.design_elevation_m`)도 보게 했다.

③ **확정 해제가 404** — [수정]이 도면 목록을 **설계값 없이** 만들어 장 나눔이 달라졌고,
   방금 확정한 장 id 가 목록에 없어 되돌릴 수 없었다. 목록 조회·확정과 같은 인자를 쓴다.

검증(공용 브라우저·실동작) — 확정 해제 404 → **200**, 표 값 `planned=840.87 fill=0.00` 등
측점마다 다름, manifest 수량표가 측점별로 갈림(220 · 240 · 260 · 264 · 280 각각 4/21 항목
채움 — 나머지 17칸은 사용자가 CAD 에서 채우는 자리). 시험 뒤 확정은 모두 해제해 원상복구.
pytest 383 passed·17 skipped, ruff format 무변경.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`3651ad98` 의 `only_explicit_curves=True` 로 전체 측점 폴리라인에서 자동 종단곡선이
전부 꺼져, B05 종단 그래프의 계획선이 직선만으로 그려졌음.

- `design_ground_following_profile()` — 변화점마다 기본 L(15m) 종단곡선을 다시 삽입.
  대칭 종단곡선은 꼭짓점을 지나지 않으므로(중앙종거 |A|·L/8), 호와 측점 세로선의 교점이
  지반고가 되도록 꼭짓점 표고를 최대 12회 반복 보정 — `design_pipe_anchored_profile` 과
  같은 방식. 결과: 호의 중심이 측점 세로선 위, 좌우 직선과 접선, 계획고 = 지반고.
- `rebuild_alignment_profile()` — `GROUND_POLYLINE_BASIS` 곡선 생략 예외 제거.
  저장된 `base_pvi` 가 보정된 꼭짓점이라 편집 델타를 지우면 초기선으로 그대로 복귀함.
- 프론트는 payload `only_explicit_curves` 를 그대로 따르므로 코드 변경 없음.
- 호 크기 기준은 현행 유지(2026-09-03 사용자 결정) — L 고정·R 은 결과값, 법정 최소반경
  미만은 경고만.

검증: `tmp/tests/test_b05_ground_profile_curves.py` 4건 + 전체 173건 통과. route 127
실데이터 오프라인 산출에서 호 126개(저장분 0개), 측점 계획고−지반고 최대 0.063mm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(B06): 횡단 카드 제목행에 성토사면 본래 경사길이 표기

사면 미교차 경고가 붙는 제목행 우측 끝에 성토사면 경사길이를 표기함.
값은 정본 설계선(`design_line`) 기준이라 기슭막이·집수정이 사면을 끊기 전
**본래 길이**이고, 양측 성토는 좌·우 두 값을 다 냄.

- `fillSlopeLengths()` 신설 — 기존 `protectedSpan`·`meetOffset` 재사용,
  성토측만 노견 끝(측구가 있으면 측구 바깥)에서 사면 끝까지 `run × √(1+1/n²)`.
- 미교차 측점은 `≥` 하한값 — 추세 외삽은 지반이 사면과 나란한 자리에서
  수십 m 씩 튀어(740m 측점 101.53m) 길이 표기에 못 씀.
- `meetOffset` 교차점을 두 걸음 사이 선형보간으로 냄 — 반폭 맞춤(1m 올림)에는
  영향이 없고 길이 표기가 탐색 간격만큼 튀는 것만 막음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@
관종·관경(`파형강관 D1200`) 대신 표시 이름 `배수관` 하나만 적음 —
2026-08-17 확정한 `PIPE_DISPLAY_NAME` 규칙과 같은 표기. 관종·관경은 툴팁에 남김.
판정은 `PIPE_TYPES` 목록으로 하고 저장 라벨은 손대지 않음 — 재진입 이관이
라벨 문자열로 구조물 종류를 되짚기 때문임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
관종·관경(`파형강관 D1200`) 대신 `배수관` 을 적음 — 횡단 카드와 같은 규칙.
판정을 `structureDisplayName()`(`_UI_Section_Common`) 한 곳으로 모아 두 렌더러가
같은 문자열을 쓰게 함. 저장 라벨은 그대로 — 재진입 이관이 라벨로 종류를 되짚음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 조작 중 계산은 브라우저 안에서 끝나야 함(2026-09-03 사용자 확정). 계획선을
만질 때마다 전 측점 횡단 계산이 서버로 나가 조작 속도를 왕복이 지배했음.

- `common_util_cross_design_areas.ts` — `B06_Section_Engine_Areas.py` 미러
  (사다리꼴 적분 + 절토 토사/암반 분리).
- `common_util_cross_design.ts` — `B06_Section_Engine_Design.py` 미러
  (표준횡단 설계선 구성 + 단면적). config 수치는 복제하지 않고
  `sections/context.standard_cross_section` 을 입력으로 받음.

두 파일 머리에 짝 파일·회귀 테스트를 가리키는 경고 블록을 둠 — 한쪽만 고치면 두 화면
값이 갈림. 아직 어느 화면도 이 모듈을 부르지 않음(다음 커밋에서 연결).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
옛 콤파스는 방위각(`atan2(ox, oz)`)만 써서 경사에 따른 남북 압축이 빠졌음 —
사시도 프리셋(오프셋 120·95·135, 앙각 27.7°)에서 바늘 41.6°, 화면 실제 북쪽 62.4°로
20.8° 어긋났음(2026-09-03 사용자 지적).

세계 축 N(−z)·E(+x)·Z(+y)를 카메라 화면 기저(오른쪽 r, 위 u)에 투영해 선과 글자를
그림. 기저는 카메라 오프셋만으로 구함(up = +y 고정). 뒤로 누운 축(깊이 > 0.25)과
정면으로 와 짧아진 축은 흐리게 그려 겹침을 줄임.

검증: typecheck 통과. 기본 시점에서 DOM 좌표가 해석값과 일치 —
N (28.0, 11.0) · E (45.0, 28.0) · Z (28.0, 27.4). 회전 중 거동은 사용자 화면 검증 대기.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 조작 중의 계산은 브라우저 안에서 끝나야 함(2026-09-03 사용자 확정). 계획고가
바뀔 때마다 전 측점 횡단 계산이 `POST …/cross-design/preview` 로 나가 왕복이 조작
속도를 지배했음.

- `refreshCrossDesigns` 를 로컬 계산으로 교체. 계획고는 저장 선형(`base_pvi`)에 편집
  델타를 얹어 TS `buildAlignment` 로 여기서 풂 — 호출부(B05·B06) 시그니처는 그대로라
  단일 창구가 유지됨. 서버 프리뷰는 선형 저장분이 없는 옛 데이터 폴백으로만 남음.
- 표준단면 config 기본값·암 경계 기본 오프셋을 `sections/context` 응답에서 세션에 기억
  (`rememberStandardDefaults`·`rememberRockBoundaryDefault`). 프론트에 config 수치를
  복제하지 않으면서 패널 없는 B05 도 같은 값으로 계산함.
- 디바운스 250 → 60ms — 왕복이 사라져 손을 떼는 즉시 유토곡선이 따라옴.
- 낡음 판정을 `hasStaleDesigns` 로 바꿔 첫 건에서 중단하고, 계획선 유효 샘플을
  샘플 배열당 한 번만 걸러 이진탐색(그리기 프레임당 2.33ms → 0.07ms 실측).
- 파이썬 엔진 2파일·프리뷰 라우터에 「TS 짝 파일과 한 벌」 경고 블록 추가.

검증: `tmp/tests/test_b06_cross_design_mirror.py` 10건 — 토사/암 2단계/L형 측구/포장/
세월교 하강/사면 미닫힘 등에서 파이썬과 TS 결과가 면적·설계선까지 일치. 전체 183건 통과.
`tsc --noEmit` 통과. 실측: route 127(측점 128) 전 측점 로컬 재계산 7.5ms.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
시안 3종 비교 뒤 사용자 선택(2026-09-03) — TerriaJS·cesium-navigation 계열 표기.
링·눈금·도북 화살을 지면 평면 도형으로 두고 카메라에 투영하므로, 링이 눌린 정도가
곧 시점 기울기이고 도북은 늘 화면의 실제 북쪽을 가리킴.

- 15° 눈금(90°마다 긴 눈금), N·E·S·W 라벨(뒤로 넘어가면 흐림).
- 표고축 침은 내려다볼수록 짧아지고, 점으로 눌리면 Z 라벨을 감춤.
- 위젯 56 → 84px — 라벨이 읽히는 최소 크기.

검증: typecheck·prettier 통과. 리로드 실측 — 위젯 84×84, 링 경로 `M0.00 −33.98…`,
도북 화살 `M0.00 −33.30 L−4.28 −17.14 L4.28 −17.14Z` 로 기본 시점 계산값과 일치.
회전 중 거동은 사용자 화면 검증 대기.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
낡음 판정이 **편집 전 계획선**과 견주고 있었음. 로컬 재계산은 편집된 계획고로 횡단
설계를 갱신하는데 비교 대상은 저장분이라, 편집이 있는 동안 판정이 영원히 참으로 남아
유토곡선이 빈 화면에 문구만 남았음(사용자 보고).

- 그리기(`_Profile_Render`)와 진입 판정(`_Profile_Panel.render`) 모두 편집이 반영된
  계획선(`toDesignProfile(alignment, …)`)과 견주도록 바꿈. 특히 진입 판정은 세션에
  미저장 편집이 남은 채 새로고침하면 「어긋남 없음」으로 나와 재계산을 예약조차 하지
  않았음 — 그래서 새로고침해도 문구가 그대로였음.
- 세월교 측점은 노면이 월류 높이만큼 일부러 내려 앉으므로, 판정에서 `surface_drop_m`
  을 더해 비교. 안 그러면 계획선을 안 건드려도 늘 어긋난 것으로 나옴.

화면 검증(공용 브라우저 5174, route 132): [초기화] 직후 문구 없음·유토곡선 정상
(절토 1,113.5㎥ / 성토 1,424.1㎥). 계획고 ▲ 1클릭 시 문구 없이 즉시 갱신
(절토 1,108.3㎥ / 성토 1,428.6㎥), ↶ 로 되돌리면 원값 복귀. 임시 진단 코드는 제거함.
전체 테스트 183건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05 3D 뷰어에는 방위 표시가 없어 방향을 읽을 수 없었음(사용자 지적, 메인 창 경유).
B04 가 오늘 새로 만든 「지면에 누운 나침반 링」을 그대로 쓰되, 두 페이지가 함께 쓰도록
공용으로 옮김.

- `B04_PreProcess_UI_Compass.ts` → `ui_template/ui_template_compass.ts` (git mv).
  `createTerrainCompass({ sizePx, className })` 로 크기·자리를 호출부가 정함.
- 스타일도 `ui_template/ui_template_compass.css` 로 옮기고 모듈이 직접 물고 옴.
  **놓을 자리만** 페이지 CSS 몫 — B04 우하단(`b04-surface__compass`),
  B05 는 ISO 버튼 아래(`b05-route__compass`).
- B05 뷰어는 104px 로 쓰고 렌더 루프에서 카메라 오프셋으로 갱신, 지형이 없으면 감춤.
  좌표 규약이 B04 와 같음(북 −z · 동 +x · 표고 +y, `Viewer.ts:295` 정점 변환) — 그대로 맞음.

화면 검증(5174): B05 나침반 104×104, ISO 버튼 아래 8px. 도북 화살이 뷰 전환에 반응 —
TOP 에서 `M0.00 -33.30`(수직), ISO 에서 `M23.56 -13.60`. 후자는 카메라 오프셋 (d,d,d)
에 대한 투영 이론값(x=R/√2=23.56, y=−R/√6=−13.60)과 일치. B04 쪽도 그대로(84×84,
우하단 16px, 링·화살 색 토큰 유지). `tsc --noEmit` 통과, 뷰어 693줄로 제한 안.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 구조물 측점이 두 좌표로 존재했음 — 종단 정본은 원값(`85.594514`), 사이드바 목록은
표기 규칙(`n+ 0.0`)대로 0.1m 로 반올림한 값(`85.6`). 중복 제거가 누가거리 키(소수 3자리)
비교라 서로 다른 측점으로 잡혀 버튼이 두 벌 섰음.

문제는 표시만이 아니었음 — 사이드바 쪽 버튼을 누르면 정본 측점에서 몇 mm 떨어진 자리에
**가짜 변화점**이 승격돼 그 구간 기울기가 수천 %로 튀었음(실측 11,858%).

겹침 판정을 키 비교에서 **거리 비교**(0.1m 이내면 같은 측점)로 바꿈. 사이드바 목록이
0.1m 반올림이라 최대 0.05m 어긋나고, 실제로 그만큼 붙은 별개 측점은 없음.

실측(route 132, 관 11개): ▲ 버튼 75 → 65개, 근접 중복쌍 9건 → 0건.
전체 테스트 183건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지적(2026-09-03) — 선택 항목이 너무 크고 대중없이 놓임. 안내는 B04·B05 와 같은
공용 좌측 패널로 빼고 본문은 고르는 자리만 남김.

- `B03_FileInput_UI_Guide.ts` 신설 — 필요한 파일 / 고르는 방법 / 알아 둘 것 3묶음을
  공용 오버레이 `optionsContent` 에 실음. 문단 구획은 공용 `ui-sidebar-section`.
- 선택 영역 160px 블록 → 한 줄 바. 긴 문구는 패널로 옮기고 힌트는 한 줄로 교체.
- 카드 `min-height: 220px` 폐지, [선택]을 제목 줄 오른쪽 끝 작은 버튼으로 이동,
  빈 칸은 제목 줄만 남김. 진행바·속도·예상완료는 올라가는 동안만 표시.
- 여백 정리 — 컨테이너 패딩 32 → 20, 그룹 제목 24 → 16px, 격자 간격 24 → 12.
- 좌측 패널이 열리면 본문을 밀어내는 규칙 추가 — B03 은 일반 레이아웃이라 공용
  워크플로 레이아웃의 padding 규칙이 없어 패널이 카드를 덮었음.

검증: 카드 높이 232 → 66px(빈 칸)·117px(파일 있음), 선택 영역 160 → 47px,
문서 높이 1408px 로 한 화면 남짓. typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지적 3건.

1. 상단 표시줄의 「절·성토 불균형」은 **종단 기준** 값이었음 — 계획선과 지반선 사이 세로
   면적(㎡)의 비라 실제 토량이 아니고 판단 근거가 안 됨. 삭제함. 의미 있는 균형은 횡단
   단면적을 쌓아 부피(㎥)로 내는 하단 유토곡선 요약이고 그쪽은 그대로 둠.

2. 계획고를 연속으로 누르면 유토곡선이 매번 사라졌다 다시 서서 깜빡였음. 재계산 대기
   중에 곡선을 **지우지 않고 직전 것을 그대로 두며**, 요약줄 끝에 「다시 계산 중…」
   칩만 붙임. 재계산이 브라우저 안에서 수십 ms에 끝나므로 화면이 비는 구간이 없어짐.
   아직 한 번도 못 그렸을 때만 예전처럼 문구로 자리를 채움.

3. [쉬프트]에서 아무것도 안 골라지던 것은 **직선화된 구간이 없어서**였음(초기 계획선은
   마디마다 기울기가 달라 직선 구간이 0개). 안내를 갈라 적음 —
   「직선화된 구간이 없습니다 — [직선화]로 먼저 만드세요」 / 「…고르세요 (여러 개 가능)
   — 끝내려면 [쉬프트]를 다시 누르세요」. 직선화 안내에도 취소 방법을 덧붙임.

전체 테스트 183건 통과, `tsc --noEmit` 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`padding: var(--spacing-20)` 은 정의되지 않은 토큰이라 선언째 무효가 되어 카드
컨테이너의 패딩이 통째로 사라졌음(2026-09-03 사용자 보고). 16px 토큰으로 교체.

검증: 실측 계산값 — 컨테이너 16px, 카드 12/16px, 선택 바 12/16px, 안내 문단 12px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시 3건(2026-09-03).

- 재접속 현황 배너(「…모두 완료된 프로젝트입니다」)를 좌측 안내 패널 「고르는 방법」
  안으로 옮김 — 고르기 전에 읽을 것과 같은 자리.
- [입력 파일 선택]·[임시 보관함에서 불러오기]·[파일 업로드]를 한 줄(`b03-file__pick-row`)로
  묶음. 좁아지면 접히되 선택 영역이 남는 폭을 먹음.
- 업로드 완료 항목 목록 삭제 — 같은 내용을 카드가 완료 상태로 이미 보여 줌.
  쓰이지 않게 된 `renderUploadResults`와 `.b03-file__results` 규칙도 제거.

곁들여 고친 것 — 카드 격자를 2열 고정에서 `auto-fill minmax(260px, 1fr)` 로 바꿈.
안내 패널을 연 상태에서 카드 폭이 210px 로 눌려 제목이 글자 단위로 접혔음(실측).
제목은 한 줄 말줄임으로 둠.

검증: 한 줄 배치 실측 — 선택 397px · 보관함 331px · 업로드 102px, 높이 76px 로 정렬.
카드 66px(빈 칸)/117px(파일 있음), 제목 줄 높이 21px(한 줄). typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1. [초기화] — [↶] 왼쪽에 둠. 전체 초기화가 아니라 **마지막 [저장] 시점**이 기준점임
   (사용자 지시). 편집 스토어가 저장 시점 편집분(`savedBaseline`)을 들고 있다가 그리로
   되돌림 — 저장한 작업은 남고 그 뒤 편집만 버림. 이력에 기록해 [↶]로 되살릴 수 있음.
   되돌릴 것이 없으면 버튼은 비활성.
   자동 선형까지 지우는 `resetAll`(좌측 [초기화])과는 다른 조작임.

2. [쉬프트]로 고른 직선이 화면에 표시되지 않아 무엇이 잡혔는지 알 수 없었음. 고른 구간을
   빨갛게 덧그림 — 범위는 **직선 + 양 끝 라운드(R)** 임. 쉬프트는 직선을 통째로 올리고
   내리므로 양 끝 호의 모양까지 함께 바뀜. 구간 시작 라운드의 BVC부터 끝 라운드의 EVC
   까지 계획선 샘플을 그대로 덧그려 곡률이 따라옴. 경계에는 점선 세로 표식.

   공용 종단 렌더러(`B06_Section_UI_Longitudinal`)는 건드리지 않고 별도 오버레이로 얹음
   (`B05_Profile_UI_Profile_RunHighlight.ts`). Y 매핑은 그 렌더러가 넘겨 주는 축 눈금에서
   되짚어 같은 스케일을 씀. 편집 버튼층(z-index 4) 아래(3)라 버튼을 가리지 않음.

`tsc --noEmit` 통과, 전체 테스트 183건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
처음엔 B03 전용 스타일로 문단을 만들었으나, 좌측 패널 양식은 다른 단계와 같아야 한다는
사용자 지시(2026-09-03). 공용 조립으로 교체함.

- 패널 루트 `b03-file__form`, 문단은 `ui-collapsible ui-sidebar-section`,
  제목은 `ui-collapsible__title` — 외곽선·캐럿·접힘 동작이 전부 공용 CSS·동작이다.
- 값도 `b04-surface__form`·`__group`·`__group-legend` 와 같게 맞춤
  (gap·padding 16, 배경 `--color-surface-raised`, legend `--text-caption`).

검증: 실측 — 문단 클래스 `b03-file__guide-group ui-collapsible ui-sidebar-section`,
패딩 16px, 배경 `rgb(37,31,56)`, 제목 클릭 시 `is-collapsed` 토글·복귀 확인.
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시 2건(2026-09-03).

- 임시 보관함 선택 요약(「선택된 보관 자료 없음」·묶음 이름·파일 수)을 없앰. 불러온 자료는
  카드가 곧바로 보여 주고, 고르기 전 상태는 [파일 업로드]가 잠긴 것으로 이미 드러남.
  쓰이지 않게 된 `.b03-file__temp-summary` 규칙과 로케일 2건도 함께 제거.
- 입력 컨테이너의 「업로드할 파일을 선택하세요」 경고를 띄우지 않음 — 아직 아무것도 고르지
  않은 상태를 붉은 글씨로 알릴 이유가 없음. 확장자·개수·필수 슬롯 같은 나머지 사유와
  [파일 업로드]를 눌렀을 때의 검사 결과는 그대로 표시.

검증: 실측 — 보관함 자리에 버튼 하나만 남음(요약 span 없음), 오류 줄 빈 문자열,
한 줄 배치 선택 518px · 보관함 210px · 업로드 102px. typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
두 곳이 같은 뿌리였음. 브라우저 재계산은 **편집이 반영된 계획고**로 횡단 설계를 만드는데
`design_profiles` 는 저장분 그대로라 두 값의 기준이 갈렸음.

1. 재계산 창구가 방금 푼 계획선을 **공유 캐시에도 얹도록** 함
   (`detail.longitudinal.design_profiles`). 이게 없으면 낡음 판정이 영원히 참이 되어
   B06 유토곡선이 통째로 빈 채로 남았음(사용자 보고). `profile_alignment`(base_pvi)는
   건드리지 않음 — 편집 델타의 기준선이라 편집분을 구워 넣으면 이중 적용됨.

2. B06 진입 정합이 **미저장 세션 편집을 못 보고 건너뛰던** 것. 서버에서 갓 받은 저장분
   끼리는 늘 일치해 「낡지 않음」이 되는데, B05가 세션에 남긴 편집은 그 안에 없음.
   세션 초안이 있으면 판정을 건너뛰고 무조건 맞추도록 함 — 재계산은 브라우저 안에서
   끝나 값이 쌈.

화면 검증(5174, 같은 시점 비교):
  수정 전 — B05 절토 4,774.1㎥ / 성토 16,715.5㎥, B06 절토 4,515.0㎥ / 성토 14,857.5㎥
  수정 후 — 양쪽 모두 절토 4,774.1㎥ / 성토 16,690.7㎥ (일치)
B06 유토곡선 영역도 곡선이 다시 그려짐(문구 없음).

전체 테스트 183건 통과, `tsc --noEmit` 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-03).

- 토글을 지형 컨테이너에서 **파일 입력 컨테이너**로 옮김 — 무엇을 받을지 정하는
  스위치라 고르는 자리 옆에 선다. 서식도 입혔음(공용 체크 줄 + 켜짐 강조).
- 켜면 지형 자료를 **통째로** 받지 않음: 포인트클라우드·좌표계·래스터 카드를 모두 잠그고
  컨테이너를 흐림. 필수 판정에서도 지형 슬롯 전체가 빠진다.
- 파일 거르기를 확장자가 아니라 **배정된 카드** 기준으로 바꿈 — `.prj` 는 노선·지형이 같은
  확장자라 확장자로 거르면 노선 좌표계까지 함께 떨어졌다.
- 이미 올라간 자료(재입력)는 지우지 않고 **조작만 잠금** — 로컬로 고른 파일만 내린다.

좌측 안내 패널의 글자 크기도 공용 양식에 맞춤 — 본문 `--text-body-sm`·`--color-text-body`
(B04 `b04-surface__check` 와 같음), 제목 `--text-caption`.

검증: 실측 — 토글이 입력 컨테이너 안에 있고, 켜면 지형 카드 4장이 모두 disabled +
[파일 선택] 잠김, 기존 업로드분은 「완료」·파일명 유지. 끄면 원복. 패널 글자 14px/12px.
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
세션에 저장하는 쪽(`createRockBoundaryStore`)은 키를 `toFixed(2)` 로 쓰는데 브라우저
재계산은 `toFixed(3)` 문자열로 찾아 **한 건도 못 읽었음**. 서버 경로는 키를 숫자로
바꿔 비교해 문제가 없었으므로 로컬 계산으로 옮기며 생긴 어긋남임.

키를 숫자로 되돌려 0.01m 단위로 맞춤. B06 에서 암 경계선을 올리내린 값이 이제 B05
유토곡선·횡단 면적에도 그대로 반영됨.

화면 검증(5173→5174, 같은 시점): B05 첫 진입 절토 4,774.1㎥ / 성토 16,690.7㎥,
B06 도 같은 값(재계산 입력·결과 로그로 대조 — 측점 65, 샘플 65, 자연방토 25건까지 동일).
B06 을 거치기 전과 후의 값 차이(성토 16,715.5 → 16,690.7)도 사라져 **첫 진입부터 일치**함.
진단용 임시 로그는 제거함.

전체 테스트 183건 통과, `tsc --noEmit` 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시 4건(2026-09-03).

- 선택 영역의 설명 문구를 좌측 안내 패널로 옮기고 본문에는 「입력 파일 선택」만 남김.
- [임시 보관함에서 불러오기] → [임시 보관함]. 버튼을 감싸던 점선 테두리 삭제 —
  버튼 자신의 테두리와 이중이었음.
- 계획노선 도형 카드는 `.shp` 만 받음. CSV 는 내부 계산이 만드는 파일이라 사용자가 넣는
  자료가 아님(사용자 확인). 컨테이너의 CSV 안내 문구도 삭제.
- 이미 `.csv` 로 올라간 옛 프로젝트가 「미등록」으로 보이지 않도록 **서버 파일 매핑에만**
  `.csv → 계획노선 도형` 예외를 둠. 새로 받는 확장자와 이미 받은 것을 갈라 둔다.

좌측 안내 문구도 함께 갱신 — CSV 언급 제거, 버튼 새 이름 반영.

검증: 실측 — 선택 영역 텍스트 「입력 파일 선택」, 보관함 테두리 none·라벨 「임시 보관함」,
계획노선 안내 문구 없음, 카드 확장자 `.shp`, 옛 CSV 는 「완료 · 용화_계획노선.csv」 유지.
typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-03).

- 고르는 자리를 flex 에서 **격자 3칸**으로 바꿈. flex 로는 내용 폭이 배분에 섞여
  288·254·288 로 어긋났고 버튼 높이도 달랐다. 격자는 칸을 먼저 나누므로 1:1:1 이고,
  칸을 꽉 채우게 해 세 칸 높이가 같아진다(실측 277×47 셋 다 동일).
- 빈 오류 줄이 자리를 잡아 토글 아래가 비어 보이던 것 제거 — 글자가 있을 때만 자리를
  차지한다(`:empty { display: none }`, min-height·마진 제거).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 헤더를 잡아 끌어 자리 이동, 이동 범위는 상단 헤더 아래 화면 안으로 clamp
- 아래 공간 부족 시 `is-flip-up` 으로 헤더 위로 펼침(바닥 기준 정렬)
- 자리는 sessionStorage 세션 캐시에만 보관, 접힘/펴짐 뒤 방향 재판정
- threshold 4px 초과 시에만 포인터 캡처 — pointerdown 캡처는 click 대상을
  제목에서 헤더로 바꿔 접기/펴기 토글을 죽임(실측)
- 이동은 window 에서 청취 — B07 CAD iframe 위로 커서가 나가도 안 끊김

검증: 공용 브라우저 B03·B05·B07 실측(이동 오차 1px 이내, clamp·뒤집힘·토글 정상),
tsc --noEmit 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 계획노선 shapefile 분석에 `preview_path`(200점 안팎 솎은 좌표열) 추가 — 이미
  메모리에 있는 정점을 쓰므로 파일 재열람 0회(솎기 0.136ms)
- LAS·GeoTIFF 는 사용자 확정대로 **bbox 사각형만** (점구름·래스터 렌더 안 함)
- `upload-overview` 응답에 분석 `metadata` 동봉 — 재접속해도 같은 그림
- 카드에 SVG 미리보기 렌더(신규 `B03_FileInput_UI_Preview.ts`), 값 없으면 미표시
- 계획노선 카드는 지형 자료 범위와 대조 — 벗어나면 경고색·안내, 좌표계가 다르면
  대조 생략(재투영 안 함). shapefile 은 좌표계가 없어 같은 세트 `.prj` 값을 씀

검증: 공용 브라우저 실측(노선 선 121점·범위 안/밖·좌표계 상이 3갈래),
tmp/tests/test_b03_preview_path.py 2건, tsc --noEmit 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
어두운 테마에서 채움 35%가 회색 덩어리로 보여 범위인지 안 읽힘 — 채움 12% +
점선 테두리로 「범위」임이 드러나게 함(실측 스크린샷 확인).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 방향키 청취를 패널 루트에서 window 로 옮김 — 그래프 클릭 뒤 포커스가 body 에
  남아 방향키가 아무 반응이 없던 결함 수정 (패널이 화면에 없으면 무시)
- 길게 누르면 편집 버튼과 같은 속도로 연속 이동 (0.5초 뒤 0.1초 간격, OS 키 반복 무시)
- 이력에 pause()/resume() 추가 — 연속 이동 전체가 되돌리기 1회로 원위치.
  구조물 이동은 서버 재계산이 뒤따르므로 키를 뗀 뒤 700ms 뒤 기록
- pause() 에서도 관 목록을 세션에 흘려 되돌리기 기준을 조작 전 값으로 고정
- 좌우 연속 이동 중에는 처음 잡은 구조물 측점·자체 누가거리 카운터 사용 —
  관 측점 id 가 누가거리 기반이라 한 번 옮기면 선택이 풀려 한 칸만 움직이던 결함 수정
- ProfileTools.nudge(delta) 노출 — [쉬프트] 모드의 상·하 방향키가 도구 ▲▼ 와
  같은 경로(onShift)로 구간 평행이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- B05_Profile_UI_Profile_Zoom.ts 신규 — 배율 상태(가로 폭 배수·세로 배율·창 중심)와
  버튼 7개(+ − ⇕+ ⇕− ▲ ▼ ⤢). 자리는 요약줄 오른쪽 끝(그래프 우측 상단),
  설명은 툴팁, 클릭은 stopPropagation 으로 측점 선택에 번지지 않게 함
- X 줌은 폭 배수 — computeProfileLayout 에 zoomX 를 넘겨 측점 간격·폭맞춤 폭에 함께 곱함.
  그래프·테이블·편집 버튼층·구조물 레인이 같은 매핑을 쓰므로 넷의 x 정렬이 유지됨
- Y 는 표시 표고창(제안 A) — createLongitudinalProfile 에 elevationOffsetRatio 인자 추가,
  창 높이 = 전범위 ÷ 배율, ▲▼ 가 창 높이의 10%씩 중심 이동. 세로 스크롤 없음
- 지반선·계획선·절성토 음영을 플롯 사각형 clipPath 안으로 옮김 — 배율을 올려도
  선이 축·측점 라벨 위로 흘러나오지 않음 (B06 은 배율 1·오프셋 0 이라 표시 불변)
- 요약줄 렌더러에 trailing 자리 추가, .b05-profile__zoom* CSS 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 구조물 측점 판정을 문자열 키에서 누가거리 허용 오차 0.1m 비교로 바꿈 —
  구조물 목록(85.59)과 계획선 측점(85.595)이 셋째 자리에서 어긋나 구조물 열을
  못 알아보고 값을 그대로 펼쳐 이웃 값과 겹쳐 보였음. 이제 고른 때만 값 열 오버레이로 보임
- 대수차 1e-4% 미만이면 직선으로 보고 곡선 L·R 을 빈 칸으로 둠 — 직선화하면
  대수차가 0 이 되어 R = L ÷ |대수차| 가 수억 m 로 발산했음 (표·값 열 오버레이 공통)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
구배 L·H·S 는 값 열을 접는 규칙에서 제외 — 구조물로 좁게 갈라진 구간도 값을 적음
(2026-09-04 사용자 확정, 「각도 행」 = 구배 3행). 그 구간만 고를 때까지 값을 감추던
옛 규칙(2026-08-03)을 걷어내고, 구조물 구간 표시·하이라이트·툴팁은 유지.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05_Profile_UI_Style.css 1379줄 -> 592줄. 규칙을 값·순서 그대로 옮겨 두 조각으로 나눔.
- B05_Profile_UI_Style_Table.css (515줄) — 도면 테이블·값 열 오버레이·우클릭 메뉴·
  계획고 편집 버튼·줌 조작구
- B05_Profile_UI_Style_Drainage.css (289줄) — 배수유역도 패널
진입 TS 두 곳(B05_Profile_UI_Page.ts, A00_Common/b_structures_section.ts)에서
본체 다음에 순서대로 불러 캐스케이드 순서 유지.

검증: tsc --noEmit 통과, prettier 서식 유지, 공용 브라우저(5174)에서 계산 스타일 확인
(표 이름표 sticky 78px, 구배 블록 absolute, 편집 버튼 21x17, 줌 22x22, 배수유역 flex).
종단 패널 캡처가 분리 전과 **바이트 단위로 동일**(md5 ee6bc8b52adb).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04_PreProcess_UI_Style.css 870줄 -> 565줄. 하단 2D 지도·도구줄·시트 툴바 규칙을
B04_PreProcess_UI_Style_Map.css(312줄)로 값·순서 그대로 옮김. 진입 TS 에서 본체 다음에
불러 캐스케이드 순서 유지.

검증: 두 파일을 다시 이으면 원본과 **경계 빈 줄 1개 외 완전 동일**(텍스트 대조).
tsc --noEmit 통과. 공용 브라우저(5174) B04 화면 실측 — 좌측 폼 flex/gap 16px,
.b04-map flex column gap 12px(896x828), 헤더·컨트롤 정상, 3D 서피스·2D 지도 렌더 정상.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04_PreProcess_Router.py 718줄 -> 493줄.
- B04_PreProcess_Router_Status.py(221줄) — 분석 상태 조회·모델 프리뷰 엔드포인트.
  prefix 없이 만들고 본체가 include_router 로 실어 붙임(본체 prefix 를 그대로 상속).
- B04_PreProcess_Router_Progress.py(47줄) — progress.json 읽기·쓰기 헬퍼.
  본체와 상태 라우터가 함께 써야 해 순환 임포트를 피하려고 별도 모듈로 둠.
  본체는 write_surface_progress 를 계속 재노출(B03_FileInput_Service_WF1 이 참조).

검증: ruff check/format 통과. 라우터 경로 9개가 분리 전과 동일(중복 prefix 없음 확인).
백엔드 재시작(8001) 후 openapi 에 surface 경로 12개 그대로, 브라우저에서
/surface/status 200(진행률 100·모델 3), /surface/models 200,
/surface/models/415/preview 200 model/gltf-binary 7,946,756바이트.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
872줄 한 파일을 셋으로 나눔 (동작 불변, 순수 분리).
- `B03_FileInput_Router.py` 309줄 — 파일 업로드·현황·워크플로 엔드포인트
- `B03_FileInput_Router_Chunks.py` 390줄 — 세션 생성·조각 전송·마무리·진행 조회
  (자체 APIRouter 를 본체가 `include_router` 로 붙여 경로 문자열 불변)
- `B03_FileInput_Router_Helpers.py` 268줄 — 필수 파일 판정·중복 지문 판별·단계 기록·알림

검증: 라우트 7개 경로·메서드 동일(`GET upload-overview|upload-status|workflow-state`,
`POST files|upload-sessions|chunks|finalize`), 공용 브라우저에서 노선 5종 실제 업로드 성공
(shp metadata preview_path 포함), ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04_PreProcess_Router_Watershed.py 714줄 -> 518줄. 산출물 기록(.npz·스테이지 기하)과
응답 좌표 변환 헬퍼 9개를 B04_PreProcess_Router_Watershed_Output.py(225줄)로 그대로 옮김.
공개 심볼 router · get_primary_region · CONTOUR_FILE · STREAM_FILE 유지
(main.py · B03_FileInput_Service_Chain · B07_DesignDetail_Router_Support 참조).

검증: ruff check 전체 통과·format 적용, tmp/tests 183 passed, 백엔드 재시작 후
경로 2개 유지, /drainage/rainfall 200, /drainage/primary-region 200(schema_version 3),
B05 화면 유역 11개·측점 66개 정상, 옮긴 순수 헬퍼 6개 직접 호출 스모크 통과.
분석 재실행(쓰기 경로)은 작업본 산출물을 덮어써서 돌리지 않음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
749줄 한 파일을 셋으로 나눔 (동작 불변, 순수 이동).
- `B03_FileInput_Router_Temp.py` 478줄 — 묶음 생성·목록·삭제·파일 업로드·프로젝트 연결
- `B03_FileInput_Router_Temp_Chunks.py` 294줄 — 세션·조각·진행·마무리 (prefix 없는
  APIRouter 를 본체가 `include_router` 로 붙여 `/api/temp-uploads/...` 경로 불변)
- `B03_FileInput_Router_Temp_Support.py` 46줄 — 조각 수·묶음 폴더·상태 갱신 (순환 방지)

검증: 라우트 10개(temp 9 + attach 1) 경로·메서드 동일, 공용 브라우저에서 실제 청크 흐름
create 200 → upload-sessions 200 → chunks 200 → finalize 200 → delete 200,
ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
808줄 한 파일을 셋으로 나눔 (동작 불변, 순수 이동).
- `B07_DesignDetail_Router_Support.py` 532줄 — 도면 목록·장 배치·확정 저장·재계산
- `B07_DesignDetail_Router_Support_Basin.py` 279줄 — 유역도 배경(GeoJSON·좌표 환산·도곽 클리핑)
- `B07_DesignDetail_Router_Support_Io.py` 88줄 — 원본 JSON·매니페스트 입출력, 측점 대응표

떼어낸 `watershed_source`·`clip_line_to_box` 는 본체에서 `as` 로 다시 내보내
호출부(`B07_DesignDetail_Router.py`)의 import 경로가 그대로임.

검증: 라우트 7개 그대로, 공용 브라우저 `design-drawings` 200 · `frame-template` 200,
ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
937줄 한 파일을 셋으로 나눔 (값·이름 불변).
- `config_system.py` 255줄 — 서버·로깅·DB·업로드·저장소·인증·CORS
- `config_system_terrain.py` 186줄 — 5장·5-2장 지형 분석·지표면 모델 파라미터
- `config_system_design.py` 520줄 — 5-3장~5-6장 경로·유역·종횡단·계획선 파라미터

본체가 두 조각을 `import *` 로 다시 내보내므로 기존
`from config.config_system import …` 호출부는 그대로임.

검증: 분리 전 원본과 대조해 **공개 상수 243개 전부 값 동일**(사라진 것은 설계 모듈
내부에서만 쓰는 `_SCS_SOIL` 하나 — 밑줄 시작이라 원래도 외부 참조 없음),
백엔드 재시작 후 기동 정상·주요 API 6종 200, ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`_Support_Basin.py` 로 옮긴 뒤 `CONTOUR_FILE` · `STREAM_FILE` · `_basins_crs` ·
`_geojson_payload` · `_geojson_features` · `_too_far_from_route` 가 진입 파일에서
사라져, 옛 이름을 참조하던 다른 워크트리의 테스트가 ImportError·AttributeError 로
깨졌음(laptop-sub 보고 2건). 프로덕션 호출부는 새 모듈을 직접 봐 동작에는 영향 없었음.

`as` 형태로 다시 내보내 분리 전 이름 14개가 진입 파일에서 모두 보이게 함.

검증: 진입 파일 속성 14개 전부 확인, 라우트 7개 유지, ruff check 통과,
tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
700줄 분리 때 _Router_Progress · _Router_Status 로 옮겨 진입 파일에서 안 보이게 된
PROGRESS_FILE_RELATIVE · _progress_file_path · read_surface_progress ·
get_wf1_analysis_status · get_surface_model_preview 를 as 재노출로 되살림.
옛 경로를 보던 호출부·테스트가 그대로 동작하게 하려는 것(laptop-main 의 B07 사례와 같은 사고 예방).

검증: 분리 전 모듈 정의 이름을 전수 대조해 누락 0개(_Router 16개 · _Router_Watershed 30개),
라우트 9개 유지, ruff check/format 통과, tmp/tests 183 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
laptop-sub 가 쓴 AST 대조법(분리 전 커밋의 모듈 정의 이름 ↔ 지금 모듈 `dir()`)을
내 4개에도 적용해 누락 26개를 찾아 되살림.

- `B03_FileInput_Router.py` 누락 17 → 0 (헬퍼 13 + 청크 엔드포인트 4)
- `B03_FileInput_Router_Temp.py` 누락 5 → 0 (`_total_chunks` + 청크 엔드포인트 4)
- `B07_DesignDetail_Router_Support.py` 누락 3 → 0 (`_BASIN_MAX_DISTANCE_M` ·
  `_clip_segment` · `_geometry_lines`)
- `config/config_system.py` 누락 1 → 0 (`_SCS_SOIL` — `import *` 가 밑줄 이름을 안 실음)

검증: 네 파일 모두 **정의 이름 누락 0**(28·19·36·246개 대조), 라우트 수 유지
(B03 7 · temp 9+attach 1 · B07 7), ruff check 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
RouteProfilePanelCallbacks 인터페이스만 B05_Profile_UI_Profile_Panel_Types.ts(52줄)로
그대로 옮기고, 진입 파일에서 다시 export 해 옛 임포트 경로(_Profile_Render 등)를 유지.
런타임 코드는 한 줄도 건드리지 않음.

검증: 분리 전 export 2개(RouteProfilePanelCallbacks · createRouteProfilePanel)가 진입
파일에서 그대로 보임, tsc --noEmit 통과, prettier 유지. 공용 브라우저(5174) 실조작 —
종단 패널 측점 66개·표 12행·줌 버튼 7개·유역 11개 정상, 측점 선택 후 방향키 862.99->863.09m,
Ctrl+Z 로 862.99m 복귀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B04_PreProcess_UI_TerrainViewer.ts 958 -> 698줄.
- _TerrainViewer_Chrome.ts(209줄) — 상태줄·표시 토글·등고선 간격 폼·뷰포트·축척·컴파스·
  표고 범례·로딩 서클 DOM 생성. 만드는 순서·클래스·인라인 스타일 그대로.
- _TerrainViewer_Contours.ts(189줄) — 등고선 적재(fetch·라인 생성·라벨·범례). 뷰어
  클로저가 쥐던 값만 ctx 로 받고 본문 수치·로직은 그대로. 호출부는 얇은 래퍼로 유지.

검증: export 2개(SurfaceTerrainViewer · createSurfaceTerrainViewer) 분리 전과 동일,
tsc --noEmit 통과, prettier 적용. 공용 브라우저(5174) B04 실조작 — 뷰어 2개·캔버스 2개
렌더, 상태줄 CLASSIFICATION · DTM · 등고선 1m, 등고 라벨 40개(상한), 범례 940m/760m,
등고선 토글을 끄면 라벨 0 → 켜면 40 복귀, 간격 5m 적용 시 상태가 5m 로 바뀌고
1m 로 되돌리면 원상 복귀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
917줄 한 파일을 넷으로 나눔 (동작 불변, 순수 이동).
- `ui_template_elements.ts` 363줄 — 버튼·입력·선택·카드·태그·토스트·확인창·셸
- `ui_template_elements_styles.ts` 369줄 — `injectBaseStyles()` 와 규칙 문자열
- `ui_template_elements_chart.ts` 185줄 — 공통 라인 차트
- `ui_template_elements_base.ts` 33줄 — 요소 생성 헬퍼 `el` (셋이 함께 써 순환 방지)

본체가 `export *` 로 다시 내보내 호출부의 import 경로는 불변.

검증: 분리 전 `export` 25개 전부 유지(+`el` 공개 1개 추가), `tsc --noEmit` 통과,
tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
925줄 한 파일을 셋으로 나눔 (동작 불변).
- `B03_FileInput_UI_Page.ts` 692줄 — 화면 조립·카드 렌더·현황 표시
- `B03_FileInput_UI_Page_Flow.ts` 262줄 — 중단 세션 이어올리기·보관함 이관·청크 업로드·
  초기 계산 중 재잠금·서비스워커. 화면 상태는 `UploadFlowContext` 창구로만 받음
- `B03_FileInput_UI_Page_Rules.ts` 107줄 — 필수 카드 판정·파일 적합성·업로드 가능 판정·
  서버 파일의 카드 매핑 (상태를 가두지 않는 순수 함수)

검증: 공용 브라우저에서 새 프로젝트 만들어 노선 5종 실제 선택·업로드 —
카드 5장 선택 후 [파일 업로드] 비활성, [LAS 없이 설계] 켜면 활성(판정 규칙 정상),
업로드 후 4장 완료 표시(20초). 남은 `route_prj` 오류·400 은 지형 자료가 없어
분리 전에도 같던 것. `tsc --noEmit` 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
728줄 한 파일을 둘로 나눔 (계산 불변, 순수 이동).
- `common_util_cross_design.ts` 405줄 — 표준단면 해석·설계선 조립·면적 산출
- `common_util_cross_design_geometry.ts` 333줄 — `SectionGeometry`(노면·측구·사면 설계고)
  와 그것만 쓰는 상수(행진 간격·최대 거리)·`sideRole`·`ResolvedGroup`

파이썬 짝 파일(`B06_Section_Engine_Design.py`)은 손대지 않음 — 미러 관계 유지.

검증: 공용 브라우저 B06 횡단 카드 실측과 서버 계산값 대조 — 측점 0에서
절토 화면 2.50㎡ / 서버 2.4985㎡, 성토 화면 1.85㎡ / 서버 1.8521㎡ 로 일치
(카드 273장 렌더, 콘솔 오류 0). `tsc --noEmit` 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
732줄 한 파일을 둘로 나눔 (동작 불변, 순수 이동).
- `B07_DesignDetail_UI_Page.ts` 517줄 — CAD 임베드·postMessage 교신·저장/확정 흐름
- `B07_DesignDetail_UI_Panels.ts` 234줄 — 도면 목록 12분류(`DRAWING_GROUPS`)와
  측점 설계 정보 카드. DOM 만 만들고 고르기 동작은 콜백으로 받음

검증: 공용 브라우저 B07 화면 실측 — 도면 목록 패널 1개·항목 54개(「설계 도면 49건」),
CAD iframe 1개 로드, 콘솔 오류 0. `tsc --noEmit` 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05_Profile_UI_Structures_Panel.ts 1024 -> 669줄. 조각 셋 모두 700줄 이하.
- _Structures_Panel_Types.ts(94줄) — GROUP_LABELS · PipeFacilityItem · StructuresSection ·
  StructuresCallbacks · 기본 구간 길이 상수. 패널이 다시 export 해 옛 임포트 경로 유지.
- _Structures_Panel_Commit.ts(312줄) — 폼 불러오기(구조물·계곡 통과 시설)와 [추가]/[수정]
  저장, 목록 알림. 검증 순서·분기·수치는 그대로이고 패널 클로저 값만 ctx 로 받음.
- _Structures_Panel_Events.ts(146줄) — 드롭다운·버튼·측점 입력 배선. 리스너 본문 그대로.
  StructuresEventContext 가 StructuresCommitContext 를 상속해 패널은 컨텍스트 하나만 만듦.
  가변 상태 4개(editingId · selectedPipeChainage · tempPipeChainage · positionConfirmed)의
  주인은 그대로 패널이고, 읽기 함수 + set* 로만 넘김.

검증: 분리 전 export 4개가 진입 파일에서 그대로 보임, tsc --noEmit 통과, prettier 적용,
tmp/tests 183 passed. 공용 브라우저(5174)에서 실제 조작으로 저장 경로까지 확인 —
C 사면안정/옹벽을 기준측점 5+0 에 [추가] -> 목록 반영, [저장] -> 서버 정본 2건(revision 0->1),
새로고침 후 목록에서 골라 [삭제] -> [저장] -> 서버 0건(revision 4). 시험 프로젝트는 원래
상태(구조물 0건)로 되돌려 둠.

참고(분리와 무관한 기존 동작): 방금 [추가]해 아직 저장 전인 항목은 structure_id 가 없어
[삭제]가 듣지 않음. 저장 뒤에는 정상 삭제됨. 분리 전 코드와 같은 분기라 이번 변경과 무관.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
증상: 방금 [추가]한(아직 저장 전) 항목을 목록에서 고른 뒤 [삭제]를 눌러도 목록에
그대로 남음. 저장 뒤에는 정상.

원인: 700줄 분리(2026-09-04)로 `_Commit`·`_Events` 조각이 `structures` 배열을
**참조로** 받아 두는데, `setStructures()` 가 `structures = next.map(...)` 로 배열을
갈아끼움. 화면 목록은 새 배열로 그려지고 조각은 옛 배열을 splice 해 사라지지 않았음.
같은 이유로 `renderOptionFields()` 의 `optionInputs = []` 도 조각이 옛 칸 목록을
읽을 수 있어 저장값이 어긋날 자리였음.

조치: 두 배열 모두 **자체를 바꾸지 않고 내용만 갈아끼움**(`splice` · `length = 0`)하고
`const` 로 못박아 다시 갈아끼우지 못하게 함. 데이터 흐름은 그대로 — 삭제는 캐시만
바꾸고, 영구저장은 [저장]에서만 나감(5장 데이터 3층).

검증(시험 프로젝트 8cd2e635, 공용 브라우저 실조작):
- 저장 전: [추가] → 목록 12건 → 고르고 [삭제] → **11건으로 사라짐**, 서버는
  revision 4·0건 그대로(쓰기 없음), 세션 캐시도 빈 목록
- 저장 경로: [추가] → [저장] revision 5·1건 → [삭제](서버 5·1건 유지) → [저장]
  revision 6·0건
- 저장값: 옹벽 옵션 `height_m 2.5 · length_m 10 · before_m 5 · after_m 5`,
  기준 5+0(100m) → 구간 95~105m 정상
- 시험 프로젝트는 구조물 0건으로 되돌려 둠. `tsc --noEmit` 통과, tmp/tests 378 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
휴대폰에서 코드를 보러 메일 앱에 다녀오면 브라우저가 탭을 버려 페이지가 다시 뜨는데,
단계 상태가 메모리에만 있어 이메일/비밀번호 화면으로 되돌아갔다(2026-09-04 사용자 보고).
받은 코드가 무용지물이 되고, 다시 로그인하면 새 코드가 발급돼 앞 코드는 폐기됐다.

- 코드를 보낸 시점에 이메일과 발송 시각만 sessionStorage 에 남기고(비밀번호는 저장 안 함),
  화면이 다시 뜨면 그 단계로 되돌린다 — 이메일 채움·잠금, 코드 입력칸 노출, 재발송 대기도
  발송 시각 기준으로 이어 센다.
- 서버 유효시간(5분)이 지난 값은 되살리지 않고 지운다. [이메일/비밀번호 다시 입력]·로그인
  성공 시에도 지운다. 세션 저장이 막힌 브라우저면 예전처럼 메모리로만 동작한다.
- 서버는 손대지 않았다 — 코드는 이미 DB 에 5분간 있고 검증에 이메일+코드만 쓴다.

검증(공용 브라우저 5174): 대기 상태를 심고 새로고침 → 코드 입력칸 노출·이메일 잠금 채움·
버튼 "인증하고 로그인"·"43초 후 재발송" 복원. [이메일/비밀번호 다시 입력] 누르면 대기 상태
삭제되고 비밀번호 화면 복귀. 발송 6분 전 값은 복원하지 않고 삭제.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 구조물 솔리드에 부재키(key) 부여 — B06과 같은 이름(inlet·outlet·extra{i}·bextra{i}·own·basin·pipe)
- 구조물 메쉬에 신원표(userData) — 이름 규칙은 그대로 유지
- 신규 모듈 두 개 — 3D 클릭·강조(Viewer_Structure_Pick), 좌측 패널 연결·B06 넘김(Structure_Pick_Session)
- 좌측 패널·종단에서 고른 것도 3D가 따라오도록 선택 동기화에 포트 추가
- B06 진입 시 세션 넘김값으로 그 측점 카드 선택·스크롤 + 기슭막이 조정창 열기
- 저장 코리도 만료(BUILD_VERSION 90→91) — 옛 저장본엔 부재키가 없음
- 뷰어 700줄 여유 — 검증용 요약을 Viewer_Debug로 분리(동작 불변)
- 검증 수단 — __corridorScene에 camera·project 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 이름표를 횡단도 이름으로 통일 — 세월교 유입·유출, BOX 좌·우, 본체는 body
- 조정창 하나가 여러 부재를 다루므로 `측이름:부재` 꼴 — 강조는 전체 키, 조정창은 앞칸만
- B06 갈래 태우기 신규 모듈 — 세월교/BOX/기슭막이 조정창으로 각각 보냄
- 저장 코리도 만료(BUILD_VERSION 91→92) — 재계산 비용 실측 차이 없음(5.1초 vs 4.7초)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 바깥 선택이 폼에 실릴 때 접힌 좌측 패널 자동 펼침(onReveal 창구)
- 계곡 통과 시설 목록 행도 보이는 자리로 스크롤(rAF)
- 종단 테이블 구조물 구간 판정을 허용오차 비교로 교체 + 병합 측점 포함(강조 0건→6건)
- 구조물 선택 세션을 소비형에서 유지형으로 — B06 카드·목록·부재 선택도 같은 칸에 기록,
  양쪽 진입 시 복원(목록 지연 로드 대비 이중 복원)
- 조정창 닫기가 세션 선택까지 지우던 결함 수정(부재 해제와 측점 해제 분리)
- B05 페이지 700줄 유지 위해 상단측 세션 보관을 Page_Helpers로 이동(동작 불변)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
브라우저 세션에 남은 계획선 편집 초안이 초기값 위에 다시 얹혀,
초기화 직후에는 멀쩡하다가 새로고침 한 번에 계획선이 측점에서 떨어짐
(실측: 측점 66개 중 25개가 10cm 초과, 최대 6.0m).

- [초기화]가 `b05-profile-alignment-draft:*` 세션 초안을 전부 제거
- 노선번호 없는 초안 키(`:none`) 폐지 — 어느 노선에나 되붙어 초기화로도
  떨어지지 않던 구멍

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 모달 닫기 규칙 일원화 — 바깥 클릭·Esc·[취소] 모두 같은 경로(attachModalDismiss).
  고친 게 있으면 공용 showConfirmDialog 로 한 번 묻고, 없으면 바로 닫음.
  껍데기 세 곳(Modals·AssetPicker·TempModal) 모두 적용.
- 확인창 z-index 토큰 --z-confirm(1050) 신설 — 모달(1000) 뒤에 깔리던 문제 해소.
- 프로젝트 로고 칸에 회사 기본 연결 표시 — 프로젝트 값이 비면 회사 로고를
  「회사 기본 로고 · <자산명>」으로 보이되 저장값은 계속 null(연결 유지).
  [기본으로] 로 전용 로고 해제. 남의 회사 프로젝트에는 기본을 내밀지 않음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실측 결과 축척은 문제가 아니었음. 실거리 3 m 가 모든 단면에서 30.0 mm
(mm/m = 10.0 단일값). 뒤죽박죽으로 보인 원인은 칸 크기 — 한 장 안에서
폭 116~218 mm, 높이 29~178 mm 로 제각각이었음.

- 장별 완전 통일: 한 장 안 모든 칸을 그 장 최대 블록 크기로 통일(_grid_for).
  테두리는 build_cross_drawing(cell_frame=...) 로 칸에 맞춰 그림.
- 장 경계는 전체 최소 장수가 되도록 동적계획으로 선택(_sheet_breaks).
  앞에서부터 채우면 바로 뒤의 큰 단면이 칸을 키워 6칸짜리 장에 1개만
  실리는 낭비가 있었음.
- 축척은 지식DB 「설계제원_총괄」 기준 1/100 고정 — 어떤 경우에도 줄이지 않고
  안 들어가면 장을 나눔. 장수는 세트마다 달라짐(2026-09-04 사용자 확정).

검증(용화_LAS): 장 21개 전부 칸 크기 단일값, mm/m = 10 단일, 측점 65개
누락 0, 칸 밖 이탈 0.000 mm. 실서버 API 로도 동일 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 줌 버튼을 셋(줌인·줌아웃·초기화)으로 줄임. 세로 배율·창 이동 버튼 제거
- 배율 1 = 기본값이자 축소 한계 — 한계에 닿은 버튼은 흐리게 죽임
- 세로는 보이는 누가거리 구간의 지반·계획선 범위로 자동(공통 함수
  windowElevationRange, B05·B06 종단이 함께 씀). 스크롤이 멈춘 뒤 0.16초에 갱신
- 계획고 편집 버튼을 누르고 있는 동안 Y 축 고정, 손을 떼면 다시 맞춤
- 유토곡선 Y 도 같은 창 기준(전 구간 ±200㎥ 고정 해제)
- B06 종단이 쓰던 공통 Y 스케일(calculateYScale) 제거 — 횡단 카드는 원래 안 쓰던 값

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 워크플로 상태 응답에 project_name 추가. 좌측 제목 패널 같은 행 오른쪽 끝에
  프로젝트 이름 표기(길면 말줄임, 전체는 툴팁). 이름표를 오버레이 쪽에 두어
  레이아웃을 직접 조립하는 B03 까지 여섯 화면이 한 곳으로 반영됨.
- fetchProjectWorkflowState 가 {status, workflow_state} 껍데기를 벗기도록 수정.
- 계획노선을 「업로드한 CSV」로 적은 주석을 「계획노선(정본)」으로 정리.
  업로드 판정이 .csv 개수만 세어 shapefile 을 막던 것도 .shp 포함으로 맞춤.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-04) — 「이전 방식이 좋았음」. 2026-08-25 `f6296fa7` 에서
직교로 바꿨던 것을 시야각 45° 원근으로 되돌림.

- 직교 전용 모듈 `B05_Profile_UI_Viewer_Camera.ts` 삭제, 뷰어 4자리 복원
  (카메라 생성 · 리사이즈 종횡비 · 화면맞춤 · 투영행렬).
- 근평면 상한 0.4m 신설 — 휠 확대가 커서 아래 지점 0.5m 앞에서 멈추는데
  근평면을 맞춤거리의 1/1000 로만 두면 긴 노선에서 그 0.5m 를 넘어 지형이 잘림
  (용화_LAS 맞춤거리 1,208m → 상한 없으면 근평면 1.21m).

자체검증(공용 브라우저 5173, 용화_LAS) — 네 방향 모두 원근 45°, 확대 한계
0.516m > 근평면 0.4m 로 잘림 없음, 구조물 클릭 선택·해제 그대로.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 지적(2026-09-04) — 「절토가 된 경우 측점 표시가 안 따라감」,
「측점 라벨이 5측점 기준으로만 붙음, 전체 라벨이 있으면 좋겠음」.

- 측점 막대 표고에서 `max(지반, 계획고)` 제거. 코리도가 켜져 있으면 계획고를
  그대로 씀 — 절토는 계획고가 지반보다 아래라 max 로는 막대만 원지반에 떠 있었음
  (실측 0측점 3.2m 공중).
- 라벨을 규칙 측점 전부에 만들고(`STATION_LABEL_STEP` 제거), 카메라 거리로 솎음
  (`LABEL_LOD` 150m 미만 전부 · 400m 미만 2칸 · 그 밖 5칸). 구조물·BP·EP 는 항상.
- 뷰어 렌더 루프에서 카메라~시점 거리로 단계를 갱신(단계 불변이면 즉시 반환).

자체검증(공용 브라우저 5173, 용화_LAS) — 절토 3측점·성토 10측점 모두 막대와
코리도 표면 높이차 0.80m(띄움값). 라벨 66개 중 화면맞춤 23 · 중간 39 · 근접 66.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 토사/암/포장 3그룹이 같은 필드를 각각 갖던 화면을 공통 한 벌로 합침 (칸 31 → 15)
- 공통 = 노폭·노견·측구·절토/성토 경사·횡단 경사, 구분선 뒤 암 = 절토 경사·L형 측구,
  구분선 뒤 포장 = 횡단 경사
- 저장 구조는 3그룹 그대로 — 공통값은 고칠 때 세 그룹에 펼쳐 넣음
- 옛 프로젝트가 그룹마다 다른 공통값을 갖고 있으면 토사 값 기준으로 한 벌 통일
  (사용자 확정 2026-09-04)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 계획평면도(지형·노선배치도·배치도)를 실제 도면으로 만듦.

- 배경 공용화: map_background() 한 창구로 도엽 등고선·세류선 읽기·좌표 환산·
  도곽 절취를 모음. 유역도와 계획평면도가 같은 것을 부르고, 환산 결과는
  파일 mtime 을 키로 캐시(_metric_lines_cached).
- 축척 1/1,200 고정(DRAWING_SCALE_PLAN) — 지식DB 「설계제원_총괄」 측량·도면
  기준. 횡단면도와 같은 원칙으로 줄이지 않고 안 들어가면 장을 나눔(plan_chunks,
  종단 측점 기준·경계 측점 1개 중복).
- 세 장이 같은 배경·같은 도곽 배치를 쓰고 주제만 다름. 측점 눈금은 종단 측점
  좌표로 찍고, 구조물은 pipe_points.json 정본을 읽어 마름모+이름으로 표기.
- 도면 목록·단건 조회에 kind="plan" 추가. 화면 목록은 id 접두어로 묶어 장이
  나뉘어도 한 그룹으로 보임.

검증(용화_LAS): 콘텐츠 734.3x489.2 mm ≤ A1 작도영역 739.2x499.2, 노선 실거리
630.1x214.2 m → 종이 525.12x178.46 mm(실측 0.83333 mm/m = 1/1,200 일치),
배경 등고선 180줄이 세 장 동일, 유역도 8.5초 → 계획평면도 1.3초(캐시 적중,
파일 재읽기 없음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 스냅샷 대상이 B04_PreProcess/drainage/edits 에서 drainage 폴더 통째로 넓어짐
  (00_watershed_response ~ 04_detailed_basins 포함). 관을 옮겨 다시 나뉜 세부유역이
  초기화로 되돌아가지 않던 구멍을 막음
- 용량 실측: 배수유역 8.6MB, 스냅샷 전체 3.9MB → 약 12MB
- 옛 스냅샷(edits 만 촬영) 호환 — 그 경우 예전처럼 관 지점 편집분만 복원
- 3D 코리도는 제외 — 스냅샷 시점(체인 직후)에 아직 없는 값이라 별도 판단 필요

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 용지도를 실제 도면으로 만듦. 축척·도곽·장 나눔은 계획평면도와
같고(1/1,200) 배경도 같은 창구(map_background)를 씀.

- 연속지적도 필지 경계 + 지번(jibun) 표기. 작은 필지는 솎고(종이 6x3 mm 미만),
  도곽을 통째로 감싸는 임야 대필지는 도곽 중심에 지번만 적음 — 그러지 않으면
  노선이 대필지 안에 들어앉을 때 지번이 통째로 사라짐.
- 시군구·읍면동/리 경계를 파선·일점쇄선으로 구분. 지적·행정 경계는 도곽 범위로
  절취 — 자르지 않으면 산지 대필지 하나가 도면을 10 km 로 벌림(실측 8,368 mm).
- 도면용 색을 화면용과 따로 정함(등고선을 가장 옅게, 행정 경계를 굵고 진하게).
- 범례를 유역도 정보표 자리(오른쪽 칸 방위표 아래)에 넣음.
- _geometry_lines 가 MultiPolygon 을 편다 — 지적·행정구역이 그 형식임.

검증(용화_LAS): 콘텐츠 734.3x489.2 mm ≤ A1 작도영역, 지번 「산77-15임」이 지적
속성과 일치, 도면 목록에 landuse 가 실림. 이 노선은 임야 대필지 한 곳에 통째로
들어가 경계선이 도곽 안에 없음 — 자료대로의 정상 결과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 라이다 계획평면도에 지표면 탑뷰 그림을 얹음.

- 확정 DTM 격자를 도곽 범위로 잘라 음영기복 PNG 를 만들고 Image 엔티티로 실음
  (북서 315도·고도 45도, 한 변 최대 1,600 px). 점구름 4,900만 점을 그대로
  그리지 않음.
- 어느 지표면을 쓸지는 1단계 확정값을 따름 — DrainageContext 에 surface_params
  를 실어 전달.
- 축척·도곽·장 나눔은 계획평면도와 같음(1/1,200) — 노선이 같은 자리에 섬.
- entities_bbox 가 꼭짓점 배열(points)을 세도록 고침. 세지 않으면 그림이 도곽
  계산에서 통째로 빠짐.

검증(용화_LAS): 콘텐츠 726.1x487.2 mm ≤ A1 작도영역, 그림 범위 안에 노선이
완전히 들어감, 음영기복 준비 0.4초·자료 214 KB. 능선·계곡이 눈으로 구분됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 계획노선 사용 범위: B02 등록에 시작·종료 누가거리 두 칸 추가, B01 수정 모달에서도
  변경. projects.route_start_m·route_end_m 신설(015_route_range.sql).
  load_design_route 가 범위 절단 → 서피스 트림 순서로 적용. 시작 >= 종료는 화면·서버
  양쪽에서 차단. 비우면 전 구간으로 종전과 같음.
- 서피스 절단 여유 기본값 30m → 3m (SURFACE_ROUTE_EDGE_TRIM_M).
- B04 지도·B05 배수유역도 줌 상한을 「화면 폭 20m」 기준으로 계산(고정 8배·16배 폐지).
  4배를 넘으면 배경 그림 흐림 보간 해제.
- 계획선 위 측점 눈금·번호 표기(측점번호+잔여거리). 관 마커와 겹치면 반대쪽으로 밀고,
  되꺾임 구간에서 라벨이 겹치면 건너뜀. 그리기 코드는 두 화면 공용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
빈 도각이던 표준 횡단면도를 실제 도면으로 만듦.

- 본 그림: B06 좌측 패널 모식도와 같은 배치를 실치수로 그림(1/50). 노폭·노견·
  측구 상단폭·노면 전폭에 치수선(눈금+치수값)을 붙이고, 절토·성토 경사비와
  횡단경사를 표기. 값은 B06 표준 횡단면 설정을 그대로 읽고 없으면 config 기본값.
- 측구 부분 확대도(1/10): 상단폭·저폭·깊이 치수 + 확대 축척 표기.
- 암반 2단 절토: 아래는 암반 경사(1:0.4), 위는 토사 경사(1:1), 갈리는 높이에
  암반선을 파선으로 긋고 각도를 함께 적음.
- 암 L형 측구·포장 횡단경사는 주기(※)로 적음 — 본 그림은 토사 기준.

곁들여: Router_Support 가 700줄을 넘어 재수출 import 를 한 문장으로 합쳐 681줄로
줄임(기능 변화 없음).

검증: 치수값이 STANDARD_CROSS_SECTION 과 일치(500·3000·500·900·4000), 확대도
900·300·300 + S=1/10, 2단 절토선 꺾임점 1개, 콘텐츠 358.2x172.6 mm ≤ A1 작도영역.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-04) — 「3D 는 보조라 후순위. 조용히 뒤에서 뜨고 다 되면
팝업으로 알릴 것. 로딩 도넛은 진행률과 무관하게 계속 돌고 숫자만 갱신」,
그리고 「직교/원근 전환 단추는 넣음」.

진입 로딩
- 단계 5 → 4. ④ 종·횡단 자료까지 끝나면 로딩 표시를 걷어 화면을 바로 쓰게 함.
- 3D 지형은 finally 뒤 배경 작업으로 돌리고 끝나면 토스트 「3D 지형 준비 완료」.
  실패해도 나머지 화면은 그대로 씀. [초기화]는 재진입이라 같은 규칙이 걸림.
- 「확정 지표면 없음」 판정을 ③ 뒤로 앞당김.

진행 서클(공용)
- 회전 껍데기(`__spin`)를 한 겹 두고 CSS 회전을 거기에만 검. 껍데기는 늘 돌고
  안쪽 svg 는 12시 고정이라 호·숫자가 제자리에서 갱신됨. `is-indeterminate` 제거.

직교/원근 전환
- 카메라 두 벌을 `B05_Profile_UI_Viewer_Camera.ts` 가 쥐고 갈아 끼움. 위치·시선·
  근평면·먼평면과 보이는 크기를 옮겨 화면이 튀지 않음.
- 마커 입력·구조물 클릭·커서 피벗 유틸이 카메라를 함수로 받게 바꿈(공용 유틸은
  값도 그대로 받아 B04 호출부는 무변경).

자체검증(공용 브라우저 5173, 용화_LAS) — 진행률 25→50→75%, 회전 애니메이션
running 유지(변환행렬 표본 전부 다름), 로딩 걷힌 순간 그래프선 2·좌측단추 61·
3D 메쉬 2, 1.8초 뒤 메쉬 489 + 토스트. 초기화 재진입도 같음. 전환 단추는
Ortho ↔ Perspective 왕복 후 값 완전 일치, B04 페이지 오류 0건.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 미리보기를 카드 한 행 전폭·높이 120px 고정으로 키움.
- 라이다: 분류 통계를 훑는 그 길에 XY 를 성기게 주워 탑뷰 점 그림(상한 5천 점,
  파일 재열람 없음). 분류가 없는 파일은 앞 3청크만 봄.
- GeoTIFF: 오버뷰가 있을 때만 128px 흑백 썸네일(2~98 백분위 대비), 없으면 종전 범위 사각형.
- 부속 파일(.shx·.dbf·.cpg·.prj·.tfw)은 그림 대신 구분되는 값 표시 — 머리글만 읽는
  가벼운 분석기 추가.
- 값이 없는 완료 카드는 「보여 줄 값이 없음」 한 줄.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 횡단면도 장 배치의 칸 여백 8mm → 0mm — 이웃 박스 테두리가 맞닿음.
- CAD 리본 높이 116px → 122px — 내용(85px)이 보이는 높이(81px)를 넘어 생기던
  세로 스크롤바 제거. 캔버스 상단이 6px 내려감.
- 장 라벨을 누가거리 범위 「1060~1070m」에서 시작 측점 「No.53」으로 교체.
- 좌측 패널 2열 격자 단추의 최소폭을 풀어 패널을 14px 넘어가던 것을 막고,
  이름이 길면 `…` 로 잘리게 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 세 곳(종단 그래프·유토곡선·측점 테이블)에 복사돼 있던 휠 처리를
  `B05_Profile_UI_Profile_Wheel.ts` 한 벌로 통합.
- 이동은 rAF 로 목표를 쌓아 프레임마다 좁힘 — `scrollLeft` 직접 대입의 120px 점프 제거.
  브라우저 `scrollTo({behavior:"smooth"})` 는 휠마다 애니메이션이 처음부터 다시 시작돼
  1.6초에 17px 만 움직여 쓰지 않음(실측).
- 세로 자동 맞춤 디바운스 160 → 80ms.
- 「다시 계산 중…」 을 요약 막대에서 떼어 곡선 영역 우측 상단 오버레이로 이동 —
  막대 줄바꿈으로 곡선이 밀리던 창밀림 제거.

자체검증(공용 브라우저 5173, 임시 탭): 휠 10칸 1,200px 중 1,199px 이동·궤적 연속,
마지막 휠 500ms → 재구성 813ms. 칩 표시/숨김에서 요약 막대 높이 53px·곡선 자리
(top 1078·height 226) 동일 — 창밀림 0. 칩은 곡선 영역 안 우측(범례 아래 4px).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 확정(2026-09-04) — 「다른 로직과 동일하게: 전처리 계산 마지막에 연산 후
영구저장, 진입 시 로딩, 조작은 캐시, 저장·확정 때 저장」. 예전에는 사용자가 B05에
처음 들어간 그 순간 브라우저가 17MB 규모를 만들어 첫 진입이 느렸음.

계산은 **재구현하지 않음** — 브라우저가 쓰는 TS 빌더(8,209줄)를 Node 로 그대로 돌림.
- `B05_Profile_UI_Corridor_Envelope.ts` 신설 — 저장 형식·버전 해시·직렬화를
  `_UI_Corridor.ts` 에서 그대로 떼어 브라우저·서버 공용으로 둠(내용 불변).
- `B05_Profile_Corridor_Node.ts` 신설 — 입력 JSON 을 받아 저장본을 내놓는 진입점.
  `npm run build:corridor` 로 번들(335kB), `npm run build` 에 물림.
- `B05_Profile_Corridor_Prebuild.py` 신설 — 상세·노선점을 모아 Node 실행 후 저장.
  번들이 TS 원본보다 낡으면 스스로 다시 만듦(두 그림이 갈라지는 것을 막는 장치).
- 체인 마지막(스냅샷 직전)에 호출. 실패는 비치명적 — 저장본이 없으면 브라우저 폴백.
- 초기값 — 스냅샷이 코리도를 `initial_corridor.json` 으로 함께 뜨고, [초기화] 복원 때
  **새 route id** 이름으로 되돌림(복원이 새 번호를 만들기 때문).
- `window.__corridorSource` 디버그 훅 — 저장본을 썼는지 다시 만들었는지 화면 밖 확인용.

자체검증: 전체 시험 381 통과·17 건너뜀(옛 테스트 2건은 이름·경로 변경에 맞춰 갱신).
실경로 — 용화 프로젝트(route 139)로 사전 생성 성공, 브라우저가 그 저장본을
`source: "stored"`, 해시 `377c2a84` 로 **그대로 채택**(재빌드 0회, 전송 278ms).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
프레임당 고정 비율(0.35)로 좁히면 주사율에 따라 속도가 달라짐 — 120Hz 화면에서는 두 배
빨라 툭 끊겨 보이고, 프레임을 한 번 놓치면 그만큼 덜컥 뜀. 흐른 시간으로 환산해
어느 화면에서나 같은 시간에 도착하게 함. 탭이 잠들었다 깬 큰 간격은 64ms로 자름.

자체검증(공용 브라우저 임시 탭, 휠 20칸): 프레임 중앙값 16.6ms(60fps) 유지,
최대 프레임 47.6 → 34.3ms, 20ms 초과 프레임 3 → 2건.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 지시(2026-09-04) — 「화면을 리프레시하는 느낌. 가장 강한 지연은 멈춘 뒤 끊김.
실시간처럼 되려면 근본적으로 표현을 바꿔야 하지 않나」. 확정: 변환 방식.

원인 — 세로 위치가 선 하나하나의 좌표에 박혀 있어, 세로 창이 바뀌면 그래프를 통째로
다시 만들 수밖에 없었음(SVG 요소 457개, 실측 34ms = 60Hz 두 프레임 누락).

- 세로에 딸린 도형(눈금선·절성토 음영·지반선·계획선)을 `b06-chart__ywindow` 한 겹으로
  묶고, 세로 창을 `translate`+`scale` 한 줄로 표현. 두 창의 대응이 1차식이라 정확히 겹침.
- 자를 영역(clip)은 변환 밖, 글자는 변환 밖에서 자리만 옮김(늘어남 방지).
  글자 내림 4px 은 변환 뒤에 더함 — 배율과 함께 커지면 선에서 떨어짐(실측 6.4px).
- 선 굵기·점선 간격은 `vector-effect: non-scaling-stroke`(변환이 걸렸을 때만 적용해
  B06 은 예전 그대로).
- 눈금 간격이 어긋나면(배율 0.8~1.25 밖) **눈금층만** 다시 만듦(요소 20개 안팎).
  눈금은 그릴 때의 좌표계에 놓아 같은 변환이 그대로 먹음.
- 눈금 계산을 `yWindowTickValues` 로 빼 그리는 쪽과 갱신 쪽이 같은 눈금을 씀.
- 패널은 스크롤마다 변환 갱신만 부름. 전체 재구성은 눈금으로도 못 살릴 때만 남김.

자체검증(공용 브라우저 임시 탭, 휠 20칸 4,800px):
① 전체 재구성 **0회**(고침 전 다회) ② 최대 프레임 **59.9 → 20.0ms**, 20ms 초과 0건
③ 눈금 글자와 눈금선 간격 6.4 → **0.5px** ④ 지반선의 한 점을 변환으로 놓은 자리와
눈금이 말하는 자리가 **0.000px** 일치(배율 2.715 상태) ⑤ B06 종단은 변환 겹 3개 모두
변환 없음(항등) — 화면 불변 ⑥ 전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 지적(2026-09-04) — 「유토곡선도 반영해야지. B06 페이지도 있잖아. 같은 로직일 텐데
왜 반영이 안 된 거야」. 그리는 쪽(종단 렌더러)은 공용이라 이미 바뀌어 있었고, **스크롤을
받아 창을 옮기는 쪽이 화면마다 따로**라 B05 만 연결돼 있던 것.

- 세로 창 모듈을 `common_util_chart_ywindow.ts` 로 옮겨 B05·B06 이 함께 씀.
  좌측 고정 축은 표식(`b05-profile__yaxis--ywindow`)이 붙은 것만 옮김 — B06 은 한 컨테이너에
  종단·유토곡선 축이 함께 살아 남의 축까지 옮기면 안 됨.
- 세로 과장(B06 조절값)을 각인·반영 — 예전에는 과장이 1일 때만 대상이었음.
- 유토곡선은 변환이 아니라 **곡선만 다시 그림**(스크롤마다). 곡선 위 말풍선·EP 표·측점
  점처럼 세로로 늘어나면 안 되는 것이 많아, 그것만 따로 옮기는 값이 다시 그리는 값보다 큼
  (유토 SVG 234개 = 종단의 1/3).
- B06 상단 패널을 통째로 다시 그리던 스크롤 처리를 걷어내고, 종단은 변환·유토곡선은
  제자리 교체로 바꿈. 700줄 제한에 맞춰 종단 조립을 `_View_Chart.ts`(116줄)로,
  유토곡선 조립기를 `_View_MassHaul.ts` 로 분리(727 → 718줄).

자체검증(공용 브라우저 임시 탭):
① B05 유토곡선 눈금이 스크롤을 따라 4.3㎥ → −1,348.8㎥ 로 이동(예전에는 안 따라옴)
② B06 종단 눈금 830/840/850m → 824/826/828m, 유토곡선 68.2㎥ → −3,375.1㎥ 로 동시 이동
③ B06 최대 프레임 **35.9 → 23.5ms**, 33ms 초과 1 → **0건**(중앙값 16.7ms 유지)
④ B05 최대 프레임 27.4ms, 33ms 초과 0건 ⑤ 전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
개수만 보이던 부속 파일 카드에 파일 안의 중요한 값을 함께 보임.

- .shx — 도형 종류(폴리라인 등)와 범위 크기를 머리글에서 읽음.
- .dbf — 속성 이름 목록을 머리글 서술자에서 읽음(앞 4개).
- .cpg — 같은 세트 .dbf 의 첫 글자 속성을 그 인코딩으로 읽어 견본으로 보임.
- .prj — 중앙자오선(투영 매개변수)과 길이 단위. proj 문자열 변환을 쓰지 않아
  정보 손실 경고가 나지 않음.
- 카드 표시 줄 수를 2 → 3 으로 늘리고, 길이 단위 표기를 m 으로 통일.
- GeoTIFF 썸네일에 다른 미리보기와 같은 점선 테두리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 보고(2026-09-04) — 「0선이 갑자기 위로 넘어가고 그 영역 채움색이 눈금 상한을 넘어
표현됨」. 보이는 구간에 세로를 맞추면서 0이 창 밖으로 나가는데, 유토곡선에는 **자르는
영역(clip)이 없어** 0선과 면 채움색이 범례·토글 버튼 위까지 그대로 칠해짐. 종단 그래프는
진작 자르고 있었는데 유토곡선만 빠져 있었음.

- 그래프 칸(축 오른쪽 · 상단 여백 아래)을 자르는 겹 둘을 둠 — 측점 세로선이 면과 곡선
  **사이**에 서야 해서 앞뒤로 나눔(그리는 순서 유지).
- 면·곡선·0선·EP 표식·선택 강조·말풍선·토량 분배를 그 겹 안으로 옮김.
- 0선은 창 안에 있을 때만 그리고 눈금에도 그때만 실음 — 밖으로 나갔는데 실으면 좌측
  고정 축 맨 위에 남의 값과 겹쳐 찍힘(사용자 확정: 0선은 나가도 됨).
- 눈금 글자는 축 **왼쪽**이라 자르는 겹에 넣지 않음(넣으면 사라짐).

자체검증(공용 브라우저 임시 탭): 확대 4칸 + 휠 25칸으로 0을 창 밖으로 보낸 상태에서
① 자르는 겹 2개 확인 ② 0선·0눈금 사라짐, 눈금 5개 전부 음수(겹쳐 찍힌 0 없음)
③ 영역 캡처로 면 채움색이 그래프 칸 위 경계에서 정확히 멈추는 것 확인.
전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 확정(2026-09-04) — 「버티기 + 부드럽게」. 누가토량 곡선은 표고와 달리 가팔라,
급한 구간이 창에 들어오면 세로 폭이 한 칸에 228 → 1,019㎥(4.5배)로 튀었음(실측).

- **버티기** — 곡선이 지금 창 안에 들어오고 창을 55% 넘게 채우면 창을 아예 안 건드림.
- **부드럽게** — 바꿔야 할 때도 한 번에 안 가고 다시 그릴 때마다 남은 만큼 20%씩 좁힘
  (약 0.15초에 걸쳐 미끄러짐). 아직 안 끝났으면 다음 프레임에 한 걸음 더.
- 여유를 5% → **20%** 로 넓혀 곡선이 위아래 끝에 딱 붙지 않게 함(종단과 같은 값).
- 곡선 계산(`computeMassHaulSeries`)을 입력 객체 단위로 아껴 둠 — 스크롤 중에는 입력이
  그대로인데 그릴 때마다 다시 계산해 프레임을 먹었음.

자체검증(공용 브라우저 임시 탭):
① 한 칸씩 8번 굴려 세로 폭 257·257·257·257 → 1,031 … : **4칸은 아예 그대로**(버티기)
② 창이 바뀌는 순간 궤적 257 → 711(42ms) → 882(80ms) → 1,030(151ms): 계단이 아니라 미끄러짐
③ 휠 20칸 기준 최대 프레임 27.4 → **24.0ms**, 33ms 초과 **0건**(고치기 전보다 나아짐)
④ B06 최대 프레임 21.2ms, 33ms 초과 0건 ⑤ 전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 완료 카드에서도 [파일 선택]을 보임. 올리는 중에만 감춤. 교체 확인 모달과
  교체 업로드 규칙은 이미 있던 것을 그대로 씀.
- 업로드 관문이 전처리 1단계 IN_PROGRESS 를 무조건 「분석 중」으로 읽어,
  자동 확정이 보류된 프로젝트는 영영 새 자료를 받지 못했음. 전처리 진행 파일이
  awaiting_confirmation·completed·failed 로 끝나 있으면 받도록 고침.
  실제로 도는 중(analyzing)이면 그대로 막음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 계획노선처럼 그릴 선이 있는 자료에는 범위 점선 상자를 그리지 않음.
  점구름·래스터는 그대로 상자를 그림.
- 노선 선 색을 녹색으로. 지형 범위를 벗어나면 붉은 경고색으로 덮어쓰는
  규칙은 유지.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 보고(2026-09-04) — 「종단 곡선 조절에 따라 횡단 기준 유토곡선 변경 안 됨」.
오늘 프레임을 아끼려고 넣은 곡선 계산 캐시가 원인. 횡단 설계는 `refreshCrossDesigns` 가
**같은 객체를 제자리에서 고치므로**(배열·요소 동일성 유지) 「입력 객체가 같으면 안 바뀐 것」
이라는 캐시 판정이 성립하지 않음. B06 은 `detail` 동일성으로 캐시해 **한 번 계산한 뒤로는
영원히 낡은 곡선**을 보였음.

- 두 곳(B05 패널·B06 조립기)의 캐시를 걷어내고 그릴 때마다 계산하게 되돌림.
- 왜 캐시하면 안 되는지 주석으로 못 박음.

자체검증(공용 브라우저 임시 탭):
① B06 — 횡단 지반 종류를 바꾸자 절토 4,500.3 → 4,500.7㎥, 토취 10,211.5 → 10,211.1㎥,
   곡선 경로도 바뀜(고치기 전에는 완전 동일)
② B05 — 계획고 6칸 올리자 계획선·유토곡선 둘 다 바뀜(성토 14,729 → 17,513㎥)
③ 휠 20칸 기준 최대 프레임 27.0ms, 33ms 초과 **0건**(캐시 없어도 예산 안)
④ 전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 보고(2026-09-04) — 「종단 그래프 왔다갔다하면 Y축 값이 비는 경우가 있음」.
세로창을 변환으로 옮기면서 눈금을 **배율이 크게 바뀔 때만** 다시 만들게 해 뒀는데,
창이 위아래로 **이동만** 하면 배율은 그대로라 눈금이 한쪽으로 쓸려 나가고 그 자리가 빔.

- 새 창에 있어야 할 눈금 수와 화면에 남는 수가 다르면 눈금을 다시 만들게 함(요소 20개
  안팎이라 값싸다). 배율 문턱 판정은 그대로 둠.

자체검증(공용 브라우저 임시 탭): 확대 4칸 뒤 좌우로 6번(+900·+900·−600·+1400·−1800·+2400px)
오가며 눈금이 플롯을 덮는지 측정 — 눈금 6~11개가 항상 이어지고 **위·아래 빈틈 최대 37px**
(플롯 높이 329px, 창 여유 20%에 해당). 고치기 전에는 플롯 절반이 비었음.
전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
사용자 보고(2026-09-04) — 배수관 2 자리에서 계획선이 수직으로 꺾이고 최대 기울기가
**155,791 %**. 원인은 「가까운 점」이 아니라 **한 구조물이 층마다 다른 누가거리를 든 것**:
  횡단 측점 264.054626 · 종단 정본 변화점 264.055 · 배수 정본 파일 **264.06**(cm 반올림).
사이드 목록이 든 264.06 으로 계획고를 편집하면 정본 옆 5mm 자리에 변화점이 하나 더 서고,
둘 사이 종단곡선이 mm 로 쭈그러들어 기울기가 거리 0 에 가까운 값으로 나뉘었음.
2026-09-03 에 ▲▼ 버튼 경로만 막아 뒀고(같은 증상 11,858%), 측점 테이블·도구 경로가 남아
다시 터진 것.

- **저장**(`common_util_drainage_pipes.py`) — 누가거리를 좌표(x·y)와 같은 **밀리미터 기준**으로
  남김(cm 반올림 제거). 종단 정본 변화점(3자리)과 값이 어긋나지 않음.
- **화면**(`_UI_Profile_Panel.ts`) — 구조물 측점 목록이 들어오는 **한 자리**에서 종단 정본
  측점(0.1m 안)으로 누가거리를 갈아 끼움. 버튼·테이블·도구 **모든 편집 경로**가 함께 막힘.
  이미 cm 로 저장된 옛 프로젝트도 이 경로로 안전해짐.

자체검증(공용 브라우저 임시 탭):
① 264 부근 그래프 측점이 **264.055 하나**로 모임(고치기 전 264.06 이 따로 있었음)
② 그 구조물 측점 계획고를 8칸 올려도 **수직 꺾임 0건**, 계획선 점 수 1,208 불변,
   최대 기울기 66.0 → 183.5%(8칸 올린 만큼의 정상값. 고치기 전 155,791%)
③ 전체 시험 381 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- google_token.json 액세스 토큰·리프레시 토큰 갱신
- scopes 에 script.projects 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 시스템 관리 회사(.env 관리자 계정 소속 회사) 소속은 전원 시스템관리자 — 서버 시작 시 일괄 반영, 가입 승인·팀원 등록 시에도 자동 부여
- 이미 소속이 있는 사용자의 회사 가입 재신청 차단 (기존: 신청 즉시 소속 해제·승인대기 전락)
- 회사관리자에게 자기 회사 역할 변경·프로젝트 삭제 허용, 마지막 관리자 강등 차단
- 역할 변경 시 is_master 동반 조정 (권한 판정 불일치 제거)
- 일반사용자도 소속 회사 프로젝트 전체 열람 (수정 권한은 별개)
- 대시보드 시스템 로그 섹션 최하단 이동
- PLAN.md 에 B01 정비 계획 반영

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B01
- 팀원 등록을 계정 대리 생성에서 「소속 없는 기존 가입자 검색·선택」으로 교체, 미가입자는 안내 메일만 발송
- 사용자 계정 삭제 API 신설, 삭제 모달에서 회사 제외/계정 삭제 선택, 관리자 수정 모달에 활성·비활성 상태 지정
- 기본정보 폼과 사용자 수정 폼을 공용 입력칸 한 벌로 통일 (이름 > 직급 > 이메일 > 부서 > 전화)
- 프로젝트 담당자 선택의 신규 등록 항목 제거

B02
- 프로젝트명 자동 조합 (사업연도 + 사업지역 + 임도종류 + 직접 입력값) 및 미리보기 표시
- 예상 연장 입력칸 제거, 노선 종료 누가거리 제목에 구간 연장 표기, 표지 값은 프로젝트명·연장에서 파생
- 취소 버튼 추가 (대시보드 복귀), 담당자 기본값을 생성자로 지정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 자리 확보 목적 (2026-09-06 사용자 지시). 뺀 6행 = 구배 L·H, 절토고,
성토고, 누가거리, 거리. 남긴 6행 = 구배 S, 계획고, 지반고, 측점, 곡선 L·R.
뺀 값은 사라지지 않음 — 구배 L·H 는 블록 툴팁, 절·성토고와 누가거리는 선택
측점 값 열 툴팁에 남김. B07 도면 종단도는 별도 코드라 12행 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 회사 정보 수정 API(PUT /dashboard/company) 및 수정 모달 신설, 회사 패널·회사 관리 표에 수정 진입점 추가
- 회사 등록·수정 입력칸 공용화 및 순서 조정 (사업자등록번호 > 회사명 > 대표자명 > 로고 > 주소)
- 회사 등록 시 사업자번호·회사명으로 기존 회사 조회, 있으면 가입 신청으로 유도
- 주소 지도 미리보기 추가 — VWorld 주소검색·배경지도 타일을 서버가 중계(키 노출 방지), 지도 라이브러리 없이 타일 3x3 조합

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 지시. 기본 켜짐 목록에서 토량분배(평형선·운반 블록)를 빼고
세션 저장 키 판을 v4 → v5 로 올림 — 안 올리면 이미 켜 둔 브라우저가 옛 값을
그대로 씀. 범례에서 켜면 예전대로 나옴. 두 화면이 같은 키를 쓰므로 두 벌을
함께 고침.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 지시. 좌클릭·휠 버튼으로 그림 위에서 바로 잡아 끈다.
공용 스크롤러 한 곳에 넣어 세 곳이 함께 얻음. 4px 문턱을 넘긴 뒤에만 이동으로
보고 그 경우에만 뒤따르는 click 을 한 번 삼켜, 측점 선택·선택 해제는 그대로 둠.
계획고 편집 버튼·리사이저 위에서 시작한 끌기는 제외(구조물 마크는 자기
pointerdown 에서 전파를 끊어 이미 제외됨). 끌기 시작 시 휠 관성 이동은 중단.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
원인은 선의 해상도 (2026-09-06 실측). 노선 정점(간격 중앙값 10.0m)을 곧바로
이어 지형 위 0.35m 로 띄웠는데, 볼록한 능선에서는 그 10m 직선이 지면을 뚫고
들어가 선이 땅속에 잠겼다 — 화면에서는 161+0.0~163+0.0 구간이 통째로 사라졌다.

정점 사이를 2m 간격으로 나눠 각 점의 지형고를 찍는다. 원래 정점은 모두 남기므로
평면 형상은 불변. 끼운 점과 원래 정점이 같은 지형면에서 높이를 받도록 지형고를
먼저 보고, 없을 때만 정점 z 를 쓴다. 곡선 경고 구간은 원래 정점 기준 인덱스라
조밀화 뒤 자리로 옮겨 자른다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- project_members 표 신설(016 마이그레이션, 기존 프로젝트는 생성자 자동 채움)
- 프로젝트 수정 모달에 참여자 선택 추가, 참여자로 지정된 일반사용자는 해당 프로젝트 수정 가능 (백엔드 _can_edit_project 동반 수정)
- B02 프로젝트 생성 시 생성자를 참여자로 자동 등록, 참여자도 같은 회사 구성원인지 검증
- 가입 요청 목록을 대기 상태만 표시 (처리 완료 건이 사용자 관리 목록과 중복 노출되던 문제)
- 팀원 등록 시 남아 있던 가입 신청 자동 정리
- 서명·로고 선택 문구를 뜻이 드러나게 수정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 지시. 요약 막대가 유토곡선 오버레이 안에 있어 패널을 접으면
같이 사라졌는데, 계획선을 만지며 봐야 하는 값이라 상단줄로 올림.

- 상단줄 「최대 기울기」 오른쪽에 「누가토량」 추가. 값은 유토곡선 계산 결과의
  마지막 누계이며 토량분배 켜짐과 무관하다. 음수(부족)면 경고색.
- 세부(절토 자연·다짐, 성토, 잉여/부족)는 그 항목 툴팁으로 내림 — 예전 요약
  막대가 세부를 툴팁에 두던 방식 그대로.
- 유토곡선 오버레이의 요약 막대 행 삭제. 비면 접히게 해 곡선이 그만큼 넓게 씀.
- 총괄값은 패널이 접혀 있어도 계산해 넘김(draw 앞단에서 산출).
- 상단줄 높이 24 → 28px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 지시(캐시·세션 일원화 1단계). 세션 접근이 19개 파일 64곳에
흩어져 있고 키 이름이 네 갈래라 같은 설계값인데 두 화면이 서로의 값을 못 보는
자리가 있었다.

- `A00_Common/b_page_state.ts` 신설 — 값마다 통(① 취향 · ② 초안 · ④ 계산 결과)과
  범위(전역·프로젝트·노선)를 한 줄로 적는 등록표. 키 형식은
  `aislo:{통}:{이름}:{프로젝트}[:{노선}]` 하나이고 **페이지 이름을 키에 넣지 않는다**.
- 옛 키는 처음 읽을 때 새 키로 한 번 옮기고 지운다(사용자가 쓰던 배치 유지).
- 초안 비우기(`clearDrafts`)·결과 버리기(`clearResults`)를 그 한 곳에 둠.
- 이번 커밋은 ① 취향값 11개를 이관 — 패널 접힘·높이, 유토곡선 펼침·높이·범례,
  테이블 펼침·높이, 배수유역 접힘·폭, B06 패널 접힘·높이.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- update_project 가 rowcount 0(변경된 컬럼 없음)을 프로젝트 없음으로 오판하던 자리에 존재 확인 추가
- 참여자 수정권한·시스템 회사 역할 규칙 검증 테스트 추가 (tmp/tests, git 추적 제외)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
캐시·세션 일원화 2단계 (2026-09-06 사용자 지시).

- ② 설계 초안 이관 — 구조물 미저장분, 상단측 변경분, 페이지 간 넘김값(구조물 선택),
  표준횡단 편집값, 조정창 4축·단수·연동값 8종, 암 경계선, 표시 반폭. 넘김값은 별도
  임시 키를 없애고 초안 한 자리로 흡수.
- ④ 계산 결과 이관 — 최신 노선 응답, 서버가 준 규격 횡단·암 경계 기본값. 횡단 상세는
  메모리 캐시에 더해 세션에도 한 벌 얹어 새로고침 뒤 첫 화면이 서버를 안 기다림
  (용량을 넘으면 조용히 건너뛰고 예전대로 다시 받음).
- B05 진입의 강제 새로읽기를 걷어냄 — 캐시로 먼저 그리고 노선번호·지표면 서명으로
  뒤에서 신선도만 확인, 달라졌을 때만 다시 그림.
- [초기화]의 초안 비우기를 `clearDrafts` 한 곳으로 모음(예전에는 파일마다 따로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-05 사용자 지시 건. 넘김 자체는 서 있었고 값이 중간에 지워지거나 대조에서
떨어지고 있었다.

- 부재키가 지워지던 길 — 3D 로 고른 뒤 선택 동기화가 **측점만** 다시 적어 부재키를
  덮었다. 같은 측점이면 이미 적힌 부재키를 지키게 함(모든 호출자에 함께 적용).
- 측점 대조 허용오차 0.01m → 0.05m. 같은 화면의 다른 대조와 같은 값이며, 3D 가 준
  누가거리가 소수점 아래에서 조금만 달라도 측점을 못 찾고 조용히 끝나던 원인.
- 「진입당 한 번」 빗장을 넘김값 서명 비교로 교체 — 자료가 늦게 와도 다시 서고,
  같은 값이면 재렌더에도 스크롤이 안 튄다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 확정. 자동탐색은 평면만 보고 노선을 정해 실제 판단과 맞지 않으므로
쓰지 않는다 — 버튼만 감추고 코드·API 는 남긴다. 대신 법정 평면 기준을 **경고**로 낸다.

- 횡단 생성이 측점마다 평면 곡선반경(`plan_radius_m`)을 낸다. 노선 폴리라인 위에서
  앞뒤 10m 떨어진 세 점의 외접원 반경이며, 직선(1만m 이상)은 null. 반지름 50m 원호로
  50.008 이 나오는 것을 확인.
- 법정 최소곡선반지름 표(별표2 Ⅰ.2.다.(1) — 40:60/40, 30:30/20, 20:15/12)와 배향곡선
  하한 10m 를 설정에 넣고 계획선 정책에 실어 화면으로 내린다. 탐색이 쓰는 등급별
  상수와는 별개다.
- 종단 상단줄에 「곡선반경 부족 n곳 / 최소 R」 경고 추가 — 자동 보정·차단은 없다.
  툴팁에 하한값과 배향곡선 하한 미만 개수를 적는다.
- 이 반경은 다음 작업(곡선부 확폭)이 그대로 쓴다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 확정. 별표2 Ⅰ.2.나.(4) 확폭표(R 10~45m → 2.25~0.25m)를 측점별
평면 곡선반경에 물려 차도 폭을 넓힌다.

- 확폭 방향은 **곡선 바깥쪽 편측** — 노선 폴리라인의 외적 부호로 회전 방향을 보고
  바깥쪽을 정한다(좌회전이면 우측). 측점 기록에 `curve_outer_side` 로 실린다.
- 차도 반폭을 좌·우로 나눠 들어 한쪽만 넓어지게 함. 확폭이 0이면 예전과 같은 대칭
  단면이다. 노견·측구·사면은 그 바깥으로 그대로 밀린다.
- 확폭을 더한 유효너비는 법정 상한 5m 에서 자른다(규격 3.0m 면 최대 2.0m 까지).
- 계산 짝을 함께 고침 — 파이썬 `compute_cross_design` 과 브라우저 `computeCrossDesign`,
  표는 양쪽에 두되 짝임을 주석으로 못 박음. 확폭 입력은 측점 기록에서 뽑는 헬퍼
  하나로 9개 호출부(횡단·확정·B07 도면)에 같은 값이 가게 함.
- 횡단도에 노폭 라벨 — 확폭이 걸리면 「노폭 4.5m (규격 3.0 + 확폭 1.5)」로 적는다.
- 확인: 표 경계·편측 적용·5m 상한·회전 방향 판정 5건(pytest) + 브라우저 표 15건 일치.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 지시. 연동 해제는 위치(4축)만 갈랐고 높이는 소유 측점 값을 계속
따라가, 소유 측점 높이를 바꾸면 푼 측점까지 같이 움직였다.

연동을 푸는 그 순간 화면에 그려진 벽 높이를 이 측점 조정값으로 굳힌다 — 값이 튀지
않으면서 이후에는 따로 논다. 이미 손댄 벽은 그대로 둔다. 단 수·형태는 소유 측점을
따르는 2026-08-30 확정을 그대로 지킨다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
캐시·세션 일원화에서 조정창 값 8종을 옮기며 다단 구간값(`extraspan`)을 등록표에
빠뜨렸다. 표에 없는 이름을 꺼내다 예외가 나 페이지 렌더가 통째로 실패했고 화면에는
「준비 중인 페이지입니다」만 떴다(화면 확인으로 발견).

- `extraspan` 을 등록표에 넣음.
- 표에 없는 이름은 이제 **예외 대신 저장 건너뛰기** — 그 값만 안 남고 화면은 선다.
  콘솔에 한 번 알려 표에 줄을 넣게 한다.
- B06 이 키를 만들 때 쓰던 형변환을 없앰 — 앞으로 등록표에 없는 이름은 컴파일에서
  걸린다. 같은 사고가 화면까지 가지 않는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- B01_Dashboard_Repository 에서 회사·가입신청 부분을 B01_Dashboard_Repository_Company 로 분리 (740줄 -> 508줄)
- 팀원 초대 메일 본문의 회사명·이름 HTML 이스케이프 (임의 HTML 삽입 차단)
- 지도 타일 엔드포인트 z/x/y 범위 검증 추가
- 회사 정보 수정 시 회사명·사업자번호 중복은 409 로 응답 (기존 500)
- 값 변경 없는 회사 수정이 404 로 튕기던 문제 수정
- 팀원 미선택 시 안내 문구 한글화

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 사용자 확정 — 구조물 **자체 면적을 빼는 것이 아니라**, 지반선과 실제로
그려지는 설계선이 이루는 폐회로의 넓이다. 기존 계산은 표준 설계선만 보아 구조물이
있는지조차 몰랐다.

- 그리는 쪽이 이미 만든 트림(`designTrim`)을 그대로 받아 「실제로 그려지는 설계선」을
  세운다 — 트림 안쪽은 설계선, 바깥은 구조물 성토부선, 그것도 없으면 원지반(면적 0).
  그림과 면적이 같은 입력을 쓰므로 둘이 갈리지 않는다.
- 벽면은 **수직**이라 트림 경계 바로 바깥에 점을 하나 더 찍는다. 안 넣으면 사다리꼴이
  단차를 비스듬히 이어 붙여 없는 면적이 생겼다(실측 6.25㎡ → 7.5㎡).
- 절토는 암 경계선이 있으면 기존 규칙대로 토사/암으로 나눈다.
- 확인(node) — 전구간 100㎡ · 벽에서 끊음 6.25㎡ · 구조물선 포함 20㎡.

한계: 서버는 아직 구조물 기하를 몰라 이 보정이 **브라우저 계산에만** 실린다. 저장·확정
뒤 서버 재계산에서는 표준 값으로 돌아간다 — 서버 반영은 남은 작업(계획서 3-2).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- DXF -> 도각 JSON 변환 엔진 신설 (ezdxf) — 선·폴리선·원/호/타원/스플라인 평탄화·글자·점 변환, 블록·치수는 분해, 해치 등 미지원 요소는 제외
- DWG 는 ODA File Converter(.env ODA_CONVERTER_PATH) 경유 변환, 미설치 시 DXF 저장 안내로 폴백
- POST /{project_id}/frame-template/import 신설 — 파일을 편집 화면용 도면으로 반환(저장은 기존 [완료] 경로 유지), 20MB·2만 도형 상한
- 도각 편집 띠에 「파일 불러오기」 추가, 자리표 팔레트 신설 (글자 14종·그림 4종을 도면 중앙에 배치 후 이동)
- CAD 텍스트 선택 시 회색 점선 외곽선 표시 (출력물에는 미포함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 부모 사이드바 팔레트(B07_DesignDetail_UI_FramePlaceholders.ts) 제거, CAD 앱에 FramePlaceholderPanel 신설
- 도면 로드 메시지에 frameEdit 플래그 추가 — 도각 편집으로 실은 도면에서만 패널 표시
- 자리표를 화면 중앙에 직접 생성 (부모 왕복 없이 CAD 상태에 추가, 실행취소 스택 반영)
- 그림 자리표는 값이 없어도 테두리와 이름을 그려 배치 위치가 보이게 함

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- ODA File Converter 제거 — 비회원 무료 사용이 비상업 용도로 제한되어 상용 서비스에 부적합
- LibreDWG dwg2dxf 를 별도 프로세스로 호출 (GPL 의무가 본 프로그램에 미치지 않는 방식), 경로는 .env LIBREDWG_DWG2DXF_PATH 또는 PATH 자동 탐색
- DWG 머리글로 형식 판정 — R2018 이후·미지원 형식은 변환 시도 없이 「2018 DWG 또는 DXF 로 저장」 안내
- 변환 실패·변환기 미설치도 같은 안내로 통일
- 형식 판정·안내 경로 테스트 추가 (tmp/tests, git 추적 제외)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat(B06): 구조물 면적·유토곡선 서버 계산 자리 마련 + 상단측 저장 누락 수정

계산 자리 일원화(CLAUDE.md 5장) — 브라우저에서만 돌던 두 계산을 서버가 같은 TS 로
한 번 더 돌려 정본에 얹음. 파이썬 포팅 금지(기하가 두 벌이 되면 그림과 수량이 갈림).

- B06_Section_Server_Calc_Node.ts 신설 — 구조물 폐회로 면적 계산 후 그 위에서
  유토곡선을 쌓음(화면과 같은 순서). balloon 위치는 서버가 만들지 않음.
- B06_Section_Structure_Layouts.ts 신설 — 정본만 읽는 제어기 흉내를 B07 도면에서
  떼어 공용화. B07·서버가 같은 한 벌을 씀.
- common_util_node_bundle.py 신설 — 번들 빌드·실행 배관 공용화(코리도도 이걸 씀).
- 전처리 체인(초기값 스냅샷 앞)·[저장]·[확정]에서 서버 재계산 호출.
- 상단측(측구 방향) 변경이 B05 [임시저장]에만 실리던 것을 B06 [저장]·[확정]에도
  실음 — flushUphillOverrides.
- 죽은 세션 등록 항목 pipes 제거(읽는 곳도 쓰는 곳도 없었음).

검증: tsc --noEmit 통과, pytest 386 passed, tmp/tests/test_b06_server_calc_node.mjs 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@
B05·B06 계산을 서버·브라우저 양쪽에서 돌 수 있게 하는 작업의 1단계.
배수관 세트(배관·세월교·BOX암거·물넘이포장·독립 기슭막이) 제원이 서버에만
있어 브라우저는 스펙 칸을 하나씩 옮겨 적는 부분 사본으로 버티고 있었다.

- common_util_culvert_sets.ts 신설 — B06_Section_Engine_Culvert.py 의 짝.
  매 상세 조회마다 도는 자리라 Node 왕복 대신 짝을 택함(CLAUDE.md 5장 ①).
- 거울 테스트 추가 — 다섯 시설을 태워 측점별 딕셔너리째 대조.
- 흩어진 임시 산식 3곳(관경÷1000 · BOX 구체 길이 · 날개벽 바닥판 연장)을
  이 한 벌로 바꿈.

검증: tsc --noEmit 통과, pytest 387 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 내보내기 엔진 신설 — 캐드 도면(JSON)을 ezdxf 로 DXF 작성(선·폴리선·글자·점·원·호, 도면층 유지), DWG 는 LibreDWG dxf2dwg 를 별도 프로세스로 호출
- POST /{project_id}/drawing-export 신설, 한글 파일명은 RFC 5987 방식으로 전달, 담지 못한 그림 수는 X-Aislo-Skipped 헤더로 통지
- CAD 출력 리본에 「DXF 내보내기」·「DWG 내보내기」 추가 — 캐드가 부모에 요청하면 부모가 서버 파일을 받아 내려받기
- 도각·내보내기 엔드포인트를 B07_DesignDetail_Router_Frame 으로 분리 (700줄 제한)
- 그림(Image)은 DXF 외부 참조 방식이라 제외하고 개수를 안내

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-06): 읽을 때는 영구저장소에서 가져오기만 하고, 계산은
화면(캐시)에서 하며, 저장·확정에서만 영구저장소에 쓴다.

- get_section_detail 이 조회할 때마다 돌리던 포장 구간 보정·세월교 노면 하강
  보정을 제거. 조회는 저장분을 그대로 싣는다.
- 두 보정을 recompute_server_side 로 옮겨 [저장]·[확정]·자동설계 체인에서
  정본에 남긴다. 보정된 설계 위에서 구조물 면적·유토곡선이 나오도록 순서를
  잡았다.
- 설계 미지정 측점 폴백(attach_default_designs)만 조회에 남긴다 — 저장분이
  있으면 아무 일도 하지 않는다.

검증: pytest 387 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 저장소에 LibreDWG 0.14.8594 Windows 실행 파일 동봉 (dwg2dxf/dxf2dwg + 필요한 DLL 4개, 약 33MB)
  실제 파일은 메인 워크트리 B07_DesignDetail/openwebcad/tools/libredwg 에 두고 보조 워크트리는 junction 으로 연결
- 파이썬 바인딩 미포함 (import 시 GPL 이 본 프로그램까지 확산) — 별도 프로세스 호출 방식 유지
- GPL v3 전문(COPYING)과 원본 출처·구성·교체 방법 README 동봉
- 변환기 탐색 순서: .env 경로 → 동봉본 → PATH
- 옛 DXF 의 유니코드 escape 를 복원해 DWG 왕복 시 한글 깨짐 해결, DWG 출력용 DXF 는 R2004 로 생성
- DWG 왕복 검증 테스트 추가 (tmp/tests, git 추적 제외)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-06): 조작 중과 [저장]·[확정]의 계산은 브라우저 몫이고,
서버는 초기값을 만들 때만 같은 코드를 Node 로 돌린다.

- 면적 산출을 B06_Section_Structure_Layouts 로 빼 Node 진입점과 브라우저가
  같은 한 벌을 쓰게 함(structureAreaRows / applyStructureAreaRows).
- [저장]·[확정]이 카드를 그리지 않은 측점까지 면적을 계산해 cross_patch 로
  보냄. 유토곡선도 그 위에서 쌓음.
- 서버는 저장 때 Node 를 돌리지 않음 — 포장 구간·세월교 노면 하강 보정만
  남기고, 그 보정은 편집분을 얹기 전에 돌게 순서를 바꿈.

검증: tsc --noEmit 통과, pytest 387 passed, Node 진입점 스모크 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
별표2 는 확폭량 표만 주고 붙이는 방식이 없어, 곡선 시·종점에서 폭이 뚝 끊겼다.
곡선 앞뒤 CURVE_WIDENING_TAPER_M(10m) 구간에서 0 → W 로 잇는다.

- 측점 생성 때 확폭량을 한 번에 계산해 curve_widening_m 으로 저장. 테이퍼는
  이웃 측점을 봐야 하므로 측점 단위 계산으로는 낼 수 없다.
- 설계 엔진(파이썬·TS 짝)이 저장된 확폭량을 우선 쓰고, 없으면 반경 표값으로
  되돌아간다 — 옛 저장분도 그대로 돈다.

검증: pytest 389 passed(테이퍼 경계값 테스트 2건 추가), tsc --noEmit 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
구조물은 보조말뚝을 박아 그 자리가 정본 측점이 된다. 규칙 격자(20m)와 0.1m
안에서 만나면 세로선·라벨이 두 겹으로 겹쳐 읽히지 않았다.

- 공용 유틸 dropStationsNear 추가(B05_Profile_Util_Station).
- 종단 그래프와 3D 측점 띠가 같은 규칙을 쓴다 — 두 화면의 측점이 어긋나지 않는다.

검증: tsc --noEmit 통과, tmp/tests/test_b05_station_merge.mjs 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 확정 지표면: 목록(surface/models)으로 id 를 찾고 3D 단계에서 surface/confirmed
  를 또 부르던 것을 확정 응답 한 번으로 합침. 모델 id·범위가 그 응답에 다 있다.
- 종횡단 설정값(sections/context): ④ 계산 결과로 보고 세션에 담음. B05·B06 을
  오갈 때마다 다시 묻지 않는다. 노선 캐시를 버리는 자리에서 함께 버린다.

검증: tsc --noEmit 통과, pytest 389 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-06): 조작은 캐시에 쌓이고 [저장]·[확정]에서만 영구저장소에
나간다. 카드 버튼(지반유형·단면유형·측구·포장·2단 비탈)은 누를 때마다
POST cross-design 이 나가 서버가 계산하고 바로 저장하고 있었다.

- 세션 초안 crossdesign 신설(B06_Section_Cross_Design_Session) — 선택값만 담는다.
- 계산은 브라우저 재계산 창구 하나로 돌린다(B05·B06 공용).
- 재계산 때 세션 선택이 정본보다 우선 — 새로고침 뒤에도 고른 값이 남는다.
- [저장]·[확정] patch 에 선택값 + 전 측점 면적을 실어 보낸다. 카드 버튼을 바꾸면
  구조물이 없는 측점 면적도 달라지므로 구조물 측점만 보내면 수량이 어긋난다.
- 구조물 목록 주석 정정(이미 초안 방식인데 옛 주석만 남아 있었다).

검증: tsc --noEmit 통과, pytest 389 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 텍스트 자리표에 칸 크기(boxWidth/boxHeight) 도입 — basePoint 를 칸 중심으로 두고 가로·세로 가운데 정렬, 선택 시 칸 테두리 표시, DXF 내보내기도 중앙 정렬로 반영
- 그림은 칸 안에서 비율을 유지하며 맞춤(letterbox) — 칸을 늘려도 로고·서명이 찌그러지지 않음
- 자리표 패널에 선택 항목 칸 크기(가로·세로 mm) 입력 추가
- 도각 편집 중 자리표에 실제 값 미리보기 — 서버가 표제란 값(공사명·회사·담당자·로고·서명)을 함께 내려주고 화면만 값으로 표시, 저장값은 {{키}} 토큰 유지
- title_block_fields 공개화 및 frame-template 응답에 fields 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실측(B05 진입): auth/session 4회, workflow-state 2회, 구조물 이관 POST 가 진입할
때마다 나갔다.

- auth/session: 라우터 가드·상단 바·워크플로 확인이 각각 부르던 것을 5초 캐시로
  묶음. 로그인·로그아웃에서 즉시 버린다.
- workflow-state: 공용 창구 하나로 모으고 같은 방식으로 캐시. 상단 오버레이가
  따로 부르던 경로를 그 창구로 돌림. 단계 이동에서 캐시를 버린다.
- 구 구조물 측점 이관 POST: 탭 수명 동안 노선마다 한 번만.

실측 결과: B05 첫 진입 20 → 18건(핵심 API 10건), B06→B05 이동 7건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 칸이 있는 글자와 그림에 모서리 그립 추가, 모서리를 끌어 칸 크기를 바꾸는 조작 신설 (다른 도면 요소에도 동일 적용)
- 기본 도각(00_template_A1)의 글자 24개에 표제란 칸을 계산해 부여 — 칸 기준 가로·세로 가운데 정렬
- 도각 편집 시 도면명·도면번호도 보던 도면 값으로 미리보기 제공
- 복제 시 미리보기 값 유지 (그립 편집 후 자리표가 토큰으로 되돌아가던 문제)
- CAD index.html 을 캐시하지 않도록 처리 — 빌드 후에도 옛 화면이 남던 문제 해소

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
포장·세월교 보정 헬퍼를 저장 시점으로 옮기면서 `@router.post(.../save)`
데코레이터와 `save_sections` 사이에 끼워 넣어, 라우트가 헬퍼(None 반환)에
붙어 있었다. 저장이 500(ResponseValidationError)으로 떨어졌다.

헬퍼를 데코레이터 앞으로 옮겨 라우트를 되돌렸다.

검증(용화 신규 프로젝트, 노선 145): 저장 200, 카드에서 고른 지반유형이
DB `cross_sections.data.design.ground_type` 에 반영되고 면적도 브라우저
계산값으로 갱신됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
페이지 번호식 이름(`..._p101_1.png`)을 내용이 드러나는 이름으로 바꿨다.
예: `노선측량_그림5-2-27_중심선과영선의위치비교.png`

- 그림 120개 이름 변경(122개 신규 등록), 본문 md 12개의 링크를 새 이름으로.
- 추출 파이프라인(`_pipeline/pdf2md.py`)과 QC 리포트 갱신.

확인: 그림 127개 · md 이미지 링크 127개 · 깨진 링크 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
LibreDWG 배포판(33MB 실행파일·DLL)이 추적되지 않은 채 남아 git sync 의 다른 창
브랜치 되받기가 계속 막혔다. 내려받아 쓰는 외부 도구라 저장소에 넣지 않는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 폴더를 B07 창이 `05a6b7e5 feat(B07): LibreDWG 변환기 동봉` 로 일부러
저장소에 넣어 두었다. 그 결정과 어긋나므로 무시 규칙을 뺀다.
(되받기 전에는 그 커밋이 여기 없어 추적되지 않은 파일로만 보였다.)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
끌어서 이동이 pointerdown 즉시 `setPointerCapture` 를 걸어, 뒤따르는 click 의
대상이 측점 `<g>` 가 아니라 스크롤러가 됐다. 그래서 측점 클릭이 배경 클릭으로
처리돼 선택이 그 자리에서 풀렸다(사용자 보고: 측점을 골라도 하이라이트가 안 됨).

- 포인터 잡기를 **끌기 문턱을 넘긴 뒤로** 미룸. 단순 클릭은 캡처가 없어 측점에
  그대로 닿고, 실제로 끌기 시작한 뒤에는 잡아 두어 창 밖에서 손을 떼도 이어진다.
- 문턱 4px → 6px. 손 떨림에 쉽게 넘어가 측점을 고르기 어려웠다.

검증(공용 브라우저, 실제 마우스 입력): 측점 클릭 → 선택·하이라이트 정상(420m),
끌기 → 선택 유지하며 팬 이동(scrollLeft 1660 → 1780).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
포인터 잡기를 끌기 시작 뒤로 미룬 뒤(측점 선택 복구), 그 전까지 브라우저 기본
글자 선택이 살아나 끌 때마다 라벨·수치가 파랗게 잡혔다.

끌기가 실제로 시작되는 순간 `user-select: none` 을 걸고 이미 잡힌 선택을 푼다.
끝나면 원래대로 되돌린다.

검증(공용 브라우저, 실제 마우스): 끄는 동안 선택된 글자 0자, 끝난 뒤 속성 원복,
측점 클릭 선택은 그대로 동작(60m).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
산림과임업기술(임도) 2장 임도구조 · 3장 임도계획 · 4장 노선측량 ·
5장 설계 · 6장 시공에서 한 줄로 뭉개져 있던 공식을 LaTeX 수식 블록으로
분리하고 기호 설명을 목록화. 본문 값·출처 불변.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 토량분배를 켜면 유토곡선이 종단과의 X 맞춤·세로 창을 버리고 스크롤러 안쪽
  폭·전 구간 Y 로 그려 곡선 전체가 한 화면에 들어옴(평형선·운반 블록을 노선
  전체로 읽는 그림이라). 끄면 예전대로 종단과 맞물린 가로 스크롤로 복귀.
- 요약 막대가 상단줄로 올라간 뒤 남던 상단 여백 축소 — 범례 top 34px → 4px,
  차트 padTop 40 → 30(범례 높이 24 + 여유).
- 종단 테이블 오버레이 높이 상한 신설 — 6행 × 행 30px + 24px(=204px).
  12행에서 6행으로 줄인 뒤 같은 높이를 나눠 가지며 행이 부풀던 것을 막음.
  레이아웃 제어(리사이저·패널 비례 연동)는 그대로 두고 상한만 걸음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 전체 맞춤(토량 분배) 보기는 측점 세로선을 그리지 않음 — 67개가 촘촘히 서서
  곡선을 덮기만 하고 자리도 못 읽음. 공용 차트에 `hideStations` 축 옵션 신설,
  분배를 끄면 예전대로 나옴.
- 같은 보기에서 좌우 여백 축소 — 종단과 맞물릴 필요가 없으므로 반 칸 들여쓰기
  (originOffset)를 빼고 우측 여백 12px. 곡선이 폭을 다 씀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「LAS 없이 설계」면 지형 한 벌(포인트클라우드·지형 PRJ·TFW)을 필수에서 면제
- 업로드 요청 검사도 완료 검사와 같은 기준으로 노선 PRJ 와 지형 PRJ 를 갈라 셈
  (종전에는 확장자만 봐서 노선 PRJ 를 지형 PRJ 로 오인)
- 업로드 현황의 「필수 충족」은 stage 0 완료를 우선 근거로 판정 — B04 이동 버튼 복구

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 지형 파일 개수 제한 해제(정확히 1개 → 1장 이상), 한 카드에 여러 장 담기
  (화면 표시 「용화_서편.las 외 1장」, 업로드는 한 장씩 차례로 전송)
- 구조화 엔진이 여러 파일을 합친 범위로 한 벌 생성 — WF1 자동 전처리·B04 재분석 모두
  프로젝트 지형 파일 전부를 대상으로 실행
- 점이 1억 개를 넘으면 씨닝 — 지면 분류점은 전부 남기고 나머지만 0.5m 칸 최저점으로 축소
  (용화 실측: 4,900만점 → 249만점, 지면점 1,140,716개 그대로, 1m 지면격자 표고차 0.0000m)
- 머리글만 읽어 5km 넘게 떨어진 파일은 업로드 거부 (임도는 길어도 2~3km)
- 화면 조립부 700줄 준수를 위해 terrainCoverage 를 판정 모듈로 이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「저장될 이름」 미리보기 줄을 없애고 프로젝트명 입력 칸 하나로 통합 — 사업연도·사업지역·
  임도종류로 자동 채우되 사용자가 사이나 끝에 글을 넣거나 자동 부분을 고칠 수 있음
- 손댄 뒤 위 세 항목을 바꾸면 해당 조각만 갈아 끼워 사용자가 넣은 글은 보존
- 비고 칸을 노선 시작 누가거리 앞으로 이동

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
프로젝트가 이미 회사에 매여 있어 따로 고를 이유가 없음 — 도면 표제란은
`COALESCE(프로젝트 로고, 회사 로고)` 로 조회하므로 회사 로고가 그대로 쓰임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 프로젝트명 조합기를 글자 단위 소유 추적으로 다시 만듦(`B02_ProjRegister_UI_Name.ts`) —
  자동 글자 사이에 글을 끼워 넣어도 사업연도·사업지역·임도종류 연동이 끊기지 않음
  (실측: 「울진군 금강송면」의 「금강송면」 앞 삽입 후에도 지역·종류·연도 변경이 반영)
- 비고 칸을 맨 마지막으로 이동
- 제목·여백·버튼 줄을 공용 템플릿(`createGeneralLayout` · `ui-general-block__actions`)으로 전환,
  화면 전용 제목 스타일 제거
- 헤더의 사용자명·로그아웃(로그인·회원가입) 버튼이 붙어 보이던 것 간격 부여

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
노선을 예상노선(원본)·계획노선(수정본) 두 벌로 나눔 (PLAN 0-7 사용자 확정).

- 예상노선 정본 `B05_Profile/route/expected_route.csv` 신설 — 자동 체인이 한 번
  씀. 초기값 스냅샷 안에도 같은 CSV 가 있으나 그 폴더는 재확정 체인이 지우므로
  스냅샷 밖에 한 벌 둠.
- 계획노선 수정본 `B05_Profile/route/planned_route.csv` — 설계 계통(`load_design_route`)이
  수정본 → 예상노선 → 스냅샷 순으로 읽음. 노선 초기화는 수정본을 지우는 것.
- `GET /route/plan` 두 노선 정점 반환(모달이 점선·실선으로 그림).
- `POST /route/replan` 고친 노선을 수정본에 쓰고(조밀화) 재확정 체인 재사용 —
  배수유역 다시 → 관 새로 → 계획선·종횡단 재생성 → 옛 측점 설계 누가거리 이월.
- `POST /route/replan/reset` 수정본 삭제 후 같은 재계산.
- 횡단배수 지점은 노선이 바뀌면 저장분을 버리고 새로 계산(사용자 확정).
  구조물은 프로젝트 정본이라 옛 측점값 그대로 남음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
공용 템플릿으로 바꾸면서 페이지 기본 폭(--page-max-width)을 따라가 넓어졌음 —
템플릿은 그대로 쓰되 이 화면의 안쪽 폭만 720px 로 좁힘.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
좌측 「계획노선」 섹션의 [계획노선 편집] 로 큰 모달을 엶(PLAN 0-2).

- 등고선 도엽 위에 예상노선(점선)·계획노선(실선)을 함께 그림. 지도 그리기는
  배수유역도와 같은 도구(`B04_PreProcess_UI_MapRender`) 재사용.
- 노드 끌어 옮기기 · 선 두 번 클릭으로 노드 끼우기 · 오른쪽 클릭으로 지우기,
  배경 끌기로 화면 이동, 휠로 확대.
- 편집 중에는 계산이 나가지 않음. [확인]에서만 서버가 배수유역부터 재계산하며
  그동안 화면을 덮는 안내를 띄움. 끝나면 세션 초안·조회 캐시를 비우고 페이지를
  다시 세움.
- [예상노선으로] 는 수정본을 지우고 같은 재계산(노선 초기화).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 진입 때 받은 판번호로 저장해, 그 사이 정본이 한 번이라도 바뀌면(다른 창
저장·노선 재계산) 409 로 거절되고, 실패 처리가 세션 초안까지 지워 사용자가 넣은
구조물이 사라졌음.

- 판번호를 **쓰기 직전에** 서버에서 다시 받아 씀.
- 저장이 실패해도 세션 초안·화면 목록을 지우지 않음(다시 [저장]하면 됨).

실화면 검증: 고치기 전 구조물 추가 후 [저장] → 정본 0건. 고친 뒤 → 정본 1건, 2건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 프로젝트 표의 진행도(%) 열 삭제 — 워크플로 배지가 같은 것을 보여 줌. 상태 문자열로
  따로 세던 서버 계산도 제거(배지는 `project_workflow_stages` 표가 근거라 둘이 어긋났음)
- 시스템 로그 표 = 이메일 · 동작 · 대상 · 일시. 「관리」 문구를 돌려 쓰던 것을 가르고,
  대상(resource_type·id)을 새로 보이며, 일시는 날짜/시각 두 줄(아랫줄 작은 글씨라 행 높이 불변)
- 표 안 관리 버튼을 한 줄로 — 작은 버튼 + 줄바꿈 금지, 폭이 모자라면 표가 가로 스크롤
  (프로젝트 행 높이 105px → 61px, 사용자 행 55px)
- 기본정보는 로그인 본인 화면 — 이메일 라벨을 「팀원 이메일」에서 「이메일」로 바꾸고
  본인 서명 칸을 사용자 수정 모달과 같은 부품으로 추가
- 제목·여백을 공용 템플릿(`createGeneralLayout`)으로 통일, 역할 배지는 제목 줄 오른쪽

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 기록을 `common_util_audit.record_audit()` 한 곳으로 모음 — 여섯 자리에 흩어져 있던
  raw INSERT 제거
- 대상 식별자 칸 신설(`017_audit_log_detail.sql`, 적용 완료) — 기존 `resource_id` 는 INT 라
  프로젝트 UUID 를 못 담아 늘 NULL 이었음. 프로젝트 생성·수정·삭제·회사 생성이 대상을 남김
- 접속 주소·브라우저 기록 — 라우터가 요청을 넘겨 주고, 프록시 뒤에서는 X-Forwarded-For 우선
- 보관 기간 `AUDIT_LOG_RETENTION_DAYS` 기본 365일, 임시 보관함 정리 루프에 얹어 함께 정리
- 화면: 시스템 로그 표에 대상·접속 주소 열 추가(대상은 UUID 앞 8자만)

자체검증 — 프로젝트 생성·하드삭제를 실화면에서 돌려 두 줄 모두
`프로젝트 e1040640… · 127.0.0.1 · 2026-09-06 09:54/09:55` 로 남는 것 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
좌측 「구조물 배치」로 넣은 옹벽·돌쌓기 같은 벽이 지금까지 측점만 심고 기하가 없어
절·성토 면적이 그대로였음(2026-09-06 사용자 확정: 반영해야 함).

- 독립 기슭막이가 쓰던 `section.revetment` 제원 자리에 그대로 얹음 — 기하·설계선
  트림·폐회로 면적·3D 가 손대지 않고 따라옴.
- 서버 `B06_Section_Engine_Structures_Wall.py`(저장분) ↔ 브라우저
  `common_util_structure_walls.ts`(미저장 초안) 짝 + 거울 테스트.
- 설치 측 칸이 없는 C군은 성토가 나는 쪽으로 자동 배치, 양측 절토면 세우지 않음.
- 구조물 목록이 바뀌면 B06 이 초안을 얹어 다시 그림.

검증: 40m 돌쌓기(찰) 추가 시 그 측점 성토 5.81 → 5.02㎡. 테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
유토곡선은 카드보다 먼저 계산돼, 구조물을 넣으면 카드 면적만 바뀌고 최종 누가토량은
옛 값으로 남았음. 구조물이 바뀌면 면적을 먼저 다시 얹고 그리게 순서를 바로잡음.

검증: 3+0.0 성토 8.06 → 5.73㎡, 최종 누가토량 553.4 → 546.4㎥ (저장 전, 즉시).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
페이지마다 따로 얹으니 새로고침 뒤 세션 스냅샷이 저장분 기준으로 되돌아갔음
(초안 벽 3건이 화면에서 사라짐). 캐시·세션·새 요청 어느 길로 들어오든 지나는
공유 저장소에서 ① 저장 안 한 구조물 벽을 얹고 ② 구조물 면적을 다시 계산하게 모음.

검증: 새로고침 뒤에도 벽 5건(저장 2 + 초안 3)이 붙고 3+0.0 성토 8.06 → 5.73㎡ 유지.
테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-06): 구조물 표시가 너무 커서 높이를 많이 차지함.

- 알약 높이 24 → 18px, 혼자 있을 때 31 → 22px, 글자 11 → 10px
- 레인 전체 54 → 42px — 그만큼 종단 그래프가 세로를 더 씀

검증: 실화면 레인 42px·알약 22px, 이름표(찰쌓기·배수관·옹벽·세월교) 모두 읽힘.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-06): 유토곡선은 자리를 많이 먹는데 정작 늘 봐야 하는 값은 마지막
지점 누가토량 하나임. 기준은 횡단으로 고정(종단 기준 곡선은 뒤에 삭제 예정).

- 총괄값 계열을 범례 선택과 무관하게 **횡단 기준**으로 뽑음
- 공용 배지 `common_util_mass_haul_badge.ts` — 종단 그래프 좌측 상단 오버레이,
  세부 내역은 툴팁
- B05: 상단줄의 「누가토량」 항목을 배지로 옮김(유토곡선 패널은 그대로 유지)
- B06: 유토곡선 그래프·범례·요약줄 삭제, 그 높이를 종단면도가 전부 사용

검증: B06 배지 −5,595.5㎥·범례 없음·종단 228px, B05 배지 −6,842.6㎥·상단줄에서 제거.
테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
연계(추가) 기슭막이가 성토사면과 안 맞는다는 지적(3-5)을 수치로 재니, 어긋난 곳은
접점이 아니라 바닥이었음 — 상단은 1:1.2 성토선에 붙는데 키는 요청값 그대로라
지형이 모자라면 바닥이 떴음(실측 0.12~0.87m).

자리는 그대로 두고 키를 지반까지 맞춤 — 지반이 낮으면 형태 높이 한계까지 키우고,
높으면 최소 높이까지 줄임. 조정창 되받기 값도 조정된 높이로 나감.

검증: 264.06 0.394 → 0.000m(키 1.00 → 1.39), 821.62 0.427 → 0.000, 914.93 0.122 → 0.000.
731.31 은 0.873 → 0.373 으로 줄되 남음(돌쌓기(메) 높이 한계 2.0m — 경고 유지가 맞음).
테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
추가 기슭막이를 옆으로 옮겨도 안 움직이는 측점이 있어(실측 1.0m 요청에 0.00~0.18m),
막는 규칙(원지반 매몰 금지)이 되돌린 양을 벽에 남기고 툴팁에 적음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
구조물 초안이 저장으로 정본이 되면, 화면이 들고 있던 상세는 초안 기준으로 벽을 얹은
사본이라 새로 저장된 구조물의 벽이 다음 조회까지 안 붙었음(8+0.0 흙막이 실측).

검증: 캐시를 비우면 벽 5 → 7개로 붙음. 테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
관 추가·이동·삭제가 B05 패널 메모리에만 있어, B06 으로 넘어가 [저장]·[확정]하면 그
편집이 사라졌음(대응표 조사에서 드러남).

- 등록표에 `pipes` 초안(프로젝트 범위)을 되살림
- 배치가 바뀌는 순간 목록을 초안에 담고, 내보내기는 `flushPendingPipes` 한 창구로 모음
- B05 [임시저장]·B06 [저장]·[확정] 모두 이 창구를 지남 (자동저장 없음)

검증: 초안으로 관 11 → 10개 저장·초안 비움, 되돌려 11개 복구. 테스트 390 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
perf(B04): 배수유역 세부 계산의 헛일 제거 — 282→154ms

DB 가 원격(dsm.chemifactory.com)이라 질의 하나가 곧 왕복 12ms 임을 실측.
순차 6건 130ms 중 대부분이 왕복 대기였음.

- context: 서로 기다릴 이유가 없는 질의를 두 묶음으로 asyncio.gather
  (묶음마다 자기 커넥션 — 풀 최대 20 이라 여유). 계획노선 읽기·지표면
  샘플러 열기도 같이 보냄.
- 격자 산출물(npz 3.1MB): 관을 옮길 때마다 다시 읽던 것을 파일 자국
  (수정시각·크기) 열쇠로 재사용. 분석이 다시 돌면 자국이 바뀌어 저절로 새로 읽음.

자체검증 — 용화 프로젝트(관 11·유역 11) 5회 중앙 282→154ms.
같은 입력에 응답 전체가 한 글자도 안 달라짐(JSON 정렬 비교).
전체 테스트 390 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@
B05 에 들어가는 것만으로 코리도 저장본 18.6MB 를 통째로 받고, 열쇠(해시)에 종횡단
내용이 섞여 있어 계획고를 한 번이라도 만졌으면 받아본 뒤 버리고 브라우저가 다시
만들었음(실측 화면 전환 16.7초). 3D 는 이미 [3D 업데이트] 수동인데 진입 경로만 자동.

- 서버: GET corridor 에 `?hash=` 를 받아 저장본 머리 4KB 에서 열쇠만 떼어 맞춰 봄.
  어긋나면 파일 대신 `{status:stale}` 만 냄. 맞으면 종전대로 파일 — 왕복은 한 번.
- 화면: 진입은 `loadCorridorIfFresh` 로 **저장본이 맞을 때만** 3D 에 올림.
  낡았으면 받지도 만들지도 않고 [3D 업데이트] 대기 표시만 켬.
- `ensureCorridor` 에 `rebuild` 인자 추가 — [3D 업데이트] 버튼 경로는 종전대로 재생성.

시험 tmp/tests/test_b05_corridor_hash_probe.py 3건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`B06_Section_Router_Confirm` 이 `_compute_default_designs` 를 `B06_Section_Router`
에서 들여왔는데, 커밋 1d4568b9 가 그 재수출을 지우면서 서버가 아예 안 떴음.
원본 모듈 `B06_Section_Router_Design.compute_default_designs` 에서 곧바로 들여옴.

시험 390건이 이 경로를 안 타서 못 잡았으므로 tmp/tests/test_app_imports.py 추가 —
`main` 을 들여와 라우터 27개가 전부 import 되는지 본다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DB·파일에는 뜻 없는 자릿수가 붙어 있고(1.4000000000000001 꼴) 서버는 응답을
전혀 압축하지 않고 있었음. B05 한 번 진입에 118MB 수신(2026-09-06 실측).

- main.py: 압축 미들웨어(1KB 이상). 3D 예상형상(/corridor)은 예외 —
  숫자 배열이라 절반만 줄면서 압축에 493ms 듦(18.6->9.4MB).
- common_util_json: round_floats(value, digits) + LONLAT_DIGITS 7(1.1cm) ·
  METRE_DIGITS 6. 저장 파일은 그대로 두고 내려보낼 때만 줄임.
  브라우저가 다시 계산에 넣는 값(종횡단 지반선)은 줄이면 안 된다고 머리에 경고 적음.
- 도엽 GeoJSON: 자릿수만 줄인 표시용 사본(.display.geojson)을 한 번 만들어 서빙.
  원본이 새로 깔리면 자동 재생성, 실패하면 원본 그대로.
  등고선 도엽 65.9->36.8MB, 압축까지 11.3MB.
- 배수유역 응답: 위경도 7자리. 151->100KB, 압축 22KB.

ruff 통과, 테스트 390 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 저녁 사용자 확정. 이유는 속도가 아니라 보안 — 저장 경로가 브라우저 계산이면
유토 배분·운반거리 코드(_balance 523 + _settle 235 = 758줄)가 번들에 남아야 해서
화면에서 안 그려도 뺄 수 없음. 서버가 정본을 내면 그 몫이 번들에서 빠짐.
대가는 저장 대기 850ms -> 약 980ms(Node 131ms) — 기다리는 조작이라 허용.

- 저장·확정이 편집을 커밋한 **뒤** recompute_server_side 를 부름(전에는 편집 앞에서
  Node 없이 보정만). 바뀐 벽·측점이 면적·유토곡선에 실림.
- run_node 갈래 제거 — 이제 부르는 자리가 둘 다 Node 를 돎(체인·저장).
  쓰이지 않게 된 enforce_stored_designs 래퍼 삭제.
- 코리도 열쇠 질의: hash 를 isinstance 로 좁힘. 파이썬에서 곧바로 부르면 Query 기본값
  객체가 들어오는데 truthy 라 열쇠 없는 호출이 통째로 stale 로 떨어졌음(보조 창 지적).

시험 395 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
등고선 도엽 36.8MB 를 매 요청 level 9 로 눌러 9.4초가 걸렸음(실측).
level 1 은 줄어드는 양이 거의 같고(66MB 기준 24.0 vs 23.9MB) 시간만 1/3.

실측(8001, IPv4) — 등고선 도엽 739ms · 전송 11.3MB(전 65.9MB 무압축),
종횡단 상세 485ms · 전송 0.33MB(전 1.56MB), 배수유역 전송 22KB(전 151KB).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계산 결과는 화면에 나가도 된다는 방침이라, 남는 위험은 입력을 바꿔가며 출력을
긁어 모으는 것임. 사람이 화면을 쓰는 속도에는 한계가 있음 — 화면 한 번 여는 데
API 가 약 180회 나가므로 한 시간에 2만 회를 넘으면 사람이 아니라고 봄.

- 막지 않음. 고객 화면을 끊을 위험이 있고 어디서 끊을지는 실제 사용 기록을 본 뒤
  정할 일임. 지금은 시스템 로그(보관 1년)에 RATE_ANOMALY 한 줄만 남김.
- 세는 값은 메모리(세션·시간대별)라 요청당 DB 비용 0. 상한을 넘은 그 순간에만
  세션 주인을 한 번 조회해 기록하고, 같은 시간대에는 다시 안 남김.
- 지난 시간대 기록은 버려 사전이 무한정 자라지 않게 함.
- 상한은 API_CALL_HOURLY_LIMIT(기본 20000, .env 로 조정).

빌드 껍데기는 이미 단단해 손대지 않음 — 실측 확인: 배포 산출물에 소스맵 0개,
식별자 뭉개짐(import{$ as e,C as t,...}), computeCrossDesign 등 원본 함수명
검색 결과 0건. 난독화 도구 추가는 얻는 것 대비 비용이 큼.

시험 tmp/tests/test_call_volume_watch.py 5건. 전체 484 통과.
실서버 확인 — 정상 사용 흐름에서 감시 로그 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05 는 해시가 바뀔 때마다 renderB05Route 로 통째로 다시 조립되어 뷰어 상태가 비워짐.
그래서 8MB 지표면을 진입할 때마다 다시 읽고 다시 파싱했고, 그것이 진입을 잡는
단일 동기 블록 14.4초였음(공용 브라우저 3왕복 실측: 14,708 / 1,060 / 14,841ms).

- 파싱해 둔 지형을 모듈 단위 cachedTerrain 에 한 벌 보관 — 같은 모델이면 새 장면에
  그대로 붙임. 다른 모델을 부르면 옛것을 버려 GPU 버퍼가 안 쌓임.
- 장면에서 뗄 때 보관본은 disposeObject 하지 않음.
- window.__surfaceTiming 디버그 훅 추가 — 단계별 시간(fetch·parse·fit·contours).

자체검증(공용 브라우저 3왕복) — B05 진입 683 / 474 / 639ms (전 14,708 / 1,060 / 14,841).
surfaceTiming: reuse 0ms · fit+markers 35ms · contours 183ms · total 222ms.
B06 진입은 2.4~2.7초로 변화 없음. 시험 395 통과·17 건너뜀, typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
인증이 걸린 모든 요청이 지나는 자리인데 요청마다 UPDATE + commit 이 나갔음.
DB 가 원격이라 그 둘이 곧 왕복 20ms 임.

실측 — verify_session 34.4ms = SELECT 10.8 + UPDATE 10.4 + commit 9.5.
쓰기를 1분 간격으로 낮춘 뒤 13.6ms(최소 9.4).

last_activity_at 은 유휴 판정에만 쓰는 값이고 그 판정이 4시간 단위라
초 단위 정확도가 필요 없음. 간격은 SESSION_ACTIVITY_WRITE_INTERVAL_SECONDS
(기본 60, .env 로 조정).

화면 한 번 여는 데 API 가 약 180번 나가므로 그만큼 곱해짐.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DB 가 원격이라 질의 하나가 곧 왕복 12ms 임. 서로 기다릴 이유가 없는 읽기를
한 커넥션에서 순차로 내면 그 왕복이 그대로 더해짐.

- config_db.run_with_connection: 저장소 함수를 자기 커넥션으로 돌려 gather 로
  묶을 수 있게 하는 공용 헬퍼. 정의를 한 곳에 둠(drainage_context 의 _query 는
  이 함수를 가리키는 이름으로 정리).
  머리에 경고 적음 — 순서가 필요한 쓰기는 이걸로 묶으면 트랜잭션이 깨짐.
- B04_PreProcess_Router_Watershed._prepare: 저장경로·좌표계·지표면확정값
  세 건을 gather 로. 약 24ms 절약.

common_util_auth_repository.py:318(decide_join_request)은 FOR UPDATE + 순서 있는
UPDATE 라 묶지 않음 — 읽기 블록만 대상.

자체검증 — 관 드래그 왕복 305 -> 259ms(최소 193), 관 11 · 유역 11 로 값 동일.
전체 484 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
측점마다 SELECT+UPDATE 두 왕복을 냈고 DB 가 원격이라 왕복 하나가 약 12ms.
22행이면 670ms 이고 측점 수에 선형으로 늘었음(보조 창 서버 내부 측정).

- B06_Section_Repository_Bulk.merge_cross_section_designs 신설 — 노선 측점을 한 번에
  읽고, 파이썬에서 chainage 를 맞춰 JSON 을 합친 뒤
  `UPDATE ... SET data = CASE id ...` 한 문장으로 되돌려 씀(없는 행은 다중 INSERT).
  행 수와 무관하게 왕복 두 번. Repository 가 685줄이라 파일을 나눔(700줄 한계).
- 부르는 자리 셋을 묶음으로 바꿈 — _apply_section_edits 의 기본설계·측점 patch 두 루프,
  _recompute 의 보정·면적 두 루프.

자체검증(공용 브라우저 [저장] 3회) — sections/save 3,593ms -> 2,205 / 1,870 / 2,547ms.
버튼 전체 대기 4,137ms -> 2,624~3,415ms. 진행 표시는 2~3ms 만에 뜸.
시험 tmp/tests/test_b06_bulk_designs.py 5건(같은 JSON 결과·왕복 두 번·1cm 허용오차·
행 없을 때 INSERT·빈 목록은 왕복 0). 전체 400 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B05 진입이 간헐적으로 13~14초 멎던 원인을 CDP 프로파일로 잡음. 13,537ms 중
getVertexPosition 3,267 + intersectTriangle 3,178 + checkGeometryIntersection 3,012
+ _computeIntersections 2,198 = 11.6초가 three.js 레이캐스팅이었음.

- terrainElevation 이 점마다 Raycaster 로 지형 높이를 찾고 있었음(한 번 쏠 때마다
  삼각형 전수 훑기). 마커·측점선이 점마다 부르는 자리라 곱해짐. 이미 있던
  TerrainHeightIndex(격자 색인)로 돌리고, 색인도 지형과 한 벌로 보관(빌드 O(삼각형)).
  같은 교훈을 2026-08-23 비탈 투영에서 겪어 색인을 만들어 뒀는데 이 함수만 옛 길이었음.
- B06 카드 버튼줄 reflow 의 레이아웃 스래싱 제거 — 한 칸 옮길 때마다 scrollWidth 를
  다시 읽어 매번 강제 레이아웃을 냈음(카드 67장마다). 읽기/쓰기를 갈라 폭을 한 번만
  재고 옮길 개수를 계산. ResizeObserver 첫 호출도 건너뜀(rAF 와 겹쳐 두 번 돌았음).
- get_section_context·get_section_detail 의 순차 읽기를 asyncio.gather 로 묶음
  (원격 DB 왕복 약 12ms/질의).

자체검증(공용 브라우저 4왕복) — B05 진입 14,708/1,060/14,841 -> 1,269/806/726/746ms.
급등 사라짐. B06 진입 2,884 -> 2,330~2,864ms(긴 작업 합 2,313 -> 1,853).
시험 400 통과·17 건너뜀, typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
route/confirm 이 측점마다 종단 정본을 다시 열고(13.8ms) 행마다 DB 에 썼음(24.5ms).
건당 38.3ms 라 30건이면 1.15초, 67건이면 2.57초로 측점 수에 선형으로 늘었음
(보조 창 서버 내부 측정).

- 다시 계산할 측점을 먼저 고른 뒤 asyncio.to_thread 를 **한 번만** 돌림. 그 안에서
  종단 정본과 포장 제안표·세월교 하강표를 한 번 읽어 측점마다 돌려 씀.
- read_cross_design_inputs 에 preloaded 인자 추가(종단 경로·내용·포장 제안표).
  경로 검증은 resolve_longitudinal_path 로 떼어 재사용.
- 쓰기는 merge_cross_section_designs 한 문장.

자체검증(공용 브라우저 [저장] 3회) — route/confirm 470~834ms -> 324/351/356ms.
버튼 전체 대기 2,624~3,415ms -> 1,826/2,766/2,979ms.
(오늘 누적: 4,137ms -> 1,826~2,979ms) 시험 400 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
카드마다 requestAnimationFrame(reflow) 을 걸어 한 프레임에 67번 돌았고, 매번
쓰기 뒤 읽기라 강제 레이아웃이 67회 났음. 한 번의 강제 레이아웃이 그때까지 들어간
카드 전부를 다시 재므로 뒤로 갈수록 비쌌음(보조 창 CPU 프로파일: 자기 시간 1위).

- reflow 를 reset(쓰기) / measure(읽기) / apply(쓰기) 세 토막으로 가름.
- 모듈 단위 scheduleReflow 가 카드를 모아 한 프레임에서 전부 reset -> 전부 measure ->
  전부 apply 순으로 돌림. 강제 레이아웃 프레임당 1회.
- ResizeObserver 는 창 크기 변경 때 그 카드만 큐에 다시 넣음(첫 호출 건너뛰기 유지).

자체검증(공용 브라우저) — B06 진입 2,330~2,864ms -> 1,994/2,088ms,
긴 작업 합 1,853 -> 1,604/1,728ms. 동작 확인: 카드를 200px 로 좁히면 버튼 3개가
... 패널로 옮겨지고 되돌리면 복귀(정상 폭에서는 scrollWidth = clientWidth = 937 로
넘침 없음). typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
배분·운반거리 산식(_balance 523 + _settle 235 = 758줄)을 브라우저 번들에서 빼기 위한
배선. 계산은 여전히 한 벌 — 서버가 같은 TS 를 Node 로 돈다(CLAUDE.md 5장).

- POST /projects/{id}/sections/{route_id}/haul-plan 신설
  (B06_Section_Router_HaulPlan.py). 브라우저가 낸 누가토량 결과를 받아 배분만 돌려줌.
  화면이 쓰는 꼴 그대로 내보내 그리기 코드를 안 건드림. 표시 전용 — 정본은 저장 때 따로.
- B05_Profile_Api_HaulPlan.ts 신설 — 편집이 멈추면(400ms) 조용히 받아 두는 선반입기.
  늦게 온 응답은 버림(최신 요청만 채택). 못 받아도 곡선 자체는 그대로 보임.
- common_util_mass_haul.massHaulPayload 가 배분을 값으로 물던 것을 끊음(extra 인자).
  이 커플링 때문에 화면에서 안 불러도 번들에 남았음.
- 저장 경로는 곡선도 배분도 안 만듦 — 서버가 정본을 내므로 balloon 위치만 보냄.
- 죽은 파일 B06_Section_UI_Section_View_MassHaul.ts(236줄) 삭제.

자체검증(공용 브라우저, 용화 route 149) — 엔드포인트 200 · 196ms.
서버 배분과 브라우저 computeHaulPlan 결과가 JSON 문자열까지 동일(blocks 1 · steps 2 ·
spoil/borrow/hauled/transferred/fill_total 전부 일치). 시험 400 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
행 높이를 재는 1차와 실제 그리는 2차가 같은 측점의 crossPlotMetrics 를 각각 계산했음.
측점 67곳 기준 3.2ms/장이라 진입에서 draw 자기 시간 213ms 의 대부분이었음
(보조 창 CPU 프로파일).

- crossPlotMetrics 를 crossPlotBase(강제 높이 전) + crossPlotFromBase(높이만 얹기)로
  가름. 기존 시그니처는 둘을 잇는 감싸개로 유지.
- Section_View 1차에서 base 를 만들어 2차 카드에 그대로 넘김.
- 1차 반폭도 카드가 실제로 쓰는 값(effectiveCardHalfWidth, 자동 줌아웃 포함)으로 맞춤 —
  전에는 1차가 원래 반폭으로 재 카드·행 높이 기준이 어긋났음.
- 쓰이지 않게 된 crossCardNaturalHeight 와 그 재수출 삭제.

자체검증(공용 브라우저) — 카드 67장·SVG 67개 그대로, 같은 행 카드 높이 통일 유지
(rowsUniform true), 높이 범위 292~1,119px. 시험 400 통과·17 건너뜀, typecheck 통과.
효과 수치는 보조 창의 격리된 프로젝트에서 3회 중앙값으로 재기로 함(내 창은 편차가 큼).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- schedule 호출이 draw 의 접힘 가드 뒤에 있어 패널을 접어 두면 한 번도 안 불렸음.
  그래서 「편집이 멈추면 조용히 받아 둔다」가 성립하지 않고 펼친 뒤에야 첫 요청이 나갔음
  (보조 창 실측: 편집 6회에 요청 0건). 접힘 여부와 무관하게 지나는 emitSummary 로 옮김 —
  거기서 이미 고른 결과를 쓰므로 계산 비용 0.
- 응답이 오면 곡선을 다시 그리고, 그리기가 다시 schedule 을 불러 요청이 끝없이
  되돌아왔음. 입력 표식(측점 수 + 마지막·중간 누계)을 두어 같은 값이면 안 보냄.

자체검증(공용 브라우저, 패널 접은 채 계획고 6회 편집) — 요청 1건, 그 뒤 4초 동안
추가 0건. 고치기 전에는 편집 중 0건 + 펼친 뒤 1건 + 되먹임 1건이었음.
시험 400 통과·17 건너뜀, typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표식(측점 수 + 누계)만으로는 부족했음 — 응답을 반영해 다시 그린 뒤 누계가 아주 조금
달라지는 경로가 있어 편집이 멈춘 뒤에도 2~3바퀴가 더 돌았음(보조 창 10초 관찰:
2.8~6.3초에 걸쳐 3건).

onReady 로 다시 그리는 동안 applying 을 세워 그 그리기가 거는 schedule 을 무시함.

자체검증(공용 브라우저, 접은 채 계획고 6회 편집 후 10초 관찰 3회) — 3/3/1건 -> 2/1/1건.
편집하는 동안은 종전대로 0건(400ms 안정화 유지). typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확인(2026-09-06) — 예상노선은 폴리라인이 아니라 점 묶음이고 규칙 없는
폴리라인과도 맞지 않음. 그래서 계획노선은 원데이터를 복사해 폴리라인으로 바꾼 것이어야
하고 그것이 불변의 초기 데이터가 됨. 곡선 기준은 지식DB(별표2 I.2.다) 값을 씀.

- common_util_route_polyline.py 신설 — 점 묶음을 폴리라인으로.
  ① Douglas-Peucker 로 꺾임점(IP)만 남김. 예상노선은 격자 탐색이 낸 조밀한 점군이라
     (용화: 1,097m 에 331점) 점마다 곡선을 끼우면 접선 자리가 1.5m 뿐이라 R 이 2~6m 로
     뭉개짐. 허용오차는 격자 해상도(2m)의 두 배.
  ② 내각 155도 이상은 곡선 생략(별표2), 그 아래는 최소곡선반지름으로 원호를 끼움.
     자리가 모자라면 반지름을 줄이되 막지 않고 위반으로 표시(사용자 확정: 경고만).
  ③ 점은 옮기지 않음 — 노드는 원본 자리에 그대로 두고 그 사이에 원호를 넣음.
- planned_route_initial_path 신설 — 세 벌 구조(예상노선 점 묶음 / 초기 폴리라인 /
  수정본). load_design_route 읽는 순서에 초기 폴리라인을 예상노선보다 앞에 끼움.
- 최소곡선반지름은 임도 종류·설계속도·지형으로 고름
  (FOREST_ROAD_PROFILE_CRITERIA[min_plan_radius_m], 못 읽으면 가장 완화된 조건).
- GET /route/plan 이 노드(반지름·내각·위반)까지 함께 돌려줌 — 노드만 옮기면 선이
  저절로 규칙을 지키게 하는 것이 목적. POST /route/replan 도 받은 노드로 다시 폴리라인화.

자체검증(용화, 실화면 API) — 예상노선 331점 -> 편집 노드 25개 + 곡선 13곳
(전부 R 12m = 설계속도 20·특수지형 법정 하한, 위반 0) -> 계획노선 정점 142개. 응답 180ms.
단순화 전에는 곡선 15곳이 R 2.75~6.51m 로 전부 위반이었음.
시험 tmp/tests/test_route_polyline.py 7건(원호가 접선과 맞물리는지 좌표로 대조).
전체 407 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 2-2. 3D 픽·사이드 목록에는 structure-pick 기록이 있는데 종단 그래프 알약 경로에만
빠져 있었음 — 세션 키가 아예 안 써져 B06 이 잡을 값이 없었음(보조 창 추적).

- 구조물 브리지에 markChainage 추가 — 알약 id 의 누가거리를 구조물 정본·관 정본 양쪽에서
  되읽음.
- Page 의 onStructureSelect 가 writeStructurePick 으로 그 자리를 남김(사이드 목록 경로와
  같은 창구).

자체검증(공용 브라우저, 용화) — 알약 18개 중 셋을 눌러 세션 키가
찰쌓기 1 -> {at:40} · 찰쌓기 3 -> {at:80} · 옹벽 -> {at:120} 으로 써짐(전에는 null).
그 상태로 B06 진입 시 측점 6+0.0(120m) 카드가 선택된 채로 뜸. typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Douglas-Peucker 허용오차는 절대 거리라 굴곡이 완만하고 길수록 통째로 삼켜짐.
4.5km 노선에서 노드 20개(간격 238m)만 남았음(보조 창 실측 5개 표본).

- 남은 노드 사이가 100m 를 넘으면 그 구간만 허용오차를 절반으로 낮춰 다시 뽑음
  (최대 3겹: 4 -> 2 -> 1 -> 0.5m). 노선 길이로 허용오차를 바꾸면 짧고 급한 굴곡이 다시
  뭉개지므로 벌어진 구간만 고름.
- shapely 대신 색인을 돌려주는 Douglas-Peucker 를 직접 둠 — 되뽑기가 원본 구간을 다시
  꺼내야 해서 색인이 필요함. 새 점은 만들지 않음(노드는 언제나 원본 자리).

반지름을 원본 굴곡에서 재어 키우는 방법도 시험했으나 되돌림 — 직각 꺾임에서 R 70m ·
중앙종거 20m 가 나와 원본과 크게 어긋났음. 중앙종거 M = R(1/cos(delta/2) - 1) 이라
R 이 클수록 원호가 꺾임점에서 멀어짐. 법정 하한이 사용자가 지시한 기준값이자 원본에
가장 가까운 값이므로 그대로 둠. 곡선별 R 조정은 노드 편집 기능으로 분리(PLAN 0-10).

자체검증 — 1.1km 노선 3개: 노드 25 -> 28, 곡선 13, 위반 0, 최대 간격 82m.
4.5km 노선: 노드 20 -> 24. 그 노선의 최대 간격 1,300m 는 알고리즘 문제가 아니라 실제
직선 구간임을 확인(원본 점 간격 중앙 3.3m · 최대 3m 로 고르고, 내각 최소가 158°).
시험 2건 추가(완만한 굴곡이 살아나는지 · 되뽑기가 원본 점만 남기는지). 전체 409 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-06) — 노드를 제어해 계획노선을 고친다. 그동안 모달은 서버가 준
폴리라인 정점을 그대로 잡았는데, 거기에는 원호 위 점이 섞여 있어 편집 대상이 아님.

- 그려 보이는 선(폴리라인, 원호 포함)과 잡는 점(노드)을 나눔. 선은 plannedLine,
  노드는 서버가 내려 준 nodes.
- 노드에 붙은 반지름·내각·법정 위반을 화면에 실음 — 위반 노드는 붉게, 상태줄에
  곡선 수와 기준 R, 미달 개수.
- 노드를 옮기면 폴리라인은 낡은 값이므로 지우고 직선으로 미리 보임. 곡선은 [확인] 때
  서버가 같은 R 규칙으로 다시 끼움(계산을 두 벌로 짜지 않음).
- API 타입에 nodes·min_radius_m·curve_count·violation_count 추가.

자체검증(공용 브라우저, 용화) — 모달이 노드 28개로 열리고 상태줄에
「노드 28개 · 초기 폴리라인 · 곡선 13곳(R 12m)」. 전에는 폴리라인 정점 142개를 잡았음.
typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
손 안 댄 프로젝트를 열면 저장본 열쇠가 맞아 매번 16.9MB 를 받았고, 브라우저 보관이
모듈 Map 이라 새로고침 한 번에 날아가 또 받았음(보조 창 실측: 첫 로그인~B05 도달 29MB
중 16.9MB 가 이것). 해시 질의(0b30f5b0)는 낡았을 때만 막았지 맞을 때는 그대로였음.

- b_asset_cache 에 readCachedBytes / writeCachedBytes / purgeAssetsWithPrefix 추가.
  앞 둘은 네트워크를 안 타는 순수 보관함 접근이고, 마지막은 주소 앞머리가 같은 옛
  보관본을 지움 — 코리도는 주소에 열쇠가 박혀 정본이 바뀌면 새 주소가 되므로 17MB 짜리가
  쌓이지 않게 담기 전에 치움.
- 코리도 조회가 보관함을 먼저 봄. 주소에 열쇠가 있어 정본이 바뀌면 저절로 다른 주소가
  되므로 옛 보관본을 잘못 쓸 일이 없음.

자체검증(공용 브라우저) — 담기·읽기 왕복 정상(44바이트 왕복, 해시 보존), 열쇠만 다른 두 벌을
담은 뒤 앞머리 지우기로 둘 다 제거 확인. typecheck 통과.
※ 실제 16.9MB 절감은 저장본이 최신인 프로젝트에서 확인해야 함 — 이 프로젝트는 검증 중
계획고를 만져 저장본이 낡은 상태라 코리도 자체가 안 실림(__corridorSource null).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보조 창이 노선 편집 [확인] 실측에서 둘을 잡음.

1. projects 에 design_speed_kph / terrain_type 컬럼이 없음(있는 것은 road_type 뿐).
   매 요청마다 OperationalError(1054) 가 ERROR 로그로 남고 기본값 폴백으로 넘어갔음.
   - 임도 종류는 projects.road_type, 설계속도·지형은 워크플로 stage 2 params 에서 읽음.
   - 산식은 이미 있던 B05_Profile_Engine_Grade.legal_plan_radius_min_m 를 씀 —
     내가 같은 표를 다시 짜 두었던 것을 지움(중복 제거).
2. 재확정 체인이 solve_route 400 으로 끊길 때 상태 코드만 남겨 원인을 못 짚었음.
   본문(사유)까지 로그에 남김. 노선 편집 [확인]이 조용히 끊겨 배수유역·관은 새 노선으로
   가고 종횡단만 옛 노선에 남는 어긋남이 굳었던 자리임.

recompute 의 상세 조회와 DB 두 건도 asyncio.gather 로 묶음(원격 DB 왕복 약 12ms/질의).

시험 409 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보조 창 실측 — [확인] 이 체인 중간에 400 으로 끊겨도 route/replan 은 success 를 돌려주고
계획노선 CSV 는 이미 새 노선으로 바뀐 뒤였음. 그 결과 배수유역·관은 새 노선, 종횡단은
옛 노선으로 어긋난 채 굳고(배수관 측점 9 -> 0), 다시 누를수록 어긋남이 쌓였음
(1,097.4 -> 1,079.4 -> 1,064.7m).

- run_redesign_chain 이 중단 사유를 문자열로 돌려줌(성공은 None). 중단 지점 넷 모두.
- replan 이 쓰기 전에 이전 수정본을 쥐고 있다가 실패하면 되돌림. 처음 고치는 경우였으면
  파일을 지워 초기 폴리라인으로 돌아감.
- 실패는 409 + 사유로 응답 — 화면이 성공으로 보이던 것을 막음.

원인 자체(자동탐색이 사용자 노선을 다시 풀다 실패)는 별건으로 남음 — 로그 사유
「세그먼트 1 (BP -> CP1) 경로 탐색 실패: 종단경사 한계(26%)·최소곡선반지름(12m)·회피지역
제약으로 통과 경로가 없습니다」. 고친 노선을 그대로 받아 쓰는 입구가 필요함(PLAN 0-2 항목 9).

시험 409 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-2 항목 9 / 0-3. 노선 편집 [확인]이 재확정 체인을 타는데 그 체인이 solve_route 로
BP·CP·EP 사이를 격자에서 다시 풀었음. 사용자가 노드를 조금만 비틀어도 탐색 제약에 걸려
체인이 통째로 멈췄음(보조 창 로그: 세그먼트 1 (BP -> CP1) 경로 탐색 실패 — 종단경사
한계 26% · 최소곡선반지름 12m · 회피지역 제약).

- B05_Profile_Engine_AsPlanned.solve_as_planned 신설 — 제어점 목록이 곧 노선이고 표고만
  지표면 격자에서 뜸. 반환 꼴은 솔버와 같아 아래 단계가 그대로 이어짐.
  종단기울기·곡선반지름 위반은 **세되 막지 않음**(사용자 확정: 자동 보정·차단 없이 경고만).
- run_route_design 에 algorithm=as_planned 갈래 추가. 스키마 검증에도 허용.
- 재확정 체인이 그 갈래를 씀 — 자동탐색은 이제 초기 업로드에서만 돎.

솔버와 지표 계산이 겹치지만 합치지 않음 — 솔버는 0-3 으로 접히는 코드라 리팩터링해
두 곳을 얽을 값어치가 없음.

시험 409 통과·17 건너뜀, main import 스모크 통과.
실화면 [확인] 재검증은 보조 창이 자기 프로젝트에서 진행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보조 창 실측 — 노드를 옮겨 재계산하면 다단 구간값(extra_spans)이 0건이 됐음.
심어 둔 표식(85.18m 의 14/6/8)이 통째로 사라짐.

원인은 순서였음. 이월이 _prepare_drainage_pipes_and_reprofile(refresh=True) **앞**에서
돌았는데, 그 단계가 측점을 새 노선 기준으로 다시 만들며 방금 얹은 설계를 덮었음.

- 이월을 측점 재생성 **뒤**로 옮김. 옛 설계는 이미 old_designs 로 손에 있음.
- 행마다 쓰던 것을 merge_cross_section_designs 로 묶음 — 행 수와 무관하게 왕복 두 번
  (원격 DB 왕복 약 12ms/질의).

같은 요청에서 확인된 통과분(보조 창) — 측점 수·끝 누가거리가 새 노선과 일치(67·1,097.4m
고정 -> 64·1,079.4m), 배수관 측점 0 -> 7~9, 「세그먼트 경로 탐색 실패」 로그 사라짐.

시험 409 통과·17 건너뜀, main import 스모크 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보조 창 지적 — [3D 업데이트]를 눌러도 브라우저가 만들기만 하고 PUT 이 없었음.
저장 시점이 B05->B06 이동뿐이라(2026-08-23 확정), 누른 뒤 새로고침하면 저장본이 낡은
채라 다음 사람이 또 만들어야 했음.

- 버튼 경로 끝에서 saveCorridorIfDirty 를 부름.
- saveCorridorIfDirty 가 PUT 성공 뒤 그 봉투를 브라우저 보관함에도 담음(옛 열쇠 자리는
  치움). 그러지 않으면 다음 진입이 새 열쇠 주소로 16.9MB 를 한 번 더 받았음.

typecheck 통과. 실측 확인은 보조 창이 자기 프로젝트에서(저장본이 최신인 자리) 진행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-10. 그동안은 화면이 route/plan 을 처음 부를 때 만들어져, 화면을 안 열면 값이
없었음 — 초기값은 서버가 낸다는 0-4 원칙과 어긋났음.

- 파일입력 자동설계 체인이 예상노선 정본을 남긴 직후(2.6단계) 초기 폴리라인도 세움.
  실패는 비치명적 — 없으면 화면이 처음 열릴 때 만들어짐.
- _ensure_planned_initial 이 **낡음도 본다** — 예상노선 파일이 더 나중에 쓰였으면 다시
  만듦. 파일을 다시 올리면 예상노선이 새로 깔리는데 초기본이 옛 노선인 채로 남으면
  노선 초기화가 옛 자리로 돌아갔음.

자체검증 — 예상노선 파일 시각을 최신으로 만든 뒤 route/plan 을 부르니 초기 폴리라인이
다시 만들어짐(노드 28 · 곡선 13 그대로). 시험 409 통과·17 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
링크 카드는 소유 측점의 벽을 빌려 그리는데, 빌릴 벽이 없는 카드에도 버튼이 떠 눌러도
아무 일이 없었음 — revetlink 에 detached 만 쌓였음(보조 창 실측: 0·20·40·60·80m 카드).
linkState 가 drawnWallKeys().length 도 함께 보게 함.

계획서 3-4 실화면 확인도 함께 마침(공용 브라우저, 용화):
- 벽이 있고 연동이 켜진 카드 820.00m 에서 [연동]을 끄자 revetx 에 820.00:outlet h=1.8 이
  적힘 — 푸는 순간의 높이가 그 측점 값으로 굳음.
- 그 뒤 소유 측점 821.62m 높이를 4.2m 로 올려도 820.00m 은 1.8m 그대로 — 따로 놂.
※ 앞서 안 굳는 것으로 본 것은 측정 오류였음. 패널이 카드마다 하나씩 67개인데 첫 번째
   패널만 봤고, 벽이 없는 카드를 골랐음(보조 창이 가려냄).

시험 409 통과·17 건너뜀, typecheck 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
자동 체인 2.7 단계 추가 — 초기 폴리라인을 세운 뒤 노선을 다시 읽어
그것을 BP·경유점·EP 로 세우고 algorithm=as_planned 로 넘김.

전에는 폴리라인 파일만 만들고 노선은 원본 점군으로 풀었음. 그래서
종횡단 측점·유토곡선·3D 코리도가 곡선 없는 점군 위에 섰음.
실측(용화 3건): DB 노선 정점 331·323 vs 초기 폴리라인 145.
노선을 한 번이라도 편집한 프로젝트만 145 로 맞아 있었음.

자체검증 — 2.7 재판독이 145 정점을 돌려주고 BP·EP 좌표가
expected_route.csv 첫·끝 줄과 같음. pytest 409 passed.

계측 로그(_log_steps) 동봉 — 재확정 체인 단계별 경과시간용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-10. 8000 에서 1회 실측 결과 재확정 체인 292.9s 중 배수유역 분석이 285.0s(97%)로
나와, 그 안쪽을 가르기 위한 마크만 추가. 로직 불변.

- B06 확정: 조회 / 기본설계 계산 / 확정 저장 / 서버 재계산 / 측구 역반영
- 서버 재계산 내부: 상세+DB 병렬 조회 / 포장·세월교 보정 / Node 번들 / 정본 저장
- 배수유역 분석 내부: _prepare(도엽 읽기·좌표변환) / preview_stages / 응답 만들기·저장
- preview_stages: 1차 영역 / 격자 확장·흐름 판정 / 흐름 강도 / 외곽선·기본 관·화살표

`_log_steps` 는 체인 모듈 것을 그대로 씀(지연 임포트로 순환 회피).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
노선 [확인] 이 293초였고 그중 285초가 배수유역 분석, 다시 그중 256초가
1차 영역 만들기였음. 범인은 ElevationSampler 하나임 —
LinearNDInterpolator 가 들로네 삼각망을 첫 호출 때 만드는데 등고선 구름을
통째로(용화 317,348점) 넘겨 그 한 번이 256~1,481초로 뛰었음(편차 큼).

표고를 묻는 자리는 도로 교차 노드에 닿은 세류 조각 몇 개뿐임. 그 조각들만
먼저 골라 그 둘레 100m 안 등고선만 남기고 삼각망을 만듦. 여유 100m 는
등고선 재샘플 간격(5m)의 스무 배라 물어볼 점은 언제나 볼록껍질 안쪽이고
보간값이 그대로임.

실측(용화 5601e828) — 보간 구름 317,348 → 4,367점,
1차 영역 256.6s → 43.8s(측정 중 기기 부하가 9배였음, 준비 5.1s → 45.7s).
결과 완전 동일 — 1차 영역 266,697㎡ · 격자 545×835 · 268,456셀 ·
노선 이탈 0m/1079m · 상류망 1 / 하류망 109 / 미연결 1153.

pytest 409 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`marks` 정의가 `save_sections` 에 들어가고 사용은 `confirm_sections` 에 남아
`NameError: name 'marks' is not defined` 로 [확인] 재계산이 500 으로 끝났음
(노선은 자동 롤백돼 자료 손상 없음). 정의를 쓰는 함수 안으로 옮기고
`save_sections` 의 잘못 들어간 두 줄 제거. 계측 항목은 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 「사용자 조작값」 목록이 세 곳에 흩어져 있었고 서로 달랐음.
브라우저(B06_Section_Cross_Refresh.ts PRESERVED_KEYS)는 extra_spans 를
살렸는데 서버 두 곳은 안 살렸음 —

  - B06_Section_Router_Design._USER_TOUCHED_KEYS (포장 강제 재계산 ·
    세월교 노면 하강 재계산이 씀)
  - B06_Section_Router 안의 인라인 사본 (단측점 설계 갱신)

그래서 포장 구간이나 세월교가 앉은 측점이 다시 계산되면 사용자가 넣은
다단 구간값이 조용히 사라졌음.

_USER_TOUCHED_KEYS 를 공개 이름 USER_TOUCHED_KEYS 로 바꾸고 extra_spans 를
넣음. 라우터의 인라인 사본을 지우고 그 한 벌을 씀.

시험 tmp/tests/test_b06_user_touched_keys.py 3건 신설 — 서버 목록에
extra_spans 가 있는지, 서버와 브라우저 목록이 같은지(status ·
pavement_suggested 는 부르는 쪽이 붙이므로 제외), 라우터에 사본이
남지 않았는지. 목록이 다시 갈라지면 시험이 깨짐.

pytest 412 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보간 구름을 물어볼 자리 둘레 100m 로 좁힌 뒤(9317ad31), 그 둘레에
등고선이 없는 자리는 볼록껍질 밖이라 최근접 정점 값으로 빠짐. 그 값은
등고선 간격(5m)만큼 틀릴 수 있고 그러면 그 조각의 상·하류 판정이 갈림.

용화 자료에서는 안 일어났으나(판정값 일치) 다른 현장에서 조용히 갈릴 수
있어 몇 점이 빠졌는지 한 줄로 남김. 계산은 안 바뀜.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-10. 1차 영역이 2.6초로 떨어진 뒤 남은 병목이 `expand_by_red_boundary` 102초라
그 안을 가르기 위한 계측. 로직 불변.

- 확장 회차별 시간·격자·셀 수·방향장 재사용 여부를 한 줄씩
- 격자 해석 1회: 하강 방향장(재사용/새로) / 지형 조립 / 도로 굽기 / 세류 새김 / 도달 판정
- 하강 방향장: 등고선 굽기 / 밴드 표고(EDT 1회) / 밴드별 하강거리(EDT N회) /
  위치에너지 조립 / 흐름 경로

실측 로그상 방향장이 회차마다 새로 만들어지고 밴드가 100단이라, 격자 전체 EDT 가
회차당 100회씩 도는 구조로 보임 — 그 가설을 수치로 가르려는 것.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 노선으로 [확인]을 되풀이하면 계획노선 정점이 136 → 134 → 119, 노드가
22 → 21 로 계속 줄었음(보조 창 실측). 사용자가 아무것도 안 옮겨도 누를
때마다 자기 노선이 뭉개졌음.

원인은 **이미 폴리라인인 것을 다시 단순화**한 것. 두 자리 모두 그랬음 —
  - read_route_plan 이 노드를 계획노선(원호 점이 섞인 폴리라인)에서 되뽑음
  - replan_route 가 화면이 보낸 노드를 또 한 번 단순화해서 씀
단순화(Douglas-Peucker)는 원본 점군에서 한 번만 돌아야 함.

고친 것:
  - build_planned_polyline 에 simplify 갈래 신설. False 면 받은 점을
    꺾임점으로 그대로 씀(중복 제거만).
  - 폴리라인을 쓸 때 그것을 낳은 **노드도 함께 저장**
    (planned_route_nodes.csv · planned_route_initial_nodes.csv).
    노드는 폴리라인에서 되뽑을 수 없으므로 낳은 값을 보관함.
  - read_route_plan 은 저장된 노드를 그대로 씀(없는 옛 프로젝트만 뽑음).
  - replan_route 는 simplify=False 로 씀.

실측(용화 b269ea34 실제 노선 파일, 4회 왕복)
  옛 방식  노드21/정점115 → 20/115 → 20/113 → 20/115  (깎이고 흔들림)
  고친 방식 노드21/정점115 → 이후 매 회차 **완전히 동일**

시험 tmp/tests/test_route_polyline_idempotent.py 2건 신설 — 노드 왕복이
제자리인지, 그리고 옛 방식이 실제로 깎이는지(갈래가 필요한 이유) 못박음.
pytest 414 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-10. 확장 95.8s 중 밴드별 EDT 가 50.4s 였음 — 단계마다 격자 전체를 훑는데
정작 쓰는 값은 그 단계 밴드 셀뿐임.

- 격자를 256칸 타일로 나눠 **셀이 있는 타일만** 둘레 32칸까지 잘라 EDT 실행.
  `analyze_domain` 이 domain 을 안 넘겨 밴드가 전역에 흩어지므로 바운딩박스 하나로는
  안 좁아짐 — 타일이라야 좁아짐.
- 창 안 최대 거리가 여유에 닿거나 창에 낮은 라인이 없으면 **그 단계를 전체 격자로 다시**
  — 근사가 아니라 같은 값을 싸게 구하는 것. 폴백 횟수는 계측 줄에 찍음.
- `return_indices` 가 주는 창 좌표에 창 원점을 더해 전체 격자 좌표로 되돌림.

자체검증 — 실제 자료(745×1035·166단, EDT 도는 91단)에서 전체격자 10.8s → **2.9s**,
폴백 9/91, 거리·목표행·목표열 **전부 `np.array_equal` 동일**. `build_contour_descent`
결과(band_elevation·valid·receiver·step_length·azimuth·levels)도 옛 코드와 완전 동일.
여유·타일 선택 근거는 파일 주석의 실측표 참조. 시험 500 통과·18 건너뜀
(기존 실패 8건은 다른 환경의 JS 도우미 문제로 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-10 이어짐. 첫 판에서는 창이 모자란 단계를 **격자 전체**로 되돌렸는데, 격자가
커질수록 그 폴백이 25/91 까지 늘어 이득이 대부분 사라졌음(실측 확장 97.7s).

- 모자란 타일만 창을 4배로 넓혀 다시 잼. 단계 전체를 되돌리지 않음.
- 타일 256 → 128 (실측: 128/여유32 2.1s vs 256/여유32 2.7s).
- 넓힘 횟수를 계측 줄에 남김(폴백 대신).

자체검증 — 전체격자 5.2s → 2.1s(넓힘 15/91), 거리·목표행·목표열 전부 동일.
`build_contour_descent` 결과도 옛 코드와 완전 동일(8.0s → 5.1s). 시험 500 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 0-10. 「등고선 굽기」가 확장 8회 합 19s 였는데, 실측해 보니 굽기 자체는 0.8~2.0s
이고 나머지는 **피처 4,200개를 회차마다 다시 `shape()` 로 푸는 값**이었음. 푸는 결과는
격자와 무관하므로 같은 목록·같은 하한이면 그대로 쓴다(목록 객체를 함께 들고 있어 id 가
다른 목록에 재사용되지 않음, 최근 2벌만 보관).

실측 — 같은 격자 연속 4회: 2.66 · 1.90 · 1.99 · 2.03s (2회차부터 파싱 재사용), 결과
배열은 4회 모두 동일. `build_contour_descent` 전체는 옛 코드 12.8s → 7.2s 이며
band_elevation·valid·receiver·step_length·azimuth·levels 전부 `np.array_equal` 동일.

안 한 것 — 격자가 커질 때 옛 굽기를 옮겨 붙이고 **테두리만** 굽는 안은 만들어 재 봤으나
`rasterize` 호출당 고정 비용 때문에 오히려 3.2s → 10.6s 로 느렸고, 창에 걸치는 선만
넘기도록 고쳐도 3.8s 로 손해였음(창 4개 × 166단). 그래서 걷어내고 파싱 캐시만 남김.
`levels` 는 피처 전체에서 나오므로 격자와 무관하다는 것도 확인함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
uvicorn StatReload 는 0.25초마다 지정 폴더를 rglob("*.py") 로 재귀로 훑는데,
폴더를 안 주면 현재 폴더가 대상이라 storage(27GB) · venv(파이썬 파일만
7,530개) · node_modules 까지 통째로 돌고 있었음.

파이썬이 실제로 사는 폴더 14개만 감시하게 함(산출물·의존성·백업 제외).
루트는 넣지 않음 — 넣으면 재귀라 도로 다 훑음. 그 대신 main.py 를 고칠 때는
서버를 손으로 다시 띄워야 함.

⚠ 이 변경이 「요청 없는 서버가 CPU 70%」를 고치지는 못했음. 그 CPU 는
감시 프로세스(0%)가 아니라 **앱 프로세스** 쪽이며 원인 미상 — 계획서에
남겼음. 이 커밋은 감시 낭비만 걷어낸 것임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
앞 커밋(351db312)이 storage·venv 는 뺐으나 `config` 가 남아 있었음.
그 안에 `node_modules` 가 있어 0.25초마다 의존성 트리를 훑고 있었음.

`node_modules` 를 품은 폴더는 감시에서 제외. 그 결과 `config/` 를 고칠 때는
`main.py` 와 마찬가지로 서버를 손으로 다시 띄워야 함 — 둘 다 자주 고치는
자리가 아님.

⚠ 측정 메모 — 루트 전체 훑기는 이 기기에서 **300초에도 한 줄을 못 뱉었음**
(옛 방식이 0.25초 주기를 지킬 수 없었다는 뜻). 다만 지금 기기가 계속
눌려 있어(서버 둘이 놀면서도 각 70%) 정확한 전후 수치는 못 냈음.
그 CPU 자체는 별건으로 계획서에 남겨 둠.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 3-5 ⓑ (2026-09-07 사용자 확정 「옹벽도 수량이 변경되어야 함」).

그동안 면적 폐회로의 바깥 경계가 **기준벽 사면(노견~벽 상단)** 까지만이었고 그 바깥은
원지반으로 봐서 면적 0 이었음. 그래서 단을 몇 개 올려도 절·성토가 한 자리도 안 변했음.

- 화면이 그리는 선(`outletFill.segments`·`basinFill.segments`)을 트림 사면에 이어 붙임.
  「면적은 실제로 그려지는 설계선을 따른다」는 기존 원칙과 같은 자리로 맞춘 것.
- 그리지 않는 `cut` 갈래(벽이 원지반에 묻혀 성토가 없는 자리)는 뺌 — 화면과 같은 규칙.

실측(용화 route 165, 새 트림 대 옛 트림):
  81.77m  0단 성토 8.4247 → 10.9027(+2.478) · 1단 이상 10.6743(+2.250) · 절토 불변
  244.14m 지형이 단을 거부(0단) · 성토 3.3492 → 4.0511(+0.702) · 절토 불변
  423.55m 벽이 묻힌 자리(cut) · 성토 3.6145 그대로 · 변화 없음
→ 단이 서면 성토가 줄고(10.90 → 10.67), 단이 안 서는 자리도 **벽 바깥 성토가 이제
  잡힘**. 후자는 단과 무관한 변화라 보고에 따로 적었음.

파이썬 짝은 없음 — 구조물 트림 면적은 TS 한 벌이고 서버는 그것을 Node 로 돌림
(`B06_Section_Engine_Areas.py` 는 구조물 없는 표준 계산). tsc 통과·시험 500 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
앞 커밋이 바로 밑의 node_modules 만 봐서 새는 곳이 있었음 —
`B07_DesignDetail/openwebcad/node_modules`(15,944개)와
`A00_Common/config/node_modules`. 그 폴더들이 0.25초마다 통째로 훑히고 있었음.

한 겹 아래(`*/node_modules`)까지 보고 제외.

실측 (놀고 있는 서버, 같은 기기·같은 절차) — **CPU 85.2% → 18.3%**.
감시 대상은 파이썬 143개 · 하위폴더 39개로 줄었음.

⚠ 원인 규명은 보조 창 몫이 컸음 — 프로세스 역할이 뒤바뀌어 보였음(내가
띄운 것은 껍데기, 그 자식이 리로더, 손자가 실제 서버). 부모만 보고 재면
0% 로 보여 「앱이 먹는다」로 두 번 오진했음. 갈래 실험(reload 끔 0% /
켬 64%)이 그것을 갈랐음.

남은 18% 는 감시 탓으로 보기 어려움(파일 143개) — 별건으로 남김.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보조 창이 원인을 확정함 —
  B07_DesignDetail\openwebcad\node_modules\forest-road-webapp
     → Junction → 저장소 루트 자신 (npm 이 만든 로컬 패키지 링크)
리로더가 B07 을 훑다가 그 정션으로 루트로 되돌아가고, 거기서 venv·storage 로
다시 들어가며 무한히 되감겼음.

실측 — 감시 폴더를 rglob 하면 파일 486,809개 · 한 바퀴 1,045초.
PowerShell 로 세면 config 4개·B07 23개뿐임. 파이썬 rglob 은 정션을 따라
들어가고 PowerShell 은 안 따라가서 눈으로는 안 보였음.

링크(정션) 폴더를 통째로 건너뛰게 함 — 정션이 또 생겨도 재발 안 함.
앞 커밋(e7d30327)이 node_modules 품은 폴더를 빼며 이번 건은 이미 덮었으나
(CPU 85% → 18%), 그건 우연히 막힌 것이라 원인 자체를 막음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07) — 「계획노선은 직선>곡선>직선 형태의 폴리라인임.
반지름은 법정 최소 값을 지키되 기존 예정노선에 가까운 폴리라인을 찾는 게 키임.」
되물어 확정: 반지름 상한은 두지 않고 원본에 가장 가까운 값으로.

옛 방식은 꺾임점마다 법정 하한(R 12m) 원호를 하나씩 끼웠음. 그래서 완만한
긴 곡선이 작은 원호 여러 개로 쪼개져 원본과 벌어졌음.

고친 것 셋
  1. 이어진 꺾임을 **한 곡선으로 묶음**(_curve_runs). 같은 쪽으로 도는
     꺾임을 모으고, 앞뒤 직선을 늘려 만나는 자리를 그 곡선의 교각점으로 씀.
  2. 그 안에서 **반지름을 골라 맞춤**(_fit_radius_m) — 법정 하한 이상에서
     예정노선 점들과의 평균 벗어남이 가장 작은 값.
  3. 묶는 것이 손해면 **도로 쪼갬**(_split_wide_runs) — 평균이 나빠지거나
     한 자리라도 8m 넘게 벌어지면 낱개로 둠.

별표2 의 155°(곡선 생략) 규칙은 **묶은 뒤 전체 교각**에 적용하도록 자리를
옮김. 조각 하나하나에 적용하면 완만한 곡선이 쪼개졌음(내각 156·138·154°
짜리 세 꺾임이 갈려 가운데 하나만 곡선이 됐음).

실측 — 흉내낸 매끄러운 곡선에서 원본 반지름을 되찾음
  원본 R 25m → 25.1m (최대 벗어남 0.12m)   전에는 R 12·12·12m, 1.66m
  원본 R 40m → 39.8m (0.09m)               전에는 R 12·12·12m, 2.66m
  원본 R 80m → 78.2m (0.44m)               전에는 R 12 다섯 개, 1.31m
실제 노선 3개(격자 탐색이 낸 지그재그)는 중립 — 최대 벗어남 3.57m 그대로,
평균 1.082 → 1.100m. 급한 꺾임에서는 하한이 이미 최선이라 그럼.

시험 tmp/tests/test_route_polyline_curve_fit.py 4건 신설 — 반지름 되찾기,
하한 지키기, 직각은 하한 그대로, 손해면 안 묶기. pytest 420 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07) — 사용자가 잡는 것은 **곡선 시작·끝점**이고 필요하면
반지름을 직접 바꿈. 정점 목록만으로는 어디부터 어디까지가 한 곡선인지,
그 반지름이 얼마인지 알 수 없어 편집·도면이 같은 값을 못 봄.

  - RouteCurve 신설 — 교각점(apex) · 반지름 · 접선길이 · 내각 ·
    곡선 시작점 · 끝점 · 그 곡선이 대신하는 꺾임점 구간 · 위반.
    반지름을 바꿔도 apex 는 안 움직임(「곡선 반지름 변경 시 주변 직선 각도
    구속」이 그 뜻 — 직선이 고정이라 접선점만 미끄러짐).
  - `planned_route_curves.json` 으로 저장(노드 CSV 옆).
  - `GET /route/plan` 이 `curves` 를 함께 돌려줌.

곁들여 고친 것 — 묶음을 도로 쪼갤 때 **별표2 의 155° 를 다시 안 봐서**
펴진 자리(내각 159°)에도 곡선이 생기고 있었음. 쪼갤 때 다시 검사함.
그 결과 용화 노선이 곡선 24 → 13곳, 정점 179 → 145 로 제자리를 찾음.

실측(용화, 예상노선 331점) — 노드 28 · 곡선 13 · 정점 145 · 위반 0 ·
벗어남 최대 3.57m 평균 1.081m(고치기 전 1.077m). 반지름은 12~28m 로
자리마다 갈림(전에는 전부 12m).

pytest 420 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 3-6 (2026-09-07 사용자 지시 5 「A군뿐 아니라 구조물 전체를 넣을 수 있어야 함」).

원인은 「B06 이 A군만 받는다」가 아니라 **레지스트리의 `enabled:false`** 였음 — B군 6종·
F군 2종·G군 1종이 목록에서 통째로 빠져 있었고, 두 화면이 같은 목록을 쓰므로 B05·B06 이
똑같이 A/C/D/E/G/기타 여섯 군만 보였음. 레지스트리 주석(2026-08-17)이 그 셋을 「B05
선택지에서 빼고 **B06 개별 횡단도 옵션으로 재사용**」이라 적어 둔 자리임.

- `fetchStructureTypes(includeDisabled)` 로 갈래를 둠. B06 만 참으로 부름 — B05 는 종전대로.
- 함께: 3-5 ⓑ 되돌릴 자리 주석(단 2개 이상일 때만 이어 붙이는 한 줄) 표시.

자체검증 — 공용 브라우저에서 두 화면 군 목록 대조:
  B06 A·**B**·C·D·E·**F**·G·기타 (8) / B05 A·C·D·E·G·기타 (6, 그대로)
  B06 에서 B군 6종(측구·산마루측구·소단측구·도수로·절토사면 배수로·맹암거)과
  F군 2종(야생동물 이동통로·비탈면 녹화)이 실제로 목록에 뜸. tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-07) — 「내각 155 이상이면 곡선 생략은 반영하지 말자.
사용자가 계획 평면 노선을 수정할 때 문제가 될 것 같아.」

곡선이 있다 없다 하면 잡는 손잡이도 있다 없다 하고, 조금 폈다는 이유로
곡선이 사라지면 되돌릴 길이 없음. 그래서 별표2 의 155° 생략 규칙을 쓰지 않고
꺾이는 자리에는 전부 곡선을 둠. 상수는 법정 근거를 잃지 않게 남겨만 둠.

실측(용화 예상노선 331점) — 곡선 13 → 26곳, 정점 145 → 181,
반지름 12~28 → 12~199m, 내각 109~177°.
벗어남은 그대로 최대 3.57m · 평균 1.081 → 1.102m (원본 충실도 유지).

시험 하나를 뒤집음 — 「펴진 자리는 곡선을 안 둔다」 → 「펴진 자리에도 곡선을
둔다」. 아주 완만하므로 원본과 거의 겹치는 것도 함께 확인.
pytest 420 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 3-6 「설치 측을 사용자가 고르게 할지(폼에 칸 추가) 뒤에 정할 것」 — 2026-09-07
사용자 확정 「폼 선택은 가능하게 반영하고 나중에 선택 비활성화로 하자」.

- 레지스트리 C군 5종(옹벽·돌쌓기(찰)·돌쌓기(메)·흙막이·큰돌쌓기)에 `side` 선택 칸.
  선택지 「자동(성토 쪽)·좌·우」, 기본은 자동 — 종전 동작(성토 나는 쪽 자동)과 같음.
- 기하는 이미 그 값을 봄 — `B06_Section_UI_Cross_Revetment.ts:168` 이 "좌"/"우" 면 그쪽,
  아니면 `fillSide()`. 배관(`common_util_structure_walls.ts:80`)·파이썬 짝도 `options.side`
  를 이미 나름. 즉 배선은 있고 **칸만 없었음**.
- 옵션 칸에 `enabled` 를 둠(기본 참). 거짓이면 폼에 **회색으로 남고** 못 고르며 필수 검사
  에서도 빠짐 — 칸을 지우지 않고 잠그는 자리(사용자 「나중에 비활성화」).

자체검증 — 레지스트리 5종 모두 `(['자동(성토 쪽)','좌','우'], 기본 '자동(성토 쪽)', enabled True)`
로 읽힘. 실화면 B06 C군 폼에 「설치 측」 칸이 그 세 선택지로 뜸(값 자동). tsc 통과.
시험 499 통과 — 실패 1·오류 8 은 모두 `require is not defined in ES module scope` 인
JS 도우미 건으로 내 변경과 무관(도우미 파일 날짜 8/27·9/2, 다른 환경에서 만든 것).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-07) — 「r과 직선 삭제나 추가가 있어야 하지 않을까?」

편집을 **꺾임점 목록 + 자리마다 곡선 켬끔 + 반지름** 셋으로 표현함.
  · 직선 삭제·추가 = 목록에서 점을 빼거나 더하기(빼면 앞뒤 직선이 하나로
    합쳐지고, 직선 위에 더하면 둘로 갈리며 그 자리에 곡선이 생김)
  · 곡선 삭제·추가 = `curve` 를 끄고 켜기(끄면 직선이 그대로 꺾임)
  · 반지름 변경 = `radius_m` 못박기(없으면 서버가 고름)

`POST /route/replan` 의 정점마다 `curve`·`radius_m` 을 받게 함.
편집값이 오면 **묶지 않음** — 사용자가 곡선 하나로 본 것을 임의로 합치면
손잡이가 사라지기 때문. 편집값은 점과 짝이라 중복 제거도 함께 함.

시험 tmp/tests/test_route_polyline_edit.py 7건 — 곡선 삭제·추가, 반지름
못박기, **반지름을 바꿔도 교각점은 안 움직임**(「주변 직선 각도 구속」),
직선 삭제·추가. pytest 427 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-07) — 「r과 직선 삭제나 추가가 있어야 하지 않을까?」
서버 쪽(f59932de)에 이어 화면을 붙임.

  - **곡선 시작·끝점을 네모로 표시** — 어디부터 어디까지가 한 곡선인지 눈으로 봄.
  - 꺾임점을 누르면 **고른 자리**가 되고 아래 편집줄이 그 곡선을 만짐.
  - **R 입력칸** — 값을 넣으면 그 반지름으로 못박고, [반지름 자동]으로 되돌리면
    서버가 예정노선에 맞춰 다시 고름.
  - **[곡선 지우기] / [곡선 넣기]** — 지운 자리는 가운데가 빈 동그라미로 보이고
    직선이 그대로 꺾임.
  - 직선 삭제·추가는 원래 있던 조작 그대로(오른쪽 클릭 삭제 · 두 번 클릭 삽입).
    다만 그때 **편집값 목록도 같은 자리에서 밀어 준다** — 안 그러면 뒤 노드의
    R·켬끔이 한 칸씩 어긋남.
  - [확인]이 정점마다 `curve`·`radius_m` 을 함께 보냄.

상태줄에 「곡선 N곳(하한 R m) · 곡선 지움 N곳 · R 지정 N곳」을 보임.

tsc --noEmit 통과 · pytest 427 passed.

남은 것 — **곡선 시작·끝점을 끌어 직선 각도와 R 을 함께 바꾸는 조작**은 다음 단계.
지금은 표시까지이고, 자리 옮기기는 꺾임점 끌기로 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실화면에서 [곡선 지우기] 클릭이 캔버스에 가로채였음 —
「<canvas …> subtree intercepts pointer events」.

원인은 세로 배치임. 상자가 세로 flex 이고 캔버스 자리가 `flex: 1 1 auto` 라
공간을 다 먹는데, 새로 넣은 편집줄에 `flex: none` 이 없어 눌려 없어지고
캔버스가 그 위를 덮었음. 바닥 단추줄과 같이 `flex: none` 을 주고
`z-index: 1` 로 올림.

실화면 재확인(용화, 20번째 꺾임점) — 네 조작 모두 동작:
  고름   → 「자동 · 내각 155° · 법정 하한 12m」
  곡선끔 → 「곡선 없음 — 직선이 그대로 꺾입니다」 · 상태줄 「곡선 지움 1곳」
  곡선켬 → 「자동」으로 복귀
  R 40   → 「값 지정」 · 상태줄 「R 지정 1곳」
  자동   → 값 비고 「자동」으로 복귀

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 2-5 (2026-09-07 사용자 지시 4 「구조물 표시 통일」). B06 종단에는 구조물 마크가
아예 없었고 배수관·세월교만 다른 계통으로 그려졌음.

- B05 가 쓰는 **같은 부품**(`buildStructureLane`)을 B06 종단 그래프 아래에 붙임.
  이름·중복 번호·툴팁·약호가 전부 B05 규칙 그대로 따라옴.
- 종단 차트가 `toX`(누가거리 → px)를 내보내 레인이 그래프와 같은 자리를 씀.
- 좌측 「구조물 배치」가 목록을 받을 때마다 `setStructureMarks` 로 넘김(구조물 정본 +
  관 정본). 관을 가상 구조물로 바꾸는 `pipesToStructureMarks` 는 B05 안에 있던 것을
  공용 자리(`B05_Profile_Api_Structures`)로 올려 **한 벌만** 둠.
- 알약을 누르면 그 자리에 가장 가까운 측점 카드를 고름(좌측 목록 클릭과 같은 규칙).
  끌기는 B05 몫이라 여기서는 자리만 보임(배수유역 재분할이 걸림).
- 검증 훅 `window.__b06Marks` 추가(`__corridorBuild` 등과 같은 용도).

자체검증 — 실화면 B06 종단에 레인 1줄·알약 10개(「배수관 1~8 · 세월교 1~2」)가 B05 와
같은 표기로 뜸. 훅 값 `{structures:10, types:36}`. tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07) — 「직선과 곡선 교차점 이동 시에는 직선의 각도와
반지름 값 변경이 되」. 되물어 확정: 끄는 점은 **곡선 시작·끝점**.

셈은 서버의 반대 방향임 — 서버는 교각점·R 에서 접선점을 내고, 화면은 끈
접선점에서 교각점·R 을 구함. 끈 쪽 직선만 돌리고 반대쪽은 옛 교각점을 지나는
그대로 두어, 두 직선이 만나는 자리가 새 교각점이 되고
R = |새 교각점 − 끈 자리| / tan(교각/2) 로 나옴.

**두 벌이 아니라 짝임** — 왕복이 제자리인지를
tmp/tests/test_route_polyline_handle_drag.py 3건이 지킴. 화면이 낸 (교각점, R)
을 서버 셈에 넣으면 끈 자리가 **1µm 안**으로 되돌아옴. 접선점을 직선 위에서만
밀면 교각점이 안 움직이고 R 만 커지는 것도 확인.

손잡이를 **속 빈 네모(5px)** 로 키움 — 3.5px 채운 네모는 선·노드와 색이 같아
눈에도 안 띄고 집기도 어려웠음(실화면). 곡선을 지운 자리에는 손잡이도 없음.

실화면 확인(용화) — 손잡이를 끌자 「14번째 꺾임점 · R 16.6 · 값 지정」으로
바뀜. 서버가 곡선 성분 22개(예: R 44.3m, 노드 1~3을 한 곡선으로)를 내려줌.

⚠ 그 확인 도중 **서버가 또 옛 코드로 돌고 있었음**(응답에 `curves` 키 자체가
없었음). 오늘 두 번째임 — 화면 검증 전에 응답에 새 필드가 있는지부터 볼 것.

tsc --noEmit 통과 · pytest 430 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실화면에서 잡음 — 곡선 하나만 지워도 나머지 반지름이 **R 12~199m → 전부 12m**
로 되돌아갔음.

원인은 편집 모델과 저장 모델이 다른 것이었음. 서버는 처음 만들 때 이어진
꺾임을 한 곡선으로 묶는데, 그 곡선의 교각점은 앞뒤 직선을 늘려 만나는 자리라
**원본 꺾임점 중 어느 것도 아님**. 편집은 「꺾임점 하나 = 곡선 하나」로
표현되므로, 묶인 채로 두면 한 번만 손대도 묶음이 낱개로 흩어지고 각 자리가
하한으로 떨어졌음.

모달이 자료를 읽을 때 **묶인 구간을 그 교각점 하나로 갈아 끼우게** 함 —
안쪽 꺾임점은 그 곡선이 대신하므로 뺌. 앞뒤 직선과 반지름이 그대로라
그려지는 선은 똑같고, 이제 손대도 안 흩어짐. 서버가 고른 반지름도 함께
들고 가 [확인] 때 되돌려 보냄.

시험 tmp/tests/test_route_polyline_apex_roundtrip.py 2건 — 갈아 끼워도 곡선
수·반지름이 같고 선이 **1mm 안**에서 일치, 그리고 안 갈아 끼우면 실제로
하한으로 눌리는 것(왜 필요한지)도 못박음.

실화면 확인(용화) — 되돌린 뒤 곡선 26곳 R 최대 198.9m → 곡선 하나 지우고
[확인] → 곡선 25곳, **R 42.5·51·198.9m 그대로**.

tsc --noEmit 통과 · pytest 432 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
④(2026-09-07)로 붙인 레인이 `chartWrap` 안에 서는데, 그래프 높이를 정할 때 잰 값에서
레인 몫을 빼지 않아 되먹임이 생겼음 — 잰 값이 커지면 그래프를 키우고, 그러면 다음 회차에
더 커짐. 실측 패널이 **16,664px** 까지 부풀어 카드·알약을 누를 수 없었음.

레인 높이(`STRUCTURE_LANE_HEIGHT_PX`)를 빼서 한 번에 수렴하게 함.
자체검증 — 패널 242px · 그래프 228px · 레인 42px · 알약 10개. tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 승인(2026-09-07). 없으면 우버콘이 StatReload 로 떨어져 0.25초마다
감시 폴더를 통째로 훑고, 그러면 요청이 없어도 CPU 를 먹음.

실측 (놀고 있는 서버) — 감시 폴더를 좁히기 전 **70%** → 좁힌 뒤 **18%** →
이 패키지 설치 뒤 **0%**. 기동 로그가
`Started reloader process [...] using WatchFiles` 로 바뀜.
보조 창(8001)도 같은 값 확인 — 리로더 0% · 서버 0%.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- `B05_Profile_UI_RouteEdit_Curve.ts` 신설(68줄) — 손잡이 끌기 역셈
  (`dragHandleTo`)·직선 교점(`intersect`)·내각(`innerAngleDeg`) 순수 기하만.
- 모달은 740 → 692줄. 화면 배선·동작 불변, 셈 식 그대로 옮김.
- 서버 정셈과 짝임을 새 파일 머리에 명시. 거울 시험은 새 자리를 보게 갱신.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「좌우 1.0m 를 넣어도 안 움직인다」의 원인은 지형이 아니라 **선반 하한**이었음 —
좌우 이동은 선반 길이가 음수가 되지 않게 `1.2 × 상하 내림`까지 따라 나가므로,
저장값이 d 2.6m 이면 하한이 3.12m 라 1.0m 요청은 아무 변화도 못 냄. 그런데도
`shiftBlockedM`(지형에 막힌 양)은 0 이라 까닭을 알 길이 없었음.

- `shiftFloorM` 추가 — 요청이 하한에 눌려 통째로 무시된 경우 그 하한을 남김.
- 벽 툴팁에 한 줄 — 하한 값과 「그 아래로 넣으면 안 움직임」을 적음.
  지형 탓(`shiftBlockedM`)과 자리를 나눠 두 까닭이 안 섞이게 함.
- 시험 `tmp/tests/test_b06_extra_shift_floor.py` — 화면 코드를 그대로 컴파일해
  Node 로 돌림. 좌우 0.5m 요청이 d 2.0m 아래에서 2.4m 로 밀리고 그 값이 알려지는 것 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 독립 기슭막이(D군) 툴팁은 **따로 만들어져** 있어 「지형에 막힘」조차 안 떴음.
  배관 벽과 같은 두 줄(지형 막힘 · 각도 하한)을 같은 문구로 붙임.
- 기준벽 경로(`computeRevetmentLayout`)에도 `shiftFloorM` 을 남김 —
  하한이 `1.2 × 상하 내림 − 자동 자리`라 d 2.6m 자리에서 1.0m 요청이 삼켜졌음.
- 하한 알림은 **사용자가 실제로 값을 넣었을 때만** 뜨게 좁힘. 요청이 0이면
  하한은 그냥 기본 자리라 모든 벽에 뜨면 소리만 됨.
- 문구를 두 경로에 맞게 고침 — 「상하 내림의 1.2배」가 아니라
  「성토선 각도(1:1.2)를 지키려면 그만큼은 나가 있어야 함」.
- 시험 3건(`test_b06_extra_shift_floor.py`) — 하한 적용·알림·요청 없을 때 침묵.

미확인 — 실화면에서 알림이 뜨는 것까지는 못 봄. 지금 프로젝트(용화)의 카드가
전부 링크 카드라 좌우 이동 조작 자체가 먹지 않아 조건을 세우지 못했음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3-7 (2026-09-07). 안내는 이미 있었으나 `activeRevet` 이 그 벽일 때만 떠서, 좌측 「구조물
배치」 폼처럼 **조정창을 안 거친 경로**로 단 수를 바꾸면 개수만 조용히 잘렸음. 사용자는
[+]를 눌러도 아무 일이 없는 것으로 보임.

- 조건을 없애고 **자리(측점·측·세워진 단 수)마다 한 번만** 내도록 바꿈. 다시 그릴 때마다
  뜨면 시끄럽고, 결과가 달라지면(지형·조작) 키가 달라져 다시 알림.
- 요청대로 다 선 자리는 기록을 지워, 나중에 또 모자라면 다시 알림.
- 문구는 기존 `B06_Cross_Extra_Limit` 그대로 — 새 문구를 만들지 않음(중복 토스트 방지).

앞서 `Station_Controls.syncCount` 에 같은 안내를 붙였다가 **기존 것과 겹쳐 두 줄로 뜨는 것**을
실화면에서 보고 되돌렸음. 안내는 이 한 자리에만 둠.

tsc 통과 · 시험 508 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
새 사용자 값을 더할 때 **네 곳을 다 고쳐야** 했고, 하나만 빠지면 그 값이 저장에서
조용히 사라졌음(`extra_spans` 실사고 `b6941bd2`). 나열을 걷어 목록 한 벌로 모음.

- 확정·저장 payload 조립(`_Router_Confirm.py`) — `if patch_item.X is not None:` 11개를
  스키마 통째 덤프 + 최상위 None 걷기로 바꿈. 새 필드가 저절로 실림.
  중첩 None 은 남김(기슭막이 4축 `d: null` 은 「자동」이라는 뜻).
- 브라우저 payload(`_Section_Store.ts`) — `put("X", design.X)` 10줄을 목록 순회로.
- `_Cross_Refresh.ts` 에 `USER_TOUCHED_KEYS` 를 내보내고 `PRESERVED_KEYS` 는
  거기에 상태 둘을 더해 만들게 함. 서버 목록과 짝임을 머리에 적음.

전수 조사 결과 `design` 키는 세 갈래였음 — ① 재계산 인자로 되먹여 사는 것 8개
② 목록으로 베껴야 사는 것 12개 ③ 순수 계산값 24개. 위험한 칸은 ② 하나뿐임.

시험 3건 추가:
- `test_b06_design_key_split.py` — 사용자 값이 ①·② 어디에도 안 걸리면 깨짐(불변식).
  지금 코드는 통과 = 알려지지 않은 구멍 없음.
- `test_b06_recompute_keeps_user_values.py` — 포장 재계산 뒤 ② 값 보존·① 인자 전달.
- `test_b06_user_touched_keys.py` — 손나열이 되살아나면 깨지는 검사 둘 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 7-1. 화면의 **모든 `/api` 요청이 「Failed to fetch」** 가 되는데 서버는 멀쩡한
증상이 하루 종일 있었음. 원인은 프록시 대상이 `http://localhost:<포트>` 인 것 —
Node 18+ 는 `localhost` 를 **IPv6(::1) 먼저** 물고, 백엔드는 `SERVER_HOST=0.0.0.0`
(IPv4 전용)으로 떠서 서로 못 만남.

실측 — `127.0.0.1:8001` 200 · `[::1]:8001` 연결 실패.
고친 뒤(vite 재기동 포함) 화면에서 `/api/health` **200**, 로그인 POST **200**.

오늘 겪은 「저장 Failed to fetch」 두 번과 「화면 백지」 세 번이 이것으로 설명됨 —
부팅 때 API 가 죽으면 앱이 아무것도 안 그리고 콘솔 오류도 안 남았음.

공용 파일이라 배분 창(claude-b1) 승인을 받고 고침. 5173·5174 양쪽에 같이 적용됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
엔진 둘이 결과 딕셔너리에 **엔진이 실제 적용했는지**를 담아 저장했고, 그 값이 다음
재계산에 인자로 되먹여졌음. 그래서 토사 측점처럼 2단을 못 쓰는 자리에서 사용자가 켜 두면
저장값이 False 로 바뀌고, 그 False 가 다시 인자가 되어 **켬이 영구히 사라졌음.**

- `two_stage_slope` 를 **받은 요청값 그대로** 내보내게 함(파이썬·TS 짝 두 줄).
- 「실제로 적용됐나」를 읽는 곳은 코드 전체에 없음(전수 확인) — 읽는 쪽 여섯은 모두
  사용자 설정으로 씀. 2단 사면이 그려지는 근거는 이 값이 아니라 설계선 기하임.
- 저장 형식 안 바뀜. 옛 저장분도 그대로 읽힘.

시험 `test_b06_two_stage_slope_kept.py` 4건 — 토사에서 켬 유지 · 되먹임 왕복 ·
끔도 유지 · 「2단은 설계선이 그린다」(암은 기하가 갈리고 토사는 같음) 확인.
거울 시험은 기존 `test_b06_cross_design_mirror.py` 가 그대로 잡음.

같은 모양인 `ditch_enabled` 은 손대지 않음 — 그쪽은 저장값을 「측구 없음」 판정으로
읽는 곳이 4군데(횡단 맞춤·횡단 그리기·B07 도면·3D 카브)라 처방이 다름.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
쓰는 쪽은 `stateKey("rockb", …)` = `aislo:draft:rockb:{p}:{r}` 에 쓰는데, 읽는 쪽
`readRockBoundarySession` 이 옛 키 `b06:rockb:{p}:{r}` 를 날문자열로 읽고 있었음.
`writeStateRaw` 는 옛 키를 안 쓰므로 **읽는 쪽이 늘 빈 값**을 받았음.

그래서 계획선을 고쳐 횡단을 다시 계산할 때(`B06_Section_Cross_Refresh`) 사용자가 옮긴
암 경계선이 안 실려 나가 **토사/암 나눔이 기본값으로 되돌아갔음** — 수량이 갈리는 자리.
[저장] payload 는 메모리 Map 을 써서 저장 자체는 무사했음.

- 읽는 쪽을 등록표(`readState("rockb", …)`)로 바꿈. 옛 키 만드는 함수는 지움.
- 실화면 실측(용화 5601e828 · route 169) — 경계선 -0.5 → -0.8m 로 옮기니
  새 키에 `{"0.00":-0.8}` 가 쌓이고 **옛 키는 아예 없었음**(고치기 전 근거).
  고친 뒤 새로고침해도 값·표기 그대로.

시험 `tmp/tests/test_session_keys_registered.py` 3건 — 등록표 밖 날문자열 세션 키를
쓰면 깨지는 그물 + 이 자리 못박기. **훑어 보니 다른 날문자열 키는 0개**로,
`rockb` 가 유일한 구멍이었음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`std-cross` 가 [저장] 뒤에도 안 비는 것이 실수인지 의도인지 갈렸음 — **의도로 확정.**
다른 초안과 달리 이 값은 브라우저가 가진 **유일한** 사용자 표준단면임:
`sections/context` 가 주는 `standard_cross_section` 은 저장분이 아니라 config 기본값이고
(`B06_Section_Router.py:132`), 저장분은 서버 안에서만 쓰임
(`stored_standard_cross_section`). 비우면 브라우저 횡단 계산이 그 순간 config 기본값으로
되돌아감. [초기화]에서만 버림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
노선을 다시 계산하면 세션의 옛 노선치가 그대로 쌓였음. 용화(5601e828)에 145·161·169
세 노선치가 남아 있는 것을 실측함.

원인은 「안 지웠다」가 아니라 **못 지웠다** — 노선 변경 자리는 새 번호를 아직 모르니
`clearDrafts(projectId)` 로 부르는데, `stateKey` 가 노선 번호 없이는 `null` 을 내어
route 범위 키가 한 개도 안 나갔음. 부르는 쪽 주석은 「남기지 않는다」였고 실제로는 다 남았음.

`clearState` 한 곳에서, 노선 범위인데 노선 번호가 없으면
`aislo:<통>:<이름>:<프로젝트>:` 로 시작하는 키를 모두 쓸어 내게 함.
`clearDrafts` 와 `clearResults` 가 함께 나음. 노선 번호를 주면 종전대로 그 한 벌만 나감.

안전 확인 — 옛 노선치를 읽는 자리 없음(`readState` 호출 8곳 전부 전역·프로젝트 범위).
노선 복원도 새 route id 를 발급하므로 옛 키는 다시 안 불림.

자체검증 — `tmp/tests/test_page_state_route_sweep.py` 3건 신설.
옛 코드로 같은 시험을 돌리면 세 벌이 그대로 남아 깨지는 것까지 확인(헛도는 시험 아님).
전체 511 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표준단면 편집값은 sessionStorage 에만 살아 **탭을 새로 열면** 사라졌음. 그때 브라우저는
config 기본값으로, 서버는 저장분으로 계산해 **같은 측점이 갈렸음**. 표준단면은 모든 측점의
횡단 모양을 정하므로 면적·유토곡선·수량까지 그대로 흐름.

- `sections/context` 가 저장분을 **한 칸 더** 실어 보냄(`stored_standard_cross_section`).
  기존 `standard_cross_section`(config 기본값)은 그대로 둠 — 옛 화면 안 깨짐, 마이그레이션 없음.
- 브라우저는 두 화면이 함께 지나는 한 자리(`fetchSectionContext`)에서 **세션이 비었을 때만**
  그 값으로 세움. 그 탭에서 고친 값이 있으면 안 건드림(초안 우선).

실측(용화 5601e828 · route 169):
- 고치기 전 — 저장분 암반 횡단경사 **5%** · 측구 상단폭 **0.9m** 인데
  화면이 받는 값은 **3%** · **0.69m**(config 기본값)였음. 응답에 저장분 칸 자체가 없었음.
- 고친 뒤 — 응답에 0.9·5 가 실리고, **빈 새 탭**에서 B06 을 열면 세션이
  `rock.ditch.top_width_m=0.9` · `rock.cross_slope_pct.max=5` 로 섬(검증 탭은 닫음).

시험 `test_b06_stored_standard_reaches_browser.py` 3건 — 칸이 따로 있고 기본은 None ·
라우터가 저장분을 실음 · 브라우저가 세션이 빈 경우에만 세움(두 갈래 모두).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
같은 노선인데 지문이 늘 어긋나 관 지점이 매번 투영 이월을 탔음.

까닭 — 같은 노선을 두 파일이 다른 자릿수로 담고 있음.
`planned_route.csv` 는 소수 4자리(`208403.2001`), `route_main.geojson` 은 소수 3자리
(`208403.2`)로 csv 를 mm 반올림한 사본임. 좌표 차는 최대 0.5mm 뿐인데, 지문이
`f"{x:.2f}"` 로 0.01m 자리에서 끊는 탓에 그 0.5mm 가 `.xx5` 경계를 넘는 정점마다
글자가 바뀜 — 169개 중 16개가 그랬음.

경계에서 자르는 방식은 저장 자릿수가 또 바뀌면 다시 흔들리므로, 글자 일치 대신
**허용오차**로 가름. 저장된 관을 지금 노선에 투영해 **재 보기만** 하고
(`max_projection_shift`, 값은 안 고침), 최대 어긋남이 0.05m 이하면 같은 노선으로 보고
저장분을 그대로 돌려줌.

허용오차 0.05m 근거 — 실측 어긋남이 최대 0.0053m 이라 다섯 배 이상 여유이고,
사람이 노선을 실제로 고치면 관은 m 단위로 밀리므로 「같다」로 볼 위험이 없음.

투영 이월 가지는 그대로 둠 — 대신 그 가지가 실제로 돌면 WARNING 을 찍게 함.
한동안 0 인 것을 확인한 뒤에야 지울 수 있음(먼저 지우면 관이 통째로 사라짐).

자체검증
- 새 시험 3건 `tmp/tests/test_pipe_route_tolerance.py` — mm 반올림 사본은 같은 노선으로
  판정되고 누가거리가 한 값도 안 움직임 / 중간을 3m 민 노선은 안 걸림 / 허용오차 범위.
- 기존 `test_pipe_point_projection.py` 2건 그대로 통과(±0.7m 잔물결 노선은 여전히 투영).
- 저장된 실제 3개 프로젝트 전후 대조 — 셋 다 「다름 → 투영」이 「같음 → 저장분 그대로」로
  바뀜. 화면 값 변화는 최대 0.0053m · 0.0009m · 0.0005m.
- 전체 514 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
자동 리로드가 조용히 죽어 **옛 코드로 도는 서버**에 오늘 두 창이 세 번 속았음
(속도 488초 오측 · 응답에 새 필드가 없는데 화면은 정상으로 보임 · 표준단면 응답이 옛 스키마).
매번 틀린 결론을 한 번씩 냈다가 되물렀음. 규칙("재기 전에 재시작")으로는 세 번 다 안 지켜져
**한 번 보면 아는 표시**로 바꿈.

- `/api/health` 가 개발 모드에서 `started_at` · `code_mtime`(기동 때 본 소스 최신 수정) ·
  `source_mtime`(지금 소스 최신 수정) · `stale` 을 함께 냄. `stale: true` 면 재시작 전
  어떤 측정도 믿으면 안 됨.
- 기동 로그에 감시 폴더 수와 소스 최신 수정 시각을 한 줄 남김.
- 실측 — 감시 폴더의 `.py` 를 고치니 리로드는 **안 뜨고** `stale` 이 즉시 true 로 바뀜.

원인 추적은 계속함(PLAN 7-2) — 한글 경로·정션은 **아님**(`watchfiles` 를 그 폴더에
직접 걸어 보니 변경을 정상 감지). uvicorn 이 감시 폴더 12개를 선언하고도 리로드를
안 내는 자리라 더 파야 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 결정 두 가지를 반영함(2026-09-07).

① 측구(옆도랑) — 목록에 두되 표시만.
레지스트리에 `design_owner` 를 새로 두고 측구에 「횡단 설계」를 적음. 구조물 배치 폼에서
그 종류를 고르면 「횡단 설계에서 관리 — 여기서 넣어도 제원·수량은 그쪽 값을 씁니다.」가
뜸. `managed_by` 와 달리 저장은 그대로 되므로 배치는 계속 가능함.

까닭 — 횡단 설계가 측구 켬/끔·형식·터파기 단면적(`ditch_area_m2`)을 파이썬·TS 짝으로
이미 셈함. 구조물로 또 세면 같은 것을 두 번 계상함.

목록 항목에 안 붙이고 폼에 붙인 것은 「한 항목 = [측점][이름]만」이 2026-08-18 사용자
지시이기 때문임.

② B군 수량 1단계 — 구조물 정본에서 시설별 연장(m)을 냄.
`common_util_structure_lengths.py` 하나. B군 수량 단위가 전부 m 이라 단면 기하가 필요
없음(맹암거 12-10 · L형 측구 12-9-1 · 산마루측구 12-9-2). 수량서 양식에 안 묶이므로
B08 을 실무 xlsx 양식으로 다시 짜도 그대로 씀.

빼는 것 셋 — 관 정본 소관(`managed_by`), 횡단 소관(`design_owner`), 그리고 소단측구
(놓일 소단이 아직 없음 — 계획서 3-9 뒤에 채움).

겹친 구간은 합쳐서 셈함. 같은 시설을 겹치게 두 번 넣으면 단순 합이 그 구간을 두 번
세기 때문임. 원래 합(`raw_length_m`)도 함께 내보내 겹침이 숨지 않게 함.

자체검증
- 새 시험 7건 `tmp/tests/test_structure_lengths.py` — 종류별 합산 / 겹침 제거(80m 인데
  단순 합 110m) / 측구 제외 / 소단측구 제외 / 배관 제외 / 구간 없는 항목은 스키마가 막음
  / 빈 프로젝트.
- 화면 확인(8001·5174, `/api/health` `stale:false`) — 구조물군 B → 종류 측구 선택 시
  안내가 254×44px 로 뜨고 문구가 맞음. 리셋으로 폼 되돌림.
- 전체 521 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 취향까지 sessionStorage 에 있어 **탭을 새로 열거나 브라우저를 껐다 켜면** 패널 높이·
접힘·유토곡선 열림이 매번 초기화됐음. 계획서에는 「PC 를 바꾸면」으로 적혀 있었으나 실제
불편은 훨씬 잦았음(사용자 승인 뒤 조사에서 드러남).

- 저장소를 통(bucket)으로 가름 — **`pref` 만 localStorage**, 초안·결과는 세션 그대로.
  설계 데이터가 아니므로 CLAUDE.md 5장 「캐시=세션」에 걸리지 않음.
- 키만 들고 저장소를 직접 만지던 화면 공용 부품 셋(`ui_template_resizer`·`_overlay`·
  `_overlay_drag`)이 같은 판단(`storageOf`)을 쓰게 함 — 안 그러면 높이 값만 세션에 남아
  절반만 옮겨졌음(실측: 접힘 4개는 옮겨지고 높이 3개는 안 옮겨짐).
- 첫 로드 때 세션에 남은 옛 취향을 한 번 쓸어 옮김 — 이 변경으로 쓰던 크기가 초기화되지 않게.

실측(공용 브라우저) — 옮긴 뒤 취향 8개 전부 localStorage, 세션 0개, 높이 보존
(종단 438px · 표 204px). **새 탭에서도 8개 그대로**(같은 값). 검증 탭은 닫음.

시험 `tmp/tests/test_prefs_persist_across_tabs.py` 4건 — 취향만 갈리는지 · 초안·결과는
세션인지 · 공용 부품이 같은 판단을 쓰는지 · 옛 값을 한 번 옮기는지.

이 조각은 DB 없이 되는 몫임. 계정 저장(`018_user_ui_prefs`)은 다음 단계.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
오늘 같은 계통이 두 번 났음 — 키는 등록표에서 받는데 **저장소는 제 맘대로** 고르는 자리.
· `rockb` — 키를 날문자열로 만들어 읽는 쪽이 늘 빈 값(`f8fafd23`)
· 화면 취향 — 키는 맞았는데 저장소를 직접 골라 **절반만** 옮겨짐(`9db84d9d`)

남은 두 자리(암 경계선 저장·표시 반폭)도 `storageOf` 를 거치게 함. 지금은 둘 다 초안이라
세션이 맞지만, 통이 바뀌면 조용히 갈릴 자리였음.

그물도 넓힘(`test_session_keys_registered.py`) — 등록표 키를 쓰는 파일이 저장소를 이름으로
직접 고르면 깨짐. 고르는 곳은 `b_page_state` 하나. 앱 전역 값(`CURRENT_PROJECT_ID_KEY`)은
등록표 밖이라 제외하고 이유를 적어 둠. **훑어 보니 남은 위반 0곳.**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 승인(2026-09-07). 앞서 취향을 localStorage 로 옮겨 **탭·재시작** 문제는 풀었고,
이 변경은 그 위에 **다른 PC 에서도 같은 배치**를 얹음. 사용자가 노트북·데스크톱 두 대를 오감.

- `db_management/018_user_ui_prefs.sql` — 사용자당 한 줄, `prefs` JSON 한 칸.
  칸을 나누면 취향이 늘 때마다 마이그레이션이 또 필요해 한 칸에 담음.
- `GET/PUT /api/dashboard/me/ui-prefs` — 배치 값만. **설계값은 안 담음**(문자열만 받음).
- 로그인이 확인된 첫 순간에 한 번 받아 로컬 위에 얹고, 취향이 바뀌면 1.5초 모아 올림.
  서버가 없거나 못 읽으면 **로컬 값으로 그대로 돔**(계획서 원문).

⚠ 같은 함정을 또 밟을 뻔했음 — 키만 아는 자리가 저장소를 직접 고르면 **올려보내기도 안 걸림**.
그래서 `storageOf` 를 없애고 **읽기·쓰기 창구 하나**(`readByKey`/`writeByKey`)로 모음.
저장소 선택과 서버 올려보내기가 그 한 곳에만 있음. 그물도 그 이름으로 갱신.

**DB 는 아직 적용하지 않았음** — 표가 없으면 API 가 실패하고 화면은 로컬 값으로 도는 것이
정상 동작임. 적용 시점은 다른 창들과 맞춘 뒤.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07)에 따라 소단을 **자동 적용하지 않고 사용자가 놓는 것**으로 만듦.
이 커밋은 그 기하 한 벌이고, 화면 폼은 다음 단계임.

새 짝 모듈 `common_util_cross_berm.py` · `.ts` — 절토 사면 꼭짓점을 만듦.
암 경계 무릎과 소단이 한 목록에 함께 들어가고, `breakpoints` 가 그 꼭짓점을 설계선에
실어 도면·면적·유토곡선·3D 가 계단을 그대로 봄.

기본값 폭 0.5m · 간격(사면길이) 3.0m · 안쪽 기울기 2°.
· 폭·간격은 별표2 범위(사면길이 2~3m마다 · 폭 50~100㎝) 안에서 가장 적게 파는 조합임.
  기본값은 되돌리기 쉬운 쪽이어야 함 — 더 넣는 것은 폼에서 한 번이지만 이미 판 것을
  되돌리면 전 측점을 다시 계산해야 함. 실효 경사로도 그러함(경사 1:1 기준)
  폭 0.5·간격 3 → 1:1.24 / 폭 1.0·간격 3 → 1:1.47 / 폭 1.0·간격 2 → 1:1.71.
· 기울기 2°는 사용자 확정값이고 법령·교본 근거가 없어 지식DB 에 적지 않음(사용자 지시).

무릎은 종전대로 **한 번만** 꺾음. 여러 번 꺾게 풀면 소단이 없는 지금 측점 설계도 같이
바뀌므로 별건으로 미룸(실측: 물결 경계에서 0.0016m 차이, 경계를 다시 만나면 구조가 달라짐).

자체검증
- 거울 시험 10건 `tmp/tests/test_cross_berm_mirror.py` — 소단 켠 5경우 포함해 파이썬·TS
  꼭짓점이 1e-9 안에서 일치. 간격이 수평이 아니라 사면길이 기준인 것, 평탄부가 2° 기운 것,
  소단이 없으면 옛 무릎 방식과 완전히 같은 것까지 확인.
- 면적 시험 6건 `tmp/tests/test_cross_berm_area.py` — 절토 55.115 → 78.785㎡(기본값),
  폭·간격이 물량에 단조로 반영, 소단 모서리가 설계선에 실림, 소단을 안 주면 설계선까지 동일.
- ⚠ 어림식 두 번을 시험이 잡아냄. 「늘어난 면적 = 폭 × 그 위 높이」는 틀림(11.797 vs
  7.770㎡) — 설계선이 밀리면 지반과 만나는 점도 함께 밀려 절토가 더 길어짐. 「폭만큼 밀림」도
  틀림 — 참값은 「그 아래 소단 개수 × 폭」임. 시험은 그 참값으로 잼.
- 기존 거울 시험(`test_b06_cross_design_mirror.py`) 10건 그대로 통과 — 리팩터가 값을
  안 바꿨다는 증거임. 전체 537 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
배분 창 지적으로 확인한 자리 — 미룰 수 없는 쪽이었음.

무엇이 문제였나 — 소단은 평탄한데 암 경계선은 지반을 따라 올라감. 지반이 1:1 이면
폭 0.5m 소단 하나를 지나는 동안 경계는 0.5m 오르고 소단은 2°(0.017m)만 오름. 그래서
설계선이 경계 아래로 **되돌아 들어가는 일이 흔함**. 무릎을 한 번만 꺾는 종전 규칙으로는
그 구간을 **암인데 토사 경사로** 그려 절토가 조용히 커짐 — 경고도 안 뜸.

고침 — `multi_knee` 를 둬서 경계를 오갈 때마다 꺾게 함. **소단이 있을 때만** 켬.
소단이 없을 때 켜면 지금 측점들의 설계가 같이 바뀌기 때문임(실측: 물결 경계 0.0016m).
기본값은 거짓이라 소단을 안 쓰는 프로젝트는 그대로임.

자체검증
- 새 시험 1건 — 경계를 뚫고 올라갔다가 소단마다 뒤처져 되돌아 들어가는 지형에서
  한 번만 꺾는 결과와 갈리고, 되돌아 들어간 구간이 암 경사(가파름)라 같은 거리에서
  더 높이 올라가는 것을 확인.
- 거울 시험에 되돌아 들어가는 경우를 한 줄 더해 파이썬·TS 일치 확인(12건).
- 전체 539 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B군(측구·맹암거 등)을 넣어도 **어디에 놓였는지 안 보였음**. 알약은 기준점 한 곳에만 찍히고,
시~종점 띠는 **고른 동안만** 폈기 때문. 측구처럼 길게 이어지는 시설은 「어디부터 어디까지」가
곧 그 시설의 내용이라 늘 보여야 함(2026-09-07 사용자 지시).

- 구간형이면 **늘** 띠를 그림. 고른 것은 두껍고 진하게(4px·0.55), 나머지는 얇고 옅게(3px·0.45).
- **레인 높이는 42px 그대로** — 2-5b 에서 줄여 둔 것을 안 부풀림.
- B05 가 레지스트리를 **한 번만 받아 쓰는 자리에 따라 나눔** — 추가 메뉴는 켜진 종류만
  (종전대로 여섯 군), **알약 레인·군 판정은 전부**. B06 에서 넣은 B군은 레지스트리에서
  꺼져 있어, 켜진 것만 주면 종단에 이름·색 없이 「?」 회색 알약으로 떴을 자리였음.

실측(용화, 구간형 7건) — 띠 **0 → 7개**, 높이 3px, 레인 42px 그대로, 알약 18개 그대로.
B군 6종은 전부 `interval` 이라 확인한 C군과 같은 경로를 탐. 타입 응답 36종에 B군 6종 포함 확인.

평면(지도)은 손대지 않음 — 노선 위에 구간을 얹는 방법이 지금 없어 **별건**으로 둠.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계단이 값에만 있던 것을 화면까지 연결함.

배선 — 세션 열쇠 `berm`(측점키 → 폭·간격·기울기)을 등록표에 두고,
`readBermSession` 으로 읽어 ① 브라우저 재계산(`refreshCrossDesigns`)과
② 서버 미리보기(`cross-design/preview` 의 `berms`) 양쪽에 실음.
암 경계선 오프셋과 같은 길이라 「계획선을 고치면 계단이 사라지는」 일이 없음.

실화면 확인(8001·5174, `/api/health` `stale:false`) — 측점 4120.0m 에 소단을 놓고
계획고를 한 칸 올렸다 내려 전 구간 재계산을 태움.
· 폭 0.5m · 간격 3.0m → 절토 6.84 → 8.10㎡ (토사 2.42→3.24 · 암 4.42→4.86)
· 폭 1.0m · 간격 2.0m → 절토 6.84 → 12.96㎡, 횡단도에 **계단이 눈으로 보임**
· 소단을 안 놓은 옆 측점(4100.0m)은 3.77㎡ 그대로 — 놓은 곳만 달라짐
· 되돌린 뒤 6.84㎡ 로 복귀. [저장]·[확정] 안 눌렀으므로 정본은 그대로.

`cut_slope_segments` 신설 — 절토 사면을 경사 구간별로 쪼갠 목록(파이썬·TS 짝).
법정 경사 검사가 읽을 값임(다른 창 요청). 소단이 서면 사면 전체를 하나로 재는
「실효 경사」가 완만해져 **위반이 사라진 것처럼** 보이므로(폭 1.0·간격 2 이면 설계 1:1 이
실효 1:1.71), 검사는 소단을 뺀 구간 자체를 봐야 함. 실측 — 소단을 놓아도 구간별 경사비는
1.0 그대로 나옴. 평탄부(소단)와 지반 만난 뒤 구간은 싣지 않음.

자체검증 — 거울 시험에 사면 구간 대조를 더해 파이썬·TS 일치 확인.
전체 539 passed · 18 skipped. TS 타입 검사 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자가 소단을 **직접 놓는** 화면을 만들었음. 프로그램이 「붕괴 우려 지역」을 판정하지
않고, 법정 기준 셋 중 무엇도 자동 적용하지 않음(2026-09-07 사용자 확정).

폼은 C군 구간형 구조물과 **같은 꼴** — 기준 측점 + 전·후 거리로 종단 범위를 잡고
폭·간격·기울기를 함께 받음. 기본값 폭 0.5m · 간격(사면길이) 3.0m · 안쪽 2°.
새 모듈 `B06_Section_UI_Berm_Panel.ts` 로 뺐음 — 좌측 페이지가 이미 700줄을 넘어 있어
거기 더 넣지 않고 두 줄만 꽂음(그 파일 분리는 별건).

세션에는 **구간 목록**으로 둠. 측점별로 펴서 저장하면 「어디부터 어디까지 놓았나」를
되짚을 수 없음. 읽는 자리에서 펴고, 서버에는 측점키 dict 로 실어 보냄.

**확정 뒤에도 계단이 남게** — 소단 제원을 설계 결과에 되싣고(`berm`),
`USER_TOUCHED_KEYS` 에 넣어 재계산이 지우지 않게 함. 서버 재계산은 세션값이 없으면
저장분을 씀(`stored_berm`).

⚠ 소단은 사용자 조작값이면서 **기하 입력**이라 다른 사용자 키와 다름 — 계산 뒤에 키만
베껴 붙이면 설계선·면적은 계단 없이 나오고 `berm` 값만 남아 서로 어긋남. 그래서 단측점
설계 경로는 저장분을 **계산 전에** 읽도록 순서를 바꿨고, 포장 강제·세월교 노면 하강
재계산 경로에도 저장분 소단을 실었음. `extra_spans` 가 그렇게 빠져 있던 자리와 같음.

자체검증 — 새 시험 2건(저장분만으로 같은 설계가 나오는지 · 값이 없거나 손상되면 None).
전체 541 passed · 18 skipped. TS 타입 검사·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
법정 위반 표시가 없던 유일한 자리였음(평면 곡선반경·성토사면 길이는 이미 있음).
절토 경사비는 표준 횡단면 설정에서 오는 입력값일 뿐이라 범위를 벗어나도 아무 표시가 없었음.

- 기준 — 별표2(지식DB `01_임도/02_상세설계/절토_비탈면.md` §1): 경암 1:0.3~0.8 ·
  연암 1:0.5~1.2 · 토사 1:0.8~1.5. **작업임도는 규정 없음 → 검사 제외.**
- 판정은 **구간별 경사**(`cut_slope_segments`)로 함. 소단이 서면 실효 경사가 완만해져
  **위반이 사라진 것처럼** 보임(폭 1.0·간격 2 이면 1:1 이 1:1.71). 그 함정을 시험으로 못박음.
- 표시는 **기존 방식 그대로** — 성토사면·미폐합 경고와 같은 자리·같은 클래스. 새 방식 안 만듦.
- 지반유형(리핑암·발파암) → 별표2 줄 매핑은 법령 근거가 아니라 **프로그램 설정**이라
  표준 횡단면 설정에서 **사용자가 고르게** 함(2026-09-07 사용자 확정). 기본값 리핑암 → 연암 ·
  발파암 → 경암. 표준단면과 함께 저장돼 이미 사용자 값 계통임.
- 기준값은 서버가 컨텍스트로 내려보냄 — 화면에 상수를 복제하지 않음.

시험 7건 — 별표2 값 · 작업임도 제외 · 매핑이 기본값일 뿐 · 구간별 판정 ·
**소단이 있어도 위반이 안 사라짐** · 경계값 통과 · 카드에 같은 방식으로 붙는지.

⚠ 실화면 — 사용자 선택 칸은 섰음(리핑암 연암 · 발파암 경암). 다만 이 프로젝트 저장분
63측점에 `cut_slope_segments` 가 아직 없어(오늘 새로 생긴 키) 경고가 뜨는 것은 못 봄.
재계산이 한 번 돌면 채워짐 — 지금 경고 0건은 맞는 동작임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
다른 창이 전 측점을 돌려 찾은 것(용화 5601e828 · route 169, 63측점 124구간).
`material: "rock"` 인데 경사비가 1.0(토사)인 구간이 **13개** 나왔음.

까닭 — 재료를 **암반 경계선을 다시 재서** 붙였음. 그런데 무릎을 지난 뒤에도 경계선은
지반을 따라 계속 오르므로, 토사 경사로 그린 구간이 경계 아래로 **되돌아가 있는** 일이
흔함. 그것을 경계로 재면 그린 것과 라벨이 어긋남.

고침 — 재료는 **그 구간을 실제로 그린 경사비**를 따라 붙임(암 경사비에 가까우면 암,
토사 경사비에 가까우면 토사). 두 경사비가 같으면(2단 절토 아님) None.

영향 — 별표2 경사 판정이 갈리던 자리임. 13개가 「암인데 너무 완만」 위반으로 잘못 뜰 수
있었음. 토사 구간 50개는 종전대로 위반 0.

자체검증 — 새 시험 1건: 지반이 가파른 암 지반에서 모든 구간의 재료가 그 경사비와 맞는지
확인(어긋나면 실패). 거울 시험도 통과. 전체 542 passed · 18 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`B06_Section_UI_Page_Persist.ts` 의 import 한 줄만 갈렸음. 양쪽 다 쓰는 이름이라 합침 —
`readByKey`/`writeByKey`(저장소 선택을 한 창구로 모은 것)와 `writeState`(소단 배선)가
같은 파일에서 각각 한 번씩 쓰임. 다른 충돌 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
한 묶음으로 처리했음 — 화면에 5m 판정이 틀린 채 서 있는 시간이 없게.

성토 사면 꼭짓점 짝 신설(`fill_profile_points` · `fillProfilePoints`). 절토와 달리
경사가 하나뿐이라 무릎이 없고, 소단 규칙은 같음. 설계선·지반 교차·꼭짓점 목록이 모두
그 선을 봄.

⚠ **옹벽 의무 판정을 함께 고쳤음** — 「성토사면 길이 5m 이내, 넘으면 옹벽·석축 의무」
(`성토_비탈면.md` §2)를 재는 `fillSlopeLengths` 가 **「성토선은 1:n 직선」을 전제로
수평거리 × 기울기**로 재고 있었음(주석에도 그 전제가 적혀 있었음). 소단이 들어가면 그
전제가 깨져 값이 틀림.

고침 — 소단이 있으면 설계선을 걸어가며 **소단으로 끊긴 한 도막**의 최대 길이를 잼.
· 전체를 한 줄로 재면 소단을 넣어도 5m 를 넘어 **의무가 사라지지 않음**
· 실효 경사로 재면 완만해져 **의무가 사라진 것처럼** 보임
둘 다 틀리므로 「끊긴 한 도막」이 맞는 기준임.

**소단이 없는 측점은 종전 식을 그대로 탐** — `design.berm` 이 없으면 예전 계산 그대로라
값이 한 톨도 안 바뀜(구조로 보장). 화면 전후 대조는 다음 단계에서 냄.

자체검증 — 새 시험 2건(성토면에 계단이 서고 같은 거리에서 덜 내려감 · 소단이 없으면
성토선이 곧은 한 줄). 전체 542 passed · 18 skipped. TS 타입 검사·ruff 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07): 「연암과 경암도 별도의 버튼으로 선택하게 하고 경암을 기본값으로
선택. 리핑을 할지 발파를 할지는 설계자가 선택 필요함.」

**축이 둘이었음 — 섞지 말 것.**
· **암질**(연암·경암) = 별표2 경사 판정의 기준. 설계자가 고름. 기본 **경암**.
· **굴착 공법**(리핑암·발파암, `cut_rock_kind`) = 어떻게 파는가. 수량·단가 몫.
처음에는 공법에서 암질을 유추하려 했는데 **그것이 잘못 세운 문제**였음. 매핑을 걷어내고
암질 선택 하나로 바꿈 — 표준 횡단면 설정 안, 자리는 그대로.

- config 매핑 상수 → `FOREST_ROAD_CUT_SLOPE_ROCK_QUALITY_DEFAULT = "hard_rock"`.
- 판정에서 `cut_rock_kind` 를 뗌. 수량 쪽 쓰임은 그대로 둠.
- 실측(용화 63측점·구간 124개) — 기본값 경암에서 **위반 0건**. config 기본 절토비 1:0.4 가
  경암 범위(0.3~0.8) 안임. 토사 63구간도 0건. **기존 설계·수량 안 바뀜.**
  (연암으로 고르면 61건 — 1:0.4 가 연암 하한 0.5 밖이라 그때는 설계 검토가 필요함.)

시험 8건 — 별표2 값 · 작업임도 제외 · **암질은 설계자가 고르고 기본은 경암** ·
**공법으로 암질을 추론하지 않음** · 구간별 판정 · 소단이 있어도 위반이 안 사라짐 ·
경계값 통과 · 카드에 같은 방식으로 붙는지.

7-3 회귀에 소단 한 줄 더함 — 「소단은 값이 아니라 **기하 입력**이라 계산 뒤에 베껴 붙이면
`berm` 값만 남고 계단이 안 그려진다」. 저장분 소단을 **계산 전에** 읽어 넣는 순서를 지킴.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07): 「연암과 경암 / 발파암과 리핑암 선택은 횡단도에서 선택 안함.
사유는 향후 설계내역에서 설계자가 직접 비율로 지정하기로 함. 암반 지정과 범위 애매모호한
경우가 있어. 실무자는 그렇게 하기로 판단함. 대신 경고부분은 삭제해주고 대신 각도를
사용자가 넣을수 있게 반영.」

**왜 폐기인가** — 판정이 서려면 측점마다 암질(연암·경암)을 못 박아야 하는데, 실무에서
암반 지정·범위가 애매해 그 못 박음 자체가 틀린 전제였음. 암 비율은 **설계내역 단계에서
설계자가 비율로** 넣음. 기준이 없으니 경고도 없음.

되돌린 것 — 1e596846(암질 선택) + 973128f7(별표2 경고). 카드 경고 배지 · 판정 모듈 ·
config 범위표 · context 필드 · 표준 패널 암질 칸 전부 사라짐.

⚠ **남긴 것** — `cut_slope_segments`(구간별 경사)는 지우지 않음. 소단 기하가 그 위에
서 있고 구간 경사를 아는 값이라 뒤에 쓸 자리가 있음. 4e7a4bf7(사면 구간 재료를 그린
경사비로 가름 — 무릎 위 라벨 13구간 오류 수정)도 남김. 검사와 무관하게 옳은 고침임.

시험 4건 — 되살아나지 않게 막는 쪽으로 다시 씀(판정 모듈 없음 · 카드 경고 없음 ·
암질 고르는 자리 없음 · **구간별 경사값은 남아 있음**).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
앞 커밋으로는 화면 값이 안 바뀌어 실화면에서 두 가지를 더 찾았음.

① **TS 결과에 소단을 안 실었음** — 파이썬만 되싣고 브라우저 판을 빠뜨렸음.
   판정(`fillSlopeLengths`)은 브라우저에서 도는데 `design.berm` 이 없어 종전 식으로 갔음.

② **소단을 폭으로 찾으면 못 찾음** — 설계선 꼭짓점에는 지반 샘플(0.5m 격자)이 섞여 있어
   폭 0.5m 짜리 소단이 **두 도막으로 쪼개짐**(실측: 평탄부 0개). 게다가 설계선은 오프셋
   오름차순이라 **우측(음수) 성토면은 같은 소단이 `-기울기`로 나와** 부호를 그대로 대면
   역시 못 찾음.
   ⇒ **기울기로 가름.** 소단은 2°(0.035), 성토는 1:1.2~2.0(0.5~0.83)이라 성토 기울기의
   절반만 잡아도 확실히 갈림. 쪼개져도 부호가 뒤집혀도 걸림.

실화면 확인(8001·5174, `stale:false`) — 측점 2820.0m, 성토사면이 긴 자리:
· 소단 없음 → **≥32.54m** (옹벽·석축 의무 대상)
· 폭 0.5m·3m마다 놓음 → **≥3.00m** (5m 이내 — 의무 해소). 3.00m 은 소단 간격 그대로임
· 옆 측점(2840.0m, 안 놓음) → **≥32.54m 그대로**

**소단 없는 측점은 값이 안 바뀜 — 272측점 전수 대조, 달라진 곳 0.**
구조로도 보장됨(`design.berm` 이 없으면 종전 식을 그대로 탐).

전체 542 passed · 18 skipped. TS 타입 검사 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07) — 소단은 좌측 별도 폼이 아니라 **다른 옹벽·기슭막이와 같은 자리**
(구조물 배치)에서 놓는 것으로 바뀜. 기하는 그대로 두고 **입구만 옮겼음.**

· 레지스트리에 **C군(사면안정) 「소단」** 신설. 옵션은 다른 C군 구간형과 같은 꼴 —
  길이·기준측점 전·후 + 폭·간격(사면길이)·안쪽 기울기.
· ⚠ **소단은 C군 구간형이지만 벽이 아님** — 기슭막이 제원 자리에 얹히지 않게 파이썬·TS
  양쪽 벽 필터에서 뺐음. 안 뺐으면 소단을 놓는 순간 「독립 기슭막이」로 그려졌을 것임.
· 구조물 목록이 바뀌면 소단 구간을 세션 사본(`berm`)으로 펴고, 달라졌을 때만 재계산함.
  계산 계통(브라우저·서버·`USER_TOUCHED_KEYS`·옹벽 의무 판정)은 **한 줄도 안 바꿨음**.
· ④에서 만든 좌측 별도 「소단」 패널은 걷어냈음(모듈 삭제).

**안쪽 기울기 기본값 2° → 0°** (사용자 재확정). 기울이는 것은 실무이나 법령·교본 근거가
없어 기본으로 넣지 않고 폼에서 받음. 주석·지식DB 방침도 그에 맞춰 고침.

**소단측구**(B군 종단배수)도 같은 꼴로 옵션을 붙였음 — 소단 위에 놓이는 시설이라 폭·간격이
소단을 따르고, 기울기만 **사면 쪽**(소단과 반대). 소단이 실제로 서면서
`PENDING_TYPE_IDS` 빈 칸이 풀려 연장 수량이 다른 구조물과 같은 길로 나옴.

자체검증 — 「근거 없는 기본값 금지」 시험에 두 타입 12개 기본값을 근거와 함께 등재.
소단측구 연장 시험을 「빈 칸」에서 「연장 100m」로 뒤집음. 전체 544 passed · 18 skipped.
TS 타입 검사·ruff 통과. 화면 확인은 다음 단계.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-07): 「대신 경고부분은 삭제해주고 대신 각도를 사용자가 넣을수 있게 반영.
전체 공통으로 변경하는 경우에는 기본값 지정으로 하면 되지만 횡단도 하나만 변경하는 폼은
가져야함 / 개별 횡단도에는 암 절토 각도의 개별 수정 가능해야함」

**화면** — 암 측점 카드 아래에 「암 절토 68.2° ↺」 칸이 섬. 값을 넣으면 그 측점만 사면이
새 경사로 다시 그려지고 절토량도 따라 바뀜. ↺ 는 표준값으로 되돌림. 전체를 바꾸는 자리는
종전대로 좌측 [표준 횡단면 설정]임.

**계산에 넣는 자리는 한 곳씩** — 파이썬 `compute_cross_design(cut_slope_ratio=…)` ·
TS `computeCrossDesign({cutSlopeRatio})` 의 **그룹을 만든 바로 뒤**에서 경사비만 갈아 끼움.
부르는 쪽 9곳에서 표준값을 측점마다 복제하는 방식은 안 씀(한 곳만 빠져도 값이 조용히
사라지는 실패군). 기하·소단 코드는 한 줄도 안 건드림 — 25 확인대로 소단이 그 값을 읽어
서므로 **위치·개수가 새 경사를 저절로 따라옴**.

⚠ **경사는 나르는 값이 아니라 기하 입력임** — 계산 뒤에 키만 베껴 붙이면 설계선은 옛 경사로
그려지고 숫자만 새것이 됨(소단에서 겪은 자리). 그래서 재계산 세 경로(포장 강제·세월교 하강·
선형 재계산)와 브라우저 재계산·서버 프리뷰 **모두 계산 인자로** 넘김.

**되돌리기는 0 을 남김** — 세션에서 지우기만 하면 정본에 남은 옛 사용자 값이 되살아나
표준으로 못 돌아감. 0 = 「표준값을 씀」.

값의 길 — 세션 `cutslope`(등록표 한 줄) → 카드 입력 → [저장]·[확정]에서 `cross_patches`
(`design.cut_slope_ratio_user`) → 정본. `USER_TOUCHED_KEYS` 양쪽에 넣어 **표준을 바꿔도
개별로 고친 측점은 그대로** 둠(사용자 원문 끝줄).

시험 — 새 7건(넣은 경사가 실제로 그려짐 · 무릎 위 토사 경사는 그대로 · 0 은 되돌림 ·
재계산에도 남음 · **계산 전에 넘어감** · 각도↔경사비 · 칸은 암 측점에만),
거울 시험에 「암 절토 경사를 측점에서 바꿈」 한 갈래 추가, 7-3 회귀 한 줄 추가.
전체 **483 passed · 17 skipped**.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-07): 「리핑암과 발파암 버튼을 삭제하면서 구분의 의미가 없어졌어. …
토사버튼만 존재하고 이값은 활성화/비활성화로 반영(기본값은 비활성화) / 비활성화 상태에서는
암경계선이 나오고 암경계선 아래는 사용자가 지정한 암 절토각 반영. 이후는 토사 절토 각도를
반영 / 활성화 상태에서는 암반이 없으니 절토는 토사 절토 각도로만 구현」

**화면** — 카드 제목줄의 지반유형 버튼 셋(토사·리핑암·발파암)이 **「토사」 단추 하나**가 됨.
색으로 켜짐/꺼짐을 보이고 **기본은 꺼짐(암)**. 측구 토글과 같은 꼴임.

실화면 확인(용화 5601e828 · route 169 · 측점 1+0.0):
· **암**(꺼짐) — 암 경계선·암 절토각 칸 보임, 절토 토사 1.99 + 암 1.91 = **3.90㎡**
· **토사**(켜짐) — 두 칸 사라짐, 절토 **전량 토사 7.20㎡**(토사 경사가 더 완만해 더 팜)
· 다시 끄면 3.90㎡ 로 정확히 원복

**저장값은 종전 그대로** — 꺼짐 = `ripping_rock`, 켜짐 = `soil`. 옛 자료의 `blasting_rock`
도 「암」으로 읽힘. ⚠ 유토곡선·수량은 이제 암을 **한 종류(리핑암)**로 잡음 — 연암:경암 ·
발파암:리핑암을 가르는 것은 **설계내역에서 설계자가 비율로**(계획서 8-1).

표준 횡단면 설정의 절토·성토 경사 칸에 **각도를 함께 보임**(툴팁) — 카드가 도(°)로 받으므로
두 자리의 말이 갈리지 않게 함. 1:0.4 = 68.2° · 1:1.0 = 45° · 1:1.5 = 33.7°.

⑤ **표준을 바꿔도 개별로 고친 측점은 그대로**를 실화면에서 확인 —
1번 카드에 40° 를 넣고 표준 암 절토경사를 0.4 → 0.8 로 바꿔 [전체 측점 반영]:
· 1번(사용자 값) **40.0° 유지 · 암 절토 5.66㎡ 그대로**
· 2번(값 없음) 68.2° → **51.3°**(=1:0.8) · 암 절토 2.61 → 4.01㎡
· 표준을 되돌리자 둘 다 원상 복귀

시험 3건 더 — 토글 하나인지 · 기본이 암인지 · 옛 발파암 자료도 암 기하로 읽히는지.
전체 **486 passed · 17 skipped**.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
근거 — 실무 오솔길 EARTH.DAT 헤더 6개 공사지가 전부 `20.0 / 60.0`
(거창·장수·진안·봉화·영월 본선·지선). 산림과임업기술 5장 「다. 공사수량의
산출」도 「도저운반성토 60m 이하 / 덤프운반성토 60m 초과(건설표준품셈
참조)」로 규정. 70m 는 Aislo 단독값이었음(2026-08-02 잠정 확정).

- config_system_design.py — EARTHWORK_HAUL_EQUIPMENT_LIMITS_M 의 dozer
  경계와 주석의 확정 이력·근거 갱신. 정의처가 이 상수 한 곳이라 다른 코드
  변경 없음.
- common_util_mass_haul_balance.ts — 경계현 설명 주석의 70m 표기 정정.

검증 — 백엔드 재시작 뒤 공용 브라우저에서 실제 API 호출,
sections/context 의 dozer.max_distance_m = 60 확인. 회귀 369 passed
(실패 3건은 haul 미참조 기존 깨짐).

지식DB 미결 No.21 해소 — 목록 정리는 위키 AI 몫.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	B06_Section/B06_Section_Api_Types.ts
아래 항목 설명은 0° 로 고쳐져 있었는데 머리말만 2° 로 남아 서로 어긋났음.
값 자체는 이미 0 이라 동작 변화 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지적 ①② 의 뿌리 하나를 고침. 곡선을 서버만 그려서, 노드를 끌거나 손잡이를
살짝 건드리기만 해도 그려 둔 선·손잡이·노드 요약을 통째로 비웠음. 그 결과 화면에서
곡선이 전부 사라져 「R 이 지워졌다」로 보였음(값 자체는 남아 [확인] 때 반영됐음).

- `buildEditedPolyline` 신설 — `build_planned_polyline` 의 **편집 갈래**
  (simplify=False + curve_flags/radii) 파이썬·TS 짝. 단순화·IP 추출·반지름 피팅은
  초기 변환 전용이라 안 옮김.
- `markEdited` 가 비우는 대신 **같은 규칙으로 다시 그림**. 나머지 곡선은 안 사라짐.
- 손잡이는 곡선 목록 자리가 아니라 **노드 번호**로 잡음 — 다시 그릴 때마다 목록이
  새로 나므로 자리로 들면 엉뚱한 곡선을 가리킴.
- 접선 자리가 모자라 R 이 눌리는 것이 끄는 즉시 보임(상태줄 「기준 미달 N곳」).
- 끌기 중에도 상태줄을 갱신 — 예전에는 아무 말이 없어 사라진 인상만 남았음.
- 서버가 곡선을 안 둔 자리(내각 179° 이상)는 **곡선 없음으로 열게** 고침. 전부 켬으로
  열면 아무것도 안 만지고 [확인]만 눌러도 곡선이 새로 생겨 노선이 조용히 바뀌었음.

거울 시험 `tmp/tests/test_route_polyline_browser_mirror.py` 10건 추가.
원호 표본 개수는 `math.sin` 의 마지막 자리 차이로 90° 처럼 딱 떨어지는 자리에서 하나
갈릴 수 있어(같은 원 위의 같은 호), 개수가 같을 때는 1e-9 로 자리까지, 갈릴 때는
현 하나분 안쪽으로 모양을 맞춤. 일부러 공식을 틀어 시험이 잡는 것도 확인함.

실화면(5174) — 노드/손잡이를 끈 뒤에도 상태줄이 「곡선 22곳(하한 R 12m)」 유지,
「기준 미달 2곳」이 그 자리에서 뜸. 종전에는 「곡선 기준 R 12m」로 바뀌며 다 사라졌음.
전체 554 passed · 18 skipped, tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-07 「묵은 것 청소」). 이름이 비슷한 표가 둘이라 **「감사 기록이 비었다」는
오진이 실제로 한 번 났던** 자리임.

지우기 전 확인(공용 DB) — `audit_logs` **0행** · 정본 `system_audit_logs` **81행** ·
이 표를 참조하는 **외래키 0건** · 코드는 쓰기(`common_util_audit.py:61`) · 읽기
(`B01_Dashboard_Repository.py:455·460`) · 정리(`purge_expired_audit_logs`) 전부 정본만 씀.

최초 스키마(`001_create_schema.sql`)는 **안 고침** — 지나간 이력은 다시 쓰지 않는 것이 규칙임.
새로 설치하면 001 이 만들고 이 파일이 지움.

공용 DB 라 **적용 전 두 창(보조 워크트리 · 데스크톱)에 알리고** 「막을 것 없음」을 받은 뒤 돌림.
서버 재시작 없음. 적용 후 확인 — 표 사라짐, 정본 81행 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지적 ③④⑤⑥ 과 추가 지시(되돌리기)를 한 묶음으로 처리.

- **③ R 라벨** — 모달 맨 아랫줄이던 곡선 편집칸을 걷고, 고른 꺾임점 **옆에 뜨는 라벨**로
  바꿈(`_Label.ts` 신설). 캔버스 밖으로 나가면 반대쪽으로 접어 넣음. 확대·이동·창 크기가
  바뀌어도 고른 노드를 따라감.
- **④ 노드가 손잡이보다 먼저 잡히게** — 반대였던 탓에 헤어핀처럼 곡선이 몰린 데서는
  노드를 아예 못 집었음. 손잡이는 **고른 곡선에만** 그림. 머리말 안내에 조작 여섯을 적음.
- **⑤ 줌·팬을 배수유역도와 동일하게**(`_Input.ts` 신설) — 휠은 **당기면 확대**(반대였음),
  계수 1.15/0.87, 상한은 화면 폭 16m 기준, 하한 0.5, **팬은 가운데 버튼 전용**.
  ⚠ 커서 고정 계산이 좌상단 기준이라 확대할수록 지점이 밀리던 것도 중심 기준으로 고침.
- **⑥ 등고선을 노선 ±300m 띠로** — 창 크기와 무관한 고정 띠라 창을 늘려도 안 깨짐.
  화면 밖 걸러내기는 종전대로 `drawPreparedLayer` 가 함.
- **되돌리기·다시하기·초기화**(`_History.ts` 신설) — [확인]이 무거워 되돌릴 길이 없으므로
  창 안에서 물릴 수 있게 함. **끌기 한 번이 한 걸음**이고 클릭만으로는 걸음이 안 생김.
  [초기화]는 **이 창을 연 상태**로 (≠ [예상노선으로]). Ctrl+Z / Ctrl+Y · Ctrl+Shift+Z.
- 700줄 제한 — 집기(hit test)를 `_Input.ts` 로 옮겨 본체 695줄.

실화면 검증(5174) — 라벨이 노드 오른쪽 [+18,−38]px 에 뜸 / 휠 당기니 중심에서 373.1 →
428.1px 로 확대 / 왼쪽 끌기로는 지도 안 움직임 / 가운데 버튼 끌기는 [60,40] 그대로 따라옴 /
단추 켜짐이 여섯 단계 모두 맞음. 전체 554 passed · 18 skipped, tsc 통과. 정본 안 건드림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지적 3건 반영.

- **접선점 표기 복구** — 손잡이를 「고른 곡선만」으로 줄이면서 직선↔R 만나는 자리의
  **표기까지 없앴음**. 접선점은 손잡이이기 이전에 읽을 정보라 **늘 그림**(고른 곡선은
  속을 채워 도드라지게). 노드를 못 집던 문제는 집기 우선순위로 이미 풀려 겹치지 않음.
- **라벨을 반지름 + 곡선 길이 두 칸으로, [자동] 단추 삭제** — 교각 Δ 는 앞뒤 직선이
  정하므로 L = R·Δ 로 묶임. 길이를 받으면 R 로 바꿔 한 값만 보관. 칸을 비우면 자동.
- **라벨 자리를 곡선 중심의 반대쪽으로**(상하좌우) — 중심 쪽에 두면 곡선을 가림.
  중심 방향은 접선점 두 방향 단위벡터의 합(각 이등분선)으로 구함.
- ⚠ 라벨 글자가 안 읽히던 것 — `--color-surface-2` 가 이 테마에 없어 밝은 기본값으로
  떨어졌음. 모달 본체와 같은 토큰으로 교체(실측 배경 rgb(37,31,56)·글자 rgb(228,224,240)).
- 상자 높이가 늦게 자라 자리가 11px 어긋나던 것도 다음 프레임에 다시 맞추게 함.
- 700줄 유지 — 교각·중심방향은 `_Label`, 등고선 띠는 `_Input` 으로 옮겨 본체 687줄.

실화면 검증 — 접선점이 고르기 전에도 보임 / 곡선 길이 40 → 반지름 203.7m 로 따라옴 /
라벨이 중심 반대쪽(위)에 붙음 / [자동] 없음. 554 passed · 18 skipped, tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시 5건. ⚠ **화면 검증은 아직 못 함** — 다른 창의 분배 조율로 git sync 를 먼저
하게 되어 미커밋으로 두지 않으려고 먼저 커밋함. 타입 검사·시험은 통과 상태임.

- **1. 패널을 화면으로** — `document.body` 에 `position: fixed` 로 띄움. 모달이
  `overflow: hidden` 이라 안에 두면 가장자리에서 잘렸음. 이제 모달 밖으로도 넘어감.
- **2. 너무 가까움 + 위치 제어** — 여백 14 → 40px 로 넓히고 방위별 상자 반지름만큼 더 밀어냄.
  **머리를 잡아 손으로 옮길 수 있음**. 옮긴 자리는 꺾임점 기준으로 기억해 지도를 옮기거나
  확대해도 따라오고, 다른 꺾임점을 고르면 자동 자리로 돌아감.
- **3. 자동 위치를 16방위로** — 4방위는 대각 자리에서 곡선을 물었음. 곡선 중심의 반대 방향을
  22.5° 단위로 맞춤.
- **4. 「법정 하한」 삭제**, 「칸을 비우면 자동」을 **다음 줄**로 뺌. 대신 무엇을 붙들고
  있는지(고정 없음 / 반지름 고정 / 곡선 길이 고정)를 그 줄에 냄.
- **5. 반지름·곡선 길이 고정 단추** — 노드를 옮기면 교각이 바뀌어 R 과 길이 중 하나는 반드시
  따라 움직임. 그래서 **셋 중 하나**임: 자동 / R 고정(길이가 따라감) / 길이 고정(R 을 L/Δ 로
  다시 잡음). 붙들어 둔 곡선은 **손잡이로도 안 바뀜**(끌면 R 이 바뀌므로 집기에서 제외).
  잠금·길이는 되돌리기 사진에도 담김.
- 새 모듈 `_Edits.ts` — 잠금 반영·상태줄 요약·서버 응답 펴기. 본체 692줄로 700줄 유지.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- `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)** — 사용자 공용 브라우저에서 **소단을 한 건 놓자 화면이 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>
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>
- `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>
- 근거 = 국가계약법 시행령 제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>
- `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>
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). 계획서 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>
화면 실측에서 드러난 표기 오류 셋 (공용 브라우저 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>
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>
B08 토적표 라우터와 B09 원가계산 라우터가 main.py 의 같은 자리(import 블록·
include_router 목록)를 각자 한 줄씩 늘려 충돌함. 둘 다 필요한 줄이라 양쪽을
그대로 살림 — 어느 쪽도 버리지 않음.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`단수처리_규칙.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>
**단수 처리를 「출력 위치」에 바인딩** (`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>
데스크탑 창이 「법정 경사 검사가 빈 값을 볼 수 있다」고 알려 와 확인함. **검사 자체가 없어
문제 없음** — 별표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>
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>
메인 창의 공종 축(`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>
**`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>
일감 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>
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>
**빈 두 성분을 채움** — `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>
배분 창이 「관측 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>
일감 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>
**㉣ 작업효율을 두 곳에 넣지 않는다 — 계획서에 없던 네 번째 규칙**
- 품셈은 작업효율 `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>
일감 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>
일감 4·5 화면의 표 부품. 이 커밋 시점에는 **아무 데서도 import 하지 않음** —
「신규 파일 먼저, 등록 줄 나중」 두 걸음 규칙(공용 파일 동시 편집 사고 예방).

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

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**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>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
일감 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>
- `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>
일감 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>
배분 창이 보고 숫자를 더해 보고 **노무 열만 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>
메인의 `막자갈`→배합 `자갈` 오탐 사례를 전해 듣고 내 필터를 재 봤더니 **같은 병이 있었음.**

- **실측** — `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>
**`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>
구조물 원단위의 `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>
**⚠ 일위대가 합계를 순공사비로 뭉쳐 넣으면 ⑤ 의 밑수가 전부 틀림**(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>
조율 창 지적으로 건설공사 표준품셈 1-3-1 을 대조함. 결과를 데이터 파일에
근거와 함께 남김.

- 야면석·고임돌·물구멍 — 산림·건설 두 품셈 모두 이름 없음(`not_found`).
  건설품셈이 다루는 석재는 해상 사석과 원석(마름돌용)뿐이고 제7장 돌공사에는
  재료 할증률표 자체가 없음. 확인한 범위를 `checked` 로 함께 기록.
- 막자갈 — 건설품셈 2호 노반재료에 4 % 로 있으나 우리 쓰임은 뒤채움이라
  조건이 다름. `candidates_pending_user` 에 조건과 함께 두고 엔진은 쓰지 않음
  (지식DB 는 근거 가이드이지 값을 확정하는 곳이 아님).
- 산림품셈 값에는 `pumsem: forest` 표시. 보완 출처를 섞지 않기 위함.
- 물구멍은 공제 대상이 아니라 관 자재임을 코드에 명시. 관 규격(법 Ø3~6㎝ /
  실무 Ø50)과 간격(법 2~3㎡ / 엔진 2.0)이 미확정임을 잠정으로 표시.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
배분 창이 「초류종자살포 배합이 네 일위대가에 있나」를 물어 확인하다 **구멍을 찾음.**

- 품셈 표 중 **첫 칸이 분류 딱지**(「자재」·「장비」)이고 **이름이 둘째 칸**인 것이 있음:
  `['자재', '종      자', '', 'kg', '0.025']` · `['장비', '종자살포기', '2,500-3,000ℓ', …]`.
  첫 칸만 보고 읽어 **그 표의 자재·장비가 통째로 빠지고 있었음** — 씨앗뿜어붙이기에서
  종자·비료·피복제·침식안정제·색소·장비 3종이 다 빠지고 **보통인부 한 줄만** 남았음.
- 첫 칸이 분류 딱지면 이름을 둘째 칸에서 읽고, 값도 그 뒤 칸에서 찾게 고침.
- **매칭 106 → 116**(노무 100 → 110). 산출 파일 다시 냄.

**⚠ 그래도 배합은 아직 못 실림 — 원인은 사급 자재 단가 미결임**
- 종자·복합비료·화이버·합성접착제·색소가 **관급 카탈로그에 없음**(임도 자재가 관급에
  없다는 앞선 발견과 같은 자리). 장비 3종(종자살포기·트럭·물탱크)도 기종 카탈로그에 없음.
- **다만 이제 못 맞춘 목록에는 남음** — 구멍을 목록으로 드러내는 규칙 그대로.
  시험으로 못 박음(`test_seeding_materials_are_listed_not_dropped`).
- ⇒ 사면 4계열의 배합이 **B09 일위대가 몫**인 것은 맞으나, **사급 단가가 들어오기 전에는
  못 세움.** 「자재총괄에 이을 것이 없다」는 메인 판정은 유지되고, 그 자재는
  **㉡ 6번 슬롯 수동 입력 목록**으로 감(야면석·막자갈·고임돌·물구멍에 이어).

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
일감 9. 수량 결과(작업 공종 축)와 자재 총괄(자재 축)을 각각 낸다.

- 자재 줄에는 공종코드를 붙이지 않음. 붙이면 자재가 내역 줄로 오해되어
  이중계상이 됨. `verify_no_code_on_materials()` 로 코드에 못 박음.
- `in_bill` 을 실어 무대·합계 줄을 가름. 수량은 그대로 넘김 —
  무대+도자+덤프 = 총 운반토량 검산에 쓰이는 값이라 빼면 검산이 죽음.
- `ground_class_set` 동봉. 「연암」이 몇 갈래 중 하나인지 알아야 예산내역서가 섬.
- 매핑표는 데이터 파일(`resources/data_work_item_mapping/`). 못 이은 줄은
  빈 코드로 두지 않고 `unmatched_work_items` 로 냄.

품셈 형태 판정 교차 확인 — 「첫 칸이 갈래 딱지이고 이름이 둘째 칸」인 표에서
직종을 첫 세 행에서만 찾아 12장 구조물 표 8건이 미판정으로 빠져 있었음.
딱지를 알아보는 규칙을 맨 마지막에 두어 앞 판정을 흔들지 않고 해소
(미판정 85 → 77, 생산량형 16건 불변). 비율 지시를 먼저 보면 강관동바리 같은
소요량표가 참조로 넘어가므로 소요량을 먼저 보게 순서를 잡음.

검증 — 인계 22건 + 품셈 5건 통과, 전체 500 passed.
실서버 `GET /quantity/handoff` 200 (내역 10줄·제외 1·자재 4, 갈래세트 5).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 공종 수량(코드=수량)을 일위대가에 곱해 직접비 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>
로케일 충돌 1건 해소 — B08 구역 줄바꿈 차이뿐, 상대 쪽 서식 채택
(내 B09 키는 자동 병합됨).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- B08 공종 마스터 재생성(ab39c174) 반영 — 자원 축 116 → 119 줄,
  미판정 83 → 76. 새로 붙은 것: 강관동바리(형틀목공·보통인부) ·
  신구 BOX접합(미장공)
- 기존 119 줄 중 **수치가 바뀐 줄 0건** — 밑수 판정 교정이 기존 소요량을
  건드리지 않았음. 일위대가 총액 분포도 그대로
  (최소 233.4 · 중앙 86,034.0 · 최대 1,916,466.0, 의심 저가 0건)
- 산출물에 `source_master_file`(마스터 파일 sha256) 추가 — 기존
  `source_dataset_version` 은 품셈 원판 지문이라 마스터를 다시 생성해도
  안 움직여, 낡은 파생물을 드러내지 못했음

검증: pytest 136 통과, 새 공종 2건 일위대가 적층 확인
(강관동바리 27,908.7 · 신구 BOX접합 33,273.1)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 암 시공법(ripping/blasting)을 갈래 비율 칸 아래에 붙임. 갈래 이름만으로는
  품셈 공종(암절취 FP-09-04 / 발파암 FP-09-05)을 못 고르던 자리. 기본은
  「안 정함」이고, 안 정하면 인계에서 사유와 함께 드러남. 비율 미입력 상태의
  「암」 한 줄에도 칸을 냄.
- 관급/사급은 표 안에서 줄마다 고름. 관급 줄에만 설치주체가 열리고 사급으로
  되돌리면 잠기며 비워짐. 만진 줄은 표시가 남음.
- 산출 요약(최소·중앙·최대)을 원단위·자재총괄·인계에 붙임. 단위별로 갈라 냄 —
  값이 있기만 하면 시험이 못 잡는 자릿수 어긋남을 사람이 훑게 하는 장치.

화면에서 걸려 고친 것 둘
- 관급을 골라도 설치주체 칸이 잠긴 채 남던 것. 고른 즉시 열고 닫게 함.
- 한 번 고른 시공법을 되돌릴 길이 없던 것. 설정 저장이 병합이라 빈 값을 보내도
  옛 값이 남았음. `save_section(replace_keys=…)` 로 되돌릴 수 있어야 하는 칸만
  통째로 갈아 끼움. 나머지는 그대로 병합.

앞 커밋에서 온 타입 오류 2건도 고침 (`slopeColumnCount` 미사용,
`variant: "outlined"` 는 없는 값). 앞선 확인에서 npx 가 엉뚱한 패키지를 실행해
「오류 없음」으로 잘못 봤음 — tsc 는 config/node_modules 것으로 부를 것.

검증 — 새 시험 5건 + 인계 28건 통과, 전체 509 passed. tsc 오류 0.
화면 실조작으로 시공법 저장·되돌리기, 관급/설치주체 저장·되돌리기 확인 후
검증으로 바꾼 값은 원래대로 복원.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 반영률: `quantity`(적용 후) · `quantity_gross`(적용 전) · `application_ratio_pct`
  세 칸을 함께 실음. 곱하기는 B08 한 곳에서만 하고 B09 는 산출근거에만 적음.
  100 % 인 줄도 율을 적음 — 칸이 비면 받는 쪽이 적용 여부를 단정 못 함.
  `verify_ratio_math()` 가 세 값의 정합을 재고 `build_handoff()` 가 실제로 부름.
- 할증 상태를 세 갈래로: `applied` / `not_applied` / `rate_unavailable`.
  두 갈래면 「율을 못 찾아 안 붙인 것」이 「붙였다」로 나가 나중에 진짜 율이
  들어왔을 때 한 번 더 붙음. 옛 깃발은 실제로 붙었을 때만 참으로 둠.
- 관급구분 `unknown` 이 세 번째 계약값임을 주석에 명시. B09 는 관급자재대에도
  도급 재료비에도 넣지 않고 missing 으로 뺌.
- 운반 줄이 실제로 실리는지 시험으로 못 박음(무대 in_bill=false 포함 4줄).

⚠ 반영률 누락 지적은 사실이 아니었음 — 실서버 확인 결과 네 반영률이 전부 100 %
이고, 성토면다짐·층따기가 같은 사면 면적에서 나와 값이 겹친 것임. 곱셈은
정상 동작 중. 다만 세 칸 계약은 이중 적용을 막으므로 그대로 반영.

검증 — 인계 40건 통과, 전체 523 passed. 실서버에서 세 칸 정합·할증 상태
`rate_unavailable`·검산 경고 0 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
조판
- 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>
⑩ 콘크리트 구조물. 품셈에 구조물별 표준 물량표가 없어(구조물_수량.md ·
배수공_수량.md §2) 실무 설계원본 관측값을 데이터 파일로 둠.

- `resources/data_structure_unit/` — 반중력식옹벽 H=2.0(m당) · 돌집수정 ㄷ/ㄴ형 ·
  집수정 Ø800 · 콘크리트포장 T=20cm. 줄마다 출처를 실음.
- 규격 정확 일치로만 씀. 보간하지 않음 — H=1.6 을 H=2.0 에서 줄여 쓰면 틀림
  (기초·벽 두께는 높이에 비례하지 않음). 안 맞으면 「원단위 미확보」로 드러내고
  표에 있는 규격을 함께 알림.
- BOX암거·세월교는 관측값도 없고 저장 제원에 두께가 없어 전개식도 못 세움.
  `not_found` 에 사유와 함께 남기고 미확보로 냄 — 두께를 지어내면 콘크리트·
  거푸집·철근으로 번져 나감.
- 성분마다 `basis_kind`(derived/observed)를 달아 화면에 「치수 전개 / 실무 관측」
  으로 보임. 두 근거가 한 표에 섞이므로 안 적으면 되짚을 수 없음.
- 배수관의 유입부 집수정을 별도 줄로 세움. 품셈도 관부설과 집수정을 다른
  공종으로 둠 — 한 줄로 합치면 어느 쪽 물량인지 못 가름.

품셈 몫 표시 (조율 창 제보 교차 확인)
- `인력(10%)`·`장비(90%)` 처럼 딱지가 비율을 달고 오는 표 25건 확인. 형태 판정은
  정상(requirement)이었으나 **장비 몫이 시공능력 공식이라 값이 아님**을 아무도
  알 수 없었음. `resource_shares`·`partial_ratio` 를 실어 「단가가 일부만 선 것」이
  정상으로 흘러가지 않게 함. 공식 기호는 첫 표에만 있고 뒤 표가 물려받으므로
  기호 유무가 아니라 몫 유무로 판정 — 기호로 세면 절반을 놓침(9-13-2).

반영률 계약 갱신 — breakdown 을 늘 실음(`application_ratio_breakdown` ·
`quantity_breakdown`). `application_ratio_pct` 는 두 율이 같을 때만 채우는 편의값.

검증 — 관측 원단위 17건 · 인계 43건 · 품셈 23건 통과, 전체 548 passed. tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 품셈 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>
- 거푸집 사용횟수는 **관측값이 아니라 법**임. 품셈 1-7-1 이 구조물 종류별로
  정해 둠(옹벽 3회 · 보호공 기초 6회). 원문 문구를 데이터에 싣고 우리 구조물이
  어느 예시에 걸리는지 적음. 걸리는 예시가 없으면 「사용횟수 미확보」.
- ⚠ 횟수별 재료 환산(품셈 12-4 합판 3회 46.1 %)은 **하지 않음**. 그 비율은
  일위대가 재료비에 걸리는 값이라 B08 이 곱하면 B09 와 겹쳐 두 번 줌.
  B08 이 내는 것은 접촉 면적 그대로 + 몇 회짜리인가까지. 시험으로 못 박음.
- 동바리는 슬래브를 떠받칠 때 쓰는 것이라 지금 서는 구조물(옹벽·집수정)은
  대상이 아님. 0 으로 적지 않고 「대상 없음 + 사유」로 냄.
- 거푸집 이름은 정확 일치로만 봄 — 부분일치면 「거푸집씻기」(공사용수)가 걸림.

공종코드 잇기
- 집수정 → FP-12-15, 물넘이포장 → FP-12-06 로 이음.
- 옹벽은 **품셈 12장에 그 이름의 공종이 없음**. 빈 코드로 두면 「매핑을 못 찾은
  줄」과 구별이 안 되므로 `composite` 로 묶음(타설+거푸집+철근+기초잡석)을 적음.
  일위대가 조립은 B09 몫이고 B08 은 물량과 묶음만 넘김.

검증 — 거푸집 8건 · 인계 45건 통과, 전체 558 passed. tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⑪ 준비공·사방공 — 자리를 만들되 없는 값을 지어내지 않음.
- ⚠ 벌목은 값을 안 냄. 토공집계의 「지장목제거」로 이미 서 있어 또 세우면 같은
  나무를 두 번 벰. 참고 면적만 보이고 「다른 표에서 이미 섬」으로 가리킴.
- 못 서는 줄에 사유를 적음 — 표토제거(두께·구간 미정) · 제근(입목 본수 없음) ·
  규준틀(개소 기준 미정). 공종코드는 미리 적어 둠.
- 사방공은 레지스트리의 실제 type_id 로 봄. 없으면 「해당 없음」 — 0 을 적지 않음.
  이름을 지어내면 영영 안 걸리므로 레지스트리와 대조하는 시험을 둠.

⑫ 최종 점검 — 탭 6장 전수를 실화면에서 돌려 값으로 서는 것 확인
(토적표 65측점 · 토공집계 10줄 · 운반거리 안내 · 준비공 5줄 · 구조물 원단위 10줄 ·
자재총괄 4줄). 전체 566 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
품셈에는 자원이 행이 아니라 **열 머리**에 오는 표가 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>
⑬ 운반 사슬 실증 중 발견. 정본에 저장되는 것은 유토곡선 한 벌(`mass_haul`)이고
배분은 그 안의 `haul_plan` 인데, 라우터가 바깥 껍데기를 그대로 넘기고 있었음.
`blocks` 를 못 찾아 운반 표가 항상 빈 표가 됨. [확정] 전에는 어차피 빈 표라
화면에서 티가 안 나던 자리임.

검증은 사용자 프로젝트를 건드리지 않고 서버 계산 코드(Node 번들)를 시험 노선으로
직접 돌려 실제 배분을 받아 확인함.
- 운반거리 표: 무대 3.90㎥/10m · 도자 7.80㎥/40m · 덤프 3,712.29㎥/288.12m
- 인계: 무대 in_bill=false + 수량 그대로, 도자 FP-10-11 · 덤프 FP-10-12
- 검산: 합 3,723.99 vs hauled 3,724.00 (차 0.01 — 배분 자체의 반올림)
- 장비 한계: 무대 20m · 도자 60m 이내 확인

저장 정본 모양을 그대로 넣은 시험 2건으로 못 박음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 자원 이름이 **둘째 줄**에 오는 표를 읽음 (철근 12-3:
  `구조별 | 가공 | 조립 | 계` 아래에 `철근공(인) | 보통인부(인)` 세 벌)
- ⚠ 「계」 열은 가공 + 조립을 이미 더한 값이라 **통째로 뺌** — 같이 읽으면
  두 번 셈(㉤ 열 방향 사고 자리). 검산: 간단 = 1.07 + 1.69 = 2.76 으로
  품셈 「계」와 일치
- 머리 줄에는 갈래 칸이 없어 자료 행과 한 칸 어긋나는 것 보정
- 열 머리 되풀이 금지는 **1단 표에만** 적용. 2단 표에서 같은 직종이
  공정마다 되풀이되는 것은 정상이라, 한 규칙으로 뭉치면 철근이 통째로 버려짐
- 내역서 후보 목록에 **규격 갈래**(`#무근구조물`)도 넣음 —
  B08 이 갈래 없는 코드를 보내면 후보로 보이고 임의로 안 고름

철근 현장가공 및 조립 4갈래 성립 (간단 919,146.7 … 매우복잡 1,278,375.3)

검증: pytest 165 통과(신규 2 — 「계」 열 제외 확인 + 되풀이 규칙 짝 시험)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
서브 창 제보(기준 단위 없이 도는 단가 125 중 122)의 뿌리. 밑수는 표 안이 아니라
**표 바로 위 본문**에 있음 — `### 12-2. 표면 마무리` 다음 줄의 `(단위: ㎡당)`.
표만 보면 못 찾고, 못 찾은 채 두면 「10㎡당」 표를 1㎡당으로 알아 곱셈이 10배 틀림.

- 원문 md 를 함께 열어 표 위 6줄에서 밑수를 읽음. **본문이 정본, 표 안 긁기는 보조** —
  13-3-1 이 본문 `(단위: ㎥당)` 인데 표 안 긁기가 비고의 `10㎡` 를 물어 오던 자리.
- `(단위: 인/㎡당)` 꼴은 **분모가 밑수** — 값의 단위(인)를 밑수로 읽으면 뜻이 뒤집힘.
- ⚠ 「당」도 「단위:」도 없으면 밑수가 아님. 처음에 조건을 느슨히 두어
  `(무한궤도,0.7㎥)` 를 「0.7㎥당」으로 읽어 5건이 잘못 잡혔음 — 조여서 고침.
- 위로 거슬러 보되 **다른 표에 닿으면 멈춤** — 앞 표의 밑수를 물어 오면 조용히 틀림.

밑수 확보 13 → 183 (그중 묶음 기준 36건: 떼채취 100㎡ · 큰돌쌓기 10㎡ ·
뒷채움 100㎡ · 묘목 1000본 · 헬기방제 160ha 등). 못 찾은 144건은
`basis_missing_2026-01-01.json` 으로 냄 — 곱해야 하는 형태만 담아 잡음을 줄임.
빈칸으로 두면 1단위당으로 오해되므로 목록으로 드러냄.

앞서 확인한 「밑수가 밀렸나」와는 다른 물음이었음 — 이번은 「아예 안 적혔나」.

검증 — 품셈 30건 통과, 전체 575 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
조율 창 판정 반영. 타설 공종은 타설 방식 × 구조물 종류로 갈림.

- **구조물 종류는 자동 판정** — 원단위 성분에 철근이 있으면 철근구조물.
  사람이 고르는 값이 아님. 옹벽 관측 원단위의 D13·D16 에서 그대로 나옴.
- **타설 방식은 설계 판단**이라 프로젝트 설정(`quantity.concrete_placing_method`)이
  고르고 기본은 레디믹스트(FP-12-01-01). 잠정이며 사용자 확정 대기.
  모르는 방식이면 기본으로 떨어지되 그 사실을 알림.
- 옹벽 묶음의 타설 코드를 `FP-12-01-01#철근구조물` 로 좁힘.
- ⚠ 묶음 넷 중 `FP-12-03`·`FP-12-25` 는 B09 일위대가가 아직 안 섬.
  `composite_not_ready` 로 함께 알림 — 지금 세우면 절반짜리가 됨.

검증 — 인계 48건 통과, 전체 578 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2단 표를 열자마자 과잉 매칭이 드러남 — 자원 축이 208 → 373 으로 뛰고
최대 단가가 2,436만원이 됨. 「한 칸 밀림」 가정이 표마다 안 맞았음

- **좌우 두 판 + 2단 머리** — 뿌리돌림 05-2 는 `근원직경 | 수량 | 근원직경 |
  수량`이라 오른쪽 판의 **직경 100 이 「특별인부 100인」**으로 읽혔음.
  첫 줄 머리가 되풀이되면 2단이라도 버림
- **라벨 칸 수가 표마다 다름** — 드론방제 08-6-2 는 라벨이 둘(`구 분 | 항 목`).
  고정 보정 대신 **숫자 칸을 순서대로** 맞추고 개수가 다르면 그 행을 버림.
  또 머리 줄 이름을 하나라도 못 풀면 표째 버림 — 넷 중 둘만 풀린 채
  숫자 둘이 **엉뚱한 직종**에 붙고 있었음
- **차원이 하나 더 있는 표** — 뭉기기 13-12-1 은 행이 공정, 숫자 칸이 토질
  3갈래인데 자원 열은 하나뿐이라 **첫 토질 값만 조용히** 서고 있었음.
  숫자 칸이 자원 열보다 많으면 버림

결과: 자원 축 231줄(갈래 88) · 일위대가 133 · 최대 5,030,954.6
(품셈대로인 값). 철근 12-3 과 콘크리트 타설 12-1 3갈래는 그대로 섬

검증: pytest 167 통과(신규 2). 갈래 표 5건 손대조 — 전부 표와 일치

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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>
목록에만 있고 화면에 없으면 사용자는 그것이 잠정인 줄도 모름. 셋 다
「지금 어떤 값으로 돌고 있는지 + 왜 잠정인지」를 함께 보임.

- 콘크리트 타설 방식을 좌측 패널 칸으로 냄. ⚠ 금액에 바로 걸리는 값이라
  기본값으로 돌고 있으면 「기본값 「레디믹스트」로 계산 중 — 아직 안 정한 값」
  안내를 띄움. 설정 기본을 None 으로 바꿔 「안 정함」과 「일부러 레디믹스트를
  고른 것」을 가름 — 값을 미리 넣으면 그 구별이 사라짐. 되돌리기도 됨.
- 물구멍 근거에 잠정값을 적음 — 「관 Ø 미정(법 3~6㎝ / 실무 Ø50) ·
  간격 2.0㎡당 1개소(법 2~3㎡당 1개소 이상)」. 「미확정」만으로는 무엇을
  정해야 하는지 모름.
- 준비공의 벌목 줄에 공종 미확정 사유와 후보를 함께 적음(수확베기·단목베기·
  위험목 베기 중 어느 것인지 원본이 말하지 않음).

검증 — 전체 580 passed, tsc 오류 0. 화면에서 셋 다 뜨는 것과 타설 방식
저장·되돌리기까지 확인 후 검증으로 바꾼 값은 원래대로 복원.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
기초잡석 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>
- ⚠ 앞 커밋의 「값 못 읽은 줄」 판정이 **머리 줄까지 잡고 있었음** —
  「특별인부 | 벌목부 | 보통인부」처럼 자원 이름만 나열된 줄. 28 공종 중
  대부분이 오탐이었음. **숫자가 있는데** 못 읽은 줄만 성분 빠짐으로 봄 (28 → 12)
- 「0.2 × 30%」꼴을 0.06 으로 읽음. ⚠ 딱지의 30 % 를 **또 곱하지 않음** —
  두 번 곱하면 0.018. 그 밖의 식(「5인/km」)은 기준이 달라 안 읽고 막은 채 둠

기초잡석 12-25 성립 (121,661.1원/㎥)
  소할 할석공 0.06 + 부설다짐 보통인부 0.6 + 적사 굴착기 0.04535hr
  (Q = 3600 ÷ 22 × 0.7 × 0.55 × 1.0 × 0.35 = 22.05㎥/hr)
  운반(덤프)은 품셈이 10장에서 따로 내므로 여기 안 붙음

⇒ 옹벽 묶음 4조각이 모두 섬 — 타설 65,826.4 · 거푸집 81,321.9 ·
   철근 1,032,497.4 · 기초잡석 121,661.1

검증: pytest 174 통과(신규 4 — 오탐 짝 시험 포함:
머리 줄은 안 걸리고, 숫자 있는 미해독 줄은 걸림)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
타설 방식 — 「무엇을 정해야 하는지」만으로는 부족하고 「정하면 얼마나 달라지는지」가
보여야 사용자가 판단함. 세 방식 단가 차이가 6배라 조용히 기본값을 쓰면 총액이 갈림.
- 방식 이름을 늘 값 옆에 보임(「적용 중: 레디믹스트 (기본값 — 확인 필요)」).
  코드(12-01-01)만으로는 무엇을 쓰는지 모름.
- 참고 단가 세 줄을 안내로 띄움 — 레디믹스트 65,826 · 기계비빔 163,508 ·
  인력비빔 408,327 원/㎥. ⚠ **표시 전용**이며 B08 의 어떤 계산에도 안 들어감
  (금액은 B09 몫). 출처·산출일을 데이터에 함께 적음.

품셈 마스터 — 값 자리에 식이 적힌 칸에 깃발(`expression_cells`).
`0.2 × 30%`(기초잡석 소할)처럼 계산이 그대로 적힌 칸은 값이 숫자로 안 읽혀
그 성분이 조용히 빠짐. 형태 판정은 통과하고 배분율 딱지도 없어 아무 검사에도
안 걸리던 자리(서브 창이 실물에서 부딪힘 — 기초잡석이 부설다짐 0.6인만으로 섬).
⚠ 식을 계산하지 않고 드러내기만 함 — 뜻을 잘못 읽으면 조용히 틀림.
31표에서 잡힘(9-12·9-13 터파기 계열 · 12-24 뒷채움 · 12-25 기초잡석 등).

검증 — 품셈 34건 통과, 전체 588 passed, tsc 오류 0.
화면에서 방식 이름·기본값 표시·단가 세 줄 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
옹벽 네 조각이 B09 에 다 서서 이제 물량을 실어 보냄.

- `composite_parts` 에 조각마다 수량·단위·근거(`basis_kind`)를 실음. 코드만
  보내면 받는 쪽이 상세 줄을 못 세움. 조각은 **원단위 성분 이름으로** 찾고
  못 찾으면 0 이 아니라 사유와 함께 `not_ready` 로 남김.
- ⚠ 철근은 ㎏ → ton 환산. 단가가 원/ton 인데 원단위는 ㎏ 이라 안 맞추면
  1000배 틀림. D13 13.45 + D16 30.42 = 43.87㎏/m × 10m = 0.4387ton.
- 철근 갈래는 **품셈 12-3 [주]① 원문**이 정함 — 「간단: 중력식 옹벽 /
  보통: 반중력식 옹벽 / 복잡: 부벽식 옹벽」. 거푸집 사용횟수(1-7-1)와 같은
  자리라 사람이 고를 칸을 만들지 않음. 캔틸레버식은 예시에 없어 「보통」으로
  때우지 않고 미확보로 드러냄.
- 전개 결과에 저장 제원(`options`)을 실어 뒤 단계가 형식을 읽게 함. 치수를
  다시 쓰라는 뜻이 아니라 읽으라는 것 — 치수 정본은 여전히 하나.
- 화면(구조물 원단위 탭)에 묶음 조각과 갈래를 보임.

⚠ 옛 시험 하나를 계약 변경에 맞춰 옮김 — `composite_not_ready` 가
「일위대가가 아직 안 선 공종」에서 「물량을 못 채운 조각」으로 뜻이 바뀜.

검증 — 인계 54건 통과, 전체 594 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`GET /api/projects/{id}/estimation/bill` — B08 인계를 서버 안에서 그대로
받아 계층을 세우고 단가를 붙여 돌려줌

- 수량은 B08 것이 정본, 여기서 다시 세지 않음 (CLAUDE.md 5장)
- 단가 없음·밑수 미확보·공종코드 없음은 0 으로 안 때우고 `missing` 으로 냄
- 이중계상 감시에 걸리면 표를 그리지 않고 409 로 멈춤

실측(프로젝트 5cff3920, 공용 브라우저 5174):
  14줄(세부 7·머리 7) · 검산줄 1 · 자재 4 · 본체합계 478,680원
  측구터파기 90.51㎥ × 5,288.6 = 478,680, 나머지 6줄은 사유째 미확보로 뜸

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면
- 「설계내역서」 탭을 켜고 [B08 수량 불러오기] 로 표를 세움.
  계층은 들여쓰기, 머리글 줄은 굵게
- 못 세운 줄은 0 으로 채우지 않고 **사유째** 표와 목록에 보임
  (「일위대가 없음」·「하위 공종에 있음(후보 2건)」·「밑수를 못 찾은 표」)
- 검산용 줄(보정량계·무대)은 수량만 보이고 금액칸이 빔
- ⚠ 「사급 자재 단가가 없어 자재비가 빠져 있음 — 지금 합계는 모자란 값」을
  합계 옆에 상시 표시

ITEM NO. 겹침 수정
- 같은 공종코드가 지반만 달리해 두 번 오면 번호가 겹치고 있었음
  (실물: 도자운반 토사/리핑암이 둘 다 `3-1`). 잎 줄은 번호를 재사용하지 않음

실측(공용 브라우저 5174, 운반이 실린 실물 자료):
  16줄 · 겹친 번호 0 · 합계 488,926원
  운반 4줄이 3-1~3-4 로 서고 무대 2줄은 검산줄로 빠짐 (㉡ 가 실물에서 돎)

검증: pytest 175 통과(신규 1), tsc 0건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「원문이 이미 정해 둠」 **네 번째** — 품셈 12-38-3 [주]④ 「보통: 측구, 수로,
옹벽, 일반적인 벽체, 박스」. 앞선 셋(거푸집 사용횟수 1-7-1 · 철근 갈래
12-3 [주]① · 밑수는 표 위 본문)과 같은 자리라 사람이 고를 칸을 안 만듦.
옹벽 → `FP-12-38#보통`, 근거 문구를 조각에 함께 실음.

- ⚠ 12-38-1 「사용횟수」는 1-7-1 과 **다른 자리**임. 그쪽은 유로폼(강재)의
  잔존율(12회 25% · 25회 10%)로 임대료·손료 산정용이고, 1-7-1 은 소모성
  거푸집 전용 횟수(옹벽 3회)임. 이름이 같아 하나로 이으면 조용히 틀림 —
  데이터에 그 구분을 적고 시험으로 못 박음.
- 유로폼 자재는 12-38-2 가 10㎡당 패널 0.89매로 냄. B08 은 **면적(㎡)** 으로
  보내고 매수 환산은 밑수를 아는 B09 가 함 — B08 이 환산하면 밑수가 두 벌.

`composite_not_ready` 를 `{code, reason}` 구조로 바꿈. 받는 쪽이 「단가 없음」과
「물량 없음」을 갈라야 함(기초잡석이 후자).

원단위 자체가 없으면 조각을 늘어놓지 않고 한 줄로 말함 — 같은 사유가 조각마다
다섯 번 반복되면 진짜 사유가 묻힘(화면에서 실제로 그렇게 보였음).

시험 추가 — 같은 공종코드가 지반만 달리해 여러 줄 오는 표본(도자 토사·리핑암).
실물에서 잡힌 모양이라 고정 자료에도 넣음.

검증 — 인계 59건 통과, 전체 600 passed, tsc 오류 0.
화면 그리기는 실제 모듈을 그대로 돌려 확인(사용자 프로젝트·DB 무접촉).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
품셈에는 소요량 대신 **「작업조 몇 인이 하루 몇 ㎡」**로 주는 표가 11건 있음.
1단위당 품 = 인원 ÷ 시공량. 행-자원으로 읽으면 **인원 4를 소요량 4로** 오해해
35배 부풀어, 형태 판정보다 **먼저** 가름
(유로폼 12-38-3 은 마스터에서 `reference` 로 찍혀 형태 필터에 버려지고 있었음)

- 유로폼 설치·해체: 형틀목공 4 ÷ 35 = 0.1143인/㎡, 보통인부 1 ÷ 35 = 0.0286인/㎡
  → 유형별 갈래로 세움 (복잡 51,009.1 · 보통 36,435.0 · 간단 31,880.7 원/㎡)
- 유형은 우리가 안 고름 — 품셈 12-38-3 [유형] 이 「보통: 측구·수로·옹벽」으로
  정해 두었으므로 갈래로 세우고 고르는 것은 B08 (철근 12-3 [주]① 과 같은 모양)
- ⚠ 못 푼 작업조 줄이 있으면 **표째 버림** — 평떼 시비에서 「트럭 2.5ton 1대」가
  조용히 빠지고 노무만으로 28.6원/㎡ 이 서 있었음(분포 최소값이 233 → 28.5 로
  떨어진 것으로 발견)
- 이름 안에 공백이 든 줄(「비 계 공」)은 한 이름으로 먼저 시도 — 공백을 구분자로만
  보면 그런 표가 통째로 버려짐

결과: 자원 축 246 → 256, 일위대가 139 → 145, 최소값 233.4 유지

검증: pytest 181 통과(신규 6 — 손계산 대조 + 오탐 짝 시험 포함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 서브 창 제보(유로폼 12-38-3 이 참조로 찍혀 읽히지도 않던 것)를 파고 들어가
더 넓은 결함을 찾음. `REFERENCE_MARKS` 의 `"단 위"` 하나로 **41건이 참조로
버려지고 있었고**, 그 안에 **돌쌓기(장비) 13-4-5·13-4-2**(우리 매핑이 실제로
쓰는 코드) · 12-2 표면 마무리 · 9-19-1 면고르기 · 9-20 뿌리다듬기 ·
13-8 막돌쌓기 · 11-2 규준틀 같은 명백한 공종이 섞여 있었음.

- 원래 겨냥은 품셈 1-2-2 「단위 표준」 표였는데 **1장은 chapter 규칙이 이미
  거르므로** 그 표지는 넓기만 했음. 「단위 열이 있다」는 소요량표의 흔한
  모양이지 참조표의 표지가 아님. 제거.
- reference 98 → 58, requirement 246 → 287. 돌쌓기(장비) 둘이 공종으로 섬.

작업조 표 깃발(`crew_table`) 16건 — 「형틀목공 4인 + 보통인부 1인 / 시공량 35㎡」
의 「4」는 소요량이 아니라 **인원**이라 그냥 읽으면 35배 부픔. 값을 바꾸지 않고
표시만 함(`expression_cells`·`partial_ratio` 와 같은 취급). 평떼 시비도 잡힘 —
서브가 실물에서 트럭 한 대를 빠뜨린 그 표.

유로폼 조각에 `incomplete_note` — 물량은 섰으나 **자재 몫(패널 0.89매/10㎡ ·
부자재 24/52/79 % · 소모자재 5 %)이 자재 단가가 없어 안 붙음**. 「못 채움」과
달리 값이 있으므로 「부분」으로 갈라 보임 — 부분 성공이 완전 실패보다 위험함.

검증 — 품셈 39건 통과, 전체 605 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
석재 할증률을 찾으러 12·13장 본문을 훑다 발견한 둘

- 품셈은 같은 기종을 「굴 삭 기」·「굴착기」·「유압식백호우」로 섞어 적음.
  메쌓기 13-6-1 의 「굴 삭 기 (무한궤도)」가 안 붙어 **장비 몫이 통째로
  빠져 있었음**. 이름 안 공백 제거 + 기종 별칭만 맞춤(규격은 안 건드림)
- ⚠ 그 정규화가 새 오독을 열었음 — 측구터파기의 「유압식백호우 … | k | 0.9」
  줄이 자원으로 잡혀 **버킷계수 0.9 를 소요량으로** 읽었음(사용료 0.9시간분
  이중). 공식 기호(K·f·E)를 단 줄은 자원으로 세지 않음 — 그 줄은 시공능력
  공식 쪽에서 씀

결과: 자원 축 256 → 259, 일위대가 145 유지, 최소 233.4 / 최대 5,030,954.6

석재 할증률은 **품셈에 없음을 확인** — 1-3-1 재료 할증률표에 야면석·막자갈·
고임돌이 없고, 13-4~13-7 돌쌓기 본문 [주]에도 할증 문구 없음. 사용자 확정 대기

검증: pytest 183 통과(신규 2 — 공식 줄 제외 + 공백 이름 매칭 짝 시험)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
서브 창 제보 교차 확인. 값을 바꾸지 않고 깃발만 실음.

- `spaced_names` 20건 — 「굴 삭 기 (무한궤도)」처럼 자간 공백이 든 자원 이름.
  같은 표 묶음 안에서도 표기가 갈림(13-6-1 은 공백, 바로 옆 13-6-2 는 없음).
  받는 쪽이 이름으로 찾으면 그 줄이 통째로 빠짐.
  ⚠ 여기서 이름을 고치지 않음 — 정규화는 값을 살리지만 잘못된 줄도 함께 살림
  (서브 실례: 정규화 직후 버킷계수 K 를 소요량으로 읽어 사용료가 이중).
  ⚠ 처음 101건으로 넓게 잡혔던 것을 **단위 칸 + 수치가 함께 있는 자원 줄**로
  좁혀 20건. 짝 시험(「단 위」·「모 래」는 안 걸림)을 같이 둠.
- `formula_rows` 24건 — 값 자리에 K·f·E·Cm 가 온 줄. 자원으로 세면 이중계상.

㉥ 물빼기 파이프 이중계상 — 품셈 13-6-2·13-7-2 [주]③ 이 제잡비 **윗단** 값에
「물빼기 파이프 설치에 관계되는 노무비, 재료비를 포함한다」고 함. 우리 원단위가
물구멍을 자재로 내므로 그 쪽과 겹침.
- **우리 선택: 물구멍을 자재로 세우고 제잡비는 아랫단(미설치)** 을 씀. 까닭은
  자재 줄로 세우면 규격·수량이 눈에 보이고 되짚을 수 있기 때문. 데이터와 코드
  양쪽에 적음.
- ⚠ 지금 쓰는 13-4 계열에는 **제잡비 행 자체가 없어 겹치지 않음**(전수 확인).
  이 규칙은 13-6·13-7 을 쓰게 될 때 걸림.

관측값이 원문과 맞는 첫 사례 기록 — 채움콘크리트 0.2㎥/㎡ 가 품셈 13-6-2 [주]⑩
「뒤채움콘크리트량은 0.2㎥ 기준」과 일치.

갈래 키 정규화 — `code` 는 내부 공백만 제거(`FP-12-03#보통`), 원문 문구는
`kind_label` 로 함께 실음. 다른 글자는 안 건드림(괄호·기호 유지 짝 시험).

검증 — 품셈 43건 통과, 전체 611 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 마감 중 발견 — `boulder_masonry`(큰돌쌓기)를 `stone_masonry(dry)` 로 전개하고
있었음. 큰돌쌓기는 품셈 13-6, 돌쌓기는 13-4 로 **규격 축이 다름**: 돌쌓기는
뒷길이(35·45·55·60㎝), 큰돌쌓기는 직경(40~60·60~80·80~100㎝). 직경 60~80㎝
짜리가 「뒷길이 45㎝」 계수로 돌아 고임돌 0.15·야면석 0.88 이 붙고 있었음.
값이 나오기는 해서 어떤 시험도 안 잡던 자리 — 전개식이 설 때까지 미확보로
드러내고(`EXPANDER_WITHHELD`) 왜 안 두는지 사람이 읽게 적음.

⑱ 화면에 안 보이던 미확정 조건 셋을 구조물 원단위 탭에 띄움. 「무엇을 정해야
하는지」만으로는 부족하고 「정하면 얼마나 달라지는지」까지 적음.
- 흡출방지재·차수시트 — 보통인부 1.04 → 1.17 인/10㎡(약 +12.5 %), 근거
  13-6·13-7 [주]②. ⚠ 큰돌쌓기·큰돌붙이기에만 걸리고 돌쌓기(13-4)에는 괄호 값
  자체가 없다는 범위도 함께.
- 목재틀흙막이 원단위 — 1㎥당 건축목공 16.975인, 각재·판재가 없어 모자란 값.
- 내역서 수량 표시 자릿수 — `단수처리_규칙.md` 에 금액 자리만 있음.

검증 — 전체 612 passed, tsc 오류 0. 화면에서 셋 다 뜨는 것 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인이 `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>
⑲. 앞서 막아 둔 큰돌쌓기를 13-6 축으로 세움.

- `boulder_masonry` 전개식 — 규격 축은 **직경**(40~60·60~80·80~100㎝)이고
  저장 제원 `stone_cm` 이 품셈 축과 글자까지 같아 그대로 씀.
  치수로 낼 수 있는 것(면적·터파기·되메우기·잔토)만 내고 나머지는 사유와 함께 알림.
  - 재료(큰돌)는 13-6 [주]⑦ 「재료량은 설계수량을 적용한다」라 원단위가 없음.
  - 고임돌·채움콘크리트는 [주]① 「품에 포함」 — 따로 세우면 이중계상.
  - 뒤채움(조약돌)은 [주]⑧ 로 13-3 적용. 두께는 13-4-3 [주]⑨ 준용인데
    직고별 **범위값**이라 한 값으로 못 정함 — 미확보.
  - 터파기 폭 규정이 품셈에 없어 돌쌓기 방식을 준용하고 그 사실을 근거에 적음.
- ⚠ 메/찰 구분 칸이 저장 제원에 없어 13-6-1/13-6-2 를 못 고름. 레지스트리는
  다른 창 소관이라 손대지 않고 `pending_user` 로 드러냄.

⚠ 함께 발견 — 엔진이 읽는 옵션 키가 레지스트리와 달랐음.
레지스트리는 `back_len_cm` 인데 엔진은 `stone_back_length_cm` 을 읽고 있어
**저장값이 영영 안 닿고 늘 기본 45㎝ 로 돌았음**. 뒷길이를 75 로 골라도 45 계수가
붙던 자리이고, 값이 나오므로 아무 시험도 안 잡았음. 두 이름 다 읽게 하고,
표에 없는 값(25·30·75)은 **덮는 위 칸**으로 접되 그 사실을 적음.

돌쌓기 뒷길이 갈래를 자동 판정해 코드에 붙임(`FP-13-04-05#55cm이하`).
「…㎝ 이하」 구간이므로 **저장값 이상인 첫 경계**를 고름. 근거 문구를 함께 실음.
갈래표는 `resources/data_masonry/` 에 데이터로 둠.

검증 — 전체 621 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
제잡비 (품셈 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>
`back_len_cm` 사고(레지스트리 키와 엔진이 읽는 키가 달라 저장값이 영영 안 닿던 것)
뒤 전수 훑기. B08 이 읽는 옵션 키 7개를 레지스트리와 대조한 결과 어긋남은 하나뿐이고
그것은 이름 어긋남이 아니라 **칸 자체가 없는 것**임(`face_slope_ratio` — 전면 기울기,
늘 기본 0.3 으로 돎). 「칸이 생기면 받는다」는 뜻으로 남겨 두고 코드에 그 사실을 적음.

대조를 시험으로 둠(`tmp/tests/test_b08_option_keys.py`) — 「이름으로 알아보는 코드는
정본과 대조하라」의 데이터 키 판. 칸이 생겼는데 목록만 남는 것도 잡음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉑. `back_len_cm` 같은 개발자 키가 그대로 화면에 뜨던 자리를 모두 바꿈
(`B08_Quantity_Wording.py`). 반영률 라벨이 서버 키로 뜨던 그 자리와 같은 병.

- 「없다」만 말하지 않고 **어디서 채우면 값이 서는지**를 함께 적음.
  「돌 뒷길이(㎝)가 아직 입력되지 않았습니다 — 구조물 상세 입력에서 입력하면
  값이 섭니다」 · 「옹벽의 이 규격은 자료에 없습니다 — 자료에 있는 규격:
  옹벽 형식 반중력식 · 높이(m) 2.0」
- 규격도 사람 말로 — `form`·`height_m` 이 아니라 「옹벽 형식」·「높이(m)」.
- ⚠ 모르는 키는 지어내지 않고 그대로 보임. 잘못된 안내가 없는 안내보다 나쁨.
- 키가 새는지 검사를 둠(`test_b08_wording.py`) — 새 문구를 넣다 흘리면 깨짐.

검증 — 문구 9건 통과, 전체 633 passed. 실물 프로젝트(`5601e828`)로 문구 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 이 보내는 칸 중 **하나(`application_ratio_pct`)만 읽고 있었음** — 나머지는
조용히 버려지고 있었음. 메인이 「저장값이 안 닿아 늘 기본값으로 돌던」 결함을
잡은 것과 같은 자리라 대조해 발견

- 새로 읽는 칸: `quantity_gross` · `application_ratio_breakdown` ·
  `quantity_breakdown` · `composite_parts` · `composite_not_ready` ·
  `structure_kind`
- **묶음 줄 조립** — 품셈에 그 공종이 없는 것(옹벽)은 조각들의
  `단가 × 조각수량` 합이 곧 그 줄의 1단위 단가. 조각이 하나라도 비면
  **금액을 안 만들고** 사유를 그대로 적음
- `composite_not_ready` 만 온 줄도 묶음으로 봄 — 그러지 않으면 「코드 없음」으로
  뭉뚱그려져 무엇이 없는지 안 보임
- 구조물 줄은 사유를 갈라 적음 — 「구조물 전개식(원단위)이 없어 조각을 못 세웠습니다」

실측(구조물 시험 프로젝트 5601e828): 23줄 · 합계 540,244원
  돌쌓기(찰) 4줄이 「후보 3건」으로 뜸 — 뒷길이가 저장 안 돼 갈래를 못 고름.
    임의로 고르지 않고 후보를 보임
  옹벽은 「원단위 미확보 (retaining_wall H=2.5) — 표에 있는 규격: 반중력식 H=2.0」
    으로 사유째 뜸
  ㉥ 가드 오탐 없음(메인이 택한 아랫단 + 물구멍 자재 조합에서 안 걸림)

검증: pytest 190 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
서브 화면에 「왜 안 서는지」가 안 뜨던 줄 셋(돌쌓기·흙막이·큰돌쌓기)을 고침.

- `blocked_reason` · `blocked_kind` 를 줄마다 실음. 갈래는 셋 —
  `input_missing`(입력하면 풀림) / `unit_data_missing`(자료 없음) /
  `formula_missing`(산출식 없음). 받는 쪽이 「사용자가 입력하면 풀리는 것」과
  「우리가 만들어야 하는 것」을 화면에서 갈라야 함(8-27 표와 같은 축).
- 문구는 `B08_Quantity_Wording` 것을 그대로 씀 — 두 벌로 짜면 갈림.
- 토공·운반 줄은 막힐 자리가 없어도 **칸은 둠** — 계약이 한 모양이어야 함.

⚠ 계약 칸 대조 시험 추가(`test_b08_handoff_contract.py`).
오늘 이 병이 계약 양쪽에서 하나씩 났음 — 우리 쪽은 레지스트리 키와 엔진이 읽는
키가 달라 저장값이 안 닿았고, 받는 쪽은 우리가 보낸 `composite_parts`·
`quantity_gross` 를 안 읽고 버렸음. **「보내는 쪽은 보냈는데 받는 쪽이 안 읽는」
자리는 양쪽 다 조용함.** 키를 늘릴 때 계약에 안 적고 늘리면 받는 쪽이 영영 모름.
자재 줄에 공종코드가 없는 것도 계약으로 못 박음.

검증 — 전체 638 passed. 실물 프로젝트(`5601e828`)에서 네 줄 다 사유가 실림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
인계 계약 시험 (같은 병 재발 방지)
- **B08 이 보내는 칸을 내가 실제로 읽는지** 시험으로 마주 걺. 새 칸이 오면 깨짐.
  안 읽는 칸은 까닭을 함께 적게 함(측점·spec_detail 등)
- 값이 자료형까지 실제로 닿는지도 짝으로 봄 — 이름만 맞고 값이 안 실리면 같은 병

㉦ 가드 신설 (품셈 13-6 [주]① 「고임돌 및 채움 콘크리트 등은 품에 포함」)
- 큰돌쌓기 줄이 서 있는데 **그 구조물이 낳은** 고임돌·채움콘크리트가 자재로도 서면 멈춤
- ⚠ 13-6 한정 — 돌쌓기 13-4 의 고임돌은 정상이라 안 걸림. 짝 시험 2건
- 내 일위대가는 그 둘을 안 세우고 있음을 확인(품셈 표에 없음)

수량 표시
- 내역서 수량을 **소수 2자리**로 보임. 계산은 전정밀 그대로
- 「표시는 2자리, 계산은 전정밀 — 표시값끼리 곱하면 끝자리가 다릅니다」를 표 아래 상시 표시
  (실무 서식 자릿수는 기준 문서에 없어 2자리는 잠정)

검증: pytest 195 통과(신규 5), tsc 0건, 화면 실측 — 15,726.93 · 92.45 로 뜸

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
데스크탑 창 보고(2026-09-08): 실무 프로젝트 구조물의 **상세 옵션이 통째로 비어 있음** —
`back_len_cm`(뒷길이) · `stone_cm`(돌규격) · `form`(옹벽 형식). 그래서 B08 수량이 품셈 갈래를
못 골라 **금액이 0 으로 남음**(13-4 돌쌓기 뒷길이 · 13-6 큰돌쌓기 직경 · 12-3 옹벽 형식).

**까닭 — 아무도 안 받고 있었음.** 레지스트리가 그 칸들을 `phase: "detail"` 로 두고
「B05 는 유무·종류·위치만, **상세 치수는 B06/B07 에서**」(2026-08-17 사용자 확정)로 갈라 놨는데,
**그 화면이 아직 안 그리고 있었음**. 폼은 한 벌인데 필터(`isB05Option`)가 늘 상세를 숨겼음.

고침 — 폼이 `includeDetail` 을 받아 **B06 에서만** 상세 칸까지 그림(B05 는 종전 그대로).
새 결정이 아니라 **2026-08-17 확정을 이제 구현한 것**임.

⚠ **기본값 없는 필수 항목은 빈 칸(「— 선택 —」)으로 연다** — 첫 항목을 슬쩍 고르면 근거 없는
값(뒷길이 25㎝ 같은)이 수량·단가로 흘러감. 설계자가 고르게 둠.

**큰돌쌓기에 「쌓기 방식」(메쌓기·찰쌓기) 옵션 신설** — 품셈이 13-6-1 메 / 13-6-2 찰로 갈라
두는데 구분 칸이 없었음(돌쌓기는 이미 타입이 갈려 있음). 기본값 없음·필수·상세.

실화면 확인(용화 5601e828 · B06) — C군 → 큰돌쌓기 고르면 **돌규격·쌓기 방식** 칸이 빈 채로 뜸.
돌규격 `60~80` · 쌓기 방식 `찰쌓기` 로 한 건 넣고 [저장] → 정본 `structures.json` 에
`{"stone_cm": "60~80", "bond": "찰쌓기", …}` 로 남는 것 확인. 시험분은 지우고 저장해
**원래 7건**으로 되돌림.

시험 5건 — B06 만 상세를 받는지 · B05 는 종전대로인지 · 기본값 없는 필수는 빈 칸인지 ·
큰돌쌓기 메/찰 구분 · **규격 축이 타입마다 다른지**(큰돌쌓기=직경, 돌쌓기=뒷길이 — 데스크탑이
섞여 있던 결함을 잡은 자리). 전체 501 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉓. ㉒ 에서 원문을 찾아 닫힌 셋을 구현.

- **비탈 규준틀 개소** — 품셈 11-2 [주]① 「비탈길이 10m 이상 20m마다 설치」.
  사면표의 측점별 사면길이·거리로 셈. ⚠ 「10m 이상」은 비탈길이 조건이고
  「20m마다」는 노선 거리 간격이라 둘을 안 섞음. 재료량은 [주]④ 「설계수량」이라
  개소만 내고 재료는 미확보로 둠.
- **수평 규준틀**은 11-3 [주]① 이 「중심점 성토고 5m 이상」인데 성토고가 사면표에
  없어 0 으로 때우지 않고 미확보로 둠.
- **목재틀흙막이 갈래** — 품셈 13-13-1 [주]③ 이 재료 구성으로 가름.
  임도 흙막이는 「보통구조 상(통나무 기슭막이)」로 잠정 판정. ⚠ 잠정임을 근거
  문구에 드러내고 「상등구조를 쓰면 8.760 → 16.975 인/㎥ 로 약 1.9배」를 함께 적음.
  갈래표는 데이터 파일(`resources/data_timber/`)이라 줄만 더하면 늘어남.
  ⚠ 밑수 1㎥ 는 구조물 체적이 아니라 **목재 채적**임을 데이터에 명시 — 그래야
  「1㎥에 건축목공 17인」이 말이 되는지 판단됨.
- **표토제거 두께** — 9-15 [주]② 가 「T : 표토두께(m)」로 공식의 입력 변수로 둠.
  품셈이 정하는 값이 아니므로 설계 입력 칸(`quantity.topsoil_thickness_m`)으로 냄.
  ⚠ 기본값 없음 · 미입력이면 물량 안 냄(0 으로 때우지 않음). 대상 면적은 참고로 보임.

검증 — 준비공 16건 통과, 전체 642 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 이 `blocked_reason`(사용자 말 문구) + `blocked_kind` 를 실어 보내기 시작함

- 문구는 **B08 것을 그대로** 씀 — 두 벌로 짜면 한쪽만 고쳐지는 자리가 됨
- 화면 미확보 목록을 두 갈래로 가름
  · 「입력하면 풀리는 것 — 설계 화면에서 값을 고르면 금액이 섭니다」(`input_missing`)
  · 「우리가 만들어야 하는 것 — 원단위·전개식이 아직 없습니다」
- 한 목록에 섞이면 사용자가 「후보를 고르면 되나」로 잘못 읽음(돌쌓기가 그 자리였음)
- ⚠ 빈 값은 오류가 아니라 **「아직 안 고른 상태」** — 랩탑이 「— 선택 —」 빈 칸으로
  열어 둔 것과 짝임(첫 항목을 슬쩍 고르면 근거 없는 값이 단가로 흘러감)

계약 시험의 측점 까닭 보강 — 「지금은 안 씀 — 구간별 산출근거를 낼 때 쓸 것」

검증: pytest 195 통과, tsc 0건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑이 B06 에서 상세 제원을 받게 하고 `bond` 칸을 더해 준 것을 받음.

- `bond`(메쌓기/찰쌓기) → 품셈 `FP-13-06-01`/`FP-13-06-02` 자동 판정.
  미입력이면 `blocked_kind: input_missing` 과 사람 말 사유로 드러냄 —
  랩탑이 「빈 값을 미확보로 계속 드러내 달라」고 한 그대로. 첫 항목을 슬쩍
  고르면 근거 없는 값이 수량·단가로 흘러감.
- `pending_user` 에서 큰돌쌓기를 뺌 — 칸이 생겨 자동으로 갈림.

전면 기울기 1:0.3 의 근거를 찾아 데이터·주석에 적음. 지어낸 값이 아니라
**교본 7-3 돌흙막이 기준**임 — 「돌 찰쌓기 3.0m 이하 1:0.3 / 돌 메쌓기 2.0m 이하
1:0.3 / 큰돌쌓기 1:0.3 이상(전도 방지)」(지식DB 돌쌓기.md §1).
⚠ 큰돌쌓기는 「1:0.3 **이상**」이라 더 완만하게 잡을 수 있음 — 칸을 만든다면
그 범위를 보여야 한다는 것도 데이터에 적음.

검증 — 전체 642 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실무 내역서는 줄마다 비고에 「단산 46 참조」를 적고 그 산출서를 펴서 검산함(8-13).
STC 실측도 `D` 가 `B`(일위대가)를 참조하는 한 층 위였음(9-3)

- `PriceBook` 의 「제목 + 상세」 한 쌍에 `kind=PRICE_BASIS` 만 얹음 —
  표를 세 벌 만들지 않음. 화면도 일위대가 탭과 **같은 2단 모양**
- 번호는 **코드에 안 박음** — 실무 참조번호는 그 내역서 안의 차례라
  프로젝트마다 다름. 코드는 공종을 가리키고 번호는 조판할 때 매김
- 같은 일위대가가 두 줄에 쓰이면 **산출서는 한 장**, 두 줄이 같은 번호를 가리킴
- 내역 줄 비고에 「단산 N 참조」를 달음
- 지금은 일위대가를 그대로 한 줄로 참조 — 할증·기타 비용이 붙을 자리를 미리 열어 둠
- `GET …/estimation/price-basis/{code}` 로 본표 조회

화면 실측: 내역 줄 「2-2-1 측구터파기 488,926 / 단산 1 참조」,
  산출서 탭에 1장(토사 FP-09-12-01 ㎥ 5,288.6), 눌러 본표·참조 코드 확인

검증: pytest 195 통과, tsc 0건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉔. 확정 7(준비공 3줄)의 마지막 하나가 닫힘.

- 사면길이 유도가 이미 성토 사면을 재고 있어 **성토 조각의 수직 낙차 합**이 곧
  성토고임. `StationSlope.fill_height_m` 으로 실어 사면표까지 옮김.
  ⚠ 좌우가 다르면 **큰 쪽**을 씀 — 「중심점 성토고 5m 이상」 판정은 가장 높은
  쪽이 기준이고 양쪽을 더하면 실제보다 두 배가 됨.
- 수평 규준틀은 **성토고 5m 이상 측점마다 한 개소**(11-3 [주]①).
  ⚠ 비탈규준틀(「10m 이상 20m마다」)과 **기준이 다름** — 이쪽은 지점 조건이라
  간격이 없음. 두 기준을 같은 식으로 쓰면 조용히 틀림.
- 성토고 칸이 아예 없으면 0 으로 때우지 않고 미확보로 둠. 성토고가 다 낮으면
  0 개소가 **값**임 — 「못 셈」과 다름. 셋을 시험으로 갈라 못 박음.

실노선 확인 — 비탈 규준틀 31개소(617.475m ÷ 20 + 1) · 수평 규준틀 39개소.

검증 — 준비공 18건 통과, 전체 647 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
두 창 합의 — 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-07 3자). 품셈 원문이 규격 표기를 한 종류로 안 씀 —
**물결표만 셋**(`∼` U+223C 662회 · `~` U+FF5E 459회 · `~` U+007E 2회),
곱셈표도 둘(`×` 97회 · `x` 4회). 같은 절 안에서도 갈림(13-06-01·02 는 `∼`,
13-06-03 은 `~`). **두 창이 각자 키를 조립하면 글자 하나로 영영 안 맞음.**

- `#55cm이하`·`#직경60㎝이상∼80㎝미만` 같은 키를 **우리가 만들지 않음**.
  `variant_axis`(어느 축) + `variant_value`(저장 원본값 그대로)만 보내고,
  원문을 읽는 쪽이 표기를 흡수함. 「…㎝ 이하」 구간 나누기도 그쪽 몫 —
  그 구간이 품셈 표의 구조이기 때문.
- ⚠ **메/찰은 예외** — 키 표기가 아니라 **공종 자체가 갈리는 의미 판정**이라
  코드가 `FP-13-06-01`/`-02` 로 통째로 달라짐. 그것은 우리 몫으로 유지.
- 계약 시험에 못 박음 — 코드에 `#`·`㎝`·`cm` 가 들어가면 깨짐. 원본값을
  가공해도 깨짐(물결표 종류를 바꾸거나 단위를 붙이면 안 됨).
- `data_masonry` 의 갈래표는 지우지 않고 **참고**로 남김 — 서브 판정과
  어긋나면 그것이 곧 신호.

마스터에 `special_glyphs` 깃발 — 규격 표기에 쓰인 특수문자 종류. 값은 안 고치고
표시만 함. 물결표가 두 종류 섞인 표가 실제로 5개 있는 것을 시험으로 못 박음
(계약 근거가 사라지면 깨짐).

검증 — 전체 653 passed, tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 8-7 「자재대·관급자재대(금액)는 B09」 — B08 자재총괄이 낸 수량·할증에
단가를 붙여 금액을 내는 자리. 수량은 B08 것이 정본이라 다시 세지 않음

- **관급은 총원가 밖 별도 표기**(⑤ 관급자재대와 같은 값), 사급은 도급 재료비
- ⚠ `unknown`(관급·사급 미정)은 **어느 합계에도 안 넣음** — 넣으면 총액이 틀리고
  어느 쪽으로 넣었는지 나중에 못 가림. 지금 실물 4건이 전부 이 상태
- 단가가 없으면 **금액을 안 만들고** 사유를 남김(사급 물가지 미결 No.18)
- 할증률이 없으면 「할증 전 수량」임을 표에 적음 — 여기서 또 곱하지 않음(㉠)
- 관급자재대 합계는 **천원 올림**(단수처리 규칙)
- 화면 탭 신설 — 세 무리를 각각 표로 보이고 합계·사유를 함께 냄

검증: pytest 205 통과(신규 5 — 합계 분리·미정 제외·단가 없음·할증 깃발·천원 올림),
tsc 0건. 화면 확인은 공용 브라우저 세션 만료로 다음 차례에

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉕ 통과(엔진 실행)에서 잡힌 것.

- 준비공 사방공 줄에 개발자 키(`soil_guard`)가 그대로 뜨던 자리 수정.
  레지스트리 이름을 받아 쓰고, 키는 `type_id` 칸으로만 오감.
  문구표에 사방 시설 이름 넷 추가(레지스트리 값 그대로 옮긴 것).
- 좌측 「토사」 비율 칸 제거 — 넣어도 버려지던 죽은 칸.
  토사 물량은 토적표 값이 그대로 서고, 비율은 암 총량을 갈래로 나눌 때만 쓰임.
- 안분 안내 문구를 「암 갈래 입력 합 …」으로 명시.
  칸에 100 을 채운 사용자에게 「입력 합 60 %」로 뜨던 자리.
- 항목 라벨을 「암 갈래 구성비(%) — 암 총량 기준」으로 바꿈.

시험: 655 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 이 변경과 무관).
사방공 이름 시험 2건 추가, 키를 화면 이름으로 못 박던 옛 시험 1건 정정.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인 창이 인계를 실제로 먹여 잡음 — 물구멍·야면석이 `owner_supplied` 인데
「사급 자재 단가 미확보」로 뜨고 있었음. `unknown` 만 가르고 나머지를 한 줄로
떨어뜨린 탓

- 관급 — 「관급 자재 단가 미확보 — 나라장터 목록에 이 품목이 없습니다.
  관급자재대(총원가 밖 별도 표기)로 갑니다」
- 사급 — 종전 문구(물가지 미결 No.18, 6번 슬롯 수동 입력 대기)
- `missing` 에 `supply_type` 을 실어 화면이 갈래로 묶을 수 있게 함
- 갈래마다 **가는 자리도 원천도 다름** — 관급은 총원가 밖·나라장터,
  사급은 도급 재료비·물가지

검증: pytest 206 통과(신규 1)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인 창이 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>
메인 창이 「가드에 짝 시험이 붙어 있나」를 물었고, 세어 보니 둘이 0 이었음
(`tmp/tests` 가 git 밖이라 그쪽에서 확인할 길이 없었음)

- `check_operator_hours_basis` — 8시간 나눗수는 통과, 5.09시간으로 줄이면 걸림
  (나눗수를 줄이는 것이 곧 효율을 사용료에 넣는 것, 품셈 8-1-6)
- `match_packed_rows` — 뭉치지 않은 표는 **가로채지 않고**, 뭉친 표는 읽음
  (그 문이 넓었을 때 자원 축이 304 → 244 줄로 떨어졌음)

검증: pytest 209 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉘ 자기 감사. B09 에 겨눈 네 축을 내 것에 그대로 겨눔.

안 부르던 검사 — 시험에서만 불리고 있던 것들을 실제 경로에 이음
- verify_no_code_on_materials · verify_bill_flags → build_handoff 결과에 실음
- check_against_plan → 운반 표 옆에 haul_check 로 실음 (계획이 있을 때만)
- 바로 위 주석이 「검사는 실제로 부른다」였는데 형제 둘이 놀고 있었음

표토 두께 — 서버·엔진은 받고 있었는데 화면에 넣을 칸이 없었음
- optionalNumberField 신설 (빈 값 = 「안 정함」, 0 과 구별)
- null 을 저장에서 버리던 것 수정 (NULLABLE_SETTING_KEYS) —
  한 번 넣으면 「안 정함」으로 못 되돌리던 자리

짝 시험 — 규칙은 있는데 시험이 없던 둘
- REFERENCE_MARKS (41건을 지웠던 그 규칙): 기준표는 잡고 「단 위」는
  안 잡는 것을 양쪽으로 박음
- attachments_of: 칸이 있을 때만 줄이 서고 부모와 id 가 갈리는 것

시험: 662 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관) · tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인 창이 8장에서 한 것과 같은 모양으로 9장을 정리

- 완료 기록 — 표 다섯이 화면으로 섰음(⑤·③·④·일위대가·자재대).
  자원 축 418줄 · 일위대가 203 · 가드 7 + 열 방향 검사 · 시험 209
- 확정 대기를 **㉮ 지금 답할 수 있는 것 / ㉯ 더 알아봐야 하는 것**으로 가르고
  항목마다 세 칸(지금 답할 수 있나 · 무엇이 채워지면 풀리나 · 어디까지 찾아봤나)
- 「낼 수 있는 것 / 막힌 것」 표 — **막힌 것의 뿌리는 셋뿐**
  (사급 자재 단가 · 밑수 미확보 · 사용자 입력). 셋 다 우리가 만들 수 없는 것
- 데이터 파일 지문표 + 「지문은 마스터 파일 자체의 것이어야 함」 경위
- 「일하는 법」 — 품셈 표 일곱 모양, 「숫자가 늘어난 것은 좋아진 신호가 아님」,
  「크기가 말이 되나」가 네 번 다 잡은 것(셋이 최소값), 「있다와 돈다는 다름」,
  「사고가 난 자리에는 반드시 짝 시험」, 계약은 양쪽에서 마주 걸 것,
  `tmp/tests` 가 git 밖이라 교차검토로 시험 유무를 못 판정하는 한계,
  폴더 튐 네 번과 「쓰는 쪽에 경로 검사」

검증: pytest 209 · tsc 0건 · 700줄 초과 0 · ruff 22파일 정렬됨.
화면 전수는 공용 브라우저 로그아웃 상태라 로그인 뒤로 남김

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉘ 자기 감사 후속. 실무 시트의 「돌쌓기 = 정면적 × 1.04」에서 그 1.04 가
곧 기울기 몫임(1:0.3 → √(1+0.3²) = 1.0440). 시트가 반올림해 적은 것을
별도 계수로 오해해 hypot 위에 또 곱하고 있었음.

- 돌쌓기·큰돌쌓기 모두 기울기 몫을 한 번만 곱함
- 상수는 지우지 않고 `sheet_check_factor_at_0_3` 으로 성격을 바꿈 —
  1:0.3 에서 시트값과 맞는지 대조하는 검산 참고값
- 하드코딩 금지 이유를 주석에 남김: 큰돌쌓기는 「1:0.3 이상」이라
  기울기가 바뀌면 1.04 는 틀린 값이 되지만 hypot 은 따라감

값 변화 (실노선):
  고임돌 -3.85 % · 야면석 -3.85 % · 물구멍 -3.85 %
  막자갈 +3.20 % (입적에서 빼는 몫이 줄어 늘어남 — 식대로임)

시험
- 옛 시험이 덧곱을 계약으로 못 박고 있어 정정
- 거울 시험 추가: 기울기 0.3·0.5·1.0 에서 정면적 × hypot 과 일치
- 시트 대조 추가: 정면적 18.87 → 돌쌓기 19.62, 오차 0.5 % 안
- NULLABLE_SETTING_KEYS 계약 시험 추가 (홑 숫자 칸만 좁게 봄)

곁들여 타설 방식 안내 한 줄 — 고른 값이 아직 금액에 안 닿는다는 사실을
화면에 적음. 인계에 타설 공종 줄을 세울지는 이중계상 확인 뒤 결정.

시험: 666 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관) · tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⑤ 구간 표기 37줄을 살피다 둘이 나옴

- 그 줄들은 **살릴 값이 아니었음** — 품셈이 실어 둔 **단가산출서 예시(빈 서식)**
  안의 셀이었음(「ha당 참나무시들음병방제 단가산출서(예시)」).
  읽으려 들면 구간 라벨(「12~14㎝」)과 항목명이 자원 이름으로 오해됨
  ⇒ 머리글에 「단가산출서」·「예시」가 있으면 **표째 건너뜀**.
  못 맞춤 882 → 497, 성분 빠짐 84 → 78. 자원 축·일위대가·분포는 그대로
  (값이 없던 표라 당연함)
- ⚠ **진짜 결함** — `RANGE_DASHES` 를 정규식 문자클래스에 그대로 넣어
  `~-–` 이 **범위 연산자**로 읽히고 있었음. 「0.7㎥」·「15톤」까지 구간으로 잡힐
  자리였음. `re.escape` 한 `RANGE_DASH_CLASS` 를 두고 세 파일이 그것을 씀
  (「한 곳으로 모으라」는 지적이 없었으면 못 봤을 자리)
- 구간 셀에 **단위 꼬리**(「51~100m」)를 허용하되 **수~수+단위 전체가 맞을 때만** —
  단위가 붙었다고 다 구간은 아님(「굴착기 0.7㎥」는 규격)

계획서 — 석재 할증률 물음을 「몇 %인가」가 아니라
「붙일까 말까, 붙인다면 근거를 어디서」로 고침(메인 지적)

검증: pytest 211 통과(신규 2 — 예시 서식 건너뜀 + 정상 표는 안 걸림)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉙ B09 2차 교차검토와 함께 나온 것.

콘크리트 타설 — placing_code() 가 시험에서만 불리던 자리를 실제로 이음
- build_handoff 가 구조물 종류별로 콘크리트 체적을 모아 타설 공종 줄을 냄
- 겹치지 않는 것을 확인함: 품셈 12-1-1 표가 직종·품만 주고 재료를 안 줌
  (서브 일위대가 B-FP-12-01-01#철근구조물 = 재료 0원 · 노무 65,826.48원)
  품은 이 줄, 재료는 자재 쪽으로 갈려 있음
- ⚠ 채움콘크리트는 뺌 — 돌쌓기 뒤채움이라 그 공종 품에 이미 들어 있을 수 있음
  (13-6 [주]① 이 큰돌쌓기는 품에 포함이라 못 박음, 13-4 는 확인 전)
- 방식을 안 정했으면 기본값으로 서되 placing_notes 로 알림
- 화면 문구를 「아직 반영 안 됨」에서 「방식에 따라 단가가 달라짐」으로 바꿈

빈 단가산출서 서식 — 품셈이 실어 둔 채워 넣으라고 둔 양식 8건
- 머리글 「단가산출서」가 정본 표지, 머리 두 줄 모양은 보조
- 값이 아예 없는 표라 공종으로 세우면 「값이 있는데 안 서는 자리」로 오해됨
- 실측: 견적 쪽 못 맞춘 자원 882 → 497, 밑수 미확보 160 → 137
- 자원 줄 418 · 단가 제목 330 은 그대로 — 정상 값은 안 지워짐

시험
- 서식 규칙 짝 시험 넷 (정상 표를 지우지 않는 것 · 다시 만든 마스터 대조 포함)
- 타설 줄 시험 넷 (방식 셋이 갈리는 것 · 콘크리트가 없으면 줄도 없는 것)
- 옛 시험 하나 정정 — 구조물 한 줄 규칙에 타설 줄이 걸리던 것

시험: 674 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관) · tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 전수(다섯 탭)에서 드러난 것

- 자재가 아예 없는 프로젝트에서 **빈 표 셋이 「(0) — 0」 으로 늘어서** 있었음.
  「이 프로젝트에는 자재 줄이 없습니다」 한 줄로 바꿈
- 계획서 「검증 함정 모음」에 셋 적음
  · 세션은 DB 라 재시작으로 안 지워지되 **튕기면 브라우저 쿠키를 의심할 것**
  · 화면이 막혀도 **엔진은 파이썬에서 직접 부를 수 있음** — 단
    `await init_db_pool()` 을 먼저 부를 것(안 부르면 **빈 응답이 「자료 없음」으로
    잘못 읽힘**), 한 이벤트 루프 안에서 끝낼 것
  · 되받기 전후로 **인계 응답을 파일로 떠 둘 것** — 「합계가 221원 줄었다」를
    짚으려면 어느 줄이 얼마나 바뀌었는지 대조할 자료가 있어야 함

화면 전수 결과 (프로젝트 b269ea34, 포트 5174)
  ⑤ 원가계산서 26줄 · [재계산] 동작
  ④ 예산내역서 16줄 · 금액줄 1 (측구터파기 92.45 × 5,288.6 = 488,926)
     비고에 「단산 1 참조」 · 안내 5 · 미확보 16 (두 갈래로 갈려 뜸)
  일위대가 203줄 · 안내 3
  ③ 단가산출서 1장 · 본표와 참조 코드
  자재대 — 이 프로젝트는 자재 0건이라 한 줄 안내(다른 프로젝트에선 미정 4건 확인)
  ⚠ 바꾼 화면 상태는 원래 탭으로 되돌려 놓음

검증: pytest 211 통과, tsc 0건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉕-1 실사용자 화면 통과(로그인 뒤). 엔진 실행으로는 안 보이던 것들.

- 토량환산계수 세 줄이 서버 키로 뜨고 있었음 (soil · ripping_rock ·
  blasting_rock) → 토사 · 리핑암 · 발파암. 준비공의 soil_guard 와 같은 병.
  모르는 키는 지어내지 않고 그대로 보임.
- 타설 방식 안내가 겹쳐 경고를 밀어내고 있었음. 기본값일 때는 「기본값으로
  계산 중」 경고가 더 많은 것을 말하므로 내 줄을 안 실음. 문구도 줄임.
  실측: 줄이기 전에는 참고 단가·⚠ 두 줄이 패널 밖으로 잘려 안 보였음.

화면 확인(스크린샷·DOM): 탭 6장 다 서고 표가 따라옴. 표토 두께 칸은
입력 가능(회색은 「안 정함」 placeholder 색).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 계약 시험이 **제 일을 했음** — 「인계가 보내는데 안 읽는 칸: spec_class,
  spec_class_basis」로 깨짐. 둘 다 읽고, 갈래 판정 근거(`spec_class_basis`)는
  **B08 문구 그대로** 줄 비고에 이음
- 예시 서식 거르기를 뺌 — B08 이 **마스터 원천에서** 거름(8건).
  두 곳에서 같은 것을 거르면 나중에 한쪽만 고쳐짐
- 짝 시험은 남기되 모양을 바꿈 — 인공 표 대신 **실물 마스터에서 그 8공종이
  자원으로 서지 않는지**. 원천이 바뀌면 이 시험이 알려 줌

검증: pytest 211 통과. 못 맞춘 자원 497(원천 필터 뒤 값과 일치)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 화면 전수 표 다섯 탭 결과와 「화면에서만 잡힌 것」(자재 0건인데 빈 표 셋)
- 공용 브라우저 로그인 절차 — 사용자가 유지하는 자격 파일 + 페이지 오리진에서
  로그인 요청, 확인은 세션 200. ⚠ 파일이 내 폴더에 없으면 **그 자리에서 읽어 쓰고
  복사·기록하지 말 것**(자격을 옮기면 지우는 사람도 늘어남)
- 「튕기면 서버가 아니라 브라우저 쿠키를 의심할 것」

마감 상태: 표 다섯 화면으로 섬 · 가드 7 + 열 방향 검사 · pytest 211 ·
tsc 0건 · 700줄 초과 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인 창 지적(「안내를 더하는 것이 곧 다른 안내를 묻는 것」)을 내 화면에도 대어 봄

- 잘리는 줄은 없었음(본문 높이 = 스크롤 높이, 6줄 다 보임)
- 다만 **같은 수가 두 번** 떴음 — 「금액을 못 세운 줄 (16)」 뒤에 갈래별 머리글이
  또 붙어 「… (16)」이 이어짐. 머리글을 **한 번만** 달게 함 (6줄 → 5줄)
- 갈래가 하나뿐일 때만 「금액을 못 세운 줄」을 앞에 붙여 뜻이 온전하게 함
- 문구도 줄임 — 「0 으로 채우지 않고 그대로 보입니다」 → 「0 으로 안 채웁니다」 등

실측(5174): 안내 5줄, 잘림 없음. 바꾼 화면 상태는 원래 탭으로 되돌림

검증: pytest 211 통과, tsc 0건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
㉕ 타설 줄 실증 중에 드러남. 관측 원단위가 「개소당」인 종류(집수정 셋)를
인계 줄이 늘 「m · 연장」으로 내보내고 있었음.

- 연장 2m 짜리 집수정이 「2.000 m」로 나가 값이 두 배로 실림
- 성분은 개소 기준으로 맞게 서는데 줄의 축만 어긋나 아무 시험도 안 잡았음
- billing_of() 로 관측표가 정한 단위·개수를 꺼내 전개 결과에 실음
- 인계 줄이 그 단위를 따름. 비어 있으면 종전대로 「m · 연장」

시험 셋 — 개소로 서는 것 · 연장이 길어도 한 개소 · ⚠ 정상 「m」 줄은
그대로일 것(좁게 고치는 짝 시험).

곁들여 타설 줄 실증: 옹벽 H=2.0(20m) + 집수정 Ø800 으로 돌리면
FP-12-01-01#철근구조물 32.840㎥ 가 인계에 섬(옹벽 27+3 · 집수정 2.84).

시험: 677 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
대기 중 둘 처리

- `tmp/snapshot_b09.py before|after|diff` — 인계 응답과 **코드 시각**을 함께 뜸.
  `/api/health` 의 `code_mtime`·`stale` 을 같이 적어, 값이 움직였을 때
  「자료가 바뀐 것」과 「코드 버전이 바뀐 것」을 가름
  (성토 −16.81 % 가 그 자리였고 **절반이 코드 버전**이었음, 장부 규칙 7·8)
  ⚠ diff 는 **어느 줄이 얼마나** 바뀌었는지로 냄 — 합계 한 줄로 말하지 않음
- 9-7 에 「값이 채워진 첫 인계에서 볼 것」 여섯을 표로 적어 둠 —
  암 갈래별 단가 · 타설 줄(65,826.4원/㎥) · 반영률 곱한 수량 · 공급 구분 ·
  돌 규격/쌓기 방식 · 개소 구조물 단위(메인 `de31cd9c`)

내 검증 프로젝트는 `2f940d8a` (배정). 첫 스냅숏 떠 둠 — 공종 10 · 자재 0

검증: pytest 211 통과. 서버 `stale` 이던 것 재시작해 코드 시각 맞춤

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
조율 창 제어 종료에 따른 마무리

- 9-7 에 「여기서 멈춤」 — B09 완료 상태(표 다섯·화면 전수·가드 8·시험 211·
  tsc 0·700줄 0)와 **이어받을 사람이 볼 미처리 둘**
  · 값이 채워진 첫 인계 받기(볼 것 여섯은 바로 아래 표)
  · 타설 줄이 실린 자료로 65,826.4원/㎥ 이 금액에 걸리는지 확인
- 확정 답이 오면 손댈 자리 셋을 짚어 둠 — 제잡비 밑수 · 수량 자릿수 · 석재 할증
- `OWNERS.md` desktop-sub 줄을 「대기」로

브라우저 화면은 원래 탭(공사원가계산서)으로 되돌려 놓음.
워킹트리 깨끗 · 폴더 `D:\aislo-wt\sub` 확인

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
조율 창 제어 종료에 따라 자기 줄만 갱신. 담당 폴더·브랜치·포트는 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
공용 파일 두 걸음 규칙 — 이 커밋은 신규 파일뿐이고 main.py 등록은 다음 커밋.
먼저 push 해야 다른 창이 등록 줄만 받고 파일이 없어 죽는 일이 없음.

까닭 — 단계마다 [확정]을 해야 다음 페이지가 열려서, 상세 설계를 확정하기
전에는 B08·B09 를 볼 수 없음. 오늘 화면 검증이 그 자리에서 두 번 막혔음.

⚠ 계산을 대신 돌리지 않음 — 잠금만 품
- 바꾸는 것은 project_workflow_stages.state 한 칸뿐
- 확정은 전 측점을 다시 계산해 정본에 쓰는 것이라, 흉내 내면
  「확정 안 했는데 확정된 값」이 생겨 막힌 것보다 나쁨
- 값이 없으면 B08 이 「미확보」로 뜨는 것이 정상

⚠ 문은 서버가 정본 — ENVIRONMENT 가 개발이 아니면 세 입구 모두 403
  (화면에서 단추를 숨겨도 API 가 열려 있으면 소용없음)

되돌리기 — 푼 단계의 이전 상태를 message 에 DEV_UNLOCK:<옛상태> 로 적어 두고
DELETE 가 그대로 복원. 그 표시가 없는 단계(진짜 확정)는 안 건드림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
앞 커밋 618b6cf4 의 신규 파일을 등록하고 화면 단추를 붙임.
두 걸음 규칙대로 파일이 먼저 push 된 뒤 등록 줄이 감.

문은 앞뒤 둘
- 서버(정본): ENVIRONMENT 가 개발이 아니면 세 입구 모두 403.
  라우터는 다른 것과 같은 보호(로그인·회사·프로젝트 접근)를 받고
  그 위에 환경을 한 번 더 봄
- 화면(보조): import.meta.env.DEV 일 때만 단추가 그려짐

눌렀을 때 바뀌는 것 — project_workflow_stages.state 한 칸뿐.
계산은 안 돌고 정본 값도 안 만듦. 실측(b269ea34):
  우회 전 [] → 우회 [3 STALE · 4 NOT_STARTED · 5 NOT_STARTED] → 되돌림 → []
  이미 COMPLETE 인 0·1·2 는 안 건드림 (진짜 확정은 보존)

되돌리기 — 푼 단계의 옛 상태를 message 에 DEV_UNLOCK:<옛상태> 로 적어 두고
[원래대로 되돌리기]가 그대로 복원. 그 표시가 없으면 진짜 확정이라 안 만짐.

드러남 — 우회 중이면 좌측에 「지금 확정을 건너뛴 상태입니다 — 값이 비어
보이는 것은 정상입니다. 건너뛴 단계 (3, 4, 5)」가 뜸.

⚠ 화면에서 잡은 것 — 단추를 패널 아래에 두니 overflow:hidden 에 잘려
  화면 밖(y=772, 패널 740)이라 눌리지 않았음. 맨 위로 옮김(상태 경고이기도 함).

시험: 677 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관) · tsc 오류 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
보조 창 요청에서 출발했는데, 보다 보니 표가 통째로 안 가고 있었음.
표토제거(값 있음·FP-09-15)·규준틀(개소·FP-11-02)이 화면에는 서는데
인계에는 없었음.

⚠ 줄을 빼면 「빠졌다는 사실조차 안 보임」 — 받는 쪽에서 「내역서에 원래
없는 것」과 「우리가 아직 못 내는 것」이 구별되지 않음.

- 값이 서는 줄 → in_bill: True, 공종코드와 수량 그대로
- 못 내는 줄 → in_bill: False + blocked_kind + blocked_reason
  (금액은 안 붙되 「무엇이 채워지면 풀리는지」가 함께 감)
- ⚠ 「다른 표에서 이미 섬」(벌목)은 blocked_kind: None — 막힌 것이 아니라
  여기서 세면 안 되는 줄임. 막힘으로 보내면 「만들어야 할 것」으로 오해됨
- origin: "preparation" 로 갈래를 나눔

시험 넷 — 값 서는 줄 · 못 내는 줄의 사유 · 이중계상 방지 줄은 막힘 아님 ·
⚠ 표를 안 주면 빈 줄을 지어내지 않을 것(좁게 고치는 짝 시험).

시험: 681 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
8-29 ㉮7(자재 원단위의 밑수 — 비탈면적인가 정면적인가)이 계획서에만
있고 화면에는 안 보였음. pending_choices 에 넣으니 구조물 원단위 탭에
바로 뜸 — 「무엇을 정해야 하나」와 「정하면 얼마나 달라지나(−4.4 %)」를 함께.

곁들여 확인 — 그 탭에 미확정 넷이 다 뜸:
  자재 원단위 밑수 · 흡출방지재·차수시트 · 목재틀흙막이 원단위 ·
  내역서 수량 표시 자릿수
계획서 8-25 가 뒤 둘을 「화면 」로 적어 두었는데 실제로는 보임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 이 준비공 여섯 줄을 인계에 실으면서(`93546b85`) 세 갈래가 섞여 옴

- ⚠ `blocked_kind` 가 **없는데 `in_bill=false`** 면 **막힌 줄이 아님** —
  「다른 표에서 이미 섬」(벌목·지장목제거)·「이 노선엔 없음」(사방 시설).
  그것을 「우리가 만들어야 하는 것」에 얹으면 사용자가 세우려 들고
  **그것이 곧 이중계상**(㉠~㉦ 규칙에 걸림)
- 화면 목록을 **셋으로** 가름 — 입력하면 풀리는 것(2) · 우리가 만들 것(10) ·
  **여기서 세지 않는 줄(2)**
- 검산 줄 비고에 B08 사유 문구를 그대로 실음
- 짝 시험 — 같은 `in_bill=false` 라도 사유가 다르면 갈래가 달라야 함

실측(5174, 2f940d8a): 세 무리가 각각 뜨고 검산줄 5개가 수량만 보임

검증: pytest 212 통과(신규 1), tsc 0건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B09 제보. 규준틀 둘(FP-11-02·FP-11-03)이 in_bill=true 로 서는데
「밑수 미확보」라 금액이 안 붙고 있었음. 개소 수는 이미 닫혔는데
그 표의 밑수 자체가 비어 있던 것.

「원문에 있었음」 아홉 번째 — 이번엔 표 **아래** [주] 였음
  [주]③ 「목재의 손율은 **1개소 사용당** 50%로 한다」
  뜻으로도 개소가 맞음 — [주]② 가 「본 품은 …한 비탈규준틀의 제작·도색·
  가설·철거를 포함한 것」이라 규준틀 하나를 말하고, [주]① 이 「20m마다 설치」

⚠ 아주 좁게 잡음 — 「N개소 **사용** 당」 표기는 품셈 전문에 딱 두 곳뿐이고
  둘 다 규준틀임. 「개소당 평균면적」 같은 흔한 말은 「사용」이 없어 안 걸림
  (넓히면 조림 2장이 통째로 걸림 — 실측 19건).
  다음 표(|)나 다음 절(###)을 만나면 멈춤 — 남의 [주] 를 물어 오면 조용히 틀림.

효과: 밑수 확보 183 → 185, 미확보 137 → 135.

시험 넷 — 규준틀에서 읽는 것 · 흔한 말에 안 걸리는 것 · 다음 절로 안 넘어가는 것 ·
다시 만든 마스터에 실제로 실렸는지 정본 대조.

시험: 685 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인이 원문 **표 아래 [주]③**(「목재의 손율은 1개소 사용당 50 %」)에서 밑수를
찾아 `FP-11-02`·`FP-11-03` 을 「1 개소」로 채움(`fc867d32`)

- 자원 축 다시 냄. 지문이 `3752af1e…` 로 따라 바뀜(낡음 감지 장치 동작)
- 기준 미상 68 → 66
- **비탈 규준틀 68,512.2원/개소 · 수평 규준틀 90,997.7원/개소** 로 섬
- 내역서(2f940d8a) 합계 **11,494 → 946,067원** — 규준틀 7개소·5개소가 실제로 실림
  · 3-1 비탈 규준틀 7 × 68,512.2 = 479,585
  · 3-2 수평 규준틀 5 × 90,997.7 = 454,988

⚠ 원문이 **표 위 본문이 아니라 표 아래 [주]** 에 있던 첫 사례 —
앞서 여덟 번은 다 표 위였음. 다음에 밑수를 찾을 땐 양쪽을 볼 것

검증: pytest 212 통과. 스냅숏 전후 대조로 준비공 6줄 신규 확인

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B09 가 「철근이 겹치나」를 물어 확인하다 드러남. 철근은 안 겹치는데
타설이 겹쳤음.

철근 — 안 겹침 (확인)
  자재로 가는 것은 재료(이형철근 D13·D16 kg)
  묶음 조각 FP-12-03 은 품 — 일위대가 실측 재료 0원 · 노무만
  ⇒ 품은 공종 줄, 재료는 자재 쪽. 타설(12-1-1)과 같은 구조

타설 — 겹쳤음 (고침)
  work_item_mapping 의 옹벽 composite 에 FP-12-01-01 조각이 이미 있는데
  _placing_rows 가 그 구조물의 콘크리트를 또 셌음
  ⇒ 묶음으로 서는 구조물은 건너뜀. 그 콘크리트는 묶음 조각이 셈
  ⚠ 묶음이 아직 미확보라 값이 안 걸렸을 뿐, 서는 날 두 번이 됨

시험 둘 — 묶음 구조물은 타설 줄 없음 · ⚠ 묶음 없는 종류는 그대로 섬
(좁게 고치는 짝. 묶음 하나 때문에 정상 줄까지 지우면 더 나쁨)
기존 타설 시험 셋은 표본을 옹벽 → 집수정으로 바꿈(옹벽이 이제 묶음이라).

시험: 685 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 창 보고(2026-09-08): 관 11개가 `pipe_points.json` 에 있고 품셈 공종도 있는데 **연장(m)이
없어** 배수관 물량이 막혀 있었음. 관 길이는 횡단 기하가 **m 단위 올림까지** 끝낸 값
(`CulvertLayout.pipe.lengthM`)인데 **정본(`design`)에 안 실렸음**.

**옮기거나 새로 짜지 않았음** — 그 계산은 **이미 서버가 Node 로 그대로 실행**하고 있었음
(`B06_Section_Server_Calc_Node` ← `Server_Calc_Prebuild.recompute_server_side`, [저장]·[확정]).
구조물 폐회로 면적이 실리는 **그 다리에 값 한 줄만** 더 실었음 — 계산을 두 벌로 짜지 않음
(CLAUDE.md 5장). B08 창이 낸 갈래 둘(서버로 이관 / 저장 때 남기기)은 둘 다 불필요했음.

- `STRUCTURE_AREA_KEYS` → **`STRUCTURE_ROW_KEYS`** 로 이름을 고치고 `pipe_length_m` 추가.
  이름이 「면적」이라 길이를 담으면 거짓말이 됨.
- **면적을 못 내는 측점에서도 길이는 냄** — 설계선이 모자라 폐회로가 안 닫히는 자리에도
  관은 서 있고 수량은 그 길이가 필요함(`return pipeRow`).
- ⚠ **서버에 화이트리스트가 하나 더 있었음** — `_AREA_KEYS`(「Node 가 다른 키를 내도 안 흘림」).
  거기 안 넣으면 Node 가 값을 내도 **조용히 버려짐**. 넣고, **두 목록을 대조하는 시험**을 둠.
- 키 이름은 `pipe_length_m` 으로 **B08 창과 미리 못 박음** — 오늘 `back_len_cm` 이 엔진에서
  `stone_back_length_cm` 로 읽혀 저장값이 영영 안 닿던 사고가 있었음.

⚠ 값이 정본에 실리려면 그 프로젝트에서 **[저장] 한 번**이 필요하고, **번들 재빌드**
(`npm run build:server-calc`)도 필요함 — 번들은 git 밖이라 창마다 각자 돌려야 함.

시험 6건 — 패치로 받는지 · 음수 거부 · 면적과 **같은 목록**으로 실리는지 · 면적 실패 시에도
길이는 나오는지 · 이름을 두 번 적지 않는지 · **서버 화이트리스트와 TS 목록이 짝인지**.
전체 507 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인이 옹벽 묶음에 타설 조각이 이미 있는데 `_placing_rows` 가 그 콘크리트를
또 세던 것을 고침(`19d4009e`). 받아서 실물로 확인

- 인계에 **타설 줄이 없어짐** — 그 콘크리트는 묶음 조각이 셈
- 내역서 합계 3,136,861 → **2,149,464원** (메인 예고 약 2,149,464 와 일치).
  **결함이 아니라 겹친 것을 뺀 것**
- ⚠ 묶음이 미확보라 값이 안 걸렸을 뿐, **묶음이 서는 날 두 번이 됐을 자리**였음

철근 「철근공·보통인부가 두 번 들어 있다」는 메인 관찰 — **정상임을 검산**
- 품셈 12-3 표가 `구조별 | 가공 | 조립 | 계` 이고 진짜 자원 머리는 둘째 줄.
  가공·조립 두 몫을 각각 세는 것이 맞음
- 검산: 철근공 1.24 + 1.84 = **3.08** = 품셈 「계」 열 · 보통인부 0.45 + 0.75 =
  **1.20** = 「계」 열. **「계」 열은 안 더함**(더하면 두 배)

검증: pytest 212 통과. 스냅숏 전후 대조

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B09 가 「옹벽 묶음이 기초잡석 물량 없음으로 막혔다」고 알려 와 원문을 전수로
확인했음. 우리 표가 빠뜨린 것이 아니라 원문에 없었음.

울진 라이브러리 §7 「반중력식옹벽 H=2.0」 원문은
  콘크리트 1.35㎥(기초 0.75+벽체 0.60) + 버림 0.15㎥ · 유로폼 3.20㎡ ·
  기초 거푸집 0.6㎡ · 물빼기 파이프 Ø50 0.32m · 철근 D13 13.45㎏ + D16 30.42㎏
이 전부이고 기초잡석·터파기·되메우기·잔토가 다 없음.

기초잡석이 있는 시트는 §1 관보호공 날개벽뿐(T=0.2 · Ø800 A-TYPE 1.15㎥/개소).
다른 구조물 값을 옮겨 쓰지 않음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 창이 측점 design 에 pipe_length_m 을 넣어 줘서 마지막 조각이 채워짐.
B08 은 잇기만 하고 길이를 짓지 않음.

값이 어디서 오나
  관 자체(있나·어디·관경·관종) → pipe_points.json (레지스트리 managed_by)
  관 연장(m)                  → 측점 design.pipe_length_m
                                (B06 이 서버 Node 로 m 단위 올림까지 끝낸 값)
  관종 → 공종코드              → work_item_mapping 의 pipe.kind_codes
     파형강관 FP-12-11-03 · 흄관 FP-12-11-02 · VR관 FP-12-11-01

⚠ facility 가 pipe 인 점만 배관 — pipe_points.json 은 계곡 통과 시설 전부의
  정본이라 BOX암거·물넘이·세월교가 같은 파일에 있음. 관경 유무로 가르면
  관경 미지정 관을 놓침. 실측: 5601e828 11점 중 관 9 · 세월교 2

⚠ 관종 기본값(파형강관)은 2026-08-17 사용자 확정값이라 근거가 있으나
  조용히 쓰지 않고 「기본값으로 섰습니다」를 알림에 실음

⚠ 안 붙인 것 둘 — 터파기·되메우기(관 부설과 각각 오면 같은 굴착을 두 번 셈,
  B09 ㉡ 가드 자리) · 유출입부 기슭막이(관 옵션이 정본이고 구조물에서 빠졌음)

연장이 없는 관은 0 으로 때우지 않고 blocked_reason 과 함께 감
「횡단설계에서 [저장]을 한 번 누르면 그 측점의 관 길이가 남고 값이 섭니다」

시험 10건 — 세월교 걸러짐 · 관경 없어도 관임 · 연장 없으면 안 섬 ·
관종 셋이 갈림 · 기본값을 알림 · 모르는 관종은 못 고름 ·
⚠ 좁게: 옆 측점 길이를 물어 오지 않음 · 실제 자료 정본 대조

시험: 697 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`pipe_length_m` 을 넣고 실화면 [저장]으로 확인하다 드러남 — **관 9개인데 값이 10곳**에 실렸음.
까닭은 `attach_culvert_sets` 가 세트를 **폭의 절반까지 옆 측점에도** 붙이기 때문임(3D·카드가
이어 그리려고). 그 자리에 길이를 실으면 수량이 **같은 관을 두 번** 셈.

- 스펙에 **놓인 누가거리(`chainage_m`)** 를 함께 얹음 — 파이썬 `attach_culvert_sets` ·
  TS `attachCulvertSets` **둘 다**(한쪽만 얹으면 세트 거울 시험이 깨짐. 실제로 깨져서 알았음).
- 길이는 그 값과 측점이 같을 때만 실음.
- 옛 값 정리 — 이미 실려 있던 이웃 측점 4곳(260.0·800.0·900.0·980.0)에서 지웠음.
  **파생값이라 병합만으로는 안 지워짐**(merge 는 키를 얹기만 함).

⚠ **따로 드러난 것 — 관 3개(439.55·620.43·720.37)는 측점 행 자체가 없음.** 그 관들은 횡단
설계도 수량도 통째로 빠져 있음. 별건으로 조사할 것(계획서에 적음).

실측 결과 — 관 길이가 실린 측점 **6곳**(85.05→10.0 · 258.12→11.0 · 534.49→9.0 · 804.30→9.0 ·
901.24→10.0 · 984.18→10.0m). 나머지 셋이 위 별건임.

시험 7건(소유 측점 판정 한 건 추가) · 전체 507 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 [저장] 뒤 실측하니 관 9개 중 6개 값이 서고(59.0m) 3개가 막힘.
그 셋에 「[저장]을 한 번 누르면 섭니다」가 떴는데 눌러도 안 풀리는 자리였음
— cross_sections 에 그 관 자리 측점이 아예 없음(관은 놓였는데 횡단이 안 만들어짐).

- 측점 목록을 함께 받아 「횡단이 있는데 길이만 없음」과
  「관 자리에 횡단이 없음」을 갈라 말함
- ⚠ 관 자리 판정을 아주 좁게(0.05m) — 실측에서 관 439.55 근처에 측점 440.0 만
  있었고, 길이 찾기와 같은 0.5m 로 보면 「횡단이 있다」로 읽혀 거짓 안내가 떴음.
  길이는 B06 이 관이 놓인 측점에만 실으므로 뜻이 다름

실측(5601e828): 값 6줄 59.0m · 막힘 3줄이 정확히 그 셋
  85.05→10.0 · 258.12→11.0 · 534.49→9.0 · 804.30→9.0 · 901.24→10.0 · 984.18→10.0

⚠ npm run build:server-calc 돌려 새 번들로 바꿨음 — 옛 번들은 이웃 측점에도
길이를 실어 같은 관을 두 번 셀 수 있었음(랩탑이 고쳐 push 한 건).

시험 4건 추가(가른 두 문구 · 목록 없으면 종전대로 · ⚠ 옆 측점은 「있음」이 아님).
시험: 701 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑이 「연장은 나오는데 그 뒤가 안 봤다」고 해서 세 걸음을 한 번에 봤음.
끊긴 자리가 둘이었음.

① 매핑에 B군이 하나도 없었음 — 연장 40.0m 은 인계까지 오는데
   공종코드가 비어 있었음. 품셈에 있는 셋을 이었음
     산마루측구 FP-12-09-02 · 소단측구 FP-12-09-03 · 맹암거 FP-12-10
     셋 다 밑수 1 m — 구조물 연장이 그대로 수량
   도수로·절토사면 배수로는 품셈에 그 공종이 없어 pending_user 로 남김
   (마스터 전수: 「수로」로 찾아도 나오는 것은 위 셋뿐)

② ⚠ 「전개식이 없다」로 단정해 B09 가 금액을 안 붙이고 있었음
   B군은 연장이 곧 수량이라 원단위 전개가 필요 없는데,
   blocked_of 가 「성분이 없으면 formula_missing」으로 봤음
   ⇒ 공종코드가 붙었고 수량이 있으면 막힌 것이 아님

실측(맹암거 40m): 0원 → 1,019,685원. 산마루·소단측구는 B09 일위대가 대기.

⚠ 그 김에 확인된 것 — verify_bill_flags 가 「코드 없이 내역에 서는 줄」을
제대로 잡고 있었음(도수로·절토사면 배수로 둘).

시험 셋 — 연장으로 서는 공종은 안 막힘 · ⚠ 코드 없으면 여전히 막힘 ·
⚠ 연장 0 이면 코드가 있어도 막힘 (둘 다 0원 줄을 막는 짝).
시험: 704 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 제안(두 창 합의). common_util_structure_lengths 가 이미 규칙 셋을 갖고
있는데 B08 이 structures.json 을 직접 읽어 세면 그것을 두 벌로 짜게 됨.

그 함수가 갖고 있는 것
  ① 겹친 구간 합치기 (같은 시설을 겹쳐 놓으면 단순 합은 두 번 셈)
  ② 측구 제외 (design_owner — 횡단이 이미 ditch_area_m2 로 셈)
  ③ 관 소관 제외 (managed_by)

⚠ B군만 그 함수로 감 — C군(돌쌓기·옹벽)은 그대로 구조물별 줄
  그 함수는 종류별로 뭉쳐 내는데, C군은 측점·규격이 줄마다 다르고 자재가
  줄마다 나옴. 실무 내역도 B군은 「산마루측구 40m」 한 줄, C군은 구조물별 줄

실측: 겹친 산마루측구 둘(80~120 · 100~140) → 80m 이 아니라 60m
      비고 「입력 구간 합 80m 에서 겹친 20m 를 뺀 값」

⚠ 만들다 낸 것 하나 — 겹침 설명을 blocked_reason 에 넣었더니 B09 가
「막힌 줄」로 읽어 금액을 안 붙였음. 비고(spec_class_basis)로 옮김.
막힌 사유는 진짜 막힐 때만(공종 못 이음 · 연장 0).

시험 다섯 — 종류별 한 줄 · 겹침이 합쳐짐 · ⚠ 겹침 설명은 막힘이 아님 ·
⚠ 안 겹치면 원합을 안 실음(반영률로 오해됨) · 공종 못 이으면 사유와 함께 막힘

시험: 709 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 창 요청(2026-09-08) — 연장(m)만 내면 산출근거에 **「어디부터 어디까지」**를 못 적음.
실무 내역은 「산마루측구 40m」 한 줄이라 없어도 서지만, 있으면 검산이 쉬워짐.

`_merge` 가 길이 대신 **합친 구간 목록**을 돌려주게 하고, 행에 `spans`
(`[{start_m, end_m}, …]`)를 실음. **길이는 그 목록의 합**이라 둘이 갈릴 수 없음.

⚠ 겹침은 **합쳐서** 냄 — 데스크탑 실측: 산마루측구 둘(80~120 · 100~140)이 **60.0m**
로 합쳐져 내역서에 감(단순 합 80.0m). 구조물별로 셌으면 **20m 를 더 셀** 자리였음.
그 규칙이 이 함수 한 벌에만 있어야 하는 까닭이기도 함(측구 제외·관 소관 제외도 같음).

시험 5건 — 안 겹치면 그대로 · 겹치면 합침(그 실측 그대로) · 맞닿은 두 구간은 하나 ·
품은 구간은 사라짐 · **행의 길이가 구간 합과 같은지**. 전체 513 passed · 17 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑이 spans 를 넣어 줘서 B군 산출근거가 채워짐.
겹침을 지운 뒤의 구간이라 그 합이 곧 length_m 임.

- station_from/to 에 처음 시작·끝 끝을 싣고
- 비고에 구간을 전부 적음 「구간 10~20m · 50~60m · 90~100m」
  ⚠ 사이가 빈 것을 숨기지 않음 — 처음과 끝만 보면 10~100 을 통으로 오해함
- 겹친 경우는 그 설명이 뒤에 붙음
  「구간 80~140m · 입력 구간 합 80m 에서 겹친 20m 를 뺀 값」

⚠ 측점 표기(NO.4+0.0)는 만들지 않음 — 측점 간격을 아는 화면 몫이고,
  두 벌로 짜면 간격이 바뀔 때 한쪽만 고쳐짐

시험 넷 — 구간이 비고에 적히고 측점이 실림 · 여럿이면 처음·끝을 싣고 전부는 비고에 ·
⚠ 구간 합이 수량과 같음(갈리면 어딘가 틀림) · ⚠ spans 가 없어도 줄은 섬(옛 자료)

시험: 713 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
메인 창이 물음 — 종단배수 셋이 같은 모양(밑수 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>
「미판정 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>
운반 계열 착수. 품셈 원문 대조 결과 **셋이 서로 다른 식**임

```
굴착기  Q = 3600 ÷ Cm(초) × q · K · f · E        (8-1-4, 이미 구현)
불도저  Q = 60 ÷ cm(분) × (q₀ × e) · f · E        (8-2-1)  ← 이번
        cm = L/V1 + L/V2 + t,  t = 기어 변속 0.25분
덤프    Q = 60 ÷ cm × q · f · E,  q = T·L/γt      (8-2-8)  ← 다음
```
- ⚠ **밑수가 60(분)** 임 — 굴착기(3600초)와 섞으면 **60배 어긋남**. 주석에 못 박음
- ⚠ 속도가 「단」에 따라 다름(8-2-1 [주]) — 굴착·운반 1단 · **흐트러진 토사운반 2단** ·
  평탄 정지 3단. **임도 운반은 [주]② 가 가장 가까워 2단 잠정 채택**(TODO 미결)
- 표에 없는 규격은 **속도를 지어내지 않음**(짝 시험)

검산: 19톤·L=20m·V1 55·V2 70 → cm 0.8994분 · **Q 86.709㎥/hr** · 1㎥당 0.01153hr

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 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>
- 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>
- 8-2-1 속도표를 단(1·2·3단)까지 전부 담음. 무한궤도 13톤·타이어의 없는 후진 3단은
  담지 않음 — 없는 속도로 싸이클이 서면 값이 조용히 틀림.
- 「(0.55-0.1)」 같은 보정식을 읽음 (8-2-1 [주]④ 정지작업 −0.1). 범위 표기와 갈라
  다룸 — 범위는 여전히 확정값 아님.
- 갈래 없는 표(「f | 1/1.3」)도 읽음.
- 결과: FP-09-17-02 비다짐(정지) 1,410.1 원/㎥ 섬 (3단 75/98, E=0.45, 19톤).
- 시험 4건 추가, 228건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- masonry_wet·masonry_dry 에 `stone_kind` 옵션 추가 (야면석·호박돌 / 깬잡석 /
  깬돌 / 견치돌). 기본값 없음·required·phase detail — 품셈 13-4-3(고임돌)·
  13-4-4(채움 콘크리트) 가 돌 종류로 갈리므로 B08 이 계수 축을 하나로 고를 수 있게 함.
- 값 선정은 설계 판단이라 기본값을 두지 않음 — 미지정이면 B08 이 드러냄.
- 지식DB 미결 22 등재: 옆도랑 저폭 0.3m 근거 공백(별표2 는 너비·깊이만) +
  현행 45° 단면이 통수단면 경제 단면 60° 와 어긋남.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
md 가 ../pic/*.png 를 네 곳 참조하는데 그 폴더가 저장소에 없었음.
원본 PDF 는 있어서 그대로 뽑음(지어낸 것 없음).

  p35_1  686×673
  p39_1  690×673
  p64_1  368×229   ← [참고자료] 돌쌓기 표준도
  p98_1  592×168

⚠ p64 가 B07 표준도 일감의 근거임 — 우리가 그리려던 그림이
품셈 참고자료로 이미 있었음. 같은 자리의 「돌쌓기 규격별 소요량」 표가
우리 계수(고임돌 0.15 · 채움콘크리트 0.20 · 모르터 0.009)의 원천이라
그림과 표가 한 벌로 표준도 한 장이 그대로 나옴.

그림에 적힌 것: 뒷길이 · 뒷채움 · 채움재(콘크리트 또는 잡석) · 기초
— 우리 전개식 성분과 그대로 맞물림.

⚠ 2026 개정안이 그 참고자료를 「삭제 검토」로 두었음. 없어지면
우리 계수의 근거가 사라지므로 어느 판을 정본으로 쓸지 정해야 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑이 stone_kind 칸을 만들어 축이 생김. 지금까지 계수 셋이
축 없이 한 벌(깬돌 계열)로만 돌고 있었음.

원문 근거 셋을 데이터 파일로 뺌 (resources/data_masonry/stone_kind_*)
  고임돌      품셈 13-4-3 · 돌 종류 네 줄(야면석/깬잡석/깬돌/견치돌)
  채움콘크리트  품셈 13-4-4 [주]① · 두 줄(야면석 33.3% / 깬돌 계열 45%)
  뒤채움      교본 7-3 · 깬돌·잡석 1/2 · 야면석 1/3

⚠ 안 고르면 종전 값 그대로 — 건설품셈 참고자료 한 벌로 돌되 그 사실을 알림.
  값을 못 낸다고 멈추면 이미 저장된 프로젝트가 통째로 빔.
  (실측: 미지정 고임돌 3.915 · 채움콘 5.220 · 막자갈 15.130 — 고치기 전과 같음)

⚠ 만들다 잡은 것 — 표는 「뒤채움 몫」인데 우리 식은 「빼는 몫」이라 뜻이 반대.
  그대로 넣었더니 미지정 막자갈이 15.130 → 19.045 로 바뀌었음. 1 에서 빼게 고침.
  종전 하드코딩 2/3 이 곧 야면석(1 − 1/3)이었음.

⚠ 지어내지 않는 자리 — 원문 「-」(견치돌 25·30 · 야면석 75)는 null 로 두고
  사유를 냄. 모르는 종류도 조용히 안 넘김.

시험 7건 — 미지정이 종전 그대로 · 야면석이 바뀜 · 깬돌이 종전과 같음 ·
⚠ 뒤채움 몫을 뒤집어 쓰지 않음 · 「-」를 안 지어냄 · 모르는 종류 · 근거 문구

시험: 720 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
수량 자릿수 (품셈 1-2-2의 1)
- 화면이 모든 수량을 2자리로 찍고 있었음. 품셈은 종목별로 자리를 따로 정함 —
  체적합계·시멘트·철근 정수 / 돌쌓기·옹벽·떼 1자리 / 철강재 3자리.
- 수량은 반올림([주]①), 금액은 버림 — 반대라 모듈을 갈라 둠.
- 항목이 표를 이김([주]②) → override 받음. 표에 없는 종목은 안 건드림.
- 서버가 줄마다 quantity_digits 를 실어 보내고 화면은 그 자리로 찍기만 함.

금액 자리 보강 (품셈 1-2-2의 2)
- 설계서 총액 1,000원 미만 버림 · 일위대가 계금 1원 미만 버림 추가.
  금액란(0.1원)·소계(1원)와 자리가 넷 다 다름.

⚠ 단위 불일치 가드
- 돌쌓기(찰)이 연장 10m 로 오는데 일위대가는 ㎡당이라 52,938.9×10 = 529,389원이
  조용히 서 있었음. 면적으로 세면 1,381,753원 — 2.6배 적은 금액이었음.
- 단위가 다르면 곱하지 않고 사유를 남김. 표기 차이(㎥/m3·개소/개)는 흡수하되
  환산은 안 함. 내역 합계 6,252,172 → 5,048,775 (틀린 두 줄이 빠짐).

제잡비 밑수
- 닫힌 물음임을 원문 인용으로 못 박음 — 산림품셈 [주]③ 여섯 자리가 「노무비의
  합계액」이고, 일위대가 안에는 간접노무비가 없으므로 그 표의 노무비 합 =
  직접노무비. 하루에 두 번 뒤집힌 값이라 세 번째가 없게 근거를 남김.

시험 10건 추가, 238건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
조율 창 지시로 KeyError 를 막으러 갔다가 더 나쁜 것을 찾음.
죽지는 않고 있었고 대신 조용히 접히고 있었음.

  40㎝  → 45㎝ 계수로 돎     999㎝ → 60㎝ 계수로 돎
  25·30 → 35 로, 75 → 60 으로 접힘

⚠ 접을 까닭이 없었음 — 품셈 13-4-3·13-4-4 [주]① 이 25·30·35·45·55·60·75
  일곱 규격을 다 줌. 우리 표가 네 칸만 들고 있었을 뿐임.

- 표를 일곱 규격으로 채움(건설품셈 참고자료 값, 고임돌은 「깬돌」 열)
- 표에 없는 값(40 등)은 접지 않고 「품셈 표에 없어 물량이 서지 않습니다」
- ⚠ 원문 「-」인 칸은 0 줄을 만들지 않음 — 0 은 「없음」과 구별이 안 되고
  받는 쪽이 「값이 0 인 자재」로 읽음
- ⚠ 고른 종류의 빈 칸은 빈 칸으로 덮음 — None 이라고 안 덮었더니
  「야면석 75㎝」처럼 원문에 「-」인 칸에 종전 값(깬돌 0.25)이 섰음(만들다 잡음)

⚠ 옛 시험이 「덮는 위 칸으로 접는다」를 계약으로 못 박고 있었음 — 오늘 네 번째.

시험 넷 — 접지 않음 · 표에 없으면 물량 안 냄 · 고른 종류의 빈 칸은 줄 없음 ·
일곱 규격이 다 섬.
시험: 723 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 품셈 13-2 채집 계열은 같은 품을 「㎡당 0.17 / ㎥당 0.64」 두 벌로 줌.
  행-자원으로 읽어 앞줄만 잡고 뒷줄을 버려, 막돌 채집이 ㎡당 값을 ㎥ 단위로
  달고 있었음 (29,251.5원/㎥ ← 실제 ㎥당은 110,123.5원).
- 밑수마다 따로 세우고 갈래 이름에 밑수를 넣음(#㎡당·#㎥당). 갈래의 단위가
  그 밑수라 내역서 단위 불일치 검사가 엉뚱한 밑수를 걸러 냄.
- 밑수 표기가 하나뿐인 표는 안 건드림 — 넓게 잡으면 멀쩡한 표가 쪼개짐.
- 열이 갈래인 표는 갈래 × 밑수로 폄(「45㎝·㎥당」).
- 이름을 못 풀면 표째 버림 — 앞줄만 서는 반쪽 단가를 만들지 않음.

⚠ 야면석 채집(13-2-4)은 아직 안 섬 — 직종을 「인 부」로만 적는데 그런 직종이
노임 카탈로그에 없음(품셈 전체에서 이 표 하나뿐). 보통인부로 단정하지 않고
사용자 확정 대기로 둠.

시험 5건 추가, 243건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 실제로 금액이 틀리던 자리 — 돌쌓기(찰)를 `m · 10.0` 으로 보내는데 품셈
13-4-5 밑수는 ㎡ 라, 받는 쪽이 52,938.9원/㎡ 를 그대로 곱해 529,389원이 섰음.
면적으로 세면 26.101㎡ × 52,938.9 = 1,381,753원 — 2.6배. 양쪽 다 오류 없이 조용했음.

- `billing_component` 를 매핑에 두고 **전개 성분에서** 내역 수량을 가져옴
  (면적 식을 두 벌로 짜지 않음). 돌쌓기·큰돌쌓기 = ㎡ · 비탈면적.
- 성분이 안 서면 **연장으로 대신 세지 않음** — 0 + 품셈 밑수 단위로 두고 사유를 냄.
- 신설 `B08_Quantity_Engine_BasisUnit.py` — 인계 줄 단위를 **공종 마스터 밑수**와
  대조해 `basis_unit_warnings` 로 냄. 표기 차이(㎥/m3·개소/개)만 흡수하고 **환산 안 함**.
- 돌 종류를 둘째 갈래 축(`secondary_axes`)으로 실어 보냄 — 품셈 13-4 [주]② 가
  「깬돌·깬잡석 전용」이고 돌 종류 표는 13-5 에 따로 있음. 공종 판단은 사용자 확정 대기.
- 옛 시험이 「10.0 m」를 계약으로 못 박고 있어 정정(오늘 다섯 번째).

시험 732 통과 (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 일위대가 211개 중 73개가 단위를 못 달고 있었고, 단위가 없으면 내역서의 단위
  불일치 검사가 못 걸림. 층따기가 「㎡ 수량 × ㎥당 단가」로 4,102,708원을 내고
  있었음 (돌쌓기 「m × ㎡당」과 같은 병).
- 원문에 적힌 자리 둘에서만 읽음 — 절 머리 아래 「(단위: ㎥당)」 · 공식형 [주]의
  「Q= ㎥/시간」. 73개 중 12개를 채웠고 나머지는 미확보로 둠.
- ⚠ 「인 당」·「일 당」은 품의 단위이지 공종 단위가 아니라 받지 않음. 틀린 단위로
  검사를 통과시키면 없느니만 못함.
- 자원 줄이 단위를 주면 그 값이 이김 — 원문 조회는 빈 자리만 채움.
- 결과: 층따기 4,102,708원이 「단위가 안 맞습니다」로 바뀜. 본체 합계
  7,837,891 → 3,735,183원. ⚠ 줄어든 것이 맞음 — B08 이 ㎥ 로 보내야 풀림.

시험 6건 추가, 249건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 또 하나의 단위 불일치 — 층따기 9-18 은 [주] 공식 `Q1 = 3600×q×K×f×E/㎝ = ㎥/시간`
이라 단가가 ㎥당인데 우리는 성토 비탈면적 ㎡ 2,645.21 을 보내고 있었음.
그대로 곱혀 4,102,708원이 서 있었음(B09 실측).

- 매핑에 `basis_unit`·`basis_source`·`mismatch_reason` 을 두고, 우리 단위와 뜻이
  다르면 **환산하지 않고** 막음(`input_missing` — 층따기 단 높이·폭은 설계 입력).
  막힌 줄에도 집계값을 `spec_detail` 에 남겨 되짚게 함.
- ⚠ 절 머리에 「(단위: …)」가 없는 공종은 마스터 `basis_unit` 이 빔(477 중 167만 참).
  그래서 밑수 대조가 조용히 통과하고 있었음 — 매핑이 원문에서 읽어 적은 밑수를
  `declared_units()` 로 함께 넘겨 대조가 서게 함.
- 성토면다짐(9-17-1)은 시공량이 ㎡/시간이라 면적이 맞음 — 좁게 막아 형제 공종은 그대로.

시험 736 통과 (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「A = 77.7 ㎡/시간」처럼 등호와 단위 사이에 수가 끼는 표기를 읽음
  (9-17-1 비탈면 다짐이 그래서 통째로 미확보였음).
- 상위 절이 스스로 안 적고 하위만 적는 경우를 채움 — 암절취 9-4 · 발파암 9-5 ·
  노체 9-16 · 덤프운반 10-12 가 전부 ㎥.
- ⚠ 좁힘: 말한 하위가 둘 이상이고 값이 하나로 모일 때만. 하나만 말한 것을 상위에
  주면 장 전체가 그 단위가 됨 — 「13. 돌공사」가 실제로 ton 으로 나왔음.
- 단위 빈 일위대가 73 → 61.

시험 3건 추가, 252건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 마스터가 못 채운 자리(절 머리에 「(단위: …)」가 없는 공종)를 원문에서 읽어 적음.
줄 번호까지 열어 확인했고, 시험이 그 줄에 그 글자가 있는지 매번 대조함.

  FP-09-03-02 기계(흙깎기) ㎥ L4704 · FP-09-04 암절취 ㎥ L4725·L4738
  FP-09-05 발파암 ㎥ L4744·L4777 · FP-09-16 노체 ㎥ L5322·L5336·L5363
  FP-09-17-01 비탈면 다짐 ㎡ L5368 · FP-10-11 불도저 운반 ㎥ L5919
  FP-10-12 덤프 운반 ㎥ L5928·L5971·L5985

⚠ FP-12-06 은 「없음」이 아니라 **거절** — L6229 「(단위: 일당)」은 품의 단위이지
공종 수량 단위가 아님. 받으면 틀린 단위로 검사를 통과시킴. 매핑에 사유를 적음.

⚠ 덤프 단위중량 γt 가 원문에 있었음(「현장값이라 미확보」 정정) —
L5930 [주]② 「토사 1.9ton/㎥, 암절취 및 발파암은 2.4ton/㎥」. 갈래별로 값이 다름.

시험 739 통과 (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
자재 카탈로그가 이름+규격 두 문자열로 줄을 찾고, 그 규약이 「공백 없는 한 낱말」임
(2026-09-08 B09 실측 — 키는 나라장터 물품식별번호라 우리가 맞출 것이 아님).
전개·관측 원단위표·할증표 세 곳을 함께 고침 — 한쪽만 고치면 이름이 갈림.

⚠ 고임돌·야면석 규격에 뒷길이를 넣지 않음 — 뒷길이는 **수량이 갈리는 축**이지
단가가 갈리는 축이 아님(야면석 톤당 단가는 뒷길이와 무관). B09 가 앞 제안을 물림.

곁들여 — 물구멍관 길이 0.5 가 구조물마다 다른 값임을 주석에 적음
(옹벽 0.32 m/m · 돌기슭막이 0.39 m · 돌골막이 0.5 m/개소, 실무 관측).

시험 739 통과 (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「(㎡당)」·「(인/100㎡당)」·「(1,000본당)」처럼 「단위:」를 뺀 절이 있음.
  씨앗뿜어붙이기 5-24 가 그 모양이라 통째로 미확보였음(메인이 물은 아홉 중 하나).
- 「인/」 앞머리는 품의 단위라 건너뜀 — 「인/㎡당」은 「㎡당 몇 인」이라 공종 단위가 ㎡.
- ⚠ 「㎥/1대, 1일」·「대/ton」은 안 받음 — 그건 시공량이지 소요량이 아니라
  공종 단위로 읽으면 뜻이 뒤집힘(역수). 밑수가 둘인 「1ha당, 100본당」도 안 받음.
- 절 단위 128 → 185, 단위 빈 일위대가 61 → 27. 내역 금액 변동 없음.

시험 2건 추가(받을 것·막을 것 짝), 254건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ **계약은 하나도 안 바뀜** — 줄의 모양·칸 이름 그대로이고 파일만 가름.
종전 이름으로 부르던 곳이 그대로 돌도록 `Engine_Handoff` 가 다시 내보냄.

  Engine_Handoff.py          249줄  build_handoff·검사·다시 내보내기
  Engine_Handoff_Mapping.py  413줄  매핑표·WorkItemMapping·갈래표·묶음 전개
  Engine_Handoff_Rows.py     700줄  줄 빌더 여덟(토공·운반·구조물·준비공·배수관·연장·타설)

확인 — 시험 739 통과로 가르기 전과 같음(B05 코리도 1건 기존 깨짐, 무관).
다시 내보내는 이름 22개를 실제로 불러 봄.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 아홉 중 여덟째 — FP-05-24 는 원문 L2769·L2794 절 머리 아래 「(㎡당)」인데
「단위:」 글자 없이 **괄호만** 있어 마스터가 못 읽던 자리(원문 열어 확인).

⚠ 그리고 매핑 밑수 칸은 **사람이 손으로 적는 자리**라, 품셈에 섞여 있는
「(㎥/1대, 1일)」 같은 **시공량**을 적을 수 있음 — 그것은 밑수의 **역수**라
받으면 그 공종이 조용히 뒤집힌 단위를 가짐. `is_quantity_unit()` 으로 좁게 막음
(나눗셈·쉼표가 있거나 「일당·조·인」이면 안 받음). 애매하면 안 받는 쪽 —
안 받으면 대조가 없을 뿐이고, 잘못 받으면 틀린 단위로 검사를 통과시킴.

시험 741 통과 (B05 코리도 1건 기존 깨짐, 무관).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
소광 기번8 내역서 「제형돌수로 B=0.75 m」 — 별표2 너비 0.5~1 m 범위 안.
한 공사지 한 줄이라 일반화 불가 표시 유지.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 네 창이 **같은 원본에서 같은 방법으로** 떠야 수치를 견줄 수 있는데,
쓰던 스크립트가 `tmp/` 에 있어 다른 창이 못 봤음(2026-09-08 랩탑 두 창이 막힘).
원본은 SELECT 만 함 — 원본 행·파일에 쓰지 않음.

뜨는 것 — DB 열 표(projects·input_files·processed_point_cloud·surface_models·
routes·route_points·route_statistics·longitudinal_sections·cross_sections·
project_workflow_stages)와 저장소 폴더 통째. 자동증가 id 는 새로 받고 참조를 다시 이음.
파일 안에 박힌 옛 UUID 와 초기값 스냅숏의 surface_model_id 도 치환함.

⚠ DB 만 뜨거나 파일만 떠서는 화면이 안 섬 — 수량은 DB(측점·횡단)를 보고
구조물·관 정본은 파일(structures.json·pipe_points.json)이라 둘 다 필요함.

쓰는 법: ./venv/Scripts/python.exe db_management/tools_clone_project.py <원본 UUID> "<새 이름>"

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-08 17:28:56 +09:00
eomsangdon added 4 commits 2026-09-08 17:44:55 +09:00
eomsangdon added 4 commits 2026-09-08 17:46:45 +09:00
eomsangdon added 7 commits 2026-09-08 18:15:37 +09:00
사용자 지적 — 창을 줄이면 내용이 밖으로 나가고 글자를 못 읽었음.

원인은 세 자리의 **고정 최소폭**과 flex 기본값이었음.
- 계획노선|지형 2열이 `repeat(2, minmax(0,1fr))` 로 **고정**이라, 좁아지면 각 열이
  카드 하나도 못 담고 넘쳤음 → `auto-fit` + `min(360px,100%)` 로 바꿔 스스로 1열로 접힘.
- 카드 격자 `minmax(260px,…)` · 고르는 줄 `minmax(200px,…)` 는 그 폭 아래에서 넘침
  → `min(…, 100%)` 로 컨테이너까지만 줄어들게 함.
- 카드 머리줄에 min-width/max-width 를 주어 배지·[선택]·[×] 가 안 밀려 나가게 함.
- 페이지 몸통(flex)에 min-width: 0 — 안 주면 안쪽 격자가 넘칠 때 몸통이 통째로
  가로로 밀렸음.

실측(공용 브라우저): 폭 1400·1000·760·620·480 에서 여섯 컨테이너 모두 **넘침 0px**,
페이지 가로 스크롤 없음(scrollWidth = clientWidth). 트랙 폭도 확인 —
1400/1200 은 580·580(남는 트랙 0px), 1000·820 은 2열, 700 이하 1열.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
창 넷이 DB·저장소를 함께 써 겹침이 실제로 생기는 자리다. 청크·임시배치 갈래에만
있던 보호막 둘이 직행 `/files` 갈래에는 빠져 있었다.

- `is_analysis_running` 가드: 분석 중 업로드를 409 로 막는다. 없으면 분석 2개가
  같은 산출물 경로에서 부딪힌다.
- `supersede_previous_input_files`: 같은 이름 옛 행을 SUPERSEDED 로 내린다.
  없으면 같은 파일이 두 줄로 활성이라 어느 것으로 도는지 순서에 달린다.

세 갈래가 같은 보호막을 쓰는지 지키는 시험을 `tmp/tests` 에 남김.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 의 「확정 없이 다음으로」 단추가 B08 화면 안에 있어, 상세설계(B07)에서
B08 로 못 넘어가면 그 단추에 닿을 길이 없었음(닫힌 문 안에 열쇠).

- 단계 표시줄이 NOT_STARTED·STALE 을 막던 것을 개발환경에서만 품
- 열어 둔 단계는 「확정 전이라 값이 비어 보일 수 있음」을 툴팁으로 알림
- 잠금을 푸는 것이 아니라 가기만 하는 것 — 실제 우회는 B08 의 그 단추가
  서버(common_util_dev_unlock)로 하고, 운영에서는 ENVIRONMENT 로 거절

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
무한 로딩으로 보이던 자리가 둘이었음.

1) 미리받기가 클릭 앞을 막음 (진짜 원인)
   진입 직후 도면 31 장을 순서대로 미리 받는데, 한 장이 0.3~1.0초라
   그 사이 클릭한 도면이 앞의 여러 장 뒤에 줄을 서서 30초 넘게 안 열렸음.
   화면은 「불러오는 중」 그대로였음.
   - 클릭이 도는 동안 미리받기가 쉬게 함
   - 클릭이 이미 받아 둔 장은 건너뜀

2) CAD 가 아무 말도 안 하면 끝이 없었음
   끝을 알리는 것이 drawing-loaded · drawing-error 두 통지뿐이라,
   iframe 이 안 뜨거나(ready 없음) 도면을 여는 중에 멈추면 영원히 돎.
   - 지켜보는 시계 추가 (ready 20초 · 도면 15초)
   - iframe 자체가 못 뜨면 기다리지 않고 바로 끊음
   - 화면 표시만 끊고 요청은 살려 둠 — 늦게 오면 그대로 받음

곁들여 B07 의 「모든 도면 확정 뒤에 이동」 가드를 개발환경에서만 품
(B09 로 가는 길. 운영에서는 그대로 막음).

확인: 단계 표시줄 B08·B09 가 눌리고 B07 → B08 이동됨. tsc 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 8 commits 2026-09-08 18:28:12 +09:00
실측(창 620) — .b09-main 이 1,190px 밀려 나감. 원인이 세 겹이었음.

- .b09-main · 표를 감싸는 body 칸에 min-width: 0 이 없었음. flex 자식 기본 최소폭이
  auto 라 안쪽 표의 최소폭(칸이 nowrap)을 그대로 물었음.
- ⚠ 진짜 원인은 그 아래였음 — .b09-sheet 가 **감싸는 칸(div)에 붙는 자리와 표(table)에
  바로 붙는 자리**가 둘 다 있음(내역서·자재대는 표에 직접). 표에는 overflow 가 안 먹어
  표 폭만큼 바깥이 밀렸음. table.b09-sheet 를 블록으로 바꿔 제 안에서 가로로 넘어가게 함.
- 주석에 백틱을 쓰면 템플릿 문자열이 끊김 — 그 사실을 주석에 남김(한 번 겪음).

실측: 다섯 탭(공사원가계산서·설계내역서·일위대가·단가산출근거·관급·사급) × 창 1400·620
전부 몸통 가로밀림 없음·넘침 0px, 표만 제 안에서 스크롤.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
업로드 하나가 그 프로젝트의 설계 산출물·초기값 스냅숏을 되돌릴 수 없게 지운다.
창 넷이 한 프로젝트를 볼 수 있어 말없이 지우면 남의 작업이 사라진다.

- `describe_existing_outputs`: 지워질 것을 사람 말로 낸다(전처리·노선·횡단·도면·
  수량·원가·초기값). 빈 폴더는 세지 않는다.
- 지울 것이 있는데 확인이 없으면 409 `confirm_required` — 무엇이 지워지는지 함께 준다.
- 세 갈래(직행·청크·보관함 연결) 전부에 `confirm_replace` 를 붙임.
- ⚠ 기본값은 확인 켬(True) — 자동 절차(체인·스크립트)는 물음에 안 걸린다.
  사람이 올리는 라우터만 False 로 불러 확인을 받는다.
- 화면: 409 를 받으면 「되돌릴 수 없습니다」와 지워질 목록을 보이고 한 번 묻는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실사용 확인에서 청크 세션 생성이 NameError 로 500 이 났다. 세 갈래가 확인
단계 이름을 다 들고 있는지 지키는 시험을 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 「넘침은 0 인데 못 읽는」 자리였음. 표가 자기 스크롤 안에서 잘려 넘침 수치로는
안 잡히고, 실제로는 좌측 패널(320 고정)과 진행단계 패널(fixed)이 화면을 덮고 있었음.

실측(B08, 본문에 남는 폭)
  860px  348 → 388     760px  248 → 288
  620px  108 → 175     500px    4 → 194
  1400·1000 은 그대로 (넓은 화면 배치 안 건드림)

방법 — 패널을 비율(vw)로 줄이면 좁아질수록 본문도 같이 줄어 결국 못 읽음.
그래서 **본문에 남길 폭**(--wf-min-content-width: 320px)을 정하고 패널이 그만큼
물러나게 함. 좁은 폭 전용 패널 폭(--wf-left-panel-narrow-width: 280px)도 따로 둠.
진행단계 패널은 폭을 줄이고 아래로 내려 본문 윗부분(탭·표 머리)을 안 가리게 함.

확인 — B03·B05·B06·B07·B08·B09 를 1400·760 두 폭에서 훑음. 문서 넘침 전부 0,
넓은 폭 배치 변화 없음(좌측 320 유지).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
공용 오버레이가 좁은 폭에서 좌측 패널을 320 에서 280·227·182 로 물리면서(ef4cdb66)
2열 칸이 128.8 에서 108.8·82.4·60px 까지 줄어 도면 이름이 말줄임으로 잘렸음.
문서 넘침은 0 이라 수치로는 안 잡히는 자리 — 잘린 것이 `overflow: hidden` 안이라서.

실측 (도면 31장, 잘린 이름 수 · 고치기 전 → 뒤)
  1400·1000    0 → 0   (2열 128.8px 그대로 — 넓은 폭 배치 안 건드림)
  860·760·620  1 → 0   (1열 221.6px)
  560         16 → 0   (1열 168.8px)
  500         19 → 2   (1열 124px)

남은 2건은 횡단도 격자 밖(「계획평면도(노선배치도)」 등)이고 폭 500 에서만 남음 —
그 폭에서 패널이 182px 까지 물러난 결과라 공용 오버레이 몫.

`repeat(auto-fit, minmax(120px, 1fr))` — 가장 긴 이름 107px + 단추 안여백·테두리
20px 를 문턱으로 잡음. 넓은 폭에서는 두 칸이 들어가 배치가 그대로임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 10 commits 2026-09-08 19:10:05 +09:00
⚠ 인라인 좌표는 미디어 규칙보다 세다. 넓은 화면에서 끌어 둔 자리가 좁은 화면에도
그대로 남아 본문을 덮었음(앞 커밋으로 폭은 줄였으나 자리는 그대로였음).

- 좁아지면 인라인 좌표를 **떼어** CSS 자리로 보냄. ⚠ **저장값은 안 지움** —
  지우면 사용자가 맞춰 둔 자리가 사라져 더 나쁨.
- 넓어지면 **끌어 둔 자리를 되찾음.**
- ⚠ 좁은 폭에서 사용자가 직접 끌면 **그 뜻이 이김** — 규칙이 다시 덮지 않음.
  그 자리는 **저장하지 않아** 넓은 화면 자리를 밀어내지도 않음.

실측(진행단계 패널, 저장값 {left:420, top:300} 을 심어 두고)
  1400  420/300 (끌어 둔 자리)        저장값 유지
   760  물러남 · 본문 남음 288px      저장값 유지
   500  물러남 · 본문 남음 194px      저장값 유지
   620 에서 직접 끌기 → 410/309 로 붙고, 폭을 600 으로 바꿔도 그 자리 유지
  다시 1400 → 420/300 되찾음 · 저장값 안 바뀜

곁들여 — 좁은 폭 진행단계 규칙에서 `top: auto; bottom: …` 을 뺌. 위·아래가 함께
잡혀 패널이 화면 높이만큼 늘어났음(실측 717px). 폭만 줄이고 자리는 그대로 둠.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
접었을 때 머리·본문만 감추고 요약줄은 남아, 폭 0 인 패널에서 글자가 64px 밖으로
새어 나왔다(폭과 무관하게 늘 같은 값 — 좁은 폭 문제가 아니라 그 자리 결함).
감추는 목록에 요약줄을 더한다.

확인: 접힘에서 display:none·넘침 0, 펼침에서 이전과 같음(넘침 0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 앞 커밋의 「본문에 320 을 남긴다」가 폭 500 에서 패널을 **180px 로 눌러** 목록
이름이 잘렸음(랩탑 보조 실측: 잘린 이름 2건). 폭을 반씩 나누면 **둘 다 못 쓰는
화면**이 됨.

- CSS ≤560 — 패널을 **안 줄임**(280px 유지). 본문 밀기는 이미 ≤860 에서 꺼져 있어
  패널이 **본문 위에 겹쳐** 뜨고, 읽을 때는 손잡이로 접음. 폭 500 에서 잘린 글자 0.
- TS — 정한 적이 없고 화면이 아주 좁으면(≤560) **접은 채로 시작**함. 펼친 채로 열면
  본문이 가려진 화면부터 보게 되기 때문임.
- ⚠ **사용자가 정한 적이 있으면 그 뜻이 이김** — 저장값이 있으면 그대로 따름.
- ⚠ **처음 앉힐 때는 저장하지 않음** — 좁아서 접은 것을 「사용자가 접었다」로 적으면
  넓은 화면으로 돌아와도 접힌 채로 남음.

실측
  정한 적 없음 + 500  → 접힘 true · 저장값 null (기록 안 남김)
  정한 적 없음 + 1400 → 접힘 false · 저장값 null
  「펼침」 정해 둠 + 500 → 접힘 false (사용자 뜻이 이김)
  잘린 글자 860·620·560·500 전부 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
창폭 480 에서 좌측 패널이 237 까지 물러나면 「횡단 반폭(m)」 라벨이 안 줄어
`.ui-field` 가 2px 넘쳤다(공용 `.ui-field` 는 안 건드리고 내 행에서 처리).

- `@media (max-width: 560px)` 에서만 라벨을 윗줄로 접는다.
- ⚠ 폭 제한 없이 `flex-wrap` 을 주면 넓은 폭에서도 라벨이 윗줄로 올라간다 —
  실제로 재 보고 되돌린 뒤 폭 조건을 붙였다.

확인(1400·760·620·480): 넘침 0 · 잘린 라벨 0 · 가로 스크롤 0,
넓은 폭 높이 42(한 줄) 유지, 480 에서만 68(두 줄).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 재확인(2026-09-09)으로 값 확인. `EARTHWORK_HAUL_EQUIPMENT_LIMITS_M` 의
dozer 는 2026-09-08 에 이미 60 으로 바뀌었는데 바로 위 설명만 70 으로 남아 있었음.
읽는 사람이 설명을 믿고 70 으로 오해할 자리라 맞춤. 동작 변화 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 5번(2026-09-09 「진행해줘」)의 1단계. 실무 원본 `07-구조도-소광리.xlsx`
53탭을 펴서 표 짜임을 확정한 뒤, B08 원단위 전개를 그 모양으로 접는 통로를 냄.

⚠ 계산은 새로 만들지 않음 — `build_unit_table` 결과를 제원 조합으로 묶고 단위당으로
나눌 뿐임(계산 자리는 한 곳, CLAUDE.md 5장).

장 나눔 축 = 제원 조합(`type_id` + 높이 + 제원 전부). 확정 ⑨ 대로 기울기가 바뀌면 장이
갈림 — 기울기가 제원의 한 칸이라 저절로 지켜짐. 측점·방향처럼 개소마다 다를 뿐인 칸은
장을 안 가름(`PER_PLACE_OPTION_KEYS`).

선행 확인 두 건도 끝냄
  · 8-3 틈메우기돌 — 53탭 전수에서 `틈메우기`·`틈막이`·`사춤` 0건 ⇒ 넣지 않음
  · 8-2 버림 콘크리트 — 실무에 있음(「바닥 10㎝ 이상 콘크리트(버림)」 · 옹벽 버림CON'C),
    KDS 44 90 00 의 100㎜ 와 같음

⚠ 만들다 잡음 — `billing_unit` 이 비어 있으면 「단위 미정」이 아니라 「m·연장」이라는
계약이 있었음(`StructureQuantity`). 미정으로 읽어 돌쌓기가 전부 단위 없는 장이 됐음.

⚠ 실무 시트와 어긋나는 줄 일곱은 PLAN 4-12 에 표로 남기고 확정 대기로 둠 —
임의로 맞추지 않음(터파기 0.35 대 2.30 이 가장 큼).

자체검증 — 새 시험 11건 통과, 회귀 562 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-08 19:23:51 +09:00
별표2 Ⅰ.1.나.(5) 가 요구하는 여덟(지반고·계획고·절토고·성토고·단면적·지장목 제거·
측구터파기 단면적·사면보호공) 중 뒤 넷이 빈칸으로 나가던 자리.

빈칸의 까닭은 「값이 없어서」가 아니라 **통로가 없어서**였음 — 표가 `source["quantities"]`
를 보는데 그 키가 원본 파일에 아예 없음(실측: 횡단 원본 15키에 `samples`·`center_z`·
`chainage_m` 은 있고 `quantities` 는 없음). 반면 저장된 설계에는 단면적이 그대로 있고
사면길이도 설계선에서 유도됨.

⚠ 계산을 새로 짜지 않음 — 단면적은 B06 저장값을 그대로 읽고, 사면 계열은 B08 이 쓰는
`station_slope` 를 그대로 부름. 계열 이름·어느 면을 쓰나도 `SlopeArea` 정의를 빌림
(거기서 밑수가 바뀌면 이 표도 같이 움직여야 함).

채운 열 칸
  단면적 3   깍기 토사 · 깍기 암석 · 쌓기
  사면   7   층따기 · 면고르기(성·절) · 지장목제거(성·절) · 성토파종 · 절토살포

⚠ 사면 칸의 단위 — B08 은 측점 사이를 적분해 ㎡ 를 내나 그것은 두 측점이 있어야 나옴.
한 장짜리 횡단도에 들어가는 것은 그 측점의 **사면길이(m)** 이고 1m 폭 조각의 ㎡/m 와
수치가 같음. 표기를 m 로 볼지 ㎡/m 로 볼지는 표기 문제이고 값은 하나임.

안 채운 칸 — 근거가 없어 임의로 안 넣음
  측구 토사/암석(저장값이 `ditch_area_m2` 한 값뿐) · 표토제거(두께 칸 없음) ·
  편책(별도 일위대가 제작 뒤 연결로 확정) · 제근(입목 본수 안 듦) · 노면다짐

자체검증 — 새 시험 8건(사면길이는 손으로 잰 √5 · √(2.4²+2²) 와 대조, `is not None`
만 보면 0 이어도 통과하므로 실수치로 맞춤), 회귀 570 통과 · 0 실패.
실프로젝트 936be972 세 측점에서 **21칸 중 14칸**에 값이 찍힘(앞서 4칸).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 18 commits 2026-09-08 19:32:21 +09:00
⚠ 빠뜨리고 있던 줄임 — 지식DB `구조물_기초_토공.md` [구현] 이 「구조물 토공 수량 항목:
터파기·**버림콘크리트**·되메우기·뒤채움·잔토처리」로 이미 지목해 두었고, 실무 시트도
같은 공종에서 버림 유무로 0.30 ↔ 0.20 ㎥/㎡ 로 갈렸음.

근거(원문 열어 확인)
  두께 KDS 44 90 00 「구조물 시공이 원활하도록 **100 mm 두께**의 버림콘크리트를 타설」
  폭   KCS 34 50 05 「두께는 설계도서에 따르며, **폭은 잡석다짐의 폭과 동일**하게 한다」

⚠ 잡석다짐 폭이 아직 없어(기초잡석은 품셈에 공종만 있고 치수가 없음) **터파기 폭을
잠정**으로 쓰고 근거 문구에 그 사실을 적음 — 정해지면 상수 한 줄만 바꾸면 됨.

- 기본은 **넣음**, 저장 제원에서 「안 넣음」이면 뺌(확정 ⑭ 「기본 보이게, 뺄 수도 있게」).
  ⚠ 빈 칸을 「빼기」로 읽지 않음 — 정한 적 없는 프로젝트에서 줄이 사라지면 안 됨.
- 돌쌓기·큰돌쌓기 둘 다. 옹벽은 관측 원단위에 이미 0.15㎥/m 로 있었음.
- 타설 줄은 **버림 몫만** 셈 — 채움 콘크리트는 그 공종 품에 들어 있을 수 있어 제외 유지.

시험 743 통과(새 6건 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(2026-09-09): 층따기 단위는 ㎡. 대신 그 면적이 B06 설계에서 나와야 한다.

- `_bench_cut_length`: 성토(diff<0) 구간에서 원지반 횡단기울기가 **1:4 보다 급한**
  조각만 골라 지표면을 따라간 길이(빗변)를 더한다. 절·성토 경계는 영교점까지만 센다.
  근거는 별표2·교본 6장 4절, 지식DB 성토_비탈면 §4 [구현].
- 결과에 `bench_cut_length_m` 을 실어 B08 이 측점 사이를 평균단면적법으로 이어 ㎡ 를 낸다.
  ⚠ 여기서 ㎥ 로 바꾸지 않는다 — 단의 높이·폭은 설계도서 값이라 지어낼 수 없다.
- 파이썬·TS 짝을 함께 고침(`common_util_cross_design_areas.ts`). 거울 테스트 통과.
- ⚠ 성토 비탈면 길이가 아니라 **원지반 표면**을 센다 — 층따기 대상 면이 그쪽이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
법이 요구하는데 우리가 안 내던 줄들임 — 국가지점번호판·안내판·차단기·가설창고·수방자재.

⚠ 개소를 **지어내지 않음.** 임도규정 제26조제5항이 「500미터 마다 설치·관리하되
**필요시 거리를 조정**할 수 있으며」라 하고 기점 포함·종점 잔여·갈림길 중복을 원문이
정하지 않음 ⇒ `연장÷500` 을 산식으로 쓰지 않고 설정 `ancillary_counts` 로 **개소를 받음**.

⚠ 사유를 **갈라 적음** — 「품셈에 그 이름의 공종이 없음」과 「개소 미입력」은 다음에 할 일이
다름. 법정 의무인 둘(번호판 제26조5항 · 안내판 제26조6항)은 그 사실을 사유에 적어
화면에서 왜 채워야 하는지 보이게 함. 차단기는 교본에만 있어 「법정」이라 적지 않음.

⚠ 다섯 중 **품셈에 공종이 있는 것은 가설창고(FP-11-01) 하나뿐**(마스터 전수 확인).
나머지 넷은 금액이 못 서지만 **줄은 세움** — 빼면 빠진 줄을 아무도 못 봄.
개소를 안 넣어도 줄이 서고 사유가 함께 감(준비공 표 · 인계 양쪽).

시험 749 통과(새 6건 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 12번 「내야 할 표 16개 전체」. 안 내던 일곱 중 넷을 냄.

- 서식은 지어내지 않고 실무 내역서(영월 기번6·봉화 기번41) 같은 이름 시트를 그대로
  옮김 — 코드번호·명칭·규격·단위·단가·비고. 중기목록표만 합계 + 3분할(노무·재료·경비).
- ⚠ 경비목록표는 취득가(천원)이지 시간당 손료가 아님. 실무 실측
  「S00104 불도저(무한궤도) 19톤 천원 184,499」와 자릿수를 맞춤 — 손료를 실으면
  세 자리 어긋난 채 「경비」로 읽힘.
- 자원 집계표(역집계)도 함께 냄. 일위대가 안쪽을 한 겹만 폄 — 기계 사용료를 다시
  손료·연료로 쪼개면 중기 집계표와 이중계상이 됨. 비율 줄(제잡비)은 자원으로 안 셈.
- 집계표는 반올림, 내역서 본체는 절사 — 어긋나는 것이 정상임을 문구로 함께 냄.
- 새 계산 없음. PriceBook 자료를 접기만 함.

실무 대조(2024 대 2026 자료): 보통인부 165,545→172,068 · 불도저19 취득가
184,499→198,150 · 시간당 126,029→124,842. 연도 차이 범위 안.

라우터 조회 하나 추가(GET .../estimation/base-data). 시험 8건, 262건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ **면이 달랐음.** 층따기는 성토부 **아래 원지반**을 계단으로 깎는 일인데(교본 6장 4절)
우리는 **성토 비탈면 길이**를 밑수로 쓰고 있었음. 값이 나오므로 아무 시험도 안 잡던 자리.

B06 설계가 측점마다 내는 `design.bench_cut_length_m`(원지반 표면의 경사길이, 원지반
횡단기울기 1:4 보다 급한 조각만)를 그대로 밑수로 씀. 면적은 종전대로 **평균단면적법**.
⚠ 값이 없는 측점은 **0** — 성토 사면길이로 대신 채우지 않음(다른 면을 세게 됨).

⚠ 단위는 **㎡ 그대로**(사용자 확정 ⑦). ㎥ 로 바꾸지 않음 — 단의 높이·폭은 설계도서 값이라
지어낼 수 없음. 앞서 「품셈 밑수가 ㎥ 라 못 곱함」으로 막아 둔 자리는 이 확정으로 풀림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 에는 「품셈 공식이 ㎥ 인데 우리는 ㎡」라 막아 두었음(410만원 자리).
사용자가 **㎡(실무 관행)**로 확정했으므로 매핑 밑수를 ㎡ 로 바꾸고 막힘을 풂.

⚠ 어긋남 자체는 사라지지 않았으므로 매핑에 **그 사실과 까닭을 적어 둠** —
품셈 9-18 [주]는 `Q1 = … = ㎥/시간` 이라 공식은 체적 기준이고, 단의 높이·폭이
설계도서 값이라 체적을 지어낼 수 없어 면적으로 감. ⇒ **받는 쪽이 ㎡ 단가를 세워야 함**
(㎥ 단가를 그대로 곱하면 금액이 틀림).

옛 시험 둘이 「층따기는 막힌다」를 계약으로 못 박고 있어 정정.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
돌은 기본 「캔다」(별표2 「야면석 등은 **가급적 현장에서 채취·사용**하도록 운반거리를
조사한다」 · 실무 견적 다섯 권에 야면석 구입 단가 0건). 구조물마다 「구입」으로 바꿀 수 있음.

⚠⚠ **채집석 공제는 사토에서 한 번만 뺀다.**
B08 은 소요량(`collected_stone_deduction_m3`, ㎥ **양수**)을 내기만 하고 공제하지 않으며,
빼는 자리는 유토곡선의 사토뿐임 — 실어 내는 몫(spoil_m3 − natural_spoil_m3)에서 먼저 빼고
모자라면 자연방토에서 뺌. (랩탑 메인의 통로에도 같은 문장을 박아 둠 — 두 곳이 같은 말이라야
나중에 누가 봐도 안 갈림.)

⚠ **부호를 넘기지 않음.** 실무 시트가 `−274.66` 이라 그대로 넘기면 두 번 뒤집힘.

밑수 — 면석 몸통(면적×뒷길이×몫) + 고임돌 + 막자갈. **이미 우리 식 안에 있는 값들**이라
새 수치를 지어내지 않음. 목적지는 `haul_deduction` 이라 자재총괄(`material` 만 모음)에
안 섞임. 인계 맨 위에 구조물 합산 한 값으로 실림.

시험 754 통과(새 6건 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
네 창 합의 문구 그대로 못 박음:

    채집석 공제는 사토에서 한 번만 뺀다.
    B08 은 소요량(collected_stone_deduction_m3, ㎥ 양수)을 내기만 하고 공제하지 않으며,
    빼는 자리는 유토곡선의 사토뿐이다 —
    실어 내는 몫(spoil_m3 − natural_spoil_m3)에서 먼저 빼고 모자라면 자연방토에서 뺀다.

- `computeHaulPlan` 이 공제를 받아 **잔량 하나하나**를 줄인다 — 총량만 줄이면 사토
  balloon·운반거리가 안 따라간다. 지반유형 안분도 같은 비율로 줄인다.
- ⚠ `null`(아직 안 옴)과 `0`(공제 없음)을 가른다. 결과에 받은 값과 실제로 뺀 값을 함께 싣는다.
- 서버 진입점·파이썬 context 를 통로로 이어 둠. B08 이 값을 내면 실어 주기만 하면 됨.

시험 3건(공제 반영·잔량 동반 감소·사토 초과 시 사토까지만·자연방토는 나중) 을
TS 를 실제로 돌려 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실무 내역이 「레미콘타설(장비) **무근,버림**」으로 갈라 적음(봉화 제50호표,
2026-09-09 데스크탑 보조 확인). 같은 공종·같은 단가라 **금액은 안 움직이고 이름만 맞춤** —
받는 쪽이 그 갈래로 일위대가를 그대로 세울 수 있게.

⚠ 버림은 늘 무근이라 구조물 종류(무근/철근)를 따라가지 않음. 그래서 버림 몫만 따로
모아 갈래 이름을 「무근,버림」으로 냄. 나머지 콘크리트는 종전대로 구조물 종류로 갈림.

검증 프로젝트 실측 — 돌쌓기 셋·큰돌쌓기 하나의 버림이 한 줄로 모여 4.700㎥.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
별표2 Ⅰ.1.나.(5) 「측구터파기 단면적」이 횡단도 표의 법정 칸인데 한 값뿐이라
「측구 토사 / 측구 암석」 두 칸이 반만 채워졌다.

- 가르는 근거는 **절토 분리와 같은 것**(지반 유형 + 암반 경계선). 새 입력을 만들지 않았다.
- 측구 상단에서 암반 경계선까지의 깊이로 공칭 도형(사다리꼴·L형)을 가로로 가른다.
- ⚠ 근거가 없으면 **나누지 않는다.** 사유를 `ditch_split_basis` 로 함께 냄:
  rock_boundary / soil_ground / rock_ground_no_boundary / no_ditch.
- 기존 `ditch_area_m2` 는 **합계로 그대로** 두고 갈래를 덧붙였다 — B08 이 순서대로 옮겨 갈 수 있게.
- 파이썬·TS 짝을 함께 고침. 거울 테스트 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 메인이 측구를 갈라 냈으므로(`6a7c339f`) 그 값을 그대로 옮김.
여기서 다시 가르지 않음 — 근거가 없는 측점은 B06 이 나누지 않고 사유를 함께 냄.

`split_basis()` 를 함께 둠 — `ditch_split_basis` 를 사람이 읽는 말로 바꿔 준다.
⚠ 표 칸은 숫자만 담으므로 이 말은 표 밖(주기·화면)에 실어야 함.
「전량 암」이 경계선을 못 찾아서인지 정말 암 지반이어서인지 숫자만으로는 구별 안 됨.

⚠ 층따기 밑수가 바뀐 것이 이 표에도 그대로 왔음 — 랩탑 메인이 「성토 사면길이」에서
「B06 이 낸 원지반 깎는 길이(`bench_cut_length_m`)」로 고쳤고, 이 모듈이 B08 `_length_of`
를 빌려 쓰므로 **같이 움직였음**. 값이 없는 옛 저장분에서는 0 으로 섬 —
성토 사면길이로 대신 채우지 않는 것이 맞음(다른 면을 세게 됨).

실측(936be972, 옛 저장분) — 여전히 **14칸**. `ditch_split_basis`·`bench_cut_length_m`
둘 다 저장된 설계에 없음(B06 확정 전 자료). 새 키가 있는 자료에서 16칸이 되는 것은
시험으로 확인함.

자체검증 — 시험 11건(측구 두 칸 · 못 가른 측점 사유 · 층따기 밑수 따라가기 추가),
회귀 573 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-08 19:44:29 +09:00
「표준도」를 누르면 도각만 실린 빈 장이 뜨던 것을, 제원 조합마다 표 한 벌을
CAD 표 객체로 그려 낸다. 도각은 두르지 않음(2026-09-08 사용자 지시).

값은 여기서 셈하지 않음 — `build_standard_sheets` 가 낸 것을 글자로 옮길 뿐임.
셈이 두 벌이 되면 도면과 수량서가 갈림(CLAUDE.md 5장).

실화면 확인 (프로젝트 936be972, 구조물 5기를 심고 확인)
  장 4개 · 개소 5 — ①③ 이 같은 제원이라 한 장에 2개소로 모임(장 나눔 실물 증명)
  돌쌓기(찰) H=2.5 뒷길이 45㎝ 깬돌   12줄  2개소·합 20.00m
  돌쌓기(메) H=2.0 뒷길이 35㎝ 야면석 10줄  1개소
  옹벽 H=2.0                          7줄  1개소 (관측 원단위 사유 1줄)
  큰돌쌓기 H=2.5                       5줄  1개소 (막힌 사유 4줄이 표에 그대로 뜸)

⚠ 만들다 잡은 것 — 표 폭을 176㎜ 로 냈더니 단서가 붙은 근거 문구(물구멍관·버림
콘크리트)가 칸을 넘어 수량 칸을 덮었음. 표는 글자를 안 접음. A1 작도 영역
739 × 499㎜ 에 맞춰 735㎜ 로 넓히고 줄 높이 9㎜ 로 잡음 —
**네 장까지** 한 면에 듦(47줄 × 9 + 간격 = 465㎜). 더 늘면 장 나눔(㉢)이 필요함.

⚠ 못 낸 값은 0 이 아니라 「-」 로 적음. 도면에 0 이 찍히면 「없다」로 읽힘.
⚠ 구조물이 없으면 빈 격자 대신 사유 한 줄이 뜸 — 빈 표는 「만들다 만 것」으로 보임.

자체검증 — 회귀 573 통과 · 0 실패. 공용 브라우저에서 표준도를 눌러 실제로 열고
확대해 글자·수치를 읽어 확인함(스크린샷 `tmp/browser/shots/standard_fit.png`).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 16 commits 2026-09-08 19:58:27 +09:00
「표가 났는데 안 보이면 낸 것이 아님」. 꺼져 있던 탭 둘을 켜고 표를 붙임.

- 새 파일 B09_Estimation_UI_BaseData.ts — 화면 조립부가 이미 1,200줄을 넘어 분리.
  상태를 안 들고 그리기만 함.
- 기초자료 탭: 노무비(118)·재료비(1)·경비(613) 목록표. 중기 탭: 중기목록표(5).
- ⚠ 빈 표를 그냥 두지 않음 — 재료비목록표가 한 줄뿐인 사유를 표에 띄움.
  「다 채운 것」으로 읽히면 안 됨.
- ⚠ 계산 과정을 감추지 않음(8-13) — 조종원 환산이 실무·교본과 다르다는 사실과
  그 영향(기계 든 공종 +19~24%)을 중기 탭에 적음. 잡재료가 연료에 접혀 있다는 것도.
- 경비목록표는 취득가(천원), 시간당 사용료는 중기 탭이라는 안내를 달았음.

실측(공용 브라우저): 기초자료 표 3장 732줄 · 중기 5줄, 사유 문구 넷 다 뜸.
⚠ 백엔드 재시작이 있어야 새 조회가 붙음(재시작 전 404 → 후 200).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
엔진(`B08_Quantity_Engine_UnitQuantity.STONE_SUPPLY_KEYS`)은 이미 `stone_supply` 를
읽는데 저장 칸이 없어 저장이 거부됐다(`정의되지 않은 옵션입니다: stone_supply`).
`back_len_cm` 때와 같은 계열 — 읽는 키와 저장 칸이 어긋난 자리.

- 붙인 곳: 돌쌓기(찰·메) · 큰돌쌓기 · 골막이 · 바닥막이 · 기슭막이 여섯.
- 기본 「채집」 — 사용자 확정 ②(2026-09-09) 「기본은 캔다, 구조물마다 바꿀 수 있게」.
  별표2 「석축 등에 필요한 야면석 등은 가급적 현장에서 채취·사용」이 근거.
- 저장 왕복을 실제로 해 봄: PUT 200 → 되읽기에서 `stone_supply="구입"` 그대로 나옴.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 어제 넣은 `ancillary_counts` 를 **엔진은 읽는데 저장 요청 모양에는 없었음** — 화면에서
넣을 길이 없어 스크립트로만 넣히던 자리였음(`stone_supply` 가 레지스트리에 없어 저장이
거부되던 것과 같은 계열 — **읽는 자리와 넣는 자리가 안 맞는 것**).

`QuantitySettingsBody` 에 칸을 두고, 「통째로 갈아 끼우는 칸」 목록에 넣음 — 병합이면
개소를 **지울 수가 없음**(0 으로 되돌리려면 통째 교체라야 함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 앞 커밋(`bfd10b57`)이 `variant_value` 까지 「무근,버림」으로 바꿔 **금액이 통째로
빠졌음**(B09 실측 275,584원 · 본체 합계 9,587,677 → 9,312,093). 품셈 12-1-1 의 갈래는
**무근구조물·소형구조물·철근구조물 셋뿐**이라 「무근,버림」은 **없는 갈래**였음.

⇒ 갈래(`variant_value`·`structure_kind`)는 **무근구조물**로 되돌리고, 실무 줄 이름은
**표시 문구(`spec`·`spec_detail`)에만** 둠. 근거 — 봉화 제50호표가 줄 이름은
「레미콘타설(장비) 무근,버림」인데 **단가는 「무근」과 같음**. 실무도 줄만 가르고 품은
무근 것을 씀.

⚠ 받는 쪽이 문자열을 눅여 읽는 방식은 쓰지 않기로 함 — 그러면 다음 갈래가 조용히
잘못 붙음. **보내는 쪽에서 바로잡는 것**이 맞음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 12번의 마지막 둘. ③(자재값 출처 둘 다)·⑮(유가 전국/지역)와 한 벌.

- 서식은 실무 시트(영월 기번6) 그대로 — 원천 5칸(단가+쪽수) + 적용(단가+출처) + 비고.
  원천 이름은 코드에 안 박고 PriceBook.slot_names 를 씀(사무소마다 다름, 9-4 미결).
- ⚠ 확정 ③ — 슬롯마다 출처를 남길 자리를 둠(쪽수·업체명·날짜). 값이 없는 원천은
  0 이 아니라 빈칸. 0 이면 「0원짜리 견적」으로 읽힘.
  견적이 국계법 시행령 §9 의 4순위라는 사실을 표가 스스로 밝힘.
- ⚠ 확정 ⑮ — 유가 전국/지역 고르는 칸을 냄. 다만 지역값이 아직 자료에 없어
  「고를 수 없음 + 까닭」으로 드러냄. 없는 값을 지어내지 않음.
- ⚠ 환율및기초자료 인건비 칸은 운전사 셋만. 직종 118개를 다 실으면 노무비목록표와
  같은 표가 두 벌이 됨 — 실무 시트도 셋뿐임.
- 조종원 시간당이 실무·교본과 다른 사실(× 16/12 × 25/20)을 표 비고에 그대로 냄.

라우터 조회 추가(GET .../estimation/price-sources). 시험 5건 추가, 267건 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실무 탭이 「위 치수조서 + 아래 수량산출서」인데 1단계에서 아래 표가 섰고 이번이 위 그림.
그림이 붙으면서 한 면에 넉 장을 쌓을 수 없게 돼 **장 나눔(㉢)도 같이** 했음.

장 나눔 — 계획평면도가 쓰는 본 그대로
  `standard_sheet` / `standard_sheet_2` … 제원 조합 하나가 한 장.
  좌측 목록은 `idPrefix` 묶음(계획평면도와 같은 짜임)이고 kind 는 새로 `standard`.
  구조물이 없어도 한 장은 남김 — 단추가 사라지면 「없어진 것」처럼 보이고 사유를 읽을
  자리도 없어짐.

그림 — `B07_DesignDetail_Engine_Cad_StandardFigure.py`
  ⚠ **기울기를 값으로 받음. 0.3 을 그림에 박지 않았음.** `face_slope_ratio` 가 오면 그
  값으로 기울고, 비어 있으면 교본 7-3 기본 0.3 으로 그리되 **「자동 판정 전」이라고 그림에
  적음**. 자동 판정이 붙는 대로 그림이 따라감.
  ⚠ 치수는 수량이 쓰는 그 상수(`STONE_MASONRY`)를 직접 읽음 — 여기서 다시 적으면 그림과
  표가 갈림. 상부 0.45+0.10H · 하부 0.45+0.40H · 터파기 폭 평균두께+0.2 · 되메우기 0.2.
  ⓘ 그 상수는 **뒷면이 수직인 1:0.3 벽**을 뜻함(하부−상부 = 0.30H = 전면이 기우는 양).
    기울기가 0.3 이 아니면 그 차이만큼 뒷면이 기욺 — 상수에서 따라 나오는 결과라 그대로 그림.
  ⚠ 치수가 없는 것은 그리되 치수를 안 적음 — 막자갈은 「입적 − 몸통 − 고임돌」이라 폭·높이로
    정의된 도형이 아님. 자리만 보이고 값은 표를 가리킴.

죽은 길 걷어냄 — `BLANK_DRAWINGS` 가 「표준도」 하나뿐이었는데 그것이 내용 있는 장이 되어
빈 도각 경로가 통째로 안 쓰이게 됨. 상수·목록 루프·분기·import 를 지움(700줄 제한도 걸렸음).

자체검증 — 회귀 573 통과 · 0 실패, `tsc --noEmit` 0.
⚠ 병합 뒤 깨진 시험 둘을 고침(내 폴더 `tmp/tests`, 랩탑 메인 `11394d40` 의 여파)
  · `stone_supply='채집'` 기본값을 확정 ② 근거와 함께 허용 목록에 등록
  · 바닥막이 「모든 옵션이 b05」 단정 → 조달이 detail 로 들어와 B05 셋만 보게 좁힘

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 7 commits 2026-09-08 20:06:21 +09:00
⚠ 확정 ⑨ 가 통째로 미구현이었음 — 레지스트리에 `face_slope_ratio` 칸이 없어 **늘 1:0.3**
으로 돌았고, 찰 H=2.5 와 메 H=2.0 이 같은 기울기로 나왔음. 우리 0.3 은 실은
**「메쌓기·성토·직고 1.5m 이하」 한 칸**이었음.

품셈 13-4-4 [주]⑪ <표준경사>를 데이터로 두고 **직고 · 메/찰 · 성토/절토** 셋으로 고름.
  메 성토 0.30 0.35 0.40 0.45 0.50 · 메 절토 0.25 0.30 0.35 0.40 0.45
  찰 성토 0.25 0.30 0.35 0.40 0.45 · 찰 절토 0.20 0.25 0.30 0.35 0.40

⚠ 경계값은 **앞 칸** — 원문 표기가 `∼1.5 · ∼3` 이라 이하로 읽음(직고 3.0m → `~3` 칸).
   7.0m 은 `~7`, 그보다 커야 마지막 칸. 해석을 데이터·주석·시험에 함께 박음.
⚠ **성토/절토가 저장에 아직 없음** — 레지스트리에 없는 키를 읽지 않고 **성토 열로 잠정**
   적용하며 **근거 문구에 그 사실을 적음**. 값이 생기면 한 줄만 바꾸면 됨.
⚠ 저장 제원에 값이 있으면 **그 값이 이김**(확정 ⑨). 자동으로 고른 값은 **저장에 안 박음** —
   「정한 적 없음」과 「0.3 으로 정함」이 구별돼야 함.
⚠ 큰돌쌓기는 이 표 대상이 아님 — 교본이 「1:0.3 **이상**」으로만 둠. 그대로 둠.

검증 프로젝트 실측 — 돌쌓기(메) H=2.0 면적 **20.881 → 21.190㎡(+1.5%)**, 찰 H=2.5 는
1:0.3 그대로. 옛 시험 셋이 「늘 1:0.3」을 계약으로 못 박고 있어 기울기를 명시하도록 정정.

시험 761 통과(새 7건 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표를 냈는데 화면에 없으면 낸 것이 아니라 붙임. 목록표 넷 아래에 A9·A10 두 장 추가.

- 자재단가대비표: 원천마다 「단가·페이지」 두 칸으로 머리글 두 줄, 채택 원천 굵게
- 슬롯 6 이 곧 「적용 단가」라 「적 용」 칸을 따로 세우지 않음 (같은 값 두 번 서는 것 방지)
- 환율및기초자료: 환율·인건비(운전사 3)·단가 및 재료비 세 구획
- 유가 적용 범위 고르는 칸 — 지역 공시가는 자료가 없어 고를 수 없게 두고 까닭 표시 (확정 ⑮)
- 두 표는 목록표와 따로 받아 옴 — 못 받아도 목록표 넷은 그대로 남음
- 시간당 노임이 소수로 남는 까닭을 화면에 밝힘 (여기서 자르면 기계 사용료가 어긋남)

검증: tsc 통과 · pytest 267 통과 · 공용 브라우저 5174 에서 표 6장·줄 737 확인,
body.scrollWidth 1696 < innerWidth 1704 (가로 넘침 없음)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
데스크탑 메인이 넣은 품셈 표준경사 판정(13-4-4 [주]⑪)이 **근거 문구 안에만** 있었고
표준도는 못 읽고 있었음. 판정 함수 `face_slope_ratio()` 를 그대로 부르게 바꿈 —
판정을 두 벌로 짜면 그림과 수량이 갈림(CLAUDE.md 5장).

실측 (프로젝트 936be972 구조물 5기)
  돌쌓기(찰) H=2.5 1:0.3  뒷길이 45㎝ 깬돌       단면 (0,0)(0.75,2.5)(1.45,2.5)(1.45,0)
  돌쌓기(메) H=2.0 1:0.35 뒷길이 35㎝ 야면석     단면 (0,0)(0.70,2.0)(1.35,2.0)(1.25,0)
  큰돌쌓기  H=2.5 1:0.3
  옹벽                                          판정 대상 아님 — 안 적음
⇒ **메쌓기가 찰쌓기와 다른 값으로 갈림**(0.35 대 0.3). 장 제목에 그대로 뜸.

메/찰은 종류에서 옴. 큰돌쌓기는 `bond` 칸이 그것이고 안 고르면 찰쌓기로 봄 —
품셈 13-6 은 둘 다 「1:0.3 이상」이라 그림 기울기가 갈리지 않음.

기울기 근거 문구를 그림 아래 한 줄로 실음 — 「사용자 지정」인지 「품셈 표준경사」인지,
그리고 「성토/절토가 저장에 없어 성토 열로 잠정」인지가 도면에서 보여야 함.

⚠ 시험 제원에서 `face_slope_ratio` 를 뺐음 — 실제 구조물 제원에 그 칸이 없는데 시험만
갖고 있어 **판정 경로가 한 번도 안 돌았음**(늘 「사용자 지정」으로 빠짐). 빼고 나니
메/찰이 갈리는 것이 시험으로 잡힘. 사용자 지정이 이기는 것도 따로 검사함.

자체검증 — 회귀 573 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-08 20:10:09 +09:00
`Router_Support_Io.BLANK_DRAWINGS` 일곱 줄(계획평면도 3종·라이다·표준 횡단면도·표준도·
용지도)이 **어느 모듈도 import 하지 않는 죽은 목록**이었음. 일곱 전부 실제 도면이 되면서
차례로 빠졌고 표준도가 마지막이었음(2026-09-09).

남겨 두면 「계획평면도가 빈 도각으로 열리나?」로 읽히는 덫임.

확인 — 실제 파일로 도면 목록을 만들어 봄(프로젝트 936be972)
  도면 36장 · kind 별 longitudinal 3 · cross 20 · plan 3 · plan_lidar 1 · landuse 1 ·
  cover 1 · cross_standard 1 · mass_haul 1 · watershed 1 · **standard 4**
  **blank 0** — 빈-도각 경로를 타는 도면이 하나도 없음.
  표준도 넉 장 제목에 판정된 기울기가 뜸(메 1:0.35 · 찰 1:0.3).

`build_blank_drawing` 자체는 남김 — 도각 표제란 시험이 쓰고, 다음에 또 「목록엔 있는데
아직 안 그리는」 도면이 생기면 그 함수가 쓰임.

자체검증 — 회귀 573 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 12 commits 2026-09-08 20:25:15 +09:00
`bond` 는 레지스트리에 이미 있는 칸인데 사유를 **조건 없이 붙이고** 있어, 메쌓기·찰쌓기를
고른 구조물에도 「메/찰 구분이 없어 못 고름」이 그대로 떴음.

⚠ 얻는 것은 **노무 품 갈래뿐**이고 재료 원단위는 13-6 [주]⑦ 때문에 여전히 안 섬 —
그래도 고치는 까닭은 **사유가 거짓이면 사유 칸 전체를 못 믿게 되기 때문**임.
재료 미확보 사유는 아직 참이라 그대로 둠.

시험 762 통과(새 1건 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
재생성이 `cross_sections` 행을 지우고 다시 쓰면 `data.design` 에 면적 4키만 남는다.
`get_cross_section_designs` 는 `ground_type` 있는 줄만 담으므로 그 상태는 「설계 없음」이고,
B08 토적표가 통째로 0 이 됐다(창 셋에서 같은 증상).

원인은 결함이 아니라 분담이었다 — 체인은 재생성 뒤 [확정]을 불러 그 자리를 채웠고,
재생성만 따로 도는 길에는 그 단계가 없었다. 그래서 [확정] 없이도 정본이 서게 한다.

- [저장]이 확정과 **같은 조회**(`get_cross_sections_missing_design_chainages`)로
  빈 측점을 골라 기본 설계로 채운다.
- ⚠ **값이 있는 행은 안 건드린다** — 사용자 조작값·이월분이 거기 있다. 시험으로 잠금.
- 실측(route 184): 저장 뒤 DB 설계 62행·38키 복구, 층따기 13,696.8 ㎡,
  측구 토사 0.173 / 암 8.886 ㎡ — 파일 기반 값과 일치.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B07 409 는 워크플로 단계가 아니라 **종단 레코드 상태**(`longitudinal_sections.status`)를
보는 가드라 `dev/unlock` 으로 안 풀렸음. 읽는 쪽만 우회함.

지킨 것 넷
  1. **문은 서버가 막음** — 화면 표시로 여는 것이 아님. 운영에서는 그대로 409
     (`is_dev_environment()` 가 거짓이면 우회가 아예 없음).
  2. **표식이 실제로 있을 때만 엶** — 개발환경이라고 무조건 열지 않음. `dev/unlock` 이
     4단계를 풀어 둔 프로젝트만. 그래야 되돌리기(DELETE)로 다시 닫힘.
  3. **레코드는 안 건드림** — `status` 는 `DRAFT` 그대로. 상태를 올리면 그것이 곧
     「확정 흉내」라 `common_util_dev_unlock` 이 스스로 금지한 자리와 같아짐.
  4. **열렸다는 것이 화면에 뜸** — 좌측 목록 머리 아래 「확정을 건너뛴 상태입니다 —
     개발 전용. 값이 비어 보일 수 있습니다.」 조용히 열면 다음 사람이 헤맴.

실화면 확인 (프로젝트 936be972)
  목록 200 · `dev_bypass: true` · 도면 34장 · 안내 문구 뜸
  표준도 4장 제목에 판정된 기울기 — 「표준도 2장 (돌쌓기(메) H=2 **1:0.35** 뒷길이 35㎝
  야면석·호박돌)」 · 찰은 1:0.3

자체검증 — 회귀 573 통과 · 0 실패, `tsc --noEmit` 0, prettier 는 바꾼 파일만.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-08 20:41:53 +09:00
`phase: "detail"` 칸(돌 종류·조달·뒷길이·전면 기울기)을 **그리는 화면이 없었음**
(2026-09-09 실측: B06 구조물 폼은 b05 phase 열 칸만 그림. 화면 글자 전수에서 「조달」·
「뒷길이」·「돌 종류」 0건). 그 자리를 표준도가 맡음 — PLAN 4-5b 「표준도는 입력 화면이기도 함」.
B06 은 「어디에·몇 m」(배치), 표준도는 「어떤 제원」.

**장 하나 = 제원 조합 하나**라 한 번 고치면 그 조합의 개소 전부에 걸림.

지킨 것
  · **자동값을 저장에 박지 않음** — 빈 칸이 「정한 적 없음」의 뜻(확정 ⑨). 비우면 그 키를
    지움. 판정된 기울기는 칸이 아니라 **회색 도움말**로만 비춤.
  · **막지 않음** — 실무 도면에 1:0.7·1:0.8 이 실재(구조물도 53장). 품셈 범위(0.20~0.50)
    밖이어도 값은 받고 안내만.
  · **값을 여기서 셈하지 않음** — 정본에 적기만 하고 표·그림은 다음 조회에서 그 정본으로
    다시 섬. 표준도가 두 번째 정본이 되면 안 됨.

⚠ 만들다 잡은 것 셋
  ① `face_slope_ratio` 가 **구조물 등록부에 없어** 저장이 통째로 거절됐음
     (`ValueError: 돌쌓기(찰)에 정의되지 않은 옵션입니다`). 한 칸 때문에 전부 못 저장되는
     것은 나쁨 — 등록부에 없는 칸은 **빼고 이름으로 알림**(조용히 버리면 저장된 줄 앎).
     그 칸 신설은 랩탑 메인 몫.
  ② 저장 뒤 표·그림을 다시 받으면서 **폼이 새로 그려져 안내가 지워졌음.** 밖에서 들고
     있다가 다시 넣음.
  ③ **장 제목에 제원이 들어 있는데 좌측 단추 글자가 안 따라왔음.** 목록을 통째로 다시
     받지 않고 표준도 줄만 갈아 끼움.

실화면 확인 (프로젝트 936be972, 개발 우회로로 열어서)
  「표준도 2장」에서 돌 종류 견치돌·뒷길이 55 로 저장 →
    단추 글자가 「…뒷길이 35㎝ 야면석·호박돌」 → 「…뒷길이 55㎝ 견치돌」로 **즉시 바뀜**
  기울기 0.7 저장 → 안내 셋: 「1개소에 반영했습니다」 · 「1:0.7 는 품셈 표준경사 표
    범위(1:0.2~1:0.5) 밖입니다 — 값은 그대로 씁니다」 · 「「전면 기울기」 칸이 masonry_dry
    등록부에 아직 없어 저장하지 못했습니다」
  조달 「구입」 저장 → 그 장의 **2개소에만** 들어가고 다른 장은 그대로(정본 실측)
  확인 뒤 **지정받은 제원으로 되돌리고 우회로도 닫음**(목록 409 복귀).

700줄 제한으로 표준도 라우터를 `B07_DesignDetail_Router_Standard.py` 로 뗌(579 + 153).

자체검증 — 새 시험 7건 + 회귀 580 통과 · 0 실패, `tsc --noEmit` 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 11 commits 2026-09-08 20:47:34 +09:00
사용자 확정 ⑨(2026-09-09) 「품셈 표준경사 표대로 자동 + 사용자가 바꿀 수 있게」.
지금은 칸이 없어 코드가 늘 0.3 으로 돌아 찰 H=2.5 와 메 H=2.0 이 같은 값으로 나왔다.

- `face_slope_ratio`(1:n 의 n) — 돌쌓기(찰·메)·큰돌쌓기·골막이·바닥막이·기슭막이 여섯.
- ⚠ **기본값 없음(빈 값)** — 빈 값이 「자동 판정」의 뜻이다. 기본값을 박으면
  「정한 적 없음」과 「그 값으로 정함」이 구별되지 않는다. 읽는 쪽이
  「비어 있으면 표대로 자동, 값이 있으면 그 값」으로 가른다.
- 그래서 「기본값 없으면 필수」 정책의 예외로 두고, 까닭을 시험 주석에 남김.
- 엔진이 읽는 이름과 글자까지 대조(`B08_Quantity_Engine_UnitQuantity` 의
  `options.get("face_slope_ratio")`), 저장 왕복도 실제로 확인(PUT 200 → 0.5 되읽음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
품셈 표준경사 표가 높이 × 메/찰 × **성토/절토** 로 갈리는데 성절토만 없었다.
새 입력을 만들지 않고 이미 저장되는 두 값으로 가린다 —
`design.section_mode` + 구조물 `options.side`.

- `common_util_structure_face_role.structure_face_role()` — ("성토"|"절토"|None, 까닭 문구).
  ⚠ 못 가르면 **None**. 성토로 눅이지 않는다 — 받는 쪽이 근거 없음을 알아야 한다.
  예외 하나: `both_cut` + 「자동(성토 쪽)」은 세울 성토면이 없어 근거 없음.
  판정을 두 벌로 짜면 그 예외에서 갈리므로 여기 하나만 둔다(CLAUDE.md 5장).
  파이썬 단독 — 읽는 쪽이 B08 뿐이다. 화면이 쓰게 되면 그때 TS 짝·거울 시험을 붙일 것.
- 전면 기울기 칸: 표 범위(0.20~0.50) 밖이면 **막지 않고 알리기만** 한다.
  실무 도면이 S0.7·S0.8 을 쓴다 — 막으면 실물이 안 들어간다.

시험 14건(네 단면유형 × 좌/우 여덟 · 자동 셋 · 모르는 값 · 옛 영문 표기 · 문구).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
앞서 「성토 열로 잠정」 딱지를 달아 두었던 자리를 채움. 랩탑 메인이 낸 공용 함수
`common_util_structure_face_role(section_mode, side)` 를 **그대로** 부름 —
판정을 두 벌로 짜면 `both_cut` + 「자동」 예외에서 갈리므로 우리 쪽에 다시 안 짬.

- 새 저장 키 없음 — 이미 저장되는 `design.section_mode` 와 구조물 `options.side` 만 씀.
  라우터가 측점별 단면유형을 모아 넘기고, 구조물은 **가장 가까운 측점** 값을 씀.
- ⚠ 못 가르면 `None` 을 **성토로 눅이지 않음** — 종전값 1:0.3 으로 서되 **왜 못 갈랐는지**를
  근거 줄에 적음. 임의값이 금액으로 굳으면 안 됨.
- 근거 줄에 판정 문구가 그대로 실림 — 「… 1:0.35 · right_cut · 자동(성토 쪽) → 성토면」.

곁들여 — 전면 기울기 칸이 레지스트리에 생겨(`ebdf2988`) 「아직 칸이 없음」 문구와
없는-키 목록에서 뺌. ⚠ 표 밖 값(실무 도면의 S0.7·0.8)은 **막지 않고 그대로** 씀 —
접으면 사용자가 넣은 값이 조용히 다른 값이 됨. 시험으로 잠금.

검증 프로젝트 실측 — 62측점 전부 `right_cut`, 돌쌓기 「자동(성토 쪽)」 → 성토면.
잠정으로 쓰던 열과 **결과는 같고 근거가 값에 생김**. 돌쌓기(메) 21.190㎡(1:0.35) 유지.

시험 747 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 3 commits 2026-09-08 21:01:57 +09:00
기울기 판정이 `section_mode` 를 받아야 도는데, 그 표를 만드는 코드가 B08 라우터 안에만
있었음. B07 표준도는 `build_table` 을 직접 부르면서 그 인자를 못 줘 **늘 「가를 근거 없음」**
으로 떨어졌음(랩탑 보조 실측).

⇒ `section_modes_from_designs(designs)` 를 엔진에 두어 **부르는 쪽마다 다시 짜지 않게** 함.
B07 은 저장된 횡단 설계 목록을 이 함수에 넣어 `build_table(..., section_modes=…)` 로 주면 됨.

⚠ 동작은 그대로 — `section_mode` 가 없는 측점은 담지 않고, 못 가르면 여전히
「가를 근거 없음 + 종전값 1:0.3」으로 섬(성토로 눅이지 않음).

내 프로젝트 실측 유지 — 돌쌓기(메) H=2.0 **1:0.35 · 21.190㎡**,
근거 「… right_cut · 자동(성토 쪽) → 성토면」.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표준도가 `build_table` 을 직접 부르면서 `section_modes` 를 안 넘겨, 성절토를 가를 근거가
없다며 **전 구조물이 종전값 1:0.3** 으로 섰음. 값이 없는 게 아니라 **안 넘긴 것**이었음.

`section_modes_from_designs` 한 벌을 그대로 씀(부르는 쪽마다 다시 짜면 B08 과 갈림).
노선은 `get_workflow_route_context` 로 찾고, 못 찾으면 빈 표 — 성토로 눅이지 않음.

⚠ 고치고 나니 **제목·그림이 표와 갈렸음** — 표는 판정된 1:0.35, 제목은 다시 판정하며
근거를 못 받아 1:0.3. 실측으로 잡았음. 그래서 **표를 만든 그 판정을 시트에 실어**
제목·그림이 같은 값을 쓰게 함(`face`·`face_reason`). 자리를 고르는 것도 B08 이 쓰는
`_section_mode_at` 과 판정 한 벌 `structure_face_role` 을 그대로 부름.

실측 (프로젝트 936be972) — 제목과 표가 **같은 값**
```
큰돌쌓기  H=2.5  제목 1:0.3   표 0.3    면적 2.6101
돌쌓기(메) H=2.0  제목 1:0.35  표 0.35   면적 2.1190   ← 메쌓기가 갈림
돌쌓기(찰) H=2.5  제목 1:0.3   표 0.3    면적 2.6101
옹벽      H=2.0  기울기 없음(판정 대상 아님)
```
표 산출근거에 판정 경로가 그대로 뜸 — 「품셈 13-4-4 [주]⑪ 표준경사 · 메쌓기 성토 ·
직고 2m ≤3m → 1:0.35 · right_cut · 자동(성토 쪽) → 성토면」.

앞서 `face_slope_ratio({}, wet=…)` 로 확인한 「근거 없음」은 `face` 를 안 준 호출이라
**정상 동작**이었음 — 함수가 성토로 안 눅이게 짠 결과.

자체검증 — 회귀 580 통과 · 0 실패. 세 라우터 모두 700줄 안(588 · 190 · 692).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 8 commits 2026-09-08 21:44:41 +09:00
 사용자 확정 2차 ① — 「㎡ 유지. 부피는 **사용자가 지정한 길이값을 곱해** 쓴다」.
그러면 품셈 ㎥ 단가를 그대로 쓸 수 있어 **단위 불일치가 풀림**(2,124만원 자리).

- 설정 `quantity.bench_cut_depth_m` 신설. [저장]으로도 넣을 수 있게 요청 모양에 칸을 두고,
  「안 정함」으로 되돌릴 수 있게 nullable 목록에도 넣음.
- 인계 줄: 길이가 있으면 **면적 × 길이 = ㎥** 로 내고, 규격 칸에 「면적 13,696.75㎡ ×
  길이 0.5m」로 **어디서 온 값인지** 남김.
- ⚠ **면적을 없애지 않음** — 횡단도 하단 표가 면적을 씀. ㎥ 를 덧붙이는 것.
- ⚠ **길이 기본값을 임의로 박지 않음** — 없으면 종전처럼 막고 사유를 냄
  (교본 「층따기 높이·폭은 **설계도서에 명시**」라 설계 입력임).
- 매핑 밑수를 ㎥ 로 되돌리고 그 까닭을 적음(공식이 체적 기준).

실측 — 길이 0.5m 를 넣으면 13,696.75㎡ → **6,848.375㎥** 로 서고 in_bill True.
안 넣으면 0 · input_missing · 「길이를 넣으면 면적 × 길이로 물량이 섭니다」.

시험 748 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 ④ 「터파기를 횡단도에서 표현 → 노티스 → 사용자가 선택」의 밑감.
근거의 급이 달라 갈라 둔다.

- 관: `KCS 44 40 10 배수관 §3.2(4) 그림 3.2-1` 표 그대로(Ø800→1.6 · 1000→1.8 ·
  1200→2.1 · 1500→2.5 m). ⚠ 관경+2b 로 계산하지 않는다 — 표가 관 두께·여유를 담고 있다.
  표에 없는 관경은 `None` — 지어내지 않는다.
- 벽: 법정 근거 없음(교본은 「설계도서 지시」까지). 실무 정본 xls 7탭 식 —
  기초 0.5×0.9(기초버림이면 0.1×0.7) + H×(평균두께+0.2). ⚠ **비탈 없음(수직)**.
- 레지스트리에 「기초」 칸(기초유/기초버림) 신설 — 정본 탭 제목 그대로. 그림·물량이 같은 축.
- 파이썬·TS 짝 + 거울 시험. 실무 수치(H=1·2·3 → 1.48·2.51·3.54)와 맞는지도 잠금.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 상부 = 뒷길이(ℓ3) + 0.30 · 하부 = 상부 + 0.30 × (H − 1.0) · 평균이 두께
- 옛 식(0.45 + 0.10H / 0.45 + 0.40H)에는 뒷길이가 없어 35↔45 를 바꿔도
  돌 부피·막자갈·터파기가 같은 값으로 섰음
- H ≤ 1.0 은 (H−1) 몫을 0 으로 눅여 하부가 상부보다 얇아지지 않게 함
- 산출근거 문구에 식을 남김 — 막자갈·터파기 두 줄
- tmp/tests/test_b08_wall_thickness.py 신설(7건), 옛 두께를 못 박던
  test_b08_stone_kind.py 의 막자갈 밑값 15.130 → 12.630 정정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 2차 ③ — 기술문서 DB 를 먼저 뒤지고, 계수 원문이 없으면 실무 기준 + 노티스.

근거 (원문 확인분)
- 대한건설협회 임금적용요령 4-나 (재경원 회계45101-45, 1995.1.13): 공표 노임은
  **기본급여액**이며 제수당·상여금·퇴직급여충당금은 예정가격작성기준에 따라 별도 계상
- 기재부 「(계약예규) 정부 입찰·계약 집행기준」 제76조의3(노무비의 계상):
  노임 + 제수당 + 상여금(연 400% 한도) + 퇴직급여충당금
- 품셈 8-1-2 5.6호가 운전사 노임을 그 예규로 넘김

미확인 (노티스로 드러냄)
- 예규 원문 자체는 저장소에 없음 — 위 둘은 인용 문서
- 16/12 는 상여 연 400% 와 산술이 일치하나 25/20 은 원문 근거 못 찾음
- 실물 셋이 같은 계수 사용: 실무 두 공사지·임도교본 예제·다산 ESTX 기준계수 0.20833

구현
- `OPERATOR_ALLOWANCE_FACTOR` = 16/12 × 25/20, 근거·한계 주석을 이 한 곳에 모음
- 나눗수 8시간은 그대로 두고 **곱셈으로만** 적용 — 나눗수를 줄이면 작업효율을
  시간당 사용료에 넣은 것이 되어 ㉣ 위반. 검사(`check_operator_hours_basis`)에도
  계수를 넘겨 곱셈 자리를 드러냄
- 일위대가 조종원 줄·A10 인건비·중기 탭 노티스를 같은 문구로 맞춤

검증 (79da822d 기준)
- 굴착기 0.7  86,096.4 → 109,704.5 (+27.4%) · 불도저 19t 124,842.3 → 148,450.4 (+18.9%)
- 조종원 수량 0.20833 = 다산 ESTX 기준계수와 일치
- 실무 시트 재현: 267,360 ÷ 8 × 계수 = 55,700 (시트 값과 일원까지 일치)
- 본체 11,356,910 → 12,141,903 (+784,993, +6.9%)
- pytest 267 통과 · tsc 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 ④ 「터파기가 횡단도에서 표현이 안 된다 → 교본·실무문서로 구현 →
노티스 → 사용자가 선택」.

- 관: 관 위에서 관 바닥까지 **표값 폭**으로 수직(KCS 44 40 10 그림 3.2-1).
  표에 없는 관경이면 **안 그린다** — 폭을 지어내지 않는다.
- 벽: 벽 바닥선 아래로 **수직**(정본 식에 기울기 항 없음). 폭 = 바닥폭 + 여유 0.2,
  깊이 = 기초유 0.5 / 기초버림 0.1.
- ⚠ `foundation` 이 비어 있으면 **안 그린다** — 고르기 전에는 근거가 없다.
- 말풍선에 **근거의 급을 갈라** 적는다: 관은 「법정 표」, 벽은 「품셈에 규정이 없어
  실무 관행으로 정한 값」.
- 파선(`.b06-chart__excavation`)으로 구조물보다 먼저 그려 벽 밑에 깔린다.

화면 확인: 관 터파기 5개소, Φ1000 → 1.80m · Φ800 → 1.60m (표값 그대로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**기초 칸**(`foundation` — 기초유 / 기초버림, 정본 xls 탭 제목 그대로)
터파기 기초 몫이 0.5×(0.7+0.2)=0.45 대 0.1×(0.7+0.0)=0.07 ㎥/m 로 갈리고, 횡단도
터파기 선도 같은 칸을 봄. 고를 자리가 어디에도 없어 비어 있던 값임.
정본에 없는 갈래를 넣으면 **막지 않고 알림**(기존 네 칸과 같은 결). 비우면 키를 지움.

**그림을 새 두께 식에 맞춤** — 데스크탑 메인이 `STONE_MASONRY` 를 갈면서
`thickness_base_m`·`thickness_top_coeff`·`thickness_bottom_coeff` 가 사라져
그림이 `KeyError` 로 죽었음(도면이 「읽지 못했습니다」로 뜸). 실화면에서 잡았음.
  상부 = 뒷길이 + 0.30 · 하부 = 상부 + 0.30 × (H − 1.0)
  H=1.0 ℓ45 → 0.75/0.75 · H=1.5 ℓ35 → 0.65/0.80 · H=2.0 ℓ35 → 0.65/0.95 ·
  H=2.0 ℓ45 → 0.75/1.05 · H=3.0 ℓ45 → 0.75/1.35   ← 실무 원본과 전부 일치

⚠ **뒷길이를 안 정한 장은 두께를 못 내므로 그리지 않음** — 0 으로 때우면 거짓 그림이 됨.

⚠ 배운 것 — 「그림이 상수를 직접 읽으니 저절로 따라온다」가 **키 이름이 바뀌면 깨진다**는
   것으로 드러남. 값은 한 벌이 맞으나 **이름이 바뀌는 것은 예고가 필요함.**

실화면 확인 — 「표준도 3장」에서 기초 「기초유」 저장 → 「2개소에 반영했습니다」,
정본 실측 `[기초유, null, 기초유, null, null]`(그 장의 두 개소에만).

자체검증 — 새 시험 3건 + 회귀 583 통과 · 0 실패, `tsc --noEmit` 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 9 commits 2026-09-08 21:58:38 +09:00
- 터파기·되메우기·잔토를 `common_util_excavation.wall_trench_area_m2` 한 벌로
  옮김(화면 B06 과 짝인 TS 가 같은 값을 냄) — 돌쌓기·큰돌쌓기 공용 `_trench_components`
- `options.foundation` 「기초유」 = 기초분 0.45㎥/m · 「기초버림」 = 0.07㎥/m
- 안 고른 프로젝트는 비탈분만 세우고 사유를 냄 — 한쪽으로 찍으면 0.45 가 임의로 굳음
- 되메우기 = (기초깊이 + H) × 0.2 × 연장 · 잔토 = 터파기 − 되메우기
- 터파기 여유폭·되메우기 두께 상수를 엔진에서 지우고 공용 모듈을 가리키게 함
- tmp/tests/test_b08_wall_trench.py 신설(7건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 입적 = 정면적 × 평균두께 · 단위 ㎥ · destination `reference`
- 값을 새로 내는 것이 아니라 이미 쓰던 밑수를 화면에 드러내는 줄
- 자재총괄·토공·일위대가 어디에도 안 섞임
- 「석적」은 정본에 없어(소광리 시트에만) 내지 않음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 확정 ⑪ 「기준 구조물에서 유도 — 기슭막이면 하단 길이」 ⇒ 벽에서 하단 길이 = 하부 두께
- 버림 콘크리트 폭이 옛 잠정(터파기 폭 = 평균두께 + 0.2)에서 하부 두께로 바뀜
  (H2.5·45 → 1.175 → 1.20㎥ / H1.5·45 → 1.025 → 0.90㎥ / 10m 기준)
- 큰돌쌓기는 직경 위끝을 하단 길이로 준용
- ⚠ 기초잡석(12-25)은 폭이 생겨도 **두께가 원문에 없어** 물량을 안 세우고 사유를 냄
  (실무 관측은 관보호공 날개벽 T=0.2 하나뿐 — 다른 구조물 값을 옮겨 쓰지 않음)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- `pipe.revet_foundation`(기슭막이 기초) 신설 — **유입·유출 한 칸**. 한 공사에서 한쪽만
  기초유로 하는 일이 드물어 폼을 둘로 안 늘렸다. 실무가 갈라 쓰면 그때 나눌 것.
- 독립 기슭막이·돌쌓기 갈래도 이음: 구조물 정본 `foundation` → `RevetmentSpec` →
  `RevetmentLayout.foundation` → 터파기 그림. ⚠ 이름을 저장 칸과 **같은 글자**로 뒀다.
- ⑨ `stone_coeff_basis`(품셈/실무 관행) · ⑩ `fill_concrete_mpa`(180/210) 칸 신설.
  ⚠ **기본값 없음** — 「비어 있음 = 아직 안 정함」이고 기본값(⑨ 품셈 · ⑩ 210)은 계산 쪽이 갖는다.
- 저장 왕복 확인: PUT 200 → 되읽기에서 "실무 관행"·"180"·"기초유" 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⑤ 돌 중량 — 지식DB 전수 확인 결과 품셈·교본에 돌중량표 없음. 값(0.88 계열)은
   그대로 두고 출처(울진 소광 원단위 라이브러리)를 산출근거·source 에 남김
⑨ `stone_coeff_basis` — 빈 값이면 품셈 열(야면석 0.11·0.15)이 기본, 「실무 관행」이면
   건설품셈 참고자료 열(0.15·0.20)로 덮이고 그 사실이 사유로 뜸
⑩ `fill_concrete_mpa` — 빈 값이면 210, 180 을 고르면 그 값이 이김. 아는 값이 아니면
   기본으로 서되 사유에 저장값을 적음
- Component 에 `spec` 칸 추가 — 같은 이름이라도 단가가 갈리는 값을 받는 쪽에 넘김
- 기본값은 등록부가 아니라 계산 쪽이 가짐(등록부 default 는 비어 있음 = 「안 정함」)
- tmp/tests/test_b08_coeff_and_strength.py 신설(6건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⑨ `stone_coeff_basis`(품셈 / 실무 관행) · ⑩ `fill_concrete_mpa`(180 / 210) 를 폼에 붙임.
둘 다 **빈 값이 기본**(품셈 열 · 210) — 값을 미리 적어 두면 「안 정함」이 사라짐.
없는 갈래는 막지 않고 알림. ⇒ 칸 일곱: 돌 종류 · 조달 · 뒷길이 · 기초 · 전면 기울기 ·
야면석 계수 · 채움 강도.

⚠ **그림이 또 죽어 있었음** — `STONE_MASONRY["excavation_extra_m"]` 이 사라져 `KeyError`.
터파기 수가 `common_util_excavation` 으로 옮겨 갔음(내가 정본 xls 에서 낸 값들).
그림도 **그 한 벌**을 읽게 바꿈 — 횡단도와 같은 상수라야 두 도면이 같은 터파기를 그림.
```
WALL_TRENCH_CLEARANCE_M 0.2 · WALL_FOUNDATION_WIDTH_M 0.9 · WALL_FOUNDATION_DEPTH_M 0.5
WALL_BLINDING_WIDTH_M 0.7 · WALL_BLINDING_DEPTH_M 0.1
```
그림에 **기초 칸을 그림** — 「기초유」 0.9×0.5 · 「기초버림」 0.7×0.1.
**안 정한 장은 기초를 안 그림**(지어내지 않음).

⚠ 오늘 두 번째임 — 공용 상수 **이름이 바뀌면 그림이 죽음**. 값이 한 벌인 것과 별개로
이름 변경은 서로 알려야 함.

실화면 확인 — 칸 일곱이 다 서고, 야면석 계수 「실무 관행」·채움 강도 「180」 저장 →
「2개소에 반영했습니다」, 정본에 그 장의 두 개소만 들어감.

자체검증 — 새 시험 3건 + 회귀 586 통과 · 0 실패, `tsc --noEmit` 0.
⚠ 병합 여파로 깨진 등록부 규정 시험을 고침 — 「빈 칸이 곧 기본」인 칸 셋
(`face_slope_ratio`·`stone_coeff_basis`·`fill_concrete_mpa`)을 규정에서 뺌.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 15 commits 2026-09-09 08:26:09 +09:00
값 한 칸에 세로축 값이 공백으로 뭉쳐 든 표를 행-자원으로도 열-자원으로도 못 읽어
두 표가 한 줄도 안 서고 있었음.

- 11-1 콘테이너형 가설건축물 F0325: 0 → 40 줄 (길이 4 × 폭 5 × 직종 2)
  `reference` 로 찍혀 형태 필터에 걸려 버려지고 있었음
- 13-5-1 돌붙임(인력) F0416: 0 → 80 줄 (메·찰 × 돌 3종 × 뒷길이 7 × 직종 2)
  「뭉친 자원 줄의 이름을 못 풀었습니다」로 버려지고 있었음

읽는 법 — 맨 아랫줄이 값, 그 위가 자원 이름, 더 위가 묶음 이름. 칸 수와 숫자 개수가
딱 나뉘지 않으면 한 줄도 세우지 않고 unmatched 로 보냄.

짓다 잡은 함정 넷
- 꼬리의 「비고」 칸(「H=2.6M 기준 …」)을 값으로 세면 표 전체를 못 읽음 — 꼬리만 떼어 냄
- 자원 줄에 줄머리가 있는 표와 없는 표가 섞여 있음 — 무조건 앞칸을 버리면 자원 하나가
  통째로 사라짐(11-1 이 7 대 8 로 어긋났음). 있는 그대로 세고 안 맞으면 앞칸을 떼어 봄
- 묶음 줄은 반대로 앞칸(축 이름)을 먼저 떼야 함 — 안 떼면 「구 분」이 묶음으로 서서
  메·찰이 통째로 사라짐
- 「구 분」·「종 별」은 자간을 벌린 한 낱말임 — 축 둘로 읽으면 갈래가 「구 메 붙 임」이 됨
- 「-」 는 그 규격이 없다는 뜻 — 0 으로 세우면 공짜 공종이 됨(야면석 70㎝ 넷)

가로채기 방지 — 값줄 위가 단위 줄인 4축 표(10-6-3)는 자원 이름이 하나도 안 풀리므로
내 표가 아니라고 보고 손대지 않음. 전체 대조로 늘어난 표가 F0325·F0416 둘뿐이고
줄이 줄어든 표는 없음을 시험으로 못 박음.

검증: 자원 축 419 → 539 줄 · 일위대가 갈래 60개 신설 · pytest 272 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「구조물을 놓아도 횡단도에 아무것도 안 보인다」가 창 둘에서 같은 증상이었다.
화면에 표식을 심어 재 보니 **브라우저 쪽 단면에 `revetment` 자체가 없었다**.

- 원인: `withDraftWalls` 가 미저장 초안 목록이 **빈 배열**일 때도 「초안 있음」으로 읽고
  **서버 저장분(`revetment`)을 통째로 지운 뒤** 아무것도 안 얹었다.
  ⇒ `!drafts || !drafts.length` 로 고쳤다 — 빈 목록도 「초안 없음」이다.
- 초안 경로가 `foundation` 을 안 실어 터파기가 안 그려지던 것도 함께 고침
  (`WallSpec.foundation` 추가, 거울 시험도 같이 갱신).
- 겹침 방지 가드를 **좁혔다** — 링크가 있기만 하면 막던 것을, 그 링크의 벽이
  **이 카드에 실제로 설 때만** 막게 했다(`culvertWallsStandAt`). 관이 아홉·열하나인
  노선에서는 링크가 거의 모든 측점을 덮어 독립 벽 경로가 통째로 죽어 있었다.

화면 확인: 벽 터파기 「기초유 · 폭 1.62m · 깊이 0.50m (수직)」, 관 터파기 Φ1000 1.80m ·
Φ800 1.60m, 그려진 선 전부 좌우 변이 수직.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 구조물 전개가 destination `earthwork` 로 내던 셋을 아무도 받지 않아 내역서에
  한 줄도 안 나갔음(두께 식·기초 몫을 맞춰도 금액 0원). 실무 토적집계에는 서는 줄
  (울진 대흥 1공구 D12~D14 구조물터파기 토사 1,248/암 30 · 되메우기 739㎥)
- 새 파일 `Engine_Handoff_Trench.py` — 700줄 제한 탓에 Rows 에 안 넣음
- 구조물터파기: 심도(직고 + 기초 깊이)로 갈라 냄. 토질·용수 칸이 없어 품셈 9-13 의
  18구분 중 하나를 못 골라 상위 코드 + `input_missing` 사유로 둠
- 되메우기: FP-09-14-01 로 붙어 금액이 섬
- 잔토처리: 사토로 갈 몫이라 in_bill=False, ⚠ 그 통로가 아직 없다는 사실을 사유에 적음
- 매핑에 구조물터파기 줄 추가(FP-09-13 · 원문 L5022~5241)
- tmp/tests/test_b08_structure_trench_rows.py 신설(6건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 우리 갈래는 「리핑암」인데 일위대가는 「파쇄암」으로 서 있어 도자 운반 금액이
  이름만 못 이어 안 붙던 자리(≒30만원)
- 근거: 품셈 10-11 f 표 「파쇄암 1/1.35」 = 10-12 [주]③ 환산계수 「암절취 1.35」
- ⚠ 갈래 이름 자체는 안 바꿈 — 흙깎기(FP-09-04)가 「리핑암」으로 서 있음
- 매핑에 `ground_aliases` 절 신설, 인계본에 `ground_class_aliases` 로 실음
- tmp/tests/test_b08_ground_alias.py 신설(4건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실무 정본이 근거임 — `구조물도/기슭막이/04.구조도(기슭막이).xls` 탭 제목이
「돌기슭막이(H=2.0m, **찰쌓기**, 기초유)」이고 그 안의 계산이 돌쌓기와 **같은 식**임.
⇒ 기슭막이는 새 식이 아니라 **「형태가 돌쌓기면 돌쌓기 식」**. 여기서 다시 짜면
같은 계산이 두 벌이 되어 돌쌓기와 갈림(CLAUDE.md 5장).

형태별 갈래
  돌쌓기(찰) → `stone_masonry(..., wet=True)`    12줄
  돌쌓기(메) → `stone_masonry(..., wet=False)`   11줄
  콘크리트 · 돌망태 · 통나무/목재틀 · 바자 → **식 없음 + 왜 없는지 한 줄**
     콘크리트   돌쌓기(13-4)가 아니라 콘크리트 구조물 — 벽 두께·저판이 정본에 없음
     돌망태     품셈 13-8, 규격 축이 망태 치수라 돌쌓기 표를 못 씀 — 원단위 미확보
     통나무틀   품셈 13-13, 밑수가 ㎥당 목공 품 — 각재·판재가 카탈로그에 없음
     바자       바자얽기(5-15) 별도 일위대가로 잇기로 확정(2026-09-09 ⑧-4)
  형태 미정 → 「형태를 골라야 물량이 섭니다」

⚠ **뒷길이·돌 종류 칸이 기슭막이 등록부에 없음** — 돌쌓기 식은 그 둘로 계수가 갈리는데
없으면 `_back_length` 가 **조용히 45㎝ 로 돎**. 값이 나오므로 아무도 못 알아채는 자리라
**「돌쌓기 기본값으로 섰음」을 줄로 드러냄.** 칸 신설은 등록부 담당 창 몫.

⚠ 확정 대기가 남은 자리(막자갈 식 · 돌 중량 · 체적/석적 줄)는 **지금 값 그대로** 둠 —
`stone_masonry` 를 부르므로 그쪽이 갈리면 기슭막이도 같이 따라감.

자체검증 — 여섯 형태를 다 돌려 봄(찰 12줄 · 메 11줄 · 나머지 0줄 + 사유).
회귀 586 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠⚠ 조사 중 큰 것이 나옴 — **우리가 「틀렸다」고 버린 옛 두께식이 실은 「골막이 식」이었음.**
소광리 숨김탭 「골막이(찰)(치수조서연결)」 원문:
```
C26  평 균 두 께 = {( 0.45 + 0.1 × H ) + ( 0.45 + 0.4 × H )} ÷ 2
```
우리 옛 식과 글자까지 같음. ⇒ **실무는 구조물 종류마다 두께식이 다름.**
확정 ②(뒷길이 기반)는 **기슭막이에 맞고**, 골막이에는 이 식이 맞음.
⇒ 골막이에 `stone_masonry` 를 그대로 부르면 **틀어짐.** 그래서 안 부름.

골막이가 돌쌓기와 다른 자리 셋 (정본 실측)
  · 두께식 위와 같음
  · 밑수가 **「돌쌓기 + 돌붙임」** (19.62 + 2.625 = 22.245) — 기슭막이는 돌쌓기만
  · 단위가 **개소당** — 기슭막이는 m당
  · 정면적이 사다리꼴 ((상장+하장)÷2×높이) − 파형강관(0.4×0.4×3.14)
  ⚠ **상장·하장 칸이 등록부에 없어** 정면적을 못 냄 — 칸 신설이 선행

바닥막이는 형태가 **돌붙임**(품셈 13-5)이라 돌쌓기(13-4) 표를 못 씀. 밑수도 면적(㎡)이라
축이 다름 — 돌붙임 원단위 미확보.

⚠ **일부러 안 부름** — 돌 계열이라 `stone_masonry` 를 부르면 **값이 나오므로 아무 시험도
안 잡음.** 오늘 큰돌쌓기에서 같은 일이 있었음(직경 60~80㎝ 가 뒷길이 45㎝ 계수로 돌던 자리).

자체검증 — 골막이 0줄 + 사유 · 바닥막이 0줄 + 사유 · 기슭막이 13줄(그대로).
회귀 586 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-09 08:27:48 +09:00
「같은 돌쌓기니 한 함수로」가 되기 쉬운 자리라, 두 정본을 나란히 잰 결과를 코드에 남김.

다른 것 넷 (소광리 「골막이(찰)(치수조서연결)」 ↔ 「돌기슭막이」)
  두께식   골막이 (0.45+0.1H)/(0.45+0.4H)   ↔ 기슭막이 뒷길이 기반(ℓ3+0.30 …)
  밑수     골막이 **돌쌓기 + 돌붙임**        ↔ 기슭막이 돌쌓기만
  단위     골막이 **개소당**                ↔ 기슭막이 m당 (확정 ⑦ 「통일 안 함」)
  정면적   골막이 **사다리꼴**(상장·하장)    ↔ 기슭막이 직사각(H × 1)

같은 것 여섯 — 막자갈 2/3 · 야면석 0.88 ton/㎡ · 물구멍 2㎡/개소 · 기울기 몫 1.04 ·
고임돌 0.15 · 채움콘크리트 0.2. **우리 기본값이 어디서 왔는지의 답**이기도 함.

`STONE_MASONRY` 상수 머리에도 한 줄 — 「**기슭막이 계열 전용**. 골막이는 두께식이 다름
(정본 C26)」. 상수만 보고 가져다 쓰면 **값이 나오므로 아무 시험도 안 잡는** 자리임.

자체검증 — 회귀 586 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-09 08:36:57 +09:00
⚠ **정정** — 어제 「돌붙임 원단위 미확보」로 사유를 냈으나 **소광리 정본에 식이 셋 있었음.**
안 찾아본 것을 「없다」고 적은 자리였음. 53탭 전수에서 드러남.

붙인 원단위 (정본 「돌붙임L3=45(사방)」 · 「돌붙임L3=30(야면석메붙임)」)
```
돌붙임(찰)  두께 0.45 · 돌 30×30×45㎝ **0.918 ton/㎡**(= 0.45 × 0.77 × 2.65) ·
            고임돌 0.15 · 모르타르 0.009 · 채움 0.2 + **버림 0.1** · 터파기 0.45   8줄
돌붙임(메)  두께 0.30 · 야면석 20×20×30㎝ **0.42 ton/㎡**(원문 직접값) ·
            고임돌 0.07 · 터파기 0.30                                          5줄
            ⚠ 모르타르·채움·버림은 **줄 자체가 없음** — 0 으로 만들지 않고 뺌
```
밑수는 **면적(㎡)** — 등록부 `area_m2` 와 축이 그대로 맞음. **기울기 몫을 안 곱함**(평면).

⚠⚠ **돌쌓기 표(13-4)와 합치지 못하게 못 박음** — 값이 겹쳐 보여 합치고 싶어지는 자리:
```
돌쌓기(13-4)  밑수 비탈면적 · 뒷길이 일곱 규격 · 기울기 몫 √(1+n²)
돌붙임(13-5)  밑수 **평면적** · 뒷길이 **넷** · **기울기 몫 없음** · 메는 모르타르·채움 없음
⚠ 45㎝ 에서 고임돌 0.15·채움 0.20 이 **우연히 같음** — 합치면 25·30·60·75 에서 조용히 틀림
```

ⓘ **돌중량이 관측값이 아니라 유도값임** — `뒷길이 × 0.77(채움률) × 2.65(비중)`.
   두 원본에서 같은 모양이 나왔음. 다만 **야면석은 그 식이 안 맞아**(공극이 커 ㎥당 무게가
   다름) 원문 직접값 0.42 를 그대로 옮김. ⇒ 확정 ⑤ 가 「값 고르기」가 아니라
   **「채움률·비중 두 인자 정하기」**로 바뀔 수 있음 — 우리 0.88 은 안 건드렸음.

⚠ 뒷길이가 **붙박이**(찰 0.45 · 메 0.30) — 정본 탭이 그 둘뿐이고 등록부에 칸이 없음.
   그 사실을 줄로 냄. 칸이 생기면 표를 열면 됨.

자체검증 — 새 시험 5건(정본 값 대조 · 메는 세 줄이 빠지는지 · 기울기 몫 없음),
회귀 591 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-09 11:28:41 +09:00
소광리 정본 「개거(150-200) (2)」·「L형수로-(201)」 — **둘 다 m당**.

⚠⚠ **두 표가 담는 것이 다름.** 값이 비슷해 보여 합치고 싶어지는 자리라 못 박음:
```
콘크리트 개거 150×200   터파기 · 유로폼 · 면목  **세 줄뿐** — **콘크리트 본체 줄이 없음**
콘크리트 L형수로 H=0.2  터파기 · 되메우기 · 잔토 · **콘크리트** · PVC Φ50 · 이형철근 D13 ·
                       거푸집 · 면목  **여덟 줄**
ⓘ 같은 것 — 둘 다 m당이고 거푸집 계열(유로폼·거푸집)과 면목이 있음
```
⚠ 개거에 콘크리트가 없는 것은 **빠뜨린 것이 아니라 원문 그대로**임. 0 으로 때우거나
L형수로 값을 옮겨 채우지 않음 — 돌붙임(메)에서 세 줄을 안 만든 그 판단과 같음.
⚠ **PVC Φ50 은 줄만 있고 수량 칸이 빔** — 안 세우고 그 사실을 줄로 냄.

⚠ 규격이 **붙박이**(「콘크리트 개거 150×200」) — `open_ditch` 등록부에 **옵션이 하나도 없음**.
   `ditch_spec` 을 주면 L형수로로 갈림. 칸이 생기면 열면 됨.

**측구(`ditch_side`)는 안 건드림** — `design_owner: 횡단 설계` 라 B06 소관이고 `enabled: False`.
정본 「측구수로400/500」은 **「터파기 계산서」**라 터파기·잔토·되메우기 셋뿐임(본체 없음) —
그쪽이 쓸 때를 위해 적어 둠.

실전개 (연장 10m)
  개거   터파기 0.3㎥ · 유로폼 5.5㎡ · 면목 20m
  L형수로 터파기 3.1645 · 되메우기 1.2997 · 잔토 1.8647 · 콘크리트 1.508 ·
         이형철근 3.98㎏ · 거푸집 7.38㎡ · 면목 10m

자체검증 — 새 시험 5건(정본 값 대조 · 개거에 콘크리트가 없는지 · 잔토 = 터파기−되메우기 ·
빈 수량 줄 · 없는 규격), 회귀 596 통과 · 0 실패.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-09 11:32:54 +09:00
eomsangdon added 70 commits 2026-09-09 11:57:06 +09:00
- 실무 내역 셋에 「노체포설·노체다짐」으로 가른 줄이 없음 — 영월은 「암성토
  BACK-HOE(0.7㎥)」 한 줄이고 그 단가산출 안에 적사→성토→다짐 3단계가 들어감,
  울진은 「유용성토」·「사토 및 다짐공」, 봉화는 성토사면다짐만 따로
- ⇒ 성토 본체 한 줄(포설) + 성토면다짐(㎡) 따로가 실무 양식. 다짐은 그 단가 안 단계
- 매핑에 적어 둔 「내역 양식이 정해지면 내린다」 조건이 채워진 것

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 새 저장 칸을 만들지 않음. 측점마다 이미 있는 `design.ground_type`
  (soil·ripping_rock·blasting_rock)이 품셈 9-13 토질 3구분과 그대로 맞물림
- 판정 규칙: 구조물이 **걸친 측점 전부**를 보고 갈래가 하나일 때만 값을 냄.
  섞이면 다수결로 고르지 않고 갈래별 측점 수를 사유에 적음(암 단가가 몇 배라
  임의 선택이 금액으로 굳음). 걸친 측점이 없으면 가장 가까운 측점 + 그 사실을 근거에
- 터파기 줄이 토질·심도로 갈려 서고, 막힌 사유가 「용수 유무」 하나로 좁혀짐
- tmp/tests 2건 추가(측점값 반영·섞임 판정)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
데스크탑 메인이 구조물 터파기·되메우기·잔토를 인계에 실었는데, **잔토 126.625㎥ 가
어디에도 안 실렸다**. 사토로 실어 내는 몫이라 유토곡선이 세야 겹치지 않는다.

    구조물 잔토는 사토에 한 번만 더한다.
    B08 은 소요량(structure_spoil_m3, ㎥ 양수)을 내기만 하고,
    더하는 자리는 유토곡선의 사토뿐이다.

- ⚠ **잔량 하나하나를 늘린다** — 총량만 늘리면 사토는 늘고 운반이 안 는다(공제 때와 같은 자리).
- ⚠ 나누는 법: 지금은 총량 하나만 오므로 **남은 사토 잔량 크기에 비례**해 나눈다.
  한 곳에 몰면 운반거리가 틀린다. 측점별 값이 오면 이 함수만 고치면 된다.
- ⚠ 자연방토·지반유형 안분은 안 건드린다 — 실어 내는 흙이고, 어느 지반에서 나온지 모른다.
- `null`(아직 안 옴) ≠ `0`(없음), 받은 값과 **실제로 더한 값**을 따로 싣는다.

시험 5건(더해짐·잔량 동반 증가·자연방토 불변·토취 불변·공제와 함께 와도 한 번씩).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- `B08_Quantity_Engine_HaulInputs.haul_inputs(unit_table)` — 둘 다 양수 ㎥,
  빼고 더하는 것은 받는 쪽(B06) 몫
- ⚠ 측점별로도 냄(`structure_spoil_points`) — 총량만 주면 잔량 비례로 흩어져
  운반거리가 틀어짐. 구조물은 구간이라 가운데 측점을 자리로 봄
- ⚠ 「아직 안 옴(None)」과 「없음(0)」을 가름
- 라우터에 `project_haul_inputs(project_id)` + `GET .../quantity/haul-inputs`
  — B06 이 이 함수를 부르면 됨(같은 계산을 두 벌로 짜지 않게)
- tmp/tests/test_b08_haul_inputs.py 신설(5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
통로는 났는데 `_mass_haul_context()` 를 **인자 없이** 불러 값이 늘 `None` 이었다
(`Router_HaulPlan.py:64` · `Server_Calc_Prebuild.py:170`). 오늘 세 번째로 나온
「받는 곳은 있는데 넣는 곳이 없던」 자리다.

- `haul_inputs_for()` 로 B08 의 `project_haul_inputs` 를 받아 두 자리 모두에 넘긴다.
  ⚠ 여기서 다시 세지 않는다 — 두 값 다 B08 전개에서 나온다(CLAUDE.md 5장).
- 측점별 잔토(`structure_spoil_points`)를 받으면 **그 자리 잔량에 얹는다** —
  총량 비례로 흩으면 운반거리가 틀린다. 총량만 오면 종전대로 비례 분배(차선).
- 저장 payload 에 받은 값·실제로 먹은 값 넷을 남긴다 — 「값이 흐르는지」를 저장분에서
  바로 가릴 수 있어야 한다.

실측(route 184): 공제 0(구입이라 채집 없음) · 구조물 잔토 12.875㎥ 가 **실제로 전달됨**.
⚠ 그 노선은 사토가 0(전 구간 토취)이라 더할 잔량이 없어 `added=0` — 아래 물음 참조.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사토가 0 인 노선(전 구간 토취)에서는 잔토를 더할 자리가 없어 **물량이 그냥 사라졌다**.
파낸 흙은 어디로든 가므로 그것이 가장 나쁘다.

- 담을 사토 잔량이 없으면 **그 측점에 사토를 새로 세워** 담는다. 물량이 보존되고
  운반비가 붙는다(금액이 느는 방향 — 안전측).
- ⚠ 토취를 줄이는 길(㉯)은 「그 잔토를 성토재로 쓸 수 있다」는 근거가 있어야 한다.
  구조물 터파기 흙은 암이 섞일 수 있고 우리가 그 판정을 안 하므로, **근거 없이 금액을
  내리지 않는다.** 확정되면 이 함수 한 곳만 바꾸면 된다 — 그 문장을 주석에 남겼다.
- 새로 세운 사토는 자연방토 0 · 지반유형 안분 0 — 실어 내는 흙이고 지반을 모른다.
- 측점별 잔토를 Node 진입점까지 이어 붙임(빠져 있어 총량 갈래로 떨어지고 있었다).

실측(route 184): 사토 0 → **12.88㎥**, 잔량이 **측점 5m 자리에 섬**(전에는 노선 전체 구간).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 키가 (심도, 토질, 근거문구)라 같은 「암절취 · 심도 2~3m」이 측점 문구가 다르다는
  이유로 두 줄로 갈렸음(실화면 121.75 + 33.875)
- 키를 (심도, 토질)로 좁히고 근거 문구는 모아서 한 줄에 적음
- tmp/tests 1건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
두 창 저장분에서 **공제가 한 톨도 안 빠졌다**(`deducted 0`). 두 노선 다 원래 사토가 0
(전 구간 토취)이라, 공제가 잔토 가산보다 **먼저** 돌아 뺄 대상이 없었다.

- 유토곡선의 사토는 「현장에 남는 흙 총량」이고 출처를 안 가린다 — 공제는 그 총량에서
  빼는 것이라 **잔토가 담긴 뒤라야** 뺄 대상이 있다.
- ⚠ 모자라면 `collected_stone_deducted_m3` 가 작게 나와 「덜 뺐다」가 값으로 드러난다 —
  그 장치는 그대로 살려 뒀다.
- ⚠ 토취는 계속 안 건드린다. 「채집석을 캐 가면 성토에 쓸 흙이 줄어 토취가 는다」는
  갈래가 있으나 근거가 없다 — 그 여지를 주석에 적어 뒀다.

시험 7건(순서 시험 추가: 잔토 100 더한 뒤 공제 40 이 실제로 빠짐).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 운반 줄이 띠(bands)·이동(transfers)에서만 만들어져 사토는 잔량(residuals)으로 남아
  어디에도 안 실렸음. 그래서 구조물 잔토 126.63㎥ 를 얹어도 덤프가 안 늘었고,
  채집석 공제도 사토를 줄이는 값이라 끝까지 금액에 안 나타났음
- 실무에는 서는 줄(울진 대흥 1공구 토적집계 D32 사토 1,281㎥)
- 운반표에 `spoil`(물량·거리·근거)을 실어 인계가 「사토 운반」 한 줄을 세움
- 물량은 유토곡선 결과 그대로 — 공제·가산이 끝난 값이라 여기서 또 만지지 않음.
  자연방토는 실어 내지 않으므로 뺌
- 거리는 설계 입력 `spoil_site_distance_m` 신설 — 안 정했으면 막고 사유
  (품셈이 정하는 값이 아니라 임의 거리가 그대로 금액이 됨)
- 지반 갈래는 유토곡선이 안분하지 않아 갈래 없이 한 줄, 그 사실을 근거에
- tmp/tests/test_b08_spoil_haul.py 신설(6건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 이 사토 운반을 덤프 단가로 가르려면 토사/암 갈래가 필요하다. 잔량에는 이미
`ea/rr/br` 이 실려 있으나(절토에서 남은 흙이라 구성비를 안다), **구조물 잔토로 생긴
몫만은 근거가 없다**(어느 지반에서 파낸 흙인지 판정하지 않는다).

- `ground_unknown_m3 = volume − (ea+rr+br)` 을 잔량마다 함께 낸다.
- ⚠ 안 내면 받는 쪽이 **0 으로 눅여 토사로 세기 쉽다** — 그래서 값으로 드러낸다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 새 판정이 아니라 구조물터파기가 쓰는 그 값(`design.ground_type` 판정) 그대로 —
  그 터파기에서 나온 흙이 곧 이 잔토라 두 자리가 같은 판정을 씀
- 섞여서 못 고른 구조물은 「모름」(None)으로 보냄 — 터파기에서 다수결로 안 고른 규칙 그대로
- 한계도 그대로 넘어감(터파기 깊이가 암반 경계보다 깊은지는 안 봄) — 사유에 적음
- 받는 쪽(B06)이 사토 잔량 ea/rr/br 에 넣으면 「모르는 몫」이 사라짐
- tmp/tests 2건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 이 구조물터파기에서 이미 판정한 토질(`design.ground_type`, 품셈 9-13 3구분)을
잔토 측점값에 함께 실어 준다. **새 근거를 만드는 것이 아니라 이어받는 것**이라
두 자리가 같은 판정을 쓴다(두 벌로 짜면 갈린다).

- `structure_spoil_points[].ground_type` (soil→ea · ripping_rock→rr · blasting_rock→br).
  옛 이름(`ground`)·라벨(`ground_label`)도 함께 받는다.
- ⚠ **섞여서 못 고른 구조물은 `null`** 로 오고 그 몫은 갈래 없이 담겨
  `ground_unknown_m3` 로 드러난다 — 임의로 토사로 몰지 않는다.
- ⚠ 한계는 그대로 넘어온다: 「터파기 깊이가 암반 경계선보다 깊은지」는 안 본다
  (터파기 토질에 이미 있던 한계이고 새로 생기는 것이 아니다).

시험 8건(갈래별로 담김·못 고른 몫은 「모름」으로 남음 포함).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 유토곡선 잔량이 갈래별 물량(ea/rr/br)을 들고 오므로 갈래마다 한 줄로 세움
  (덤프 단가가 토사·암으로 갈려 합쳐 세우면 한쪽 단가로 다 물림)
- 갈래를 못 붙인 몫(ground_unknown_m3)은 따로 한 줄로 세우고 막음 — 토사로 눅이면
  임의 단가가 됨
- 갈래가 안 오는 옛 저장분에서는 종전처럼 한 줄
- tmp/tests 3건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
기초잡석(②)
- 두께 0.2m(사용자 확정). 폭은 버림 폭과 같아(KCS 34 50 05) **버림 × 두께 비**로 나옴
  ⇒ 관측 원단위로 오는 옹벽에도 값이 섬(버림 0.15㎥/m ⇒ 잡석 0.30㎥/m)
- destination `unit_price` — 운반·부설·다짐 품이 붙는 공종이라 자재총괄에 안 섞임
- 인계에 FP-12-25 줄로 섬. 묶음 구조물(옹벽)은 조각이 이미 세므로 건너뜀
- 두께는 설정 `rubble_base_thickness_m` 로 화면에서 바꿀 수 있음

용수 축(④)
- 품셈 9-13 의 18구분을 토질 × 육상/용수 × 심도로 골라 자식 코드로 내려감
- ⚠ 기본 「육상」은 **통상값이고 사용자 확정이 아님** — 그 사실을 줄 사유에 적음
- 3m 초과 칸은 원문에 없어 상위 코드 + 사유

- 설정 신설: rubble_base_thickness_m(0.2) · structure_trench_water(육상)
- tmp/tests 신설 test_b08_rubble_base.py(7건) + 터파기 시험 6건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 타설 줄(품셈 12-1)은 품만 주고 재료를 안 줌(서브 일위대가도 재료 0원) — 콘크리트를
  자재 축에 안 보내면 재료비가 통째로 빠짐. destination 을 material 로 옮김
- 배합 분해 금지(㉢)는 그대로 — 「콘크리트 ㎥」에서 멈춤
- 할증 이름 잇기(값은 그대로, 찾을 때만 다른 이름):
  · 이형철근 D13·D16 → 「이형철근」 (품셈 1-3-1, 규격 안 가림)
  · 콘크리트 셋 → 「레미콘」 **레미콘 타설일 때만**. 비빔은 시멘트·골재가 각각 할증되는
    자리라 붙이지 않고 사유를 냄
- 할증률 미확보 사유를 비고에 적음 — 「표에 이름 없음」과 「이 방식엔 안 붙임」은 할 일이 다름
- tmp/tests/test_b08_material_concrete.py 신설(6건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 ① — 작업효율 0.50(두 끝의 평균). 딸림 지시 「값을 코드에 박고 끝내지 말 것 ·
화면에 칸으로 세우고 근거를 보이고 바꿀 수 있게」를 그대로 구현.

막혔던 자리 둘
- 품셈 9-3-2 가 작업효율을 「0.55∼0.45」 범위로 줌 → 확정값이 아니라 계수가 안 섬
- 그 표에 장비가 없음 → [주]① 「무한궤도 굴착기(0.7㎥)」가 마스터에 안 실려 기종을 못 고름
⇒ 두 자리를 채워 흙깎기 단가가 처음으로 섬: 2,515.1원/㎥ × 2,355.84㎥ ≒ 592만원

구현
- `B09_Estimation_FactorChoices` 신설 — 범위 칸을 품셈에서 훑어 모으고(코드 안 박음),
  고를 수 있는 것은 원문 두 끝과 그 평균 셋뿐. 기본은 평균
- 장비 규격도 같은 결로: 흙깎기는 [주] 에만 있는 값을 채우는 칸, 층따기는 원문 0.7㎥ 를
  기본으로 두고 실무(영월 0.2㎥)로 바꿀 수 있는 칸
- 고른 값은 프로젝트 설정 `estimation` 구획에 저장 — 프로젝트마다 갈림
- `cached_build` 를 고른 값별로 캐시 (전역 한 벌이면 한 프로젝트가 남의 금액을 흔듦)
- `GET/PUT /{project_id}/estimation/factors` · 기초자료 탭 맨 위에 칸과 근거 표시

⚠ 짓다 잡은 것 — 「0.45-0.05」를 범위로 잘못 읽고 있었음. 그건 뺄셈(=0.40)이라
품셈이 이미 정한 값인데 「고를 것」으로 둔갑했음. 물결(∼) 일 때만 범위로 봄

검증: pytest 279 통과(신규 7) · tsc 통과 · 평균 2,515.1 / 하한 2,794.6 으로
고른 값이 단가에 실제로 닿는 것 확인
⚠ 화면 확인은 못 함 — 내 창 브라우저 세션이 만료됐고 자격 파일이 이 폴더에 없음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 지시(2026-09-09): 「값을 코드에 박고 끝내지 말 것 · 대신 페이지에 남길 것」

- 층따기 길이(확정 2차 ①) — 비면 층따기 줄이 막힘. 칸이 없어 값이 안 들어가던 자리
- 기초잡석 두께(확정 3차 ②, 0.2m) — 근거: 폭은 버림 폭과 같음(KCS 34 50 05),
  두께는 품셈 12-25 가 안 정해 사용자 확정값
- 사토장까지 거리(확정 3차 ③ 미정) — 비어 있고, 비면 사토 운반 줄이 막힘
- 구조물터파기 용수(확정 3차 ④) — 기본 「육상」이 **통상값이고 사용자 확정 아님**을
  칸 밑 근거 줄에 적음. 품셈 9-13 의 18구분이 이 값으로 갈림
- 칸마다 근거 한 줄(`b08-quantity__hint`)을 붙임 — 왜 그 값인지 화면에서 보이게

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
일위대가가 선 141 공종 중 **70 공종**이 「품셈 표에 있는데 못 붙은 줄」을 갖고 있었음.
막지 않는 것은 맞으나(막으면 정상 공종이 무더기로 멈춤) 화면이 말하지 않아
**조용히 싼 단가**가 내역서에 그대로 들 수 있었음.

실례 — 초류종자살포(FP-05-24-01, 수량 17,873.80㎡)
  품셈 5-24-1 은 자재 5(종자·비료·피복제·침식안정제·색소) + 장비 3(종자살포기·트럭·
  물탱크) + 인력 2 인데, 우리 단가는 **인력 둘만**으로 233.4원/㎡ 였음.

- `UnitPriceBuild.unattached` 신설 — 공종별로 못 붙은 줄 이름을 들고 있음
- 본표(`detail_of`)가 `unattached`·`unattached_note` 를 함께 냄
- 일위대가 상세 화면이 그 문구를 굵게 띄움. 다 붙은 단가는 아무 말도 안 함
  (늘 경고가 뜨면 아무도 안 읽음)
- 품셈이 자간을 벌려 적은 이름(「종      자」)은 눌러서 보임

⚠ 지역 이름 충돌 하나 잡음 — `names` 가 공종 이름표라 같은 이름을 쓰니 조립이 통째로
터졌음. 주석으로 못 박음.

검증: pytest 282 통과(신규 3) · tsc 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 안 정하면 타설 줄은 기본값(레디믹스트)으로 도는데 할증만 미확보로 두어 같은
  프로젝트에서 두 값이 어긋났음(실화면). 안 정함 = 기본값으로 보고 사유를 적음
- 비빔은 그대로 미확보 + 사유(시멘트·골재가 각각 할증되는 자리)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 유토곡선 잔량은 다짐상태인데 이 값은 자연상태(제자리 기하 부피)라 그냥 더하면 섞임
  (2026-09-09 랩탑 메인 지적). `volume_basis: "natural"` 을 총량·측점마다 실음
- ⚠ 엄밀히는 되메움에 쓰이는 흙이 다짐부피 ÷ C 라 조금 더 들지만, 실무 정본 시트도
  그냥 빼므로(터파기 1.55 − 되메우기 0.30 = 잔토 1.25) 값은 그대로 두고 사실만 적음
- tmp/tests 1건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 유토곡선 잔량이 되돌린 값(natural_m3_by_ground)을 들고 오면 **그것을 씀**.
  없으면 다짐값으로 서되 「품셈 운반 밑수는 자연상태」라는 사실을 근거에 적음
  (조용히 쓰면 상태가 어긋난 물량이 단가에 물림). 우리가 환산하지 않음 — 계수는 저쪽에 있음
- 갈래를 못 붙인 몫은 상태도 못 되돌리므로 그 사실을 함께 적음
- `haul.spoil.volume_basis` 신설 — 받는 쪽이 단가와 맞는지 스스로 보게
- 범위를 줄 사유에 적음: 「사토장 정지」는 실무가 사토 운반 단가 안 조각(1/3)으로 넣으므로
  수량 줄을 따로 안 세움 · 사토장 사면 보호공은 실무 집계표에 행이 없어 안 셈
  (교본 6장 3절은 요구 — 뒤집으면 그때)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「사토장 정지」는 실무가 사토 운반 단가 안 조각(1/3)으로 넣으므로 수량 줄을 안 세움
  (세우면 같은 품을 두 번 셈)
- 사토장 사면 보호공은 실무 내역·사방공 집계표에 행이 없어 안 셈. 교본 6장 3절은
  요구하나 프로젝트 규칙상 실무가 안 세면 안 세는 쪽이 기본 — 뒤집히면 이 문장만 지움

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 코드 주석에만 두면 화면에서 안 보임(오늘 여러 번 나온 자리)
- 「제자리 기하 부피(자연상태) · 되메움에 쓰이는 흙은 다짐부피 ÷ C 라 조금 더 들지만
  실무 정본도 그냥 빼므로 그대로 둠」을 두 줄의 spec_detail 에 실음
- 잔토 사유를 지금 동작으로 고침 — 「통로가 없어 안 실림」 → 「유토곡선이 사토에 얹어
  사토 운반 줄로 섬」(2026-09-09 통로가 생김)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
구조물터파기 여덟 갈래가 「단가가 일부만 섰습니다 — 붙은 몫 10%」로 서 있던 자리.
값이 없어서가 아니라 품셈이 「육상토사(0~1m)와 동일」처럼 **다른 절을 가리키는데**
그 참조를 안 따라가서였음.

- `B09_Estimation_MachineProductivity_Reference` 신설 — 참조를 따라가 계수를 이음.
  값을 옮겨 적지 않고 가리키는 절을 그때그때 읽음. 사슬·순환도 처리(순환은 멈춤)
- 열 갈래가 풀림: 09-13-02·03·05·06·08·09·11·12·17·18
- 빌려 온 계수는 **출처를 줄 비고에 적음** — 「계수 출처: 「…와 동일」 → 육상토사(0~1m)」

⚠ 짓다 잡은 것 셋
- 「육상과동일」은 「육상」이라는 절이 아니라 **제 이름에서 용수를 육상으로 바꾸라**는 뜻.
  이름 규칙을 먼저 태우면 없는 절을 찾다가 네 갈래를 놓쳤음
- 한 표에 참조가 둘이고 **가리키는 곳이 다름**. 9-13-11 은 치즐 줄이 「육상과동일」,
  백호우 줄이 「용수 암절취(0~1m)와 동일」임. 아무 줄에서나 주우면 용수 자리에 육상
  계수가 붙어 작업효율이 0.375 대신 0.50 으로 서고 **금액이 조용히 틀림**.
  ⇒ **기계 줄에 붙은 참조만** 보게 함
-  **묶음 배분율이 첫 줄에만 붙고 있었음** — 품셈이 「인력(10%)」 머리를 병합해 적어
  다음 줄엔 딱지가 없음. 그래서 「보통인부 1.0」이 100%로 서 **조용히 열 배**가 됐음
  (구조물터파기 단가가 224,305원/㎥ 이었음). 묶음 머리를 만날 때까지 이어 주게 고침

막힌 채로 두는 것 — 암·발파암 갈래는 **깨기(대형브레이커)·치즐**이 그대로 빠져 있어
금액을 세우지 않음. 다만 **사유를 남은 줄로 고쳐 적음**(백호우 이야기는 이미 풀렸음).
9-13-14 는 자기 자신을 가리키는 원문 오기라 **고쳐 읽지 않고** 사유로 남김.

검증: pytest 288 통과(신규 6) · 토사 갈래 단가가 처음 섬(1~2m 7,218.5원/㎥)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 잔토 「그 통로가 없다」 → 2026-09-09 에 생김(HaulInputs → 사토 가산 → 사토 운반 줄)
- `face_slope_ratio` 「레지스트리에 없는 키」 → 칸이 생김(돌쌓기 계열 여섯 · 표준도 폼).
  빈 값이 「자동」의 뜻
- 성토/절토 「저장이 아직 안 갖고 있다」 → 측점 단면유형 + 설치 측으로 판정 중.
  못 가르는 자리만 남고 그때도 눅이지 않고 사유를 적음 (masonry_slope 정책 문구도 함께)
- 품셈 9-13 「토질·용수 칸이 없다」 → 셋 다 서면 자식 코드로 내려감

⚠ 사유가 거짓이면 사유 칸 전체를 못 믿게 됨 — 오늘 통로가 여럿 생겨 낡은 자리를 훑음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 2026-09-09 사용자 확정: 사토장은 **이미 있는 측점 위에만** 놓임 ⇒ 거리는 「발생점 →
  사토장 측점」 누가거리로 저절로 나옴. 가정할 것이 없어짐
- 잔량이 `spoil_haul_distance_m` 을 들고 오면 갈래별 **가중평균**을 내어 그 거리로 줄이 섬
  (실무 내역이 운반수단 × 지반별 평균 하나를 올리는 서식)
- 없는 갈래만 산출 조건의 대체 거리로 서고, 거리 출처를 값 옆에 적음
- 사유·화면 도움말을 「거리가 없음」 → 「사토장을 아직 안 놓았음」으로 고침
  (사토장이 서면 낡을 문구였음)
- tmp/tests 2건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「운반거리의 산정 시에 모든 수량은 다짐상태로 환산하여 계산하고, 내역서에
적용하는 수량은 자연상태로 한다」(설계실무 요령, config 5-4-3 인용문) 인데
유토곡선이 쌓은 다짐 물량이 그대로 내역 줄로 서 있었음.

- HaulSummary: 줄마다 `natural_m3`(÷C)·`volume_basis`·`conversion_c` 를 함께 냄.
  환산은 이 파일 한 곳에서 한 번만. 거리·검산은 다짐 기준 그대로.
  `L`(1.3·1.35·1.625) 은 안 씀 — 품셈 10-11·10-12 가 `f = 1/L` 을 스스로 곱함.
- 토공집계표: 운반 줄을 자연상태로 실음. 갈래를 모르면 다짐 그대로 두고 사유 표기.
- 사토 줄: `natural_m3_by_ground`·`volume_basis` 신설. 갈래 없는 몫은 환산 안 함.
- 구조물 잔토(자연상태)를 곡선에 담기 전 ×C — 왕복이 맞게 됨. 갈래 모르면 그대로.

실측 변화(내역 4줄): 도자 토사 15.65→17.39 · 리핑암 70.30→61.13 ·
덤프 토사 33.76→37.51 · 리핑암 140.78→122.42 (합 260.49→238.45, −8.5%).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	B08_Quantity/B08_Quantity_Router_Earthwork.py
- 유토곡선은 다짐상태로 쌓고(운반거리를 그 기준으로 재야 맞음) 내역서 수량은 자연상태임
  (config_system_design 5-4-3). 인계 줄이 다짐값을 그대로 읽고 있었음
- 되돌린 값(natural_m3)이 오면 그 값으로 서고, 쓴 계수(÷C)를 근거에 적음
- ⚠ 되돌릴 계수가 없으면(갈래 못 붙임) 다짐 그대로 두고 사유를 냄 — 토사 계수로 눅이면
  근거 없이 금액이 움직임
- 거리는 안 바뀜(다짐 기준이 맞음)
- tmp/tests/test_b08_haul_state.py 신설(4건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
칸이 없어 `_back_length` 가 조용히 45㎝ 기본값으로 돌던 자리임.

- `back_len_cm` 25·30·35·45·55·60·75㎝ / `stone_kind` 야면석·호박돌·깬잡석·깬돌·견치돌
- 기본값 없음 — 값이 없으면 「기본값으로 섰음」이 드러나야 함
- 돌쌓기(찰·메)와 같은 키·같은 글자 (품셈표 `stone_kind` 데이터셋과 대조)
- 기슭막이는 돌이 아닌 형태(콘크리트·돌망태·바자)도 있어 필수로 두지 않음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 되돌린 값(natural_m3_by_ground)이 오면 그 값으로 서고 상태를 사유에 적음
- 안 오면 다짐 그대로 두고 「내역 수량은 자연상태여야 함」을 사유로 냄
- tmp/tests 2건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 축이 다른 값을 그냥 빼면 암에서 15% 어긋남(우리가 만드는 어긋남). 갈래를 실어 보내
  유토곡선이 ×C 로 다짐 축에 맞춰 빼게 함
- 갈래를 못 가른 구조물 몫은 계수가 없어 따로 냄(환산 안 함)
- ⚠ 벽 입적 ↔ 원바닥 암 부피의 관계를 정한 원문이 없음(캐면 부풀고 쌓으면 공극) —
  그 가정은 어느 쪽으로 가도 남으므로 가정은 그대로 두고 축만 맞춤.
  실무 시트가 그냥 뺀다는 사실까지 값과 함께 보냄
- tmp/tests 3건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
유용토운반작업장(구 사토장) — 노선 옆에 남는 흙을 쌓는 성토 단면.

- `common_util_spoil_fill.{ts,py}` 신설(한 벌, 거울 시험) — 평상(노면 끝 높이) →
  1:n 비탈 → 지반과 만나는 데까지. 단면적은 적분으로 정확히 셈.
  폭 시작점 = **노면 끝**(사용자 확정) ⇒ 그 구간 노견도 이 성토 안에 듦.
  폭 상한 = **지반 샘플이 있는 데까지**. 상한에서도 모자라면 그 폭을 냄(임의로 안 넓힘).
  용량에서 폭을 되풀이로 역산하는 `solveSpoilWidthM` 함께 냄.
- 등록부 `spoil_bank` 를 넓힘 — 새 종류를 만들지 않음(지식DB 상 같은 시설임).
  이름 「유용토운반작업장(구 사토장)」 · 구간형 · 횡단도에 그림 ·
  칸 `side`(자동=성토 쪽) · `fill_slope_ratio`(비면 노선 성토 기울기) · `extra_distance_m`.
- 기울기·적치높이 기본값은 지어내지 않음 — 지식DB §4 가 근거 없음을 못 박음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
채집석은 **벽 입적(제자리 부피)**이라 자연 축이고 유토곡선은 다짐 축임.
축이 다른 값을 그냥 빼고 있었음(리핑암이면 13% 어긋남).

- 갈래별 값(`collected_stone_by_ground_m3`)이 오면 갈래마다 ×C 해서 뺌
- 갈래를 못 가른 몫은 계수가 없어 **환산하지 않고** 그대로 뺌
- 갈래가 아예 안 오면 종전처럼 총량을 그대로 뺌 (안 온 것과 0 은 다름)
- 통로 정리 — `_mass_haul_context` 가 B08 입력 dict 를 통째로 받게 함
  (칸이 늘 때마다 인자를 늘리다 빠뜨리던 자리)

⚠ 벽 입적과 원바닥 암 부피의 관계를 정한 원문이 없음 — 그 가정은 그대로 두고
**축만** 맞춘 것임(세 창 합의, 근거 문구는 B08 이 값과 함께 보냄).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 관 허용오차 두 값이 우연히 다른 것처럼 보였음. `LENGTH_MATCH_TOLERANCE_M`(0.5m,
  「길이를 어디서 가져오나」)과 `SECTION_MATCH_TOLERANCE_M`(0.05m, 「횡단이 있나」)을
  한 자리에 이름 붙여 모으고 **맞추면 둘 다 나빠지는 까닭**을 적음
  ⚠ 두 값의 차이는 증상이고 병은 「관 자리에 측점이 없는 것」(계획서 3-14, B06 자리)
- 채집석 축 맞춤 검산을 값과 함께 보냄 — 더하는 쪽·빼는 쪽에 같은 계수가 걸려
  사토 총량이 그대로임(61.88 → 61.887)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「단가가 일부만 섰습니다 — 붙은 몫 0%」 만으로는 어디를 손볼지 알 수 없었음.
구조물터파기가 그 자리였는데, 참조는 이미 풀렸고 실제로 막는 것은 깨기(대형브레이커)·
치즐이었음.

- 사유에 `component_gaps`·`unattached` 를 이어 붙임
  「붙은 몫 0% · 깨기, 치즐소모량(본/hr) 줄이 아직 안 붙었습니다 (계수 참조는 풀렸습니다).」

검증: pytest 288 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사토장이 선 측점은 **노면 끝 바깥이 사토장 몫**이라 노선 성토에서 빼야 함.
안 빼면 같은 흙을 두 번 셈(2026-09-09 확정 ㉠).

- `compute_cross_design(spoil_fill=…)` / `computeCrossDesign({spoilFill})` 신설(짝)
- 새 칸: `spoil_fill_area_m2` · `spoil_fill_side` · `spoil_fill_width_m` ·
  `spoil_fill_max_width_m` · `spoil_fill_line` · `spoil_fill_unclosed` ·
  `spoil_fill_replaced_fill_m2`(노선 성토에서 뺀 몫 — 되짚기용)
- **합쳐서 하나로 내지 않음** — 받는 쪽이 갈라 볼 수 있어야 함
- 기울기가 비면 그 측점의 노선 성토 기울기를 그대로 씀(새 값 안 만듦)
- `fillAreaBeyond`/`_fill_area_beyond` — 경계 종거를 보간해 자름(한 칸도 안 흘림)
- 거울 시험에 사토장 사례 둘 추가 + 값이 0 이면 잡히는 가드

⚠ `B06_Section_Engine_Design.py` 가 924줄 — 700줄 제한 초과 상태임(이번 전에도 881줄).
  기능이 다 선 뒤 분리할 자리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
표토 운반(법이 요구하는데 제거만 세고 있던 자리)
- 시행규칙 별표2 「표토는 전량 제거한 후 … 최고 홍수위보다 높은 장소로 운반하고
  쌓아두어야 한다」 — 제거(9-15)만 세면 운반이 빠짐
- 물량은 제거 물량 그대로(다시 안 셈), 거리는 설계 입력 `topsoil_haul_distance_m`
- 거리가 없으면 막고 사유 · 제거가 안 서면 운반도 안 섬(밑수가 그 줄) · 법 문구를 사유에

화면 칸(사용자 지시 「대신 페이지에 남길 것」)
- 부대시설 개소 다섯(국가지점번호판·안내판·차단기·가설창고·수방자재) — 서버가 받고
  있었는데 넣을 칸이 없던 자리. 산식으로 만들지 않는다는 사유를 칸 밑에 적음
- 표토 운반거리 칸 + 별표2 근거 한 줄

- tmp/tests/test_b08_topsoil_haul.py 신설(5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「입목 본수를 들고 있지 않음」이 원문과 달랐음. 품셈 9-21 [주]① 은
  **소림(30~60㎥/㏊)·중림(60~90)·밀림(90 이상)** 으로 가름 — 본수가 아니라 **축적**
- ⚠⚠ 그리고 **9-21 표에 밑수 단위 열이 없음**(9-20 은 「10주당」이라 적혀 있음).
  등급을 넣어도 「무엇당 값」인지 모르면 못 셈 — 원문 확인이 필요한 자리로 사유에 적음
- 임목축적 등급 설정·화면 칸 신설(`stand_volume_class`) + 근거 한 줄
  (산림조사부·영림계획에서 옮겨 적는 값이라 프로그램이 만들 수 없음)
- 대상 면적(벌개제근 연동, 지장목제거와 같은 자리)을 참고값으로 실음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 9-20 가. 「벌개·제근 → 뿌리다듬기 → 적재 → 운반」이 시공 과정 표준이고 [주] 가
  「제근 후 뿌리다듬기와 적재항목에 적용」이라 두 항목을 줌. 별표2 도 「그 뿌리…를 전량
  제거한 후 운반하고 쌓아두어야」로 뒤 단계를 요구 — 우리는 제거 한 줄만 세고 있었음
  (표토와 같은 병: 법·품셈이 두 동작을 묶는데 앞 동작만 셈)
- 적재는 FP-09-20-02(「10주당」) · ⚠ 운반은 그 장에 공종이 없어 코드를 못 붙임 —
  지어내지 않고 사유로 냄
- 둘 다 제근과 같은 밑수(본수)가 서야 값이 남. 대상 면적은 참고값으로 실음
- tmp/tests 3건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
품셈 제8장 [주]⑤ 「불도저 및 굴착기에 리퍼, 브레이커, 부착용집게를 조합하여 사용할
때는 …잡재료비율을 16%로 계상하고, 리퍼, 브레이커, 부착용 집게의 손료 및 치즐
소모율을 추가하는 것이다」 를 따라감.

세 자리를 이었음
1. **뭉개진 카탈로그 줄을 원문으로 되살림** — `mach_base_2026.json` 의 대형 브레이커
   여섯 줄이 이름 칸에 표 전체가 뭉쳐 규격·손료계수가 없었음. 건설품셈 제8장 (0230)
   표에서 읽어 채움. ⚠ **두 번 검증** — 계수 합 3,000+2,833+768=6,601 이 표의 「계」와
   같고, 같은 방식으로 읽은 굴착기 「계 2,085」가 카탈로그 0.0002085 와 정확히 일치
2. **부착용 장비는 손료만으로 층을 세움** — 제 엔진이 없어 운전경비표에 줄이 없음.
   없다고 버리면 깨기 몫이 영영 안 붙음. ⚠ 리퍼·브레이커·집게에만 여는 길
3. **작업량을 직접 준 기계 줄을 읽음** — 「대형브레이커(㎥/hr) 3.5」. 공식이 아니라
   시간당 작업량을 표가 바로 주는 모양. 단위가 붙은 칸만 읽음(짐작 금지)

결과
- 구조물터파기(암절취·육상·2~3m) 155.625㎥ × 72,378.4 = **11,263,899원** — 처음 섬
- 돌쌓기 단가에 **부착용 집게 손료**가 더해짐(메 76,607.9 → 78,864.5) — [주]⑤ 그대로
- 본체 19,444,626 → **30,892,279원**
- 남은 것은 **치즐(자재) 하나** — 기계가 빠지면 막고 자재 소모품이 빠지면 드러내기만
  하는 규칙대로, 금액을 세우고 본표가 「치즐소모량 줄이 아직 안 붙었습니다」를 말함

⚠ 아직 안 한 것 — 같은 [주]⑤ 의 **「잡재료비율 16%」**. 조합 사용 시 굴착기 잡재료가
22% 가 아니라 16% 임. 그 자리는 운전경비 층이라 따로 손봐야 함.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 갈라 내라는 원문이 없고 실무도 한 덩이로 셈. 별표2 타.(1) 이 「노출되는 면은
  전체면적 녹화」라 소단도 녹화 대상이므로 섞여 있는 것이 틀린 것이 아님
- 가르면 「그 몫으로 무엇을 세나」를 우리가 정하게 되어 근거 없는 줄이 섬 —
  대신 근거 문구에 「소단면 포함」을 적어 가르지 않고 보이게 함

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
① 수량 산식이 확정 대기인 줄에 그 사실을 함께 실음 (계획서 4-12 3단계)
   구조물터파기가 내역서에서 가장 큰 줄(11,263,899원)이 됐는데 그 밑수가 사용자
   확정을 기다리는 식 위에 서 있음. 값은 그대로 두고 **드러내기만** 함.
     「⚠ 터파기 수량 산식이 확정 대기입니다 — 실무 시트는 기초만(기초폭 × 깊이 0.3)
       세고 우리는 벽 전체를 셉니다(m당 실무 0.35 vs 우리 2.30, 약 6.6배).
       실무 식으로 확정되면 이 줄 금액이 약 1/6.6 로 줄어듭니다.」
   되메우기·잔토처리도 같은 뿌리라 함께 표시. ⚠ 측구터파기는 다른 뿌리라 대상 아님

② `VARIANT_ALIASES` — 축이 달라 다르게 불리는 갈래를 **이름을 갈지 않고** 이음
   우리 「리핑암」은 B05·B06 지반유형(캘 수 있는가), 품셈 「파쇄암」은 운반 상태
   (부서졌는가)라 일반적으로 같은 말이 아님 — 발파암도 캐고 나면 파쇄암 상태임.
    다만 산림품셈 10-11 f 표가 토사·파쇄암·발파암을 따로 두어 그 표의 파쇄암은
   발파를 뺀 나머지이고, 10-12 [주]③ 「토사 1.3, **암절취 1.35**, 발파암 1.625」가
   10-11 의 파쇄암 1/1.35 와 **같은 값**이라 그 표 안에서는 암절취(리핑) = 파쇄암임.
   그 문장을 주석에 그대로 남김

검증: pytest 290 통과 · `find_variant_code("FP-10-11","리핑암")` → `B-FP-10-11#파쇄암`

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 운반 단가가 지반 갈래로 갈리는데 `variant_value` 가 비어 있어 받는 쪽이 갈래를 못 골랐음
  (「버림」에서 275,584원이 사라졌던 자리와 같은 병)
- `variant_axis: "ground_class"` · `variant_value: 리핑암` 으로 실음. 갈래가 없는 줄은 None
- ⚠ 이름은 우리 갈래 그대로 — 일위대가의 「파쇄암」과는 인계본 `ground_class_aliases` 가 이음
- tmp/tests 2건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 소광리 숨김탭 「골막이(찰)(치수조서연결)」 C26 이 우리가 확정 ② 로 버린 옛 식과
  글자까지 같음 — 그 식은 틀린 식이 아니라 **골막이 식**이었음. 기슭막이에 쓰던 것이
  어긋남의 정체였음
- 골막이는 두께식 말고도 셋이 더 다름(밑수 = 돌쌓기+돌붙임 · 단위 = 개소당 ·
  정면적 = 사다리꼴) — 상수만 보고 가져다 쓰지 못하게 적음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
① 품셈 제8장 [주]⑤ 의 마지막 조각 — 「…조합하여 사용할 때는 …**잡재료비율을 16%로
   계상**하고, 리퍼·브레이커·집게의 손료 및 치즐 소모율을 추가」. 손료·치즐만 넣고
   이 줄을 빠뜨리면 본체 재료비가 22% 로 남아 조금씩 비싸짐.
   - 기계마다 「#조합」 층을 함께 세움(손료·조종원 같음, 잡재료만 16%)
   - 조립 **끝에 한 번** 조합 공종의 본체 줄을 그 층으로 바꿔 닮 — 도중에는 어느 공종이
     조합인지 아직 모름. 바꾼 줄 24
   - 부착 장비는 **이름이 아니라 분류번호**로 잡음(0103 리퍼 · 0230 브레이커 ·
     0240 진동콤팩터 · 7206 집게) — 이름은 원천이 뭉개 놓는 일이 있음(0230 이 그랬음)
   - 결과: 구조물터파기 72,378.3 → 72,333.2 · 돌쌓기(메) 78,864.5 → 78,423.8 ·
     돌쌓기(찰) 61,757.3 → 61,418.0 · 본체 30,892,279 → **30,849,376원**

② 터파기 노티스 문구 정정 — 「실무는 기초만 세고 우리는 벽 전체를 셈(6.6배)」이
   **틀렸음**. 우리 식은 정본(기초 0.45 + 비탈) 그대로이고, 6.6배는 소광리 시트가
   비탈 줄을 안 적어서 난 것임. ⇒ 「비탈 터파기를 셀지 확정 대기 — 안 세면 약 1/7」로
   고침. 값·금액은 그대로

검증: pytest 290 통과(신규 1)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자는 「이 구간에 ○㎥」를 정하는데 단면은 폭을 알아야 그려짐.
그 구간 측점을 한꺼번에 보고 **폭 하나**를 이분법으로 찾음(작업장은 폭이 일정함).

- `enforce_spoil_fills` 신설 — `enforce_ford_surface_drops` 와 같은 자리·같은 방식.
  자동설계 체인·[저장] 뒤 **맨 마지막**에 돎(앞 보정이 다시 계산하면 사토장 칸이 지워짐)
- 「자동」이면 그 측점의 **성토 쪽**에 섬 (`structure_face_role` 재사용)
- 상한(지반 샘플이 있는 데까지)에서 멈추고 못 담은 몫은 `spoil_fill_unplaced_m3` 로 냄
- 구간 안 측점만 씀 — **새 측점을 만들지 않음**(사용자 확정 ③)
- 용량이 없으면 아무것도 안 세움(폭을 정할 근거가 없음)

실측 — 용량 200㎥·800㎥ 를 넣으면 각각 그만큼 담기고(오차 2% 안), 100만㎥ 를 넣으면
상한 폭에서 멈추고 남은 몫이 값으로 남음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 토공집계표는 실무 토적집계 모양이라 무대·도자운반·덤프운반을 함께 싣는데, 인계본에는
  운반표(FP-10-11·FP-10-12)가 같은 물량으로 또 실렸음 — 둘 다 in_bill 이었음
  (실측: 도자 17.389·61.130 · 덤프 37.511·122.417 이 두 축에 각각)
- 집계 쪽 운반 줄을 in_bill=False 로 두고 사유를 적음. 값은 남김 — 검산
  (무대+도자+덤프 = 총 운반토량)이 그 값을 씀(무대를 그렇게 둔 것과 같은 규칙)
- 성토 같은 다른 집계 줄은 안 건드림
- tmp/tests/test_b08_haul_double_count.py 신설(5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
품셈 9-21 제근은 장비 규격 두 갈래(0.2㎥·0.7㎥)를 **고르라고** 둔 표인데 둘 다 붙고
보통인부도 두 번 붙어 단가가 **128,039원**으로 서 있었음. 밑수가 원문에 없어 아직
금액이 안 서 있었을 뿐, **밑수가 정해지는 날 조용히 두 배로 설 자리**였음.

- `B09_Estimation_ResourceAxis_ChooseOne` 신설 — 블록마다 갈래 하나, 열마다 갈래 하나.
  장비 2 × 임목밀도 3 = **여섯 갈래**로 세움 (55,625.9 ~ 111,161.4원)
- ⚠ **「고르는 표」를 좁게 가름** — 기계 줄이 둘이라고 다 그런 표가 아님. 9-13 암절취는
  깨기(브레이커)와 들어내기(백호우)가 **함께 듦**. 자국은 **같은 이름에 규격만 다른 것**.
  품셈도 그렇게 말함 — 9-20-1 [주]④ 「0.2㎥ 또는 0.4㎥ … 계수를 달리 적용」
- ⚠ 밑수는 만들지 않음 — 9-21 은 표 머리·제목·[주] 어디에도 밑수 표기가 없음
  (앞 절 9-20-1 「(10주당)」·9-20-2 「(단위: 10주당)」과 대비되는 자리)

⚠ 짓다 잡은 것 — 기종 해석이 **넘겨받은 카탈로그를 무시**하고 기계 카탈로그를 직접 봐서,
노무만 든 카탈로그로 돌릴 때도 기계 줄이 나왔음. 카탈로그에 기계가 없으면 이 표를
안 읽게 막음(시험이 그것을 잡았음).

⚠ 시험 하나가 **버그를 맞는 것으로 적어 두고 있었음** — 「제근은 보통인부 줄이 둘이다」.
그것이 곧 이중계상이었음. 뒤집어 다시 적었음.

검증: pytest 295 통과(신규 4) · 자원 축 539 → 547 줄, 늘어난 8 줄은 전부 제근

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「반쪽 단가」 표시가 여태 **이름을 카탈로그에서 못 찾은 줄**만 잡고 있었음. 그물 밖에 둘이
더 있었고, 둘 다 **금액이 서 있는 줄**이라 표시가 없으면 완성된 값으로 읽혔음.

- 기초잡석 12-25 — 원문에 「운반 | 덤프트럭(15ton)」 줄이 있는데 우리 단가에 없음.
  ⚠ 사유를 「원문이 값을 안 줌」으로 뭉뚱그리지 않음 — 그 값은 품셈 10-12(덤프운반)가
  **운반거리로** 내는 것이라 **거리가 정해지면 풀림**. 「영영 막힘」과 「곧 풀림」은
  사용자가 보는 뜻이 다름
- 기초잡석 소할 — 원문이 「**브레이커 사용할 때 제외**」라 한 줄인데 지금은 무조건 붙음.
  ⚠ 조건부 열두 줄 중 **이것만 금액이 서 있음**(다른 열한 줄은 붙는 쪽, 이것은 빠지는 쪽)
- 규준틀 11-2·11-3 — 지금 값은 **인력 품만**. 손율은 원문에 있음(비탈 50% · 수평 80%)

⚠ 앞 보고를 정정함 — 규준틀은 「표시가 아무것도 없다」고 했으나 **B08 인계가 이미
「재료량은 [주]④ 설계수량에 따른다라 미확보」를 싣고 있었음.** 화면 문구 뒤쪽이 잘려
안 보였던 것임. 그래서 그 말은 되풀이하지 않고 **B09 쪽에서만 아는 것**만 보탬.
「잘린 자리를 사유가 없는 자리로 읽지 말 것」을 주석에 남김

검증: pytest 300 통과(신규 5)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
교본 6장 3절이 운반처리 위치를 평면도·횡단도에 표시하도록 요구함.

- 긴 파선+점(9 3 2 3) · 사토장 색 — **터파기 짧은 점선과 선 종류를 가름**
- 이름표 「유용토운반작업장 ○㎡」 를 평상 위에 얹음
- 말풍선에 단면·폭·구간 용량·못 담은 몫·잘림 경고와 **근거 두 줄**
  (「폭은 노면 끝에서 잼」·「교본 6장 3절이 표시를 요구함」)
- 지반을 못 만나 잘린 사토장은 붉게 — 사면 미폐합 경고와 같은 결
- 계획선을 만져도 사토장이 안 사라지게 저장분 폭·구간값을 이어 붙임
  (폭은 구간 용량에서 서버가 정한 값이라 브라우저가 다시 풀지 않음)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「재료량은 설계수량에 따른다」는 값을 안 준다는 뜻이지 안 센다는 뜻이 아님.
  근주이식·임목파쇄(셀지 말지가 설계 판단)와 성격이 다름 — 확정 ⑨·⑩ 과 같은 틀로 감
- 제안값(울진 소광 §8 관측): 각재 50×50 0.0044㎥ · 판재 T12 0.0029㎥ · 못 0.03㎏/개소
- ⚠ 「실무 관측값이지 법정 기준 아님」과 손율 원문값(비탈 50% · 수평 80%)을 줄 사유와
  화면 칸 밑에 함께 적음 — 값만 박으면 「대신 페이지에 남길 것」 지시를 어기는 것
- 개소가 안 서면 재료도 안 섬(밑수가 그 줄) · 자재 축으로 감(할증은 자재총괄에서 한 번)
- 설정 `frame_material` + 화면 칸 셋
- tmp/tests/test_b08_frame_material.py 신설(7건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사토장이 **측점 위에만** 서므로(사용자 확정 ③) 거리는 「발생점 → 사토장 측점」
누가거리로 그냥 나옴. 가정할 것이 없어짐.

- `_spoil_sites` — 측점 설계에 실려 온 사토장 구간값을 구조물 단위로 접음(다시 안 셈)
- 거리 = 발생점별 물량 가중평균 + `extra_distance_m`(항상 더함)
- 사토장이 없으면 종전대로 설계 입력값 · 그것도 없으면 막힘(임의 거리 안 넣음)
- 사유에 사토장 측점·수용량·**못 담는 몫**을 실어 화면이 드러내게 함
- `distance_basis` 칸 신설 — 받는 쪽이 「측점 기준」과 「설계 입력값」을 갈라 봄

⚠ 사토장에 쌓아도 **유토곡선 사토는 줄지 않음** — 그 흙은 여전히 실어 내야 하는 흙이고
  사토장은 목적지임. 줄이면 운반비가 사라짐. (네 창에 확인 요청함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사토장
- 카드 면적표에 「사토장」 줄을 따로 세움 — 성토와 **합치지 않음**(확정 ㉠).
  사토장이 없는 측점에는 줄을 세우지 않음(어느 측점에 있는지 표에서 보이게)
- 성토와 다른 색으로 둠 — 같은 색이면 한 덩어리로 읽힘

등록부(다른 창 요청, 기본값 없음 — 현장 치수라 지어내지 않음)
- `erosion_check.top_length_m`·`bottom_length_m` — 골막이 정면적이 사다리꼴이라
  두 변이 있어야 셈. 실무 정본 산출식이 상장ⓐ·하장ⓑ를 씀
- `soil_guard.form` 에 「떼」 추가 — 실무 정본에 떼흙막이 산출식이 있는데 붙일 칸이 없었음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	B08_Quantity/B08_Quantity_Engine_UnitQuantity.py
① 마스터가 본문·표에서 밑수를 「인」으로 읽어 온 자리가 여섯 있음(드론방제 둘·지상방제·
   야면석 채집·휘발유·천공기). 「인」은 **사람 수**이지 공종 단위가 아니라, 그대로 두면
   「몇 인짜리 공종」이 되어 **단위 불일치 검사가 엉뚱하게 통과**함.
   ⚠ 원문 쪽 고치기는 마스터 몫(데스크탑 메인) — 여기서는 **받는 쪽에서 막음**.
   같은 규칙이 `WorkItemUnit` 머리말에 이미 있어 짝을 맞춤

② 규준틀 사유 갱신 — 데스크탑 메인이 각재·판재·못을 자재 축에 세워(`e100d311`)
   「인력 품만」의 뜻이 바뀜. 재료가 오되 관급·사급이 안 갈려 아직 금액 0 임을 적음

⚠ 계획서 9장 재판정(미체크 27 → 21 · 크기 딱지)은 `docs/` 가 git 밖이라 커밋에 안 실림 —
  파일에는 반영돼 있음.

검증: pytest 300 통과 · 밑수가 「인」인 자원 줄 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
돌골막이(erosion_check)
- 소광리 정본 「골막이(찰)(치수조서연결)」 식을 개소당으로 전개.
  정면적 사다리꼴 − 방수로 파형강관 → 돌쌓기 → 평균두께 → 입적 →
  야면석·고임돌·막자갈·채움콘크리트·물구멍관 → 바닥파기·잔토·되메우기 11줄.
- 거울 시험이 정본 W열과 소수점까지 일치(19.62 / 2.625 / 20.56 / 19.58 /
  3.34 / 10.54 / 4.45 / 4.91 / 8.61 / 2.74 / 5.87).
- 엑셀의 줄별 INT(x*100)/100 자름을 그대로 옮김 — 다음 줄이 잘린 값을 받음.
- 두께식 주석 정정: 「0.45 + 0.1H」의 0.45 는 상수가 아니라 뒷길이 ℓ3
  (정본 C26 이 P6/100 을 읽음). 골막이도 뒷길이 기반임.
- 등록부에 없는 칸 셋(뒷길이·돌 종류·방수로 유무)은 붙박이로 돌되 사유를 냄.

떼흙막이(soil_guard)
- 형식 「떼」가 들어와 정본 「떼흙막이」 표가 섬 — 떼 1.39㎡ · 터파기 0.17㎥.
- 사용자 확정 4차대로 그림·옵션은 기슭막이와 한 벌, 수량 데이터는 분리.
  나머지 일곱 형식은 원단위 미확보 사유로 뜸.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-09 12:00:10 +09:00
정본이 줄마다 INT(x*100)/100 으로 자르고 다음 줄이 그 잘린 값을 받으므로
표시용이 아니라 계산의 일부임. 안 자르면 막자갈 10.55 · 잔토 2.75 로
정본과 갈림. round(4.905) 가 짝수 반올림으로 4.90 이 되는 자리(물구멍관)도
함께 적음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 14 commits 2026-09-09 12:16:49 +09:00
「인」 오독 넷(원문 대조)
- 8-6-2 드론방제·8-6-3 지상방제 「(단위 : 인)」은 **소요인력**이지 공종 밑수가 아님
- 13-2-4 야면석 채집 「(단위: 인 당)」은 표 안이 ㎡당·㎥당 두 줄이라 하나로 못 정함
- ⚠ 넓게 「인」을 버리면 2-2-5 천공기가 사라짐(「천공인부 1인당 1대」) — 숫자가 붙었나로 좁게 가름

칸 이어붙임 — 앞 칸 값 + 뒤 칸 단위로 **원문에 없는 밑수**가 서던 자리
- 13-2-4 「0.36 ㎥당」(0.36 은 뒷길이 60 의 ㎡당 값)
- 5-19-2 「30 ㎥당」(30 은 표토두께 ㎝)
- ⇒ detect_basis 가 **칸 하나 안에서만** 봄. 「100㎥당」처럼 한 칸에 다 있는 것은 그대로

- 마스터 재생성: 밑수 확보 182 → 180 (없는 값 둘이 빠지고 넷이 미확보로 정직해짐)
- tmp/tests/test_b08_master_basis_person.py 신설(5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 소광리 C26 이 `P6/100`(뒷길이 45㎝)을 읽는 것이라 골막이도 **뒷길이 기반**임.
  둘은 「더하는 몫」만 다름 — 골막이 ℓ3 + 0.1H/0.4H · 기슭막이 ℓ3 + 0.30 / +0.30(H−1)
- 앞서 상수처럼 적어 두었는데 그렇게 굳으면 **뒷길이를 바꿔도 골막이 값이 안 움직이는**
  결함이 조용히 남음(랩탑 보조가 셀 참조로 확인해 알려 옴)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠⚠ **진단이 뒤집힌 자리임.** 계획서 3-14 는 「관을 나중에 놓으면 측점이 안 생긴다」로
적혀 있었으나 실측하니 **측점은 이미 있었음** — 구조물 이름표까지 달고.

진짜 원인 — **관 자리와 측점 자리는 최대 0.5m 어긋나고 그것이 설계임.**
측점을 만들 때 정수 미터가 같은 격자 측점이 있으면 그리로 스냅함
(`B05_Profile_Engine_Sections_Core` — 횡단 파일명이 정수 미터라 두 측점이 한 파일을
덮어쓰는 것을 막는 가드). 관 440.241 은 **측점 440.0** 위에 섬.
그런데 붙이는 쪽이 **0.02m** 로만 봐서 그런 관은 어느 측점에도 안 붙었음
⇒ 횡단도에 안 서고 길이도 안 실려 B08 이 「연장 없음」으로 막음.

- `attach_culvert_sets` / `attachCulvertSets`(짝) — **가장 가까운 측점 하나**를 그 관의
  자리로 봄. 거리로 자르지 않아 스냅 폭이 바뀌어도 따라가고, 하나만 고르므로 두 번 안 셈
- `pipeOwnerChainage` 신설 — 길이를 싣는 주인도 같은 규칙
- `SECTION_MATCH_TOLERANCE_M` 0.05 → 0.5 — 좁게 보면 「횡단 자체가 없습니다」라는
  **거짓 사유**가 뜸(반대 방향의 거짓). 옛 판단 근거를 주석에 남기고 뒤집은 까닭도 적음

실측 — 관 9개 중 **5개만** 길이가 있던 것이 **9개 전부**로 (440·620·720·900 복구).

곁들여
- 「측점 없는 구조물 N개」 알림 + [측점 만들기] 단추(3-14 ㉯) — **진짜로 측점이 없는**
  경우를 위해 남김. 판정은 스냅을 셈에 넣어 0.5m.
  샘플링 조건은 확정 때 남긴 `sampling.json` → 없으면 1단계 저장값. 둘 다 없으면 막고 사유
- 등록부 `retaining_wall.form` 에 「식생옹벽블럭」 추가(다른 창 요청)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
B08 이 율을 이미 곱해 보내고, 율이 갈리는 줄은 `pct` 를 비운 채 갈래로만 보냄.
받는 쪽은 **곱하지도 100% 로 채우지도 않아** 값은 맞았는데, **왜 그 수량인지**가
화면에 아무 데도 없었음 — 값이 맞아도 그것은 반쪽임.

- `application_ratio_breakdown` 을 읽어 사유로 적음
  「반영률이 갈래마다 다릅니다 — fill 80%, cut 100% (적용 후 수량)」
- ⚠ **「율 없음」이라 쓰지 않음** — 사실이 아님. 오늘 가장 위험하다고 본 오독과 같은 말임
- 율이 안 걸린 줄은 아무 말도 안 함

검증: pytest 303 통과(신규 3) · 율을 어긋나게 넣어 실제로 돌려 봄
  (quantity 1300 · gross 1500 · pct None → 1300 그대로 · gross 안 씀 · 두 번 안 곱함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 보조가 산출식을 손에 들고 기다리던 칸들. **기본값은 안 넣음**(현장 값이라
지어내면 안 되고, 비어 있으면 사유가 뜨는 것이 맞음).

- 골막이 `back_len_cm`(뒷길이 ℓ3) · `stone_kind`(돌 종류) · `spillway`(방수로)
  ⚠ 뒷길이 하나에 두께식·고임돌·야면석·채움콘 네 성분이 걸림
  ⚠ 방수로는 지금 **늘 빼고** 있었음 — 「없음」을 고를 칸이 없었음
- 개거 `ditch_spec` — 콘크리트 개거 150×200 / L형수로 H=0.2. 비우면 실무 붙박이(개거)
- 물빼기 구멍 덮어쓰기 `weep_hole_diameter_mm` · `weep_hole_area_m2` (여섯 종류)
  비우면 **국가기준**(Ø50 · 2㎡당) — 사용자 확정 「국가기준 + 숫자 변경 가능하게」
  ⚠ 바닥막이는 뺌 — 바닥에 눕는 시설이라 벽면이 없음

칸 이름·글자는 기슭막이·돌쌓기와 같은 벌을 씀(엔진이 읽는 이름 그대로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1번 비탈 터파기 「지금 이대로」 — `BASIS_WALL` 에서 「확인 후 쓸 것」을 걷고 확정 표시로 바꿈
  (「법정 근거 없음」은 사실이라 그대로 둠)
6번 제근 밑수 **면적 축** — 산림품셈 9-21 에 밑수 표기가 없어 **건설품셈 3-9-2 「1,000㎡당」**
  을 ⚠ **교차 참조**로 빌려 씀. 제근·뿌리 적재가 같은 면적으로 섬(㎡)
  ⚠ 임목축적 등급은 **단가 갈래**이지 물량 밑수가 아님 — 비어도 값은 서고 사유만 남음
4번 뿌리 운반 **덤프**(FP-10-12) — ⚠ 운반 밑수는 부피(㎥)인데 뿌리 부피를 든 곳이 없어
  물량은 안 섬. 사용자 관찰(실무에서 운반품이 안 붙기도 함)도 사유에 적음

곁들여 — 준비공 인계 줄이 **값이 서는 순간 근거를 잃던 자리**를 고침(대분류 이름만 싣고
  있었음). 제근이 확정으로 값이 서자 「교차 참조」 표시가 사라진 것에서 드러남

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
막자갈 (작은 것 3)
- 옛 식(입적 − 몸통 − 고임돌)에서 (뒷채움 상 + 하) ÷ 2 × H 로 갈아탐.
- 상·하는 벽 두께가 아니라 뒷채움 폭임. 정본 04.구조도(기슭막이).xls
  여섯 탭(H=1.0~3.0 · 메/찰 · 기초유/버림) 전부 상 0.30 · 하 0.45 로 같음.
  소광리는 같은 식에 0.30/0.60 을 써서 0.900 이 나옴 — 그 사실을 사유로 냄.
- H=2.0 에서 정본 0.75 와 일치(옛 식은 1.66 쪽으로 튀던 자리).

석적 (작은 것 4)
- 정면적 × 뒷길이 × 0.77 로 새 줄. 정본에 없고 소광리에만 있는 줄임을 사유에 적음.
- 「체적」은 이미 「입적」 이름으로 내고 있어 이름만 맞음 — 새로 만들지 않음.

돌 무게 (큰 것 7)
- 뒷길이 × 0.77(채움률) × 2.65(비중) 계산식이 기본. H=2.0 에서 정본 1.92 톤과 일치.
- 야면석만 관측표(35→0.575 · 45→0.880 · 55→1.100) — 공극이 커 계산식이 안 맞음.
- 종류를 안 고르면 정본 줄 이름 그대로 「돌」로 서고 그 사실이 사유로 뜸.
- 잠정임(실무자 협의 후 명확히)을 화면 근거에 적음.

터파기 (큰 것 1) — 기초 + 비탈 그대로. 코드 변경 없음.

채집석 밑수도 새 줄을 따라감 — 석적 + 고임돌 + 막자갈.
거울 시험 신설: 정본 H=2.0 여섯 줄 일치, 일부러 다른 두 줄(입적·물구멍관)의
차이까지 못박음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	B08_Quantity/B08_Quantity_Engine_Pipe.py
# Conflicts:
#	B08_Quantity/B08_Quantity_Engine_UnitQuantity.py
골막이 (erosion_check)
- spillway 「있음/없음」 — 「없음」이면 파형강관 0.5024㎡ 를 안 뺌. 정면적이 밑수라
  일곱 줄이 +2.1~3.1 % 움직임. 「있음」이 정본과 같은 값(정본은 방수로 치수 0 인
  개소에서도 뺐음). 안 고르면 정본 쪽으로 서고 사유가 뜸.
- stone_kind · back_len_cm 를 읽음. 「칸이 없다」던 사유가 「안 골랐다」로 바뀜.

돌 무게 헬퍼 한 벌 (stone_weight_per_m2)
- 확정 5차 큰 것 7 규칙을 돌쌓기·골막이가 같이 씀. 계산식이 기본, 야면석만 관측표.
  두 벌로 두면 같은 확정이 구조물마다 갈림.

물구멍 헬퍼 한 벌 (weep_hole_spec)
- weep_hole_diameter_mm · weep_hole_area_m2 를 읽고 비우면 Ø50 · 2㎡당.
  지름은 규격(spec)으로 실어 단가가 갈리게 함.
- 정본이 개소당 관 길이를 평균두께(0.83m)로 잡는 것을 주석에 남김 — 우리 상수 0.5m
  와 갈리는 자리이고 미결임.

개거 — ditch_spec 칸이 와서 두 규격을 고를 수 있음.

시험 — 등록부 정책 예외에 새 칸 넷(ditch_spec · weep_hole 둘 · fill_slope_ratio)과
사토장 둘을 넣음. 613 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 31 commits 2026-09-09 16:11:56 +09:00
- 실무(영월 1.9)가 한 면적에 두 작업을 얹음 — 뿌리뽑기 @475 · 잡관목제거 @882 가
  같은 11,035㎡. ⚠ 이중계상이 아니라 서식이 그러함(사유에 적음)
- 잡관목제거는 품셈에 이름이 없음(실무 D00033 별도 단가) — 공종 보류(확정 5차 3번)라
  코드 없이 서고 사유가 붙음
- ⚠ 곁들여 잡은 것: `item` 칸을 **늘 지반 갈래로 읽고 있었음** — 지장목제거의 작업 갈래에
  「시공법 미지정으로 공종을 못 고름」이라는 틀린 사유가 붙었음. 갈래로 읽는 공종을
  GROUND_SPLIT_GROUPS 로 한정하고 나머지는 규격 칸으로 보냄
- tmp/tests/test_b08_tree_removal_split.py 신설(5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 5차 「비탈 터파기, 지금 이대로」 ⇒ 구조물터파기·되메우기·잔토처리 세 줄의
「확정 대기」 문구를 걷음. **값은 안 바뀜** — 11,256,879원이 확정된 값이 됨.

⚠ 표는 지우지 않고 **비워** 둠 — 같은 성격의 자리가 또 생기면 여기 적으면 됨.
적을 때 「왜 대기인지」와 「정해지면 얼마나 움직이는지」를 함께 적으라는 규칙을 주석에 남김.

검증: pytest 303 통과 · 본체 31,118,251원 그대로

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 「기본 안 셈」이되 「현장에 따라 파쇄가 적용될 필요 있음」이라 **임목파쇄만** 켤 수 있게 둠
- ⚠ 안 켠 프로젝트에는 **줄 자체가 없음** — 빈 칸이 「세야 함」으로 읽히지 않게
  (부대시설은 법정 의무라 늘 서는 것과 다른 자리)
- 켜도 부피는 지어내지 않음 — 넣어야 값이 서고 FP-08-11(이동식 임목 파쇄)이 붙음
- 근주이식(FP-14-02)은 **칸도 안 만듦** — 켤 자리가 없으면 물을 일도 없음
- 설정 `wood_chipping_enabled`·`wood_chipping_volume_m3` + 화면 칸 둘
- tmp/tests/test_b08_wood_chipping.py 신설(5건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 4차 원문 — 「흙막이는 횡단도에서 **표현방식들과 옵션들은 동일하게** 반영하면
될거야. **형상은 동일해.** 물론 **데이터는 분리하여 계산**되어야함.」

- 그리기 경로는 **이미 같음** — C군 벽은 `attachWallSpecs` 로 `section.revetment` 에 붙어
  기슭막이와 같은 기하를 탐(따로 그리지 않음). 형태 이름도 「찰/콘크리트」 글자로 갈려
  흙막이 선택지(돌(찰)·돌(메)·떼…)가 그대로 먹힘
- 빠져 있던 것은 **옵션 칸**이라 기슭막이 열두 칸을 **같은 글자 그대로** 옮김 —
  단 수 · 올림 · 이동 · 뒷길이 · 돌 종류 · 조달 · 야면석 계수 · 채움 강도 ·
  전면 기울기 · 기초 · 물빼기 구멍 둘
  ⚠ 흙막이 수량이 안 쓰는 칸도 **숨기지 않음**(사용자가 「동일하게」라 함) — 수량 쪽에서
    조용히 무시되면 됨
- ⚠ 코드에 **「형상 동일 ≠ 수량 동일」**을 못 박음. 원단위·공종코드·성분 줄은 흙막이 자기 것.
  반대 사례가 골막이임(그림도 수량도 다르고 두께식마저 다른 식) — **계열이 다르면 상수를
  나눠 쓸 것**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
실무 원본 횡단도에는 그 자리가 **아예 없음**(400dpi 실측, 다른 창 확인) —
납품 양식을 늘리는 것이 아니라 **안 쓰던 빈 줄을 쓰는 것**임.

- 우측 그룹의 빈 줄 자리에 「사토장」 신설 (`spoil_fill`)
- 값은 B06 이 낸 `spoil_fill_area_m2` 를 그대로 옮김 — 여기서 더하거나 빼지 않음
  (`fill_area_m2` 에서 이미 빠져 있음 · 확정 ㉠ 같은 흙을 두 번 세지 않기)
- 사토장이 없는 측점은 값이 안 실려 종전처럼 빈칸

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 채움콘크리트 계수가 돌 종류로 갈리는데(깬돌 0.2 · 야면석 0.15) 근거 문구에
  종류가 안 적히던 자리 — 값은 바뀌는데 왜 바뀌었는지가 화면에 안 보였음.
  고임돌은 이미 적고 있었으므로 같은 규칙으로 맞춤.
- 병합 해결 과정에서 골막이 두께식 주석 두 줄이 한 줄로 붙은 것 복구.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠⚠ **차단인지는 `blocked_kind` 가 정한다 — 문구가 아니다.**
배수관 다섯 줄이 `blocked_kind=None · in_bill=True` 인데도 **사유가 있다는 것만으로**
막혀 금액이 안 서고 있었음. 그 사유는 차단이 아니라 **주의 문구**였음 —
「관종을 안 정해 기본값(파형강관)으로 섰습니다」.
⇒ 사유만 온 줄은 **금액을 세우고 그 문구를 곁말(ⓘ)로** 닮. 차단 표시가 붙은 줄은 그대로 막음.
ⓘ 오늘 두 번째 같은 병임 — 아침엔 겹침 설명을 `blocked_reason` 에 넣었더니 막힌 줄로 읽혔음.

⚠ 그리고 막힘이 풀리자 **다음 벽**이 드러남 — 관부설 12-11 표를 한 줄도 못 읽고 있었음.
그 표는 **규격이 열**(∅800·∅1000·∅1200)이고 값이 **나눗셈 식**(「0.62/2.5」 = 관 2.5m
한 개당 0.62시간 ⇒ m 당 환산값)임.
- `match_spec_column_table` 신설 — 첫 줄이 규격 이름만 늘어선 표일 때만 내 표로 봄
- 「0.016/2.5/2」처럼 겹친 나눗셈도 읽음 · 값이 빈 칸(기초콘크리트·거푸집)은 건너뜀
- 관경마다 갈래가 섬. B08 이 「Ø800」으로 보내도 「∅800mm」 갈래에 붙음

결과 — 배수관 네 줄이 처음으로 금액이 섬
  Ø1000 10m × 10,903.7 = 109,037 · Ø800 11m × 10,973.0 = 120,703 ·
  Ø800 9m ×2 = 197,514  ⇒ 합 **427,254원**
  본체 31,118,251 → **31,545,505원**
  ⚠ Ø1500 은 품셈 표에 그 관경이 없어(800·1000·1200) 그대로 막힘 — 후보만 보임

검증: pytest 307 통과(신규 4) · 자원 축 547 → 565 줄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠⚠ **깨진 시험의 뿌리는 칸이 아니라 자리였음.** 정책 시험은 `tmp/tests` 라 **git 밖**이라
정본(추적됨)만 다른 창에 가고 예외 목록(추적 안 됨)은 안 따라감 ⇒ **다른 창에서만 깨짐.**
오늘 그 일이 두 번 났음. ⇒ **까닭을 값 옆(정본)에 두어 함께 움직이게 함.**

- 스키마에 칸 둘 신설
  · `empty_means` — **「비워 두는 것이 뜻인 칸」**(세 번째 갈래). 비면 계산 쪽이 기준값으로
    돌고 그 사실이 화면에 뜸. 값을 넣으면 그 값이 이김
  · `default_basis` — 기본값이 **도메인 확정값이 아닐 때** 그 뜻(「다단 없음」·「안 더함」).
    법정·확정 수치면 비워 둠 — 비어 있는 것이 「확정값」이라는 뜻
- 56곳에 까닭을 적음 — 전면 기울기 · 야면석 계수 · 채움 강도 · 비탈 기울기 · 물빼기 둘 ·
  개거 규격 · 뒷길이 · 돌 종류 / 단 수 · 올림 · 이동 · 조달 · 설치 측 · 추가 운반거리
- 정책 시험이 그 칸을 읽게 바꿈 + 까닭이 한 낱말이면 잡는 시험 둘 추가

⇒ 앞으로 등록부에 칸을 열 때 **예외 목록을 고치지 말고 까닭을 값 옆에 적을 것.**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
정본 여섯 탭 전수 확인 구간이 H=1.0~3.0 인데 코드가 높이를 막지 않고
표준경사표는 직고 7m 까지 칸을 준다 — 높은 벽이 실제로 설 수 있음.
그 구간에서 막자갈 두께(= 물량 ÷ 비탈면적)가 0.375 ÷ √(1+경사²) 로 거의
붙박이라, 직고와 함께 두꺼워지는 품셈 13-4-4 [주]⑨ 범위보다 얇아짐
(H 3.0 0.359 안 · H 3.5 0.354 아래). 방향이 반대라 값만 보면 안 드러남.

값은 정본 식대로 세우고 막지도 눅이지도 않음 — 근거 구간 밖이라는 사실만
사유로 냄. 큰돌쌓기는 막자갈 줄 자체가 없어 이 갈림이 안 번짐.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TS 짝이 2026-09-04 에 이미 이 선으로 갈라 두었음(`common_util_cross_design_geometry.ts`).
**새로 긋는 선이 아니라 TS 에 있던 선을 파이썬에도 그은 것**이라 거울이 안 깨짐.

- `_SectionGeometry` + `_side_role`(TS `sideRole`) → `…_Engine_Design_Geometry.py`
- 안 옮긴 것 — 측구 방향 해석 · 지반 보간 · 사면 폐합 허용오차. **TS 도 본체에 둔 것들**
- 계산은 **한 줄도 안 바꿈**. 옮기기만 함

검증 — 거울 시험(횡단 설계선·단면적 두 쪽 대조) 통과. 전체 610 통과 / 22 건너뜀.
남은 것 — ② 표준값 해석·저장분 읽기 도우미 분리(522줄이라 급하진 않음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 표토제거: 대상 면적 0 ㎡ 에 0 ㎥ 를 「값 있음」으로 내고 있었음. 0 은 「없음」과
  구별이 안 되고 받는 쪽이 「표토가 없는 노선」으로 읽음. 두께 미입력은 이미
  막고 있었는데 면적 0 만 통과하던 자리. 운반 줄은 제거를 밑수로 삼아 함께 막힘.
- 표토 대상 면적이 별표2 문언과 두 방향으로 어긋남 — 법은 「노면·절토대상지」인데
  우리는 절토·성토 사면적을 다 더하고 노면(연장 × 노폭)은 안 셈. 성토대상지는
  별표2 (7) 이 「제거·정리」로만 두어 운반·적치 의무를 안 검. 값은 그대로 두고
  사유로만 드러냄 — 실무 확인 사항이라 임의로 확정하지 않음.
- 비탈 규준틀 재료량이 「수평 값 준용」인 사실이 상수 주석에만 있고 화면 근거에는
  없었음 — 값이 서면 어디서 온 값인지 안 보이던 자리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「품셈 표에 그 관경이 없음」만 적으면 사용자가 **엉뚱한 것을 정하러 감** — 정할 것이
단가가 아니라 **시설 선택**일 수 있음.

- 관부설 품셈 표가 다루는 관경은 ∅800·∅1000·∅1200 뿐임을 사유에 적음
- Ø1,500 이상이면 임도기술교본 3장을 가리킴 — 「BOX암거 적용 — 수리계산상 배수관
  **Ø1,500㎜ 이상** 적용 유역」(`횡단배수관_암거 §5`)
- ⚠ **단정하지 않음** — 그 §5 는 **교본 기준이지 법령·행정규칙이 아님**. 프로젝트 규칙이
  「기본값은 현행 법령·행정규칙, 교본은 과거 참조」라 **가리키기만** 하고 사유에 그 사실을
  함께 적음

검증: pytest 307 통과 · Ø1500 두 줄에 그 문구가 뜸

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
배수관 네 줄이 금액으로 섰으나 그 값은 **인력 품만**임 — 파형강관·커플링밴드·
크레인(5ton)·모래부설이 아직 안 붙음. 까닭이 둘로 갈림:
  · 관·모래 — 원문이 「별산」·「설계수량」이라 한 자리
  · 크레인 — 기계 카탈로그에 없음(9-9 목록에 올림)

 원문을 대조하다 **숨은 값** 하나 나옴 — 커플링밴드는 표가 비었으나 [주]① 이
「**1EA/6m**」를 줌. 자재가 서면 m 당 1/6 EA 로 셀 수 있음(「필요시 별도 산정」 조건 하나 더).

ⓘ 원문 특이점도 계획서에 적어 둠 — 배관공이 ∅800 0.25 · ∅1000 **0.22** · ∅1200 0.41 로
**가운데만 작음**. 크레인·보통인부는 관경이 커질수록 늘어남. **원문 그대로라 손대지 않음.**

검증: pytest 307 통과 · ∅800 0.25/8.0 = 0.03125 로 열 순서가 맞음을 원문과 대조

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ **시험만으로는 안 잡히던 자리임.** 실제 프로젝트에 사토장을 놓고 눈으로 본 뒤 잡음.

① **사토장을 지워도 값이 남음** — `enforce_spoil_fills` 가 **얹기만** 해서, 구조물을
   지운 뒤에도 저장분의 `spoil_fill_*` 가 그대로 남아 횡단도에 계속 그려지고 면적표에도
   섰음. ⇒ 사토장이 덮지 않는 측점에 **값이 남아 있으면** 사토장 없이 다시 계산해 지움.
   노선 성토도 그때 원래 값으로 돌아옴(사토장 몫을 빼 두었던 것이 복구됨).
   ⚠ **칸이 있는 것과 값이 있는 것은 다름** — 설계 결과는 사토장이 없어도 `0.0` 을 늘
     실으므로 「값이 남은」 측점만 되돌림(`_has_spoil_value`)
② **말풍선에 늘 뜨던 가짜 경고** — 「⚠ 0.0㎥ 는 못 담음」. 폭을 이분법으로 찾아
   400 − 399.9937 = 0.0063 이 남는 것이라, 표시 자릿수에서 안 보이는 몫은 경고 안 함

실측(프로젝트 fa76c162) — 지운 뒤 사토장 0 · 용량 null · 노선 성토가 정확히
「지우기 전 + 옮겨 갔던 몫」으로 복구됨(100m 1.7563+4.9217=6.678 …).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
원문·실무 대조에서 나온 것:
- 품셈 9-15-2(답외구간) 원문에 T(표토두께) 0.2m · L(운반거리) 20m 가 적용값으로
  박혀 있음. 종전 사유 「품셈이 정하는 값이 아닙니다」가 반쪽이라 정정 — 값을
  자동으로 넣지는 않되 원문에 있는 값을 없다고 말하지도 않음.
- 그 품에 20m 압토가 이미 들어 있음. 실무 내역서(영월 2024)도 「표토제거 답외구간
  / M2 · 도자 19Ton · D=20」 한 줄뿐이고 운반 줄이 따로 없음. 우리 운반 줄은
  20m 를 넘는 몫일 때만 새 줄인데 그 가름을 아직 안 함 — 사유로 남김.
- FP-10-12(덤프 운반)은 부모 코드라 품이 없음. 잎은 토사/암절취/발파암이고
  갈래를 안 보내면 B09 가 후보만 보이고 금액이 안 섬. 표토는 토사이므로
  variant_axis=ground_class · variant_value=토사 로 실어 보냄. 준비공 줄이
  갈래를 넘길 통로도 함께 엶(종전에는 늘 None).

파일 분리(700줄 제한):
- 부대시설 다섯 줄을 _Preparation_Ancillary 로, 상태 낱말을 _Preparation_Status 로
  가름. 상태 문자열은 받는 쪽 판정에 쓰이므로 두 벌이 되지 않게 한 벌만 둠.
  710줄 → 622 + 113 + 16.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
777줄이던 _Handoff_Rows 를 565 + 255 로 가름. 줄의 모양은 안 바뀜 —
갈라낸 넷을 본체에서 다시 내보내 부르는 쪽 import 도 그대로임.
상태 낱말은 _Preparation_Status 한 벌에서 읽음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 레지스트리 이름이 없으면 내역 줄 이름에 코드값이 그대로 떴음(`retaining_wall`).
  _Wording.type_label 이 이미 대비표를 들고 있으므로 그것을 씀 — 이제 「옹벽」으로 섬.
- 관측 원단위로 가는 구조물은 표에 터파기 줄이 없으면 그 구조물만 조용히 빠졌음.
  옹벽이 터파기 0 줄인데 사유도 안 났음(돌쌓기는 세 줄이 섬). 값을 지어내지 않고
  「터파기가 안 선 구조물」 줄을 in_bill False · blocked_kind unit_data_missing 로
  세워 빠졌다는 사실이 보이게 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
랩탑 메인이 화면에서 잡음: 「측구터파기 · 굴삭기+브레카」가 work_item_code null
인데 blocked_kind 도 null 이라 아무 말 없이 금액만 빠졌음.

인계본의 bill_flag_warnings·unmatched_work_items 에는 이미 실려 있었음 —
목록은 있는데 줄에 표시가 없었던 것. 줄 단위로 보는 쪽(B09·화면)은 목록을 안 봄.
같은 모양이 여덟 줄이었음(흙깎기·측구터파기·도자운반 둘·덤프운반 둘·지장목제거·큰돌쌓기).

- 토공 줄: 코드가 없으면 시공법 미지정이면 input_missing, 매핑을 못 이었으면
  unit_data_missing 으로 갈라 답. 다음에 할 일이 다름(사용자 입력 vs 매핑 작업).
- 운반 줄: 같은 규칙. 무대(free_haul)는 품에 포함이라 안 세우는 것이지 막힌 게
  아니므로 표시를 안 답.
- 불변식 시험을 세움 — 코드도 막힘 표시도 없이 내역에 서는 줄이 하나라도 있으면 깨짐.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠⚠ 한 칸(`ditch_enabled`)에 **두 뜻**이 담겨 있었음.
결과(실제 섰나)를 그대로 다시 입력으로 넣어 읽었으므로 **한 번 저장되면 자동 판정이
영영 다시 안 돌았음.** 계획고를 내려 절토가 생겨도 측구가 안 서고 **아무 말도 안 나왔음.**

- **선택** `ditch_choice` (없음 = 자동) · **결과** `ditch_enabled` (실제 섰나)로 가름
- 자동 판정을 **먼저** 하고 선택을 그 위에 얹음. 양성 단면은 선택보다 기하가 먼저
- ⚠ **옛 저장분은 자동값과 다를 때만 선택으로 살림** — 같으면 자동이 그렇게 냈던 것이고
  다르면 사용자가 일부러 바꾼 것임. 설계 의도를 잃지 않으면서 굳은 값을 푼 것
  (오늘 `length_m` 에서 겪은 「저장분이 걸린 자리」를 같은 방식으로 처리)
- 화면 카드는 이제 **선택**을 읽어 상태를 세우고, 표시는 **결과**를 보임
- 파이썬·TS 짝 양쪽 + 호출부 여섯 곳(재계산·저장·확정·사토장·요청 스키마)

시험 다섯 추가 — 「결과를 다시 넣어도 자동이 계속 돎」이 그 잠금. 전체 616 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
물넘이포장이 면적을 못 받아 「0.0 ㎡」로 내역에 서고 있었음. 코드가 붙어 있어
0 원 줄이 만들어지고 화면에는 값이 있는 줄로 보임 — 0 은 「없음」과 구별이 안 됨.
줄은 그대로 넘기되 in_bill False + 까닭(원단위 사유 그대로) + input_missing 로 둠.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 토글이 **2단**이라 「자동으로 되돌리기」 단추가 없음. 되돌리려면 원래 값으로 다시
누르는 수밖에 없는데, 그것을 선택으로 굳히면 **방금 고친 병이 그대로 되돌아옴**
(지형이 바뀌어도 안 따라감).

⇒ 선택이 자동값과 같으면 **선택 없음(자동)** 으로 본다. 파이썬·TS 짝 양쪽.
시험 하나 추가 — 「자동과 같은 선택은 자동으로 푼다」. 전체 617 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 5차 6번 「제근 밑수 — 면적 축. 건설품셈 3-9-2 「1,000㎡당」을 빌려 씀」.

- `WorkItemUnit.BORROWED_UNITS` 신설 — **사용자가 정한 자리만** 담음. 우리가 골라 채우는
  표가 아님. 값과 **근거 문구를 한 자리에** 둠(⚠ 교차 참조 표시 — 임도 전용 품이 있는데
  건설품셈을 쓰는 것이라 화면이 그 사실을 밝혀야 함)
- ⚠⚠ `BORROWED_BASIS_PER` — **「1,000㎡당」이라 ÷1,000 환산**. 단위만 「㎡」로 달고 값을
  그대로 두면 **금액이 천 배**가 됨. 단위와 배수를 한 자리에 두고 시험으로 못 박음
- ⇒ 제근 여섯 갈래에 밑수가 붙어 단가가 섬 — 굴착기 0.7㎥·소림 **55.4원/㎡**

⚠ **자릿수가 견준 값과 어긋남을 사유에 함께 적음** — 실무 영월 「뿌리뽑기」는 475원/㎡ 이고,
빌려 온 3-9-2 는 같은 1,000㎡당에 굴착기(0.2㎥) 3.76hr 로 산림품셈 9-21 의 0.80hr 보다
4.7배 큼. **100㎡당으로 보면 실무와 자릿수가 맞음.** 값은 확정대로 두고 **어긋남을 보임** —
지어내지도, 조용히 넘기지도 않음.

검증: pytest 311 통과(신규 4)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 20 commits 2026-09-09 20:43:26 +09:00
상시계획서에 남아 있던 완료된 조사·근거 원문을 검증 폴더로 옮김.
계획서에는 결과만 남기고 경로 인용도 두지 않음 (2026-09-09 사용자 확정).

계획서 1,841줄 10.5만 자 → 1,166줄 6.5만 자 (-38%).
미체크 항목 53건 그대로 — 살아 있는 일감 손실 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 판단으로 계획서에서 뺀 것 — 원문 그대로 보관.

- 공통기반 0-5·0-7 : 행동지침 5장(계산 자리·데이터 3층)과 겹침
- 8-33            : 창별 검증 프로젝트 표는 OWNERS.md 자원 점유로, 나머지는 여기
- 참고 절 셋       : 데이터 세트 정의는 지침과 중복, 구조물 구현 기준·계곡 통과
                    시설 선정은 옛 자료

계획서 1,167줄 6.4만 자 → 1,058줄 5.9만 자.
미체크 53 → 57 (0-8 고칠 순서 셋 · 투영 이월 하나를 체크박스로 세움).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`spoil_bank.side` · `extra_distance_m` 은 정본에 `default_basis` 로 까닭이 적혀 있어
목록 없이도 통과함(빼고 돌려 확인). **앞으로도 목록에 넣지 말 것**을 그 자리에 적음.

⚠ 같은 상태인 것이 **13 개 더 있음** — `revetment`·`soil_guard`·C군 `side` 계열.
  빼도 통과하나 이번에는 안 건드림(주석 덩어리가 얽혀 있어 잔손질 범위를 넘음).

`resources/tester/` 1183 통과 / 22 건너뜀 / 실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
창끼리 같은 위키를 찾게 그래프 본체 여섯만 추적 (합쳐 120KB).
위키화 뒤 `git sync` 한 번이면 문서와 그래프가 함께 옴.

- `.gitignore` 40행 `graphify-out/` 에 `/` 가 없어 docs/wiki/graphify-out 까지
  같이 막고 있었음 (`git check-ignore` 로 확인). 뿌리에만 걸도록 고침
- 날짜별 산출물 13MB · `.graphify_python`(PC 별 경로) · `.graphify_root` ·
  `.graphify_incremental.json`(이 PC 절대경로가 박힘) 은 계속 제외
- `.gitattributes` — 줄끝 변환을 끔. 바꾸면 서명(.sig)이 깨지고 창마다 헛 diff 가 남음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
날짜별 산출물까지 통째로 실어 창끼리 같은 위키를 보게 함. 374 파일 13MB.

PC 마다 값이 다른 둘만 제외 —
  `.graphify_python`            이 PC 파이썬 실행 경로
  `.graphify_incremental.json`  이 PC 저장소 절대경로가 박혀 있음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PLAN 9-6 · 8-32 두 잔손질.

① 미공표 직종 신뢰도 플래그 (9-6)
   지식DB 가 「단가 채택 시 플래그 유지 필요」(노임단가_적용 §2-3) ·
   「해당 단가 사용 시 경고 표시」(원가_입력변수_사전)로 두었는데 노임 층에 없었음.
   - load_labor_reliability() — 원문 기호 `*`(조사현장 5개 미만)·`**`(미조사) 그대로.
     정상 공표 직종은 아예 안 담음(빈 값과 「정상」을 구별할 일이 없게).
   - PriceTitle.reliability — 노임 제목 전부 + 조종원 줄에도 같이 붙임.
   - build_summary 의 labor_reliability → 화면 힌트 줄로 경고.
   ⚠ 금액을 막지 않음 — 값은 그대로 서고 「조사현장이 적다」는 사실만 나름.
   ⚠ 내역에 실제로 실린 것만 경고 — 카탈로그 40직종을 다 띄우면 쓰지도 않는 직종이
     화면을 채움. 실측 둘: 1037 벌목부 · 1050 일반기계운전사(지식DB 예시 그대로).

② 층따기 사전 밑수 (8-32)
   원가_출력변수_사전 B2-9 가 「㎡·m」였음. 품셈 9-18 은 ㎥ 당이고, 우리도 확정 2차 ①
   로 면적이 정본이되 길이를 곱해 ㎥ 로 내보내고 있음. 두 축을 한 칸에 적어 ㎡ 로
   내도 되는 것처럼 읽히던 자리 — 밑수를 ㎥ 로 고치고 까닭을 비고에 적음.
   코드는 이미 ㎥ 로 내보내 수치 변화 없음.

시험 여섯 신설 · 전체 1182 통과 · 실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
두 PC 가 각자 `graphify update` 를 돌려 같은 이름으로 다른 그래프를 냈음.
그래프는 만들어지는 물건이라 내용을 합칠 것이 아니고, 랩탑 것이 최신·전체라 그쪽을 취함
(CLAUDE.md 6장 「같은 자리를 서로 다르게 고쳐 부딪히면 랩탑 쪽」).

  2026-09-09/graph.json 796KB → 906KB · graph.html 845KB → 985KB
  + .graphify_analysis.json · .graphify_labels.json · cache/stat-index.json

곁들여 되살린 것 —
  B08_Quantity/0_old_260726_codex.zip 이 랩탑 `auto:` 커밋에 삭제로 실려 있었음.
  랩탑이 지운 것이 아니고 이 PC 파일이 이력과 해시까지 같아, 시놀로지가 랩탑 쪽에
  파일을 못 놓은 자국으로 보고 되살림. 지우기로 정하면 한 줄로 다시 뺄 수 있음.

⚠ 남은 것 — 두 PC 가 다 위키화를 돌리면 이 충돌이 되풀이됨. 만드는 곳을 한 곳으로
   모을지 사용자 판단 대기.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정 5차 작은 것 1 「지금은 안 넣되 숫자 넣으면 되게 열어 둘 것」.
근거는 산림품셈 1-2-6 — 주재료비(할증수량 제외)의 2~5%까지, 산정 근거 명시.

- 기초자료 탭 「산출 조건」에 칸 하나 + [적용]. 비면 줄 자체가 안 섬(지금 상태 그대로).
- 밑수는 **자재 줄만** — 노무·경비, 하위 일위대가 재료비는 안 듦(층마다 거듭 세지 않음).
- 상한 5% 초과는 거절(400) — 조용히 깎아 넣지 않음.
- ⚠ 지금은 일위대가에 주재료비가 선 공종이 0개라 붙을 밑수가 없음 — 그 사실을 칸 밑에 띄움.
- 곁다리: 비율 줄(제잡비·공구손료)이 저장했다 읽으면 사라지던 것을 고침.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 사용자가 누른 선택(`ditch_choice`)과 자동 판정 결과(`ditch_enabled`)를 다른 칸으로 나눔.
- 캐시(`CrossDesignChoice`)에 칸이 없어 토글이 화면에서 안 돌던 자리 이음 —
  선택이 있으면 그것을 따르고, 없으면 저장분 결과를 자동값과 다를 때만 선택으로 살림.
- 서버 patch 스키마에도 같은 칸을 둠. 최상위 `None` 은 병합에서 걷히므로
  「자동」으로 되돌리는 길은 아직 없음(카드 토글은 켬/끔 둘뿐이라 지금은 손해 없음).

화면 실측(카드에서 껐다 켜기)은 PLAN.md 3-16 에 미체크로 남아 있음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
화면 실측에서 토글이 안 돌던 까닭이 「칸 하나 빠짐」이었음 — 통로 어느 한 곳만
빠져도 눌린 값이 조용히 사라지므로 네 파일을 함께 지킴. patch 병합이 「끔」(False)을
걷지 않는 것도 함께 봄.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 35 commits 2026-09-10 06:11:42 +09:00
옛 문구가 영어 한 줄("unresolved source gap")이라 무엇이 없어 미뤄졌는지 안 보였음.
지금 사실대로 적고 받아야 할 자료(실무 구조물 일람표)와 지식DB 근거 자리를 함께 붙임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「동바리 대상 없음」은 옹벽·집수정을 세어 보고 하는 말인데, 셀 구조물이 하나도
없어도 뜨고 있었음. 화면 조건에 구조물 수를 함께 봄 — 서버 값·금액은 안 바뀜.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
품셈 8-1-7 5호 「유류가격은 해당지역의 가격으로 한다」. 칸은 있었으나 시도별 값이
없어 잠겨 있었음. 오피넷 avgSidoPrice.do 스냅샷을 받아 데이터셋으로 세우고 물림.

- 안 고르면 전국평균 그대로 — 현장 소재지를 임의로 찍지 않음.
- 판에 없는 지역은 조용히 전국평균으로 눕지 않고 사유를 남김.
- 「지역 공시가」를 고를 수 있는지는 코드가 아니라 판이 정함.
- ⚠ 원천의 시도 가름이 행정구역과 다름(20=전남광주 한 줄, 07·16 없음) — 원문 그대로 둠.
- 수집 스크립트에 시도별 호출을 더함(전국평균과 두 벌로 보존).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
확정 2차 ② 후반 「사용자가 값을 바꿀 수 있게」. 식은 이미 있었고 없던 것은 덮어쓸 칸이었음.

- 등록부(돌쌓기 계열 다섯 종류)에 `thickness_top_m`·`thickness_bottom_m` 칸을 둠.
  큰돌쌓기는 두께 식이 달라 뺐고 화면에서도 그 장에는 안 뜸.
- 빈 칸은 「안 정함」 — 자동값을 저장에 박지 않음. 상부만 넣으면 하부는 그 위에서 식을 이음.
- 근거 문구가 어디서 온 값인지 적음(「사용자 입력」 / 「뒷길이 45㎝ + 0.3」).

화면 실측(랩탑_보조, 표준도 3장 돌쌓기(찰)) — 0.60 넣고 저장하니 2개소 반영,
입적 24.375 → 20.625㎥ 로 움직였고 칸을 비워 되돌리니 24.375 로 복귀함.
시험 다섯 추가, 전체 1203 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
요율 숫자만으로는 그 데이터를 보고 금액을 되짚을 수 없었음. 밑수를 무엇으로 잡고
어떻게 자르는지가 코드에만 있어, 데이터를 갈아 끼운 사람이 규칙이 바뀐 줄 모름.

- 빠져 있던 밑수 한 칸(건설기계대여대금 지급보증수수료)을 채움.
- 처리 규칙을 데이터에 실음 — 자르는 법(줄 버림·관급자재대 천원 올림) · 안전관리비
  A·B 두 식과 1.2·1.1 · 조달수수료 차감 없음 · 이윤 밑수 · 규모 구간 판정.
- 거울 시험 6개 — 한쪽만 바뀌면 멈춤. 금액은 안 바뀜(1208 통과·실패 0).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⚠ 잡은 자리(2026-09-09 실측) — 표준단면 「측구 상폭」을 0.69 → 0.9 로 고쳐 저장했더니
정본 한 줄에 **새 측구 기하(상폭 0.9 · 측구 0.18㎡)** 와 **옛 절토 면적(3.33㎡)** 이 섞여
남았음. 브라우저는 만진 측점만 다시 계산하는데 저장은 전 측점 면적을 실어 보내므로,
안 만진 측점이 옛 값 그대로 정본이 됨. 수량이 갈리는 자리임.

- [저장]·[확정]이 면적을 모으기 **전에** 전 측점을 다시 계산함(`reconcileDesigns`).
- 표준단면 패널에 「고친 값이 측점에 아직 안 실렸음」 알림 — 언제 따라오는지 함께 적음.

 거울(파이썬·TS) 문제가 아님을 먼저 가름 — 같은 입력을 주면 두 쪽이 같은 값을 냄
(측점 20.0m: 0.69 기준 절토 3.328 · 0.9 기준 3.899, 저장분은 3.328 + 측구 0.180 으로 섞여 있었음).

시험 둘 추가(저장·확정이 재계산을 먼저 부르는지), 전체 1205 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
물량은 인계로 오는데 단가가 없어 성토 13,150.2㎥·성토면다짐 12,350.3㎡ 가 금액 없이
서 있었음. 원문에는 값이 다 있고 막힌 까닭만 서로 달랐음.

- 노체포설(9-16-1): 기종이 [주]에만 있어 못 골랐음 → 흙깎기와 같은 장비 칸을 둠
  (무한궤도 굴착기 0.7㎥, [주]① 그대로. 화면에서 바꿀 수 있음).
- 비탈면 다짐(9-17-1): 표가 한 장도 없고 값이 절 제목에 있음(A = 77.7 ㎡/시간)
  → 제목·[주]에만 있는 작업량을 싣는 자리를 두고 원문 문구를 줄에 남김.
- 부착 콤팩터(0240-0007)는 카탈로그에 이름이 비어 있어 손료가 안 붙고 있었음 —
  이름 대신 분류번호로도 가림(조합 사용 넷은 그대로, 목록을 넓히지 않음).

금액: 성토 59,477,858원 · 성토면다짐 17,827,251원 (합 77,305,109원)이 새로 섬.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 0-5(세트 통짜 배선)는 아직 못 함 — 까닭 ①(관 지점을 B06 이 못 받음)은 풀렸으나
②(폼 → 조정창 되받기 · 형태별 높이 한계 되돌리기)가 그대로임. 억지로 갈지 않음.

대신 폼 칸 20개를 캐시 경로와 대조해 빠진 칸 셋을 찾음.
- `revet_foundation` — 그리기가 읽는 값(터파기 파선)인데 안 옮겨 적고 있었음. 이어 붙임.
  ⚠ 화면 실측은 못 함 — 상세 단계 칸이라 B06 배치 폼에 아직 안 뜸(정본도 전부 비어 있음).
- `inlet_basin_form`·`inlet_basin_material` — 수량 전용이라 캐시에 안 실어도 됨(사유를 시험에 적음).

시험 둘 추가 — 새 폼 칸이 캐시 경로에서 빠지면 잡음. 전체 1207 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
기계경비 = 기계손료 + 운전경비 + 수송비인데 수송비가 없었음. 수송비를 내는 공종
FP-10-04 중기운반은 표가 미판정이라 단가가 아예 안 섰음.

- 산림품셈 10-4 사이클 그대로 — 트레일러(20TON) t1=20·t3=20·t4=0.42 /
  트럭(10.5TON) t1=10·t3=10·t4=5 · ㎝=t1+t2+t3+t4 · N=60×0.9/㎝, 단위는 회당.
- 거리·도로 구분은 설계 입력 — 비면 줄이 안 서고 사유만 남음(임의 거리 금지).
- 원문이 「-」로 둔 칸(트레일러·고속4차선)은 지어내지 않고 사유로 냄.
- ⚠ 우리가 정한 둘을 화면 근거에 적음 — 속도를 8-1-6의 2 나 이동속도표에서 가져온 것,
  운반시간을 왕복으로 본 것.
- 곁다리: 운전경비 표가 페이지에서 잘려 앞자리를 못 이어받아 39 기종이 통째로
  버려지고 있었음(그 안에 수송 차량 2702 가 있었음). 이어받되 카탈로그에 있는
  코드일 때만 받게 함 — 운전경비 줄 92 → 158.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
산림품셈 1-4 가 26표로 품을 할인·할증하는데 한 계열도 안 붙고 있었음(자재 할증만 있었음).

- 붙는 자리 = 일위대가의 품(인력) 줄. 물량에 곱하면 자재·기계까지 부풀어 이중계상임
  (원문 제목이 「품의 할인·할증」이고 1-6 라 표가 직접노무비를 품셈으로 냄).
- 기본은 「안 고름」 — 한 계열도 안 고르면 금액이 한 원도 안 움직임.
- 각 계열에 [주] 원문을 그대로 띄움 — 26계열의 [주] 가 대개 조림·숲가꾸기·방제를
  지목하고 임도 토공에 붙이라는 지시가 원문에 없어, 켜는 것은 사용자 판단임.
- 여럿 고를 때 합산인지 곱인지 원문에 없음 — 합산으로 두되 한 곳(COMBINE_RULE)에서
  갈아 끼울 수 있게 하고 그 사실을 화면 근거에 적음.
- 품이 늘면 제잡비 밑수도 함께 늘도록 줄 차례를 지킴(할증 줄이 제잡비보다 먼저).
- ⚠ 율 표는 24개임 — 1-4-24(장비품의 -20%)·1-4-26(적용시공량 규칙)은 성격이 달라 뺌.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 0-8 의 남은 하나. 서버는 분석이 도는 동안 새 자료를 이미 막고 있었고
(`is_analysis_running`), 없던 것은 **막힌 까닭을 사람에게 보이는 것**이었음.
여럿이 한 프로젝트를 보면 「왜 안 올라가지」가 됨.

- 분석을 띄우는 **경로 넷 모두** 시작한 사람을 `params.started_by` 로 담음.
- `analysis_lock_owner` 가 그 id 로 이름을 붙여 냄 — 옛 자료는 id 가 없어
  **이름 없이 잠금만** 돎(막는 것이 먼저).
- `/upload-overview` 응답에 `analysis_lock` 을 실어 B03 화면이 띠로 보임.

화면 실측 — 「엄상돈 님이 올린 자료를 분석하는 중입니다」 띠가 경고색으로 뜸(응답을
잠깐 가로채 확인하고 곧바로 되돌림). 지금 도는 분석이 없어 실제 잠금 화면은 다음 업로드 때 볼 것.
시험 넷 추가(도는 중 아님·이름 붙음·옛 자료·경로 넷 대조), 전체 1211 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Q = 1000 × V × W × E × D × f / N 로 서는 첫 공종. 계수 여섯은 표에 다 있고 기종만
[주]에 있어 마스터가 못 싣던 자리.

- 롤러만 듦 — [주]③ 의 「굴착기와 진동롤러 조합」은 포설(9-16-1)과 다짐을 함께 쓰라는
  뜻으로 읽음. 이 줄에 굴착기를 또 넣으면 포설에서 센 굴착기를 두 번 셈.
- 계수가 하나라도 없으면 안 섬 — 채워 넣지 않음.
- 조건([주]⑤ 대규모 성토지 층다짐)과 기종 근거를 줄에 남김.
- ⚠ 인계에 그 줄이 없어 금액은 아직 안 섬 — 층다짐을 셀지는 설계 판단(사용자 확정 대기).
  넣으면 13,150.2㎥ × 527.40 = 6,935,414원.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 4-13. 소광리 `07-구조도-소광리.xlsx` 다섯 탭의 **개소당 소계를 그대로** 옮김
(Ø800 A·C · Ø1000 A·C · Ø800 A+집수정). 비례로 늘리지 않음 — 그 규격에서만 맞는 값임.

- 원단위표에 다섯 줄 추가. 거푸집 종류가 탭마다 갈려 이름을 뭉개지 않음 —
  Ø800 A·C 는 **유로폼**, Ø1000 과 A+집수정은 **합판거푸집(4회)**.
- ⚠ 철근·면목 줄은 원본 날개벽 탭에 **없음**(집수정구조도 탭에만 있음). 지어내지 않음.
- 등록부·배치 폼에 「관보호공 날개벽」 칸(A-TYPE·C-TYPE·A-TYPE+집수정). 비우면 안 셈.
- ⚠ 겹쳐 세는 자리 — 「A-TYPE+집수정」은 집수정을 품은 형식이라 집수정 형식도 차 있으면
  **사유로 알림**(값은 안 고침). 원단위표 `double_count_rules` 와 짝.

ⓘ 집수정 Ø800 은 **이미 표에 있었음**(`pipe_inlet_basin` □형·콘크리트·800) — 다시 만들지 않음.
화면 실측 — 배수관 폼에 칸이 뜨고 선택지 셋 확인. 엔진 실행으로 날개벽 줄이 따로 서고
터파기 13.104 · 콘크리트 2.0595 · 유로폼 12.5376 이 나오는 것까지 봄.
시험 일곱 추가, 전체 1218 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
내역에 실리는 25 줄 중 FP-11-01 가설창고만 밑수가 없어 대조를 건너뛰고 있었음.
품셈 11-1 은 절 머리에 「(단위: …)」가 없어 마스터가 못 채우는 자리라, 매핑에
원문 근거와 함께 「개소」를 적어 통로로 채움([주]① 설치·해체 각각 · [주]③ 1개설치당).

- 매핑에 `ancillary` 절을 만들고 그 절도 밑수 대조에 쓰이게 함.
- 이제 내역에 실리는 25 줄이 전부 대조됨 — 일부러 m 로 보내면 가드가 잡는 것을 시험으로 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 0-2 「재계산 중간 취소」 재판정. **취소는 만들지 않기로 닫음.**
· 잰 값 — 서버 계측 네 번 87.3 · 90.0 · 93.9 · 95.4초(평균 91.7). 293초에서 이미 3분의 1.
· 취소가 「반쯤 부순 상태」를 만드는 단추가 됨 — 관 지점은 체인 **전에** 이미 지워지고,
  체인이 끊기면 노선만 새것·종횡단은 옛것으로 어긋남(2026-09-06 실측 사고와 같은 자리).
· 시간의 90 %가 배수·관·측점 재생성 한 곳이라, 급하면 취소보다 그 자리를 줄이는 것이 이득.

대신 대기 안내를 고침 — 「몇 분 걸립니다」 → 「1분 반쯤 걸립니다 (N초 지남)」로
**경과 시간이 1초마다 돎**. 멈춘 것인지 도는 것인지 사람이 알 수 있어야 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
별표2 (5)(가) 가 설계서 작성 순서를 열셋으로 못 박아 두었는데, 우리가 무엇을 내고
무엇을 못 내는지가 계획서에만 있었음. 원가계산에 「설계서 구성」 탭으로 세움.

- 법이 적은 차례 그대로. 줄마다 상태(있음·반쪽·없음)와 어디서 나오는지를 적음.
- ⚠ 「없음」과 「우리 몫 아님」을 가름 — 일반시방서·특별시방서·예정공정표는 현장을
  아는 사람이 쓰는 문서라 프로그램이 지어낼 것이 아님. 법이 목차를 정했다고 열셋을
  다 우리가 만드는 것은 아님.
- 못 내는 것에는 무엇을 받아야 내는지를 적음(공사설명서 = 서식·설계하중 표기).
- 사방사업은 목록이 다름(별표0 은 위치도·관계지적조서·설계도면을 더 둠)을 함께 적음.

⇒ 법이 정한 13 중 7 이 서 있고, 3 은 설계자·발주청 몫, 우리가 더 낼 것은 3
  (공사설명서 · 각종 중기경비계산서 · 산출기초).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
노체다짐과 식이 다름 — 롤러는 V·W·E·D·f/N, 콤펙터는 A·N·H·f·E/P.
원문이 답까지 적어 두어(「∙ = 4.26 ㎥/시간」) 표 계수로 셈한 값과 맞대는 시험을 둠.

- 표 칸에 단위가 붙어 오는 것(「0.09㎡」·「36,000회/hr」)을 수만 떼어 읽음.
- 기종은 절 제목이 정함(플레이트 콤팩터 1.5) — 표에 기종 칸이 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 V-8. 엔진이 일부러 화면 몫으로 남긴 자리(`_Handoff_Rows_Prep.py:182`
「표기는 만들지 않는다 — 측점 간격을 아는 화면 몫이다」)를 채움.

- 토적표가 쓰던 `stationLabel` 을 **내보내 같이 씀** — 두 벌로 만들면 같은 측점이
  화면 두 곳에서 다르게 적힘.
- 구간은 `start_m`·`end_m` 을 그대로 씀. `length_m` 이 그 구간의 합이라 두 값이 갈릴 자리가 없음.
- 값이 없으면 표기를 안 붙임(지어내지 않음).

화면 실측 — 「돌쌓기(찰) H=2.5 · L=10.0m · NO.4 ~ NO.4+10」(정본 80~90m)로 뜸.
시험 둘 추가(표기 함수 한 벌 · 구간은 구조물 값에서), 전체 1220 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
별표2 (5)(가) 아홉째. 중기목록표가 「얼마」라면 이 장은 「왜 그 값인가」임.
원가계산 → 중기 탭의 목록표 아래에 붙음.

- 기종마다 취득가·내용시간·손료계수(상각·정비·관리) → 시간당 손료 · 주연료와 유가 ·
  조종원 일당과 시간당 환산 · 시간당 사용료 3분할을 차례로 보임.
- 내역에 실제로 선 기종만 냄(카탈로그 613 을 다 뿌리지 않음).
- 부착 장비(브레이커·콤팩터·집게)는 손료만 드는 것이 정상이라 결함으로 안 셈
  — 제 엔진이 없어 연료·조종원이 본체에 듦(건설품셈 제8장 [주]⑤).
- 수송비는 이 장에 안 붙임 — 「회당」으로 서는 별개 공종이라 자리만 가리킴.
- 계산서 합계가 일위대가가 실제로 쓰는 값과 같은지 시험으로 못 박음(두 벌 방지).

⇒ 「설계서 구성」의 중기경비계산서가 반쪽 → 있음으로 바뀜(법이 정한 13 중 8 이 섬).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
조합 사용이면 본체 잡재료가 16% 로 줄어 재료비가 달라져 층이 따로 섬(굴착기 0.7
재료비 26,130 → 24,845). 갈래를 안 적어 똑같은 장이 두 번 나온 것처럼 읽혔음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획서 4-12. **빈 자리를 그냥 두면 사용자가 「고장인가」로 읽음** — 장마다 왜 그림이
없는지와 **무엇을 받아야 서는지**를 표 위에 한 줄 적음.
- 돌쌓기(찰) — 「뒷길이를 고르면 그림이 섭니다」 · 옹벽 — 「단면이 달라 아직 안 그림」

⚠ **큰돌쌓기를 `FIGURE_TYPE_IDS` 에서 뺌** — 그림은 두께를 뒷길이에서 내는데 큰돌쌓기는
규격이 **직경**이라 목록에만 있고 결과는 늘 빈 그림이었음(품셈 13-6 직경 ↔ 13-4 뒷길이,
수량 쪽에서 이미 갈라 둔 자리). **식은 만들지 않음** — 「직경에서 두께를 내는 법」은
도메인 판단이라 사용자 몫이고, 지금은 사유만 띄움.

⚠ 곁가지 하나를 화면에서 잡아 함께 고침 — 그림 대상 목록을 **기울기 판정**에도 쓰고 있어
큰돌쌓기를 빼자 **장 제목의 「1:0.3」까지 사라졌음**. `SLOPE_TYPE_IDS` 로 갈라 되살림.

화면 실측 — 표준도 1장에 「그림 없음 — 큰돌쌓기는 규격이 직경이라 …」 한 줄이 표 위에 뜸.
시험 다섯 추가, 전체 1225 통과·실패 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 사용자 규칙 — 끝난 항목의 조사·검증 원문은 검증 폴더로 통째로 옮기고
계획서에는 결과 한두 줄만 남김. 링크는 남기지 않음(찾는 일은 위키·graphify 몫).

옮긴 것 — 재계산 취소 재판정 · 직행 files 가드 · purge 확인 · 업로드 잠금 표시 ·
도수로 보류 확정 · 측구 토글 실측 · 표준도 두께 칸 · spoil_bank 예외 · 날개벽 원단위 ·
표준도 「지금 무엇이 서 있나」 전수표.

계획서 1,547줄 · 80,056자 → 1,408줄 · 73,939자 (139줄 · 6,117자 줄었음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
별표2 (5)(가) 열셋째. 근거는 줄마다 이미 있었고 묶는 자리만 없었음.
원가계산에 「산출기초」 탭으로 세움. 넷으로 접음 —
① 어느 판으로 계산했나(데이터 기준일·지문) ② 무엇을 골랐나(고른 값만)
③ 공종마다 무엇을 근거로 했나(줄 문구 그대로) ④ 못 채운 자리(0 으로 안 때운 자리).

- 판 목록은 장부(_manifest.json)를 그대로 읽음 — 목록을 따로 적으면 한쪽만 고쳐짐.
- ⚠ 여기서 값을 다시 계산하지 않음 — 금액 칸이 아예 없음(두 벌 방지, 시험으로 못 박음).

⇒ 「설계서 구성」의 산출기초가 반쪽 → 있음. 법이 정한 13 중 9 가 서고,
  우리가 더 낼 것은 공사설명서 하나(서식·설계하중 표기는 사용자에게 받아야 함).

곁들여: 자재총괄의 「미분류」를 「미정(발주기관 결정)」으로 고침 — 발주기관이 정할
자리인데 우리가 못 만든 것처럼 읽히던 문구(V-14). 값·판정은 그대로.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
「사람이 한 번 봤다」로 두면 다음 사람이 또 봐야 함. 본 것을 시험으로 남김.

- V-11 인계 계약 검사가 양쪽으로 무는지(칸을 늘려도·빠뜨려도 걸리는지) — 가드의 가드.
- V-16 불도저 운반이 갈래(토사·파쇄암)마다 금액으로 서는지. 덤프 운반은 아직 안 서는
  것도 사실대로 못 박음(운반거리 설계 입력 대기).
- V-17 공구손료와 제잡비는 밑수도 가는 자리도 달라 겹치지 않음(주재료비→재료비 /
  노무비→경비). 지금은 주재료비가 0 이라 3% 를 넣어도 한 원도 안 움직이는 것을 못 박음.
- 곁들여: 석공사·철골공사는 특수공구라 건설품셈 1-2-6 이 「별도 계상」으로 두었음을
  공구손료 칸 사유에 적음 — 일반 비율을 그대로 붙이면 안 되는 자리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
끝난 항목의 조사·근거·검증 원문은 계획서에 안 남기는 것이 사용자 확정 규칙임.
계획서에는 결과 한두 줄만 두고 원문 22건을 이 파일로 통째로 옮김.

- 함께 옮긴 것: 항목이 이미 닫혀 자리를 잃은 고아 근거 두 덩어리.
- 살아 있는 정보는 계획서에 한 줄로 남김 — 마스터가 반쯤 빈 것, 야면석 규격 넷에 값이
  없는 것, 공구손료가 붙을 밑수가 아직 0 인 것, 유가 지역 자동 연동을 안 한 것,
  수송비에서 우리가 정한 둘, 품 할증이 임도 토공용이 아니라는 것.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 1 commit 2026-09-10 19:15:27 +09:00
2026-09-10 사용자 확정. `docs/wiki/graphify-out/cache/` 443파일(4.3MB)은 **PC 마다 다시
만들어지는 파생물**인데 git 이 나르고 있었음. 코드 창에서 graphify 가 돌 때마다 그 폴더가
바뀌어, 위키 브랜치를 받을 때 「덮으면 로컬이 날아간다」로 **병합이 막히는** 구조였음.

- `.gitignore` 에 캐시 폴더 추가 + 추적 해제(파일은 그대로 남음, 다시 만들어짐)
- AGENTS.md 에 그 사실과 「graph.html 은 코덱스가 주인」을 적음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eomsangdon added 2 commits 2026-09-10 21:01:25 +09:00
eomsangdon added 2 commits 2026-09-10 21:12:26 +09:00
eomsangdon added 1 commit 2026-09-10 22:06:50 +09:00
경쟁사 프로그램 오솔길의 엑셀 매크로(PERSONAL.XLSB) VBA 7개 모듈을
모듈별 md 문서로 정리. 문서 안은 계산 로직 단위로 나눔.

- 임도 횡단물량: 평균단면적법, 보정계수(토사 0.9·암 1.0), 유용토=MIN(보정량계,성토입적),
  차인토량, 누가토량 수식 확보
- 야계사방댐: 터파기 유/무 두 갈래(지역 관행 차이), 유용토 상대가 성토+되메우기
- 사방댐 토공: 평균단면적법 / 3-4각형법 두 방식, 토사·암석 2열 분리
- 공통 보조 프로시저: 보정계수를 표에서 역산하는 방식 확인

단면적 산출·구조물 물량은 컴파일된 OSKi.arx 안이라 미확보 — 역공학 안 함.
VBA 원문은 저장하지 않고 재추출 방법만 README에 남김.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YTbyFkYhKNUYvxRV7DYfxZ
eomsangdon added 1 commit 2026-09-10 23:07:05 +09:00
저장소 안 LibreDWG(dwg2dxf)로 오솔길 도면양식 55개를 DXF 변환해 글자 추출.
변환물은 저장소에 두지 않고 명령만 문서에 남김.

- 제출 양식이 발주 지역(OSKid: KN·KP·JN·CN)마다 표 열 구성이 다름을 확인.
  JN은 저수·저사·토사조절선이 없고 평떼·줄떼·찰쌓기·메쌓기가 들어감.
  KP는 떼붙임·좌안·우안 추가, 댐 토공표에 터파기조건 열 추가.
- 표제란은 DWG 파일 교체로 자사화 — 도면 안에 방법이 글로 적혀 있음.
- 발주처 로고를 별도 폴더(발주처_시군_공사_마크)에서 갈아 끼움.
- 임도 물량표(Wchart)에 매뉴얼 BOM에 없던 볏집거적·새심기 확인.
- 곡선설치표 신버전에 곡선중심 X·Y 추가, RE 정보표에 오차적용경사 확인.

폴더를 10_원문(전사)과 20_분석(분석)으로 나누고 README 색인 갱신.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YTbyFkYhKNUYvxRV7DYfxZ
eomsangdon added 1 commit 2026-09-10 23:09:54 +09:00
DWG 56개(임도 표·심볼, 사방댐 표·상세도, 캐드 템플릿)를 LibreDWG로
DXF 변환해 10_원문/도면양식DXF/ 에 원본 폴더 구조 그대로 보관.
원본 DWG는 손대지 않음.

- 변환 성공 56 · 실패 0
- 폴더 README에 다시 만드는 명령, 들어 있는 것, 읽어 본 결과 기록
- 도면양식 개요 문서의 "저장소에 두지 않음" 문구를 실제와 맞게 수정

계산식은 없음 — 양식은 표 껍데기라 공식이 안 들어 있음.
건진 것은 열 구성과 항목 이름(볏집거적·새심기·오차적용경사·터파기조건).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YTbyFkYhKNUYvxRV7DYfxZ
eomsangdon added 1 commit 2026-09-10 23:33:41 +09:00
전 세션 산출물이 미커밋으로 남아 있던 것 — 싱크로 다른 창에 못 넘어가던 자리.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ikwZL5RDn97nEX5KU13qg
eomsangdon added 1 commit 2026-09-11 15:21:57 +09:00
eomsangdon added 1 commit 2026-09-11 16:18:08 +09:00
- 워크트리 넷의 링크 구성 실측(정션·하드링크·복사본·없음)
- 오르카는 무시 파일만 하드링크, 폴더는 안 만듦 — 그 워크트리에서 세션 훅 안 돎
- 오르카에 커밋·푸시 명령 없음 — 역할 나눔이 방향
- 토큰 실측(커밋 1회 191~338 · 따라오기 52~88)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011N7TKFmaPogzq9HUi6jKo7
eomsangdon added 22 commits 2026-09-11 19:34:43 +09:00
eomsangdon added 1 commit 2026-09-11 20:25:37 +09:00
eomsangdon added 3 commits 2026-09-11 20:43:06 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019QCqqbnuccwP57S3LSA3bv
- main_laptop_1-2/PLAN.md 하드링크 이미 끊어져 갈라짐(107,270 ↔ 111,121)
- PowerShell 은 하드링크를 LinkType=HardLink 로 봄 — 옛 구멍은 「건너뜀」이었음
- 고친 스크립트 모래상자 시험 넷 통과
- 오르카 setup 문구는 CLI 로 못 바꿈

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011N7TKFmaPogzq9HUi6jKo7
eomsangdon added 3 commits 2026-09-11 20:51:01 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019QCqqbnuccwP57S3LSA3bv
- orca terminal close 셋 + worktree rm 둘, 메인 파일·원격 브랜치 멀쩡함 확인
- 제거 전 정션 없음 확인 — 원본 삭제 위험 없었음
- 장부 못 찾으면 .claude 정션 대상을 메인으로 쓰는 길 추가
- 사용자 확정 셋(자동 커밋 유지·브랜치 이름 규칙·docs 문 유지)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011N7TKFmaPogzq9HUi6jKo7
eomsangdon added 1 commit 2026-09-11 21:13:25 +09:00
- orca 환경(--environment) 으로 상대 PC 오르카를 직접 부리는 길 확인
- CODEX·안티그래비티 워크트리 생성, 링크 일곱 다 섬, 추적 붙임
- 상대 창 승인 대기 없이 내 권한으로 수행

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011N7TKFmaPogzq9HUi6jKo7
eomsangdon added 10 commits 2026-09-11 22:16:30 +09:00
eomsangdon added 10 commits 2026-09-11 22:34:55 +09:00
eomsangdon added 5 commits 2026-09-11 22:53:58 +09:00
eomsangdon added 1 commit 2026-09-12 10:20:36 +09:00
eomsangdon added 8 commits 2026-09-12 14:26:50 +09:00
- 지침 4장은 ORCA 기본 · 공용은 사용자가 지시할 때만으로 줄임
- 되돌릴 때 필요한 시동·명령파일·캐시 비우기·재시작 절차를 원문 그대로 이 문서에 옮김
- ORCA 쪽 캐시 비우기는 전용 명령이 없어 미확인으로 남김 (첫 B07 검증 때 확정할 것)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
- 측구 토사·암을 절토 면적비로 다시 안분하지 않고 B06 이 낸
  ditch_soil_area_m2·ditch_rock_area_m2 를 그대로 씀. 근거 ditch_split_basis 도 줄에 실음.
- 설계값이 없는 저장분만 옛 안분으로 떨어지고 사유를 줄 주기에 남김.
- 표기 자리수 — 단면적 ㎡ 1자리 · 체적 계열 ㎥ 2자리 · 합계 정수 (계산은 전정밀 그대로).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
확폭을 측점마다 앞뒤 10m 세 점의 외접원 반경으로 다시 재던 것을 계획노선 곡선표
(시·종점·설계 반경)로 바꿈. 종전에는 같은 곡선 안에서도 측점마다 확폭이 갈리고,
곡선 밖 직선까지 확폭이 흘러나가며, 측점 간격보다 짧은 곡선은 통째로 빠졌음.
곡선 안은 설계 반경의 표값 한 값, 앞뒤 10m 는 0 으로 잇고, 그 밖은 확폭 없음.
곡선표가 없는 옛 프로젝트는 종전 방식으로 물러섬.

횡단도는 차도 끝에만 눈금이 있어 노면이 넓어져도 차도가 는 것인지 노견이 는 것인지
가릴 수 없었음. 노면 끝에도 옅은 눈금을 세우고 노폭 라벨에 노견 폭을 덧붙임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-12 15:03:46 +09:00
암 절토 칸은 속값이 이미 경사비인데 화면만 각도(°)로 바꿔 보여 줘, 도면·좌측 표준
설정·품셈이 모두 1:n 인 자리에서 이 칸만 머리로 환산해야 했음. 머리말 「1:」과 n 입력으로 바꿈.

기슭막이 상단에서 바닥으로 늘 긋던 대각 이음선은 사용자 지시로 뺌.

조정창이 좌측 상단 면적표를 덮어 수치가 안 보이던 것을 표 높이만큼 내려 세움.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 2 commits 2026-09-12 15:50:11 +09:00
B05 와 B06 은 한 페이지인데 구조물을 넣고 빼는 자리가 B05 뿐이라 화면을 오가야 했음.
종단 그래프 렌더러·알약 레인·좌측 배치 폼은 이미 공용이었으므로, 빠져 있던 조작층만
B05 와 같은 부품(mountStructureMenu)으로 B06 에도 붙임.

관 추가·삭제는 이동과 같은 예약 경로를 씀 — 세션에 쌓고 [저장]·[확정]에서 정본
(pipe_points.json)으로 나가며, 세부 배수유역 재분할은 그때 서버가 처리함. 넣었다 바로
빼거나 뺐다 다시 넣으면 예약만 걷어 내 정본이 흔들리지 않음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-12 15:54:19 +09:00
B05 에서만 되던 끌어 옮기기를 B06 종단에도 붙임 — 측점선과 알약 어느 쪽을 끌어도 같은
길을 타고, 관은 예약 이동(저장·확정 때 정본과 배수유역 재분할), 구조물은 정본 이동임.

끌기 판별과 대상 찾기는 새 모듈(B06_Section_UI_Section_View_Menu)로 모아, 종단 화면
본체가 더 커지지 않게 둠.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-12 16:02:55 +09:00
세 자리가 어긋나 있었음.
- B06 저장이 델타를 먼저 내보내고 B05 스냅샷을 나중에 써서, 두 화면을 오가며 만지면
  스냅샷이 B06 편집을 통째로 덮었음. B05 [임시저장]과 같은 순서(스냅샷 먼저, 델타 나중)로 바꿈.
- B05 저장이 구간값 키만 넘겨, B06 에서 예약한 관 이동·추가·삭제가 조용히 빠졌음. 키 셋을 다 넘김.
- B06 좌측 목록이 정본만 읽어 B05 에서 넣고 안 저장한 관이 안 보였음. 구조물과 같은 규칙으로
  미저장분을 먼저 씀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-12 16:16:30 +09:00
B05 는 관 목록 전체를 세션 스냅샷으로, B06 은 바뀐 것만 따로 담고 있어 담는 꼴이 둘이었음.
저장 순서를 맞춰 결과는 같게 했으나 자리가 둘인 한 같은 사고가 다시 남.

B06 의 추가·삭제·이동을 모두 B05 가 쓰는 스냅샷(pipes)에 쓰도록 바꾸고, B06 전용 예약
경로(culvertedit 세션·queueAdd·queueRemove·queueMove)를 걷어 냄. 옛 세션에 남아 있던
이동 예약만 저장 때 한 번 흘려보내게 읽기를 남김.

이제 관을 넣고 빼고 옮기는 길이 좌측 폼·목록·종단 우클릭·측점선 끌기 모두 한 함수이고,
담기는 자리도 한 곳임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 34 commits 2026-09-12 16:35:15 +09:00
- 상태줄에 계획노선 길이 실시간 표기 (계획서 0-9 ①)
- 시점·종점 이름표와 규칙측점 눈금 표기, B04 지도와 같은 `drawStationTicks` 재사용 (②)
- 곡선 조작 패널을 모달 지도 칸 안으로 가둠 — 상자 밖·하단 정보행 위로 안 나감 (⑨)
- 그리기를 `B05_Profile_UI_RouteEdit_Render.ts` 로 분리 — 본체 703줄 → 627줄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
- 기본값 정의처는 config_system_design 한 곳 그대로. 고른 값은 프로젝트 설정
  quantity.conversion_factors_override 에 얹고, earthwork_conversion_factors() 한 함수가
  기본값 위에 얹어 풀어 냄.
- 그 함수를 거치는 자리 여섯 — 토적표·운반표·기초단가(B08), 유토곡선 컨텍스트·
  배분 계산·[저장] 재계산(B06). 상수를 직접 드는 자리를 없앰.
- 산출 조건 패널에 갈래별 계수 칸 신설 — 기본값·품셈 범위를 함께 보이고,
  「유토곡선·운반표·기초단가에도 같이 닿음」 안내 한 줄. 범위 밖은 막지 않고 사유를 받음.
- 품셈 체적변화율 범위를 서버 상수로 두고 화면에 내려보냄(프론트에 다시 적지 않음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
- 확정 지표면이 있으면 LAS 등고선을 바탕으로 씀, 없으면 도엽 등고선 유지 (계획서 0-9 ⑥)
- 등고선 가닥마다 높이값 라벨, 겹치면 건너뜀 (③)
- 등고선을 누르면 그 가닥만 도드라지고 상태줄에 높이 표기 (⑦)
- 화면에 드는 가닥 수로 등고선 간격을 고름 — 1m 자료가 선으로 뭉개지던 것 해소
- `B04_PreProcess_UI_MapRender.ts` 700줄 초과로 사전 투영을 `_Prepare.ts` 로 분리

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
- 임도 종류별 하한 표를 config 에 둠, 작업임도는 규정이 없어 0(제한 없음)
- 기본 반지름과 하한을 갈라 둠 — 한 값이면 하한 0 이 반지름 0 이 되어 곡선이 안 그려짐
- `/route/plan` 이 `limit_radius_m`·`limit_curve_length_m` 를 함께 내림
- 반지름 칸·곡선 길이 칸·손잡이 끌기가 하한에서 멈추고, 노드 이동은 그 걸음을 되돌림
- 이미 하한을 밑돌던 자리는 그대로 두고 지키던 자리가 넘어가는 것만 막음
- 시험 `resources/tester/test_plan_curve_limits.py` 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
- Shift+클릭으로 노선 위 두 점을 찍으면 구간 길이와 종단기울기 표기 (계획서 0-9 ⑤)
- 지반고 통로 `POST /route/elevations` 추가 — 종·횡단과 같은 sampler 를 읽기만 함
- 찍는 순간에만 서버를 부름, 끄는 동안에는 안 부름
- 700줄 규정에 맞춰 구간 재기와 [확인] 처리를 `_Measure.ts`·`_Apply.ts` 로 분리

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
- 조건 상자 다섯을 `ui-collapsible ui-sidebar-section` 으로, 제목에 `ui-collapsible__title` 부여
- 자체 `b09-panel__actions` 를 공용 `ui-sidebar-actions` 로 바꿔 [계산]·[확정] 이 패널 바닥에 고정
- 패널 루트에 `attachCollapsible` 연결 — 제목 행 클릭으로 접힘·펼침
- 상자 꼴(패딩·모서리·배경)은 `.ui-sidebar-section` 이 붙은 것만 집어 기초자료 본문 표는 불변

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
- 원지반 횡단선·기본 계획 횡단선·성토사면 길이 셋만 보임, 구조물은 안 그림 (계획서 0-9 ⑧)
- 서버 `POST /route/cross-preview` 가 `generate_sections`+`compute_cross_design` 정본을 재사용
- 계획고는 편집 중에 없어 그 측점 지반고를 그대로 놓음(지반 추종) — 창에 그렇게 적음
- 성토사면 길이는 B06 화면이 쓰는 `fillSlopeLengths` 를 그대로 부름
- 700줄 규정에 맞춰 곡선 패널 배선을 `_CurveBar.ts` 로 분리

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
개발용 「확정 없이 다음으로」 줄이 공용 `ui-sidebar-actions` 를 쓰고 패널 맨 위에
있어, 공용 코드(`splitSidebarActions`)가 **첫 번째** 그 클래스를 패널 바닥 액션 줄로
집고 스크롤 영역을 그 줄 안에 가둠. 그 아래 조건 칸과 진짜 [저장]·[확정] 줄이
`overflow: hidden` 밖으로 밀려 잘리고 스크롤바도 안 생기던 것을 바로잡음.

- 개발용 줄 단추 묶음을 `b08-quantity__dev-actions` 로 바꿔 공용 클래스에서 뗌
- 조건 칸을 `ui-collapsible ui-sidebar-section` 상자로 묶는 `groupPanelSections` 신설
  (새 파일 `B08_Quantity_UI_SidePanel_Sections.ts` — 본문이 이미 700줄을 넘김)
- 토량환산계수 구획도 제 제목으로 접히게 `ui-collapsible` 부여
- 표를 못 받은 경우(`table === null`) `concrete_placing` 접근에서 터져 페이지가
  통째로 백지가 되던 것을 `?.` 로 막음

자체검증(ORCA 내장 브라우저 5173, 모듈 직접 로드) — 스크롤 래퍼가 패널 직계로 돌아옴
(`b08-quantity__panel ui-sidebar-fill`) · `ui-sidebar-actions` 1개만 남음 ·
[저장]·[확정] 줄 바닥 920px = 패널 바닥 920px = 창 높이 920px 로 잘림 없음 ·
상자 7개(제목 6 + 무제목 1) · 「구조물·사토」 제목 클릭에 511px → 42px → 511px 로
접힘·펼침 확인 · `tsc --noEmit` 통과 · `pytest -q` 1294 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RANEBHns1S4tkmsYwewtk
- 탭 열 개(살아 있는 아홉)의 화면 열마다 이름·원천(파일:줄)·식·등급 후보 정리
- 이미 있는 것 넷 가름 — formula_text · source_label · base_label · work_item_basis
- 등급 여섯에 안 맞는 일곱 갈래를 6장에 모음, 핵심은 ㉱ 「여기서 안 세는 줄」이
  막힘과 뜻이 정반대라 일곱째 등급 「제외」가 필요해 보이는 것

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
- 조작 설명을 지도 좌상단 2열 오버레이로, 상태·범례를 좌하단 오버레이로 (계획서 0-9 ⑩⑫)
- 단추를 제목행 오른쪽으로 옮기고 공용 `.ui-btn` 규격을 씀, 하단 정보행 삭제 (⑪⑬)
- LAS 등고선을 도엽과 같은 5m 단위로 그림 (⑭)
- 바탕이 LAS 면 세류선도 등고선 범위 안쪽만 그림 (⑮)
- 지도 오른쪽 위 반시계·시계 단추로 15°씩 그림 전체 회전, 집기도 따라감 (⑯)
- R·L 하한을 5m 로 채움. 다만 L 하한은 칸 입력만 막음 — 기하에 걸면 거의 곧은 자리에서
  R 이 부풀어 아무것도 안 고쳤는데 노선이 바뀜 (⑰)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
화면에 뜬 숫자가 어디서 와서 어떻게 나왔는지 가릴 길이 없어 개발·검산이 막히던 것을
엶(PLAN 8-36 ①②③④). 칸에 마우스를 올리면 등급·값·식·원천·자리가 카드로 뜨고,
토글을 켜면 등급색이 칸 왼쪽 띠로 붙음.

- `common_util/common_util_provenance.py` — 등급 상수 여덟과 `ColumnProvenance`.
  사람이 고르는 여섯(입력·측량·기준·계산·최종·막힘)에 `excluded`(일부러 안 셈,
  채우면 이중계상)와 `unclassified`(판단 미룸)를 더함. `excluded` 는 데스크탑 보조의
  B09 조사에서 나온 것으로 `blocked` 와 뜻이 정반대라 갈라 둠. 값 안에 선택이 숨은
  열을 위해 `rule`(채택 규칙) 칸도 둠.
- ⚠ 로직 보안 — `provenance_payload()` 가 개발환경이 아니면 `None` 을 돌려주고
  라우터가 응답에서 칸을 통째로 뺌. 화면에서 숨기는 것이 아니라 안 보내는 것임.
  문의 정본은 `is_dev_environment()` 하나로 통일.
- `ui_template/ui_template_provenance.ts` — 호버 카드·등급색·토글 한 벌. B09 도 같이 씀.
- `B08_Quantity/B08_Quantity_Provenance.py` — 토적표 20열 사전. 사전은 **열 단위**이고
  줄마다 갈리는 사유만 줄 쪽에서 얹음(칸마다 지으면 한 장이 6천 칸이라 응답이 붐).
- 토적표에는 `final` 열이 하나도 없어 억지로 붙이지 않음 — 중간 장부이고 내역서로
  나가는 값은 토공집계표에서 섬.

자체검증 — 시험 8개 추가(`test_b08_provenance.py`). 값어치는 첫 번째에 있음:
사전 열 이름이 전부 실제 `EarthworkRow` 에 있는가(엔진이 이름을 갈면 사전만 옛것으로
남는데 화면에서는 카드가 그냥 안 떠 눈에 안 띔). 배포환경 `None` 도 시험으로 박음.
브라우저(ORCA 5173, 실제 사전을 물려 토적표를 그림) — 표시된 칸 40개(2줄×20열) ·
등급 갈래 survey 12 / calc 28 · 카드에 「절토 토사 보정량 · 계산 · 값 45.00 ·
식 절토 토사 입적 × 토량환산계수(다짐) · 자리 EarthworkTable.py:210」 · 토글에 배경이
투명 → 초록 7 % 로 바뀌고 왼쪽 띠 inset 3px. 줄 사유가 그 줄 모든 칸에 뜨던 것을
사유가 닿는 열(`ditch_*`)에만 뜨게 고침 — 「절토 보정량」 카드에 「측구 가름값이…」 가
떠서 읽는 사람을 속이던 자리임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RANEBHns1S4tkmsYwewtk
- 내역서 note 가 이어 붙이는 조각 20개를 임자 열(규격·수량·단가·금액·줄전체)로 가름
- 덮어쓰는 자리가 더 많아 사유 둘이 겹치면 하나가 사라지는 것을 드러냄
- 화면 비고 칸은 그대로 두고 조각 배열은 호버 카드용으로 따로 실을 것

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
① 버그 — BillRow.note 한 칸에 덮어쓰던 13곳·이어 붙이던 7곳을 조각 배열 notes 로
   옮김. 한 줄에 사유가 둘이면 하나가 조용히 사라지던 것이 멈춤. 조각마다 닿는 열
   키를 함께 실어 호버가 그 칸에만 띄우게 함. 화면 비고 칸은 종전과 같은 꼴 유지.
② 사전 — B09_Estimation_Provenance.py 신설(기존 B09 파일이 700줄 초과). 8장 57열.
   이미 있던 formula_text·source_label·base_label 은 그대로 쓰고 없는 것만 새로 적음.
③ 배선 — 라우터 5개 응답에 _with_provenance(), 표 여섯에 markProvenanceCell +
   attachProvenance. 개발환경이 아니면 응답에 칸 자체가 안 생김(로직 보안).
④ 등급색 토글을 탭 줄 끝에. 사전이 안 오면 단추도 안 세움.

⚠ 원가계산서 금액은 같은 열에서 중간줄과 마지막줄의 성격이 갈리는데 등급이 열에
   하나뿐이라 calc 로 두고 rule 에 어느 줄이 final 인지 적음(PLAN 8-36 ① 에 남김).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
같은 열이라도 줄마다 성격이 갈리는 자리가 있음 — 원가계산서 「금액」은 중간줄
(간접노무비 따위)이 계산인데 마지막줄(총원가·도급금액·총계)은 최종임(데스크탑 보조
B09 배선에서 나옴). `markProvenanceCell` 은 이미 칸마다 등급을 받고 있었으나
카드 배지가 열 등급으로만 그려져 **띠는 최종인데 배지는 「계산」**으로 어긋났음.

- `fill()` 이 칸을 받아 배지를 `cell.dataset.provTier || column.tier` 로 그림
- 등급을 안 심은 칸은 `attachProvenance` 가 열 등급으로 채움 — 안 그러면 배지는
  뜨는데 띠가 안 붙는 「색 없는 칸」이 생김. 부르는 쪽이 등급을 빼먹기 쉬운 자리라
  여기서 맞춤. 줄마다 다른 칸에만 세 번째 인자를 주면 됨.

자체검증(ORCA 5173) — 같은 열 `amount_krw` 에서 등급 안 심은 칸은 배지 「계산」·띠
초록 rgb(31,138,76), `final` 심은 칸은 배지 「최종」·띠 금색 rgb(184,134,11) 3px inset.
배지와 띠가 같은 말을 함. `tsc --noEmit` 통과 · 병합 뒤 `pytest -q` 1313 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RANEBHns1S4tkmsYwewtk
- 메인 창을 왼쪽으로, 오른쪽 세로 칸에 「횡단」·「이전 횡단」 두 판 (계획서 0-9 ⑱)
- 노드를 놓으면 보던 측점을 다시 셈해 새것은 위, 옛것은 아래로 (⑲)
- 측점 표기를 구조물 목록과 같은 규칙으로, 긴 안내문 삭제 (⑳㉑)
- 좌하단에 예상노선·계획노선 길이 둘 (㉒)
- [거리 재기] 단추와 구분선, 잰 값은 작은 창에 내고 닫으면 지움 (㉓㉔)
- 잰 구간을 누가거리로 잘라 꼬임 해소 (㉕)
- 곡선 패널 닫기 단추와 빈 곳 누르기 해제, 하단 정보는 내각만 (㉖㉗)
- 고른 등고선에 높이 라벨, 회전 아이콘을 반원 화살표로 (㉘㉙)
- 돌려도 글자는 바로 세움 — `UPRIGHT_LABELS` 한 값으로 되돌릴 수 있음 (㉚)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jsXWphgRUHAG2mFupSKPX
- 자재단가대비표: 적용 칸을 calc+rule(기.가·유.물·견적), 값 없는 원천 칸은 blocked
- 환율및기초자료: 공표·공시값 standard 와 사용자가 고른 유가 범위 input 을 가름
- 단가산출근거·산출기초: 모으는 표라 식을 비우고 source·등급만 채움
- 설계서 구성표·산출 조건 패널은 일부러 뺌(프로젝트 값이 아니거나 근거 한 줄과 중복)
- 원가계산서 금액은 총원가·도급금액·총계 세 줄에만 칸 단위 final 을 심음
- 700줄을 넘어 Provenance / _Sources / _Common 셋으로 가름(공통 조각을 한쪽에 두면
  불러들이기가 고리를 이룸)

사전 16장 92열, 등급 여덟이 모두 쓰임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
토적표만 서 있던 근거 호버를 토공집계·운반·준비공·자재총괄·구조물 원단위까지 넓힘.
사전 여섯 장 48열이 됨(토적표 20 · 집계 5 · 운반 5 · 준비공 5 · 자재 7 · 원단위 6).

같은 열이라도 줄마다 성격이 갈리는 자리를 **칸 등급**으로 갈랐음
- 토공집계 「계」 — 무대(소운반 20m) 줄은 `final` 이 아니라 `excluded`. 집계에는
  오르되 내역 줄이 아님(품셈 1-2-7). 채우면 이중계상이라 「못 세움」과 뜻이 정반대임
- 운반표 — 같은 줄의 토량·거리 둘 다 `excluded`. 값은 검산에만 씀
- 준비공 「수량」 — 값을 못 세운 줄은 `blocked`. 근거가 오면 채워질 자리라 제외와 갈림

**B08 에서 `final`(최종)이 처음 서는 자리는 토공집계표 「계」** 임. 토적표는 중간
장부라 최종 열이 하나도 없음 — 그 갈림을 시험으로 박았음(등급 여섯은 한 장이 아니라
여러 장을 합쳐야 다 쓰임).

자체검증 — 시험 4개 추가(모두 12개). 집계표·운반표 사전 열 이름이 실제 엔진 줄에
있는지 대조하고(운반표 `average_distance_m` 은 필드가 아니라 property 라 따로 봄),
등급·이름·식 검사를 여섯 장 전부로 넓힘. `pytest -q` **1317 passed** · `tsc` 통과.
브라우저(ORCA 5173, 실제 사전을 물려 다섯 표를 그림) — 집계 정상줄 `final` /
무대줄 `excluded` · 운반 정상 `calc` / 무대 `excluded` · 준비공 정상 `calc` /
값 없는 줄 `blocked` · 자재 총수량 `final` · 관급사급 `input` · 원단위 수량 `calc`.
카드에 식·원천·채택·자리가 다 뜸.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RANEBHns1S4tkmsYwewtk
화면 실측에서 조정창 윗변이 면적표 아랫변과 1px 겹쳤음. 표 높이 기준값을 3.2rem 에서
3.6rem 으로 올려 6px 띄움.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-12 16:46:54 +09:00
`B06_Section_UI_Section_View.ts` 가 817줄로 한도를 넘겼음. 종단 그래프·구조물 알약 레인·
우클릭 메뉴·누가토량 배지·고정 Y축을 세우는 몫과 가로 스크롤 세로창 배선을
`B06_Section_UI_Section_View_Draw.ts` 로 옮겨 693줄로 줄임.

높이 재기·되먹임 보정·선택 상태는 본체가 그대로 쥐고, 옮긴 쪽은 넘겨받은 인자만 쓰므로
화면 상태가 두 곳에 남지 않음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 14 commits 2026-09-12 18:19:31 +09:00
- 개발 중에는 앱이 내려갈 때 Vite 를 죽이지 않음. Vite 는 한 앱 프로세스가 아니라
  개발 세션의 것이고, 다음 기동이 그대로 물려씀
- Vite 가 이미 그 포트에 살아 있으면 npm run build 를 건너뜀(첫 기동에서만 빌드)

까닭 — uvicorn 리로더가 *.py 마다 앱 프로세스를 갈아 끼우는데, 옛 프로세스가 종료하며
Vite 를 죽이면 새 프로세스가 「Vite 없음」으로 보고 npm run build(최대 300초 + B07 CAD)를
처음부터 다시 돌렸음. 그 사이 /api/health 가 stale: true 인 채 옛 코드를 계속 내주어
옛 화면을 보고 헛검증하게 됨. 2026-09-12 에 두 번 멈췄고 한 번은 두 시간 반 동안 안 끝남.

배포 환경은 그대로 — 빌드도 종료 정리도 종전과 같음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
무슨 일이 있었나
랩탑 줄의 병합 `20ba886c`(Merge origin/main_desktop_1·main_laptop_1·sub_desktop_1 into
sub_laptop_1)가 우리 파일 22개를 떨구고 35개 파일의 내용을 옛것으로 되돌림. 손으로 지운
커밋은 없고 **병합 자체가 떨군 것**임. 그것이 `origin/dev`·`main_laptop_1`·`sub_laptop_1`·
`CODEX` 까지 퍼졌고(데스크탑 둘만 무사), 이 창의 병합 `d92c1f2b` 로 들어옴.

잃었던 것
- 공용 — `common_util_provenance.py` · `ui_template_provenance.ts`
- B08 — 근거 사전 · 좌측 패널 상자 모듈 · 토량환산계수 칸
- B09 — 근거 사전 셋
- B05 — 계획노선 편집 모듈 아홉 · 지형 라우터 · B04 지도 모듈
- 시험 셋과, 35개 파일 안의 최근 작업(환산계수 고르기 · 근거 호버 배선 등)

어떻게 되살렸나
`611a2b40`(병합 직전, 전부 온전)에서 `git show <커밋>:<경로>` 로 내용만 꺼내 되돌림.
이력은 안 건드림. ⚠ HEAD 에만 있던 「추가 816줄」은 랩탑의 새 작업이 아니라 **되살아난
옛 코드**였음(B05 편집은 모듈로 쪼개기 전 덩어리 · B08 라우터는 환산계수 고르기 전 옛
상수판). 되돌릴 시점 이후의 **진짜 새 커밋은 둘뿐**이라 그 둘만 패치로 다시 얹음 —
`9f827bf6`(리로드 빌드 고리 끊기, 데스크탑 보조) · `b9bca6b3`(B06 조정창 1px, 랩탑).
위키 여덟은 코덱스 몫이라 손대지 않음.

자체검증 — 양쪽 작업이 다 살아 있음을 짚어 확인: `main.py` 의 「개발 서버는 살려 둔다」 ·
`B05_Profile_Engine_Grade.py` 의 `plan_curve_length_limit_m` · `B08_..._EarthworkGrid.ts` 의
`attachProvenance`. `tsc --noEmit` 통과 · `pytest -q` **1317 passed, 28 skipped**
(되살리기 전에는 시험 둘이 수집 단계에서 깨져 있었음).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RANEBHns1S4tkmsYwewtk
eomsangdon added 1 commit 2026-09-12 18:36:30 +09:00
B05·B06 종단을 같은 템플릿으로 맞추면서 **계획선 편집 버튼층만 빠져 있었음** — B06 에는
편집분을 얹어 계획선·전 측점 횡단을 다시 푸는 코드도, 편집 초안 세션도 이미 있었는데
누를 버튼이 없었음.

B05 와 같은 부품(createEditOverlay)을 종단 그래프에 얹고, 누른 값은 B05 와 같은 세션
초안에 쌓음. 누르는 즉시 계획선·횡단을 다시 풀어 카드에 반영함.

저장도 이었음 — 종전에는 B06 이 초안을 읽기만 해서, B06 에서 [저장]·[확정]하면 계획선
편집이 정본에 안 남고 다음 진입 때 사라졌음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-12 18:57:50 +09:00
편집 버튼층은 `inset: 0` 으로 부모를 꽉 채우는데, B05 는 부모가 그래프뿐이지만 B06 은
구조물 알약 레인도 같은 칸 안에 있어 ▼ 가 레인 위로 내려앉았음(실측: 그래프 바닥 231px
인데 버튼이 270~287px). 버튼층 높이를 그래프 높이로 잘라 B05 와 같은 자리에 세움
(실측 후 ▲ 72~89px · ▼ 212~229px, 그래프 70~231px 안).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 2 commits 2026-09-12 19:07:40 +09:00
B05 에는 있고 B06 에 없던 장치였음. ▲▼ 를 누를 때마다 세로 창이 새 계획선에 맞춰 다시
잡혀, 값은 바뀌는데 선은 제자리에 있는 것처럼 보였음. B05 와 같이 누르고 있는 동안
창을 고정하고 손을 뗀 뒤 한 번만 다시 맞춤.

실측(랩탑_보조 534.0m 측점): 계획고 837.24 → 839.84m 일 때 설계선이 3.2px 올라감.
종전에는 같은 조작에서 0.4px 만 움직였음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 4 commits 2026-09-12 20:01:32 +09:00
- 백그라운드 태스크 셋을 cancel() 만 하고 지나가던 것을 gather 로 실제로 거둠
- 「백그라운드 작업 정리」·「DB 풀 종료」 두 걸음에 각 5초 시한. 못 끝내면 경고만
  남기고 넘어감 — 종료는 기다리는 곳이 아니라 끝내는 곳이고, 남은 정리는 OS 몫
- 끝에 「앱 종료 끝」을 찍어 종료가 끝까지 갔는지 로그로 갈림
- 모듈 맨 위에 [boot] 워커 프로세스 시작 pid 를 찍음. 리로드 뒤 이 줄이 찍히면
  새 워커는 뜬 것(포트를 못 잡은 자리), 안 찍히면 아예 시작도 못 한 것(리로더 자리).
  고칠 자리가 전혀 다른데 종전 로그로는 못 가렸음

⚠ 이번 멈춤의 원인이라는 증거는 아직 없음 — 로그에 「앱 종료 중」이 안 찍혀 종료
코드까지 가지도 못했을 수 있음. 위 [boot] 표식이 다음 멈춤 한 번으로 그것을 가름.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
uvicorn 0.24 BaseReload.restart() 는 윈도우에서만 옛 워커를
os.kill(worker_pid, CTRL_C_EVENT) 로 내리려 함. CTRL_C_EVENT 는 프로세스 그룹을
지정해 보낼 수 없어(MSDN: 그룹 id 가 0 이 아니면 호출은 성공하지만 신호는 전달되지
않음) 워커에 아무것도 안 감. 바로 다음 join() 이 영원히 안 풀려 옛 워커가 살아서 옛
코드로 계속 응답하고, 새 워커는 태어나지 않으며, 그 뒤 파일 변경은 감지조차 안 됨.

실측(그 자리를 흉내 낸 부모·자식 한 쌍):
  CTRL_C_EVENT   → 8초 안에 안 풀림 (DETACHED · CREATE_NO_WINDOW · +NEWGROUP 모두)
  terminate()    → 0.00초
  CTRL_BREAK     → 0.00초 (자식을 그룹 우두머리로 띄웠을 때)

고침은 uvicorn 자신의 리눅스 경로를 그대로 씀. DEBUG + win32 개발 기동에서만 갈아
끼우고, uvicorn 이 위쪽에서 고치면 _patch_windows_reload 를 지우면 됨.

⚠ 앞선 두 커밋(빌드 고리·종료 시한)은 이번 멈춤의 원인이 아니었음. 빌드 고리는 실제
문제였고, 종료 시한은 다른 경우를 막는 값이 있어 남김. [boot] 표식이 이 진단을
가능하게 했으므로 함께 남김.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrXDD23Dvt2sR7q3X6oekp
eomsangdon added 1 commit 2026-09-12 20:34:36 +09:00
- 재계산 결과 반영을 `refreshCards` 로 묶음. 측점마다 `refreshCard` 를 부르면
  그때마다 종단 그래프·유토곡선까지 다시 그려, 62 측점 기준 한 번 누를 때
  종단도를 62 번 다시 그림.
- ▲▼ 는 계획선(`design_profiles`)만 먼저 갈아 끼우고 다시 그림 — 선이 즉시 움직임.
- 전 측점 횡단 재계산은 120ms 디바운스로 미룸(B05 프리뷰와 같은 규칙) — 길게
  누르는 동안은 선만 따라오고, 손을 뗀 뒤 한 번만 돎.

실측(62 측점, 같은 노선·같은 조작)
- 한 번 누름: 화면 갱신 920~955ms → 17~23ms · 최장 멈춤 879~971ms → 180~229ms
- 1.5초 길게 누름: 멈춤 954ms×3회·누적 2,577ms → 최장 213ms·누적 473ms,
  적용 단수 3 단 → 10 단(제 속도)
- 값 동일성: 누가토량 배지·카드 3장·계획고 라벨·세션 초안 전부 변경 전과 일치
- `npm run typecheck` 통과 · `pytest resources/tester/` 1,323 passed / 22 skipped

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 14 commits 2026-09-12 21:53:33 +09:00
만들자마자 탭 줄에 붙이는 바람에 **탭 단추들보다 먼저** 서서, 「토적표」 앞에 탭이 하나 더
있는 것처럼 보였음(2026-09-12 실측: 토글 x=8 · 토적표 x=84). 표를 고르는 단추가 아니라
보기 방식을 바꾸는 단추라 섞이면 안 됨.

만드는 자리는 그대로 두고 **붙이는 것만 탭 단추를 다 세운 뒤로** 미룸.

자체검증(ORCA 5173, 로그인한 실제 화면) — 탭 줄 차례가
토적표(8) · 토공집계(74) · 운반거리(152) · 준비공·사방공(230) · 구조물 원단위(336) ·
자재총괄(441) · **등급색 토글(519)** 로 맨 끝에 섬. 토글을 켜면 칸 왼쪽 3px 띠와 옅은
배경이 붙고(측량 372칸 · 계산 868칸), 다시 누르면 사라짐. `tsc --noEmit` 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RANEBHns1S4tkmsYwewtk
- 교각점 고정 단추: 켜면 그 꺾임점이 노드·손잡이 어느 쪽으로도 안 끌림(`apexLock`)
- 계획 횡단선을 절·성토 교차점에서 끊음 — 그 밖은 원지반이라 지반선과 겹쳐 그려지던 것.
  교차점은 B06 이 쓰는 `toeOffsets` 를 열어 함께 씀
- 횡단 판을 캔버스에서 SVG 로 바꾸고 휠 줌·가운데 끌기 팬·더블클릭 원복을 붙임
- 줌·팬 본문을 `A00_Common/b_svg_zoom_pan.ts` 공용 조각으로 빼고 B06 은 감싸개만 남김
- 「이전 횡단」 판은 계획 평면선이 바뀔 때만 채움(같은 측점 두 번 누르기로는 안 채움)
- 「거리 재기」 단추의 눌린 꼴 추가 · 등고선 높이 라벨을 맨 위로 올리고 더 촘촘히

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
R 하한만 막고 L 하한은 칸 입력에서만 막던 것을 고침. L = R·Δ 라 한 자리의 하한을
반지름 하나로 모아 봄(`radiusFloorM` = max(R 하한, L 하한/Δ)) — 값 끌어올리기·
모자란 양 판정·칸 막기가 모두 이 값을 씀.

내각 155° 이상은 별표2 Ⅰ.2.다.(1) 상 곡선을 안 둬도 되는 자리라 L 하한을 안 걺 —
걸면 교각이 0 에 가까워 R 이 수십 배로 부풀어 안 고친 구간이 휨. 그 자리는 곡선
패널에 「155° 이상 — 곡선 생략 가능」으로 적어 냄.

`deflectionRad` 를 화면 파일(`_Label`)에서 셈 파일(`_Edits`)로 옮김 — 순수 함수가
DOM 파일에 얹혀 있어 시험이 화면째 들여와야 했음(부르던 자리는 재수출로 지킴).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
eomsangdon added 1 commit 2026-09-13 09:23:46 +09:00
700줄 한도 대응. 순수 이동으로 동작 불변.
- B06_Section_UI_Page_Design_Sync.ts — 설계 선택 반영·낡음 재계산·소단 동기화·[전체 반영]
- B06_Section_UI_Page_Grade_Edit.ts — 종단 계획선 ▲▼ 제공자
- 남은 B06_Section_UI_Page.ts 644줄

소스 문자열 감시 시험 셋이 분리 모듈까지 읽게 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 6 commits 2026-09-13 09:24:00 +09:00
노임표에 없는 직종명을 유사 직종으로 바꿔 읽는 자리를 공종 단위로 둠(FP-13-02-04 한 곳). 산출기초에 준용 근거(재경원 회계 45101-45) 표시. 뒷길이 다섯 × 밑수 둘, 일위대가 10벌이 새로 섬.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
stone_kind 표의 「사용자 확정 대기」 문구를 확정된 계산식 기준으로 고침. 관측표 종류 주석이 코드(안 고르면 계산식)와 반대로 적혀 있던 것 바로잡음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
B08 인계의 준비공·부대시설 줄이 B09 에서 내역 본체 또는 제외 줄로 반드시 서는지, 표토제거 2,359.035㎥ 가 수량째 본체에 서는지 마주 걸어 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
eomsangdon added 1 commit 2026-09-13 09:28:49 +09:00
계획서 4-13 「칸만 오면 됨」 확인 — 관측 원단위가 든 종류는 하단표가 이미 섬.
날개벽 개소당 6줄 · 집수정 개소당 5줄 · 옹벽 반중력식 H=2.0 8줄.
식생옹벽블럭은 자료가 없어 줄 0개 + 사유만 — 값을 지어내지 않는 것을 함께 굳힘.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-13 09:49:25 +09:00
확정 8-2·14 — 버림 콘크리트 「넣음/안 넣음」 칸을 등록부(돌쌓기 찰·메·큰돌쌓기·기슭막이)와
표준도 입력(EDITABLE_KEYS)·제원 폼에 세움. 기본은 넣음(KDS 44 90 00 100㎜).
셈은 이미 wants_blinding 으로 서 있었고 끄는 자리만 없던 것임.

확정 5차 작은 것 2 — 표준도 그림 물빼기 주석이 기본 상수를 적던 것을
구조물 제원(weep_hole_*)에서 읽게 바꿈. 수량표와 같은 함수(weep_hole_spec)를 씀.

확정 6 — 표준도 장에서만 뜨는 [여기서 고치기] 단추를 고정 액션 줄에 둠.
표는 CAD 안이라 단추를 못 달고, 제원 폼은 도면 목록 아래라 밀림.
값 복사본은 만들지 않음 — 폼 한 벌이 그대로 정본 창구임.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 1 commit 2026-09-13 10:05:00 +09:00
구조물 폼 select 는 「기본값 없는 필수」만 빈 보기를 두어, `empty_means` 가 적힌 칸도
첫 보기가 골라진 채 저장됐다. `fill_concrete_mpa` 가 180 으로 박혀 엔진 기준값
210(확정 ⑩)과 갈렸다 — 채움콘크리트 규격·단가가 조용히 달라지는 자리.

빈 보기 판정을 「필수 + empty_means」 한 줄(`keepEmpty`)로 합치고 초기값도 같은 판정을 씀.
기본값이 있는 칸은 그대로 첫 보기를 쓴다(2026-08-17 지시 유지).
클라이언트 옵션 타입에 empty_means 를 더함 — 서버는 이미 실어 보내고 있었다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fe1QWPTfw11PaKh2LjwXdR
eomsangdon added 4 commits 2026-09-13 10:07:25 +09:00
다른 창이 넣은 네 줄을 사용자 확인 후 커밋.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
before_m·after_m(구간 규약)과 관 부속의 앞뒤 걸침 칸이 장 나눔 키에 들어가, 제원이 같은 구조물이 자리만 달라도 장이 갈리던 것 바로잡음. 랩탑 보조 실측 제보.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01DJffo4VwgTumVUM3kdbJzd
eomsangdon added 7 commits 2026-09-13 11:36:50 +09:00
코덱스가 토큰 한도로 중지한 STmate 분석을 이어받아 마무리한 것.
scratch/orca_artifacts 에 있던 산출물을 지식DB 정식 자리로 옮김.

이번에 새로 확정한 것
- 내부 반올림이 은행가 반올림(최근접-짝수)임 — SimpleRoundTo·Ceil·SetRoundMode
  전부 미임포트, 반올림 함수 본체에 부호 처리 없음. 출력 XLSX 의 Excel 사사오입과
  20개 경계 중 10개가 원 단위에서 갈림
- 간접비 항목별 밑수를 RATE 화면 그리드 묶음 제목에서 확정.
  환경보전비 밑수가 직접공사비가 아니라 재료비+직접노무비+산출경비임을 정정
- JB_R 35열 확장 시점이 2020-05-27 이고 기존 1~20열은 한 칸도 안 바뀜
- 원가계산 설정 선택축 83개 전수. 화면 순번과 내부값이 뒤집힌 축 둘 확인
- 문서 13(통제시험 T1~T11)·14(최종 완료 보고서) 신규

원본 C:\경영정보(주) 는 읽기만 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
자동푸시가 scratch/orca_artifacts 사본까지 함께 커밋한 것을 걷어냄.
같은 내용이 resources/knowledge/original/경쟁사 프로그램/STmate 분석/ 에
바이트 동일로 들어가 있음(41개 동일, 2개는 경로만 고친 스크립트).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
손으로 정확히 쳐야만 되던 주소칸을 후보 검색·선택 방식으로 바꿈.
VWorld 주소검색을 서버가 중계하고, 고른 즉시 좌표를 알므로 지도를 다시
찾지 않고 그림. 못 찾는 주소는 「직접 입력」으로 옛 방식을 씀.

- 회사 목록 SQL 이 business_address·business_owner 를 안 가져와 수정 모달이
  비어 열리고 저장 시 빈 값으로 덮어쓰던 것 수정
- 지도 기본 배율 15 → 17, +·- 단계 조절 추가
- 라벨·입력·버튼을 한 줄에 눕혀 줄 어긋남 해소
- 모달 안 휠이 뒤 대시보드로 새던 것 차단
- 회사 패널에 주소 한 줄 표시

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJC56e4osweKJ4vafm9ReM
개발 중 로그인마다 인증 코드를 기다리던 것을 끄는 스위치.
AUTH_OTP_DISABLED 가 true 이고 ENVIRONMENT 가 development 일 때만 듣는다 —
운영에서는 켜져 있어도 무시된다.

- 로그인: 새 브라우저·주기 재인증 둘 다 코드 없이 통과, 생략마다 경고 로그
- 회원가입: 흐름은 그대로 두고 인증 코드를 서버 로그에 기록
- .env 에 AUTH_OTP_DISABLED=True (배포 전 False 로 되돌릴 것)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TJC56e4osweKJ4vafm9ReM
eomsangdon added 1 commit 2026-09-13 14:23:29 +09:00
eomsangdon added 24 commits 2026-09-13 14:23:41 +09:00
문서 주장을 믿지 않고 원본 파일과 직접 대조한 결과.

바로잡은 것
- COSTN.DBF 는 암호화돼 있지 않음. 맛보기 71행·봉화 248행을 그대로 읽음.
  암호화된 것은 BDQTY 와 SYSINFO 둘뿐. 단가 네 성분이 평문이라 골든셋을
  단가 수준까지 뽑을 수 있음
- TAMT=MAMT+LAMT+SAMT 에 예외가 있음. 59행 중 2행(관급 흄관)이 어긋남.
  하드 오류로 막으면 실데이터를 거부하게 됨
- 프로젝트 RATE 표는 4종이 아니라 6종. RATE_A(25x10)·RATE_B(35x10) 추가 발견.
  값이 0~1 계수로 성격이 다르며 수공형식 밑수 배분표로 보임

새로 확정한 것 — 통제시험 T1 의 절반을 정적으로 풀었음
- 출력 XLSX 비고 칸의 실제 요율을 프로젝트 RATE 표에서 역추적해 좌표 확정
  산재 RATE_R[45,1] · 건강 [46,1] · 연금 [46,6] · 장기요양 [46,11]
  고용보험 등급1~7 [45,11..17] · 산안비 [20,17] 율 [20,18] 기초액
  간접노무비 [10,1]
- 5개 연도 시계열이 실제 법정요율 변천과 일치해 A등급
- RATE_R 행 45~49 가 부속표 영역, 행 0~44 가 규모·기간 행렬임을 가름

판정 — 기초단가 원천(자재 5.7만건·노임·중기·표준시장단가)이 전부 암호화라
STmate 복제는 불가. 계산 엔진은 구현 가능하고 Aislo 목적에는 충분함.
문서 15 신규, 검증 스크립트 5개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
프로젝트 STC 의 BOQ11 만 입력으로 삼아 직접비부터 총공사비까지 다시 계산하고
STmate 가 뽑은 XLSX 공사원가계산서와 원 단위로 대조한 결과.

결과
- 실무 프로젝트 6건 전부, 모든 항목이 1원도 안 틀림
- 내역 행 금액 ROUNDDOWN(수량 x 단가) 대조 1,515건 중 불일치 0
- 봉화 2024 는 직접비부터 총공사비 1,414,283,000 까지 전 항목 일치

새로 밝힌 규칙 다섯 — 이것 없이는 맞지 않음
- 말단 행 판별: BDCODE1 접두 T*(제목)·E*(계)·C*(제외총계)·:(페이지) 가 구조 행
- C* 로 닫히는 구역은 제외금액 구역이라 직접비에서 뺌
- 산업안전보건관리비의 관급재 밑수 = 관급자재대 - 조달수수료
- 끝전조정 = 도급공사비 천원 차액을 ROUND(차액/1.1) 로 세전 환산해 이윤에서 차감
- 관급자재대 = ROUNDUP(원자재대, 천원)

이로써 09번 완료 정의의 원설계 재현 조건이 실증으로 충족됨.
끝전조정·간접비 순서·계층 집계·제외금액 취급이 B 에서 A 실증으로 올라감.

문서 16 신규, 회귀 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
골든셋 회귀에서 소광 한 건이 어긋난 원인을 파고든 결과.

- 한 STC 에 BOQ11·BOQ12 가 함께 있으면 출력은 BOQ12 를 씀.
  BOQ11 을 현재안으로 잡으면 그 프로젝트만 통째로 틀림
- 변경 파일의 BOQ11 차수1 이 앞 파일의 BOQ12 와 원 단위로 같음.
  차수 인계 메커니즘 실증
- PRJLST.TCOSTn = MCOSTn+LCOSTn+SCOSTn 이며 직접공사비 합계
- 소광 변경1차 직접공사비 173,311,386 -> 257,410,433, 증감 +84,099,047

회귀 스크립트가 현재안 표를 고르도록 고침. 이로써 실무 프로젝트 6건 전부
원 단위 일치, 내역 행 1,515건 불일치 0.

08번 문서의 차수 경고를 실제 규칙으로 승격. 문서 16 보강, 차수 추적
스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
15번이 「BDQTY 암호화로 단가 조립 불가」·「중기 손료 계수 어디에도 없음」이라
적은 것을 정정. 출력 XLSX 의 일위대가표·중기사용료 시트에 구성 자원·수량·
단가·성분별 금액이 전부 평문으로 있음. 입력 원장은 못 읽어도 조립 규칙은 읽힘.

밝힌 것
- 호표 성분 소계는 절사. 중기사용료 398건 100%, 일위대가 325/345.
  집계표 행 금액(ROUND)과는 다른 자리이므로 섞으면 안 됨
- 중기 시간당 사용료 = 손료(취득가 x 손료율) + 운전원 + 주연료 + 잡품(연료비 x 율)
  성분별로 절사한 뒤 합
- 잡품은 수량x단가가 아니라 연료비에 비율을 곱하는 가산 행
- 시간당 손료율 25개 장비 실측. 같은 장비도 암석 조건이면 손료율이 오르고
  (0.2085 -> 0.2405), 부착 장비는 취득가가 부착물만의 값임
- 일위대가 호표가 다른 호표를 참조하므로 위상순서 계산이 실제로 필요함

⚠ 손료율 값은 STmate 가 담은 것임. Aislo 기본값은 현행 건설기계 경비 산정
기준에서 확정할 것이며 이 표는 대조용.

문서 17 신규, 검증 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
07번이 C등급으로 두고 「최저가·최신가·특정 슬롯 우선 중 어느 하나라고 단정할
근거가 없다」 한 항목을 실증으로 확정.

출력 XLSX 의 자재단가대비표에 후보 다섯 칸(조달가격·물가자료·물가정보·
거래가격·견적단가)과 적용 단가·출처가 나란히 있어 직접 검정함.

- 실무 6건 전수 186건 중 186건이 후보 최저가와 일치
- 후보 값이 2종 이상인 76건 전부 최저가
- 후보 값이 3종 이상인 36건 전부 최저가
- 최저가가 아닌 후보를 택한 건 0, 후보 밖 값을 쓴 건 0

곁들여
- COSTN 의 여섯 칸 중 여섯 번째가 적용 단가 칸으로 보임
- 후보 없이 적용만 있는 25건은 유가 자료, 적용 0 인 49건은 별도계상
- 남은 것은 사용자 수동 고정 시의 우선순위 (T10)

09번이 꼽은 여섯 호환성 차단점 중 자재 자동채택이 풀림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
전제 정정
- STmate 라이선스가 없어 13번 T1~T11 을 띄울 수 없음. 「나중에 시험으로
  확정」 계획이 성립하지 않으므로 13번 머리에 못박고, 대체 경로 셋과
  그것으로 이미 푼 것을 적음. 목록 자체는 장부 겸 절차서로 남김
- 남은 것을 늘릴 유일한 수단은 표본 늘리기. 특히 수공(S)·실적(TA/SA)
  형식 표본이 하나도 없어 그 세 형식은 전혀 검증되지 않음

통제시험 없이 새로 밝힌 것
- 요율 항목이 두 부류임. 고정 칸(보험·산안비·이윤)과 규모·기간에 따라
  행이 움직이는 것(간접노무비·기타경비·일반관리비). 뒤쪽은 고정 좌표라는
  모델 자체가 틀림
- 이윤 좌표 RATE_R[20,16] 확정 (3건 일치)
- 요율이 그 프로젝트 표에 아예 없는 경우가 실재함. 간선임도 간접노무비
  14.5%, 소광 이윤 13.435% 가 자기 RATE_R 에 없음 = 사용자 수동 입력.
  재구현은 rate_source 를 table(coord)/manual 로 갈라 저장해야 함

교차검증 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
출력 XLSX 21개 시트 중 검증한 것이 4개뿐이었음. 나머지를 전부 열어 본 결과
계산 사슬 앞쪽이 통째로 비어 있었음.

채운 것
- 노임 일단가 -> 시간당 환산식. 환율및기초자료 시트에 식이 있고 INITIAL 의
  RXNM_ 에 문자열로 저장됨. 적용 직종은 COND_
- ⚠ 식은 좌에서 우로 차례로 평가해야 함. 계수를 먼저 곱하면 부동소수점
  때문에 1원 틀어짐. 18건 중 좌우순차 18/18, 계수선계산 14/18
- 단가산출 D코드 공식. Q = 3600*q*K*f*E/Cm 로 시간당 작업량을 내고
  성분단가 = 절사(중기 시간당 성분단가 / Q, 소수1). Q 는 소수2 로 먼저 확정.
  73개 호표에서 발견. 품셈 근거·토질·조합기준이 문자열로 남아 있음
- 계산 설정 스냅샷이 출력 XLSX 의 INITIAL 시트에 통째로 있음.
  12번이 「화면 없이는 재현 불가」라 한 것을 정정. JMKN6 = 적용 단가 확인
- 집계표 행 금액은 사사오입 100%. 호표 성분 소계(절사)와 다른 자리임을
  수치로 가름

문서 18 신규, 검증 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
T9 확정 — 계류보전 2025(변경) 의 공사원가계산서가 당초·변경·증감을 나란히
내는 것을 찾아 가름. 직접노무비가 +8,802,162 늘었는데도 건강보험료·
노인장기요양보험료·연금보험료는 증감 0 임.

- 재계산 모드: 간접노무비·산재·고용. 요율은 당초와 같고 변경 밑수로 다시
  계산하면 원 단위로 일치
- 당초액 유지 모드: 건강·장기요양·연금. 사후정산 대상이라 설계 단계에서
  당초액을 그대로 가져감. 재계산했다면 85만 원이 더 붙었을 것
- 전부 재계산으로 구현하면 그만큼 틀림

곁들여 출력 시트가 21종이 아니라 30종이었음. 설계변경 시트 3종이 있어
「변경 출력이 표본에 없다」던 앞선 서술이 틀렸음.

문서 19(진행률 장부) 신설 — 원천별로 파일·표·시트를 실제로 세어 진행률과
남은 것을 적음. 계수 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
남은 16종을 전부 열어 본 결과 새 계산 규칙은 나오지 않음. 대신 둘이 밝혀짐.

- 착공내역서 178건 절사 100% — 설계내역서와 같은 규칙
- 목록표 7종·표지 2종·총괄내역서 2종은 계산 쌍이 없는 색인·표지 성격
- 집계표 4종에는 단가 열이 없음. 금액 = 절사(수량 x 해당 호표의 시간당
  성분단가). 굴삭기 0.2·0.7 은 전 성분 일치
- ⚠ 어긋나는 칸은 전부 -1 이며, 경비로 역산하면 표시 수량 940.69 가
  실제로는 940.68998... 임. 집계표 수량은 표시용 반올림값이라 그대로
  역산하면 1원씩 어긋남. 09번의 「입력 원값과 표시 반올림값을 분리」가
  이 자리

진행률 장부의 출력 시트 칸을 48% -> 100% 로 갱신. 훑기 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
일위대가 호표 참조 그래프 (④단계)
- 봉화 2024 의 45개 호표를 그래프로 세움
- 구성행이 다른 호표를 가리키고 단가가 일치하는 것 22건, 이름은 같은데
  단가가 다른 것 0건
- 순환 참조 없음 -> 위상순서 계산 가능. 깊이 최대 2단
- 09번의 「의존 그래프·위상순서·순환은 오류」가 실데이터에서 성립함

설계변경 직접비
- 계류보전 2025(변경) 의 BOQ11 은 한 표에 차수1(당초)·차수2(변경) 를 나란히 담음
- 양쪽을 각각 다시 세워 직접재료비·직접노무비·산출경비 전부 원 단위 일치
- 행금액 절사 대조 294건 x 2 = 588건 불일치 0
- 제외금액 구역 판정은 차수와 무관하게 같음
- 19번 6장의 간접비 모드와 합쳐 변경설계가 직접비부터 간접비까지 전부 재현됨

진행률 장부 갱신 — 지금 자료로 할 수 있는 일은 사실상 소진. 남은 것은
새 표본이 있어야 열림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
System 폴더만 보고 STmate 자료 폴더를 STC 와 같다고 넘겼던 것이 구멍이었음.
그 폴더에 STC 에 없는 Start8x.Ini·STini.MEM·QCODE.SMT 가 있었음.

Start8x.Ini 에서 나온 것
- 간접비 계산 순서가 KAN_ORD_1/KAN_ORD_2 코드 목록으로 저장돼 있음.
  두 목록의 차이가 321(기타경비 묶음 1개) 대 331~338(세부 경비 8개) 이라
  12번의 「일반형식 대 수공형식」 구분과 정확히 맞음. KAN_TYP 가 고름
- 코드 사전 301~370 을 봉화 출력 순서와 대조해 확정. 값이 0 인 항목은
  출력에서 빠진다는 규칙으로 하나도 어긋나지 않음. 등급 A
- ⚠ 후보 슬롯 이름이 설치본마다 다름. 설치 기본은 다섯째가 「유통 물가」인데
  실무 프로젝트는 「견적단가」임. 슬롯 번호에 기관명을 박으면 안 되는 근거
- COD_FMT_1~8 코드 종류 사전 (대가=일위대가 B, 산근=단가산출 D)
- [EQUIPMENT] 에 노임 환산식·환율·적용 직종의 설치 기본값
- [NAG_HAL] 할증률 설정 자리 발견 (표본은 전부 0)
- DISP_EX=제외금액 — C* 구역 이름의 출처

SET_REP.DBF 는 보고서 서식 75종 카탈로그. 표본 XLSX 에 나온 30종 말고
기성·견적·계약·준공·계획·실행예산 등 45종이 더 있음. 새 계산은 아니고
출력 변형. 수공양식·표준시장 서식이 카탈로그에 있어 그 형식이 실제로
지원됨을 확인

COSTN.SMT·QCODE.SMT·PRJLST.SMT 는 본문에 읽히는 문자열이 없어 암호화로
판정. 다만 같은 정보가 출력 XLSX 에 평문으로 있어 의존 그래프 복원에는
지장 없음

문서 20 신규, 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
최종 확인에서 내 오류 하나와 큰 구멍 하나가 나옴.

정정
- *.SMT 를 암호화라 적은 것은 틀렸음. 앞 4KB 만 보고 필터를 세게 걸어
  놓쳤고 본문은 0x200 부터임. COSTN.SMT 276개·PRJLST.SMT 153개 문자열이
  평문으로 읽힘. 암호화는 BDQTY·SYSINFO 둘뿐이라는 판정은 그대로 유효

구멍 — 지식DB 에 STmate 트랙이 셋이고 서로 몰랐음
- technical_info/01_임도/05_원가정보 (계산 로직 10문서, 2026-08)
- original/원가계산/STmate (STC 포맷 8문서, 2026-08-15)
- original/경쟁사 프로그램/STmate 분석 (이번 것)
- 단수처리 규칙·INITIAL 시트·SMT 문법·BDQTY 난독화는 이미 있던 것을
  다시 한 셈. 다만 실행모듈 정적분석·폼 복원·골든셋 회귀·변경설계 모드·
  단가산출 Q식은 이번에만 나온 것

PRJLST.SMT — 가장 중요한 발견
- 프로젝트별 원가계산 설정이 INI 평문으로 들어 있음. 차수별 섹션
- 요율이 좌표가 아니라 값으로 저장됨 (R_KANNO=10.8, R_IYUN=15 등)
  → 프로젝트 읽기·검산에 요율 좌표(T1)가 필요 없음. 우선순위 격하
- 수공형식 세부경비 8개 항목 확정 (R_S_SUDO/BOKRI/SOMO/TONGSIN/SEGUM/
  PEGI/DOSEO/JIGUP). KAN_ORD_2 의 331~338 과 일치
- 직접입력 금액 C_KUNBO·C_YUNBO·C_IYUN_M 이 변경설계 「당초액 유지」와
  끝전조정 보정액의 저장 자리

암호화의 성격
- 암호화 41개는 전부 파일명에 출처 기관·반기가 박힌 유료 구독 데이터.
  평문 43개는 법정 공개 자료인 제비율 요율표. 후보 슬롯 이름이 국내
  물가지 이름 그대로임. 프로그램 로직이 아니라 사온 데이터를 지키는 것
- Aislo 는 노임·유가·환율·시설공통자재를 이미 직접 확보. 실질 격차는
  물가지 자재단가 구독 하나

문서 21 신규, SMT 덤프 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
폼 233개(고유 190개) 중 3개만 뽑아 쓰고 있었음. 전수로 훑어 폼 40개에서
선택축 272개를 뽑음. 계산설정 폼 하나에서 뽑았던 83축의 세 배가 넘음.

화면에서 새로 나온 계산 규칙
- wM_Edt_Hal: 적용단가 = 기준단가 x 율%, 소수 n 자리 미만 절사/반올림.
  「적용단가 0원인 것과 보호표시된 것은 수정 안 됨」 = T10 일괄변경 수동값
  우선순위가 화면 안내문에 있음
- wM_Rate: 단수처리가 전역이 아니라 비목(M·L·X·W)마다 절사/반올림 x 소수 0~4위
- wM_Sel_Prn: ACTTYP = 표준시장단가 적용 방식(노임외 비목 적용안함/재료비로/
  경비로), ACTOPT = 끝전 보정 우선순위. 설치폴더의 STBSC 파일명과 정확히 대응.
  봉화는 ACTYP=1 ACTOP=2 = 「노임외 재료비로 적용 + 소수 비교후 타금액 우선보정」
  ⚠ 변경 차수가 화면에서 8차까지임. COSTN 접미사 4벌과 어긋나므로 재확인 필요
- wM_Set_Sys: KCDNM·ACDNM·ZCDNM·JCDNM·ECDNM·BPNNM 이 전부 소수 자리수 설정.
  20번에서 미확정으로 둔 것이 풀림. EXRNM 은 환율 적용 범위, RX1NM~RX4NM 은
  작업조건별 노임 환산식 4벌(터널·장대터널·펌프/GRAB/버켓준설선)
- wM_KanJub_K: 기성 계산은 부가세 선택지가 설계용과 다름 (재료비+산출경비의 10% 추가)
- wM_Mrg_BSC: 반기 기준자료 갱신의 매칭 키 5단계와 덮어쓰기 정책
- wM_JabPum·wQtyList: 코드 종류 전체 목록에 「그림코드」가 따로 있음

문서 22 신규, UI 카탈로그 원자료와 스크립트 3개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
세 폴더 머리에 서로를 가리키는 블록을 넣음 — 또 갈라지지 않게.
technical_info/01_임도/05_원가정보/원가계산_체계.md,
original/원가계산/STmate/_meta.md,
original/경쟁사 프로그램/STmate 분석/README.md 셋 다.
2026-09-13 에 ③이 ①②를 모르고 시작해 중복 분석한 사실도 함께 적음.

COSTN.SMT 전수 파싱 — ②트랙이 해독해 둔 문법을 그대로 씀
- 맛보기 1건 + 실무 STC 7건에서 자원참조 1,570·품 1,460·Q식 187·
  중간라벨 162·할증률 92 검출
- 참조되는 자원은 중기(X) 1,504 로 압도적. 노무 58·재료 7·경비 1.
  단가산출은 거의 전부 중기 시간당 사용료를 작업량으로 나누는 계산임
- 중기 한 대를 참조하면 노무·재료·경비 세 성분을 각각 따로 끌어옴
  (L 548·S 524·M 498). 총액 하나로 저장하면 안 되는 이유
- ⚠ Q 식이 한 꼴이 아님. 최소 10가지. 3600 계열(초)과 60 계열(분),
  포설은 60*L*D*H*E*f/(N*Cm). 하드코딩 금지, 텍스트 평가 경로 필요
- 운반 계산이 적재시간+왕복시간+적하시간 으로 사이클을 쌓음.
  km/hr·km·m/min 인자가 함께 나옴. 임도 토공 운반에 직접 쓸모
- 할증률 92건이 품목마다 제각각 (2%·3%·5%·24%·52%·0.443%).
  BDQTY 입력 원장은 여전히 막혔으나 적용값은 읽힘

문서 23 신규, 파싱 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
11번은 핵심 CPM 12개만 다뤘고 32개 모듈이 손대지 않은 채였음.

플러그인 규약
- 46개 중 31개 모듈이 Calc_Kanjub 를 내보냄. 재계산 진입점이 한 곳이 아니라
  모듈마다 있음. T8(UI 명령별 재계산 범위)이 어려운 까닭

DP_Common.CPM 73함수 = 계산 공용 라이브러리
- 식 평가 CALC_STR·CALC_STR_PART·CALC_STR_URC·GET_URC_TYP
- 중간변수 GET_VARI_VAL·SET_VARI_VAL (:=A01 라벨)
- 반올림 MROUNDUD·MROUNDUP·MTRUNC·MINT·MFRAC·GET_ROUND_CUT
- 조건 IIF·IFI·IFO·CHK_TRUE_CLSTR — 식에 조건 분기가 들어감
- AMTTOHAN 금액 한글 변환
- ⇒ 식 평가기는 사칙연산+ROUND 만으로 부족. 조건 함수와 중간변수 필요

ST_P_XLS.CPM 72함수 — 엑셀이 양방향 교환 경로
- CONV_XLS_2_ST(엑셀→STmate 역등록)·XLS_2_BDREC(엑셀→BDQTY)·Prn_FMLA_INFO
- 암호화된 BDQTY 를 엑셀에서 만들 수 있다는 뜻

SX32W.CPM 29함수 = Rainbow Sentinel SuperPro 동글 API
- 라이선스가 소프트키가 아니라 USB 동글. 통제시험이 영구 불가인 근거 확정

ST_Jabpum: Edt_Hal_Amt / Edt_Hal_Rate — 할증이 금액·율 두 갈래

변경 차수 8차 의문 해소
- PRJLST.SMT 섹션 최대 2, DBF 접미사 1~4, 바이너리에 1~3차변경만,
  BOQ2* 없음. 한 파일은 4벌이 맞고 8차는 분리형 파일 선택임

문서 24 신규, export 원자료와 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
PRJLST.SMT 저장키 전수
- 241종. 접두어가 뜻을 가름 — C_(금액직접입력 62)·R_(요율 39)·I_(선택 41)·
  B_(켬끔 12)·D_(밑수 26)·S_(산출액 30)·ADD_(추가금액 22)
-  D_ 와 S_ 가 같은 항목 이름으로 짝을 이룸. 항목마다 「어떤 밑수에 곱했고
  얼마가 나왔는지」를 프로젝트에 남김. 09번의 indirect_result 계약과 맞음
- 추가금액 저장 구조 ADD_AMT_단계_행_칸 (11번이 화면 문자열로만 본 것)
- 고용개선지원비가 휴업수당·장려금·사회보험·지원금 네 갈래
- 수공 밑수 배분 계수 R_R_DM·DL·L·DMDL·DML 이 rGrd_RateB 열 이름과 일치

간접비 식 템플릿 26개 전수
- 밑수별 기본 꼴 여섯 (총액·노무·재료·노무+토큰·총액-재료·세 성분 합)
- ⚠ 식 안에 IF(...) 조건 분기가 있음. DP_Common 의 IIF·IFI·IFO 가 처리.
  사칙연산과 ROUND 만으로는 재현 불가
- ROUNDDOWN([C_KUNBO]*[RAT_1]) — 장기요양은 건강보험료 「직접입력 금액」에
  요율을 곱함. 19번의 「당초액 유지」와 이어짐
- 복합 보험식·변경설계 A/B·사급자재 /1.1 전부 포함

설정 사슬이 닫힘 — 화면 272축 → 저장키 241종 → 식 26개 → 함수 73개 →
D_/S_ 재저장 → 출력. 다섯 칸이 모두 이어짐.

문서 25 신규, 키 원자료와 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
eomsangdon added 2 commits 2026-09-13 14:48:18 +09:00
- 장 나눔·제원 입력 엔진과 기울기 판정 대상을 B08 로 옮김
- 창구를 /quantity/structure-sheets 로 옮기고 기초잡석 두께·지반 갈래를 함께 넘김
  (옛 B07 창구는 두께를 안 넘겨 원단위 탭과 값이 갈렸음)
- 구조물도 탭 조각 renderStructureSheets 신설 — 탭 등록은 브레인 몫이라 안 붙임
- B07 표준도 목록은 탭 배선 날까지 B08 엔진·창구를 불러 그대로 둠

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 14 commits 2026-09-13 14:48:51 +09:00
Cm(사이클 시간) 식 54꼴
- t1+t2+t3+t4 4단계가 최다. 5·6단계도 있음
- 운반은 L/V1+L/V2+0.25 — 거리/적차속도 + 거리/공차속도 + 상수.
  임도 토공 운반에 그대로 쓸 수 있음
- 굴삭기는 선회각별 사이클 초 (90도 18초, 135도 20초)

품셈 인자 실측 — q(버킷용량)·K(버킷계수)·f(토량환산)·E(작업효율)·V1~V4(속도)·
t1~t6(단계시간)·P=qo*eo(출력)
- ⚠ f 가 1/1.3 같은 분수 문자열로 적힘. 미리 소수로 접으면 자릿수가 어긋남

wM_Edit_San 은 단순 입력이 아니라 식 편집기
- 손료계산(F6)·계산(F9)·중기공식 편집·함수 입력·연산기호·변수명
- 문법 강조·문법 오류 검사·문법설명 보기
- COSTN.SMT 전개 텍스트가 이 편집기의 산출물. 재구현하려면 식 언어와 검사기 필요

⚠ 낙찰율 NAGCD 발견 — 계산 사슬에 없던 것
- wBoq 단가 그리드 23열의 마지막이 NAGCD(낙찰율)
- wM_Edit_San 에 결과값에 낙찰율적용·계약단가·결과금액조정
- 우리가 판 8단계는 설계까지임. 계약·실행예산·기성·준공 단계가 더 있고
  계산 규칙이 다를 수 있음 (기성 제잡비는 실제로 부가세 선택지가 다름)

그 밖
- 내역 계층 표기가 += ~ +===== 로 레벨을 나타냄
- Prn_* export 152개를 SET_REP 74종과 이어 64종 대응

문서 26 신규, 스크립트 3개·원자료 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
26번에서 「우리가 판 8단계는 설계까지」임이 드러나 그 뒤를 팠음.

계약 (wM_Mk_Cont)
- 낙찰율이 하나가 아니라 노·재·경 세 갈래로 따로 들어감
- 적용율을 제외할 공정을 행 단위로 고름 (관급자재대 등).
  16번의 C* 제외금액 구역과는 다른 개념
- 단가적용율 0% 이면 계약단가를 0 으로 만들어 공내역 생성
- 예상적용율 찾기 — 목표 계약금액에서 역산

기성 (wM_KanJub_K)
-  간접비가 「금회직접공사비 x 계약제잡비율」 단일 요율로 바뀜.
  설계처럼 항목별 밑수x요율이 아님
- 전회·금회·누계와 각각의 비율을 함께 들고 감. 사정·잔량·기성고(%) 포함
- ⚠ 부가세 선택지가 설계와 다름 (재료비+산출경비의 10% 추가)
- BOQ11 의 QTY1_B/N/O/H 가 기성 수량 칸으로 보임 (설계 표본에선 전부 0)

실행예산 (wM_Boq_ExecX)
- 설계단가를 그대로 쓰지 않고 실행단가를 따로 만듦
-  차액 보정 순서 — 성분별 절사로 생긴 차액을 어느 비목에 몰아줄지 고름

준공은 계약금액·준공금액 두 열뿐. 별도 계산 없음.

계약제잡비율 계산은 ST_KanJub 한 곳에만 있음.

⚠ 설계는 원 단위까지 재현했으나 뒤 네 단계는 「구조는 알고 값은 못 맞춤」.
기성·계약 STC 표본이 0건이라 골든셋 검증 불가.

문서 27 신규, 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
식 언어의 변수 선언이 드러남
- 「금액변수 대상:M, 저장:S, %」「소계변수 대상:M, 저장:L, %」
- 변수마다 어느 비목에서 가져와 어느 비목에 넣을지와 비율 여부를 함께 지정.
  단가 식은 숫자 계산이 아니라 비목 사이의 값 이동임
- 금액변수/소계변수가 갈리고 「금액을 계산후 제외처리」가 따로 있음
- ⚠ 중기공식(Q식)을 사용자가 등록·수정·삭제함. 10꼴은 고정 목록이 아님

STmateQty8 — 수량산출서가 별도 파일이고 엑셀 셀에 별명을 붙여 변수로 씀
- 기본수량변수(내역에 붙음) ↔ 확장수량변수(셀별명, 중간값)
- 수량산출서 → 단가산출 전송 경로. Aislo B08 과 직접 겹침
- 표본 QCODE 가 전부 빈 표라 파일 형식은 못 봄

ST_U_Convert — 조달청·XML 양방향 변환이 프로그램 안에 있음
- Conv_Jodal_ST8 / Conv_ST8_Jodal / Conv_ST8_XML / Conv_XML_ST8
- MK_K_FLD·CHK_K_FLD 호환규정 필드 생성·검사
- XML 스키마는 실행 중 조립이라 정적으로 못 얻음
-  같은 모듈에 노임 직종 사전 106종이 평문으로 있음. CONLD·COND_ 의
  직종 코드가 가리키는 이름표

식 문법 오류 메시지에서 규칙 여섯 (줄 단위 검사·거듭제곱·강제금액·
그림코드 제약·집계제외·비목별 군별단가)

⚠ EQSYNC.DBF 도 암호화. 암호화 파일이 셋으로 늘었음
(BDQTY·SYSINFO·EQSYNC)

문서 28 신규, 문자열 훑기 스크립트 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
브레인(데스크탑 메인) 요청 둘 처리.

① 16번 골든셋 재현 의존성
- 골든셋·단가조립·자재채택 계열은 로컬 원본 C:\경영정보(주) 를 안 씀.
  저장소 안 실무문서/ 자료만 봄 → 랩탑에서도 그대로 돎
- 다만 D:\aislo-wt\sub 절대경로가 박혀 있어 창마다 깨졌음.
  스크립트 23개를 저장소 뿌리 자동탐색(_repo_root)으로 고침
- 고친 뒤 골든셋 재실행해 6건 전부 여전히 초록 확인
- 로컬 원본이 필요한 25개는 설치폴더 분석용이며 검산과 무관

② 자원 이름·코드 목록 (단가 없이도 축 매칭에 쓸 것)
- STC 의 COSTN.DBF 가 평문이라 코드·명칭·규격·단위가 그대로 읽힘
- 실무 7건 합쳐 서로 다른 코드 894개
  M 재료 228 · D 단가산출 273 · B 일위대가 158 · X 중기 96 · S 경비 92
  · L 노무 37 · W 일식견적 10
- 출력 XLSX 의 목록표 시트 6종에서도 317개가 평문으로 읽힘
- 30_원자료/stmate_code_name_list.csv 로 저장 (code·name·size·unit)
- 곁들여 ST_U_Convert 에 노임 직종 사전 106종이 평문 (28번 §3.1)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
전제: 가격 값은 중요하지 않음. 반기마다 바뀌고 Aislo 는 자기 원천을 구독함.
중요한 것은 코드 체계·분류 깊이·명칭/규격/단위 자리·카탈로그 규모.

스키마는 암호화돼 있지 않음 — 막힌 것은 레코드 본문뿐
- JDCODE_*.BSC 12필드: 분류3단 + JDCODE(17자리) + NAME + SIZE(110자) +
  UNIT + EQCODE + GNCODE + TYP_STN + PSCODE + ST_NAME(표준명칭 별도)
- GRPCOD_*.BSC 7필드: CUR_COD/ROT_COD/LEV 부모-자식 트리 + 형제순서
- CSTA 32필드: 재·노·경 세 성분 두 벌 + _R 계열 + 비목별 요율

암호는 오프셋별 고정 변환
- 같은 필드 안에서 같은 평문은 늘 같은 암호문 (EQCODE 57,580행 단일 암호문)
- ⚠ 필드가 다르면 키가 다름. ROT_COD 가 CUR_COD 와 일치하는 비율 0.0%
  → 필드 안 동일성만 셀 수 있고 필드 사이는 못 이음. 트리 연결 복원 불가
- ②트랙의 STC 난독화 판정과 같은 결론이고 기준자료에서도 성립함을 확인

값을 못 읽어도 잰 것
- 자재 57,580건 전부 고유 코드인데 명칭은 1,761종뿐. 같은 이름이 규격만
  달리해 평균 33건씩 갈림 — 규격 매칭이 자원 축의 실제 난관임을 수치로 보임
- 단위 59종(자재)·130종(통합). 분류 4~5단 깊이, 상위 노드 596/5,792개
- 경비·중기는 EQCODE·PSCODE·ST_NAME 을 쓰고 자재는 안 씀
- 표준시장단가는 RATE_L(72종)만 채워지고 RATE_M·RATE_S 는 빈칸
  = 노무비만 요율 조정. 설치폴더의 「노임외 재료비적용」 파일명과 일치

⇒ 가격을 못 읽는 것이 축을 세우는 데 걸림돌이 되지 않음. 이름·코드가
필요하면 평문인 COSTN.DBF 쪽에서 얻음(894개 이미 추출).

문서 29 신규, 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
최종 빈칸 점검에서 확장자 기준으로 한 번도 안 연 파일을 훑다가 나옴.
28번의 「XML 스키마는 실행 중 조립이라 못 얻음」은 틀렸음 — 정정함.

System/Valid_Xml.vsl = 조달청 공사원가호환규정 V1.0.5 XSD 전문 (1,429줄)
- 조달청 공사원가통합관리시스템(npccs.g2b.go.kr) 발표하는 공개 규격.
  STmate 고유가 아니라 국가 표준이라 Aislo 가 그대로 따르면 됨
- complexType 32 · simpleType 21 · 열거형 40곳
- 같은 폴더에 「호환규정코드(2026_09_01)」 안내문도 있음

문서 뼈대가 우리가 판 STmate 구조와 한 겹씩 대응
- 일위대가/상세 · 중기단가산출 · 기계경비/상세 · 자재 · 노무 · 경비항목 ·
  실적단가 · 제경비항목 · 내역서→공종→세부공종

 규격이 우리 계약을 뒷받침함
- 제경비항목에 적용산식·적용산식설명 칸이 있음 = 「식을 데이터로 저장하라」가
  납품 규격의 요구사항이기도 함
- 직접공사비정보에 제요율적용제외공종_금액 이 박혀 있음 = C* 제외금액 구역과
  낙찰율 적용제외가 국가 표준에도 있는 개념

 기계경비 산출 규격이 우리가 캔 것과 정확히 일치
- 시간당노임산출 H0-일반구간·H1-터널구간·H2-장대터널·H3-펌프준설선·
  H4-그래브준설선·H5-버킷준설선·H_-사용자정의
  = 22번의 wM_Set_Sys cmBx_Sel_RX 와 하나도 안 틀림.
  Start8x.Ini 의 RXXNM·RX1NM~RX4NM 이 이 자리임
- 환율형식(USD/EUR/100엔)도 EXNM_·EXEUR·EXYEN 과 맞음
- ⚠ 시간당손료산출이 E0-주간·E1-야간·E2-2교대·E3-3교대 네 갈래.
  17번에서 뽑은 손료율 25개는 E0 하나뿐임

열거형 — 주공사 9종(국가유산수리 포함)·공사현장지역코드 290·인도조건 40·
시설물유형 27·지역구분 3(산간도서 포함)·내진등급·에너지효율·녹색건축 등

XSD 사본과 구조 덤프를 30_원자료에 넣음. 최신판은 npccs.g2b.go.kr 에서
직접 받을 것.

문서 30 신규, 스크립트 2개 추가.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
eomsangdon added 1 commit 2026-09-13 14:54:00 +09:00
eomsangdon added 9 commits 2026-09-13 14:54:06 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
- ① 이름 잇기 74자리 · ② 지반 갈래 어휘 8벌·별칭 사전 11곳 · ③ 코드 없는 공종 37
- 명세와 어긋나는 실측 다섯 — 자원 축 파일은 안 쓰는 옛것(지금 575줄·못 맞춤 508) ·
  부모 코드에 수량(FP-09-04·10-12·09-15 금액 안 섬) · 별칭은 표 범위에서만 참 ·
  #갈래 제목 202건이 한글 키 · 콘크리트 축 두 벌
- 코드 무변경. 곁 발견(자재총괄 누락·B07 확정 재계산 덮어쓰기)은 기록만

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
eomsangdon added 1 commit 2026-09-13 14:56:06 +09:00
- 구조물 원단위 탭 앞에 「구조물도」 탭 등록(브레인 지정 배선 권한)
- 탭 차례 바꾸기·원단위 흡수는 PLAN 5장 몫이라 손대지 않음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-13 15:04:43 +09:00
- 도면 목록·단건 조회·화면 제원 칸·[여기서 고치기]·창구 함수 제거
- 도면 kind 에서 standard 를 뺌. 표·그림 조립(build_standard_drawing·그림)은
  B08 상단 그림 일감이 다시 쓸 자리로 남김
- 옛 [여기서 고치기] 시험을 B08 구조물도 탭 폼 자리 확인으로 바꿈

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-13 15:04:49 +09:00
eomsangdon added 1 commit 2026-09-13 15:11:00 +09:00
eomsangdon added 5 commits 2026-09-13 15:11:06 +09:00
- 자재 0 의 뿌리: 사급 자재 카탈로그 부재(관급 나라장터뿐) · 품셈 칸 규격 없음 ·
  자재 칸에 섞인 경비·작업 단계 · 구조물 표는 값 없이 이름만
- 못 맞춘 508 중 임도 60코드 몫 138줄, 절반은 표 딱지를 이름으로 읽은 표 읽기 문제
- STmate 목록이 이름·규격을 대는 것 13종 · 판정 물음 넷
- 코드 무변경(메모리 실행 진단)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
eomsangdon added 4 commits 2026-09-13 15:23:09 +09:00
목적: 값이 아니라 조합을 확보하는 것. 표준일위대가 배포본은 암호화라 못
읽지만 실무에서 실제 쓴 조합은 출력 엑셀에 평문으로 남음.

누락 감사 — 호표 526개를 하나씩 셈
- 일위대가표 170개 전부 추출, 누락 0
- 중기사용료 143개 전부 추출, 누락 0
- 단가산출근거 213개 중 187 정상 + 빈호표 5 + 못잡음 21
- 못 잡은 21개는 전부 정체 확인함. 운반 계산(거리·속도 인자만 있음)과
  기계+인력 비율 조합이라 「자원 조합」이 아닌 것. 값을 못 읽은 게 아님
- 빈 호표 5개는 무대처리·흙쌓기 등 금액 0원 항목
⇒ 설명되지 않는 누락 0건

확보한 조합 350개 (중복 제거)
- 일위대가 132 · 단가산출 136 · 중기 82, 구성행 1,729 (조합당 평균 4.9)
- Q식을 가진 조합 107개
- 150/350 이 다른 호표를 참조 — 2단 이상으로 쌓임
-  규격이 바뀌면 구성은 같고 수량만 비례 (기슭막이 H=2.0 vs 2.5).
  한 조합 + 규격별 수량표로 접을 수 있음
- 건설표준품셈이 23개 조합에 근거로 적혀 있어 현행 갱신 시 대조점이 됨

⚠ 수량은 그 시점 품셈값이므로 조합은 그대로 쓰되 수량은 현행 품셈으로
다시 맞춰야 함.

30_원자료/일위대가_레시피.json (265.8 KB) 와 감사 기록 저장.
문서 31 신규.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
eomsangdon added 9 commits 2026-09-13 16:47:28 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
- 명세 13장 식 언어(사칙·^·비교·SQRT·MIN·MAX·SUM·IF·LOOKUP 근사/EXACT)를 직접 짠 파서로 풂
- 수는 BigInt 분수로 들고 적힌 차례대로 풂 — 부동소수 버림·반올림 1 틀어짐 막음
- 줄마다 반올림 floor·round(사사오입)·ceil·none·round_half_even, refs 는 앞 줄만
- 서버는 build:formula 번들을 Node 로 부름(B06 Server_Calc 본), 파이썬은 껍데기뿐
- 시험 15건 — 실무 찰쌓기 탭 12줄 엑셀 캐시값 재현 포함

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-13 17:02:29 +09:00
- 풀이기에 명세 13장 보강분: when(안 선 줄, 가리키면 오류) · destination 필수(기본값 없음) ·
  spec 의 {제원} 채움 · 반올림 trunc(ROUNDDOWN)·ceil_away(ROUNDUP)
- resources/library_structure/masonry_wet.json — 줄 15 · 뒷길이×돌종류 표 · 제원 vars ·
  물구멍 2.5㎡ 실무 관측은 대안 후보로
- 양식 제원 채우기 B08_Quantity_Engine_StructureTemplate.py(계산 없음)
- 대조 시험 121건: 높이·뒷길이·돌종류·기초·사용자 칸·when 갈래에서 전개와 한 줄도 안 갈림.
  알려진 차이 하나(실무 관행 계수가 돌종류를 지우는 전개 결함)는 시험에 드러냄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 10 commits 2026-09-13 17:02:44 +09:00
eomsangdon added 1 commit 2026-09-13 17:09:03 +09:00
- 브레인 판정(PLAN 10장): 관이 벽을 가로지르므로 개소당 길이 = 평균두께(옛 붙박이 0.5m)
- 골막이는 그 정본이 0.5 라 그대로 둠
- 찰쌓기 양식 물구멍관 식도 같이 고쳐 대조 시험 121건 그대로 일치, 길이 시험 1건 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-13 17:11:01 +09:00
- 자재 0 해소 첫 걸음: 사급 자원 19건(AR-M 17·AR-X 2, 이름·규격·단위, 단가 칸 없음)
  resources/data_resource_catalog/ 신설 — 임도 60 + 사방 11 코드 범위의 진짜 자원만
- 규격이 조인 키: AR 항목은 후보가 하나여도 규격이 같아야 고름 · 품셈 칸에 규격이
  없으면 「규격 미정 — 후보 N」(성공으로 안 셈)
- 형식이 하나뿐인 계열만 규격으로 고름(공기압축기(이동식) 3.5·10.3) · 형식 둘이면 규격 미정
- 범위 별칭 한 벌: 화약공→화약취급공(1016) scope FP-09-05 · pum_edition 다르면 안 씀 ·
  scope 없음·겹친 두 코드는 읽을 때 오류
- 일위대가: 맞췄으나 단가 층 없는 줄은 조용히 안 빠지고 드러냄 · 기계 몫이면 막음
- ResourceAxis.py 700줄 초과분(조사용 덤프)을 _Dump.py 로 뗌
- 돌망태 품셈 절 표기 13-8 → 13-11 바로잡음
- 결과: 자원 줄 575→592(자재 0→11) · 못 맞춤 508→491 · 내역 금액 변화 0(막힌 공종 그대로)
- 시험 test_b09_resource_axis_join.py 8건 · 전체 1377 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 브레인 복구분(29180653) 넷 + 명세 갱신본 — origin/dev 와 hash-object 대조로 같은 내용임을 확인

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-13 17:23:15 +09:00
- 양식이 있는 종류(찰쌓기)는 장마다 양식으로 줄을 다시 세움(L=1 m당) — 식·설명·반올림·
  갈 곳·출처·안 섬 까닭을 줄에 실음. 양식 없는 종류는 지금 전개 그대로(고정형 모양)
- 화면 표: 산출 근거 밑에 식 한 줄 · 갈 곳 칸 · 안 선 줄은 「안 섬」과 까닭
- 전개 결함 둘 고침(브레인 판정): 「실무 관행」 계수가 돌종류를 지우던 것 ·
  기초잡석이 서는데 「두께가 없어 안 섬」 사유가 함께 뜨던 것
- 검증 프로젝트 찰쌓기 15줄 — 양식 m당×10 = 원단위 탭 합계 전부 일치

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-13 17:25:52 +09:00
- 정본 resources/data_aliases/aliases_2026-01-01.json · 로더 common_util/common_util_aliases.py
  (칸 빠짐·모르는 축·겹친 범위의 두 대상은 읽을 때 오류 · 판이 다르면 안 씀 · 양방향 조회)
- 흩어진 세 벌을 옮김: 매핑표 ground_aliases(리핑암→파쇄암·암절취) 삭제 ·
  B09 UnitPrice 전역 VARIANT_ALIASES 삭제 · B08 인계본 ground_class_aliases 는 별칭표에서 만든 보기
- 범위: 리핑암→파쇄암 @FP-10-11 · 리핑암→암절취 @FP-10-12 · 화약공→1016 @FP-09-05 (근거 문구 줄마다)
- 자원 축 별칭 검사도 같은 로더로 합침(자원 목록 폴더에서 별칭 파일을 옮김)
- 시험 test_common_aliases.py 6건 · 전체 1509 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-13 17:39:40 +09:00
- build_table 이 양식 있는 종류(찰쌓기) 성분을 양식 풀이 값으로 갈음. 양식 없는 종류는 전개 그대로
- 구조물에 library_item — 원단위 탭 「양식」·구조물도 머리 「양식 있음/없음」으로 가림
- 뒤 단계가 아직 이름으로 찾으므로 돌 줄은 종류 이름으로 넘김(1장 코드 잇기 뒤 걷을 자리) ·
  자료 출처·근거 문구는 전개 것을 그대로 둠
- 검증 프로젝트 전·후 대조: 구조물 5 중 찰쌓기 2 갈음 · 움직인 값 없음 · 자재총괄 최대 차 7e-15 ·
  채집석 공제 58.674·잔토 91.75 그대로. Node 가 안 돌면 전개 값 + 사유

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-13 17:52:23 +09:00
- 양식 장의 식 칸을 화면에서 고치면 같은 풀이기(TS)로 왕복 없이 즉시 다시 풂
- [식 저장]은 식만 보내고 서버가 Node 로 다시 푼 값을 돌려줌 — 브라우저 값을 받아 적지 않음
- 고친 식은 프로젝트 장 단위(산출 조건 structure_formula_overrides) · 양식 식과 같거나 비면 지움
- 원단위·자재총괄·인계·유토 입력(build_table)도 같은 고친 식을 봄 · 고친 줄 출처 user(「사용자 식」)
- 틀린 식도 막지 않고 저장하되 줄마다 오류를 돌려줌 · 양식에 없는 줄 차례는 400
- 개인 라이브러리 저장 단추는 4장(라이브러리 저장소) 몫으로 남김

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-13 18:02:54 +09:00
- 뭉친 줄 해석기: 「굴 삭 기 (무한궤도)」를 굴착기(무한궤도)로 맞춰 큰돌쌓기 메쌓기(13-6-1)·
  13-7-2 장비 몫이 붙음(형식을 적은 이름만 · 형식 없는 굴삭기는 판정 Ⓒ대로 규격 미정)
- 비고·합계 줄을 자원으로 안 읽음(단목베기 4-2-2 가짜 막힘 제거) · 「-」 칸은 그 갈래에 품 없음
  (산림복원용 흙막이 13-13-2 가 특별인부·굴삭기 빠진 채 조용히 서던 것을 사유와 함께 막음)
- 지장목제거(판정 Ⓑ): 잡관목제거 → FP-04-02-02 #5m미만 · 뿌리뽑기 → FP-09-21 + 임목축적 등급 갈래 ·
  준비공 「제근·뿌리다듬기」는 같은 면적이라 참조로만(이중계상 막이) · 미결 목록에서 뺌
- 기계 이름 별칭(백호·굴삭기→굴착기)은 별칭표 대상이 아닌 카탈로그 이름 정규화로 주석 정리
- 일위대가 전후 대조(HEAD↔수정): 새로 선 공종 13-6-1·13-7-2 · 새로 막힌 공종 13-13-2(사유 있음) ·
  내역 금액: 단목베기·제근은 밑수 미확보로 계속 막혀 변화 없음 · 전체 시험 1513 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 저장 칸 structure_formula_overrides 의 키를 장 이름에서 양식 type_id 로 바꿈(브레인 판정, PLAN 10장)
- 구조물도·build_table 모두 type_id 로 찾음 · 같은 양식의 장이 모두 같은 고친 식을 받음
- 화면 안내에 「같은 양식의 장 모두에 걸림」 · 시험: 뒷길이를 고쳐 장 이름이 바뀌어도 사용자 식 남음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-13 18:21:24 +09:00
- 라이브러리 항목을 목록으로(항목마다 AX-ST-<8hex>.json) · 기본 찰쌓기에 코드 부여
- 가져오기: 로그인한 사람의 개인·회사 단 + 프로그램 기본에서 골라 {프로젝트}/B08_Quantity/library 에 박음 · 그 종류의 고친 식은 비움
- 표·원단위·자재총괄·인계는 박힌 양식 → 없으면 프로그램 기본만 읽음(여는 사람마다 값이 안 갈림)
- [확정] 때 아직 안 박힌 기본 양식을 박음 · 장 머리에 「어느 단에서 가져왔나 · 고친 식 N줄」
- 시험 test_b08_structure_library.py 6개 · 전체 1524 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-13 18:21:55 +09:00
- 마스터 생성기: 밑수가 절 이름에만 있는 표를 이름 전체가 「수+단위+당」일 때만 읽음 —
  4-2-1 「100본당」·4-2-2 「1,000㎡당」 두 표만 바뀜(재생성 diff 2표 · basis_missing 140→138)
- 뭉친 줄 조합 기종: 앞머리를 공백 지우고 견줌 — 「굴착기+부착용집게」가 카탈로그 「부착용 집게」에 붙어
  단목베기 4-2-2 가 섬(X-0201-0020#조합 + 부착용 집게)
- 실무 대조: 단목베기 5m 미만 866원/㎡ ↔ 영월 설계내역 「잡관목제거 벌목(5m미만)」 882원/㎡(노임 연도 차 2%)
- 합판거푸집 12-4: 사용횟수별 비율 미구현이라 일부러 안 풂 — 막힌 사유를 그 까닭으로 갈아 끼움(판정)
- 일위대가 HEAD↔수정 대조: 바뀐 공종은 FP-04-02-02 하나 · 전체 시험 1522 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-13 18:32:35 +09:00
- [내 라이브러리에 저장]: 그 장의 양식 + 고친 식을 로그인한 사람 개인 단에 한 벌로 씀(같은 종류는 그 코드로 덮어씀) · 저장 안 한 식이 있으면 막음
- [내 것 지우기]: 개인 단의 그 종류만 지움 · 박힌 양식·고친 식은 안 바뀜
- 기본 찰쌓기 양식에 pum_edition 2026-01-01(명세 17장 ③)
- 결함: 식 저장 뒤 다시 그린 표에 「저장 안 한 식」 표시가 남아 헛물음이 뜨던 것 — 장을 그릴 때 비움
- 시험 2개 추가 · 전체 1531 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-13 18:47:40 +09:00
- 식 칸 옆 반올림 고르개·자리수 · 고르개에 「버림 — 엑셀 ROUNDDOWN」처럼 엑셀 이름과 음수 보기
- 고친 반올림은 고친 식과 같은 자리(양식 + 프로젝트)에 저장 · 양식과 같으면 지움 · [양식대로]로 식·반올림 함께 되돌림
- build_table 도 양식을 m당(L=1)으로 풀고 연장을 곱함 — 실무 시트처럼 뒷줄이 반올림한 값을 보고 구조물도와 안 갈림
- 「대안 후보」(물구멍 2.5㎡ 등) 표 밑에 보임 · UI 700줄 넘어 식 칸 표를 _Formula.ts 로 뗌
- 시험 2개 추가 · 전체 1533 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-13 18:54:03 +09:00
- 양식 갈음의 종류 이름 치환(_downstream_name) 삭제 · 돌쌓기·골막이·바닥막이(메) 전개도 「돌」+규격
- 자재총괄 줄에 spec·supply_key — 관급구분 열쇠는 이름+규격, 옛 열쇠(이름만·종류 이름)도 받음
- 화면 자재총괄 이름 칸·원단위 성분 칸에 규격 표시, 관급 선택은 supply_key 로 저장
- 원단위 합계 열쇠에 규격 포함 · 종류 이름 DESTINATION 항목 정리

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- dev 8210c2b7: 돌 줄 이름 「돌」 + 규격에 종류(_downstream_name 걷음) 그대로 취함
- sub_laptop_1 cf0ccfac: _user_basis(식·반올림 근거) · m당 풀이 × 연장 그대로 둠
- 병합 뒤 전체 1535 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-13 18:54:25 +09:00
eomsangdon added 2 commits 2026-09-13 19:02:39 +09:00
eomsangdon added 1 commit 2026-09-13 19:15:29 +09:00
- 양식에 unit_price.rows(수량은 원단위 줄 from_row · 코드는 work_item_code+variant_from 또는 ref_code)
- 서버가 B09 단가표(PriceBook.resolve, 읽기만)로 줄마다 재료·노무·경비 · 금액란 0.1원 버림 · 계금 1원 버림
- 못 푼 줄은 막힘 + 까닭(0 아님), 원단위 줄이 안 선 장은 안 섬 · 단위 다름·하위 구조물(B-AX-ST)은 막힘
- 창구 /structure-sheets/unit-price 를 장 조회와 따로 둠(단가표 첫 조립 14초)
- 찰쌓기: 돌쌓기 B-FP-13-04-05#갈래 · 기초잡석 B-FP-12-25 · 모르터는 공종 코드 미정
- 시험 4개 추가 · 전체 1539 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-13 19:25:37 +09:00
- 마스터 부모 94곳에 parent_mode — 기본 choose_one, 합산형은 사람이 적은 셋(9-4·9-5·12-38)만 단계·가중치
- 9-4 암절취 = 암파쇄(연암·보통암·경암, 브레이커+굴착기 조합 1/Q) + 집토(굴착기 0.7 공식) 합으로 조립
- 표에 없는 암질은 9-4-1 [주]① 평균으로만 섬 · 9-5 발파암은 발파 단계(착암기 층 없음) 사유로 막힘
- B08 인계가 흙깎기 암 갈래 이름을 갈래 값으로 넘김 · 갈래 고르기형 부모를 가리키는 줄은 오류로 막음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 줄이 B-AX-ST-* 를 가리키면 그 양식을 sub_vars 제원으로 L=1 풀고 일위대가를 먼저 세워 안 자른 단위당 금액을 씀
- 깊이 5단(PLAN 10장 판정) · 돌면 막힘 · 하위가 미완이면 윗 줄도 막힘 · 제원이 비면 막힘(0 으로 안 풂)
- 하위 양식은 프로젝트에 박힌 것 + 프로그램 기본에서만 찾음(개인·회사 단은 안 읽음)
- 시험 3개 추가 · 전체 1548 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-13 19:46:33 +09:00
- 9-12·9-13 「대형브레이커(㎥/hr)」 줄에 같은 표의 굴착기를 같은 1/Q 로 붙이고 #조합(잡재료 16%)으로 바꿔 닮
- 구조물터파기·측구터파기 암·발파암 갈래 단가가 몸체 장비비만큼 오름

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 줄 조합은 양식+프로젝트(종류별), [내 라이브러리에 저장] 때 양식에 실림
- 수동 단가는 프로젝트만(값·출처·넣은 날짜) — 빨간 테두리 + 「미확정 N건」
- 고르개는 이 프로젝트 단가표에서 품셈·자원을 낱말로 찾음
- 다른 양식을 가져오면 그 종류의 줄 조합·수동 단가도 비움

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-13 20:12:28 +09:00
- 정본 둘(structures.json·pipe_points.json)과 B06 관 연장을 읽어 종류별 표로 세움
- 한 줄 = 측점 + 실치수(제원 칸) + 개소·연장 · 표마다 개소·연장 합·평균치수
- 칸 출처 자동·사용자·라이브러리(양식 기본값)·빈칸 · 배수관과 세월교는 다른 표
- 이 표에서 고친 값을 B05 가 바꾸면 빨간 테두리와 알림(조용히 안 사라짐)
- 구조물도 탭 앞에 탭 등록

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 5 commits 2026-09-13 21:55:55 +09:00
산림 품셈엔 배합 절이 없어 건설 품셈 [건축] 9-1-1 을 옮김 — 보통인부 0.66인/㎥(모래체가름 포함).
시멘트 510kg·모래 1.10㎥ 는 자재 단가 층이 없어 안 붙은 줄로 드러냄(원문 할증 포함 값).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
단끊기는 공정 네 줄을 토질 갈래마다 더하고 [주]⑤ 작업반장 1인/보통인부 20인을 더함.
원문 합계 줄은 절취를 ㎥당으로 더한 값이라 안 씀(까닭을 적은 공종만 섬). 같은 모양 뭉기기 13-12-1 은 안 더함.
「단위:」 없이 분모만 적은 본문 밑수를 읽어 조림·시비·떼심기 22표가 밑수 없음에서 풀림.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 칸 조작은 캐시(sessionStorage)에, [저장] 때 structures.json·pipe_points.json 에 바로 씀
- 산출 조건에 손댄 칸 표(고치기 전 값) · ↺ 로 되돌리면 자동으로 돌아감
- 상세 칸만 고침 — 자리·길이·높이·관경은 시·종점과 한 벌이라 구조물 놓기(B05) 몫
- 틀린 값·놓기 칸·판번호 어긋남은 아무것도 안 씀 · 값 꼴은 구조물도 제원 저장과 같음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 9 commits 2026-09-13 22:12:21 +09:00
12-6 은 두께 칸이 작업조 칸과 엇갈려 병합된 표라 두께 줄을 시공량 갈래로 읽음(20·30·40㎝, ㎥당).
후진 진입·경운기 칸은 「50%까지 감」 범위라 안 세움. 공종 단위가 빈 작업조 표는 시공량 열 머리 단위를 씀.
13-4-1·13-4-4 는 hwpx 병합대로 앞 세 돌 골·켜 두 잎 + 호박돌 및 야면석 한 잎으로 갈래를 세움(각 40 갈래).
13-4-4 는 같은 절의 표준경사 표 오판정으로 아직 막힘 — 형태 판정 일감으로 넘김.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
자동 판정이 못 가른 76표 중 64표와 오판 2표(13-4-4 뒷길이 표준·표준경사)를 표 머리·바로 위 본문 단위로 가름.
생산량형 8 · 소요량형 1 · 계수 23 · 참조 34. 못 가른 13표는 미판정으로 남김.
표 번호와 절 번호를 함께 대조해 원천 차례가 밀리면 빌드를 멈춤. 일위대가 금액 변화 없음.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 운반 줄 단가를 이름으로 되찾던 자리를 인계 줄 → 내역 줄 짝으로(도자운반 토사·리핑암 같은 이름 실결함)
- 총 절취량 검산을 줄 이름 「깎기」·「절취」가 아니라 코드 9-3·9-4·9-5 로 셈

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 5 commits 2026-09-13 22:27:04 +09:00
① 구조물 터파기·되메우기는 토공집계로만 — 토공·사토 공제·참고로 가는 성분을 구조물 줄·묶음 조각·타설·기초잡석이 또 집으면 오류.
② 시멘트·모래·자갈이 자재총괄에 뜨면 오류. ③ 원단위표가 할증을 붙였거나, 자재 합계가 순수량 × (1+율) 과 다르거나,
할증 포함 재료량을 준 공종에 자재가 일위대가 재료비로 붙으면 오류.
판정은 B08 인계(double_count_violations), 멈춤은 B09 build_bill 한 자리. 배정 프로젝트 실측 어긴 자리 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 양식 일위대가로 셀 구조물도 장은 인계 줄 하나(코드 AX-ST · 갈래 = 제원 키 · 수량 연장 m)
- 양식이 품은 줄(기초잡석)은 따로 인계 안 함 — 이중계상 막음
- B09 내역이 자기 단가표로 B08 일위대가 엔진을 돌려 금액 · 못 받거나 막히면 사유
- 수동 단가도 씀 — 내역 요약에 미확정 N건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-13 22:36:19 +09:00
- 내역 단가 = 구조물도 일위대가 표 계금(성분 칸 0.1원 절사 합의 1원 절사), 금액 = 성분 소계 × 연장
- 명세 7장 「호표 안 성분 소계는 절사」 — 안 자른 값을 쓰면 192,429 ↔ 192,430 으로 갈렸음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-13 22:45:51 +09:00
- 내역서 창구가 기본값 cached_build() 대신 _build_for(프로젝트) 를 씀 — 계수를 고른 프로젝트에서 화면과 내역이 갈리던 자리
- 단가산출서 한 장 창구도 같은 단가표

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-13 22:55:32 +09:00
공종 마스터·자원 축 줄·B08 인계 줄마다 공종 코드가 본 판을 실음(명세 17장 규칙 3).
판이 다른 인계 줄은 내역서에서 「확인 대기」로 빠지고, 코드에 박힌 절 번호(합산 단계·표 형태 판정·가드 목록)는
마스터 판과 다르면 마스터 빌드·단가 조립을 멈춤(규칙 4). 판 기준은 common_util_pum_edition 한 곳.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- find_variant_code 가 글자 대신 수의 짝·구간으로 고른 자리를 한 번씩 로그(명세 14장 정정, 판정 (나))
- 수량 소수자리는 이름 그대로 두고 종목 이름을 못 맞춘 줄만 로그

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-13 23:13:26 +09:00
- 계수로 미리 접으면 267,360 → 55,699 로 1원 틀림 — 식 1/8*16/12*25/20 을 차례로 풀어 55,700
- 중기 호표 운전원 줄은 시간당 노임 제목(#시간) × 인수로 부름(STmate 운전원 1 × 55,700 모양)
- 골든셋 시험 test_b09_golden_stmate — 실무 6건 환율및기초자료 시간당 칸 전수 재현
  (다섯 건 원 미만 절사 · 2025 울진 소광 0.1원 미만 절사 — 자리는 설정값)
- 28자리 끝 반올림 차례만 다른 합 비교 시험을 허용 오차로

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 8 commits 2026-09-13 23:29:20 +09:00
기초잡석 줄·콘크리트 타설 줄은 여러 구조물 성분을 이름으로 모아 한 줄로 세워 누구 것을 뺐는지 안 남김.
그래서 물량 보존으로 봄 — 모음 줄 + 양식 호표(B-AX-ST)가 품은 몫 + 묶음 조각이 원단위 합을 넘으면 오류.
빌더의 건너뛰기를 따라 짜지 않아, 다른 구조물에서 건너뛰기를 빠뜨리면 여기서 걸림. 배정 프로젝트 어긴 자리 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
종전 variant_key 는 표 첫 열 값 24개라 머리행 갈래·두 단 머리를 놓치고 첫 열이 자원 이름인 표를 갈래로 적었음.
표 모양 가르기는 B09 표 읽기에 이미 있어 두 벌을 안 짜고, 그 읽기를 메모리의 마스터에 돌려 표마다 가른 갈래를 원문 표기로 실음.
못 가른 표는 빈칸. 공종마다 variant_keys(불도저 공식 갈래·합산형 단계 암질·[주]① 평균 · 부모는 단계 갈래).
짝 시험 — 단가표 #갈래 제목이 전부 마스터 키에 있어야 함.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 잡품을 연료 수량에 접지 않고 주연료비의 % 가산 행으로(STmate 잡품 단가 칸 = 연료 금액)
- 시간당 중기사용료(X) 호표 — 줄 금액 0.1원 미만 · 성분 소계 원 미만 절사(명세 7장, 봉화 0.7㎥ 96,843)
- 조종원 시간당 노임 자르는 자리를 프로젝트 설정 operator_wage_digits 로(기본 0, 화면은 뒤)
- 골든셋 ④ 벌 — 실무 6건 중기사용료 시트 143 호표를 우리 단가표 층으로 되풀어 전수 일치

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 00:01:34 +09:00
유토곡선 장비 경계의 도자 한계거리가 config 붙박이였고 설정 칸 haul_limits_m_override 는 아무도 안 읽었음.
dozer_haul_limit_m 칸으로 갈음해 B06 유토곡선 문맥·배분·B08 산출 조건이 같은 값을 읽음(common_util 한 곳).
화면에 기본값 60 m · 근거(품셈 8-1-1 · 산림과임업기술 5장 · 실무 EARTH.DAT 전수)를 보이고, 종무대 20 m 는 규정이라 값만 보임.
종무대 이하 값은 저장에서 막음 · 비우면 기본값.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 시공능력 Q 로 선 기계 줄(굴착기·도자·직접 작업량·다짐·암 잎)은 D(단가산출)에 달고 B 는 D 를 수량 1 로 부름
- 종전 PriceBasis 의 껍데기 D(D → B) 걷음 — 「단산 N」은 D 를 품은 줄에만(갈래 줄도 실제 단가 코드로 찾음)
- 자원 집계가 B→B·B→D 참조를 끝까지 풀어 기계 사용료에 닿음(종전 조용히 버림) · 모르는 종류는 드러냄
- 조합 16% 바꿔 달기·공종 근거 문구가 D 줄도 봄
- 전후 대조: B·X 420 제목 금액 전부 같음 · 검증 프로젝트 내역 본체 122,924,846 그대로

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 00:26:50 +09:00
- 표토제거: 답외구간 FP-09-15-02 · 밑수 ㎡ · 대상 노면·절토대상지(성토 사면 안 셈) · 노면 폭이 빈 측점이 있으면 안 섬
- 표토 운반·적치: 제거 ㎡ × 두께 · 거리 − 압토 20 m · 20 m 이내면 제거 품에 듦
- 층따기: 「제안값(확정 아님)」 경고 줄 · 칸에 자동으로 안 넣음
- 시험: 옛 ㎥ 기대값 넷 갱신 · 노면 면적 평균단면적 시험

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- fix2(사사오입 0.01) — 굴착기·도자·다짐 작업량, 암 평균 Q, 표 직접 작업량
- TRUNCATED_KINDS 에 PRICE_BASIS(D) 더함 — B 는 다음 차례
- 골든셋 ③ 단가산출근거 실무 6건 208 호표 전수 일치(제외 소계·% 줄·산근 참조·계약단가 읽기) · 회귀 3,545.5 → 3,545
- 검증 프로젝트 내역 본체 122,924,846 → 122,870,975 · 전체 시험 1606 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 00:28:02 +09:00
- 산출 조건 칸 topsoil_target · 기본 None = 별표2 Ⅰ.2.차.(6) 「노면·절토대상지」
- 노면만: 실무 영월 한 건(1m당 3.34㎡) 관측 — 사유에 법 문언이 아님을 함께 적음
- 칸 밑에 근거 두 줄 · 운반 부피도 고른 대상 따라감

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 산출 조건 subgrade_compaction_enabled · 기본 False(9-16-2 [주]⑤ 「대규모 성토지로서 층다짐이 필요한 경우」 조건부)
- 토공집계 「노체다짐」 줄 · 규격 진동롤러(자주식 10ton) · 매핑 FP-09-16-02 · 갈래 없음
- [주]③ 굴착기+진동롤러 조합 중 굴착기는 성토(포설) 줄이 셈 — 두 번 안 셈(#조합 철회)
- 칸 밑에 [주]⑤ 근거

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 00:53:35 +09:00
- TRUNCATED_KINDS 에 UNIT_PRICE(B) 더함 · 비율 줄(공구손료·제잡비·품 할증)도 0.1원 절사
- 내역 줄 bill_line — 성분마다 절사(수량 × 성분 단가), 합계 = 셋의 합 · 직접비 밑수도 자른 성분
- 묶음 줄·구조물도 일위대가 표(하위 양식 포함)도 같은 규칙 — 성분 소계 원 미만 절사
- 골든셋 ① 일위대가표 성분 소계 477/510(93.5%) · 안 맞는 19 호표 = 영월 반올림 원본 17 · 영덕 적용률 줄 서식 2
- 골든셋 ① 설계내역서 줄 321 전수 일치
- 검증 프로젝트 내역 본체 122,870,975 → 122,848,989 · 전체 시험 1614 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 11 commits 2026-09-14 00:58:52 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
- 원가계산서: 폐기물처리비를 경비 줄로(예정가격작성기준 제19조③18호) · 법정경비 뒤라 그 밑수엔 안 섞임
- 분리발주 칸(기본 아님) — 켜면 총원가 밖 · 총공사비에만 더함
- 준비공 「임목폐기물 처리」 톤: WA = 0.5·π·(B/2)²·h·1.3·W1·N · WR = WA × 15/85 (한국건설기술연구원 2012)
- 조사값 넷(1,000㎡당 본수·흉고직경·수고·단위체적중량) 칸 · 기본값 없음 · 5톤·100톤 경계 알림
- 수동 처리단가 빨간 테두리 + 「미확정 N건」 · 내역엔 안 서고 제외 사유 「경비」
- 시험: 승률 구조(경비·일반관리비·이윤 밑수 증가 · 법정경비 불변 · 분리발주) · 실정보고 부피 대조

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-14 01:10:59 +09:00
eomsangdon added 1 commit 2026-09-14 01:30:05 +09:00
- 틀 B09_Estimation_UI_Shell: 탭 줄과 등록만 · 탭마다 파일 하나(계약 _Shell_Types)
- 설계내역서: 실무 열(합계/노무/재료/경비 단가·금액) · 머리글 접기·레벨 고르개 · 줄 누르면 제 N 호표 · 단산 N 단추 · 미확정 빨간 테두리
- 일위대가·단가산출근거: 목록표(내역에 처음 쓰인 차례) + 본표 · 줄 누르면 하위 호표·산근·중기로 · 자취 눌러 되돌아감 · Q 식 글자 그대로
- 옛 탭 여섯(원가계산서·중기·관급사급·기초자료·설계서 구성·산출기초)은 옛 코드 그대로 이어 붙임 — 새 탭 파일이 서면 등록 한 줄씩 바꿈
- 본표 합계 줄 = 호표 성분 소계 원 미만 절사 값 · 비율 줄 금액도 0.1원 절사 표시
- 사전 ui_template_locale_b3 새 벌(b2 700줄 넘음)
- 검증: ORCA 검증 프로젝트 — 본체 122,848,989 · 지장목제거 865·15,460,837 · 제 9 호표 합계 1,708 = 산근 8호표 합계 1,708 · 옛 탭 여섯 다 뜸 · 접기 53→51·레벨1 11줄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 01:32:14 +09:00
- 환경친화적인 도로건설 지침 부록1 확인: 뿌리분 체적 V = 0.3927D³ × 1,300㎏/㎥ — 고르개로 넣음(기본은 분배비 15/85)
- 뿌리분 직경 D 는 지침 표기 「뿌리분의 직경(DBH, m)」이 모호해 흉고직경과 따로 받음
- 지상부 식을 지침 원문대로 π 3.14 로 셈 — 실정보고 예 130.40㎥ 와 바로 맞음
- 분리발주 칸 밑·사유에 「임목폐기물은 분리발주 대상 아님(환경부 회신)」

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 3 commits 2026-09-14 01:40:19 +09:00
- 서버: /estimation/cost-sheet(GET·PUT) · /estimation/rate-table — 새 라우터 파일
- 직접비 = 설계내역서 합계 · 기준 입력 = estimation.cost_sheet · 폐기물처리비 = 임목폐기물 톤 × 수동 단가
- 서식 줄: 나.순공사원가 … 바.총공사비 (DFM TWM_KANJUB 차례·표기) · 경비 세목 번호 차례
- 기준 입력판: 형식(일반만) · 2.공사의종류 · 3.공사기간 · 6.관/사급 · 7.산업안전 · 8.환경보전 · 9.건설기계 — 선택지는 요율 데이터에서
- 요율표: 첫 탭 묶음 10개(보기 전용 · 수정은 잠김)
- 탭 계약 파일은 서브 314c0040 과 같은 내용(blob 동일) · 사전은 새 벌 b4
- 시험: 서식 차례·엔진 값 일치·폐기물 자리·저장값 거름·구간 표기

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 01:56:05 +09:00
- 서버: 내역 응답에 집계표 넷(resources)·목록표(lists) — 내역이 쓴 자원을 처음 쓰인 차례로 되모음
  (묶음 줄·구조물도 호표 줄도 구성까지 풀어 셈) · 재료비 집계표에 자재대(사급·관급) 줄 이어 붙임
- 중기시간금액집계표: 단가 열 없이 합계·노무·재료·경비 — 성분마다 반올림한 뒤 합(골든셋 131/144, 합계 한 번 반올림 107/144)
- 재료·노무·경비 집계표: 반올림(수량 × 단가) 골든셋 279/279 — 시험 한 벌 더함
- 중기사용료 호표: 잡품 줄은 수량 칸 율(%) · 단가 칸 밑수(주연료비) · 금액 — 실무 표 그대로. 제잡비·공구손료 줄도 밑수를 단가 칸에
- 자재단가대비표: 슬롯 1~6 단가·페이지 · 채택 칸 굵게 · 최소단가 표시(서버 min_slot)
- 목록표 일곱(일위대가·단가산출근거·중기·재료비·노무비·경비·일식견적): 색인만 — 서버 번호·단가 그대로, 일위대가·산근·중기 줄은 누르면 들어감
- 옛 중기 탭 줄을 새 탭으로 바꿔 끼움(중기경비계산서는 옛 표를 아래에 이어 보임)
- 검증: ORCA — 중기 목록 9 · 굴착기 0.7 호표 합계 109,704 · 잡품 22 % × 21,418.1 = 4,711.9 · 노무 집계 벌목부 9,686,529 · 중기 집계 성분 합 · 시험 1638 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 01:58:03 +09:00
eomsangdon added 1 commit 2026-09-14 01:59:55 +09:00
eomsangdon added 1 commit 2026-09-14 02:01:22 +09:00
- 화면 확인: 옮기기 전후 같음 — 표 3 · 줄 192 · 판 12 · 근거 공종 92 · 못 채운 자리 88

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 02:03:43 +09:00
- 화면 확인: 옮기기 전후 같음 — 사급 0 · 관급 0 · 안 갈린 것 13줄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 02:05:37 +09:00
- 화면 확인: 옮기기 전후 같음 — 중기 탭 표 19 · 줄 171 · 계산서 18 장(불도저 19 손료계수 1811 · 시간당 손료 35,884.965)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 02:47:06 +09:00
- 저장하면 이 탭 자료와 설계내역서 한 벌(UI_Store forgetBill)을 함께 새로 받음 — 값이 다시 섬
- 화면 확인: 옮기기 전후 같음 — 표 6 · 줄 737 · 고르개 32 개 고른 값 전부 같음 · 숫자 칸 2 · 글 35,074 자
- 계산 입력 확인: 기계 작업효율 E 평균 0.50 → 상한 0.55 를 화면에서 고르면 「사용자가 고른 값」 · 제 2 호표 2,511 → 2,284 ·
  되돌린 뒤(기본값) 2,511 그대로 — 검증 프로젝트 설정 원래대로 복구

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 02:56:32 +09:00
- 옛 탭 여섯은 모두 새 틀 탭 파일로 옮겨짐(설계서 구성 · 산출기초 · 관급·사급 · 중기경비계산서 · 기초자료, 원가계산서는 랩탑_메인)
- 화면 확인(지운 뒤 13 탭 전부): 설계내역서 53줄 · 본체 122,848,989 · 일위대가 18 · 산근 10 · 중기 표 19·줄 171 ·
  관급·사급 13 · 기초자료 표 6·줄 737 · 설계서 구성 13 · 산출기초 표 3·줄 192 — 옮기기 전과 같음 · tsc 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 02:59:08 +09:00
- 10 일반관리비: (주)공사/전문공사 = 요율 구간표만 갈림 · 밑수는 형식 칸(일반 = 순공사원가 + 관리품목자재대)
- 11 절사: 총공사비/공급가액 N원 미만 — 고른 때만 이윤 자동보정(총공사비·공급가액 비례 부가세면 ÷1.1 반올림, 실무 봉화 373→339·영월 695→632, 산림조합은 차액 그대로) · 잔차 맞춤
- 12 부가세: 공급가액·재료비·없음·산림조합 형식·산림조합-면세품 (칸 이름은 기성 선택지를 받을 수 있게 문자열)
- 기본값은 종전 계산과 같음 · 자동보정 줄은 「… 절사 자동보정」으로 적음
- 원가계산서 탭: 10·11·12 고르개 · 관리품목 자재대 · 면세품 금액 칸
- 시험: 기본값 불변 · 밑수·표 갈림 · 실무 절사 식 · 끝자리 · 골든셋 초록

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 03:16:15 +09:00
- B09_Estimation_Edits: 고친 값 한 벌 — 기본 조립(cached_build) 복사본에 얹음(캐시 키에 고친 값) · 기본 벌은 그대로(골든셋 무관)
  · 얹지 못한 값은 edit_skipped 로 남김 · 값 없는 슬롯은 받지 않음(422 + 까닭)
- 새 라우터 B09_Estimation_Router_Edits(GET/PUT /estimation/edits) — Router.py 는 _build_for 가 고친 값을 얹게만 바꿈
- 화면: 줄마다 채택 슬롯 고르개 · 일괄(변동없음/1~5 단가/최소단가) · 고친 줄 「사용자」 + ↺(지우면 계산값으로)
- 곁: 사용자 식 셈(B09_Estimation_Expression — ROUND·ROUNDDOWN·INT·SQRT, eval 없음)과 본표 편집 칸(UI_DetailEdit)을 먼저 둠 — 서버 편집 문이 서기 전까지 잠자 있음
- 검증: 시험 1656 통과 · ORCA 채택 저장 → 「사용자」·↺ → ↺ 뒤 고친 값 {} 로 복구 · 값 없는 슬롯 422 「경유: 1번 원천에 값이 없어」

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 03:24:57 +09:00
- 4 고용보험료: 자동(추정금액 구간 · 종전) · 없음 · 1~7등급 직접
- 5 퇴직공제부금비: 자동(추정금액 1억 이상 · 종전) · 적용 · 미적용 — 토목·준설·건축·기타는 현행 제비율에서 율이 같아 칸 안 둠
- 폐기물처리비 자리: 경비·승률 안(법 문언 · 기본) / 이윤 뒤·총원가 안·승률 밖(실무 관행 울진소광·실정보고)
- 칸 밑 안내: 절사 기본 「안 함」과 실무 3건(총공사비 천원 미만 + 이윤 자동보정) · 폐기물 법/실무 갈라 적음 · 주/전문 규정 없음
- 시험: 등급 1.57% · 없음 · 없는 등급 멈춤 · 퇴직공제 1억 미만 적용 · 승률 밖 자리 · 골든셋 초록

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- get_bill · _project_root_of · _build_for 는 Router.py 에 그대로(랩탑_메인 CostSheet import 그대로)
- 새 파일은 본 라우터의 _project_root_of·_build_for 를 부를 때마다 빌려 씀 — 시험이 본 라우터 것을 바꿔 끼움
- 검증: 시험 1666 통과 · 골든셋 초록 · 재시작 뒤 B09 문 열하나(factors·base-data·price-sources·basis-sheet·machine-expense·
  design-doc-index·bill·unit-prices·edits·cost-sheet·PUT factors) 전부 200

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 03:37:22 +09:00
- 구성행(sheet_rows): 수량 고치기 · 줄 빼기(수량 0, 흐리게) · 줄 더하기(단가표 고르개) — 비율 줄·돌림 참조는 받지 않음
- Q 식(price_basis_q): 식은 명세 13장 식 언어 — B08 구조물도 풀이기(evaluate_sheets, Node 한 벌)를 그대로 부름 ·
  소수 2자리 사사오입 확정 → 새 수량 = 수량 × 옛 Q ÷ 새 Q · 비고에 「Q(사용자) = 식 = 값」
  · PriceDetail.output(시공능력 Q)을 Q 로 선 장비 줄 넷 자리(굴착기·도자·직접 작업량·암 잎)에서 실음 · 저장 모양에도 실음
- 따로 짰던 파이썬 식 셈(B09_Estimation_Expression)은 걷어냄 — 식 풀이 두 벌 금지(브레인 판정)
- 새 문: GET /estimation/edits/sheet/{code}(본표 + 줄마다 고친 값 표시) · GET /estimation/edits/search(줄 더하기 고르개)
- 화면: 본표 [편집] — 수량 칸 · ✕ · Q 식 칸 · 줄 더하기 · 고친 줄 「사용자」 + ↺
- 검증: 시험 1664 통과 · 골든셋 초록 · ORCA — 제 3 호표 보통인부 0.023→0.046 이면 5,652→9,610 · 내역 본체 122,848,989→122,857,198,
  ↺ 뒤 5,652 · 산근 2호표 Q 58.21→116.42 이면 1,695→847, ↺ 뒤 1,695 · 틀린 식 422 「모르는 이름: abc」 · 고친 값 {} 로 복구

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 04:06:45 +09:00
- estimation.rate_overrides 에 칸 주소(variable·table·match)·요율·사유·입력 시각을 한 줄씩 — 마스터 요율 파일은 안 건드림
- 엔진이 계산할 때 복사본에만 얹음 · 덮어쓰기 없으면 원본 그대로(골든셋 초록) · 원가계산서 비고에 「요율 덮어쓰기 N건 — 사유」
- 요율표: 칸마다 기본값·지금 값·주소 · [수 정]에서 입력 · 고친 칸 테두리 + (기본 X) · ↺ · 고친 요율 목록에 사유 칸(비면 저장 안 됨)
- PUT /estimation/rate-table: 사유 빈 줄·틀린 주소·같은 칸 두 번·음수면 아무것도 안 저장 · 값·사유 같으면 입력 시각 유지
- 판이 바뀌어 주소가 안 맞으면 조용히 버리지 않고 알림
- 시험: 마스터 불변 · 계산에 걸림 · 한 값짜리 · 거름 · 주소 틀리면 멈춤 · 화면 주소 왕복

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 서버가 내역 줄 성분 단가에 율을 얹어 다시 셈(줄 칸이 전체 칸보다 우선) · 수량은 그대로
- 공용 작은 버튼 글자색 상속 — 어두운 화면에서 검정 글씨로 묻히던 것

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 04:08:16 +09:00
- 13 사급비 위치: 재료비에 포함만(사급은 이미 내역 재료비 · 실무 거창·영월) — 칸만 받음
- 14 낙찰방식: 하도급대금 지급보증 요율 줄 — 종합심사 외(규모 구간) · 종합심사 대상(300억 이상 줄) · 턴키(0.084)
- 15 이행보증: 일반계약 = 추정가격 300억 이상만 공사이행보증수수료 · 최저가·기술제안 = 규모 무관
  (종전 늘 계산 — 제비율 기준 「소규모 통상 비대상」·실무 여섯 건 금액 없음과 어긋났음)
- 곁 고침: 70억 이상 구간 [기초액 + (직공비−기준액) × 율] × 공기 — 종전 백분율만 쓰고 기초액·기준액을 버렸음
- 16 적용기준: 칸만 받음(조달청 표 한 벌 · 제20조 국가 표 이미지 미확인 · 행자부 표 없음)
- 칸 밑 안내 · 시험: 300억 미만 안 섬 · 100억 식 965,000 · 요율 줄 셋 · 13·16 계산 불변 · 골든셋 초록

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 산업안전보건관리비: 고시 별표1 「보건관리자 선임 대상 건설공사의 적용비율」 열을 대상액이 아니라
  공사가 선임 대상인가(요율 데이터 manager_thresholds 800억 · 토목 1,000억)로 가름 — 두 줄이 겹쳐 멈추던 자리
- 하도급대금 지급보증수수료: 기본 꺼짐 — 실무 원가계산서 6건에 줄 없음 · 건설산업기본법 제34조 대상이면 켬
  (칸 밑에 「대상 아님인지 안 적음인지 못 가름」 사유)
- 시험: 50억 이상 2.60 / 선임 대상 2.73 · 하도급 꺼짐·켬 · 골든셋 초록

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 2 commits 2026-09-14 04:26:51 +09:00
- B07 표준도 그림 코드를 B08 로 옮겨 모양 목록(선·글자)으로 냄 · 화면이 SVG 로 그림(그림 6 : 표 4)
- 벽 두께를 수량표와 같은 함수로 — 상부·하부 두께를 넣어도 그림만 옛 두께이던 것 고침
- 터파기 점선을 수량식과 넓이가 같은 평행사변형으로(앞면 따라 기움)
- 큰돌쌓기(직경 축)·옹벽·뒷길이 미정 장은 그림 자리에 까닭 한 줄
- B07 CAD 표 조립은 같은 모양 목록을 CAD 엔티티로 옮겨 적음(CAD 편집 뒤 일감용)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 04:28:42 +09:00
- 12번 §4~6 서식(35번 정정 반영) 차례·표기 · 줄마다 「공통 요율 / 요율표 미확보(RateB·RATE_RA·An_A) / 확인 대기」
- 확인 대기: 실적형 이윤 밑수(35번 §5-1) · 실적수공 안전관리비 존재(§5-2) — 값을 지어내지 않음
- 0 원으로 안 채움 — 금액 칸 「-」 + 까닭 · 머리에 「금액 미산출」
- 원가계산서 아래 형식 탭 넷을 눌러 바꿈(GET ?form=) · 기준 입력판은 그대로
- 시험: 금액·0원 없음 · 수공 경비 여덟 막힘 · 확인 대기 · 실적일반 보증·환경 밑수 · 모르는 형식 멈춤

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 04:42:33 +09:00
- 뒷길이를 안 고른 돌쌓기 장: 표가 쓴 그 뒷길이(양식 장은 양식이 푼 값, 전개 장은 기본 45㎝)로 그림
- 「⚠ 뒷길이를 안 골라 기본 N㎝ 로 섰습니다」 한 줄을 한 곳에 두고 표 사유·그림이 같이 씀(골막이 문구도 같은 함수)
- 돌쌓기 표 사유에 그 한 줄이 새로 붙음 — 전에는 기본값인 줄 표에 안 드러났음
- 그림 까닭은 정말 못 그리는 장(큰돌쌓기 직경 축·옹벽)만

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 04:51:35 +09:00
- STmate wM_Mk_Cont(27번 §2) 본뜸: 단가 적용율 【노】【재】【경】 · 적용 옵션 여섯(화면 표기 그대로) · 적용제외 공정
- 설계 내역(/estimation/bill) 줄을 복사해 성분마다 적용률 — 절사는 설계 내역 규칙(bill_line) 그대로 · 설계 불변
- W 코드: 동일코드 한 벌(기본) / 개별생성 켜면 줄마다 · 적용 제외 줄은 설계 단가·설계 코드
- 0%: 「공내역 생성」 켜면 0 원 공내역 줄 · 끄면 적용 안 함(판정 대기)
- 뜻 미확인 옵션(노무비율)·아직 안 선 옵션(기초단가 적용·일위대가 생성·비과세자재)은 칸만 받고 까닭을 화면에
- GET/PUT /estimation/contract · 탭 파일 B09_Estimation_UI_Tab_Contract.ts(등록은 서브) · 사전 b4
- ⚠ 계약 표본 0건 — 구조가 서는지까지만 시험

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 05:06:56 +09:00
- _Base(110줄) 성분 계약·갈 곳(DESTINATION)·배합 성분(MIX_COMPONENTS) — 이중계상 경계
- _StoneSpec(525줄) 돌쌓기 제원·계수표·표준경사 판정·벽 두께·버림/기초잡석 상수
- _Masonry(523줄) 돌쌓기·큰돌쌓기 전개식(버림·터파기 줄)
- UnitQuantity(581줄) 종류→전개식 표·관측 원단위·딸린 줄·build_table — 옮긴 이름은 다시 내보내 부르는 쪽 44곳 그대로
- 코드 줄은 옮기기만 함 · 검증 프로젝트 응답 여섯(원단위·구조물 집계·구조물도·운반·인계·내역) 지문이 쪼개기 전과 같음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-14 05:14:44 +09:00
- 기초단가 적용: 자재·노임·중기 취득가 채택 단가에 적용률 — 복사본만, 설계 단가표 불변
- 조립값과 다른 줄(할증·수동 단가)·단가표 밖 코드는 성분 곱셈 + 비고에 까닭
- 계약 호표: 설계 본표와 같은 꼴(detail_of)로 W-B·W-D 따로 — 기초단가 적용과 함께만
- 0% 는 0 원(브레인 판정) · 공내역 생성은 그 줄 이름만 가름
- 시험 11건 · 전체 1699 통과(골든셋 포함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 05:27:54 +09:00
- 반중력식 H=2.0 관측 줄에 단면(기초 1.6×0.4 · 벽체 1.6 상단 0.3 앞면 0.118 뒷면 0.032 · 전단키 0.35×0.3 · 버림 0.1 · 물빼기 관 0.4)을 실음 — 출처 소광리 07-구조도 「옹벽2.0」 산출식·일반도
- 그 치수로 표 수량이 다시 나오는지 시험(콘크리트 1.345→1.35 · 버림 0.145→0.15 · 유로폼 3.205→3.2 · 관 0.32)
- 그림: 기초·벽체·전단키 + 버림(키 자리 비움) + 기초잡석(산출 조건 두께 · 버림과 같은 폭) + 물구멍
- 표 사유에 새 한 줄 둘(그림도 같은 말): 관측 줄에 터파기·되메우기·잔토가 없음 · 물빼기 칸을 채워도 관측 값이 붙박이라 안 닿음
- 까닭은 표가 못 선 장만(형식 미정 · 자료에 없는 규격 · 단면 치수 없는 규격) — 표 사유와 같은 말

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 05:38:37 +09:00
- 단가표 복사본의 중기(X) 호표만 실행단가로 갈아 끼워 일위대가 다시 조립 — 설계·계약 불변
- 조립값과 다른 줄은 설계 단가 그대로 + 비고에 까닭
- 「기본보정」은 뜻 미확인 — 차액을 안 몰고 남김(확인 대기)
- 계약 모듈의 다시 조립·묶음 합 조각을 두 단계가 같이 씀
- 실행예산 탭 파일 · 사전 키(등록은 서브) · 시험 7건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 05:59:36 +09:00
① 터파기·되메우기·잔토 — 소광리 「옹벽2.0」에 줄이 없어 브레인 판정대로 기초 폭 + 양쪽 여유 0.3(같은 파일 식생옹벽블럭 기초 터파기)로 수직 · 깊이 기초 0.4 + 버림 0.1 + 기초잡석 · 비탈분 제외(지반선이 제원에 없음) · earthwork 로만
   m당 터파기 1.54 · 되메우기 0.36(터파기 − 기초·전단키·버림·잡석) · 잔토 1.18 · 인계 심도 구분은 판 깊이(0.7 m → 0~1m)
② 관측 값을 원문으로 — 콘크리트 1.35→1.345 · 버림 0.15→0.145 · 유로폼 3.2→3.205 ⇒ 기초잡석 0.30→0.29
③ 물구멍관 — 실무 관측 식(「옹벽2.0」 T31 벽 높이 ÷ 개소당 면적 × 관 0.4)에 제원 칸이 닿음 · 규격 Ø50 이 붙어 자재총괄에서 돌쌓기 물구멍관과 한 줄(33.924 + 3.2 → 37.124 m) · 관 길이는 관측값으로 표시
- 검증 프로젝트 내역 본체 122,848,989 → 124,202,681원(+1,353,692 = 구조물터파기 심도 0~1m 15.4㎥ 1,341,216 + 되메우기 21.0→24.6㎥ +12,476)
- 그림: 터파기 점선·「터파기 폭 2.20 × 깊이 0.70」 · 표 사유와 같은 말 · 옛 값을 박은 시험 8건을 원문 값으로(전 값은 주석)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-14 06:01:40 +09:00
feat(b09): 실행예산 차액 보정 뜻을 화면에 — 기본보정은 「안 몰고 남김(뜻 확인 대기)」

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
@
eomsangdon added 1 commit 2026-09-14 06:11:52 +09:00
- 밑폭 2.2(기초 1.6 + 여유 0.3×2) · 윗폭 = 밑폭 + 0.5 × 판 깊이 × 2 = 2.9 · 깊이 0.7 → m당 터파기 1.54 → 1.785 · 되메우기 0.36 → 0.605 · 잔토 1.18 그대로
- 검증 프로젝트 내역 본체 124,202,681 → 124,424,547원(+221,866 = 구조물터파기 0~1m 15.4→17.85㎥ +213,375 · 되메우기 24.6→27.05㎥ +8,491)
- 그림 터파기 점선을 사다리꼴로 · 「밑폭 2.20 · 윗폭 2.90 × 깊이 0.70」 · 표 사유와 같은 말

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 06:12:23 +09:00
- 계약내역·계약 원가계산서(같은 엔진에 계약 직접비)를 읽기만 해 파생 — 계약 불변
- 제잡비 줄마다 계약잡비율 = 도급액 ÷ 계약 직접공사비 (구조로 읽음, 확인 대기)
- 회차 목록 저장 · 기성(%) · 잔량 · 계약 수량 넘으면 알림
- 부가세: 직접입력 / 공급가액 / 재료비 / 재료비+산출경비 (설계 vat_base 같이 씀)
- 원가계산서 조립·계약본 받기 조각을 떼어 기성이 같은 길로 받음
- 기성 탭 파일 · 사전 키(등록은 서브) · 시험 6건 · 전체 1717 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 2 commits 2026-09-14 06:32:19 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
구조물도 남은 종류 그림을 시작하며 시험 제원으로 표를 세워 보다 드러남:
- 골막이(개소당)·바닥막이(㎡당)가 「m · 연장 0」으로 읽혀 구조물도 전 줄 「단위당 못 냄」 · 인계 「물량이 0 이라 내역에 안 세움」 → 내역 단위 개소 1 / ㎡ 면적으로
- 떼흙막이 개소당 값이 연장으로 나뉘어 떼 0.139/m 로 보였음 → 개소당 1.39
- 개거 「L형수로 H=0.2」 — 엔진 키가 「콘크리트 L형수로 H=0.2」라 등록부에서 골라도 영영 안 섰음 → 등록부 글자로
- 기슭막이 사유 「돌 종류·뒷길이 칸이 없어」 — 칸이 선 뒤로 거짓 · 돌쌓기 한 줄과 같은 말 두 번 → 걷음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-14 06:53:36 +09:00
- 기슭막이(돌쌓기형) — 돌쌓기 그림 그대로 · 기울기 판정 대상에 넣고 찰/메는 형태에서(표와 한 벌)
- 골막이 — 정면 사다리꼴 · 방수로 관 · 바닥파기 띠 + 옆 단면 · 치수는 표와 같이 쓰는 erosion_check_section 한 벌로 뽑음(값 불변)
- 떼흙막이 — 정본 평균 붙박이 치수(dims)로 · 그 치수로 표 두 줄(떼 1.39 · 바닥파기 0.17)이 다시 나오는지 시험
- 바닥막이 — 돌 켜 · 버림 · 기초잡석(산출 조건) · 터파기 · 표 사유에 새 한 줄 「터파기는 돌 두께만 — 버림·기초잡석은 판 깊이에 안 들어감」을 그림도 같이 씀
- 표가 안 선 장은 표 사유를 그대로 까닭으로 · 개거 둘은 원문끼리 치수가 달라서/단면 그림이 없어서 까닭
- 화면 확인: 검증 프로젝트 936be972 에 넷을 잠깐 놓았다 되돌림(구조물 5개 원본과 같음 · 단계 상태 그대로 · 내역 124,424,547 그대로)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 6 commits 2026-09-14 06:55:38 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
- 계약잡비율: 기본 역산값(도급액 ÷ 계약 직접공사비) · 계약서 값 직접입력이 이김(사유 필수)
- 줄별 절사 누적으로 단일율 곱과 벌어진 금회·누계 차이를 비고에 적음
- 공급가액 절사(총공사비에서 조정 + 10원~1억) · 총공사비 절사(이윤금액 직접입력 + 10원~1억)
  — 떨어지는 몫은 설계 원가계산서와 같은 식으로 이윤에서
- 사정: 뜻 미확인이라 칸만 받고 계산에 안 씀
- 시험 4건 보탬 · 전체 1723 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 07:09:59 +09:00
- 집수정 □형 Ø800 — 관측 줄에 원문 치수(소광리 「집수정구조도(800)」 설계조건 칸·산출식)를 싣고 그 치수로 표 수량이 원문 식대로 다시 나오는지 시험
  원문 값으로: 콘크리트 2.84 → 2.83752 · 합판거푸집 21.28 → 21.2843 · 철근 D13 4.78 → 4.776 · 면목 12.67 → 12.6728(터파기·되메우기·잔토 그대로)
  그림: 긴 벽 정면(바닥기초·관·방수로·터파기) + 평면 · 관·방수로 자리는 원문 입체도 모식이라 적음
- 물넘이포장 — 슬래브 T(규격) · 와이어메쉬 2/3T(소광리 「포장」 그림) · 터파기 · 새 사유 「원문 둘이 다름: 소광리 포장 와이어매쉬 1.0·비닐 2㎡ ↔ 이 표(울진 1공구) 1.16·비닐 없음」을 표·그림이 같이 씀
- 날개벽 5종 — 원문 탭에 구조도 그림이 없고 날개 모양이 손으로 적은 수뿐이라 까닭 · 돌집수정 ㄷ·ㄴ형 — 집계표 관측값이라 치수 원문 없음 까닭
- 사유 문구(브레인 판정): 개거 150×200 「원문 둘이 다름(산출식 0.3×0.1 ↔ 그림 홈 150×200 + 밑 보 400×200)」 · 바닥막이 「옹벽은 버림·잡석까지 팜 — 바닥막이는 정본이 돌 두께만이라 다름」

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 7 commits 2026-09-14 07:10:33 +09:00
- 원문 표 그대로: 최소 높이 토사 500 mm · 암반 400 mm · 폭 1 m 이상(기계 작업 3 m 이상)
- 값·칸·자동 채움은 그대로 — 말만 고침(2026-09-14 브레인 정정)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 준공 별도 계산 규칙 미확인(35번 §3) — 규칙을 짓지 않고 기성 누계를 옮김 · 기성 한 장 불변
- 기성 회차가 없으면 준공금액 비움(0 원으로 안 채움)
- 기성 계산 조각(progress_for)을 떼어 준공이 같은 길로 받음
- 기성 간접재료비 확인 대기 닫음 — 예정가격작성기준 제17조·제39조② 근거(브레인 판정)
- 준공 탭 파일 · 사전 키(등록은 서브) · 시험 2건 · 전체 1730 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
요율을 원본 「공사원가계산서」 비고에서 뽑아 그 원본 전용 판을 지어 엔진에 넣음 —
「요율 데이터가 달라서 틀림」을 없애고 남는 차이를 밑수·절사·사슬로 몰아 둠.

· 제비율 줄마다 54자리 전수 일치(안전관리비 A·B 와 작은 쪽 채택 포함)
· 사슬은 비고가 다 보이는 셋(봉화·영월·울진 공통) 순공사원가~총공사비 33자리 일치
· 이윤 — 자동절사가 맞춘 원본 둘(봉화 339 · 영월 632) · 설계자 명시 조정 하나(울진 905,980)
· 영월 도급공사비 차 762,000 = 원본에만 있는 국가지점번호판검증수수료 줄
· 고칠 자리 하나(배정 대기) — 안전관리비 B 절사 자리가 영월에서 1원 갈림(미채택 줄)
· 짝 파일이 700줄에 닿아 새 파일로 가름(원본 읽기는 공유)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 07:52:59 +09:00
- 전개가 structures.json 만 읽던 구멍 — pipe_points.json 도 읽음(관 자체는 관 줄이 셈)
- 관 부설(품셈 12-11 m당)에 기슭막이 몫 없음 → 기슭막이는 전개 한 곳에서만 · 사유에 적음
- 안 적힌 벽 칸은 등록부 기본값(횡단도 그림과 같은 값) + 「기본값으로 섰음」 사유
- 구조물 목록에 남은 관 지점 종류 옛 저장분은 안 셈(두 번 방지)
- 기슭막이 공종 = 형태로 돌쌓기 찰·메 코드 · 독립 기슭막이 한쪽 설치에 두 칸이 다르면 사유만
- 산출식 없는 세월교가 「터파기 줄 없음」 거짓 사유를 안 내게 · 구조물도 제원 저장이 관 지점 시설엔 안 먹힘을 알림

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 10 commits 2026-09-14 07:58:46 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
- 자동으로 안 채움: 임도기술교본 6-4 「설계도서에 명시되어 있는 높이와 폭」(브레인 판정)
- 칸·근거 줄·단추 묶음을 B08_Quantity_UI_Side_BenchCut.ts 로 뺌(페이지 700줄 넘음)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 2장 — FP- 는 산림사업 표준품셈 한 판, 건설품셈은 기계 층만. 고시 2025-82호 총칙 7 조문 근거
- 7장 — 금액의 단위표준 표 다섯 줄과 실측 대조. 넷은 맞고 「총액 1,000원 미만버림」만 미확인
- 7장 — 수량의 단위표준 [주] 셋. 「규정 없는 자리 소수 2자리」는 이 표에도 없는 자리에만
- 막히면 산림품셈을 먼저 볼 것 — 덤프 운반이 건설 8-2-8 만 보다 막혔던 자리

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
- 쪽 끝 기종 이름에 다음 쪽 머리글·다음 분류 이름이 붙고, 다음 분류 첫 기종들은 이름이 비던 병
- 이름·규격은 건설공사 표준품셈 제8장 기종 목록 줄에서 읽음 · 취득가·손료계수는 원천 그대로
- 대형 브레이커 되살림 표 옆에 같은 약속으로 둠(원천이 실으면 지움)
- 자원 축 781/386 · 범위 81공종 상태 전후 같음 · 시험 4건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 08:22:19 +09:00
- 브레인 판정: 값 없음을 감추면 조용히 빠지거나 조용히 부풂 — 없으면 없다고 보이기
- 관 지점 벽 치수를 등록부 기본값으로 채운 줄 = 미확정: 원단위 합·자재·터파기·되메우기·기초잡석·타설·잔토·채집석에서 뺌
- 인계 막힘 갈래 넷째 값 unconfirmed(계약 칸은 안 늘림) · B09 는 내역 제자리에 빈 금액 + 빨간 테두리 · 머리 뱃지
- 구조물도 그림에 표와 같은 기본값 사유 줄 · 「횡단도와 같은 값」 문구는 틀려 고침(B06 관 벽 높이는 관경 기준)
- 936be972 내역 184,291,506 → 124,424,547 · 미확정 18건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 6 commits 2026-09-14 08:23:35 +09:00
- 원문 비고 「별산」·「별도계산」·「설계수량」(〃·병합 칸 포함)·「필요시적용」은 안 넣는 줄로 까닭을 남김
- 규격 칸(1:2)과 관경 열(∅800mm)을 조인 키로 — 접합몰탈·고무링이 자재 줄로 섬(단가 층은 아직 없음)
- 크레인은 기종이 여럿이라 고르지 않음 — 「규격 미정 · 원문 규격 10ton/5ton」(브레인 판정 대기)
- 옆 칸 규격 「40.64㎝」 = 카탈로그 절단기 40.64(기계 운전 자료가 없어 층은 못 섬 — 사유로 드러남)
- 카탈로그 밖 자원 목록에 고무링 ∅800/1000/1200mm · 지수활제 보탬(원문 F0346 · 단가 없음)
- 범위 81공종 상태 전후 같음(못 붙은 줄의 까닭만 바뀜) · 시험 4건 · 전체 1749 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- B08: 갈래로 안 나뉜 암 총량은 시공법만 골라서는 안 풀림 → 사유 「암 갈래 구성비(%)가 아직 없어…」 · 시공법 안내 목록에서 뺌
- B09 내역: 공종을 못 고른 줄에 B08 막힘 까닭이 있으면 그 문구 그대로(입력 필요 ↔ 매핑 구멍 가름)
- 배정 프로젝트 흙깎기 암 3,104.57㎥ · 측구터파기 암 160.48㎥ 가 이 자리 · 시험 1건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 08:40:54 +09:00
- 표가 읽는데 등록부에 없어 영영 안 서던 칸 — 옛 저장본은 안 깨지고 비면 사유(어디서 적는지)
- 개거(점 배치) length_m · 물넘이포장 thickness_cm·length_m(detail · 구조물 집계표에서도 고침)
- B05 시설 칸에 물넘이 두께·길이 입력 — 시설 저장이 칸을 통째로 갈아 끼워 집계표로 적은 값이 지워지던 길을 막음
- 700줄 한계로 유입구 형식 목록을 _Fields 로 옮김(부르는 쪽 그대로)
- 사유 문구: 「open_ditch 연장」 키 노출 · 「연장·면적이 0」 → 무엇을 적으면 서는지

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 08:42:01 +09:00
- 원문 본문 식(채워 넣는 서식)을 데이터로: Qt = T/γt×L · n = Qt/(0.7×K) · ㎝t = t1+t2+t3+t4+t5 · Q = 60×Qt×f×E/㎝t
- 브레인 판정: n 의 Qt 계산값(원문 표기 10 버림) · 발파암 E 0.9(원문 누락) · Es 운반 줄 값 · 거리별 갈래
- 거리는 B08 인계(유토곡선·사토장)에서 — 내역이 조립에 넘기고, 호표 한 장은 코드 #L…m 에서 되읽음
- 거리 없는 줄은 0 원 아니라 「운반거리 미입력」 · 갈래는 범위 별칭 리핑암 → 암절취
- 배정 프로젝트 164.23m: 토사 3,249원/㎥ · 암절취 8,882원/㎥ · 같은 인계 대조로 바뀐 줄은 이 둘뿐(+1,437,981원)
- 시험 5건 · 전체 1761 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- Q1 = 3600×0.7×K×f×E0/22초 · 토사 47.63 · 암절취 16.32 · 발파암 13.67 ㎥/hr
- E0 는 운반 식 Es 와 다른 기호 — 토사 0.60(표 「임도」·10-12-3 [주]③) 채택 · 본문 0.75 버림(브레인 판정)
- 거리 무관이라 늘 세움 · 내역은 인계 수단 표지 dump_loading 줄을 잎 #적재 로(B08 짝 줄은 다음 커밋)
- 시험 1건 보탬

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 08:49:42 +09:00
- 저장이 옵션을 통째로 갈아 끼워 집계표·구조물도로 적은 칸(관 기슭막이 기초 등)이 조용히 지워졌음
- 같은 시설 종류면 폼이 적는 칸만 갈고 나머지는 이어 붙임 · 종류를 바꿀 때만 통째로
- 폼이 아는 칸을 폼이 비우면 지움(사용자가 폼에서 한 일)
- 폼 칸 목록 거울 시험 — 폼에 칸을 늘리고 목록에 안 넣으면 시험이 잡음
- ORCA 936be972: 집계표로 기초유 적고 B05 폼 고침 → 재계산 요청에 기초유 남음 확인 · 값·캐시 되돌림

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 09:10:51 +09:00
- 한 벽을 두고 값이 셋(등록부·표 H2.5 · 구조물도 H2.5 · 횡단도 관경 기준)이던 결함 — 근거 있는 관경 기준으로 맞춤
- 관 벽 높이 안 적으면 관경 + 여유 0.5 를 0.1m 로 올리고 근입 0.5 더함(Ø800 1.8 · Ø1000 2.0 · Ø1500 2.5)
- 파이썬(B06 엔진)·TS(세트 스펙·횡단 상수) 거울 시험 · 등록부 기본 2.5 걷고 empty_means
- 최소값이라 미확정·금액 밖은 그대로
- B05 벽 칸(관 유입·유출 · 독립 기슭막이)은 비워 두고 회색 제안값 · [제안값 넣기] 누른 때만 값 — 저장 한 번에 미확정이 확정으로 바뀌던 길을 막음
- 전체 시험: 받은 덤프 적재 커밋 몫 2개만 빨강(보고함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 7 commits 2026-09-14 09:11:22 +09:00
- v16 「덤프 운반은 아직 안 선다」가 지키던 것 = 운반거리(설계 입력) 없이 운반이 조용히 금액을 갖지 않기
  → 「거리가 와야 선다」로: 거리 없는 기본 조립엔 운반(#L…m) 없음 · 거리 무관 적재(#적재)만 섬
- 갈래 제목 ⊂ 마스터 갈래 키: 10-12 는 표가 아니라 본문 식이라 마스터 표에 갈래가 없음
  (#L…m 는 프로젝트 거리마다 생겨 마스터에 둘 수도 없음) → 식이 내는 FP-10-12 갈래만 까닭 적고 제외
- 58afe8f2 를 일부 시험만 돌리고 올려 난 빨강 · 전체 1763 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- _haul_rows 한 곳: dump_truck 내역 줄 뒤에 haul_equipment dump_loading 짝 줄(갈래·수량 같음)
- 흙깎기 9-3-2(㎝ 20초·135°)에 싣기가 안 들어 있어 운반과 한 벌로 냄(브레인 판정)
- B09 운반토량 검산(운반 ≤ 절취)에서 적재 줄은 뺌 — 같은 흙을 두 번 세지 않게
- 시험 기대값: 운반표 줄 4 → 6(적재 둘) · 내역 줄 3 → 5 · 전체 1763 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 고시 다섯 줄 중 총액 줄만 우리가 안 따르고 있었음(기본값 꺼짐)
- 실무 6건 끝 세 자리 000 ↔ 우리 373·695·578·654·341·639
- 곁 버그 — 절사 자동보정이 둘째 걸음부터 ÷1.1 누락으로 진동
- 집계표 ROUND 는 설계서 소계와 다른 자리로 봄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
eomsangdon added 1 commit 2026-09-14 09:14:55 +09:00
- 뿌리: 사용자가 고른 적 없는 첫 선택지가 저장돼 확정으로 굳음(옛 2026-08-17 「빈 보기 두지 않음」 걷음)
- 구조물 목록 일반 폼: 기본값 없는 고르기 칸은 늘 빈 보기(필수 「— 선택 —」 · 아니면 「— 안 정함 —」)
- 시설 폼 optionalSelect: 맨 앞 빈 보기(날개벽 「안 놓음」 등) — 기본값이 있는 칸은 다음 차례(②③)
- ORCA 936be972 B05 관 폼: 날개벽 「안 놓음」 빈 값으로 섬 확인

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 09:21:32 +09:00
- 칸에는 저장된 값만 · 기본값은 회색 글씨(숫자)·빈 보기 이름(고르기)으로 제안 · [제안값 넣기] 누른 때만 값
- 새 구조물 추가도 기본값을 안 실음(defaultOptions 로 채우던 자리) · 잠긴 칸(enabled:false)만 프로그램 값 유지
- C군(범위 계산 타입)은 길이처럼 높이도 비면 안 놓음 — 비면 횡단도 벽이 조용히 안 서던 길
- B08: 돌 조달을 안 정하면 「채집으로 셈」 사유를 보임(조용히 채집 되지 않게)
- ORCA 936be972: 돌쌓기(메) 고르면 높이·길이·전·설치측 빔 + 제안 · 단추로 채워짐 확인(저장 안 함)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 5 commits 2026-09-14 09:21:38 +09:00
- 제외 목록 대신 갈래마다 어디서 왔나를 한 칸: 덤프 운반·적재 10-12 제목 → 그 식(브레인 판정)
- 짝 시험: 표에서 온 갈래는 마스터 갈래 키에 있어야 함 · 식이 낸 갈래는 출처가 적혀 있고 마스터엔 없어야 함
- 마스터에는 「식 공종 갈래」 칸을 안 둠(표에서 뽑은 것만 담는 자리)
- 전체 1771 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
eomsangdon added 1 commit 2026-09-14 09:28:12 +09:00
- 관종 파형강관·관경 1000 · 유입/유출 구조 기슭막이 · 집수정 길이 2 · 날개벽 있음·1·2·45 · BOX 2.0×2.0 ·
  월류 폭 5/10 · 월류 높이 필요 수심 · 독립 기슭막이 양쪽 — 전부 「안 정함 (제안 …)」·회색 글씨로만
- [제안값 넣기] 누른 때만 빈 칸에 제안값 · 적은 월류 높이가 필요 수심보다 낮으면 여전히 되돌림
- BOX암거 새로 놓을 때 기본값 싣던 자리도 걷음 · 비운 칸은 횡단도가 등록부 기본값으로 그림(저장만 안 함)
- 700줄 한계로 물넘이·세월교 칸 묶음을 `_Drainage_Facility_Ford.ts` 로 뗌
- ORCA 936be972: 관종 「안 정함」 · 저장된 관경 1000 은 그대로 · 날개벽 고친 요청에 관경·날개벽만 실림 · 캐시 되돌림

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 2 commits 2026-09-14 09:31:04 +09:00
- 옛 「기본값 있는 칸은 첫 보기」(2026-08-17)를 확인하던 줄을 브레인 판정(2026-09-14)대로 뒤집음
- 칸 만들기가 `_Structures_Fields.optionControl` 로 옮겨간 자리를 봄

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 09:34:36 +09:00
- 페이지를 열기만 해도 관종·관경·구조·벽 길이·전/후·집수정 길이 기본값이 옵션에 박혀 임시 저장·[저장]에 확정으로 굳던 자리
- 벽 형태·높이는 조정창에서 조작했을 때만 싣음(앞 조각 c4eccee5 auto 커밋에 먼저 쓸려 올라감)
- 세월교·BOX: 저장돼 있던 칸이거나 조정창 조작으로 등록부 기본값과 달라진 칸만 스펙 값을 싣음
- ORCA 936be972 B06: 관 폼 관종 「안 정함」 · 저장된 관경 1000 만 · 벽 칸 빔+제안 · 임시 저장에 기본값 안 생김

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 6 commits 2026-09-14 10:30:48 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
근거 — 산림청고시 제2025-82호 「금액의 단위표준」 「설계서의 총액 · 원 · 1,000 · 미만버림」.
실무 6건 원가계산서가 여섯 다 000 으로 끝나는 것이 증거.

· 기본 켬 — cut_basis="grand_total" · cut_unit_krw=1000
· 조용히 안 깎음(2026-09-08 합의의 정신) — 이윤 조정액 줄과 결과 메모에 고시 번호를 달고
  기준 입력판 11 에서 끌 수 있음을 함께 적음 · 칸 밑 안내도 고쳐 씀
· 끄는 값을 none 으로 바꿈 — 빈 값은 저장이 안 돼 기본으로 되돌아가 끌 수가 없었음
· 진동 고침 — 걸음마다 ÷1.1(종전엔 첫 걸음만). 이윤 1원이 총공사비 1.1원이라
  잔차를 그대로 빼면 경계를 지나침(울진 신설 654→999→900→910→909…)
· 안 앉으면 「끝자리 N원이 남음」을 메모로 보임
· 실무 6건 전수 000 판정을 새 벌로 지킴

곁 — tmp/tests/test_b09_cost_fixtures.py 를 resources/tester/ 로 옮김(픽스처 포함).
     tmp 쪽 사본은 안 지움 · 겹침은 파일 머리에 적음.
     기본이 바뀌어 깨진 남의 시험 6건은 「안 자른 값」 자리에 cut_basis="none" 을 넣어 고침.

전체 시험 1782 통과 · 28 건너뜀.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 11:03:31 +09:00
eomsangdon added 3 commits 2026-09-14 11:18:24 +09:00
eomsangdon added 6 commits 2026-09-14 12:12:34 +09:00
eomsangdon added 8 commits 2026-09-14 12:38:14 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 골든 금액 시험이 원본 수량을 bill_line 에 바로 넣어 새 길을 안 거침 — 초록이 증거가 아니던 자리
- 원본 321줄 자리 규칙 대조를 따로 만들어 철근 Ton 소수 3자리 4줄을 뽑아냄
- 재지 못한 것을 잰 척하지 않을 것

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0154EMdwPYNPuKc9eZv8SLEX
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 5 commits 2026-09-14 12:57:34 +09:00
eomsangdon added 6 commits 2026-09-14 13:22:58 +09:00
eomsangdon added 9 commits 2026-09-14 13:45:48 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
마스터 전후 대조: 표가 옮겨 붙은 공종 8(12-02·12-17-01·01-01-02·05-34·08-02-03·09-07-01·09-11-01·14-02) · 일위대가 453 제목 금액 변화 0 · 12-02 가짜 갈래 둘이 12-17-01 로만 옮김

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 13:57:40 +09:00
eomsangdon added 5 commits 2026-09-14 14:18:05 +09:00
eomsangdon added 4 commits 2026-09-14 14:37:55 +09:00
eomsangdon added 3 commits 2026-09-14 14:56:18 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
서버 Node 가 벽 몸 ∩ 성토 폐회로 넓이를 재 design.extra_walls[].fill_overlap_m2 로 남기고 B08 다단 줄 비고에 「벽 몸 N㎡ × 연장 ≈ ㎥ 두 번 셈」 · 258.12 1단 1.335㎡ × 10m ≈ 13.3㎥ · 금액 변화 0 · 미확정 단은 안 붙임

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 15:11:27 +09:00
서버 Node 가 기준벽 역할별 넓이를 design.wall_fill_overlap 에 남기고 B08 이 다단 목록 통(base 표시 칸)으로 읽어 기준벽 줄 비고에 붙임 · 호출부(Router_Material) 안 늘림 · 936be972 빈 저장: 관 9 곳 유출 벽 258.12 1.417 · 720 1.403 · 804.18 1.166 · 982.64 0.807 · 620 0.136 · 440 0.046 · 533.98 0.004 · 85.05/900 0㎡ · 이 프로젝트 기준벽은 모두 미확정(금액 밖)이라 비고 안 뜸 · 벽 칸을 적으면 「1.42㎡ × 10m ≈ 14.2㎥」 · 금액 변화 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 15:26:31 +09:00
eomsangdon added 4 commits 2026-09-14 15:50:14 +09:00
실무 대조: 오솔길 BOM 6벌 면적 셈법 ±0.11% · 거창 줄 없음 · 영월 성토면 × 50% · 원문 9-19-1 성토면·9-19-2·3 식재 조건부
배정 프로젝트: 인계 줄 +3(성토면 12,350㎡ · 절토면 토사 3,085.51 · 암 2,262.62) 외 변화 0 · 본체 합계 105,512,060 그대로 · 규격 글로 시작하는 갈래는 규격에 한 번만(도자 운반 「토사 토사」 → 「토사」 · 금액 불변)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
배정 프로젝트: 절토면 토질을 고르고 [저장] → 내역 3-8-2 사유 「입력이 필요합니다」 → 「단가가 일부만 — 공기압축기(이동식) 3.5」 · 「안 정함」으로 되돌려 저장(네 칸 빈 값)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 16:11:12 +09:00
머리 칸이 다르거나 수량이 수가 아니면 칸 주소를 짚은 사유로 그 호표를 통째로 뺌(추측 안 함) · 갈 곳은 구성 = unit_price · 별산자재 = material · % 가산 행 = reference + 항목 사유 · 계약단가·낙찰율 줄 안 뽑고 항목 사유 · 품셈 근거 줄은 formula_text 보존 · 원문 호표·자원 코드와 공사명은 출처로만(판정 Ⓑ~Ⓗ · ㉮㉯㉰)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
배정 프로젝트 화면: 돌쌓기(찰) 장에서 봉화 엑셀 읽기 → 「호표 45개 · 구성 줄 209줄」 → 제6호표 기슭막이(깬잡석,찰쌓기) H=2.0m 구성 9줄 넣기 → 목록 「개인 · [고정형] …」 · [내 것 지우기]로 되돌림(목록 기본 한 줄)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 16:36:28 +09:00
일위대가 금액 바뀐 제목 4(9-5-1 · 9-19-1 연암·보통암ㆍ경암 · 9-19-3) · 나머지 456 변화 0 · 기계 층 미완성 6→4
배정 프로젝트: 면고르기 칸 비면 합계 그대로 · 칸 고르면 성토면 인력 점토 3,269원/㎡ · 절토면 호박돌 4,353원/㎡ 금액 섬(되돌림)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
936be972 실측: 봉화 제6호표 가져오기 → 내역 「기슭막이 H=2.0m 10m」 2줄이 「막힌 줄 9: 공종 코드 미정」으로 섬(전엔 줄이 사라짐) → 코드 3줄 고르고 6줄 수동 단가(검증용) → 일위대가 482,766원/m · 내역 4,827,660원 × 2줄 「수동 단가 6건 미확정」 · 되돌려 본체·인계·내역·원단위·장 전부 같음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 16:50:40 +09:00
eomsangdon added 6 commits 2026-09-14 17:04:33 +09:00
eomsangdon added 4 commits 2026-09-14 17:22:24 +09:00
④ 1.2배의 대상을 「호별 산정이 끝난 금액」으로 바꿈 — evaluate 가
   버림(밑수 × 율 + 기초액) 을 먼저 맺고 배수를 곱함(종전엔 곱한 뒤 한 번만 버림).
   근거 둘이 같은 쪽 — 고시 제4조① 단서 문언 · 골든셋 실증(영월 2024 B 20,330,639 → 20,330,638).
   A(배수 1)는 어느 차례로 해도 같은 값.
   ⚠ 두 실증본이 갈림 — 거창 2025 원본(STmate 출력 아님)은 옛 규칙이라 B 가 1원 위.
     목표가 STmate 골든셋 재현이라 STmate 쪽으로 맞춤. 고정값 벌에 갈림을 적어 둠.

⑤ SA(실적수공) 안전관리비 「확인 대기」 → 별도내역. TA 와 같은 자리가 됨.
   PENDING_SAFETY 상수를 걷고 파일 머리 문구도 고침. 금액엔 안 닿음.

⑥ 고시 대조를 상시 벌로 세움 — test_b09_safety_notice.py 여덟 자리.
   별표1 표를 원문 md 에서 읽어 요율 데이터 16칸 전수 대조(값을 시험에 안 박음) ·
   제4조①1·2호 구간 경계 넷 · 단서 A·B·1.2배 · 제2조2호 대상액 구성 · 1.2배 차례 회귀.

잴 시험 먼저 빨강 확인한 뒤 고침. 전체 시험 1911 통과 · 28 건너뜀 · 1 xfail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
실측(936be972 단가표): 고정형 줄 이름 그대로 찾기 — 종전 8줄 전부 후보 0 → 깬잡석채집 50건(야면석 채집…) · 고임돌채집 14(막돌 채집…) · 레미콘타설(장비) 22(레디믹스트콘크리트 타설 먼저) · 기초다짐 및 뒤채움 16 · PVC파이프 0(자재라 자원 갈래) · 두 번째부터 40~80ms

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
936be972 실측: 고정형 가져오기 → 기초잡석이 호표 밖 몫으로 따로 섬(내역 6-3 3.5 → 7.7㎥ · +515,466) · 채집석 17.76㎥ 사토 공제 그대로 · 되돌려 전부 같음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 1 commit 2026-09-14 17:39:55 +09:00
eomsangdon added 5 commits 2026-09-14 17:57:42 +09:00
배정 프로젝트: 인계 줄 18(관 유입·유출부 기슭막이) 갈래 값·판정 근거만 바뀜 · 본체 105,512,060 그대로(모두 미확정) · 전체 1928 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
화면(936be972 돌쌓기(찰) 장): 기본 항목 복제 → 목록 「개인 · [양식형] 돌쌓기(찰)」 + 「내 라이브러리에 베낌 — 가져와 고친 뒤 [내 라이브러리에 저장]」 · 프로젝트 라이브러리 폴더 안 생김 · [내 것 지우기]로 되돌림

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 4 commits 2026-09-14 18:18:07 +09:00
배정 프로젝트: 뿌리뽑기 줄만 사유가 「하위 후보 6건」→「입력이 필요합니다」 · 소림·0.7 넣으면 55원/㎡ × 17,698㎡ = 973,414(되돌림) · 전체 1935 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
화면(시스템 관리자 계정): 두 단추 보임 · 확인창 「모든 회사가 쓰는 프로그램 기본에 발행 — 같은 종류가 있으면 덮어씀」 · 공용 storage 라 취소로 멈춤(쓰기 없음 확인) · 쓰기는 시험(임시 storage)으로 잼

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 5 commits 2026-09-14 18:37:03 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
화면(936be972 · 봉화 호표 가져온 장): 확인창 문구 확인 · 공용 storage 라 취소(쓰기 없음) · 가림은 임시 storage 시험 · 되돌림

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
화면: 복제로 만든 개인 항목 선택 → 동료 목록 받음 → 확인창 「받는 쪽 목록에 받음으로 뜸 · 그 사람 것은 안 덮음」 · 공용 storage 라 취소(동료 폴더 안 생김 확인) · 개인 항목 지워 되돌림 · 쓰기는 임시 storage 시험

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 3 commits 2026-09-14 19:44:32 +09:00
일위대가 새 제목 6(1회 81,321 → 4회 32,528 → 6회 26,023원/㎡) · 나머지 462 변화 0 (브레인 ㉮)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
- 문구 못박음 셋: ① 옹벽 높이 칸 밑 「기본값 · 소광리 도면 H=2.0 · 바꿀 수 있음」(등록부 default_basis 를 모든 칸 밑 회색 한 줄로) · ② 일반관리비 「임도가 어느 쪽인지 규정이 없어 (주)공사 기본 · 칸에서 바꿀 수 있음」 · ③ 모르타르 배합 「산림품셈에 배합 절이 없어 건설품셈 [건축] 9-1-1 을 씀(교차 참조)」
- B08: 막자갈 비고 「칸을 새로 두는 것은 B05 등록부 몫」 · 일위대가 머리 5단 한도 · 야면석 계수 칸 밑 「돌 종류는 그대로」 · 식 저장 전 상태 줄 「제원을 바꿔도 따라감」 · 양식 장 머리 「반올림은 m당 값에 걸고 수량 = m당 × 연장」
- 산출 조건 제근 굴착기 크기 칸(임목축적 등급 밑 · 「안 정함」 · 회색 제안 0.7㎥ + 근거 + [제안값 넣기] 누른 때만) — 936be972 소림 + 0.7 → 뿌리뽑기 55원/㎡ × 17,873.80㎡ = 983,057원(되돌림)
- 라이브러리 이름표: [내 라이브러리에 저장]·[발행] 창이 장 이름(종류 + 제원 요약)을 채워 묻고 고친 이름으로 저장 · 취소면 안 씀 · 비우면 양식 이름
- B05 계곡 통과 시설 폼 머리 「[저장]은 이 폼에 있는 칸만 바꿈 — 폼에 없는 칸은 그대로 둠」 · B09 폐기물처리비 자리 칸 밑 「법정경비 밑수에는 안 넣음」 · 내역서 「금액을 못 세운 줄」 첫 줄 「사유는 아래 단계가 낸 것을 그대로 옮김」
- 남은 하나(표 형태 66표 까닭 form_basis 화면)는 자원 축 파일을 거쳐야 해 브레인 물음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
eomsangdon added 5 commits 2026-09-14 20:01:26 +09:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
3. 제3조(적용범위) 「총공사금액 2천만 원 이상」 — 요율 데이터의
   minimum_total_construction_amount_krw 를 규모 기준액과 견주고 미달이면 줄 자체를 안 만듦
   (A·B 곁줄도 안 섬 · 0 원으로 안 채움). 잴 시험 먼저 빨강 확인한 뒤 고침.
   ⚠ 견주는 값은 규모 기준액(추정가격 · 없으면 수렴한 총원가) — 고시의 「총공사금액」과 딱 같은
     말은 아니나 계산 차례상 안전관리비 앞에 설 수 있는 값이 그것뿐. 보건관리자 문턱과 같은 축.

1. 1.2배 차례 = STmate 쪽 확정(브레인 판정) — 안 고른 갈래의 사유를 코드에 남김.
   거창 2025 원본은 버림(밑수 × 율 × 1.2) 로 1원 위지만 STmate 출력이 아니라 채택하지 않음.

4. 관급 ÷1.1 = 실무 따름 — 근거를 정확히 적음. 고시 제4조① 단서는 「해당 재료비를 대상액에
   포함」까지만이고 부가세를 말하지 않음 · ÷1.1 은 부가세 제외 환산으로 실무 6건 공통.

전체 시험 1952 통과 · 28 건너뜀 · 1 xfail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA
금액은 아직 안 서고 막힌 까닭이 드러나는 일감(브레인 ㉯ ⑴~⑸) · 배정 프로젝트 변화 0 · 전체 1962 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin sub_laptop_1:sub_laptop_1
git checkout sub_laptop_1
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eomsangdon/Aislo#11