test(z01): 기초단가 원천 시험 — 손료표 복원 뒤 멈추던 것 · 줄 번호 열쇠를 표 차례·코드로
코덱스 2단 머리 복원(42073a6d)으로 손료표 13개는 풀림. 남은 둘에서 시험이 멈추고(15건 오류) 있었음.
- 5220 소형브레이커 · 7995 배관파이프 — 머리 「시 간 당(10-7)」 은 표 위 글줄로 돌아왔으나 표에 계수 칸이
없음(원문에 값 없음) → 멈추지 않고 「손료 계수 칸 없는 표」 로 못 보는 자리에 남김
- ⚠ 목록 열쇠·원표 맞대기가 줄 번호에 기대고 있었음(`손료 줄 L2683` · 운전경비 원표를 `line` 으로 찾음)
→ md 가 고쳐질 때마다 통째로 밀림. 코드·8-4 안 표 차례로 바꿈
- 복원으로 원문에서 새로 읽히는 손료 줄 → 자료에 없는 기종 8 묶음(0230·3601·6532·6801·7101·7120·7830·9060)
· 원문 손료 코드 586 → 608 · 뭉개진 손료 글 11 이 모두 표로 돌아와 못 봄 목록에서 빠짐
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -212,9 +212,9 @@
|
||||
"why": "자료 이름이 빔 — 원문 손료표 머리 `(코드) 이름` 엔 이름 있음"
|
||||
},
|
||||
"셈 손료 코드 수": {
|
||||
"source": 586,
|
||||
"source": 608,
|
||||
"data": 387,
|
||||
"why": "원문 586 줄 중 자료 387 — 뭉친 줄·해상장비·`-0003` 줄을 자료가 안 옮김(`… 자료에 없음` 참조)"
|
||||
"why": "원문 손료 코드 608(코덱스 복원으로 586 에서 늘어남) 중 자료 387 — 자료에 없는 기종 묶음(`… 자료에 없음` 참조)"
|
||||
},
|
||||
"셈 연료 코드 수": {
|
||||
"source": 197,
|
||||
@@ -246,6 +246,18 @@
|
||||
"data": null,
|
||||
"why": "축약 손료표(내용시간·계만) — 자료가 내용시간을 안 옮김"
|
||||
},
|
||||
"손료 0230 자료에 없음": {
|
||||
"source": [
|
||||
"0230-0002",
|
||||
"0230-0004",
|
||||
"0230-0006",
|
||||
"0230-0007",
|
||||
"0230-0008",
|
||||
"0230-0010"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 0240-0007 machine_name": {
|
||||
"source": "유압식 진동콤팩터(굴착기 부착용)",
|
||||
"data": "대형 브레이커시 간 당(10-7)연간분류규격내용연간표준상각정비관리상각비정비비관리비번호(㎥)시간가동시간비율비율계비율계수계수계수0230-00020.23,0008900.90.850.13,0002,8337686,60100040.43,0008900.90.850.13,0002,8337686,60100060.63,0008900.90.850.13,0002,8337686,60100070.73,0008900.90.850.13,0002,8337686,60100080.83,0008900.90.850.13,0002,8337686,60100101.03,0008900.90.850.13,0002,8337686,601(0240) 유압식 진동콤팩터(굴착기 부착용)",
|
||||
@@ -290,6 +302,17 @@
|
||||
"data": null,
|
||||
"why": "원문 줄 코드가 `-0003` 꼴 — 자료가 못 읽고 빠뜨림"
|
||||
},
|
||||
"손료 3601 자료에 없음": {
|
||||
"source": [
|
||||
"3601-0102",
|
||||
"3601-0202",
|
||||
"3601-0204",
|
||||
"3601-0302",
|
||||
"3601-0402"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 3611-0142 machine_name": {
|
||||
"source": "콘크리트 피니셔(중앙분리대용)",
|
||||
"data": "콘크리트 피니셔(포장용)",
|
||||
@@ -500,11 +523,25 @@
|
||||
"data": null,
|
||||
"why": "원문 한 칸에 여러 코드가 뭉친 줄 — 자료가 안 옮겨 손료가 없음"
|
||||
},
|
||||
"손료 6532 자료에 없음": {
|
||||
"source": [
|
||||
"6532-0220"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 6540-0131 machine_name": {
|
||||
"source": "워터젯트",
|
||||
"data": "진동파일 해머(유압식)시 간 당(10-7)연간분류규격내용연간표준상각정비관리상각비정비비관리비번호(㎾)시간가동시간비율비율계비율계수계수계수6532-02201627,0008900.90.50.11,2867146822,682(6540) 워터젯트",
|
||||
"why": "자료 이름 칸에 원문 뭉개진 손료 글이 통째로 들어감 — 자료 이름 틀림"
|
||||
},
|
||||
"손료 6801 자료에 없음": {
|
||||
"source": [
|
||||
"6801-0010"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 6802-0040 machine_name": {
|
||||
"source": "파일천공전용장비",
|
||||
"data": "고압분사전용장비",
|
||||
@@ -535,6 +572,20 @@
|
||||
"data": "고압분사전용장비",
|
||||
"why": "앞 기종 6801 이름이 붙음 — 원문 뭉개진 글(L2927) 경계에서 밀림"
|
||||
},
|
||||
"손료 7101 자료에 없음": {
|
||||
"source": [
|
||||
"7101-0450"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 7120 자료에 없음": {
|
||||
"source": [
|
||||
"7120-0746"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 7202 자료에 없음": {
|
||||
"source": [
|
||||
"7202-0008",
|
||||
@@ -593,6 +644,13 @@
|
||||
"data": null,
|
||||
"why": "원문 한 칸에 여러 코드가 뭉친 줄 — 자료가 안 옮겨 손료가 없음"
|
||||
},
|
||||
"손료 7830 자료에 없음": {
|
||||
"source": [
|
||||
"7830-0081"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 7930-0001 machine_name": {
|
||||
"source": "모터",
|
||||
"data": "우레탄폼 분사용기구",
|
||||
@@ -739,6 +797,18 @@
|
||||
"data": null,
|
||||
"why": "해상장비 손료표(형식·출력 여러 칸) — 자료가 안 옮김"
|
||||
},
|
||||
"손료 9060 자료에 없음": {
|
||||
"source": [
|
||||
"9060-0060",
|
||||
"9060-0100",
|
||||
"9060-0200",
|
||||
"9060-0300",
|
||||
"9060-0500",
|
||||
"9060-0600"
|
||||
],
|
||||
"data": null,
|
||||
"why": "코덱스 복원(0a3908b5·42073a6d)으로 원문에서 새로 읽히게 된 손료 줄 — 자료가 아직 안 실음"
|
||||
},
|
||||
"손료 9070 자료에 없음": {
|
||||
"source": [
|
||||
"9070-0015",
|
||||
@@ -860,69 +930,22 @@
|
||||
}
|
||||
},
|
||||
"machine_blind": {
|
||||
"손료 뭉개진 글 L1947": {
|
||||
"손료 계수 칸 없는 표 5220": {
|
||||
"what": [
|
||||
"0230"
|
||||
"분류 번호",
|
||||
"규 격",
|
||||
"내용 시간",
|
||||
"연간 표준 가동 시간"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
"why": "복원 뒤에도 원문 표에 계수 칸이 없음 — 머리 「시 간 당(10-7)」 은 표 위 글줄로만 · 값은 원문에 없음"
|
||||
},
|
||||
"손료 뭉개진 글 L2384": {
|
||||
"손료 계수 칸 없는 표 7995": {
|
||||
"what": [
|
||||
"3601"
|
||||
"분류 번호",
|
||||
"규 격",
|
||||
"내용 시간"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L2683": {
|
||||
"what": [
|
||||
"5220"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L2894": {
|
||||
"what": [
|
||||
"6532"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L2927": {
|
||||
"what": [
|
||||
"6801"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L2956": {
|
||||
"what": [
|
||||
"7101"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L2988": {
|
||||
"what": [
|
||||
"7120"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L3209": {
|
||||
"what": [
|
||||
"7830"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L3297": {
|
||||
"what": [
|
||||
"7995"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L3346": {
|
||||
"what": [],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
},
|
||||
"손료 뭉개진 글 L3367": {
|
||||
"what": [
|
||||
"9060"
|
||||
],
|
||||
"why": "원문 손료표가 표가 아니라 한 줄 글로 뭉개짐 — 코드·값을 못 가름, 이 기종 손료는 안 봄(자료에도 없음)"
|
||||
"why": "복원 뒤에도 원문 표에 계수 칸이 없음 — 머리 「시 간 당(10-7)」 은 표 위 글줄로만 · 값은 원문에 없음"
|
||||
},
|
||||
"손료보정 수 자리 가름": {
|
||||
"what": "뭉개진 글의 이어 붙은 수(2510)를 통째로 맞댐",
|
||||
@@ -944,6 +967,10 @@
|
||||
"what": "원문과 안 맞댐",
|
||||
"why": "계산 칸(계 × 10⁻⁷) — 원문 `계`(source_coefficient_1e_minus_7)만 맞댐"
|
||||
},
|
||||
"안 잰 칸 mach_loss_coef.note": {
|
||||
"what": "원문과 안 맞댐",
|
||||
"why": "데스크탑 서브가 붙인 설명 글 — 값 아님"
|
||||
},
|
||||
"안 잰 칸 mach_loss_coef.specification": {
|
||||
"what": "원문과 안 맞댐",
|
||||
"why": "규격 칸이 한 칸에 여러 값·여러 열로 뭉쳐 가르기 어려움 — 안 맞댐"
|
||||
@@ -1040,28 +1067,28 @@
|
||||
"what": "원문 표 토막 수가 안 맞음",
|
||||
"why": "원문 운전경비 표 토막 수가 코드 수와 안 맞음(`동력 15.1㎾`·`73.7+ 휘발유54.5` 등) — 이 줄 자료 값은 못 봄"
|
||||
},
|
||||
"연료 표 L3420": {
|
||||
"연료 표 3108-0040": {
|
||||
"codes": [
|
||||
"3108-0040",
|
||||
"3901-0300"
|
||||
],
|
||||
"why": "원문 운전경비 표 토막 수가 안 맞음 — 이 표 줄은 못 읽음"
|
||||
},
|
||||
"연료 표 L3444": {
|
||||
"연료 표 5401-0015": {
|
||||
"codes": [
|
||||
"5401-0015",
|
||||
"5805-0003"
|
||||
],
|
||||
"why": "원문 운전경비 표 토막 수가 안 맞음 — 이 표 줄은 못 읽음"
|
||||
},
|
||||
"연료 표 L3456": {
|
||||
"연료 표 7101-0450": {
|
||||
"codes": [
|
||||
"7101-0450",
|
||||
"7811-0120"
|
||||
],
|
||||
"why": "원문 운전경비 표 토막 수가 안 맞음 — 이 표 줄은 못 읽음"
|
||||
},
|
||||
"연료 표 L3462": {
|
||||
"연료 표 7812-0005": {
|
||||
"codes": [
|
||||
"7812-0005",
|
||||
"7994-0050"
|
||||
@@ -1157,6 +1184,14 @@
|
||||
"what": "코드(`B09_Estimation_Statutory.STATUTORY_ITEMS`)가 직접공사비로 계산하고 있는 것과 맞춘 표기.",
|
||||
"why": "설명 글"
|
||||
},
|
||||
"안 잰 칸 rate_overhead.basis": {
|
||||
"what": "조달청 「2026년 토목·조경·산업환경설비공사 원가계산 간접공사비(제비율) 적용기준」(2026-04-13). ⚠ 구간 라벨의 `billion` 은 **십억 원** — `lt_5_billion` 은 50억 미만이다. 종합(토목·조경·산업설비)은 5억미만~30억~50억 8 · 50~100억·100~300억 6.5 · 300~1000억 5 · 1000억이상 4.5, 전문 등은 5억미만 8 · 5~30억 6.5 · 30~50억·50~100억 5 · 100억이상 4.5.",
|
||||
"why": "데스크탑 서브가 붙인 설명 글 — 값 아님"
|
||||
},
|
||||
"안 잰 칸 rate_overhead.specialty_note": {
|
||||
"what": "⚠ 2026-09-18 **300억 이상 두 구간이 통째로 빠져 있었음** — 마지막이 「100억-300억 미만」으로 닫혀 300억 넘는 전문공사가 어느 구간에도 안 걸렸음. 원본 XLSX(BL35:BR46) 대로 300~1000억 · 1000억 이상을 더함(둘 다 4.5%). 값은 원문 그대로.",
|
||||
"why": "데스크탑 서브가 붙인 설명 글 — 값 아님"
|
||||
},
|
||||
"안 잰 칸 rate_performance_guarantee_fee.typical_forest_road_applicability": {
|
||||
"what": "not_applicable",
|
||||
"why": "임도 적용 판단 — 원문 칸 아님"
|
||||
|
||||
@@ -221,7 +221,7 @@ def read_machine(path: Path) -> dict:
|
||||
codes, prefix = _codes(r[1], prefix)
|
||||
prices = r[2].split()
|
||||
if codes is None or len(codes) != len(prices):
|
||||
out["skipped"][f"가격 줄 L{t['line'] + 2 + n}"] = {"what": r[1][:40]}
|
||||
out["skipped"][f"가격 줄 {_t(r[1])[:24]}"] = {"what": r[1][:40]}
|
||||
continue
|
||||
out["price"].update(
|
||||
(c, {"price_thousand_krw": _num(p)}) for c, p in zip(codes, prices)
|
||||
@@ -235,8 +235,11 @@ def read_machine(path: Path) -> dict:
|
||||
sub = next((r for r in t["rows"] if not r[0]), [])
|
||||
if "상각비 계수" in sub:
|
||||
cols.update(zip(LOSS_COEF, range(sub.index("상각비 계수"), 99)))
|
||||
else:
|
||||
elif "시간당(10-7)" in head:
|
||||
cols[LOSS_COEF[3]] = head.index("시간당(10-7)")
|
||||
else: # 원문 표에 계수 칸이 없음(5220·7995 — 머리 「시 간 당(10-7)」 은 표 위 글줄로만 남음)
|
||||
out["skipped"][f"손료 계수 칸 없는 표 {t['rows'][0][0][:4] if t['rows'] else '?'}"] = {"what": t["headers"]} # fmt: skip
|
||||
continue
|
||||
for n, r in enumerate(t["rows"]):
|
||||
if not r[0]:
|
||||
continue
|
||||
@@ -246,7 +249,7 @@ def read_machine(path: Path) -> dict:
|
||||
if not codes or any(len(v) != len(codes) for v in values.values()):
|
||||
raise ValueError(r[0])
|
||||
except ValueError:
|
||||
out["skipped"][f"손료 줄 L{t['line'] + 2 + n}"] = {"what": r[0][:40]}
|
||||
out["skipped"][f"손료 줄 {_t(r[0])[:24]}"] = {"what": r[0][:40]}
|
||||
continue
|
||||
out["loss"].update(
|
||||
(c, {f: v[k] for f, v in values.items()}) for k, c in enumerate(codes)
|
||||
@@ -254,12 +257,13 @@ def read_machine(path: Path) -> dict:
|
||||
for k in range(at["8-3 기계손료"], at["8-4 운전경비"]):
|
||||
if not lines[k - 1].lstrip().startswith("|") and "시 간 당(10-7)" in lines[k - 1]:
|
||||
heads = re.findall(r"\((\d{4})\) ?(?:[^|()]{0,30}\([^)]*\)){0,2}[^|()]{0,30}?시 간 당\(10-7\)", lines[k - 1]) # fmt: skip
|
||||
out["skipped"][f"손료 뭉개진 글 L{k}"] = {"what": heads}
|
||||
if heads: # 표 위 머리 글줄(`시 간 당(10-7)` 한 줄)은 표로 읽힘 — 뭉개진 글만
|
||||
out["skipped"][f"손료 뭉개진 글 {'·'.join(heads)}"] = {"what": heads}
|
||||
prefix = None
|
||||
for t in tables:
|
||||
if not at["8-4 운전경비"] < t["line"] < at["8-5 기계가격"]:
|
||||
continue
|
||||
out["fuel_tables"][t["line"]] = {"headers": t["headers"], "rows": t["rows"]}
|
||||
out["fuel_tables"][len(out["fuel_tables"])] = {"headers": t["headers"], "rows": t["rows"]}
|
||||
if t["line"] > at["8-4-9 [90]"] or t["headers"][0] != "분류번호":
|
||||
continue
|
||||
for r in t["rows"]:
|
||||
@@ -270,7 +274,9 @@ def read_machine(path: Path) -> dict:
|
||||
raise ValueError(r[0])
|
||||
parsed = [(*_fuel(f), _num(m), _num(o)) for f, m, o in zip(*cols)]
|
||||
except ValueError:
|
||||
out["skipped"][f"연료 표 L{t['line']}"] = {"codes": codes and [codes[0], codes[-1]]}
|
||||
out["skipped"][f"연료 표 {codes[0] if codes else _t(r[0])[:24]}"] = {
|
||||
"codes": codes and [codes[0], codes[-1]]
|
||||
}
|
||||
out["fuel_unread"] = out.get("fuel_unread", set()) | set(codes or ())
|
||||
continue
|
||||
out["fuel"].update((c, dict(zip(FUEL_FIELDS, p))) for c, p in zip(codes, parsed) if p[1] is not None) # fmt: skip
|
||||
@@ -315,10 +321,15 @@ def check_machine(src: dict, bad: dict, blind: dict) -> dict:
|
||||
_unchecked(blind, var, records, {"machine_code", "machine_name", *fields})
|
||||
blind.update(source["skipped"])
|
||||
tables = v["mach_fuel_rate"]["source_tables"]
|
||||
for st in tables:
|
||||
t = source["fuel_tables"].get(st["line"])
|
||||
for n, st in enumerate(
|
||||
tables
|
||||
): # ⚠ 줄 번호로 안 맞댐 — md 가 고쳐지면 통째로 밀림. 8-4 안 표 차례로
|
||||
t = source["fuel_tables"].get(n)
|
||||
if t != {"headers": st["headers"], "rows": st["rows"]}:
|
||||
bad[f"운전경비 원표 L{st['line']}"] = {"source": t, "data": _without_why(st)}
|
||||
bad[f"운전경비 원표 {n + 1}번째"] = {
|
||||
"source": t,
|
||||
"data": {k: st[k] for k in ("headers", "rows")},
|
||||
}
|
||||
counts["운전경비 원표 수"] = (len(source["fuel_tables"]), len(tables))
|
||||
_unchecked(blind, "mach_fuel_rate.source_tables", tables, {"line", "headers", "rows"})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user