feat(b08): 안 고른 돌쌓기 뒷길이를 품셈 13-4-4 [주]⑩ 뒷길이 표준 하한으로 — 범위 안 첫 규격(메 ~3m 36→45) · 전개·양식·구조물도 한 벌 · 사유에 원문 줄 번호(B1)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"dataset_id": "masonry_back_length_standard",
|
||||
"effective_date": "2026-01-01",
|
||||
"note": "돌쌓기 뒷길이 표준 — **높이 × 메/찰** 로 범위가 갈린다. 뒷길이를 안 고른 돌쌓기는 붙박이 45㎝ 로 서고 있었는데, 그 자리를 이 표의 **하한**으로 바꿈(2026-09-14 브레인 판정). 사용자가 칸에서 고르면 그 값이 이김.",
|
||||
"source": {
|
||||
"doc": "산림사업 표준품셈(산림청고시 제2025-82호) 13-4-4 [주]⑩ <뒷길이 표준>",
|
||||
"line": "원문 L7172~7181",
|
||||
"quote": "높은 메쌓기는 밑으로 내려갈수록 뒷길이를 길게 하는 것이 원칙이다 · 높이는 첨단으로부터 기준 한다 · 특수한 조건에서는 본 기준과 달리 적용할 수 있다"
|
||||
},
|
||||
"policy": {
|
||||
"suggestion": "⭐ 제안값 = **범위 안에 드는 품셈 규격 중 가장 작은 것**(브레인 판정 ㉮). 하한이 규격(25·30·35·45·55·60·75)에 없으면 그 위 첫 규격 — 메쌓기 ~3m·~5m 하한 36㎝ 는 45㎝. 35 로 내리면 품셈 범위 아래로 나가 안 됨.",
|
||||
"boundary": "⚠ 원문 표기 `∼1.5 · ∼3 · ∼5 · ∼7 · 7이상` — 표준경사 표(`masonry_slope`)와 같이 「∼」를 **이하**로 읽어 경계값은 앞 칸(높이 3.0m → `~3` 칸).",
|
||||
"no_write_back": "⚠ 제안값을 저장에 박지 않음 — 「안 고름」과 「45 로 고름」이 구별돼야 함(표준경사와 같은 자리)."
|
||||
},
|
||||
"steps_m": [1.5, 3.0, 5.0, 7.0],
|
||||
"table_cm": {
|
||||
"메쌓기": [
|
||||
[25, 35],
|
||||
[36, 45],
|
||||
[36, 60],
|
||||
[45, 75],
|
||||
[75, null]
|
||||
],
|
||||
"찰쌓기": [
|
||||
[25, 35],
|
||||
[30, 35],
|
||||
[35, 45],
|
||||
[35, 55],
|
||||
[45, 60]
|
||||
]
|
||||
},
|
||||
"not_here": {
|
||||
"note": "이 표가 쓰지 않는 칸.",
|
||||
"items": [
|
||||
"돌붙이기 열(메 25~60 · 찰 20~40)은 높이로 안 갈림 — 바닥막이 돌붙임은 뒷길이가 붙박이(`_UnitQuantity_Revetment.BED_SILL_FORMS`)라 여기서 안 씀",
|
||||
"골막이는 뒷길이 기본이 종전대로 45㎝ — 이 표의 대상(돌쌓기 13-4)이 아님"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,13 @@
|
||||
"source": "judged_face_slope",
|
||||
"note": "사용자 값이 있으면 그 값, 없으면 품셈 13-4-4 [주]⑪ 표준경사를 전개가 판정해 넘김"
|
||||
},
|
||||
"L3": { "label": "뒷길이(㎝)", "option": "back_len_cm", "default": 45 },
|
||||
"L3": {
|
||||
"label": "뒷길이(㎝)",
|
||||
"option": "back_len_cm",
|
||||
"default": 45,
|
||||
"default_from": "standard_back_length",
|
||||
"note": "안 고르면 품셈 13-4-4 [주]⑩ 뒷길이 표준 하한(높이·메/찰 · 범위 안 가장 작은 규격) — 전개와 한 벌(2026-09-14 브레인 판정 ㉮). 45 는 표를 못 읽을 때만"
|
||||
},
|
||||
"돌종류": { "label": "돌 종류", "option": "stone_kind", "default": "" },
|
||||
"계수기준": { "label": "야면석 계수", "option": "stone_coeff_basis", "default": "" },
|
||||
"TOP_IN": {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""뒷길이 표준(품셈 13-4-4 [주]⑩) — 안 고른 돌쌓기의 뒷길이는 **표의 하한** (2026-09-14 브레인 판정 ㉮).
|
||||
|
||||
앞서 붙박이 45㎝ 로 섰음. 표는 높이 × 메/찰 로 범위를 줌 — 하한이 규격(25·30·35·45·55·60·75)에
|
||||
없으면 **범위 안 그 위 첫 규격**(메쌓기 ~3m·~5m 하한 36 → 45). 경계값은 앞 칸(표준경사와 같음).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from B08_Quantity.B08_Quantity_Engine_UnitQuantity_StoneSpec import ( # noqa: E402
|
||||
_back_length,
|
||||
back_length_default_note,
|
||||
standard_back_length,
|
||||
)
|
||||
|
||||
# (높이, 메쌓기 제안, 찰쌓기 제안) — 원문 L7174~7177
|
||||
CELLS = [
|
||||
(1.0, 25, 25),
|
||||
(1.5, 25, 25), # 경계값은 앞 칸
|
||||
(2.5, 45, 30), # 메 36~45 → 45 · 찰 30~35 → 30
|
||||
(3.0, 45, 30),
|
||||
(4.0, 45, 35), # 메 36~60 → 45 · 찰 35~45 → 35
|
||||
(6.0, 45, 35), # 메 45~75 · 찰 35~55
|
||||
(7.5, 75, 45), # 메 75이상 · 찰 45~60
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("height, dry, wet", CELLS)
|
||||
def test_표_하한(height: float, dry: int, wet: int) -> None:
|
||||
assert standard_back_length(wet=False, height_m=height)[0] == dry
|
||||
assert standard_back_length(wet=True, height_m=height)[0] == wet
|
||||
|
||||
|
||||
def test_하한이_규격에_없으면_그_위_첫_규격_사유() -> None:
|
||||
cm, basis = standard_back_length(wet=False, height_m=2.5)
|
||||
assert cm == 45
|
||||
assert "36~45㎝" in basis and "하한 36㎝ 는 규격 일곱(원문 L7152)에 없어" in basis
|
||||
assert "원문 L7172~7181" in basis # 사용자가 되짚을 줄 번호(브레인 2026-09-14)
|
||||
|
||||
|
||||
def test_고른_값이_이긴다() -> None:
|
||||
assert _back_length({"back_len_cm": "55"}, wet=True, height_m=2.5) == 55
|
||||
assert back_length_default_note({"back_len_cm": 55}, 55, wet=True, height_m=2.5) is None
|
||||
|
||||
|
||||
def test_메찰_높이를_모르는_자리는_종전_45() -> None:
|
||||
assert _back_length({}) == 45
|
||||
assert "기본 45㎝" in (back_length_default_note({}, 45) or "")
|
||||
@@ -38,6 +38,9 @@ def _structures() -> list[dict]:
|
||||
"length_m": 10,
|
||||
"foundation": "기초유",
|
||||
"stone_kind": "야면석·호박돌",
|
||||
# 2026-09-14 — 안 고르면 뒷길이 표준 하한(찰 ≤3m 30㎝)이라 야면석 관측 무게(35·45·55)가
|
||||
# 없어 돌 줄이 안 섬. 돌 줄을 보는 시험이라 45 로 고름 · 빈 칸 길은 아래 시험.
|
||||
"back_len_cm": 45,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -76,6 +79,21 @@ def test_양식_갈음은_값을_안_움직인다() -> None:
|
||||
assert stone["source"] == "uljin_library"
|
||||
|
||||
|
||||
def test_뒷길이_안_고르면_양식도_전개와_같은_표준_하한() -> None:
|
||||
"""품셈 13-4-4 [주]⑩ 하한(찰 ≤3m 30㎝)을 전개와 양식이 한 벌로 씀(브레인 판정 ㉮)."""
|
||||
structures = _structures()[:1]
|
||||
structures[0]["options"].pop("back_len_cm")
|
||||
structures[0]["options"].pop("stone_kind")
|
||||
names = {"masonry_wet": "돌쌓기(찰)"}
|
||||
before = build_table(structures, names, None, None, 0.2, use_templates=False)["structures"][0]
|
||||
after = build_table(structures, names, None, None, 0.2)["structures"][0]
|
||||
assert after["library_item"] == "돌쌓기(찰)"
|
||||
assert [c["name"] for c in after["components"]] == [c["name"] for c in before["components"]]
|
||||
for got, want in zip(after["components"], before["components"]):
|
||||
assert got["amount"] == pytest.approx(want["amount"], rel=1e-9, abs=1e-12), got["name"]
|
||||
assert any("하한 30㎝" in note for note in before["notes"])
|
||||
|
||||
|
||||
def test_자재총괄_갈래와_배합_성분() -> None:
|
||||
names = {"masonry_wet": "돌쌓기(찰)", "masonry_dry": "돌쌓기(메)"}
|
||||
before = build_material_table(
|
||||
|
||||
@@ -89,7 +89,9 @@ def test_기본값으로_그린_장은_표_사유와_같은_말을_적는다() -
|
||||
options = {"height_m": 2.0}
|
||||
_rows, table_notes = stone_masonry(2.0, 1.0, options, wet=False)
|
||||
table_default = [note for note in table_notes if "뒷길이를 안 골라" in note]
|
||||
assert table_default == [back_length_default_note(options, 45)]
|
||||
# 2026-09-14 — 기본은 뒷길이 표준 하한(메 ≤3m 36~45㎝ → 45) · 표·그림이 같은 말.
|
||||
assert table_default == [back_length_default_note(options, 45, wet=False, height_m=2.0)]
|
||||
assert "하한 36㎝ 는 규격 일곱" in table_default[0]
|
||||
|
||||
texts = _texts(build_figure(_sheet()))
|
||||
assert table_default[0] in texts
|
||||
|
||||
@@ -61,7 +61,16 @@ CASES = [
|
||||
dict(height=2.0, length=7.5, back_len_cm=45, face_slope_ratio=0.35, foundation="기초유"),
|
||||
dict(height=2.0, length=10.0, back_len_cm=55, thickness_top_m=0.9, foundation="기초버림"),
|
||||
dict(height=2.0, length=10.0, back_len_cm=45, thickness_bottom_m="1.4", stone_kind="깬잡석"),
|
||||
dict(height=2.0, length=10.0, stone_kind="야면석·호박돌", stone_coeff_basis="실무 관행"),
|
||||
# 뒷길이 45 — 안 고르면 표준 하한 30㎝ 라 야면석 관측 무게(35·45·55)가 없어 양식만 오류 줄(명세 13장 Ⓐ)
|
||||
dict(
|
||||
height=2.0,
|
||||
length=10.0,
|
||||
back_len_cm=45,
|
||||
stone_kind="야면석·호박돌",
|
||||
stone_coeff_basis="실무 관행",
|
||||
),
|
||||
# 뒷길이 안 고름 — 전개·양식이 같은 표준 하한(찰 ≤3m 30㎝, 브레인 판정 ㉮)
|
||||
dict(height=2.0, length=10.0, stone_kind="깬돌", foundation="기초유"),
|
||||
dict(height=1.5, length=10.0, back_len_cm=35, weep_hole_area_m2=3, foundation="기초유"),
|
||||
dict(height=2.5, length=12.0, back_len_cm=60, stone_kind="견치돌", rubble=0.3),
|
||||
# 줄이 안 서는 갈래 — `when`
|
||||
|
||||
@@ -125,7 +125,8 @@ def test_실무_시트_m당_값_재현() -> None:
|
||||
품셈 1-2-2 의 소수 자리는 표기 규칙이고 계산은 전정밀로 둔다(PLAN 8-16).
|
||||
맞추려고 식을 비틀지 않는다 — 허용오차를 그 차이만큼 둔다.
|
||||
"""
|
||||
result = expand(돌쌓기찰(height=1.5, length=1.0))
|
||||
# 실무 시트가 뒷길이 45 — 2026-09-14 부터 안 고르면 표준 하한(찰 ≤1.5m 25㎝)이라 고름.
|
||||
result = expand(돌쌓기찰(height=1.5, length=1.0, back_len_cm=45))
|
||||
assert result.height_m == 1.5
|
||||
assert result.length_m == 1.0
|
||||
assert 성분(result, "터파기").amount == pytest.approx(1.55, abs=0.02)
|
||||
@@ -135,7 +136,7 @@ def test_실무_시트_m당_값_재현() -> None:
|
||||
|
||||
def test_평균두께는_전정밀로() -> None:
|
||||
"""실무가 0.83 으로 반올림해 재계산한 자리 — 우리는 0.825 를 그대로 쓴다."""
|
||||
result = expand(돌쌓기찰(height=1.5, length=1.0))
|
||||
result = expand(돌쌓기찰(height=1.5, length=1.0, back_len_cm=45))
|
||||
# 터파기 = 높이 × (평균두께 + 0.2) × 연장 = 1.5 × 1.025 = 1.5375
|
||||
assert 성분(result, "터파기").amount == pytest.approx(1.5375)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user