From d0978d24220062ba700b34028ae07f95ed0e40cb Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 04:43:58 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat(B08):=20=ED=81=B0=EB=8F=8C=EC=8C=93?= =?UTF-8?q?=EA=B8=B0=20=EB=A9=94/=EC=B0=B0=20=EC=9E=90=EB=8F=99=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95=20+=20=EC=A0=84=EB=A9=B4=20=EA=B8=B0?= =?UTF-8?q?=EC=9A=B8=EA=B8=B0=20=EA=B7=BC=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 랩탑이 B06 에서 상세 제원을 받게 하고 `bond` 칸을 더해 준 것을 받음. - `bond`(메쌓기/찰쌓기) → 품셈 `FP-13-06-01`/`FP-13-06-02` 자동 판정. 미입력이면 `blocked_kind: input_missing` 과 사람 말 사유로 드러냄 — 랩탑이 「빈 값을 미확보로 계속 드러내 달라」고 한 그대로. 첫 항목을 슬쩍 고르면 근거 없는 값이 수량·단가로 흘러감. - `pending_user` 에서 큰돌쌓기를 뺌 — 칸이 생겨 자동으로 갈림. 전면 기울기 1:0.3 의 근거를 찾아 데이터·주석에 적음. 지어낸 값이 아니라 **교본 7-3 돌흙막이 기준**임 — 「돌 찰쌓기 3.0m 이하 1:0.3 / 돌 메쌓기 2.0m 이하 1:0.3 / 큰돌쌓기 1:0.3 이상(전도 방지)」(지식DB 돌쌓기.md §1). ⚠ 큰돌쌓기는 「1:0.3 **이상**」이라 더 완만하게 잡을 수 있음 — 칸을 만든다면 그 범위를 보여야 한다는 것도 데이터에 적음. 검증 — 전체 642 passed. Co-Authored-By: Claude Opus 5 (1M context) --- B08_Quantity/B08_Quantity_Engine_Handoff.py | 17 +++++++++++++++-- .../B08_Quantity_Engine_UnitQuantity.py | 3 +++ .../masonry_class_2026-01-01.json | 19 +++++++++++++++++++ .../work_item_mapping_2026-01-01.json | 19 ++++++++++--------- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Engine_Handoff.py b/B08_Quantity/B08_Quantity_Engine_Handoff.py index 2ca0bba3..87aefef8 100644 --- a/B08_Quantity/B08_Quantity_Engine_Handoff.py +++ b/B08_Quantity/B08_Quantity_Engine_Handoff.py @@ -602,9 +602,22 @@ def _structure_rows( type_id = str(structure.get("type_id") or "") entry = mapping.for_structure(type_id) or {} code = entry.get("work_item_code") - # 돌쌓기는 **뒷길이 갈래**로 단가가 갈린다 — 저장 제원에서 자동으로 고른다. + # 돌쌓기는 **뒷길이 갈래**로, 큰돌쌓기는 **메/찰**로 단가가 갈린다 — + # 둘 다 저장 제원에서 자동으로 고른다(사용자 칸을 따로 만들지 않는다). class_key: str | None = None class_basis = "" + if entry.get("class_from") == "bond": + bond = str((structure.get("options") or {}).get("bond") or "").strip() + bond_codes = entry.get("bond_codes") or {} + if bond in bond_codes: + code = bond_codes[bond] + class_key = bond + class_basis = f"쌓기 방식 「{bond}」 → 품셈 13-6 {code.split('-')[-1]}" + else: + class_basis = ( + "큰돌쌓기 쌓기 방식이 아직 입력되지 않았습니다 — 구조물 상세 입력에서 " + "메쌓기·찰쌓기 중 하나를 고르면 공종이 정해집니다" + ) if code and entry.get("class_from") == "back_length": class_key, class_basis = masonry_class(structure.get("options") or {}) if class_key: @@ -618,7 +631,7 @@ def _structure_rows( blocked_kind, blocked_reason = blocked_of(structure, class_basis) if code is None and composite is None: unmatched.append(f"{wording_type_label(type_id)} — 품셈 공종을 아직 못 이었습니다") - elif entry.get("class_from") == "back_length" and class_key is None: + elif entry.get("class_from") in ("back_length", "bond") and class_key is None: unmatched.append(f"{wording_type_label(type_id)} — {class_basis}") length = float(structure.get("length_m") or 0.0) rows.append( diff --git a/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py b/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py index 13117703..214aedfe 100644 --- a/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py +++ b/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py @@ -293,6 +293,9 @@ def stone_masonry( # ⚠ `face_slope_ratio` 는 **레지스트리에 없는 키**다 — 즉 지금은 늘 기본 0.3 으로 돈다. # 상수로 두는 것이 아니라 「칸이 생기면 바로 받는다」는 뜻으로 남겨 둔다. # (키 이름 어긋남으로 저장값이 안 닿던 `back_len_cm` 사고와 구별할 것 — 이쪽은 **칸 자체가 없다**.) + # **기본 0.3 의 근거** — 교본 7-3 돌흙막이 기준: 「돌 찰쌓기 3.0m 이하 **1:0.3** / + # 돌 메쌓기 2.0m 이하 **1:0.3** / 큰돌쌓기 **1:0.3 이상**(전도 방지)」 + # (`지식DB 02_상세설계/구조물/돌쌓기.md §1`, 값은 `data_masonry` 의 `face_slope`). slope_ratio = _num(options.get("face_slope_ratio"), 0.3) # 전면 기울기 1:0.3 (교본 7-3) constants = STONE_MASONRY diff --git a/resources/data_masonry/masonry_class_2026-01-01.json b/resources/data_masonry/masonry_class_2026-01-01.json index 9026c746..6ed74845 100644 --- a/resources/data_masonry/masonry_class_2026-01-01.json +++ b/resources/data_masonry/masonry_class_2026-01-01.json @@ -31,5 +31,24 @@ "60~80", "80~100" ] + }, + "face_slope": { + "note": "전면 기울기(1:n) — **교본 7-3 돌흙막이 기준**이 형식별로 정해 둔다. 코드의 기본 0.3 은 지어낸 값이 아니라 이 표에서 온 것이다.", + "source": "resources/knowledge/technical_info/01_임도/02_상세설계/구조물/돌쌓기.md §1 (교본 7-3)", + "quote": "돌 찰쌓기 3.0m 이하 1:0.3 / 돌 메쌓기 2.0m 이하 1:0.3 / 큰돌쌓기 1:0.3 이상(전도 방지)", + "by_type": { + "masonry_wet": 0.3, + "masonry_dry": 0.3, + "boulder_masonry": 0.3 + }, + "pending": "⚠ 큰돌쌓기는 「1:0.3 **이상**」이라 더 완만하게 잡을 수 있음 — 칸을 만든다면 그 범위를 보여야 함. 지금은 하한 0.3 으로 감." + }, + "bond": { + "note": "큰돌쌓기 쌓기 방식 — 저장 제원 `bond`. 품셈 13-6-1(메)·13-6-2(찰)로 그대로 갈린다.", + "option_key": "bond", + "codes": { + "메쌓기": "FP-13-06-01", + "찰쌓기": "FP-13-06-02" + } } } diff --git a/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json b/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json index c6bafe55..46d8d9b1 100644 --- a/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json +++ b/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json @@ -139,6 +139,16 @@ "type_id": "ford_pavement", "work_item_code": "FP-12-06", "master_name": "콘크리트 포장(인력시공)" + }, + { + "type_id": "boulder_masonry", + "work_item_code": null, + "class_from": "bond", + "bond_codes": { + "메쌓기": "FP-13-06-01", + "찰쌓기": "FP-13-06-02" + }, + "class_note": "저장 제원 `bond`(메쌓기/찰쌓기)로 품셈 13-6-1·13-6-2 를 고름 — 자동 판정" } ], "pending_user": { @@ -160,15 +170,6 @@ "FP-09-05 발파암" ], "why": "설계자가 넣는 암 갈래 이름(풍화암·연암·보통암·경암)이 리핑이냐 발파냐를 말하지 않음. 갈래마다 시공법을 지정하는 칸이 필요함" - }, - { - "type_id": "boulder_masonry", - "candidates": [ - "FP-13-06-01 메쌓기", - "FP-13-06-02 찰쌓기" - ], - "why": "저장 제원(`boulder_masonry`)에 **메/찰 구분 칸이 없어** 어느 쪽인지 못 고름. 레지스트리(`B05_Profile_Structure_Types.json`)는 다른 창 소관이라 여기서 못 고침 — 칸이 생기면 `structure` 에 옮긴다.", - "class_axis": "직경(`stone_cm`) 40~60·60~80·80~100 — 품셈 13-6 축과 글자까지 같음" } ] }, From 089f80b55098345b90f0e6f0a63cc8a4165dd83b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 04:52:43 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat(B08):=20=EC=84=B1=ED=86=A0=EA=B3=A0?= =?UTF-8?q?=EB=A5=BC=20=EC=82=AC=EB=A9=B4=ED=91=9C=EC=97=90=20=EC=8B=A4?= =?UTF-8?q?=EC=96=B4=20=EC=88=98=ED=8F=89=20=EA=B7=9C=EC=A4=80=ED=8B=80=20?= =?UTF-8?q?=EA=B0=9C=EC=86=8C=EB=A5=BC=20=EC=85=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ㉔. 확정 7(준비공 3줄)의 마지막 하나가 닫힘. - 사면길이 유도가 이미 성토 사면을 재고 있어 **성토 조각의 수직 낙차 합**이 곧 성토고임. `StationSlope.fill_height_m` 으로 실어 사면표까지 옮김. ⚠ 좌우가 다르면 **큰 쪽**을 씀 — 「중심점 성토고 5m 이상」 판정은 가장 높은 쪽이 기준이고 양쪽을 더하면 실제보다 두 배가 됨. - 수평 규준틀은 **성토고 5m 이상 측점마다 한 개소**(11-3 [주]①). ⚠ 비탈규준틀(「10m 이상 20m마다」)과 **기준이 다름** — 이쪽은 지점 조건이라 간격이 없음. 두 기준을 같은 식으로 쓰면 조용히 틀림. - 성토고 칸이 아예 없으면 0 으로 때우지 않고 미확보로 둠. 성토고가 다 낮으면 0 개소가 **값**임 — 「못 셈」과 다름. 셋을 시험으로 갈라 못 박음. 실노선 확인 — 비탈 규준틀 31개소(617.475m ÷ 20 + 1) · 수평 규준틀 39개소. 검증 — 준비공 18건 통과, 전체 647 passed, tsc 오류 0. Co-Authored-By: Claude Opus 5 (1M context) --- .../B08_Quantity_Engine_Preparation.py | 49 +++++++++++++------ B08_Quantity/B08_Quantity_Engine_SlopeArea.py | 4 ++ .../B08_Quantity_Engine_SlopeLength.py | 9 ++++ 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Engine_Preparation.py b/B08_Quantity/B08_Quantity_Engine_Preparation.py index 35c64a9f..bcb52002 100644 --- a/B08_Quantity/B08_Quantity_Engine_Preparation.py +++ b/B08_Quantity/B08_Quantity_Engine_Preparation.py @@ -72,13 +72,23 @@ def batter_frame_count(slope_rows: Iterable[dict[str, Any]]) -> tuple[int, list[ return count, notes -def level_frame_count(slope_rows: Iterable[dict[str, Any]]) -> tuple[int, list[str]]: - """수평 규준틀 — **중심점 성토 높이 5m 이상**에 설치(품셈 11-3 [주]①). +def level_frame_count(slope_rows: Iterable[dict[str, Any]]) -> tuple[int | None, list[str]]: + """수평 규준틀 — **성토고 5m 이상 측점마다** 한 개소(품셈 11-3 [주]①). - ⚠ 성토고는 사면표에 없다 — 그 값을 받기 전에는 **0 으로 때우지 않고 미확보**로 둔다. + ⚠ 「비탈길이 10m 이상 20m마다」인 비탈규준틀과 **기준이 다르다** — 이쪽은 **지점 조건**이라 + 간격이 없다. 두 기준을 같은 식으로 쓰면 조용히 틀린다. + ⚠ 성토고 칸이 아예 없으면 **0 으로 때우지 않고** 미확보로 둔다 — 「없음」과 다르다. """ - return 0, [ - "중심점 성토고 5m 이상 지점에 설치(품셈 11-3 [주]①)인데 성토고가 이 표에 없어 개소를 못 셈" + rows = list(slope_rows) + if not rows: + return None, ["사면표가 없어 성토고를 못 봄"] + if all("fill_height_m" not in row for row in rows): + return None, ["성토고가 사면표에 없어 개소를 못 셈 (품셈 11-3 [주]① 「성토고 5m 이상」)"] + tall = [ + row for row in rows if float(row.get("fill_height_m") or 0.0) >= LEVEL_MIN_FILL_HEIGHT_M + ] + return len(tall), [ + f"성토고 {LEVEL_MIN_FILL_HEIGHT_M:g}m 이상 측점 {len(tall)}곳 (품셈 11-3 [주]①)" ] @@ -119,15 +129,7 @@ def preparation_rows( "work_item_code": "FP-09-21", }, _batter_frame_row(list(slope_rows)), - { - "group": "준비공", - "item": "수평 규준틀", - "unit": "개소", - "amount": None, - "status": STATUS_PENDING, - "reason": level_frame_count(())[1][0], - "work_item_code": "FP-11-03", - }, + _level_frame_row(list(slope_rows)), ] @@ -179,6 +181,25 @@ def _batter_frame_row(slope_rows: list[dict[str, Any]]) -> dict[str, Any]: } +def _level_frame_row(slope_rows: list[dict[str, Any]]) -> dict[str, Any]: + """수평 규준틀 한 줄. 성토고를 못 보면 미확보, 보면 개소가 선다.""" + count, notes = level_frame_count(slope_rows) + return { + "group": "준비공", + "item": "수평 규준틀", + "unit": "개소", + "amount": float(count) if count is not None else None, + "status": STATUS_READY if count is not None else STATUS_PENDING, + "reason": "; ".join(notes) + + ( + " · 재료량은 품셈 11-3 [주]④ 「설계수량에 따른다」라 미확보" + if count is not None + else "" + ), + "work_item_code": "FP-11-03", + } + + def erosion_rows(structures: Iterable[dict[str, Any]] = ()) -> list[dict[str, Any]]: """사방공 줄 — 이 노선에 사방 시설이 **있을 때만** 값이 선다.""" found = sorted( diff --git a/B08_Quantity/B08_Quantity_Engine_SlopeArea.py b/B08_Quantity/B08_Quantity_Engine_SlopeArea.py index d5df001e..47d92d1e 100644 --- a/B08_Quantity/B08_Quantity_Engine_SlopeArea.py +++ b/B08_Quantity/B08_Quantity_Engine_SlopeArea.py @@ -69,6 +69,8 @@ class SlopeAreaRow: chainage_m: float distance_m: float = 0.0 berm_width_m: float = 0.0 + # 성토고(m) — 수평 규준틀 개소 판정(품셈 11-3 [주]① 「성토고 5m 이상」)이 쓴다. + fill_height_m: float = 0.0 unclosed: bool = False lengths: dict[str, float] = field(default_factory=dict) areas: dict[str, float] = field(default_factory=dict) @@ -102,6 +104,7 @@ def build_rows( row = SlopeAreaRow( chainage_m=slope.chainage_m, berm_width_m=slope.berm_width_m, + fill_height_m=slope.fill_height_m, unclosed=slope.unclosed, ) for series, faces in SERIES: @@ -153,6 +156,7 @@ def build_table( "chainage_m": row.chainage_m, "distance_m": row.distance_m, "berm_width_m": row.berm_width_m, + "fill_height_m": row.fill_height_m, "unclosed": row.unclosed, "lengths": row.lengths, "areas": row.areas, diff --git a/B08_Quantity/B08_Quantity_Engine_SlopeLength.py b/B08_Quantity/B08_Quantity_Engine_SlopeLength.py index 8f6a3d28..e7497743 100644 --- a/B08_Quantity/B08_Quantity_Engine_SlopeLength.py +++ b/B08_Quantity/B08_Quantity_Engine_SlopeLength.py @@ -59,6 +59,10 @@ class StationSlope: cut_length_m: float = 0.0 fill_length_m: float = 0.0 berm_width_m: float = 0.0 + # 성토고(m) — 성토 사면 조각들의 **수직 낙차 합**. 노면 끝에서 원지반까지 내려간 높이다. + # ⚠ 좌우가 다르면 **큰 쪽**을 쓴다. 「중심점 성토고 5m 이상」(품셈 11-3 [주]①) 판정은 + # 가장 높은 쪽이 기준이고, 양쪽을 더하면 실제보다 두 배가 된다. + fill_height_m: float = 0.0 segments: tuple[SlopeSegment, ...] = () # 사면이 샘플 범위 끝까지 원지반을 못 만나 **면적이 잘린** 측점. # 설계 엔진이 `slope_unclosed` 로 이미 경고하는 값을 그대로 물고 온다. 잘린 측점은 @@ -204,10 +208,15 @@ def station_slope(chainage_m: float, design: dict[str, Any]) -> StationSlope: for side in ("left", "right"): segments.extend(_side_segments(design, side, ratios)) berm = design.get("berm") or {} + fill_by_side = { + side: sum(abs(s.rise_m) for s in segments if s.role == "fill" and s.side == side) + for side in ("left", "right") + } return StationSlope( chainage_m=float(chainage_m), cut_length_m=sum(s.length_m for s in segments if s.role == "cut"), fill_length_m=sum(s.length_m for s in segments if s.role == "fill"), + fill_height_m=max(fill_by_side.values(), default=0.0), berm_width_m=_num(berm.get("width_m")) or 0.0, segments=tuple(segments), unclosed=bool(design.get("slope_unclosed")), From 5bd129bae432d69c7c7dc693ee652068108d4be4 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 04:57:54 +0900 Subject: [PATCH 3/6] =?UTF-8?q?fix(B08):=20=EA=B0=88=EB=9E=98=20=ED=82=A4?= =?UTF-8?q?=EB=A5=BC=20=EC=A1=B0=EB=A6=BD=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0=20=EC=9B=90=EB=B3=B8=EA=B0=92=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=B4=EB=83=84=20+=20=ED=8A=B9=EC=88=98=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=20=EA=B9=83=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠ 계약 변경(2026-09-07 3자). 품셈 원문이 규격 표기를 한 종류로 안 씀 — **물결표만 셋**(`∼` U+223C 662회 · `~` U+FF5E 459회 · `~` U+007E 2회), 곱셈표도 둘(`×` 97회 · `x` 4회). 같은 절 안에서도 갈림(13-06-01·02 는 `∼`, 13-06-03 은 `~`). **두 창이 각자 키를 조립하면 글자 하나로 영영 안 맞음.** - `#55cm이하`·`#직경60㎝이상∼80㎝미만` 같은 키를 **우리가 만들지 않음**. `variant_axis`(어느 축) + `variant_value`(저장 원본값 그대로)만 보내고, 원문을 읽는 쪽이 표기를 흡수함. 「…㎝ 이하」 구간 나누기도 그쪽 몫 — 그 구간이 품셈 표의 구조이기 때문. - ⚠ **메/찰은 예외** — 키 표기가 아니라 **공종 자체가 갈리는 의미 판정**이라 코드가 `FP-13-06-01`/`-02` 로 통째로 달라짐. 그것은 우리 몫으로 유지. - 계약 시험에 못 박음 — 코드에 `#`·`㎝`·`cm` 가 들어가면 깨짐. 원본값을 가공해도 깨짐(물결표 종류를 바꾸거나 단위를 붙이면 안 됨). - `data_masonry` 의 갈래표는 지우지 않고 **참고**로 남김 — 서브 판정과 어긋나면 그것이 곧 신호. 마스터에 `special_glyphs` 깃발 — 규격 표기에 쓰인 특수문자 종류. 값은 안 고치고 표시만 함. 물결표가 두 종류 섞인 표가 실제로 5개 있는 것을 시험으로 못 박음 (계약 근거가 사라지면 깨짐). 검증 — 전체 653 passed, tsc 오류 0. Co-Authored-By: Claude Opus 5 (1M context) --- .../B08_Quantity_Build_WorkItemMaster.py | 25 + B08_Quantity/B08_Quantity_Engine_Handoff.py | 19 +- .../work_item_mapping_2026-01-01.json | 25 +- .../data_work_item_master/_manifest.json | 6 +- .../work_item_master_2026-01-01.json | 755 +++++++++++++++++- 5 files changed, 818 insertions(+), 12 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py b/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py index 736e7025..017fa63f 100644 --- a/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py +++ b/B08_Quantity/B08_Quantity_Build_WorkItemMaster.py @@ -407,6 +407,29 @@ def formula_rows(table: dict[str, Any]) -> list[str]: return found +# ⚠ **규격 표기에 쓰이는 특수문자** — 원문이 한 종류로 안 쓴다(2026-09-07 실측). +# 물결표만 셋이다: `∼`(U+223C) 662회 · `~`(U+FF5E) 459회 · `~`(U+007E) 2회. +# 곱셈표도 `×`(U+00D7) 97회 · `x`(U+0078) 4회로 갈린다. +# **두 창이 각자 갈래 키를 조립하면 글자 하나로 영영 안 맞는다** — 그래서 우리는 +# 키를 조립하지 않고 **저장 원본값만** 보낸다(인계 계약). 여기서는 **표시만** 한다. +# ⚠ 값을 고치지 않는다 — 원문 표기를 흡수하는 것은 **원문을 읽는 쪽**의 몫이다. +SPECIAL_GLYPHS = { + "∼": "∼(U+223C)", + "~": "~(U+FF5E)", + "~": "~(U+007E)", + "×": "×(U+00D7)", + "x": "x(U+0078)", + "–": "–(U+2013)", + "‐": "‐(U+2010)", +} + + +def special_glyphs(table: dict[str, Any]) -> list[str]: + """규격 표기에 쓰인 특수문자 종류. 갈래 키를 맞출 때 대조할 자리.""" + text = " ".join(norm(cell) for row in table.get("rows", []) for cell in row) + return sorted({SPECIAL_GLYPHS[ch] for ch in text if ch in SPECIAL_GLYPHS}) + + def crew_table(table: dict[str, Any]) -> bool: """작업조 + 시공량으로 적힌 표인가.""" hay = " ".join(norm(h) for h in table.get("headers", [])) @@ -532,6 +555,8 @@ def build() -> dict[str, Any]: "spaced_names": spaced_names(table), # ⚠ 공식 기호 줄 — 소요량이 아니다. 자원으로 세면 이중계상. "formula_rows": formula_rows(table), + # ⚠ 규격 표기 특수문자 — 갈래 키를 맞출 때 대조할 자리(값은 안 고침). + "special_glyphs": special_glyphs(table), # 공식 기호가 이 표에 직접 있는가 — 없으면 앞 표에서 물려받는 모양이다. "capacity_formula_here": capacity_formula_pending(table), "variant_key": variant_axis(table), diff --git a/B08_Quantity/B08_Quantity_Engine_Handoff.py b/B08_Quantity/B08_Quantity_Engine_Handoff.py index 87aefef8..94d6e298 100644 --- a/B08_Quantity/B08_Quantity_Engine_Handoff.py +++ b/B08_Quantity/B08_Quantity_Engine_Handoff.py @@ -499,6 +499,9 @@ def _earthwork_rows( "spec_detail": "", "composite_parts": None, "structure_kind": None, + # 토공·운반 줄에는 갈래 축이 없다 — 그래도 **칸은 둔다**(계약이 한 모양). + "variant_axis": None, + "variant_value": None, "spec_class": None, "spec_class_basis": "", # 토공 줄은 막힐 자리가 없다 — 그래도 **칸은 둔다**(계약이 한 모양이어야 한다). @@ -551,6 +554,9 @@ def _haul_rows( "spec_detail": "", "composite_parts": None, "structure_kind": None, + # 토공·운반 줄에는 갈래 축이 없다 — 그래도 **칸은 둔다**(계약이 한 모양). + "variant_axis": None, + "variant_value": None, "spec_class": None, "spec_class_basis": "", "blocked_kind": None, @@ -610,6 +616,7 @@ def _structure_rows( bond = str((structure.get("options") or {}).get("bond") or "").strip() bond_codes = entry.get("bond_codes") or {} if bond in bond_codes: + # 메/찰은 **의미 판정**이라 우리 몫이다 — 공종 자체가 갈린다. code = bond_codes[bond] class_key = bond class_basis = f"쌓기 방식 「{bond}」 → 품셈 13-6 {code.split('-')[-1]}" @@ -620,8 +627,7 @@ def _structure_rows( ) if code and entry.get("class_from") == "back_length": class_key, class_basis = masonry_class(structure.get("options") or {}) - if class_key: - code = f"{code}#{normalize_kind_key(class_key)}" + composite = mapping.composite_for(type_id) if code is None else None kind = structure_kind(structure) if composite else None parts: list[dict[str, Any]] | None = None @@ -629,6 +635,9 @@ def _structure_rows( if composite: parts, parts_missing = composite_quantities(structure, composite, mapping) blocked_kind, blocked_reason = blocked_of(structure, class_basis) + # 갈래 축과 **저장 제원 원본값**. 가공하지 않는다. + variant_axis = str(entry.get("variant_axis") or "") or None + variant_value = (structure.get("options") or {}).get(variant_axis) if variant_axis else None if code is None and composite is None: unmatched.append(f"{wording_type_label(type_id)} — 품셈 공종을 아직 못 이었습니다") elif entry.get("class_from") in ("back_length", "bond") and class_key is None: @@ -660,6 +669,12 @@ def _structure_rows( "blocked_kind": blocked_kind, "blocked_reason": blocked_reason, # 규격 갈래(뒷길이 …㎝ 이하) — 못 고르면 사유가 남는다. + # ⚠ **갈래 키 문자열을 우리가 조립하지 않는다** (2026-09-07 계약 변경). + # 품셈 원문이 물결표를 섞어 쓴다(`∼` U+223C / `~` U+FF5E). 두 창이 각자 + # 키를 조립하면 **글자 하나로 영영 안 맞는다.** 우리는 **어느 축인지와 + # 저장 원본값**만 보내고, 원문을 읽는 쪽이 그 표기를 흡수한다. + "variant_axis": variant_axis, + "variant_value": variant_value, "spec_class": class_key, "spec_class_basis": class_basis, # ⚠ 물량을 못 채운 조각 — 0 으로 적지 않고 사유와 함께 드러낸다. diff --git a/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json b/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json index 46d8d9b1..7481524e 100644 --- a/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json +++ b/resources/data_work_item_mapping/work_item_mapping_2026-01-01.json @@ -119,16 +119,16 @@ "work_item_code": "FP-13-04-05", "master_name": "돌쌓기 > 찰쌓기(장비)", "note": "인력 시공이면 FP-13-04-04", - "class_from": "back_length", - "class_note": "저장 제원 `back_len_cm` 으로 「…㎝ 이하」 구간을 고름 — 자동 판정" + "class_note": "⚠ 갈래 키 문자열을 여기서 만들지 않는다 — `variant_axis`+`variant_value`(저장 원본값)만 보내고 「…㎝ 이하」 구간 나누기는 **품셈 원문을 읽는 쪽**이 한다(2026-09-07 계약).", + "variant_axis": "back_len_cm" }, { "type_id": "masonry_dry", "work_item_code": "FP-13-04-02", "master_name": "돌쌓기 > 메쌓기(장비)", "note": "인력 시공이면 FP-13-04-01", - "class_from": "back_length", - "class_note": "저장 제원 `back_len_cm` 으로 「…㎝ 이하」 구간을 고름 — 자동 판정" + "class_note": "⚠ 갈래 키 문자열을 여기서 만들지 않는다 — `variant_axis`+`variant_value`(저장 원본값)만 보내고 「…㎝ 이하」 구간 나누기는 **품셈 원문을 읽는 쪽**이 한다(2026-09-07 계약).", + "variant_axis": "back_len_cm" }, { "type_id": "pipe_inlet_basin", @@ -148,7 +148,8 @@ "메쌓기": "FP-13-06-01", "찰쌓기": "FP-13-06-02" }, - "class_note": "저장 제원 `bond`(메쌓기/찰쌓기)로 품셈 13-6-1·13-6-2 를 고름 — 자동 판정" + "class_note": "메/찰(`bond`)은 **공종 자체가 갈리는 의미 판정**이라 여기서 고른다. 직경 갈래는 `variant_value` 로 원본값만 보낸다 — 원문이 물결표를 섞어 써서.", + "variant_axis": "stone_cm" } ], "pending_user": { @@ -264,5 +265,17 @@ "hand_mixed": 408327 } } - } + }, + "variant_contract": { + "note": "갈래 계약(2026-09-07 3자) — **키 문자열을 두 창이 각자 조립하지 않는다.**", + "why": "품셈 원문이 물결표를 섞어 쓴다: 13-06-01·02 는 `∼`(U+223C), 13-06-03 은 `~`(U+FF5E). 각자 조립하면 글자 하나로 영영 안 맞는다.", + "b08_sends": [ + "work_item_code", + "variant_axis", + "variant_value", + "kind_basis" + ], + "b09_does": "원문 표기(물결표·공백·괄호)를 흡수해 자기 키로 옮긴다. 「…㎝ 이하」 구간 나누기도 그쪽 몫 — 그 구간이 **품셈 표의 구조**이기 때문." + }, + "masonry_class_reference": "resources/data_masonry/masonry_class_2026-01-01.json — ⚠ 이제 **참고용**이다. 서브 판정과 어긋나면 그것이 곧 신호다." } diff --git a/resources/data_work_item_master/_manifest.json b/resources/data_work_item_master/_manifest.json index 4c6fc350..dd120b46 100644 --- a/resources/data_work_item_master/_manifest.json +++ b/resources/data_work_item_master/_manifest.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "dataset_id": "data_work_item_master_manifest", - "generated_at": "2026-09-08T01:52:34+09:00", + "generated_at": "2026-09-08T04:57:04+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": "08b0c7c26c4aa569ace3b13490b8cbd00606254abb1439894eac750d387bfb03", - "size_bytes": 839464 + "sha256": "1c49012f9f50d721676ad8def15c87c96b77aad83123286dd6981b7d9cefcd81", + "size_bytes": 856450 }, { "file": "form_undetermined_2026-01-01.json", diff --git a/resources/data_work_item_master/work_item_master_2026-01-01.json b/resources/data_work_item_master/work_item_master_2026-01-01.json index cc9c3e9d..741b4fad 100644 --- a/resources/data_work_item_master/work_item_master_2026-01-01.json +++ b/resources/data_work_item_master/work_item_master_2026-01-01.json @@ -2,7 +2,7 @@ "schema_version": "1.0", "dataset_id": "work_item_master_forest", "effective_date": "2026-01-01", - "generated_at": "2026-09-08T01:52:34+09:00", + "generated_at": "2026-09-08T04:57:04+09:00", "dataset_version": { "dataset_id": "pum_forest", "effective_date": "2026-01-01", @@ -154,6 +154,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "2.5톤 차량", @@ -276,6 +277,7 @@ "관 류(管類)" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "단 위", @@ -903,6 +905,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "설계서의 총액", @@ -975,6 +978,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "경 암 ( 硬 岩 )", @@ -1103,6 +1110,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자연상태의 체적", @@ -1154,6 +1162,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "사용고재(시멘트공대 및 공드람 제외)", @@ -1222,6 +1231,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "6톤 차량", @@ -1802,6 +1815,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "시 멘 트", @@ -1864,6 +1878,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "모 래", @@ -1909,6 +1924,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "모 래" @@ -1939,6 +1955,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "원 형 철 근", @@ -2019,6 +2036,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "목 재", @@ -2174,6 +2192,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "6월∼9월", @@ -2224,6 +2245,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "3년차 이상", @@ -2274,6 +2296,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "집단화 정도", @@ -2328,6 +2353,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "작업구역", @@ -2406,6 +2434,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "산지경사", @@ -2484,6 +2515,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "도 보", @@ -2554,6 +2588,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "식생을 제거하지 않고는 보행이 곤란하다", @@ -2604,6 +2639,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "가슴높이 이상의 초본․관목", @@ -2654,6 +2690,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "어렵다(높이 1.2m 이상이고, 직경이 4~6cm 이상)", @@ -2704,6 +2743,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "돌 등 장애물 함량이 30% 이상이고, 나무뿌리가 밀하게 분포할 경우", @@ -2754,6 +2796,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "과밀(80%초과 피복)", @@ -2814,6 +2859,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "대 (임지의 71% 이상 분포)", @@ -2864,6 +2912,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "돌, 도랑, 그루터기 등으로 주행이 매우 힘들다", @@ -2914,6 +2963,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "가선을 이용한 기계장비의 원목․생산재 집재", @@ -2999,6 +3051,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "11~20m", @@ -3049,6 +3104,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "규격재 생산을 위한 조재" @@ -3089,6 +3145,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "산림병해충방제 (단목베기, 나무주사)", @@ -3179,6 +3238,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "산림병해충방제 (산물수집-기계장비 집재)", @@ -3235,6 +3297,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "매개충나무주사" @@ -3286,6 +3349,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "사면형", @@ -3346,6 +3410,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "접근성", @@ -3400,6 +3467,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "방제 수종", @@ -3448,6 +3516,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "그물망 피복 시 임내 운반거리", @@ -3520,6 +3591,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "장비의 규격 (굴삭기)", @@ -3568,6 +3640,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업 가능 시간", @@ -3634,6 +3707,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "1", @@ -3693,6 +3767,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "적용방법", @@ -3933,6 +4010,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "2회", @@ -4006,6 +4084,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "거 푸 집 씻 기", @@ -4089,6 +4170,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+007E)", + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 면적", @@ -4459,6 +4544,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통휘발유 (주연료)", @@ -4507,6 +4593,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "예취기(휘발유)" @@ -4541,6 +4628,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "아키아윈치(휘발유)" @@ -4573,6 +4661,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "2드럼 케이블윈치(휘발유)" @@ -4605,6 +4694,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "천공기 (휘발유)" @@ -4649,6 +4739,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "트랙터 부착 기계", @@ -4770,6 +4861,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "트랙 접지력 보강", @@ -4815,6 +4907,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "주재료", @@ -4865,6 +4958,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "주재료", @@ -4907,6 +5001,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "주재료", @@ -4947,6 +5042,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "주재료", @@ -4999,6 +5095,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "x(U+0078)" + ], "capacity_formula_here": false, "variant_key": [ "농약 (Fluroxypyr -meptyl + Triclypyr-TEA 미탁제)" @@ -5033,6 +5132,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소금처리량(g)" @@ -5069,6 +5169,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "농약 (글리포세이트)", @@ -5120,6 +5221,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "수량", @@ -5212,6 +5316,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "훈증약제", @@ -5284,6 +5389,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "수 량", @@ -5341,6 +5447,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "수 량", @@ -5398,6 +5505,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "수 량", @@ -5455,6 +5563,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "수 량", @@ -5505,6 +5614,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "그물망", @@ -5553,6 +5663,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "메인파쇄기날", @@ -5606,6 +5717,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+007E)", + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 면적", @@ -5996,6 +6111,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "45cc (배기량기준)" @@ -6038,6 +6156,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "예취기 (배기량 35cc)" @@ -6080,6 +6201,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "아키아윈치", @@ -6257,6 +6381,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "배부식분무기" @@ -6299,6 +6426,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "45cc (배기량 기준)" @@ -6341,6 +6471,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "5HP(양수기)" @@ -6383,6 +6514,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "무인헬기(FAZER) 내용가동시간 1,400시간기준" @@ -6425,6 +6557,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "무인멀티콥터(평균가) 내용가동시간 1,000시간 기준", @@ -6473,6 +6606,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "1톤(방제차량)", @@ -6521,6 +6655,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "-" @@ -6565,6 +6700,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "손료계수(10⁻⁷)", @@ -6634,6 +6772,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소요인력", @@ -6668,6 +6807,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 면적", @@ -7608,6 +7750,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "구 분", @@ -7644,6 +7787,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 면적", @@ -8696,6 +8842,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "구 분", @@ -8738,6 +8885,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 면적", @@ -9705,6 +9855,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "노면정지", @@ -9753,6 +9904,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "모든 벌채산물 임내존치지역", @@ -9853,6 +10005,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "10㎥ 미만", @@ -9919,6 +10072,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "10㎥ 미만", @@ -10015,6 +10169,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "드론조종자 (건설기계조종원)", @@ -10101,6 +10256,7 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "위치 및 임․소반", @@ -11587,6 +11743,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "벌도목 구분", @@ -11645,6 +11802,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "벌도ㆍ조재 공정량(㎥)", @@ -11679,6 +11837,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "154" @@ -11719,6 +11878,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 임․소반", @@ -12547,6 +12709,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "벌목", @@ -12701,6 +12866,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "5m 미만", @@ -12774,6 +12942,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -12864,6 +13035,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부" @@ -12906,6 +13078,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "0.13인" @@ -12946,6 +13119,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "1인" @@ -13004,6 +13178,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "0.3m 미만", @@ -13063,6 +13240,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -13164,6 +13344,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "특별인부(인)", @@ -13341,6 +13524,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼ 19", @@ -13401,6 +13587,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "줄떼", @@ -13449,6 +13636,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "지게", @@ -13542,6 +13730,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -13696,6 +13885,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소묘식재", @@ -13744,6 +13934,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소나무", @@ -13834,6 +14025,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소묘", @@ -13888,6 +14080,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "0.3m 미만", @@ -13947,6 +14142,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "0.3m 미만", @@ -14006,6 +14204,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "인 력 시 공", @@ -14139,6 +14340,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인력품의 10%" @@ -14179,6 +14381,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "특별인부(인)", @@ -14340,6 +14545,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인력품의 10%" @@ -14370,6 +14576,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "8 ∼ 17", @@ -14430,6 +14639,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "파종상 만들기", @@ -14502,6 +14714,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "지면긁기작업", @@ -14553,6 +14769,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "맹아근주 정리작업" @@ -14597,6 +14814,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "움싹본수조절", @@ -14655,6 +14873,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "큰나무 식재" @@ -14699,6 +14920,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부" @@ -14743,6 +14965,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "묘목", @@ -14829,6 +15054,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부(인)" @@ -14873,6 +15099,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "줄떼", @@ -14921,6 +15150,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "줄떼심기", @@ -14969,6 +15199,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "새채집", @@ -15048,6 +15279,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "말뚝", @@ -15119,6 +15353,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통토사", @@ -15203,6 +15438,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "단끊기", @@ -15277,6 +15513,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "단끊기", @@ -15342,6 +15579,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "단끊기", @@ -15400,6 +15638,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "종자", @@ -15502,6 +15741,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "6", @@ -15558,6 +15798,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "15", @@ -15619,6 +15860,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "표토채취", @@ -15683,6 +15925,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "채 취", @@ -15755,6 +15998,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조경공", @@ -15806,6 +16050,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부" @@ -15850,6 +16095,7 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조경공", @@ -15930,6 +16176,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조경공", @@ -15981,6 +16228,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부" @@ -16041,6 +16289,7 @@ "보 통 인 부" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -16175,6 +16424,7 @@ "물 탱 크" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -16293,6 +16543,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "초본 위주형", @@ -16385,6 +16638,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "초본 위주형", @@ -16487,6 +16743,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -16557,6 +16814,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "9", @@ -16628,6 +16886,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "9", @@ -16699,6 +16958,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10% 이내", @@ -16755,6 +17017,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조경공", @@ -16812,6 +17075,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특 별 인 부", @@ -16863,6 +17127,7 @@ "보 통 인 부" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "폭 1.5m 이하", @@ -16926,6 +17191,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "K(버킷계수)", @@ -16986,6 +17252,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "표시봉 설치" @@ -17030,6 +17297,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "지주목 설치" @@ -17074,6 +17342,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "대 절" @@ -17118,6 +17387,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소묘, 중묘", @@ -17166,6 +17436,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소 묘", @@ -17229,6 +17500,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인공림(10년이하 조림지)", @@ -17292,6 +17564,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "낫" @@ -17336,6 +17609,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "묘목찾기", @@ -17410,6 +17684,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "묘목찾기", @@ -17484,6 +17759,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "괭이, 도끼 등" @@ -17537,6 +17813,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "기계작업" @@ -17583,6 +17860,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "약제살포", @@ -17637,6 +17915,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "소금 처리", @@ -17715,6 +17996,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "뿌리 고살", @@ -17775,6 +18059,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "80% 이상", @@ -17847,6 +18134,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부 (체인톱 사용)", @@ -17909,6 +18197,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "0~0.5m", @@ -18020,6 +18311,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "11미만", @@ -18082,6 +18376,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특 별 인 부", @@ -18133,6 +18428,7 @@ "보 통 인 부" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특 별 인 부", @@ -18190,6 +18486,7 @@ "보 통 인 부" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "우 드 칩", @@ -18266,6 +18563,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "100m이하", @@ -18320,6 +18618,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "ha당원목재적 평균거리", @@ -18396,6 +18695,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "ha당원목재적 평균거리", @@ -18497,6 +18799,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "8", @@ -18684,6 +18987,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "20이하㎥", @@ -18770,6 +19076,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "50m 내외" @@ -18821,6 +19128,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "50이하", @@ -18956,6 +19264,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "20m이하", @@ -19021,6 +19330,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "30이하", @@ -19156,6 +19466,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "0.1∼0.2㎥", @@ -19240,6 +19553,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "60m 이하", @@ -19296,6 +19610,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "50이하", @@ -19431,6 +19746,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "100m 이하", @@ -19524,6 +19842,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "120m 이하", @@ -19593,6 +19912,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "120m 이하", @@ -19662,6 +19982,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "100m이하", @@ -19806,6 +20127,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "100m 이하", @@ -19896,6 +20220,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "100m 이하", @@ -19976,6 +20303,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "100m 이하", @@ -20059,6 +20389,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "20㎥ 미만", @@ -20111,6 +20444,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "원목의 길이", @@ -20187,6 +20523,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "원목의 길이", @@ -20263,6 +20602,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "원목집재와 동시에 부산물 수집시" @@ -20304,6 +20644,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "9㎝ 이하", @@ -20395,6 +20738,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "생산목 검척" @@ -20427,6 +20771,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "2.1m", @@ -20534,6 +20879,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "1회 적 재 량", @@ -20622,6 +20970,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "100", @@ -20706,6 +21055,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "0.5", @@ -20787,6 +21137,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "100", @@ -20871,6 +21222,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "100", @@ -20952,6 +21304,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "100", @@ -21051,6 +21404,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -21151,6 +21505,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -21233,6 +21588,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "10~12", @@ -21396,6 +21754,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "10~12", @@ -21537,6 +21898,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "아바멕틴", @@ -21592,6 +21954,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "10~12", @@ -21755,6 +22120,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "10~16", @@ -21917,6 +22285,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "티아메톡삼 분산성액제 15%", @@ -21979,6 +22348,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -22167,6 +22539,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -22355,6 +22730,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -22553,6 +22931,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "디노테퓨란(15)․에마멕틴벤조에이트(4.5) 분산성액제 19.5%", @@ -22609,6 +22988,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -22797,6 +23179,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -22985,6 +23370,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -23173,6 +23561,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "사업 구분", @@ -23855,6 +24244,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "공종", @@ -24465,6 +24855,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "위치 및 면적", @@ -25069,6 +25462,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "아바멕틴(1.8)·설폭사플로르(4.2) 분산성액제 6%" @@ -25101,6 +25495,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -25299,6 +25696,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "테부코나졸 유탁제 25%" @@ -25331,6 +25729,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "10∼12", @@ -25529,6 +25930,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "6", @@ -25837,6 +26239,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "4cm", @@ -26032,6 +26435,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "중부지방소나무" @@ -26076,6 +26480,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "8롤 미만", @@ -26144,6 +26551,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "트랩설치", @@ -26207,6 +26615,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -26319,6 +26728,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "산림항공방제", @@ -26401,6 +26811,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소형헬기 (AS350)", @@ -26595,6 +27006,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "드론조종자 (건설기계 조종원)", @@ -26684,6 +27096,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "드론조종자 (건설기계 조종원)", @@ -26783,6 +27196,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -26844,6 +27258,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "250배", @@ -26994,6 +27409,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "방제실행 등록" @@ -27045,6 +27461,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "10m이하", @@ -27121,6 +27540,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "10개 이하", @@ -27184,6 +27606,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "잔가지 줍기" @@ -27226,6 +27649,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "벌목부", @@ -27309,6 +27733,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "이동식 임목 파쇄기" @@ -27371,6 +27796,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부" @@ -27422,6 +27848,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부(인)" @@ -27475,6 +27902,9 @@ "E", "㎝(sec)" ], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": true, "variant_key": [ "K", @@ -27544,6 +27974,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "대형브레이커+ 유압식백호우 (무한궤도,0.7㎥)", @@ -27613,6 +28044,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "K", @@ -27686,6 +28118,7 @@ "착 암 공" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -27796,6 +28229,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "연 암", @@ -27861,6 +28295,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "K", @@ -27932,6 +28367,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "대형브레이커+유압식백호우 (무한궤도,0.7㎥)" @@ -27983,6 +28419,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "무근콘크리트" @@ -28029,6 +28468,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "무근콘크리트" @@ -28084,6 +28526,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "철근콘크리트" @@ -28120,6 +28565,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인력", @@ -28189,6 +28635,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "철근콘크리트" @@ -28235,6 +28684,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "메쌓기", @@ -28306,6 +28756,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "콘크리트" @@ -28350,6 +28803,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "아스팔트" @@ -28403,6 +28857,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력", @@ -28516,6 +28973,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력(10%)", @@ -28603,6 +29061,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -28706,6 +29165,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -28818,6 +29278,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -28899,6 +29360,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -28954,6 +29418,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29014,6 +29481,9 @@ "E", "㎝(sec)" ], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -29093,6 +29563,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29146,6 +29620,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29206,6 +29684,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -29309,6 +29788,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29388,6 +29870,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29474,6 +29959,9 @@ "E", "㎝(sec)" ], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -29569,6 +30057,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29640,6 +30132,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29718,6 +30214,9 @@ "E", "㎝(sec)" ], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -29821,6 +30320,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29900,6 +30402,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -29984,6 +30489,9 @@ "E", "㎝(sec)" ], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -30087,6 +30595,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -30166,6 +30678,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "인력 (10%)", @@ -30259,6 +30775,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력 (10%)", @@ -30338,6 +30855,9 @@ "f", "E" ], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": true, "variant_key": [ "A", @@ -30420,6 +30940,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "K(버킷계수)", @@ -30482,6 +31003,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "T(표토두께)", @@ -30592,6 +31116,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "K", @@ -30652,6 +31177,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "V(다짐속도,km/hr)", @@ -30724,6 +31250,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "흡입준비(t1)", @@ -30813,6 +31342,7 @@ "E", "f" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "L", @@ -30904,6 +31434,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "굴착기 (무한궤도, 0.7㎥)", @@ -30977,6 +31508,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부 (인)", @@ -31058,6 +31590,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인력시공", @@ -31124,6 +31657,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인력", @@ -31179,6 +31713,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인력", @@ -31257,6 +31792,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -31322,6 +31858,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -31373,6 +31910,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "굴착기 (무한궤도)", @@ -31449,6 +31987,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "K(버킷계수)", @@ -31518,6 +32057,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "운반비", @@ -31566,6 +32106,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "운반비", @@ -31623,6 +32164,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "구 입", @@ -31671,6 +32213,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "골재생산", @@ -31719,6 +32262,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "운반비", @@ -31767,6 +32311,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "운반", @@ -31930,6 +32477,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "토사", @@ -32018,6 +32566,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부(인)" @@ -32080,6 +32629,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "소 재 (조재목)", @@ -32178,6 +32728,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업반장(인)", @@ -32229,6 +32780,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업반장(인)", @@ -32287,6 +32839,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업반장(인)", @@ -32345,6 +32898,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "차량구분", @@ -32386,6 +32940,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "시간(분)" @@ -32420,6 +32975,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부(인)" @@ -32454,6 +33010,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "연장", @@ -32546,6 +33103,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "연료비", @@ -32606,6 +33166,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "짐내리는 인부", @@ -32682,6 +33245,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "운반대" @@ -32730,6 +33296,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -32809,6 +33376,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트 블 록", @@ -32928,6 +33496,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업반장", @@ -32990,6 +33559,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업반장", @@ -33059,6 +33629,7 @@ "E", "f" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "L", @@ -33183,6 +33754,7 @@ "formula_rows": [ "K" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "K", @@ -33237,6 +33809,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "적재(t1)", @@ -33342,6 +33915,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인원(명)" @@ -33392,6 +33966,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인원(명)" @@ -33432,6 +34007,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "① 드론준비시간(분)", @@ -33501,6 +34079,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "비계공", @@ -33566,6 +34145,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "건축목공", @@ -33614,6 +34194,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "건축목공", @@ -33668,6 +34249,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "부설장비", @@ -33762,6 +34344,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "무근구조물", @@ -33816,6 +34399,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "무근구조물", @@ -33870,6 +34454,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "무근구조물", @@ -33914,6 +34499,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "25", @@ -33988,6 +34574,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "25", @@ -34074,6 +34661,7 @@ "미 장 공" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "미 장 공" @@ -34106,6 +34694,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "무근콘크리트", @@ -34155,6 +34746,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "f₁" @@ -34191,6 +34783,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "Type-Ⅰ", @@ -34236,6 +34829,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "f₁" @@ -34270,6 +34864,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "Type-Ⅰ", @@ -34310,6 +34905,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "시멘트(kg)", @@ -34372,6 +34968,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "설 치", @@ -34425,6 +35022,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "철근공(인)", @@ -34517,6 +35115,7 @@ "박 리 제" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "횟수별", @@ -34655,6 +35254,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "문양 스티로폴(자재비 포함)", @@ -34716,6 +35316,7 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트믹서트럭 직접타설인경우", @@ -34801,6 +35402,9 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "명칭", @@ -34864,6 +35468,7 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -34911,6 +35516,7 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "포장두께(㎝)", @@ -34990,6 +35596,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트(레미콘)", @@ -35084,6 +35691,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트", @@ -35170,6 +35778,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트", @@ -35224,6 +35833,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "유공관 설치", @@ -35361,6 +35973,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "∅800mm", @@ -35504,6 +36117,7 @@ "흄 관" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "∅800mm", @@ -35612,6 +36226,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "절단기", @@ -35692,6 +36307,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "∅800mm", @@ -35800,6 +36416,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트 (레미콘)", @@ -35918,6 +36535,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "콘크리트 (레미콘)", @@ -36020,6 +36638,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "파형강관부설", @@ -36077,6 +36696,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "구체콘크리트 (레미콘)", @@ -36171,6 +36791,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "구체콘크리트 (레미콘)", @@ -36327,6 +36948,7 @@ "보 통 인 부" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "무근콘크리트", @@ -36413,6 +37035,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "구체콘크리트 (철근)", @@ -36492,6 +37115,7 @@ "철 근 공" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "결속선(R=0.9mm)", @@ -36559,6 +37183,9 @@ "철 물" ], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "자재", @@ -36652,6 +37279,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "자재", @@ -36734,6 +37364,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "자재", @@ -36795,6 +37428,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료비", @@ -36843,6 +37477,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -36932,6 +37567,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "뒷채움 자재비 및 운반비 별산", @@ -37065,6 +37701,9 @@ "f", "㎝(sec)" ], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": true, "variant_key": [ "소할(30%)", @@ -37157,6 +37796,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "기계", @@ -37240,6 +37880,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "뒷채움 자재비 및 운반비 별산", @@ -37357,6 +37998,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -37418,6 +38060,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "자재", @@ -37471,6 +38116,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -37532,6 +38178,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료비", @@ -37589,6 +38236,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -37668,6 +38316,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "재료", @@ -37787,6 +38438,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료비", @@ -37835,6 +38487,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료비", @@ -37883,6 +38536,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료", @@ -37945,6 +38599,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -38022,6 +38677,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료비", @@ -38070,6 +38726,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -38155,6 +38812,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "재료비" @@ -38197,6 +38855,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -38258,6 +38917,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "제작비", @@ -38312,6 +38972,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -38382,6 +39043,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "패 널 류 보, 드롭헤드, 강관파이프, 훅  클래프, 웨지핀" @@ -38425,6 +39087,9 @@ "내 부 패 널" ], "formula_rows": [], + "special_glyphs": [ + "x(U+0078)" + ], "capacity_formula_here": false, "variant_key": [ "패 널", @@ -38480,6 +39145,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "요 율" @@ -38524,6 +39190,7 @@ "crew_table": true, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "복 잡", @@ -38578,6 +39245,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "복 잡", @@ -38655,6 +39323,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "규격", @@ -38715,6 +39384,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통인부", @@ -38765,6 +39435,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작업반장", @@ -38833,6 +39504,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "40㎝이상∼60㎝미만", @@ -38885,6 +39560,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인 부", @@ -38944,6 +39620,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "증가율(%)" @@ -38980,6 +39659,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "×(U+00D7)" + ], "capacity_formula_here": false, "variant_key": [ "25㎝(17×17)", @@ -39063,6 +39745,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "35cm 이하", @@ -39127,6 +39810,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "모래 기초다짐", @@ -39199,6 +39885,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "(mm)", @@ -39274,6 +39961,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "골쌓기", @@ -39474,6 +40162,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "35cm 이하", @@ -39538,6 +40227,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "야면석(㎥) 깬잡석(㎥) 깬 돌(㎥) 견치돌(㎥)" @@ -39590,6 +40280,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "골쌓기", @@ -39780,6 +40471,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "야면석(㎥) 호박돌(㎥)", @@ -39836,6 +40528,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "상부의 두께(㎝) 하부의 두께(㎝)" @@ -39872,6 +40567,10 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)", + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "∼1.5", @@ -39918,6 +40617,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "메쌓기", @@ -39996,6 +40696,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "35cm 이하", @@ -40060,6 +40761,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "25㎝", @@ -40123,6 +40825,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "종 별", @@ -40207,6 +40910,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "35cm 이하", @@ -40282,6 +40986,9 @@ "굴 삭 기 (무한궤도)" ], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "직경 40㎝이상 ∼60㎝미만", @@ -40373,6 +41080,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "직경 40㎝이상 ∼60㎝미만", @@ -40464,6 +41174,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "직경 40㎝이상 ~60㎝미만", @@ -40564,6 +41277,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "직경 40㎝이상 ~60㎝미만", @@ -40657,6 +41373,9 @@ "굴 삭 기 (무한궤도)" ], "formula_rows": [], + "special_glyphs": [ + "∼(U+223C)" + ], "capacity_formula_here": false, "variant_key": [ "직경 40㎝이상 ∼60㎝미만", @@ -40748,6 +41467,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "뒷길이 평균 적용" @@ -40798,6 +41518,7 @@ "장 비" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "인 력", @@ -40868,6 +41589,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "직경 15㎝ 길이 4m" @@ -40912,6 +41634,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통 인부 (인)" @@ -40952,6 +41675,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보 통 인 부 (인)" @@ -41010,6 +41734,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "계수" @@ -41052,6 +41777,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "8 9", @@ -41218,6 +41946,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조약돌량(㎥)", @@ -41273,6 +42002,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조립 설치", @@ -41367,6 +42097,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조약돌량(㎥)", @@ -41438,6 +42169,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "조립 설치", @@ -41537,6 +42269,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "특별인부", @@ -41588,6 +42321,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "자재", @@ -41690,6 +42424,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통토사", @@ -41758,6 +42493,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "작 업 반 장", @@ -41802,6 +42538,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "4m 표준", @@ -41873,6 +42612,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보통구조", @@ -41965,6 +42705,7 @@ "E", "㎝(sec)" ], + "special_glyphs": [], "capacity_formula_here": true, "variant_key": [ "인력(10%)", @@ -42030,6 +42771,7 @@ "굴 삭 기" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "식생매트설치", @@ -42089,6 +42831,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "간 단 구 조", @@ -42140,6 +42883,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "단 끊 기", @@ -42203,6 +42947,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "보 통 인 부" @@ -42261,6 +43006,9 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [ + "~(U+FF5E)" + ], "capacity_formula_here": false, "variant_key": [ "어려운 조건", @@ -42302,6 +43050,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "어려운 조건", @@ -42370,6 +43119,7 @@ "굴 삭 기" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "사 면", @@ -42477,6 +43227,7 @@ "보 통 인 부" ], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "폭 1.5m 이하", @@ -42547,6 +43298,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "0.8㎥ 굴착기(우드그랩 부착)", @@ -42598,6 +43350,7 @@ "crew_table": false, "spaced_names": [], "formula_rows": [], + "special_glyphs": [], "capacity_formula_here": false, "variant_key": [ "0.8㎥ 굴착기", From 5755b1b41305b10e1e820d7bf1a770aee604c662 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 05:13:35 +0900 Subject: [PATCH 4/6] =?UTF-8?q?fix(B08):=20=EC=8B=A4=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=ED=86=B5=EA=B3=BC=EC=97=90=EC=84=9C=20=EB=93=9C?= =?UTF-8?q?=EB=9F=AC=EB=82=9C=20=ED=99=94=EB=A9=B4=20=EA=B2=B0=ED=95=A8=20?= =?UTF-8?q?=EC=85=8B=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ㉕ 통과(엔진 실행)에서 잡힌 것. - 준비공 사방공 줄에 개발자 키(`soil_guard`)가 그대로 뜨던 자리 수정. 레지스트리 이름을 받아 쓰고, 키는 `type_id` 칸으로만 오감. 문구표에 사방 시설 이름 넷 추가(레지스트리 값 그대로 옮긴 것). - 좌측 「토사」 비율 칸 제거 — 넣어도 버려지던 죽은 칸. 토사 물량은 토적표 값이 그대로 서고, 비율은 암 총량을 갈래로 나눌 때만 쓰임. - 안분 안내 문구를 「암 갈래 입력 합 …」으로 명시. 칸에 100 을 채운 사용자에게 「입력 합 60 %」로 뜨던 자리. - 항목 라벨을 「암 갈래 구성비(%) — 암 총량 기준」으로 바꿈. 시험: 655 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 이 변경과 무관). 사방공 이름 시험 2건 추가, 키를 화면 이름으로 못 박던 옛 시험 1건 정정. Co-Authored-By: Claude Opus 5 (1M context) --- .../B08_Quantity_Engine_EarthworkSummary.py | 2 +- .../B08_Quantity_Engine_Preparation.py | 20 +++++++++++++++---- B08_Quantity/B08_Quantity_Router_Earthwork.py | 5 ++++- B08_Quantity/B08_Quantity_UI_Page.ts | 5 ++++- B08_Quantity/B08_Quantity_Wording.py | 5 +++++ ui_template/ui_template_locale_b2.ts | 5 ++++- 6 files changed, 34 insertions(+), 8 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Engine_EarthworkSummary.py b/B08_Quantity/B08_Quantity_Engine_EarthworkSummary.py index f3e3eb17..f94daae3 100644 --- a/B08_Quantity/B08_Quantity_Engine_EarthworkSummary.py +++ b/B08_Quantity/B08_Quantity_Engine_EarthworkSummary.py @@ -94,7 +94,7 @@ def _split_by_rock(total: float, source: SummaryInput) -> list[tuple[str, float, given = sum(ratios.values()) if given <= 0: return [("암", total, "")] - note = "" if abs(given - 100.0) < 1e-9 else f"입력 합 {given:g} % → 100 % 로 안분" + note = "" if abs(given - 100.0) < 1e-9 else f"암 갈래 입력 합 {given:g} % → 100 % 로 안분" return [(name, total * ratios[name] / given, note) for name in classes if ratios[name] > 0] diff --git a/B08_Quantity/B08_Quantity_Engine_Preparation.py b/B08_Quantity/B08_Quantity_Engine_Preparation.py index bcb52002..ba97fa77 100644 --- a/B08_Quantity/B08_Quantity_Engine_Preparation.py +++ b/B08_Quantity/B08_Quantity_Engine_Preparation.py @@ -22,6 +22,8 @@ from __future__ import annotations from typing import Any, Iterable +from B08_Quantity.B08_Quantity_Wording import type_label + #: 사방 시설로 보는 구조물 종류 — **레지스트리의 실제 `type_id` 를 쓴다**(D 그룹 + 흙막이). #: 목록에 없으면 그 노선에 사방공이 **없는** 것이다. 이름을 지어내면 영영 안 걸린다. EROSION_CONTROL_TYPES = frozenset( @@ -200,8 +202,16 @@ def _level_frame_row(slope_rows: list[dict[str, Any]]) -> dict[str, Any]: } -def erosion_rows(structures: Iterable[dict[str, Any]] = ()) -> list[dict[str, Any]]: - """사방공 줄 — 이 노선에 사방 시설이 **있을 때만** 값이 선다.""" +def erosion_rows( + structures: Iterable[dict[str, Any]] = (), + names: dict[str, str] | None = None, +) -> list[dict[str, Any]]: + """사방공 줄 — 이 노선에 사방 시설이 **있을 때만** 값이 선다. + + ⚠ 줄 이름은 **레지스트리 이름**을 쓴다 — `type_id` 를 그대로 적으면 화면에 + `soil_guard` 같은 개발자 키가 뜬다(B08 ㉑ 과 같은 병). `names` 가 없으면 + 문구표가 받아 주고, 그것도 없으면 키를 보이되 **지어내지는 않는다**. + """ found = sorted( { str(item.get("type_id")) @@ -224,7 +234,8 @@ def erosion_rows(structures: Iterable[dict[str, Any]] = ()) -> list[dict[str, An return [ { "group": "사방공", - "item": type_id, + "item": type_label(type_id, names), + "type_id": type_id, "unit": "개소", "amount": None, "status": STATUS_PENDING, @@ -240,10 +251,11 @@ def build_table( structures: Iterable[dict[str, Any]] = (), slope_rows: Iterable[dict[str, Any]] = (), topsoil_thickness_m: float | None = None, + names: dict[str, str] | None = None, ) -> dict[str, Any]: """화면·인계가 그대로 쓰는 모양. **못 서는 줄도 목록에 남는다.**""" rows = preparation_rows(slope_totals, slope_rows, topsoil_thickness_m) + erosion_rows( - structures + structures, names ) return { "columns": ["구분", "공종", "단위", "수량", "상태", "사유"], diff --git a/B08_Quantity/B08_Quantity_Router_Earthwork.py b/B08_Quantity/B08_Quantity_Router_Earthwork.py index b6eb40d6..23373193 100644 --- a/B08_Quantity/B08_Quantity_Router_Earthwork.py +++ b/B08_Quantity/B08_Quantity_Router_Earthwork.py @@ -22,6 +22,7 @@ from fastapi.responses import JSONResponse from pydantic import BaseModel from B03_FileInput.B03_FileInput_Repository import get_project_storage_relative_path +from B05_Profile.B05_Profile_Structures_Schema import structure_type_map from B06_Section.B06_Section_Repository import ( get_cross_section_designs, get_longitudinal_section, @@ -99,11 +100,13 @@ async def get_earthwork_table(project_id: UUID, route_id: int) -> JSONResponse: ) ) # 준비공·사방공 — 못 서는 줄도 사유와 함께 남긴다(빈 표는 「빠뜨림」과 구별이 안 됨). + structures = await _route_structures(project_id) table["preparation"] = build_preparation_table( slope.get("totals") or {}, - await _route_structures(project_id), + structures, slope.get("rows") or [], settings.get("topsoil_thickness_m"), + {type_id: definition.name for type_id, definition in structure_type_map().items()}, ) method, method_is_default = concrete_placing_method(settings) # ⚠ 금액에 바로 걸리는 값이라 「기본값으로 돌고 있음」을 응답에 실어 화면이 띄우게 한다. diff --git a/B08_Quantity/B08_Quantity_UI_Page.ts b/B08_Quantity/B08_Quantity_UI_Page.ts index fdf95ad2..2e0413c6 100644 --- a/B08_Quantity/B08_Quantity_UI_Page.ts +++ b/B08_Quantity/B08_Quantity_UI_Page.ts @@ -218,7 +218,10 @@ function buildQuantitySidePanel( panel.append(field(L("B08_Quantity_Side_RockRatios"), "")); for (const name of classes) { // 「암」은 비율을 넣으면 사라지는 되메움 줄이라 비율 칸을 두지 않는다. - if (name !== "암") { + // 「토사」도 비율 칸을 두지 않는다 — 토사 물량은 토적표의 흙깎기 값이 그대로 서고, + // 비율은 **암 총량을 갈래로 나누는 데만** 쓰인다(집계 엔진 `_rock_split`). + // 칸을 두면 넣은 값이 조용히 버려져 「입력 합 60 %」 같은 안내가 뜬다(2026-09-08 통과). + if (name !== "암" && name !== "토사") { panel.append( numberField(name, draft.rock_ratios_pct[name] ?? 0, (value) => { draft.rock_ratios_pct[name] = value; diff --git a/B08_Quantity/B08_Quantity_Wording.py b/B08_Quantity/B08_Quantity_Wording.py index b535dd4e..2ce69b9a 100644 --- a/B08_Quantity/B08_Quantity_Wording.py +++ b/B08_Quantity/B08_Quantity_Wording.py @@ -30,6 +30,11 @@ TYPE_LABELS = { "ford_pavement": "물넘이포장", "ford_bridge": "세월교", "box_culvert": "BOX암거", + # 사방 시설 — 레지스트리 이름 그대로 옮긴 것(2026-09-08 확인). 지어낸 이름 아님. + "erosion_check": "골막이", + "bed_sill": "바닥막이", + "check_dam_small": "소형사방댐(복합형)", + "revetment": "기슭막이", } #: 저장 제원 칸의 사람 이름 + **어디서 채우는지**. 키 이름을 화면에 내보내지 않기 위한 표. diff --git a/ui_template/ui_template_locale_b2.ts b/ui_template/ui_template_locale_b2.ts index 038fb415..c7380d2f 100644 --- a/ui_template/ui_template_locale_b2.ts +++ b/ui_template/ui_template_locale_b2.ts @@ -657,7 +657,10 @@ export const ui_locales_b2 = { B08_Quantity_Ratio_SeedCut: ["초류종자살포(절토면)", "Seed spray (cut)"], B08_Quantity_Ratio_TreeRemoval: ["지장목제거", "Obstacle removal"], B08_Quantity_Side_RockSet: ["암 갈래 세트", "Rock class set"], - B08_Quantity_Side_RockRatios: ["지반 구성비(%)", "Ground composition (%)"], + B08_Quantity_Side_RockRatios: [ + "암 갈래 구성비(%) — 암 총량 기준", + "Rock class split (%) of rock volume", + ], B08_Quantity_Btn_Save: ["저장", "Save"], B08_Quantity_Save_Success: ["산출 조건을 저장했습니다.", "Calculation settings saved."], B08_Quantity_Save_Failed: ["산출 조건을 저장하지 못했습니다.", "Failed to save the settings."], From 3e729439cb5439e87bf6e8f8a18410c5610527fd Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 05:46:12 +0900 Subject: [PATCH 5/6] =?UTF-8?q?fix(B08):=20=EC=9E=90=EA=B8=B0=20=EA=B0=90?= =?UTF-8?q?=EC=82=AC=20=E2=80=94=20=EC=95=88=20=EB=B6=80=EB=A5=B4=EB=8D=98?= =?UTF-8?q?=20=EA=B2=80=EC=82=AC=20=EB=84=B7=20=EC=97=B0=EA=B2=B0=20+=20?= =?UTF-8?q?=ED=91=9C=ED=86=A0=20=EB=91=90=EA=BB=98=20=EC=9E=85=EB=A0=A5=20?= =?UTF-8?q?=EC=B9=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ㉘ 자기 감사. B09 에 겨눈 네 축을 내 것에 그대로 겨눔. 안 부르던 검사 — 시험에서만 불리고 있던 것들을 실제 경로에 이음 - verify_no_code_on_materials · verify_bill_flags → build_handoff 결과에 실음 - check_against_plan → 운반 표 옆에 haul_check 로 실음 (계획이 있을 때만) - 바로 위 주석이 「검사는 실제로 부른다」였는데 형제 둘이 놀고 있었음 표토 두께 — 서버·엔진은 받고 있었는데 화면에 넣을 칸이 없었음 - optionalNumberField 신설 (빈 값 = 「안 정함」, 0 과 구별) - null 을 저장에서 버리던 것 수정 (NULLABLE_SETTING_KEYS) — 한 번 넣으면 「안 정함」으로 못 되돌리던 자리 짝 시험 — 규칙은 있는데 시험이 없던 둘 - REFERENCE_MARKS (41건을 지웠던 그 규칙): 기준표는 잡고 「단 위」는 안 잡는 것을 양쪽으로 박음 - attachments_of: 칸이 있을 때만 줄이 서고 부모와 id 가 갈리는 것 시험: 662 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관) · tsc 오류 0. Co-Authored-By: Claude Opus 5 (1M context) --- B08_Quantity/B08_Quantity_Engine_Handoff.py | 4 ++ B08_Quantity/B08_Quantity_Router_Earthwork.py | 25 ++++++++- B08_Quantity/B08_Quantity_UI_EarthworkGrid.ts | 2 + B08_Quantity/B08_Quantity_UI_Page.ts | 52 +++++++++++++++++++ ui_template/ui_template_locale_b2.ts | 3 ++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/B08_Quantity/B08_Quantity_Engine_Handoff.py b/B08_Quantity/B08_Quantity_Engine_Handoff.py index 94d6e298..35bdea2f 100644 --- a/B08_Quantity/B08_Quantity_Engine_Handoff.py +++ b/B08_Quantity/B08_Quantity_Engine_Handoff.py @@ -775,7 +775,11 @@ def build_handoff( "excluded_row_count": sum(1 for row in work_items if not row["in_bill"]), } # ⚠ 검사는 **실제로 부른다** — 만들어 두고 안 부르면 없는 것과 같다. + # 2026-09-08 ㉘ 자기 감사: 아래 줄 하나만 이어져 있고 형제 둘은 **시험에서만** 불리고 + # 있었다. B09 에서 같은 병(가드 둘이 놀고 있음)을 지적해 놓고 내 쪽도 같았다. result["ratio_math_warnings"] = verify_ratio_math(result) + result["material_code_warnings"] = verify_no_code_on_materials(result) + result["bill_flag_warnings"] = verify_bill_flags(result) return result diff --git a/B08_Quantity/B08_Quantity_Router_Earthwork.py b/B08_Quantity/B08_Quantity_Router_Earthwork.py index 23373193..bcae977f 100644 --- a/B08_Quantity/B08_Quantity_Router_Earthwork.py +++ b/B08_Quantity/B08_Quantity_Router_Earthwork.py @@ -32,6 +32,7 @@ from B08_Quantity.B08_Quantity_Engine_EarthworkSummary import SummaryInput from B08_Quantity.B08_Quantity_Engine_EarthworkSummary import build_table as build_summary_table from B08_Quantity.B08_Quantity_Engine_EarthworkTable import StationArea, build_table from B08_Quantity.B08_Quantity_Engine_HaulSummary import build_table as build_haul_table +from B08_Quantity.B08_Quantity_Engine_HaulSummary import check_against_plan from B08_Quantity.B08_Quantity_Engine_Handoff import load_mapping from B08_Quantity.B08_Quantity_Engine_Preparation import build_table as build_preparation_table from B08_Quantity.B08_Quantity_Engine_HaulSummary import summary_input_rows @@ -85,6 +86,17 @@ async def get_earthwork_table(project_id: UUID, route_id: int) -> JSONResponse: table["haul"] = haul # 운반계획은 [저장]·[확정]에서 정본에 남는 값이다 — 아직 없으면 빈 표가 정직하다. table["haul_available"] = bool(plan) + # ⚠ 검산을 **실제로 부른다** — 무대·도자·덤프 합이 운반계획 총량과 맞는가(8-7 ㉡). + # 2026-09-08 ㉘ 자기 감사: 만들어 두고 시험에서만 부르고 있었다. 값을 막지는 않고 + # 차이만 실어 화면이 띄우게 한다 — 막으면 계획이 없는 정상 상태에서도 멈춘다. + if plan: + check = check_against_plan(haul, plan) + table["haul_check"] = { + "hauled_total_m3": check.hauled_total_m3, + "plan_total_m3": check.plan_total_m3, + "difference_m3": check.difference_m3, + "by_equipment": check.details, + } table["summary"] = build_summary_table( SummaryInput( @@ -189,6 +201,11 @@ class QuantitySettingsBody(BaseModel): topsoil_thickness_m: float | None = None +#: `None` 이 「안 정함」을 뜻하는 칸 — 저장에서 **버리지 않고 그대로 덮어쓴다**. +#: 빈 문자열로 되돌리는 칸(시공법·타설 방식)과 달리 숫자 칸은 되돌릴 값이 `None` 뿐이다. +NULLABLE_SETTING_KEYS = ("topsoil_thickness_m",) + + @router.put("/{project_id}/quantity/settings") async def save_quantity_settings(project_id: UUID, body: QuantitySettingsBody) -> JSONResponse: """산출 조건을 정본에 남긴다 — [저장]이 부르는 자리. @@ -206,6 +223,12 @@ async def save_quantity_settings(project_id: UUID, body: QuantitySettingsBody) - content={"status": "error", "message": "프로젝트 저장 폴더를 찾지 못했습니다."}, ) values = {key: value for key, value in body.model_dump().items() if value is not None} + # ⚠ `None` 을 통째로 버리면 **「안 정함」으로 되돌릴 길이 없다** — 한 번 넣은 값이 + # 영영 남는다(2026-09-08 ㉘ 자기 감사). 시공법·타설 방식은 빈 문자열로 되돌리지만 + # 숫자 칸은 되돌리는 값이 `None` 뿐이라, **화면이 보낸 것**만 골라 살린다. + for key in NULLABLE_SETTING_KEYS: + if key in body.model_fields_set: + values[key] = getattr(body, key) if "concrete_placing_method" in values: method = values["concrete_placing_method"] # 「안 정함」으로 되돌릴 수 있어야 한다 — 빈 값이면 지운다(8-22 ② 와 같은 자리). @@ -225,7 +248,7 @@ async def save_quantity_settings(project_id: UUID, body: QuantitySettingsBody) - _save_quantity, root, values, - ("rock_methods", "material_supply", "concrete_placing_method"), + ("rock_methods", "material_supply", "concrete_placing_method") + NULLABLE_SETTING_KEYS, ) except Exception: logger.exception("B08 설정 저장 실패(쓰기): project_id=%s", project_id) diff --git a/B08_Quantity/B08_Quantity_UI_EarthworkGrid.ts b/B08_Quantity/B08_Quantity_UI_EarthworkGrid.ts index 9825c0e7..be3184cc 100644 --- a/B08_Quantity/B08_Quantity_UI_EarthworkGrid.ts +++ b/B08_Quantity/B08_Quantity_UI_EarthworkGrid.ts @@ -65,6 +65,8 @@ export interface QuantitySettings { material_supply?: Record; /** 콘크리트 타설 방식. `null`·없음이면 **아직 안 정한 것**이고 화면이 기본값 안내를 띄운다. */ concrete_placing_method?: string | null; + /** 표토 두께(m). `null`·없음이면 **안 정한 것**이라 표토제거 줄이 「근거 없음」으로 선다. */ + topsoil_thickness_m?: number | null; } export interface EarthworkTable { diff --git a/B08_Quantity/B08_Quantity_UI_Page.ts b/B08_Quantity/B08_Quantity_UI_Page.ts index 2e0413c6..2b3099d9 100644 --- a/B08_Quantity/B08_Quantity_UI_Page.ts +++ b/B08_Quantity/B08_Quantity_UI_Page.ts @@ -84,6 +84,8 @@ async function saveQuantitySettings(projectId: string, draft: DraftSettings): Pr rock_methods: draft.rock_methods, material_supply: draft.material_supply, concrete_placing_method: draft.concrete_placing_method, + // ⚠ `null` 도 그대로 보낸다 — 「안 정함」으로 되돌릴 길이 있어야 한다(시공법과 같은 규칙). + topsoil_thickness_m: draft.topsoil_thickness_m, }), }, ); @@ -134,6 +136,37 @@ function numberField(label: string, value: number, onInput: (value: number) => v return row; } +/** 비워 둘 수 있는 숫자 칸 — **빈 값은 「안 정함」**이고 0 과 다르다. + * + * ⚠ `numberField` 로 두면 빈 칸이 0 으로 읽혀 「두께 0m」와 「안 정함」이 같아진다. + * 표토제거처럼 **안 정하면 줄이 아예 안 서는** 값은 그 둘을 갈라야 한다. + */ +function optionalNumberField( + label: string, + value: number | null, + step: string, + onInput: (value: number | null) => void, +): HTMLElement { + const row = document.createElement("label"); + row.className = "b08-quantity__field"; + const name = document.createElement("span"); + name.textContent = label; + const input = document.createElement("input"); + input.type = "number"; + input.className = "b08-quantity__input"; + input.min = "0"; + input.step = step; + input.placeholder = L("B08_Quantity_Unset_Placeholder"); + input.value = value === null || value === undefined ? "" : String(value); + // 자동저장은 만들지 않는다 — 입력은 캐시에만 남는다(CLAUDE.md 5장). + input.addEventListener("input", () => { + const text = input.value.trim(); + onInput(text === "" ? null : Number(text)); + }); + row.append(name, input); + return row; +} + /** 타설 방식 표기 — 코드가 아니라 사람이 읽는 이름으로 보인다. */ const PLACING_LABELS: Record = { ready_mixed: "레디믹스트", @@ -182,6 +215,8 @@ interface DraftSettings { rock_methods: Record; // 콘크리트 타설 방식 — `""` 는 「안 정함」이고 저장에서 지워진다. concrete_placing_method: string; + // 표토 두께(m) — `null` 은 「안 정함」. 정해야 표토제거 줄이 선다(품셈 9-15 [주]② 의 T). + topsoil_thickness_m: number | null; // 자재별 관급/사급 — 표 안에서 줄마다 고른 값. material_supply: Record; dirty: boolean; @@ -265,6 +300,22 @@ function buildQuantitySidePanel( } } + // ── 표토 두께 — 정해야 준비공 표토제거 줄이 선다(품셈 9-15 [주]② 의 「T : 표토두께(m)」) ── + // ⚠ 2026-09-08 ㉘ 자기 감사: 서버·엔진은 이 값을 받고 있었는데 **화면에 넣을 칸이 없었다.** + // 「죽은 칸」(넣어도 안 쓰임)의 반대 짝이다 — 쓰이는데 넣을 데가 없던 자리. + panel.append(field(L("B08_Quantity_Side_Topsoil"), "")); + panel.append( + optionalNumberField( + L("B08_Quantity_Side_Topsoil_Label"), + draft.topsoil_thickness_m, + "0.01", + (value) => { + draft.topsoil_thickness_m = value; + draft.dirty = true; + }, + ), + ); + // ── 콘크리트 타설 방식 — ⚠ **금액에 바로 걸리는 값**이라 잠정임을 조용히 두지 않는다 ── panel.append(field(L("B08_Quantity_Side_Placing"), "")); panel.append( @@ -503,6 +554,7 @@ export async function renderB08Quantity(root: HTMLElement): Promise { application_ratios_pct: { ...(stored.application_ratios_pct ?? {}) }, rock_methods: { ...((stored.rock_methods ?? {}) as Record) }, concrete_placing_method: (stored.concrete_placing_method as string) ?? "", + topsoil_thickness_m: (stored.topsoil_thickness_m as number | null) ?? null, material_supply: { ...((stored.material_supply ?? {}) as Record) }, dirty: false, }; diff --git a/ui_template/ui_template_locale_b2.ts b/ui_template/ui_template_locale_b2.ts index 4f4ce8ee..35671a42 100644 --- a/ui_template/ui_template_locale_b2.ts +++ b/ui_template/ui_template_locale_b2.ts @@ -628,6 +628,9 @@ export const ui_locales_b2 = { B08_Quantity_Method_Unset: ["안 정함", "Not set"], B08_Quantity_Method_Ripping: ["긁어내기(암절취)", "Ripping"], B08_Quantity_Method_Blasting: ["터뜨리기(발파암)", "Blasting"], + B08_Quantity_Side_Topsoil: ["표토제거", "Topsoil Removal"], + B08_Quantity_Side_Topsoil_Label: ["표토 두께(m)", "Topsoil thickness (m)"], + B08_Quantity_Unset_Placeholder: ["안 정함", "Not set"], B08_Quantity_Side_Placing: ["콘크리트 타설", "Concrete Placing"], B08_Quantity_Side_Placing_Label: ["타설 방식", "Method"], B08_Quantity_Placing_Unset: ["안 정함(기본값 사용)", "Not set (default)"], From 8ccd577827e7d877f7b8d3f59cc2a8008d520463 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 05:51:55 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix(B08):=20=EB=8F=8C=EC=8C=93=EA=B8=B0=20?= =?UTF-8?q?=EB=A9=B4=EC=A0=81=EC=9D=B4=20=EA=B8=B0=EC=9A=B8=EA=B8=B0=20?= =?UTF-8?q?=EB=AA=AB=EC=9D=84=20=EB=91=90=20=EB=B2=88=20=EB=A8=B9=EB=8D=98?= =?UTF-8?q?=20=EA=B2=83=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ㉘ 자기 감사 후속. 실무 시트의 「돌쌓기 = 정면적 × 1.04」에서 그 1.04 가 곧 기울기 몫임(1:0.3 → √(1+0.3²) = 1.0440). 시트가 반올림해 적은 것을 별도 계수로 오해해 hypot 위에 또 곱하고 있었음. - 돌쌓기·큰돌쌓기 모두 기울기 몫을 한 번만 곱함 - 상수는 지우지 않고 `sheet_check_factor_at_0_3` 으로 성격을 바꿈 — 1:0.3 에서 시트값과 맞는지 대조하는 검산 참고값 - 하드코딩 금지 이유를 주석에 남김: 큰돌쌓기는 「1:0.3 이상」이라 기울기가 바뀌면 1.04 는 틀린 값이 되지만 hypot 은 따라감 값 변화 (실노선): 고임돌 -3.85 % · 야면석 -3.85 % · 물구멍 -3.85 % 막자갈 +3.20 % (입적에서 빼는 몫이 줄어 늘어남 — 식대로임) 시험 - 옛 시험이 덧곱을 계약으로 못 박고 있어 정정 - 거울 시험 추가: 기울기 0.3·0.5·1.0 에서 정면적 × hypot 과 일치 - 시트 대조 추가: 정면적 18.87 → 돌쌓기 19.62, 오차 0.5 % 안 - NULLABLE_SETTING_KEYS 계약 시험 추가 (홑 숫자 칸만 좁게 봄) 곁들여 타설 방식 안내 한 줄 — 고른 값이 아직 금액에 안 닿는다는 사실을 화면에 적음. 인계에 타설 공종 줄을 세울지는 이중계상 확인 뒤 결정. 시험: 666 passed · 24 skipped (B05 코리도 1건 기존 깨짐, 무관) · tsc 오류 0. Co-Authored-By: Claude Opus 5 (1M context) --- .../B08_Quantity_Engine_UnitQuantity.py | 33 ++++++++++++++----- B08_Quantity/B08_Quantity_UI_Page.ts | 7 ++++ ui_template/ui_template_locale_b2.ts | 4 +++ 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py b/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py index 214aedfe..0f656b00 100644 --- a/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py +++ b/B08_Quantity/B08_Quantity_Engine_UnitQuantity.py @@ -58,7 +58,14 @@ DEFAULT_BACK_LENGTH_CM = 45 # 돌쌓기 전개식의 상수 — 실무 수식에 박혀 있던 값을 뺀 것. STONE_MASONRY = { - "face_to_slope_factor": 1.04, # 돌쌓기 면적 = 정면적 × 1.04 (비탈 기울기 몫) + # ⚠ **곱하는 값이 아니라 검산 참고값이다** (2026-09-08 ㉘ 에서 고침). + # 실무 시트의 「돌쌓기 = 정면적 × 1.04」에서 그 1.04 가 **곧 기울기 몫**이다 + # (1:0.3 → √(1+0.3²) = 1.0440 ≈ 1.04). 시트가 반올림해 적은 것을 우리가 + # **별도 계수로 오해해 `hypot` 위에 또 곱하고 있었다** — 면적이 4 % 부풀었고 + # 그 면적이 고임돌·야면석·채움콘크리트·모르터·물구멍 **전부의 밑수**였다. + # ⚠ 하드코딩하면 안 되는 값이다 — 큰돌쌓기는 「1:0.3 **이상**」이라 기울기가 + # 바뀔 수 있고, 그때 1.04 는 틀린 값이 되지만 `hypot` 은 따라간다. + "sheet_check_factor_at_0_3": 1.04, # 1:0.3 에서 시트값과 맞는지 대조하는 자리 "thickness_base_m": 0.45, # 평균두께 식의 밑돌 두께 "thickness_top_coeff": 0.10, # 상부 두께 계수 (0.45 + 0.10·H) "thickness_bottom_coeff": 0.40, # 하부 두께 계수 (0.45 + 0.40·H) @@ -178,7 +185,9 @@ BOULDER_DIAMETERS = ("40~60", "60~80", "80~100") #: 큰돌쌓기 전개 상수. **재료 원단위는 품셈에 없다** — 13-6 [주]⑦ 「재료량은 설계수량을 적용한다」. #: 그래서 여기서 내는 것은 **면적과 터파기 계열까지**이고 큰돌 자체는 미확보로 둔다. BOULDER_MASONRY = { - "face_to_slope_factor": 1.04, # 돌쌓기 면적 = 정면적 × 1.04 (13-4 와 같은 기울기 몫) + # ⚠ 검산 참고값 — 곱하지 않는다. 까닭은 `STONE_MASONRY` 의 같은 칸 주석을 볼 것. + # 큰돌쌓기는 전면 기울기가 「1:0.3 **이상**」이라 특히 하드코딩하면 안 된다. + "sheet_check_factor_at_0_3": 1.04, "excavation_extra_m": 0.2, # 터파기 폭 여유 "backfill_thickness_m": 0.2, # 되메우기 두께 } @@ -221,8 +230,8 @@ def boulder_masonry( slope_ratio = _num(options.get("face_slope_ratio"), 0.3) # 레지스트리에 칸 없음 — 기본 0.3 constants = BOULDER_MASONRY face_area = height_m * length_m - slope_area = face_area * math.hypot(1.0, slope_ratio) - masonry_area = slope_area * constants["face_to_slope_factor"] + # 기울기 몫은 **한 번만** — 13-4 와 같은 자리다(㉘). + masonry_area = face_area * math.hypot(1.0, slope_ratio) components = [ Component( @@ -230,7 +239,7 @@ def boulder_masonry( "㎡", masonry_area, DESTINATION["돌쌓기"], - f"비탈면적 × 1.04 · 직경 {diameter}㎝ (품셈 13-6)", + f"정면적 × √(1+{slope_ratio}²) · 직경 {diameter}㎝ (품셈 13-6)", ) ] @@ -300,9 +309,9 @@ def stone_masonry( constants = STONE_MASONRY face_area = height_m * length_m # 정면적 - # 비탈면적 = 정면적 × √(1+n²) — 기울어진 만큼 길어진다. - slope_area = face_area * math.hypot(1.0, slope_ratio) - masonry_area = slope_area * constants["face_to_slope_factor"] + # 돌쌓기 면적 = 정면적 × √(1+n²) — 기울어진 만큼 길어진다. **기울기 몫은 한 번만.** + # 실무 시트의 「정면적 × 1.04」가 바로 이 값이다(1:0.3 에서 1.0440 ≈ 1.04). + masonry_area = face_area * math.hypot(1.0, slope_ratio) thickness = ( (constants["thickness_base_m"] + constants["thickness_top_coeff"] * height_m) + (constants["thickness_base_m"] + constants["thickness_bottom_coeff"] * height_m) @@ -310,7 +319,13 @@ def stone_masonry( volume = face_area * thickness # 입적 components = [ - Component("돌쌓기", "㎡", masonry_area, DESTINATION["돌쌓기"], "비탈면적 × 1.04"), + Component( + "돌쌓기", + "㎡", + masonry_area, + DESTINATION["돌쌓기"], + f"정면적 × √(1+{slope_ratio}²) — 비탈면적", + ), Component( "고임돌", "㎥", diff --git a/B08_Quantity/B08_Quantity_UI_Page.ts b/B08_Quantity/B08_Quantity_UI_Page.ts index 2b3099d9..2ede41d7 100644 --- a/B08_Quantity/B08_Quantity_UI_Page.ts +++ b/B08_Quantity/B08_Quantity_UI_Page.ts @@ -352,6 +352,13 @@ function buildQuantitySidePanel( placing.is_default ? `${label} (${L("B08_Quantity_Placing_Default_Tag")})` : label, ), ); + // ⚠ 고른 값이 **아직 금액에 안 닿는다**는 사실을 숨기지 않는다(2026-09-08 ㉘). + // 인계가 타설 공종 줄을 아직 안 세운다 — B09 일위대가가 타설 품을 이미 갖고 있는지 + // 확인되기 전까지는 세우면 같은 콘크리트를 두 번 센다(이중계상 ㉢ 과 같은 자리). + const pending = document.createElement("p"); + pending.className = "b08-quantity__note"; + pending.textContent = L("B08_Quantity_Placing_NotApplied"); + panel.append(pending); } // ⚠ 「정하면 얼마나 달라지는지」까지 보여야 사용자가 판단한다. 이 값은 **참고 표시 전용**이고 // B08 의 어떤 계산에도 안 들어간다(금액은 B09 몫). diff --git a/ui_template/ui_template_locale_b2.ts b/ui_template/ui_template_locale_b2.ts index 35671a42..b25bbbb4 100644 --- a/ui_template/ui_template_locale_b2.ts +++ b/ui_template/ui_template_locale_b2.ts @@ -628,6 +628,10 @@ export const ui_locales_b2 = { B08_Quantity_Method_Unset: ["안 정함", "Not set"], B08_Quantity_Method_Ripping: ["긁어내기(암절취)", "Ripping"], B08_Quantity_Method_Blasting: ["터뜨리기(발파암)", "Blasting"], + B08_Quantity_Placing_NotApplied: [ + "⚠ 이 선택은 아직 금액에 반영되지 않습니다 — 견적의 일위대가가 타설 품을 이미 갖고 있는지 확인 중입니다.", + "Not yet applied to cost — checking whether the unit-price already covers placing labour.", + ], B08_Quantity_Side_Topsoil: ["표토제거", "Topsoil Removal"], B08_Quantity_Side_Topsoil_Label: ["표토 두께(m)", "Topsoil thickness (m)"], B08_Quantity_Unset_Placeholder: ["안 정함", "Not set"],