fix(844-1): 켜쌓기율 셈 차례 = 수량 × 율 → 끝수(문서 셈 · B09 와 같게) · 값 달라진 시험 가름

- 흠: run_line 켜쌓기율 = 줄 0.1 원 버림 뒤 × 율 · 다시 버림 → 문서 셈 · B09(raw) 와 1 ~ 2 원 어긋남(GC000261 율 90 노무비 48,364 대 48,365 · 840-5 앞에도 율 400 갈래 중 GC000260 59 · GC000261 109 갈래 다름) · 고친 뒤 0
- 율 100 · 없음 · B09 raw 길 안 바뀜 · 빌더 1,520 --check 같음 · 840-5 직후 대 지금 표본 20,393 다름 0

낡은 시험 고침:
- 728_2 사석 수상고르기 44,791.1 → 48,851.7 · 725_1 GF000099 서울 5,295 → 5,660 — 840-5 조종원 1/8 × 16/12 × 25/20(굴착기 시간당 노무비 35,412 → 59,020)만
- 715 사전조합 SK 넣기 — 811-1 뒤 SK 줄 = 참조 한 행 · 쓰는 SK 지우기 막음
- 717_3 화면_이음 지움 — 소스 글자만 보는 시험

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-15 21:25:15 +09:00
co-authored by Claude Opus 5.5
parent b88b5e164a
commit 502fd766d9
5 changed files with 10 additions and 43 deletions
+3 -3
View File
@@ -548,8 +548,8 @@ def run_line(
logic = whole.logic(code)
auto = {k: v for k, v in m01.mau.values(whole, logic).items() if v is not None}
with mf.mp.choosing(picks):
got = mf.run(whole, code, {**auto, **m01._dec(given or {})})
got = layered(got if raw else mcut.engine(whole, code, got), rate)
got = layered(mf.run(whole, code, {**auto, **m01._dec(given or {})}), rate)
got = got if raw else mcut.engine(whole, code, got) # 율 곱 → 끝수(문서 셈 · 844-1)
except (mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueError) as e:
return {"기준": None, "까닭": str(e) or type(e).__name__}
if "결과" in got:
@@ -559,7 +559,7 @@ def run_line(
mats = logic_mats(whole, logic, got["줄"], picks)
lines = pct_extras(whole, logic, got["줄"], got.get("중간") or {})
out = {"기준": money, "줄": lines, "재료": mats, "까닭": None, **mcut.kept(got)}
return out if raw or rate in (None, 100) else mcut.plain(out) # 켜쌓기율 곱 뒤 다시 버림
return out
def pct_extras(whole: Any, logic: dict, lines: list[dict], env: dict) -> list[dict]:
+4 -3
View File
@@ -126,7 +126,7 @@ def test_chain_base_flattened_delete_free(world):
def test_precombo_holds_sangeun(world):
"""사전조합에 SK 넣기(740-1) = 로직 줄 + 패치(SK 몸) · 1 단위 값 × 수량 · SK 지워도 그대로."""
"""사전조합에 SK 넣기(811-1) = SK 참조 한 행 · 1 단위 값 × 수량 · 쓰는 SK 는 못 지움."""
from M02_MasterTemplete import M02_Labor_Doc as labor
sk = _sk(world["personal"], 바탕={"로직": PCT}, 덮개={"labor:LB000036#0": {"qty": 0.5}})
@@ -141,8 +141,9 @@ def test_precombo_holds_sangeun(world):
},
)["이름"]
line = store.read("precombo", sc)["문서"]["담은로직"][0]
assert line["로직"] == PCT and line["패치"]["덮개"] and line["본뜬"]["키"] == sk
store.delete("sangeun", sk)
assert line["참조"] == {**MINE, "키": sk} # 811-1 SK 줄 = 참조 한 행(안 펼침)
with pytest.raises(store.StoreError, match="쓰는 곳"):
store.delete("sangeun", sk)
pill = {f"{refs.ref_id({**MINE, '키': sc})}#0": 2} # 723-1 안 줄 수량 = 쓰는 쪽 알약
got = labor.calc({"담은로직": [{"참조": {**MINE, "키": sc}, "수량": {"손": 1}}]}, pill)
assert got["반영합"]["계"] == pytest.approx(one * 2, abs=1)
@@ -9,7 +9,6 @@
"""
import json
import re
import shutil
import subprocess
from pathlib import Path
@@ -25,7 +24,6 @@ from M02_MasterTemplete import M02_Sangeun_Doc as sd
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 같은 임시 층
ROOT = Path(__file__).resolve().parents[2]
M02 = ROOT / "M02_MasterTemplete"
PCT = "GC001109" # 원/㎡ · 인력 둘 + 「노무비 * 3 / 100」
TWO_MATS = "GC000565" # 원/m · 재료 줄 둘
COVER = {"덮개": {"labor:LB000036#0": {"qty": 0.5}}}
@@ -151,36 +149,3 @@ def test_normalizeLabor_줄_패치_지킴():
assert got.returncode == 0, got.stderr
rows = json.loads(got.stdout)["담은로직"]
assert rows[0]["패치"] == COVER and "패치" not in rows[1]
def test_화면_이음():
"""806-1 — 조합 일위대가도 일위대가표 한 부품 · 단가산출(SK) 줄 = 그 SK 문서 모달(`Labor_SkEdit`) · 옛 조합 전용
단가산출 보기 모달 걷음 · 셈 주입(프로젝트 복사본)엔 옛 줄 모달 · 고친 것 있이 닫으면 물음 · 700 줄."""
detail = (M02 / "M02_MasterTemplete_Labor_Detail.ts").read_text("utf-8")
assert "return mountLaborTable(host, doc, opt);" in detail
assert not (M02 / "M02_MasterTemplete_Labor_SangeunModal.ts").exists()
table = (M02 / "M02_MasterTemplete_Labor_Table.ts").read_text("utf-8")
assert "if (isSkRef(row.참조) && !opt.calc)" in table and "openSkEdit({" in table
assert "readOnly: !edit || row.참조.층 !== opt.layer," in table # 위 층 SK = 읽기만
assert "closed: (done) => alive && done && recalc()," in table # 저장했으면 금액 다시 셈
modal = (M02 / "M02_MasterTemplete_Labor_SkEdit.ts").read_text("utf-8")
assert "mountSangeunDetail(host, doc," in modal and "source: true" in modal
assert re.search(
r'saveTemplate\(\s*layer,\s*"sangeun",\s*opt\.ref\.키', modal
) # 저장 = 그 SK 문서(그 층 · 그 주인)
assert "await handle.flush();" in modal # 수식 저장 먼저
assert "dirty && !saved && !(await showConfirmDialog(" in modal # 고친 것 물음
sk = (M02 / "M02_MasterTemplete_Labor_RowSk.ts").read_text("utf-8")
assert '{ layer: "personal", owner: null }' in sk
cover = (M02 / "M02_MasterTemplete_Sangeun_Cover.ts").read_text("utf-8")
assert "/sangeun/calc" in cover and "/sangeun/from-line" in cover
assert "coverTable" not in cover and not (M02 / "M02_Sangeun_Cover_Model.ts").exists()
for name in (
"M02_MasterTemplete_Labor_Rows.ts",
"M02_MasterTemplete_Labor_Table.ts",
"M02_MasterTemplete_Labor_Combo.ts",
"M02_MasterTemplete_Labor_SkEdit.ts",
"M02_MasterTemplete_Sangeun_Cover.ts",
"logic/M02_Sangeun_Cover_Model.ts",
):
assert len((M02 / name).read_text("utf-8").splitlines()) <= 700, name
@@ -104,7 +104,7 @@ def test_no_base_common_option_seoul(world): # noqa: F811
assert got["빠진줄"] == [], got
assert got["기준"], {k: v for k, v in got.items() if k != "줄"}
assert got["기준"]["계"] == pytest.approx(_m01(GF, {"지역": "서울", "보정작업": "해당 없음"}))
assert float(got["기준"]["계"]) == 5295 # 751-3 끝수(옛 날 값 5,297.37)
assert float(got["기준"]["계"]) == 5660 # 751-3 끝수 · 840-5 굴착기 조종원 35,412 → 59,020/시간
def test_screen_no_base_inputs_and_gap_dash():
+2 -1
View File
@@ -51,7 +51,8 @@ def test_단목베기_100본_제안_본으로_바꾸면_1본_계(whole):
def test_사석_수상고르기_10제곱미터_에서_1제곱미터(whole):
one = _shown(whole, _doc("GC000421", "㎡"))
assert one["기준"]["계"] == Decimal("44791.1") # 10㎡ 447,911(1 원 버림) ÷10
# 10㎡ 488,517(1 원 버림) ÷10 — 굴착기 조종원 시간당 283,296 × 5/24 = 59,020(840-5) × 1.72
assert one["기준"]["계"] == Decimal("48851.7")
def test_성격_다르면_계수_칸_없으면_셈_막음(whole):