"""B09 — 기계 작업량 **밑값**을 마스터에서 읽는다(2026-09-16 사용자 원칙 · 브레인 지시). 마스터 = 관리자가 제어할 값 · **코드 안에 있으면 안 됨.** 그동안 불도저 속도·삽날 용량(건설품셈 8-2-1)과 덤프 운반·적재 식 계수(산림품셈 10-12)가 코드 상수로 박혀 있었다. 값은 그대로 두고 자리만 옮긴다 — `resources/data_machine_productivity/machine_productivity_<판>.json`. ⚠ **식은 여기 없다.** `Q = n·q·f·E` 같은 식은 값이 아니라 로직이라 계산 모듈에 남는다. ⚠ 옮기면서 값을 하나도 안 바꿨다 — 원문(pum_const C0426·C0427)과의 대조는 시험이 지킨다. """ from __future__ import annotations import json from decimal import Decimal from functools import lru_cache from pathlib import Path from typing import Any DATA_DIR = Path(__file__).resolve().parent.parent / "resources" / "data_machine_productivity" PREFIX = "machine_productivity_" class MachineProductivityDataError(FileNotFoundError): """밑값 판이 없다 — 지어내지 않고 멈춘다.""" @lru_cache(maxsize=2) def _read(path: str, _mtime_ns: int) -> dict[str, Any]: return json.loads(Path(path).read_text(encoding="utf-8")) def load() -> dict[str, Any]: """끝 판 한 벌(이름 차례).""" found = sorted(DATA_DIR.glob(PREFIX + "*.json")) if DATA_DIR.is_dir() else [] if not found: raise MachineProductivityDataError(f"기계 작업량 밑값 판이 없습니다: {DATA_DIR}") return _read(str(found[-1]), found[-1].stat().st_mtime_ns) def records(variable: str) -> list[dict[str, Any]]: return load()["variables"][variable]["records"] def dozer_speeds() -> dict[str, dict[Decimal, dict[int, tuple[Decimal, Decimal]]]]: """{무한궤도·타이어: {규격(ton): {단: (전진, 후진)}}} — 후진이 원문에 없는 단은 담기지 않는다.""" out: dict[str, dict[Decimal, dict[int, tuple[Decimal, Decimal]]]] = {} for row in records("dozer_speed"): track = out.setdefault(row["track"], {}) gears = track.setdefault(Decimal(row["tonnage_ton"]), {}) gears[int(row["gear"])] = ( Decimal(row["forward_m_per_min"]), Decimal(row["reverse_m_per_min"]), ) return out def dozer_blades() -> dict[tuple[str, Decimal], Decimal]: """{(무한궤도·타이어, 규격(ton)): 삽날 용량 q˚(㎥)}.""" return { (row["track"], Decimal(row["tonnage_ton"])): Decimal(row["blade_m3"]) for row in records("dozer_blade") } def haul_params() -> dict[str, Decimal]: """덤프 운반·적재 식이 쓰는 밑값(적재 규격 T · 버켓 q · 싸이클 · 주행속도 · 적하·대기·덮개).""" return {row["key"]: Decimal(row["value"]) for row in records("dump_haul")}