feat(b08): 밑수 미확보를 「원문 부재 75」와 「미판독 12」로 가름 · 강관비계 공㎥당 채움

브레인 판정(안티그래비티 3바퀴 — 96 → 실질 43). **미확보 88 중 76 은 고칠 것이 아님** —
원문에 밑수가 아예 없는 것이라 채우면 없는 값을 지어내는 꼴.

- 미확보 줄마다 `why` 를 붙여 **자동으로 가름** — 표 머리·첫 줄·표 위 여섯 줄에 「…당」·「단위」가
  적힌 괄호가 있으면 「미판독」, 없으면 「원문 부재」. ⚠ 목록만 가르고 **값은 안 채움**
  ⇒ 산림 87 = **원문 부재 75 + 미판독 12** · 건설 439 = 원문 부재 308 + 미판독 131
  ⇒ 다음 바퀴에 75 가 또 「할 일」로 세어지지 않음(집계에도 `basis_absent_in_source`·`basis_unparsed`)
- 미판독 가운데 **F0366 강관비계**만 채움 — 원문 L6634 「(단위: 공㎥당)」.
  「공㎥」(공간체적)가 자동 판정 단위 목록에 없어 못 읽던 자리. ⚠ 목록을 넓히면 규격 칸이
  밑수로 둔갑하므로 그 표만 사람 판정으로 둠 ⇒ 확보 242 → 243
- ⚠ 안티그래비티가 채울 수 있다 한 넷(F0251·F0304·F0362·F0379)은 **원문을 열어 보니 단위줄이
  없음** — 채우지 않고 사유로 남김(억지로 채우면 지어내는 꼴)
- 이름표에 `why` 칸 · 지문·줄 수 갱신

⚠ 건설 기계 쪽은 코덱스의 8-4 행 병합 복원을 기다려 한 번에 — 지금 손대지 않음

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsGw1Dz9HmhuAxGisxmDPF
This commit is contained in:
2026-09-18 03:22:49 +09:00
co-authored by Claude Opus 5
parent 37230ff6ed
commit c3592b250c
12 changed files with 1164 additions and 561 deletions
@@ -355,6 +355,15 @@ def finish(
"form_undetermined": len(report["undetermined"]),
"basis_found": report["basis_found"],
"basis_missing": len(report["basis_missing"]),
# ⚠ 미확보를 둘로 가른다 — 「원문 부재」는 채울 것이 아니고 「미판독」만 할 일이다.
"basis_absent_in_source": sum(
1
for i in report["basis_missing"]
if str(i.get("why", "")).startswith("원문 부재")
),
"basis_unparsed": sum(
1 for i in report["basis_missing"] if str(i.get("why", "")).startswith("미판독")
),
"basis_grouped": report["basis_grouped"],
# 줄의 구실 — 공종(`work_item`) · 묶는 마디(`group`) · 총칙(`general_provision`) ·
# 표도 아래도 없는 잎(`empty`). 화면·조합은 공종 축만 보면 된다.
@@ -273,6 +273,9 @@ BASIS_JUDGMENTS: dict[str, tuple[str, float, str, str]] = {
# ⚠ **왜곡 고침 하나** — 값이 아니라 **밑수 단위**가 틀려 있던 자리.
# 원문 L7489 가 「(단위: 1일당)」인데 마스터가 「개」로 서 있었다(13-10-2 윈치말뚝 박기).
"F0430": ("13-10-2", 1.0, "", "왜곡 고침 — 원문 「(단위: 1일당)」인데 「개」로 서 있었음"),
# ⚠ 「공㎥」(공간체적)는 자동 판정의 단위 목록에 없어 못 읽던 자리 — 원문 L6634 「(단위: 공㎥당)」.
# 단위 목록을 넓히면 규격 칸이 밑수로 둔갑하므로, 이 표만 사람 판정으로 둔다(2026-09-18).
"F0366": ("12-19", 1.0, "공㎥", "강관비계 — 원문 「(단위: 공㎥당)」"),
}
@@ -243,6 +243,37 @@ def person_basis_ok(raw_quantity: str | None, unit: str | None) -> bool:
return bool((raw_quantity or "").strip())
#: 원문이 **밑수 같은 글을 아예 안 적었나**를 보는 표지. 괄호에 「당」이나 「단위」가 있으면 적은 것이다.
_DECLARES_RE = re.compile(r"[(][^)]*(?:당|단위)[^)]*[)]")
#: 표 위아래로 얼마나 볼 것인가. 머리글 줄도 함께 본다.
DECLARE_LOOK = 6
def source_declares_basis(lines: list[str], line_no: int, table: dict[str, Any]) -> bool:
"""원문이 이 표에 **밑수 같은 글을 적어 두었나** — 적었으면 참.
왜 가리나 — 밑수 미확보 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 row in (table.get("rows") or [])[:2]:
if any(_DECLARES_RE.search(norm(c)) for c in row):
return True
if not lines or line_no <= 0:
return False
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
def basis_from_source(lines: list[str], line_no: int) -> tuple[float | None, str | None]:
"""표 바로 위 본문에서 밑수를 읽는다. 못 찾으면 `(None, None)` — 1 로 단정하지 않는다.
@@ -703,6 +734,13 @@ def table_entry(
"section": norm(table.get("section")),
"pum_form": form,
"line": table.get("line"),
# ⚠ 「원문 부재」는 **채울 것이 아니다** — 없는 값을 지어내면 안 된다.
# 「미판독」만 진짜 할 일이다(2026-09-18 브레인 · 안티그래비티 3바퀴).
"why": (
"미판독 — 원문이 적었는데 우리가 못 읽음"
if source_declares_basis(source_lines, int(table.get("line") or 0), table)
else "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
),
}
)
shares = resource_shares(table)
@@ -1977,7 +1977,7 @@
"merged_columns": 178,
"files": 41,
"tables": 101,
"columns": 541,
"columns": 543,
"value_groups": 207,
"unknown": 0,
"value_groups_by_kind": {
@@ -6363,7 +6363,7 @@
"name_ko": "밑수 못 찾은 표",
"summary": "기준 수량을 못 읽은 품셈 표. 1 단위당으로 단정하면 곱셈이 틀린다.",
"shape": "list",
"rows": 88,
"rows": 87,
"columns": [
{
"key": "pum_table_id",
@@ -6388,6 +6388,12 @@
"name_ko": "원문 줄 번호",
"unit": "",
"visible": false
},
{
"key": "why",
"name_ko": "사유",
"unit": "",
"visible": true
}
]
}
@@ -7342,6 +7348,12 @@
"name_ko": "원문 줄 번호",
"unit": "",
"visible": false
},
{
"key": "why",
"name_ko": "사유",
"unit": "",
"visible": true
}
]
}
@@ -1,7 +1,7 @@
{
"schema_version": "1.0",
"dataset_id": "data_work_item_master_manifest",
"generated_at": "2026-09-18T02:18:51+09:00",
"generated_at": "2026-09-18T03:14:14+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": "0831920a5895a9bd804b7cce02308e15cb65ca5b570c6322b1d0690071b81530",
"size_bytes": 1081225
"sha256": "574ac7c0556ed514838bef6f592097b66217df008b72770a226210c600937509",
"size_bytes": 1081351
},
{
"file": "form_undetermined_2026-01-01.json",
@@ -22,8 +22,8 @@
},
{
"file": "basis_missing_2026-01-01.json",
"sha256": "ed79b3dbcc6df0c1b07d9dd9eb6fba2c4bcd4d99debf766922052791e3218243",
"size_bytes": 12229
"sha256": "63895255047e849f5d70a1ab6551839d551d9e09609a8b32d487cfdb53892bf9",
"size_bytes": 20017
}
]
}
@@ -1,7 +1,7 @@
{
"schema_version": "1.0",
"dataset_id": "data_work_item_master_manifest",
"generated_at": "2026-09-18T02:19:39+09:00",
"generated_at": "2026-09-18T03:15:03+09:00",
"built_by": "B08_Quantity/B08_Quantity_Build_WorkItemMaster.py",
"source": {
"dataset_id": "pum_const",
@@ -12,8 +12,8 @@
"files": [
{
"file": "const_work_item_master_2026-01-01.json",
"sha256": "865b096a2256c869e74742e075fc6a02eff191dfd3fdce7e76ec489ca5bd7e66",
"size_bytes": 4501243
"sha256": "6b9d3bde5af18ab00abb07f379b0700cca5ab75c52f21a366b287be09e3e9fe5",
"size_bytes": 4501303
},
{
"file": "const_form_undetermined_2026-01-01.json",
@@ -22,8 +22,8 @@
},
{
"file": "const_basis_missing_2026-01-01.json",
"sha256": "125bf1d2ee64cfd771cbe1c068e50a4623210f9969aec6ba1061323ef86624b8",
"size_bytes": 72968
"sha256": "ff9b91fd0a605c7268ef5e39d66f06f219b733a8ca1d79d5840af2e436a3642b",
"size_bytes": 111352
}
]
}
@@ -8,529 +8,610 @@
"pum_table_id": "F0042",
"section": "2-1-1. 휘발유․오일",
"pum_form": "requirement",
"line": 1305
"line": 1305,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0043",
"section": "2-1-1. 휘발유․오일",
"pum_form": "requirement",
"line": 1328
"line": 1328,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0050",
"section": "2-1-4. 페인트 및 마킹테이프",
"pum_form": "requirement",
"line": 1417
"line": 1417,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0052",
"section": "2-1-4. 페인트 및 마킹테이프",
"pum_form": "requirement",
"line": 1444
"line": 1444,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0057",
"section": "2-1-7. 소각, 매몰, 훈증, 박피",
"pum_form": "requirement",
"line": 1518
"line": 1518,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0061",
"section": "2-1-11. 지상 약제살포",
"pum_form": "requirement",
"line": 1570
"line": 1570,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0062",
"section": "2-1-12. 그물망 피복",
"pum_form": "requirement",
"line": 1579
"line": 1579,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0078",
"section": "3-4-3. 임산물 운반로 및 작업로 보수비 산정",
"pum_form": "requirement",
"line": 1815
"line": 1815,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0083",
"section": "4-1-1. 임업용 동력기계톱",
"pum_form": "productivity",
"line": 1929
"line": 1929,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0084",
"section": "4-1-2. 하베스터(부착형 스트로크)",
"pum_form": "productivity",
"line": 1947
"line": 1947,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0085",
"section": "4-1-2. 하베스터(부착형 스트로크)",
"pum_form": "requirement",
"line": 1957
"line": 1957,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0089",
"section": "4-4. 가지정리",
"pum_form": "requirement",
"line": 2041
"line": 2041,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0090",
"section": "4-5. 벌도 위험목 점검",
"pum_form": "requirement",
"line": 2052
"line": 2052,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0091",
"section": "4-6. 벌목부 작업안전 보조",
"pum_form": "requirement",
"line": 2062
"line": 2062,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0095",
"section": "5-1-3. 교목굴취(근원직경)",
"pum_form": "requirement",
"line": 2156
"line": 2156,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0097",
"section": "5-1-5. 떼운반 적재 기준표",
"pum_form": "requirement",
"line": 2177
"line": 2177,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0108",
"section": "5-3-5. 교목식재(흉고직경)",
"pum_form": "requirement",
"line": 2355
"line": 2355,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0117",
"section": "5-12. 떼붙임(재배잔디)",
"pum_form": "requirement",
"line": 2496
"line": 2496,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0127",
"section": "5-19-2. 표토펴기 및 고르기",
"pum_form": "requirement",
"line": 2668
"line": 2668,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0129",
"section": "5-21. 표토이식",
"pum_form": "requirement",
"line": 2693
"line": 2693,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0154",
"section": "6-2-1. 둘레베기",
"pum_form": "requirement",
"line": 3095
"line": 3095,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0155",
"section": "6-2-2. 줄베기",
"pum_form": "requirement",
"line": 3105
"line": 3105,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0156",
"section": "6-2-3. 모두베기",
"pum_form": "requirement",
"line": 3121
"line": 3121,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0157",
"section": "6-3. 맹아제거",
"pum_form": "requirement",
"line": 3138
"line": 3138,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0158",
"section": "6-4-1. 덩굴걷기",
"pum_form": "requirement",
"line": 3159
"line": 3159,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0159",
"section": "6-4-2. 덩굴 약제 살포처리",
"pum_form": "requirement",
"line": 3169
"line": 3169,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0160",
"section": "6-4-3. 소금처리",
"pum_form": "requirement",
"line": 3180
"line": 3180,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0161",
"section": "6-4-4. 뿌리제거",
"pum_form": "requirement",
"line": 3199
"line": 3199,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0163",
"section": "6-5. 어린나무 가꾸기",
"pum_form": "requirement",
"line": 3260
"line": 3260,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0169",
"section": "7-1-1. 수확",
"pum_form": "productivity",
"line": 3377
"line": 3377,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0170",
"section": "7-1-1. 수확",
"pum_form": "requirement",
"line": 3387
"line": 3387,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0171",
"section": "7-1-1. 수확",
"pum_form": "requirement",
"line": 3397
"line": 3397,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0172",
"section": "7-1-2. 숲가꾸기, 병해충방제",
"pum_form": "requirement",
"line": 3411
"line": 3411,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0174",
"section": "7-3. 아키야윈치(임업용 윈치) 집재",
"pum_form": "requirement",
"line": 3455
"line": 3455,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0175",
"section": "7-4-1. 수확",
"pum_form": "requirement",
"line": 3468
"line": 3468,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0176",
"section": "7-4-2. 숲가꾸기, 산림병해충방제",
"pum_form": "requirement",
"line": 3492
"line": 3492,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0177",
"section": "7-5-1. 수확",
"pum_form": "requirement",
"line": 3512
"line": 3512,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0178",
"section": "7-5-2. 숲가꾸기, 병해충방제",
"pum_form": "requirement",
"line": 3535
"line": 3535,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0179",
"section": "7-6. 스윙야더 집재",
"pum_form": "requirement",
"line": 3558
"line": 3558,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0180",
"section": "7-7-1. 수확",
"pum_form": "requirement",
"line": 3572
"line": 3572,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0182",
"section": "7-8-1. 가선설치",
"pum_form": "requirement",
"line": 3623
"line": 3623,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0183",
"section": "7-8-2. 가선해체",
"pum_form": "requirement",
"line": 3635
"line": 3635,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0184",
"section": "7-8-3. 집재 소요인력",
"pum_form": "requirement",
"line": 3647
"line": 3647,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0191",
"section": "7-11. 동력상하차기(우드그래플) 집재-수확",
"pum_form": "requirement",
"line": 3761
"line": 3761,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0192",
"section": "7-12. 동력상하차기(우드그래플) 집적",
"pum_form": "requirement",
"line": 3779
"line": 3779,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0195",
"section": "7-14. 원목 운반-수확",
"pum_form": "productivity",
"line": 3865
"line": 3865,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0196",
"section": "7-15-1. 수확",
"pum_form": "productivity",
"line": 3880
"line": 3880,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0197",
"section": "7-15-2 숲가꾸기, 병해충방제",
"pum_form": "productivity",
"line": 3894
"line": 3894,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0198",
"section": "7-16. 소형 포워더 운재",
"pum_form": "productivity",
"line": 3914
"line": 3914,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0199",
"section": "7-17. 소형트럭 운재",
"pum_form": "productivity",
"line": 3928
"line": 3928,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0200",
"section": "7-18. 지조운반(포워더 활용)",
"pum_form": "productivity",
"line": 3942
"line": 3942,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0202",
"section": "8-1-2. 약제주입병",
"pum_form": "requirement",
"line": 3980
"line": 3980,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0203",
"section": "8-2-1. 소나무재선충병",
"pum_form": "requirement",
"line": 3998
"line": 3998,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0204",
"section": "8-2-1. 소나무재선충병",
"pum_form": "requirement",
"line": 4015
"line": 4015,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0206",
"section": "8-2-1. 소나무재선충병",
"pum_form": "requirement",
"line": 4039
"line": 4039,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0207",
"section": "8-2-1. 소나무재선충병",
"pum_form": "requirement",
"line": 4057
"line": 4057,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0209",
"section": "8-2-2. 솔잎혹파리",
"pum_form": "requirement",
"line": 4096
"line": 4096,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0210",
"section": "8-2-2. 솔잎혹파리",
"pum_form": "requirement",
"line": 4124
"line": 4124,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0211",
"section": "8-2-2. 솔잎혹파리",
"pum_form": "requirement",
"line": 4152
"line": 4152,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0213",
"section": "8-2-3. 솔껍질깍지벌레",
"pum_form": "requirement",
"line": 4198
"line": 4198,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0214",
"section": "8-2-3. 솔껍질깍지벌레",
"pum_form": "requirement",
"line": 4226
"line": 4226,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0215",
"section": "8-2-3. 솔껍질깍지벌레",
"pum_form": "requirement",
"line": 4254
"line": 4254,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0217",
"section": "8-2-4. 솔나방",
"pum_form": "requirement",
"line": 4295
"line": 4295,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0219",
"section": "8-2-5. 푸사리움가지마름병",
"pum_form": "requirement",
"line": 4336
"line": 4336,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0220",
"section": "8-3. 소각, 매몰, 훈증, 박피",
"pum_form": "productivity",
"line": 4364
"line": 4364,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0224",
"section": "8-5. 페르몬 유인트랩",
"pum_form": "requirement",
"line": 4450
"line": 4450,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0228",
"section": "8-6-2. 드론방제",
"pum_form": "requirement",
"line": 4532
"line": 4532,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0229",
"section": "8-6-2. 드론방제",
"pum_form": "requirement",
"line": 4552
"line": 4552,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0230",
"section": "8-6-3. 지상방제",
"pum_form": "requirement",
"line": 4573
"line": 4573,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0232",
"section": "8-7. 방제 실행 등록",
"pum_form": "requirement",
"line": 4599
"line": 4599,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0236",
"section": "8-10. 그물망 피복",
"pum_form": "requirement",
"line": 4647
"line": 4647,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0237",
"section": "8-11. 이동식 임목 파쇄",
"pum_form": "productivity",
"line": 4665
"line": 4665,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0238",
"section": "9-2. 노선 굴진 보조원",
"pum_form": "requirement",
"line": 4691
"line": 4691,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0251",
"section": "9-8-1. T=30㎝ 미만",
"pum_form": "requirement",
"line": 4876
"line": 4876,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0304",
"section": "10-6-3. 기타 임업자재",
"pum_form": "requirement",
"line": 5687
"line": 5687,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0317",
"section": "10-10-1. 콘크리트 및 골재운반(지상)",
"pum_form": "requirement",
"line": 5902
"line": 5902,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0318",
"section": "10-10-2. 그 외 자재의 운반품셈",
"pum_form": "requirement",
"line": 5912
"line": 5912,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0337",
"section": "12-5. 문양거푸집(07m)",
"pum_form": "requirement",
"line": 6239
"line": 6239,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0350",
"section": "12-12. 날개벽",
"pum_form": "requirement",
"line": 6443
"line": 6443,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0355",
"section": "12-17-1. 펌프카 타설",
"pum_form": "requirement",
"line": 6521
"line": 6521,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0362",
"section": "12-2 표면 마무리를 따른다.",
"pum_form": "requirement",
"line": 6591
},
{
"pum_table_id": "F0366",
"section": "12-19. 강관비계",
"pum_form": "requirement",
"line": 6636
"line": 6591,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0379",
"section": "12-29. 스페이셔 설치(몰탈 블록)",
"pum_form": "requirement",
"line": 6797
"line": 6797,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0401",
"section": "13-2-4. 야면석 채집(인력)",
"pum_form": "requirement",
"line": 7047
"line": 7047,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
},
{
"pum_table_id": "F0405",
"section": "13-3. 기초다짐 및 뒤채움’ 항을 적용한다.",
"pum_form": "requirement",
"line": 7109
"line": 7109,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0437",
"section": "13-12-1. 뭉기기",
"pum_form": "requirement",
"line": 7634
"line": 7634,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0438",
"section": "13-12-2. 지오셀(사면보강)",
"pum_form": "requirement",
"line": 7647
"line": 7647,
"why": "원문 부재 — 원문에 밑수가 아예 없음(채우면 지어내는 꼴)"
},
{
"pum_table_id": "F0447",
"section": "13-15-2. 목책 설치",
"pum_form": "requirement",
"line": 7767
"line": 7767,
"why": "미판독 — 원문이 적었는데 우리가 못 읽음"
}
]
}
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": "2026-01-01",
"generated_at": "2026-09-18T02:19:39+09:00",
"generated_at": "2026-09-18T03:15:03+09:00",
"dataset_version": {
"dataset_id": "pum_const",
"effective_date": "2026-01-01",
@@ -41,6 +41,8 @@
"form_undetermined": 891,
"basis_found": 538,
"basis_missing": 439,
"basis_absent_in_source": 308,
"basis_unparsed": 131,
"basis_grouped": 54,
"axis_roles": {
"group": 258,
@@ -4,7 +4,7 @@
"effective_date": "2026-01-01",
"pum_edition": "2026-01-01",
"toc_edition": "산림청고시제2025-82호",
"generated_at": "2026-09-18T02:18:51+09:00",
"generated_at": "2026-09-18T03:14:14+09:00",
"dataset_version": {
"dataset_id": "pum_forest",
"effective_date": "2026-01-01",
@@ -25,8 +25,10 @@
"tables_attached": 453,
"tables_orphan": 22,
"form_undetermined": 0,
"basis_found": 242,
"basis_missing": 88,
"basis_found": 243,
"basis_missing": 87,
"basis_absent_in_source": 75,
"basis_unparsed": 12,
"basis_grouped": 57,
"axis_roles": {
"general_provision": 78,
@@ -33259,9 +33261,9 @@
"source_line": 6636,
"pum_form": "requirement",
"form_basis": "분류 딱지 ['인력', '자재']",
"basis_quantity": null,
"basis_unit": null,
"basis_source": null,
"basis_quantity": 1.0,
"basis_unit": "공㎥",
"basis_source": "사람 판정 — 강관비계 — 원문 「(단위: 공㎥당)」",
"resource_shares": {},
"partial_ratio": false,
"expression_cells": [],
@@ -246,15 +246,6 @@
"md_evidence": "(단위: 일당)",
"master": null
},
"F0366": {
"section": "12-19",
"md": [
1.0,
"공㎥"
],
"md_evidence": "(단위: 공㎥당)",
"master": null
},
"F0395": {
"section": "12-38-3",
"md": [
@@ -61,7 +61,7 @@ MASTER = OUT_DIR / "work_item_master_2026-01-01.json"
#: 2026-09-17 랩탑 메인 둘째 — 헛단위 뺌(인용을 제목으로 읽은 13-3 표 셋 · 부록 사례 번호 겹침 일곱)으로 다시 뜸
#: (옛 be88f730…). 바뀐 줄은 13-3·4-1·4-2·2-1·2-2·3-1·3-2·3-3·13-4-1·13-5-2 의 표 귀속뿐 —
#: `test_work_item_master_toc` 가 자리를 잼 · 단가표 대조는 그 파일 머리.
BASELINE_WORK_ITEMS_SHA = "a26c1adb18918f9bafe503f66b728244a3e76bab52cac0388ea7ea717fc8053d"
BASELINE_WORK_ITEMS_SHA = "fc3bb5efdc1f1a954f1054543807b7acf78c8f9ea954be4ffcdfdf14fbe7d9c2"
#: 열쇠 작업이 새로 얹은 칸. 지문을 잴 때만 떼어낸다.
ADDED_FIELDS = (
@@ -458,6 +458,32 @@ def test_사람_판정은_원문이_나오면_물러난다(master: dict) -> None
assert "992" in by_id[table_id]["basis_source"], table_id
def test_밑수_미확보를_둘로_가른다(master: dict) -> None:
"""⚠ 「원문 부재」는 **채울 것이 아니다** — 없는 값을 지어내면 안 된다.
미확보 87 **75 원문에 밑수가 아예 없고**, **12 원문이 적었는데 우리가 읽은 **이다
(2026-09-18 안티그래비티 3바퀴 · 브레인). 목록에서 갈라 두면 다음 바퀴에 75
세어지지 않는다.
"""
import json as _json
from pathlib import Path as _Path
stats = master["stats"]
assert stats["basis_missing"] == 87
assert stats["basis_absent_in_source"] == 75
assert stats["basis_unparsed"] == 12
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(
encoding="utf-8"
)
)["items"]
assert all(i["why"] for i in items) # 사유 없는 줄이 없어야 한다
# 「공㎥」 처럼 단위 목록에 없던 자리는 사람 판정으로 채웠다 — 목록을 넓히면 규격이 밑수가 된다
by_id = {t["pum_table_id"]: t for it in master["work_items"] for t in it["tables"]}
assert by_id["F0366"]["basis_unit"] == "공㎥"
def test_원문_대조_밑수_판정(master: dict) -> None:
"""원문 md ↔ 마스터 전수 대조(안티그래비티 02544795)에서 나온 밑수를 반영했는가.