Merge remote-tracking branch 'origin/main_laptop_1' into sub_desktop_1
충돌은 **뽑아서 생기는 파일 넷**(공종 마스터 둘 · 이름표 둘)뿐 — 손으로 쓴 자리가 없어 랩탑 쪽을 취함. 랩탑이 판정 코드를 고쳐 뽑은 것이라 그쪽이 새 것임(형태 275 → 196). 곧바로 다시 뽑아 덮음.
This commit is contained in:
@@ -212,13 +212,33 @@ def build() -> tuple[
|
||||
|
||||
require_code_edition(data["effective_date"], "공종 마스터 빌드 — 표 형태·부모 모양 판정")
|
||||
tables = data["variables"]["pum"]["tables"]
|
||||
# 원문을 함께 연다 — 밑수가 표 밖(본문)에 있기 때문이다. 못 열면 밑수 없이 간다.
|
||||
source_lines: list[str] = []
|
||||
for entry in data.get("sources") or []:
|
||||
candidate = ROOT / str(entry.get("path") or "")
|
||||
if candidate.is_file():
|
||||
source_lines = candidate.read_text(encoding="utf-8").splitlines()
|
||||
break
|
||||
# 원문을 함께 연다 — 밑수·[주]가 표 밖(본문)에 있기 때문이다. 못 열면 밑수 없이 간다.
|
||||
# ⚠ **표마다 제 원문 파일을 본다** — 건설은 원문이 장별로 갈려 있고 `line` 도 그 파일 기준이다.
|
||||
# 첫 파일만 열어 모든 표의 줄 번호를 맞대면 **남의 장 글을 근거로 읽는다**
|
||||
# (2026-09-18: 그 탓에 건설 밑수 미판독 79 가 헛으로 세어졌다).
|
||||
_line_cache: dict[str, list[str]] = {}
|
||||
|
||||
def lines_of(table: dict[str, Any]) -> list[str]:
|
||||
name = str(table.get("source_file") or "")
|
||||
if name not in _line_cache:
|
||||
candidate = ROOT / name
|
||||
if not candidate.is_file():
|
||||
candidate = candidate.with_suffix(".md")
|
||||
if not candidate.is_file(): # 산림처럼 표에 파일이 안 적힌 판 — 첫 원천을 쓴다
|
||||
first = next(
|
||||
(
|
||||
ROOT / str(e.get("path") or "")
|
||||
for e in data.get("sources") or []
|
||||
if (ROOT / str(e.get("path") or "")).is_file()
|
||||
),
|
||||
None,
|
||||
)
|
||||
candidate = first or candidate
|
||||
_line_cache[name] = (
|
||||
candidate.read_text(encoding="utf-8").splitlines() if candidate.is_file() else []
|
||||
)
|
||||
return _line_cache[name]
|
||||
|
||||
toc_table = next(t for t in tables if t["table_id"] == "F0001")
|
||||
nodes = parse_toc(toc_table["rows"])
|
||||
toc_corrections = renumber_from_body(nodes, tables)
|
||||
@@ -247,7 +267,7 @@ def build() -> tuple[
|
||||
if node is not None and not title_names_node(section, node):
|
||||
node = None # 번호만 겹친 딴 문서 표(부록 사례) — 못 붙인 표 목록으로
|
||||
entry = table_entry(
|
||||
table, section, number, chapter, source_lines, node and node["name"], report
|
||||
table, section, number, chapter, lines_of(table), node and node["name"], report
|
||||
)
|
||||
if node is None:
|
||||
orphans.append({"pum_table_id": table["table_id"], "section": section})
|
||||
|
||||
@@ -45,6 +45,13 @@ _ASIDE_HEAD_RE = re.compile(r"비고|적용기준|산출근거|산출식|참고"
|
||||
COST_ITEMS = {"재료비", "설치비", "노무비", "경비", "제작비", "운송비", "자재비", "주재료비"}
|
||||
#: 공식 기호 한 글자(아래첨자·숫자 꼬리 포함) — `β` · `E` · `t 1` · `q₀`.
|
||||
_SYMBOL_RE = re.compile(r"[A-Za-zα-ωΑ-Ω][₀-₉0-9]?")
|
||||
#: 할증·보정 낱말 — 값이 품이 아니라 **다른 값에 곱하는 율**임을 원문이 이름으로 말한 자리.
|
||||
_RATE_WORD_RE = re.compile(r"할증|할인|가산|감액|경비의|노무비의|재료비의|기계경비의|효\s*율")
|
||||
#: 능력(작업량·시공량·소요시간) 낱말 — 「한 시간·하루에 얼마」라 품 표가 아니라 능력 표다.
|
||||
_CAPACITY_RE = re.compile(
|
||||
r"작업량|시공량|시공능력|작업능력|처리량|산출량|소요시간|작업시간|"
|
||||
r"㎥/hr|㎡/hr|본/hr|톤/hr|ton/hr|hr/ton|min/|/hr|/일\)"
|
||||
)
|
||||
|
||||
|
||||
def _squeeze(text: Any) -> str:
|
||||
@@ -118,9 +125,78 @@ def judged_const_form(table: dict[str, Any]) -> tuple[str, str] | None:
|
||||
return "coefficient", f"줄 이름이 공식 기호뿐 {sorted(set(named))[:4]}"
|
||||
|
||||
# ⑧ 값이 모두 백분율 — 품·자재 수량이 아니라 요율(층별 할증 `5% 8% 12%`)
|
||||
# ⚠ 「0」은 백분율 줄의 첫 칸으로 자주 온다(지하층 0 · 4층 5% …) — 셈에서 빼고 본다.
|
||||
percents = [_squeeze(c) for c in _value_cells(table) if _squeeze(c)]
|
||||
figures = [x for x in percents if _NUMBERS_RE.match(x) or x.endswith("%")]
|
||||
if figures and all(x.endswith("%") for x in figures) and len(figures) >= 3:
|
||||
marks = [x for x in figures if x not in ("0", "0.0")]
|
||||
if marks and all(x.endswith("%") for x in marks) and len(marks) >= 3:
|
||||
return "coefficient", "값이 모두 백분율 — 요율표"
|
||||
|
||||
# ⑨ 할증·보정 낱말이 줄 이름·머리에 있고 값이 있음 — 율표(수직고별 할증률 · 기계경비의 %)
|
||||
if found := next((x for x in headers + first_col if _RATE_WORD_RE.search(x)), None):
|
||||
return "coefficient", f"'{found}' — 할증·보정 율표"
|
||||
|
||||
# ⑩ 작업량·시공능력·소요시간 표 — 품이 아니라 **능력**이다(한 시간·하루에 얼마)
|
||||
if found := next((x for x in headers + first_col if _CAPACITY_RE.search(x)), None):
|
||||
return "productivity", f"'{found}' — 작업량·시공능력 표"
|
||||
|
||||
# ⑪ 기계 기초표 — 가격·손료는 **기계 벌(mach_base_2026.json)이 정본**이라 공종 품이 아님
|
||||
if any("가격" in h for h in headers) and any("분류번호" in h for h in headers):
|
||||
return "reference", "기계 가격표 — 기계 벌이 정본"
|
||||
if any("시간당" in h for h in headers) and any("분류번호" in h for h in headers):
|
||||
return "reference", "기계 손료표 — 기계 벌이 정본"
|
||||
|
||||
# ⑫ 머리 칸이 시공능력 공식 기호 — `K`·`E`·`f`·`t(분)` (건설 8-2 기계 시공능력 밑값)
|
||||
if found := next((h for h in headers if _FORMULA_HEAD_RE.fullmatch(h)), None):
|
||||
return "coefficient", f"머리가 공식 기호 '{found}' — 시공능력 밑값"
|
||||
|
||||
# ⑬ 줄 이름이 시간 — 「시간(분)」·「사이클타임」은 품이 아니라 **걸리는 시간**이다
|
||||
if found := next((x for x in first_col if _TIME_ROW_RE.search(x)), None):
|
||||
return "productivity", f"줄 이름 '{found}' — 걸리는 시간"
|
||||
|
||||
# ⑭ 줄 이름이 사용량·소요량 — 자재 소요량 표(`사용량(kg) | 6.5 | 8.0`)
|
||||
if found := next((x for x in first_col if _AMOUNT_ROW_RE.search(x)), None):
|
||||
return "requirement", f"줄 이름 '{found}' — 자재 소요량"
|
||||
|
||||
# ⑮ 다짐 기준표 — 두께·횟수·규격을 정한 **시방 기준**이지 품이 아님(건설 8-2-9 롤러)
|
||||
if sum(1 for h in headers if _COMPACT_RE.search(h)) >= 2:
|
||||
return "reference", "다짐 두께·횟수 기준표 — 시방 기준"
|
||||
|
||||
return None
|
||||
|
||||
|
||||
#: 머리 한 칸이 공식 기호뿐 — 건설 8-2 시공능력 식의 밑값(`K`·`E`·`f`·`t(분)`·`C(분)`).
|
||||
_FORMULA_HEAD_RE = re.compile(r"[A-Za-zα-ωΑ-Ω][₀-₉0-9]?(?:\([^)]{1,4}\))?")
|
||||
#: 줄 이름이 「걸리는 시간」 — 품(사람·날)이 아니라 능력 쪽 값.
|
||||
_TIME_ROW_RE = re.compile(r"시간\(|\(분\)|사이클|주기\(")
|
||||
#: 줄 이름이 자재 쓰는 양.
|
||||
_AMOUNT_ROW_RE = re.compile(r"사용량|소요량|사용수량")
|
||||
#: 다짐 기준표 머리 — 두께·횟수·규격을 정한 시방 기준.
|
||||
_COMPACT_RE = re.compile(r"다짐두께|다짐횟수|다짐기계|다짐")
|
||||
|
||||
#: 머리에 구간이 적힌 표 — 「0∼10m」·「10m미만」처럼 **조건으로 갈리는** 표.
|
||||
_RANGE_RE = re.compile(r"[∼~~]|미만|이상|이하|초과")
|
||||
#: 규격·치수 단위 — 값이 이것뿐이면 품이 아니라 **규격 배정·기준**이다.
|
||||
_SPEC_UNIT_RE = re.compile(r"^[\d,.]+\s*(?:㎜|mm|㎝|m|㎡|㎥|inch|인치|kg|㎏|톤|ton|개|주|본)$")
|
||||
|
||||
|
||||
def const_undetermined_kind(table: dict[str, Any]) -> str:
|
||||
"""못 가른 까닭을 **갈래로** 적는다(2026-09-18 브레인 — 남은 것을 눈으로 가르기 위해).
|
||||
|
||||
⚠ 갈래는 「어디를 더 봐야 하나」를 가리킬 뿐, 형태를 짐작해 채우지 않는다.
|
||||
"""
|
||||
headers = [_squeeze(h) for h in table.get("headers") or []]
|
||||
rows = table.get("rows") or []
|
||||
first_row = [_squeeze(c) for c in (rows[0] if rows else [])]
|
||||
values = [_squeeze(c) for c in _value_cells(table) if _squeeze(c)]
|
||||
|
||||
if not _has_number(values):
|
||||
return "값이 없음 — 설명·서식·이름 목록"
|
||||
if first_row and not any(_NUMBER_RE.match(c) for c in first_row) and sum(1 for c in first_row if c) >= 2: # fmt: skip
|
||||
return "머리가 두 단 — 아래 단이 하위 구분(잣대가 못 폄)"
|
||||
if any(_RANGE_RE.search(h) for h in headers):
|
||||
return "머리가 구간 — 조건으로 갈리는 표"
|
||||
figures = [c for c in values if _NUMBERS_RE.match(c) or _SPEC_UNIT_RE.match(c)]
|
||||
if figures and all(_SPEC_UNIT_RE.match(c) for c in figures):
|
||||
return "값이 규격·치수뿐 — 기준표(원문이 품을 안 적음)"
|
||||
return "그 밖 — 사람이 봐야 함"
|
||||
|
||||
@@ -15,7 +15,10 @@ from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Forms import (
|
||||
judged_basis,
|
||||
judged_form,
|
||||
)
|
||||
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_FormsConst import judged_const_form
|
||||
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_FormsConst import (
|
||||
const_undetermined_kind,
|
||||
judged_const_form,
|
||||
)
|
||||
|
||||
# ── 형태 판정 ────────────────────────────────────────────────────────────
|
||||
# 헤더·비고 문자열에서 찾는 표지. 앞의 것이 먼저 걸린다(생산량형이 더 좁은 표현이라 우선).
|
||||
@@ -198,7 +201,8 @@ def detect_form(table: dict[str, Any], chapter: str | None) -> tuple[str, str]:
|
||||
# ⚠ 여기까지 왔다는 것은 산림 판정이 이미 못 가렸다는 뜻이라, 산림 결과는 흔들리지 않는다.
|
||||
if hit := judged_const_form(table):
|
||||
return hit[0], f"건설 꼴 — {hit[1]}"
|
||||
return "undetermined", "헤더·첫 행에 단위·밑수·직종 표지 없음"
|
||||
# 못 가른 것은 **갈래를 적어** 남긴다 — 「어디를 더 봐야 하나」가 보여야 줄일 수 있다.
|
||||
return "undetermined", f"단위·밑수·직종 표지 없음 · {const_undetermined_kind(table)}"
|
||||
|
||||
|
||||
BASIS_RE = re.compile(r"(\d[\d,.]*)\s*(㎥|m3|㎡|m2|㏊|ha|km|㎞|m|인|본|개|kg|㎏|톤|ton)\s*당")
|
||||
@@ -218,8 +222,12 @@ SOURCE_BASIS_RATIO_RE = re.compile(
|
||||
|
||||
#: 밑수 단위 — 건설은 「일·기·조·명·틀」도 씀(2026-09-18 브레인 · 건설 밑수 미판독 162).
|
||||
#: ⚠ 「회」는 넣지 않는다 — 2026-09-17 데스크탑 서브가 원문을 열어 **밑수 단위가 아니라고** 판정(10-4 중기운반).
|
||||
#: 2026-09-18 건설 미판독 101 을 보고 넓힘 — 원문이 세는 물건이 그대로 밑수인 자리.
|
||||
#: `(1대당)` · `(층당)` · `(set당)` · `(Joint당)` · `(1발파당)`.
|
||||
#: ⚠ 「단위당」은 안 넣는다 — 무엇의 단위인지 원문이 안 적었다.
|
||||
_BASIS_UNIT = (
|
||||
"공㎥|㎥|m3|㎡|m2|㏊|ha|㎞|km|m|매|본|개소|개|인|공|kg|㎏|톤|ton|주|식|대|일|기|조|명|틀"
|
||||
"|층|set|SET|Joint|joint|발파|구멍|孔|㎢|km2|도엽|ea|EA"
|
||||
)
|
||||
#: ⚠ **괄호 앞뒤에 글이 붙은 건설 꼴**도 읽는다 — `(용접개소당)` · `(세면기 개당)` · `(절단길이 10m당)` ·
|
||||
#: `(m당 : 관길이기준)`. 산림은 괄호 안이 밑수뿐이라 이 넓히기로 값이 달라지지 않는다.
|
||||
@@ -231,6 +239,8 @@ SOURCE_BASIS_RE = re.compile(
|
||||
)
|
||||
#: 한 괄호 안의 밑수 토막 — 둘 이상이면 못 고른다(`(1ha당, 100본당)`).
|
||||
_BASIS_TOKEN_RE = re.compile(rf"[\d,]*\.?\d*\s*(?:{_BASIS_UNIT})\s*당")
|
||||
#: 「당」이 안 붙은 단위까지 센다 — `1일 1대당` 처럼 **단위가 둘인 칸**을 가려내는 데 쓴다.
|
||||
_BASIS_UNIT_TOKEN_RE = re.compile(rf"[\d,]+\s*(?:{_BASIS_UNIT})")
|
||||
#: 표 위로 몇 줄까지 거슬러 볼 것인가. 더 올라가면 **앞 표의 밑수**를 잘못 물어 온다.
|
||||
SOURCE_LOOKBACK = 6
|
||||
|
||||
@@ -749,6 +759,21 @@ def table_entry(
|
||||
if not absent and basis_qty is None and basis_unit is None:
|
||||
basis_qty, basis_unit = detect_basis(table)
|
||||
basis_source = "표 안" if basis_unit else None
|
||||
# ⚠ 원문이 **표 머리 칸에** 밑수를 적어 둔 자리도 읽는다 — 「(단위 : ㎢)」·「(도엽당)」
|
||||
# (2026-09-18 건설 미판독 97 을 갈라 보니 이 꼴이 열넷).
|
||||
if not absent and basis_unit is None:
|
||||
cells = [*(table.get("headers") or [])]
|
||||
cells += [c for row in (table.get("rows") or [])[:2] for c in row]
|
||||
for cell in cells:
|
||||
text = norm(cell)
|
||||
# ⚠ 한 칸에 단위가 둘이면(`손료계수 (1일 1대당)`) 어느 쪽이 밑수인지 못 가린다 —
|
||||
# 한쪽만 집으면 조용히 틀리므로 **안 읽고 넘긴다**.
|
||||
if len(_BASIS_UNIT_TOKEN_RE.findall(text)) > 1:
|
||||
continue
|
||||
qty, unit = basis_from_source([text, "", "|"], 3)
|
||||
if unit:
|
||||
basis_qty, basis_unit, basis_source = qty, unit, "표 머리"
|
||||
break
|
||||
elif basis_source is None:
|
||||
basis_source = "본문"
|
||||
# 본문·표 안에 없을 때만 **절 이름**을 본다(4-2-2 「1,000㎡당」) — 이름 전체가 밑수일 때만.
|
||||
@@ -776,9 +801,14 @@ def table_entry(
|
||||
"line": table.get("line"),
|
||||
# ⚠ 「원문 부재」는 **채울 것이 아니다** — 없는 값을 지어내면 안 된다.
|
||||
# 「미판독」만 진짜 할 일이다(2026-09-18 브레인 · 안티그래비티 3바퀴).
|
||||
# ⚠ **작업조 표는 밑수가 애초에 표 밖이다** — 하루 편성 인원·장비를 적고
|
||||
# 시공량은 [주]·다른 표에 있다. 「미판독」으로 세면 없는 할 일이 생긴다
|
||||
# (2026-09-18 건설 미판독 101 가운데 79 가 이 꼴이었다).
|
||||
"why": absent
|
||||
or (
|
||||
"미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"원문 부재 — 작업조 표(하루 편성) · 밑수는 표 밖의 시공량"
|
||||
if crew_table(table)
|
||||
else "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
if source_declares_basis(source_lines, int(table.get("line") or 0), table)
|
||||
else "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
),
|
||||
|
||||
@@ -6363,7 +6363,7 @@
|
||||
"name_ko": "밑수 못 찾은 표",
|
||||
"summary": "기준 수량을 못 읽은 품셈 표. 1 단위당으로 단정하면 곱셈이 틀린다.",
|
||||
"shape": "list",
|
||||
"rows": 81,
|
||||
"rows": 79,
|
||||
"columns": [
|
||||
{
|
||||
"key": "pum_table_id",
|
||||
@@ -7267,7 +7267,7 @@
|
||||
"name_ko": "형태 미판정 표",
|
||||
"summary": "생산량형인지 소요량형인지 못 정한 표.",
|
||||
"shape": "list",
|
||||
"rows": 275,
|
||||
"rows": 196,
|
||||
"columns": [
|
||||
{
|
||||
"key": "pum_table_id",
|
||||
@@ -7323,7 +7323,7 @@
|
||||
"name_ko": "밑수 미확보 표",
|
||||
"summary": "기준 수량을 못 찾은 표.",
|
||||
"shape": "list",
|
||||
"rows": 439,
|
||||
"rows": 431,
|
||||
"columns": [
|
||||
{
|
||||
"key": "pum_table_id",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "data_work_item_master_manifest",
|
||||
"generated_at": "2026-09-18T12:38:26+09:00",
|
||||
"generated_at": "2026-09-18T12:53:57+09:00",
|
||||
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
|
||||
"source": {
|
||||
"dataset_id": "pum_forest",
|
||||
@@ -12,8 +12,8 @@
|
||||
"files": [
|
||||
{
|
||||
"file": "work_item_master_2026-01-01.json",
|
||||
"sha256": "00bffb68105d4be348c92aa6d7c436eedb85170394d4f35ea68a814ae8fb46c1",
|
||||
"size_bytes": 1095109
|
||||
"sha256": "41a9ebd574ed425ca9cc180f3b9b5cbc3fa603d3e9a94e4731f2db275fb101fe",
|
||||
"size_bytes": 1095122
|
||||
},
|
||||
{
|
||||
"file": "form_undetermined_2026-01-01.json",
|
||||
@@ -22,8 +22,8 @@
|
||||
},
|
||||
{
|
||||
"file": "basis_missing_2026-01-01.json",
|
||||
"sha256": "ab1fef3d606fefb142d1d4c2af6bba82e3ab3a6b03d05f9ab358f67d490a86df",
|
||||
"size_bytes": 18830
|
||||
"sha256": "57c58458ef2a95aa67a5dd2e15989f2613c628e7c697c84d4a944349fa102422",
|
||||
"size_bytes": 18434
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "data_work_item_master_manifest",
|
||||
"generated_at": "2026-09-18T12:39:43+09:00",
|
||||
"generated_at": "2026-09-18T12:54:47+09:00",
|
||||
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
|
||||
"source": {
|
||||
"dataset_id": "pum_const",
|
||||
"effective_date": "2026-01-01",
|
||||
"sha256": "207129f59d95baed23a3a360c262a7250fb17fc44eada0c321d07825c410ee20",
|
||||
"sha256": "b8c85e6ab5b242d5d82a42ff761ec4e144309a1389bc267ea2f1ceabc3d4b8f1",
|
||||
"file": "pum_const_2026.json"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"file": "const_work_item_master_2026-01-01.json",
|
||||
"sha256": "31cf0d289351d45a804d2d2cf0b6c489786eabc69e685b8e413d3a00ec4e1fcc",
|
||||
"size_bytes": 4708119
|
||||
"sha256": "a3862986f252c2c395d765a879cd2e60899f011559268d27539bb051930738d1",
|
||||
"size_bytes": 4712576
|
||||
},
|
||||
{
|
||||
"file": "const_form_undetermined_2026-01-01.json",
|
||||
"sha256": "5a526986ac85619a3dd0b8b377a39a36ce18ed272641215089ab47cc45834570",
|
||||
"size_bytes": 152983
|
||||
"sha256": "b1b4619532c561bb17e53881e5732548a0f8e666dee7f841d9507f1ba760dddf",
|
||||
"size_bytes": 115516
|
||||
},
|
||||
{
|
||||
"file": "const_basis_missing_2026-01-01.json",
|
||||
"sha256": "90ef86c25df7e1f7e7b120aeeaec6813bf5b1f690d46e4fd2178d1e22f4497b5",
|
||||
"size_bytes": 111824
|
||||
"sha256": "bdc0720276122659f931f7144cce751aa18ea09d706ca7eb34a438b5e969bf7e",
|
||||
"size_bytes": 110609
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -417,20 +417,6 @@
|
||||
"line": 4373,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0228",
|
||||
"section": "8-6-2. 드론방제",
|
||||
"pum_form": "requirement",
|
||||
"line": 4541,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0229",
|
||||
"section": "8-6-2. 드론방제",
|
||||
"pum_form": "requirement",
|
||||
"line": 4561,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0230",
|
||||
"section": "8-6-3. 지상방제",
|
||||
|
||||
@@ -88,13 +88,6 @@
|
||||
"line": 1109,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0148",
|
||||
"section": "2-12-2 마스트 설치 및 해체('23년 신설)(층당)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1162,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0150",
|
||||
"section": "2-12-3 축중계 설치 및 해체('09년 신설, '10년 보완)(회당)",
|
||||
@@ -207,6 +200,13 @@
|
||||
"line": 118,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0258",
|
||||
"section": "2-2-2 주요자재 / 강재류’를 적용한다.5-1-7 어스앵커 공법('20, '26년 보완)",
|
||||
"pum_form": "productivity",
|
||||
"line": 142,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0263",
|
||||
"section": "5-1-9 주열식 현장벽체공법(CIP,Cast In Placed Pile)('26년 신설)",
|
||||
@@ -235,6 +235,13 @@
|
||||
"line": 271,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0269",
|
||||
"section": "5-1-9 주열식 현장벽체공법(CIP,Cast In Placed Pile)('26년 신설)",
|
||||
"pum_form": "productivity",
|
||||
"line": 291,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0271",
|
||||
"section": "5-1-10 차수그라우팅('26년 신설)",
|
||||
@@ -340,6 +347,13 @@
|
||||
"line": 670,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0303",
|
||||
"section": "85-3 말뚝5-3-1 기성말뚝 기초('99년 신설, '15, '16, '20, '26년 보완)",
|
||||
"pum_form": "productivity",
|
||||
"line": 698,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0306",
|
||||
"section": "5-3-2 말뚝박기용 천공('08, '15, '16, '20, '25, '26년 보완)",
|
||||
@@ -389,6 +403,13 @@
|
||||
"line": 869,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0322",
|
||||
"section": "5-3-5 현장타설말뚝('15, '21, '26년 보완)",
|
||||
"pum_form": "productivity",
|
||||
"line": 927,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0324",
|
||||
"section": "5-3-5 현장타설말뚝('15, '21, '26년 보완)",
|
||||
@@ -424,13 +445,6 @@
|
||||
"line": 487,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0376",
|
||||
"section": "6-3-10 신축이음(Expansion Joint) 설치('18년 신설)",
|
||||
"pum_form": "requirement",
|
||||
"line": 561,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0421",
|
||||
"section": "8-1-2 공사규모별 표준건설기계('04, '17, '25년 보완)",
|
||||
@@ -459,6 +473,20 @@
|
||||
"line": 272,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0447",
|
||||
"section": "8-2-6 모터 스크레이퍼Q = ⋅q⋅f⋅E cm여기서Q: 시간당 작업량(㎥/hr)q: 적재함용적×적재계수(k)f: 체적환산계수E: 작업효율cm : 1회 싸이클 시간",
|
||||
"pum_form": "productivity",
|
||||
"line": 440,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0449",
|
||||
"section": "8-2-6 모터 스크레이퍼Q = ⋅q⋅f⋅E cm여기서Q: 시간당 작업량(㎥/hr)q: 적재함용적×적재계수(k)f: 체적환산계수E: 작업효율cm : 1회 싸이클 시간",
|
||||
"pum_form": "productivity",
|
||||
"line": 479,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0450",
|
||||
"section": "8-2-6 모터 스크레이퍼Q = ⋅q⋅f⋅E cm여기서Q: 시간당 작업량(㎥/hr)q: 적재함용적×적재계수(k)f: 체적환산계수E: 작업효율cm : 1회 싸이클 시간",
|
||||
@@ -480,6 +508,27 @@
|
||||
"line": 861,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0475",
|
||||
"section": "8-2-15 법면다짐기",
|
||||
"pum_form": "productivity",
|
||||
"line": 894,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0484",
|
||||
"section": "8-2-19 콘크리트 운반",
|
||||
"pum_form": "productivity",
|
||||
"line": 1006,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0491",
|
||||
"section": "8-2-19 콘크리트 운반",
|
||||
"pum_form": "productivity",
|
||||
"line": 1092,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0493",
|
||||
"section": "8-2-19 콘크리트 운반",
|
||||
@@ -1033,20 +1082,6 @@
|
||||
"line": 426,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0804",
|
||||
"section": "1-8-2 도로 표지판 설치('08년 신설, '20년 보완)(일당)",
|
||||
"pum_form": "requirement",
|
||||
"line": 606,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0855",
|
||||
"section": "3-2-5 터널굴착 1발파당 작업인원('07, '20년 보완)(1발파당)",
|
||||
"pum_form": "requirement",
|
||||
"line": 149,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0856",
|
||||
"section": "3-2-5 터널굴착 1발파당 작업인원('07, '20년 보완)(1발파당)",
|
||||
@@ -1110,13 +1145,6 @@
|
||||
"line": 168,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0979",
|
||||
"section": "7-4-3 배송관 진수(set당)",
|
||||
"pum_form": "requirement",
|
||||
"line": 303,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C0980",
|
||||
"section": "7-4-3 배송관 진수(set당)",
|
||||
@@ -1544,6 +1572,13 @@
|
||||
"line": 1844,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1128",
|
||||
"section": "9-5-4 수치지도 작성('21, '22, '24, '26년 보완)",
|
||||
"pum_form": "productivity",
|
||||
"line": 1851,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1131",
|
||||
"section": "9-5-4 수치지도 작성('21, '22, '24, '26년 보완)",
|
||||
@@ -1558,6 +1593,13 @@
|
||||
"line": 1937,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1138",
|
||||
"section": "9-5-4 수치지도 작성('21, '22, '24, '26년 보완)",
|
||||
"pum_form": "productivity",
|
||||
"line": 1952,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1139",
|
||||
"section": "9-5-4/2. 수동입력'의 품을 적용한다.",
|
||||
@@ -1705,13 +1747,6 @@
|
||||
"line": 2889,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1233",
|
||||
"section": "9-5-4/2. 수동입력’을적용한다.",
|
||||
"pum_form": "requirement",
|
||||
"line": 2922,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1246",
|
||||
"section": "9-5-4 9. 수치표고모형구축’의 ‘가. 항공레이저측량에 의한 방법(레이저지형자료취득, 자료처리, 수치표고모형제작, 정리 및 점검)’ 공정에 한하여 적용한다.",
|
||||
@@ -1747,48 +1782,6 @@
|
||||
"line": 3171,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1260",
|
||||
"section": "9-5-6 지도제작(기본도)",
|
||||
"pum_form": "requirement",
|
||||
"line": 3191,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1263",
|
||||
"section": "9-5-6 지도제작(기본도)",
|
||||
"pum_form": "requirement",
|
||||
"line": 3216,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1266",
|
||||
"section": "9-5-6 지도제작(기본도)",
|
||||
"pum_form": "requirement",
|
||||
"line": 3245,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1267",
|
||||
"section": "9-5-6 지도제작(기본도)",
|
||||
"pum_form": "requirement",
|
||||
"line": 3253,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1270",
|
||||
"section": "9-5-7 토지이용 현황도 제작",
|
||||
"pum_form": "requirement",
|
||||
"line": 3283,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1272",
|
||||
"section": "9-5-7 토지이용 현황도 제작",
|
||||
"pum_form": "requirement",
|
||||
"line": 3300,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1274",
|
||||
"section": "9-5-9 정밀도로지도 구축('19년 신설, '20년 보완)",
|
||||
@@ -2132,6 +2125,13 @@
|
||||
"line": 4600,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1412",
|
||||
"section": "1-1 철골 가공 조립(공장생산)1-1-1 기본철골공수('08, '13년 보완)",
|
||||
"pum_form": "requirement",
|
||||
"line": 26,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1415",
|
||||
"section": "1-1-3 기본용접공수",
|
||||
@@ -2433,13 +2433,6 @@
|
||||
"line": 541,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1671",
|
||||
"section": "13-1-7 장거리 배관('93, '26년 보완)(Joint당)",
|
||||
"pum_form": "requirement",
|
||||
"line": 643,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1674",
|
||||
"section": "13-1-8 이중보온관 설치('26년 보완)",
|
||||
@@ -2468,41 +2461,6 @@
|
||||
"line": 1149,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1703",
|
||||
"section": "13-3 배관 및 기기보온13-3-1 pipe보온('04년 보완)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1288,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1704",
|
||||
"section": "13-3 배관 및 기기보온13-3-1 pipe보온('04년 보완)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1319,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1705",
|
||||
"section": "13-3 배관 및 기기보온13-3-1 pipe보온('04년 보완)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1345,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1706",
|
||||
"section": "13-3 배관 및 기기보온13-3-1 pipe보온('04년 보완)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1376,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1707",
|
||||
"section": "13-3 배관 및 기기보온13-3-1 pipe보온('04년 보완)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1402,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1720",
|
||||
"section": "13-4-3 STORAGE TANK",
|
||||
@@ -2552,13 +2510,6 @@
|
||||
"line": 1726,
|
||||
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1731",
|
||||
"section": "13-5-2 보일러 드럼 설치(대당)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1739,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C1732",
|
||||
"section": "13-5-2 보일러 드럼 설치(대당)",
|
||||
@@ -3063,13 +3014,6 @@
|
||||
"line": 162,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C2130",
|
||||
"section": "2-2-13 도상갱환('11년 신설)",
|
||||
"pum_form": "requirement",
|
||||
"line": 1088,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "C2268",
|
||||
"section": "3-1-5 석축 헐기(인력)('22년 보완)",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
"effective_date": "2026-01-01",
|
||||
"pum_edition": "2026-01-01",
|
||||
"toc_edition": "산림청고시제2025-82호",
|
||||
"generated_at": "2026-09-18T12:38:26+09:00",
|
||||
"generated_at": "2026-09-18T12:53:57+09:00",
|
||||
"dataset_version": {
|
||||
"dataset_id": "pum_forest",
|
||||
"effective_date": "2026-01-01",
|
||||
@@ -25,10 +25,10 @@
|
||||
"tables_attached": 453,
|
||||
"tables_orphan": 22,
|
||||
"form_undetermined": 0,
|
||||
"basis_found": 251,
|
||||
"basis_missing": 81,
|
||||
"basis_found": 253,
|
||||
"basis_missing": 79,
|
||||
"basis_absent_in_source": 71,
|
||||
"basis_unparsed": 10,
|
||||
"basis_unparsed": 8,
|
||||
"basis_grouped": 59,
|
||||
"axis_roles": {
|
||||
"general_provision": 78,
|
||||
@@ -21171,9 +21171,9 @@
|
||||
"source_line": 4541,
|
||||
"pum_form": "requirement",
|
||||
"form_basis": "직종 표기((인)·인부·공)",
|
||||
"basis_quantity": null,
|
||||
"basis_unit": null,
|
||||
"basis_source": null,
|
||||
"basis_quantity": 1.0,
|
||||
"basis_unit": "ha",
|
||||
"basis_source": "표 머리",
|
||||
"resource_shares": {},
|
||||
"partial_ratio": false,
|
||||
"expression_cells": [],
|
||||
@@ -21262,9 +21262,9 @@
|
||||
"source_line": 4561,
|
||||
"pum_form": "requirement",
|
||||
"form_basis": "직종 표기((인)·인부·공)",
|
||||
"basis_quantity": null,
|
||||
"basis_unit": null,
|
||||
"basis_source": null,
|
||||
"basis_quantity": 1.0,
|
||||
"basis_unit": "ha",
|
||||
"basis_source": "표 머리",
|
||||
"resource_shares": {},
|
||||
"partial_ratio": false,
|
||||
"expression_cells": [],
|
||||
|
||||
@@ -56,26 +56,6 @@
|
||||
"class": "㉰ 사용자 판단 필요",
|
||||
"class_why": "⚠ 마스터 「1km」는 반쪽 — 원문은 「인/1일 1km당」으로 분모가 둘(일·km)"
|
||||
},
|
||||
"F0228": {
|
||||
"section": "8-6-2",
|
||||
"md": [
|
||||
1.0,
|
||||
"ha"
|
||||
],
|
||||
"md_evidence": "표·머리 무인헬기 (ha당)",
|
||||
"master": null,
|
||||
"why": "원문 줄 칸 「무인헬기 (ha당)」 — 마스터가 아직 안 읽음(2026-09-09 「인」 오독 판정과 같은 자리, 밑수는 ha)"
|
||||
},
|
||||
"F0229": {
|
||||
"section": "8-6-2",
|
||||
"md": [
|
||||
1.0,
|
||||
"ha"
|
||||
],
|
||||
"md_evidence": "표·머리 멀티콥터 (ha당)",
|
||||
"master": null,
|
||||
"why": "위와 같음(멀티콥터)"
|
||||
},
|
||||
"F0322": {
|
||||
"section": "10-13-1",
|
||||
"md": null,
|
||||
|
||||
@@ -68,7 +68,7 @@ MASTER = OUT_DIR / "work_item_master_2026-01-01.json"
|
||||
#: 2026-09-18 합침(랩탑 메인 · 데스크탑 서브 9f27d619 와 한 점) — 위 넓힘 + 데스크탑 서브의
|
||||
#: F0046·F0068 밑수 되돌림·F0076 형태 판정·원천 벌 재추출을 한 벌로 다시 뽑아 지문이 또 뜸
|
||||
#: (옛 837eb8aa… · 옛 6f223c69…). 양쪽 다 **원문을 더 읽은 것**이고 금액은 그대로다.
|
||||
BASELINE_WORK_ITEMS_SHA = "645798a58bcd8d283653192d4da8b5be40e0b88474b8e8c3bbab77174b83eb7d"
|
||||
BASELINE_WORK_ITEMS_SHA = "7919a44eab4ecf9a09edb39f0c4b48f5576caa8c5d491fe6d3e5fb89ba655436"
|
||||
|
||||
#: 열쇠 작업이 새로 얹은 칸. 지문을 잴 때만 떼어낸다.
|
||||
ADDED_FIELDS = (
|
||||
@@ -482,14 +482,15 @@ def test_밑수_미확보를_둘로_가른다(master: dict) -> None:
|
||||
from pathlib import Path as _Path
|
||||
|
||||
stats = master["stats"]
|
||||
assert stats["basis_missing"] == 81
|
||||
assert stats["basis_missing"] == 79
|
||||
# 2026-09-18 합침 70 → 71 — 원문 md 가 풀리며 밑수를 안 적은 표가 하나 더 드러남
|
||||
assert stats["basis_absent_in_source"] == 71
|
||||
# 2026-09-18 「당」 없이 몫으로만 적힌 자리(「(인/100㎡)」·「(대/ton)」)를 가리게 해 다섯을 더 채움.
|
||||
# 미판독 12 → 9 → 10(가림이 넓어져 새로 드러난 것 포함) · 확보 243 → 251.
|
||||
# ⚠ 남은 아홉은 **거절 자리**다 — 「(단위 : 인)」 셋(2026-09-09 오독 판정) ·
|
||||
# 「㎥/1인/1일」·「1ha당, 100본당」·「1대 1조, 시간당」·「인 당」은 분모가 둘 이상이다.
|
||||
assert stats["basis_unparsed"] == 10
|
||||
# 2026-09-18 10 → 8 — **표 머리 칸까지 읽게 하자** 8-6-2·8-6-3 드론방제 「ha당」 둘이 채워짐
|
||||
assert stats["basis_unparsed"] == 8
|
||||
assert stats["basis_absent_in_source"] + stats["basis_unparsed"] == stats["basis_missing"]
|
||||
items = _json.loads(
|
||||
_Path("resources/data_work_item_master/basis_missing_2026-01-01.json").read_text(
|
||||
|
||||
Reference in New Issue
Block a user