feat(b08): 두 단 머리를 이어 읽어 미판정 196 → 175 · 밑수 미판독 75 → 2(나머지는 거절 자리)
브레인 일감(2026-09-18 둘째 바퀴). 잣대는 원문 ↔ 마스터 어긋남 건수.
- **머리 두 단을 이어 본다**(`judged_const_form` ⑯) — ⚠ 평탄화가 아니라 **위 단을 그대로 두고
아래 단을 머리에 더해** 한 번만 다시 봄. 21 표가 갈림(직종 18 · 공식 기호 3)
- 못 가린 175 는 갈래를 다시 나눔 — 머리 두 단·값 있음 81 · 값은 있는데 표지 없음 82 ·
머리가 구간 6 · **원문이 품을 안 적음 6(할 일 아님)**
- 밑수 미확보 사유를 셋으로 가름(`_basis_missing_why`)
· **원문 부재**(채울 것 아님) 364 · **거절 자리** 72 · **미판독**(진짜 할 일) 2
· ⚠ 거절 자리 = 원문이 적은 것이 값의 단위인 자리 — 「회당」(2026-09-17 판정) ·
「(인/일)」·「(㎥/hr)」·「(ℓ/hr)」는 「하루에 몇 인」이라는 뜻이지 표의 밑수가 아님 ·
밑수가 둘인 자리(「1ha당, 100본당」)도 여기
· 산림도 같은 눈으로 — 미판독 10 → 1(F0237 「1대 1조, 시간당」만 사람 판정)
- 밑수 단위에 JOINT·호 더함 · 작업조 표는 「밑수가 표 밖(시공량)」으로 따로 적음
- 셈 — 건설 미판정 196 → 175 · 건설 밑수 확보 711 → 713 · 산림 미판정 0 · 산림 밑수 미확보 79 그대로
(속가름: 원문 부재 70 → 78 · 미판독 8 → 1)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -77,7 +77,23 @@ def _has_number(cells: list[str]) -> bool:
|
||||
return any(_NUMBERS_RE.match(_squeeze(c)) for c in cells if _squeeze(c))
|
||||
|
||||
|
||||
def judged_const_form(table: dict[str, Any]) -> tuple[str, str] | None:
|
||||
def _sub_header_row(table: dict[str, Any]) -> list[str] | None:
|
||||
"""머리가 두 단인 표의 **아래 단**. 아니면 `None`.
|
||||
|
||||
아래 단은 이름줄이라 **수가 없다**(`구분 | 점질토 | 사질토`). 첫 줄에 값이 있으면 자료 줄이다.
|
||||
"""
|
||||
rows = table.get("rows") or []
|
||||
if not rows:
|
||||
return None
|
||||
first = [_squeeze(c) for c in rows[0]]
|
||||
if sum(1 for c in first if c) < 2:
|
||||
return None
|
||||
if any(_NUMBERS_RE.match(c) for c in first if c):
|
||||
return None
|
||||
return [c for c in first if c]
|
||||
|
||||
|
||||
def judged_const_form(table: dict[str, Any], _twice: bool = False) -> tuple[str, str] | None:
|
||||
"""건설 꼴로 본 `(형태, 까닭)`. 못 가리면 `None` — 미판정으로 남김.
|
||||
|
||||
차례가 뜻을 가진다 — 좁은 표지부터. 계수·기준표를 먼저 걸러야 직종 낱말이 계수표를 품으로 오인하지 않는다.
|
||||
@@ -162,6 +178,17 @@ def judged_const_form(table: dict[str, Any]) -> tuple[str, str] | None:
|
||||
if sum(1 for h in headers if _COMPACT_RE.search(h)) >= 2:
|
||||
return "reference", "다짐 두께·횟수 기준표 — 시방 기준"
|
||||
|
||||
# ⑯ 머리가 두 단인 표 — **위 단을 버리지 않고 아래 단을 머리에 더해** 한 번 더 본다.
|
||||
# ⚠ 평탄화가 아니다(위 단에 밑수·갈래가 든다) · 한 번만 되본다(두 단이 셋이 되진 않는다).
|
||||
if not _twice and (sub := _sub_header_row(table)):
|
||||
merged = {
|
||||
**table,
|
||||
"headers": [*(table.get("headers") or []), *sub],
|
||||
"rows": (table.get("rows") or [])[1:],
|
||||
}
|
||||
if hit := judged_const_form(merged, True):
|
||||
return hit[0], f"머리 두 단을 이어 보니 — {hit[1]}"
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -191,12 +218,12 @@ def const_undetermined_kind(table: dict[str, Any]) -> str:
|
||||
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 "머리가 구간 — 조건으로 갈리는 표"
|
||||
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 "그 밖 — 사람이 봐야 함"
|
||||
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 "머리가 구간 · 값 있음 — 조건으로 갈리는 표"
|
||||
return "값은 있는데 표지가 없음 — 사람이 봐야 함"
|
||||
|
||||
@@ -227,7 +227,7 @@ SOURCE_BASIS_RATIO_RE = re.compile(
|
||||
#: ⚠ 「단위당」은 안 넣는다 — 무엇의 단위인지 원문이 안 적었다.
|
||||
_BASIS_UNIT = (
|
||||
"공㎥|㎥|m3|㎡|m2|㏊|ha|㎞|km|m|매|본|개소|개|인|공|kg|㎏|톤|ton|주|식|대|일|기|조|명|틀"
|
||||
"|층|set|SET|Joint|joint|발파|구멍|孔|㎢|km2|도엽|ea|EA"
|
||||
"|층|set|SET|Joint|joint|JOINT|발파|구멍|孔|㎢|km2|도엽|ea|EA|호"
|
||||
)
|
||||
#: ⚠ **괄호 앞뒤에 글이 붙은 건설 꼴**도 읽는다 — `(용접개소당)` · `(세면기 개당)` · `(절단길이 10m당)` ·
|
||||
#: `(m당 : 관길이기준)`. 산림은 괄호 안이 밑수뿐이라 이 넓히기로 값이 달라지지 않는다.
|
||||
@@ -285,29 +285,31 @@ _DECLARES_RE = re.compile(
|
||||
DECLARE_LOOK = 6
|
||||
|
||||
|
||||
def source_declares_basis(lines: list[str], line_no: int, table: dict[str, Any]) -> bool:
|
||||
"""원문이 이 표에 **밑수 같은 글을 적어 두었나** — 적었으면 참.
|
||||
def source_declares_basis(lines: list[str], line_no: int, table: dict[str, Any]) -> str | None:
|
||||
"""원문이 이 표에 **밑수 같은 글을 적어 두었나** — 적었으면 그 글, 아니면 `None`.
|
||||
|
||||
왜 가리나 — 밑수 미확보 88 중 **76 은 원문에 밑수가 아예 없는 것**이고(채우면 지어내는 꼴),
|
||||
**12 만 원문에 적혀 있는데 우리가 못 읽은 것**이다(2026-09-18 안티그래비티 3바퀴).
|
||||
그 둘을 목록에서 갈라 두면 다음 바퀴에 76 이 또 「할 일」로 세어지지 않는다.
|
||||
⚠ 목록만 가른다 — **여기서 값을 채우지 않는다.**
|
||||
"""
|
||||
if any(_DECLARES_RE.search(norm(h)) for h in table.get("headers") or []):
|
||||
return True
|
||||
for head in table.get("headers") or []:
|
||||
if m := _DECLARES_RE.search(norm(head)):
|
||||
return m.group(0)
|
||||
for row in (table.get("rows") or [])[:2]:
|
||||
if any(_DECLARES_RE.search(norm(c)) for c in row):
|
||||
return True
|
||||
for cell in row:
|
||||
if m := _DECLARES_RE.search(norm(cell)):
|
||||
return m.group(0)
|
||||
if not lines or line_no <= 0:
|
||||
return False
|
||||
return None
|
||||
start = max(0, line_no - 1 - DECLARE_LOOK)
|
||||
for index in range(line_no - 2, start - 1, -1):
|
||||
text = lines[index].strip() if 0 <= index < len(lines) else ""
|
||||
if text.startswith("|"):
|
||||
break # 앞 표에 닿았다
|
||||
if _DECLARES_RE.search(text):
|
||||
return True
|
||||
return False
|
||||
if m := _DECLARES_RE.search(text):
|
||||
return m.group(0)
|
||||
return None
|
||||
|
||||
|
||||
def basis_from_source(lines: list[str], line_no: int) -> tuple[float | None, str | None]:
|
||||
@@ -722,6 +724,26 @@ def new_report() -> dict[str, Any]:
|
||||
return {"basis_found": 0, "basis_grouped": 0, "basis_missing": [], "undetermined": []}
|
||||
|
||||
|
||||
#: 밑수로 안 받기로 한 단위 — 원문이 적었어도 **채울 것이 아니다**.
|
||||
#: 「회」 2026-09-17 데스크탑 서브 판정(10-4 중기운반) · 「인」 2026-09-09 오독 판정(사람 수는 밑수가 아님).
|
||||
#: ⚠ **빗금 단위는 값의 단위이지 밑수가 아니다** — `(인/일)`·`(㎥/hr)` 는 「하루에 몇 인」·
|
||||
#: 「한 시간에 몇 ㎥」라는 뜻이라 표의 밑수가 아니다(2026-09-18 건설 미판독 39 를 갈라 보니 이 꼴).
|
||||
_REJECTED_BASIS_RE = re.compile(r"회\s*당|단위\s*[::]?\s*인|인\s*당|/|단위\s*당")
|
||||
|
||||
|
||||
def _basis_missing_why(table: dict[str, Any], source_lines: list[str]) -> str:
|
||||
"""밑수를 못 채운 까닭. ⚠ **채울 것(미판독)과 아닌 것(원문 부재)** 을 가른다."""
|
||||
# 작업조 표는 하루 편성만 적고 시공량이 표 밖에 있다 — 표에서 채울 것이 아니다.
|
||||
if crew_table(table):
|
||||
return "원문 부재 — 작업조 표(하루 편성) · 밑수는 표 밖의 시공량"
|
||||
mark = source_declares_basis(source_lines, int(table.get("line") or 0), table)
|
||||
if mark is None:
|
||||
return "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
if _REJECTED_BASIS_RE.search(norm(mark)) or len(_BASIS_TOKEN_RE.findall(norm(mark))) > 1:
|
||||
return f"원문 부재 — 거절 자리: 원문이 적은 것이 '{norm(mark)[:20]}' 라 밑수로 안 받음"
|
||||
return f"미판독 — 원문이 '{norm(mark)[:24]}' 라고 적었는데 우리가 못 읽음"
|
||||
|
||||
|
||||
def table_entry(
|
||||
table: dict[str, Any],
|
||||
section: str,
|
||||
@@ -804,14 +826,7 @@ def table_entry(
|
||||
# ⚠ **작업조 표는 밑수가 애초에 표 밖이다** — 하루 편성 인원·장비를 적고
|
||||
# 시공량은 [주]·다른 표에 있다. 「미판독」으로 세면 없는 할 일이 생긴다
|
||||
# (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 "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
|
||||
),
|
||||
"why": absent or _basis_missing_why(table, source_lines),
|
||||
}
|
||||
)
|
||||
shares = resource_shares(table)
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "mach_base",
|
||||
"effective_date": "2026-01-01",
|
||||
"generated_at": "2026-09-18T10:45:29+09:00",
|
||||
"generated_at": "2026-09-18T13:19:25+09:00",
|
||||
"sources": [
|
||||
{
|
||||
"path": "resources/knowledge/original/원가계산/건설공사_표준품셈/01_공통부문/제8장_건설기계.md",
|
||||
"sha256": "0741b48d0c2dff638d33e6086cae292def015c9db1c7f4bb687befdde87a8e31",
|
||||
"sha256": "b820290a56d7ebeed9bcdbb8128ccf6ecbaf5de6cc395b2efd8c75a4e99dbc72",
|
||||
"role": "primary"
|
||||
}
|
||||
],
|
||||
@@ -15105,7 +15105,7 @@
|
||||
"source_tables": [
|
||||
{
|
||||
"section": "8-4 운전경비 산정('08, '09, '10, '11, '12, '13, '14, '15, '16, '17년 보완)8-4-1 [00]토공기계",
|
||||
"line": 3729,
|
||||
"line": 3735,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -15367,7 +15367,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4 운전경비 산정('08, '09, '10, '11, '12, '13, '14, '15, '16, '17년 보완)8-4-1 [00]토공기계",
|
||||
"line": 3765,
|
||||
"line": 3771,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -15597,7 +15597,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-2 [10]다짐기계",
|
||||
"line": 3797,
|
||||
"line": 3803,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -15867,7 +15867,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-3 [20]운반 및 하역기계('21년 보완)",
|
||||
"line": 3834,
|
||||
"line": 3840,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -16089,7 +16089,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-3 [20]운반 및 하역기계('21년 보완)",
|
||||
"line": 3865,
|
||||
"line": 3871,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -16415,7 +16415,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-4 [30]포장기계",
|
||||
"line": 3909,
|
||||
"line": 3915,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -16645,7 +16645,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-5 [40]콘크리트기계",
|
||||
"line": 3941,
|
||||
"line": 3947,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -16699,7 +16699,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-5 [40]콘크리트기계",
|
||||
"line": 3951,
|
||||
"line": 3957,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -16881,7 +16881,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-6 [50]골재생산기계 등",
|
||||
"line": 3977,
|
||||
"line": 3983,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -16983,7 +16983,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-6 [50]골재생산기계 등",
|
||||
"line": 3993,
|
||||
"line": 3999,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -17069,7 +17069,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-7 [60]기초공사용 기계('21년 보완)",
|
||||
"line": 4007,
|
||||
"line": 4013,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -17251,7 +17251,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-8 [70]기타기계('24년 보완)",
|
||||
"line": 4033,
|
||||
"line": 4039,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -17553,7 +17553,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-8 [70]기타기계('24년 보완)",
|
||||
"line": 4074,
|
||||
"line": 4080,
|
||||
"headers": [
|
||||
"분류번호",
|
||||
"기계명",
|
||||
@@ -17711,7 +17711,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4105,
|
||||
"line": 4111,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -17879,7 +17879,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4118,
|
||||
"line": 4124,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -18020,7 +18020,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4131,
|
||||
"line": 4137,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -18110,7 +18110,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4141,
|
||||
"line": 4147,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -18186,7 +18186,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4152,
|
||||
"line": 4158,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -18258,7 +18258,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4162,
|
||||
"line": 4168,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -18306,7 +18306,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4172,
|
||||
"line": 4178,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
@@ -18480,7 +18480,7 @@
|
||||
},
|
||||
{
|
||||
"section": "8-4-9 [90]해상기계(9010) 펌프준설선 ('10, '11년 보완)",
|
||||
"line": 4184,
|
||||
"line": 4190,
|
||||
"headers": [
|
||||
"명 칭",
|
||||
"단위",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2114,7 +2114,7 @@
|
||||
"name_ko": "건설품셈 표",
|
||||
"summary": "표 하나가 한 줄. 머리와 줄을 원문 그대로 담는다.",
|
||||
"shape": "list",
|
||||
"rows": 2272,
|
||||
"rows": 2273,
|
||||
"columns": [
|
||||
{
|
||||
"key": "table_id",
|
||||
@@ -7267,7 +7267,7 @@
|
||||
"name_ko": "형태 미판정 표",
|
||||
"summary": "생산량형인지 소요량형인지 못 정한 표.",
|
||||
"shape": "list",
|
||||
"rows": 196,
|
||||
"rows": 175,
|
||||
"columns": [
|
||||
{
|
||||
"key": "pum_table_id",
|
||||
@@ -7323,7 +7323,7 @@
|
||||
"name_ko": "밑수 미확보 표",
|
||||
"summary": "기준 수량을 못 찾은 표.",
|
||||
"shape": "list",
|
||||
"rows": 431,
|
||||
"rows": 438,
|
||||
"columns": [
|
||||
{
|
||||
"key": "pum_table_id",
|
||||
@@ -7552,7 +7552,7 @@
|
||||
"name_ko": "갈래 열쇠 장부",
|
||||
"summary": "공종 열쇠 아래 갈래마다 번호를 매긴 것. 사라진 갈래의 번호는 다시 쓰지 않는다.",
|
||||
"shape": "map",
|
||||
"rows": 207,
|
||||
"rows": 208,
|
||||
"columns": [
|
||||
{
|
||||
"key": "@key",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "data_work_item_master_manifest",
|
||||
"generated_at": "2026-09-18T12:53:57+09:00",
|
||||
"generated_at": "2026-09-18T13:27:21+09:00",
|
||||
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
|
||||
"source": {
|
||||
"dataset_id": "pum_forest",
|
||||
@@ -12,7 +12,7 @@
|
||||
"files": [
|
||||
{
|
||||
"file": "work_item_master_2026-01-01.json",
|
||||
"sha256": "41a9ebd574ed425ca9cc180f3b9b5cbc3fa603d3e9a94e4731f2db275fb101fe",
|
||||
"sha256": "170b13a97e07bec53f1ba361a8b89664b3c1d0330598ca69ae88debe94d3825b",
|
||||
"size_bytes": 1095122
|
||||
},
|
||||
{
|
||||
@@ -22,8 +22,8 @@
|
||||
},
|
||||
{
|
||||
"file": "basis_missing_2026-01-01.json",
|
||||
"sha256": "57c58458ef2a95aa67a5dd2e15989f2613c628e7c697c84d4a944349fa102422",
|
||||
"size_bytes": 18434
|
||||
"sha256": "3ef647276c8b93c5f1532ef8d6c0e83f6d8154dbd392c06fc71d148b0ad65d78",
|
||||
"size_bytes": 18788
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "data_work_item_master_manifest",
|
||||
"generated_at": "2026-09-18T12:54:47+09:00",
|
||||
"generated_at": "2026-09-18T13:28:12+09:00",
|
||||
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
|
||||
"source": {
|
||||
"dataset_id": "pum_const",
|
||||
"effective_date": "2026-01-01",
|
||||
"sha256": "b8c85e6ab5b242d5d82a42ff761ec4e144309a1389bc267ea2f1ceabc3d4b8f1",
|
||||
"sha256": "df4de0d8194bc0f30b4078dbfd4b50d3c59d38ee53225e0d8eb056e7b0da9f55",
|
||||
"file": "pum_const_2026.json"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"file": "const_work_item_master_2026-01-01.json",
|
||||
"sha256": "a3862986f252c2c395d765a879cd2e60899f011559268d27539bb051930738d1",
|
||||
"size_bytes": 4712576
|
||||
"sha256": "f2e53cf68ea6d051d02aefea798d9da380d893a99b6502885bba3678b5c68616",
|
||||
"size_bytes": 4718431
|
||||
},
|
||||
{
|
||||
"file": "const_form_undetermined_2026-01-01.json",
|
||||
"sha256": "b1b4619532c561bb17e53881e5732548a0f8e666dee7f841d9507f1ba760dddf",
|
||||
"size_bytes": 115516
|
||||
"sha256": "16745ba1e2da669dc43febb2dcbc4c52acce7c146debb1ad72dd5cb6216ca81d",
|
||||
"size_bytes": 104333
|
||||
},
|
||||
{
|
||||
"file": "const_basis_missing_2026-01-01.json",
|
||||
"sha256": "bdc0720276122659f931f7144cce751aa18ea09d706ca7eb34a438b5e969bf7e",
|
||||
"size_bytes": 110609
|
||||
"sha256": "03854c4fa9421f70f0decb6c0d89a58b0f21be34616de81e54720cf049013bcb",
|
||||
"size_bytes": 115094
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -58,14 +58,14 @@
|
||||
"section": "4-1-1. 임업용 동력기계톱",
|
||||
"pum_form": "productivity",
|
||||
"line": 1932,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(단위 : ㎥/1인/1일)' 라 밑수로 안 받음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0084",
|
||||
"section": "4-1-2. 하베스터(부착형 스트로크)",
|
||||
"pum_form": "productivity",
|
||||
"line": 1950,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(단위 : ㎥/1인/1일)' 라 밑수로 안 받음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0085",
|
||||
@@ -114,7 +114,7 @@
|
||||
"section": "6-2-1. 둘레베기",
|
||||
"pum_form": "requirement",
|
||||
"line": 3099,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(1ha당, 100본당)' 라 밑수로 안 받음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0155",
|
||||
@@ -415,14 +415,14 @@
|
||||
"section": "8-3. 소각, 매몰, 훈증, 박피",
|
||||
"pum_form": "productivity",
|
||||
"line": 4373,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(㎥/인)' 라 밑수로 안 받음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0230",
|
||||
"section": "8-6-3. 지상방제",
|
||||
"pum_form": "requirement",
|
||||
"line": 4582,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(단위 : 인)' 라 밑수로 안 받음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0232",
|
||||
@@ -443,7 +443,7 @@
|
||||
"section": "8-11. 이동식 임목 파쇄",
|
||||
"pum_form": "productivity",
|
||||
"line": 4674,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "미판독 — 원문이 '(단위 : 1대 1조, 시간당)' 라고 적었는데 우리가 못 읽음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0238",
|
||||
@@ -527,7 +527,7 @@
|
||||
"section": "13-2-4. 야면석 채집(인력)",
|
||||
"pum_form": "requirement",
|
||||
"line": 7079,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(단위: 인 당)' 라 밑수로 안 받음"
|
||||
},
|
||||
{
|
||||
"pum_table_id": "F0405",
|
||||
@@ -555,7 +555,7 @@
|
||||
"section": "13-15-2. 목책 설치",
|
||||
"pum_form": "requirement",
|
||||
"line": 7868,
|
||||
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
|
||||
"why": "원문 부재 — 거절 자리: 원문이 적은 것이 '(단위: 인/조)' 라 밑수로 안 받음"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -12928,6 +12928,12 @@
|
||||
"3시간차단": "01",
|
||||
"4시간차단": "02"
|
||||
}
|
||||
},
|
||||
"CW-00370": {
|
||||
"next_serial": 2,
|
||||
"slots": {
|
||||
"㎾": "01"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"effective_date": "2026-01-01",
|
||||
"pum_edition": "2026-01-01",
|
||||
"toc_edition": "산림청고시제2025-82호",
|
||||
"generated_at": "2026-09-18T12:53:57+09:00",
|
||||
"generated_at": "2026-09-18T13:27:21+09:00",
|
||||
"dataset_version": {
|
||||
"dataset_id": "pum_forest",
|
||||
"effective_date": "2026-01-01",
|
||||
@@ -27,8 +27,8 @@
|
||||
"form_undetermined": 0,
|
||||
"basis_found": 253,
|
||||
"basis_missing": 79,
|
||||
"basis_absent_in_source": 71,
|
||||
"basis_unparsed": 8,
|
||||
"basis_absent_in_source": 78,
|
||||
"basis_unparsed": 1,
|
||||
"basis_grouped": 59,
|
||||
"axis_roles": {
|
||||
"general_provision": 78,
|
||||
|
||||
@@ -483,14 +483,17 @@ def test_밑수_미확보를_둘로_가른다(master: dict) -> None:
|
||||
|
||||
stats = master["stats"]
|
||||
assert stats["basis_missing"] == 79
|
||||
# 2026-09-18 합침 70 → 71 — 원문 md 가 풀리며 밑수를 안 적은 표가 하나 더 드러남
|
||||
assert stats["basis_absent_in_source"] == 71
|
||||
# 2026-09-18 합침 70 → 71 → 78 — **거절 자리를 「채울 것 아님」 쪽으로 옮겼다.**
|
||||
# 원문이 적은 것이 「(인/일)」·「㎥/hr」·「회당」이면 그것은 값의 단위이지 밑수가 아니다.
|
||||
assert stats["basis_absent_in_source"] == 78
|
||||
# 2026-09-18 「당」 없이 몫으로만 적힌 자리(「(인/100㎡)」·「(대/ton)」)를 가리게 해 다섯을 더 채움.
|
||||
# 미판독 12 → 9 → 10(가림이 넓어져 새로 드러난 것 포함) · 확보 243 → 251.
|
||||
# ⚠ 남은 아홉은 **거절 자리**다 — 「(단위 : 인)」 셋(2026-09-09 오독 판정) ·
|
||||
# 「㎥/1인/1일」·「1ha당, 100본당」·「1대 1조, 시간당」·「인 당」은 분모가 둘 이상이다.
|
||||
# 2026-09-18 10 → 8 — **표 머리 칸까지 읽게 하자** 8-6-2·8-6-3 드론방제 「ha당」 둘이 채워짐
|
||||
assert stats["basis_unparsed"] == 8
|
||||
# 2026-09-18 8 → 1 — 거절 자리(빗금 단위·회당·밑수 둘)를 갈라내니 **진짜 할 일은 하나**다
|
||||
# (F0237 「1대 1조, 시간당」 — 무엇이 밑수인지 사람이 봐야 함).
|
||||
assert stats["basis_unparsed"] == 1
|
||||
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(
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_표는_다_붙고_못_붙인_표는_목록(built: tuple) -> None:
|
||||
# 2026-09-18 2,192 → 2,202 — 코덱스가 제8장 손료표 열(C2193~C2202)을 되살림
|
||||
# 2026-09-18 합침 2,202 → 2,270 → 2,272 — 랩탑 서브·안티그래비티·코덱스가 원문 md 의
|
||||
# 뭉친 줄·표를 잇달아 풂(8-2 시공능력 · 8-4-9 해상기계 …)
|
||||
assert stats["tables_total"] == 2272
|
||||
assert stats["tables_total"] == 2273
|
||||
assert stats["tables_attached"] + len(master["orphan_tables"]) == stats["tables_total"]
|
||||
assert stats["tables_orphan"] == len(master["orphan_tables"]) == 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user