feat(M01): PLAN 7-5 — 안 쓰는 마스터 old/ 로 마저 옮기고 죽은 코드 셋 끊음

- 아무도 안 읽는 최상위·ref 파일 7개를 old/ 로(지우지 않음) — _원문목록·_열목록_화면표·
  수량_돌쌓기찰라이브러리_소광리·공종_수량연결_실무·수량_구조물원단위_울진·
  품셈_산림_재료할증_울진·품셈_산림_돌종류계수_울진(뒤 넷은 old_code 만 읽어 이제 0)
- 공종_자원별칭_실무도 old/ 로 — common_util_aliases.py 를 읽던 시험 둘이 이미 깨져 있어(
  B08·B09 모듈 없음) 실제로 부르는 살아 있는 코드가 없었음
- 살아 있는 common_util/ 에서 dead 모듈 셋(work_item_key·work_item_link·aliases)을
  old_code/common_util/ 로 옮김 — old_code 만 부르던 것이라 옮겨도 부르는 자리 그대로(
  old_code 는 old_code 를 스스로 루트로 읽는 관례) · 상대경로 계산만 한 단 보정
- 깨져 있던 시험 둘(test_b09_fuel_kind_vibrator·test_b08_root_removal_excavator)도
  resources/tester/ 에서 old_code/resources/tester/ 로 — 7-3 이 놓친 것 마저 정리
- UnitPrice.py 의 load_basis_missing() — old/ 스냅샷 대신 새 최상위 마스터
  `기준수량없음_산림품셈_2026-01-01.json` 으로(브레인 판정: 마스터 쪽) · old_code 로
  옮겨진 뒤 root 계산이 한 단 부족해 조용히 빈 딕셔너리를 돌려주던 것도 같이 바로잡음
  (79건 견본 대조 통과) · check_master.py 틀 검사에 특수 파일 면제 한 줄 추가
- 검증 — typecheck · check_master 틀 0건 · M01·자재품목 시험 215 + masterdata·m01_api 98 통과 ·
  전체 모으기 1475 그대로

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
2026-09-22 14:35:46 +09:00
co-authored by Claude Sonnet 5
parent 04784a808a
commit e937978116
16 changed files with 15 additions and 7 deletions
@@ -500,19 +500,23 @@ def _add_machine_layers(
@lru_cache(maxsize=1)
def load_basis_missing(
file_name: str = "2_공종_산림_밑수없음_2026-01-01.json",
file_name: str = "기준수량없음_산림품셈_2026-01-01.json",
) -> dict[str, str]:
"""B08 이 낸 **밑수 못 찾은 표** 목록 — `{표 번호: 절 이름}`.
「10㎡당」 같은 기준을 원문에서 못 찾은 표다. 1 단위당으로 단정하면 곱셈이
10배·100배 틀리므로(떼채취가 실제로 100배였다) 그 표를 쓰는 공종은
**금액을 안 만든다**.
2026-09-22 — old/ 스냅샷 대신 최상위 마스터로 옮김(PLAN 7-5 ⑤ · 브레인 판정).
⚠ `root` 계산이 파일이 `old_code/` 로 옮겨진 뒤(PLAN 7-3) 한 단 부족해 있었음 —
조용히 빈 딕셔너리를 돌려주던 것을 여기서 같이 바로잡음(3단 위가 프로젝트 뿌리).
"""
import json
import os
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
path = os.path.join(root, "resources", "master_data", "old", file_name)
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
path = os.path.join(root, "resources", "master_data", file_name)
if not os.path.exists(path):
return {}
with open(path, encoding="utf-8") as handle:
@@ -22,10 +22,10 @@ from pathlib import Path
from typing import Any
ALIAS_FILE = (
Path(__file__).resolve().parents[1]
Path(__file__).resolve().parents[2]
/ "resources"
/ "master_data"
/ "ref"
/ "old"
/ "공종_자원별칭_실무_2026-01-01.json"
)
AXES = frozenset({"resource", "variant"})
@@ -20,7 +20,7 @@ from functools import lru_cache
from pathlib import Path
from typing import Any, Iterable
MASTER_DIR = Path(__file__).resolve().parent.parent / "resources" / "master_data" / "old"
MASTER_DIR = Path(__file__).resolve().parent.parent.parent / "resources" / "master_data" / "old"
#: 우리가 세운 공종·구조물 — 난수 코드가 곧 불변 열쇠
_STABLE_CODE = re.compile(r"^AX-(?:WK|ST)-[0-9a-f]{8}$")
@@ -19,7 +19,7 @@ from functools import lru_cache
from pathlib import Path
from typing import Any
FOLDER = Path(__file__).resolve().parent.parent / "resources" / "master_data" / "old"
FOLDER = Path(__file__).resolve().parent.parent.parent / "resources" / "master_data" / "old"
CONFIRMED = "확정"
#: 표 `policy.both_precedence` 낱말 → 그 행의 열쇠 칸
_KEY_COLUMN = {"forest": "forest_key", "construction": "const_key"}
@@ -62,6 +62,8 @@ DIVISIONS = {
_FILE = re.compile(
rf"^(?:(인력|기계)|({'|'.join(mf.GROUPS)})_({'|'.join(BOOKS)})(?:_(\d\d)장_(.+))?)\.json$"
)
#: 8장 틀에 안 맞는 특수 최상위 파일(표·요소가 아닌 다른 모양) — 틀 검사에서 뺌(PLAN 7-5 ⑤).
SPECIAL_FILES = {"기준수량없음_산림품셈_2026-01-01.json"}
_SOURCE = re.compile(
rf"^(?:자체|(?:{'|'.join(b for b in BOOKS if b not in ('건설품셈', '자체'))})(?:\s\S.*)?|건설품셈 (?:{'|'.join(DIVISIONS)}) \S.*)$"
)
@@ -253,6 +255,8 @@ def check_combo_form(name: str, data: dict) -> list[str]:
def check_form(name: str, data: dict) -> list[str]:
if name == mcb.FILE:
return check_combo_form(name, data)
if name in SPECIAL_FILES:
return []
m = _FILE.match(name)
if not m:
return [