From 1ecb5f02a46e12f65869c591b97247baabb8d5e1 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 22 Sep 2026 18:34:00 +0900 Subject: [PATCH] =?UTF-8?q?knowledge(=EB=8B=A8=EA=B0=80=EC=82=B0=EC=B6=9C)?= =?UTF-8?q?:=20=EC=9D=B4=EB=A6=84=20=EC=8B=9D=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EC=97=86=EC=9D=B4=20=EB=A7=8C=EB=93=A4=EA=B8=B0=20=EB=B6=84?= =?UTF-8?q?=EC=84=9D=20=E2=80=94=20=EB=A7=8C=EC=95=BD=20=EA=B2=B9=EC=B9=A8?= =?UTF-8?q?=C2=B7=EB=A1=9C=EC=A7=81=20=EB=B9=84=EB=AA=A9=20=EB=AF=B8?= =?UTF-8?q?=EC=A0=95=C2=B7=EB=A9=88=EC=B6=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=8B=A4=EC=88=98=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ --- .../master_data/ref/_분석_이름식_계산없이.md | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 resources/master_data/ref/_분석_이름식_계산없이.md diff --git a/resources/master_data/ref/_분석_이름식_계산없이.md b/resources/master_data/ref/_분석_이름식_계산없이.md new file mode 100644 index 00000000..ff60cdd1 --- /dev/null +++ b/resources/master_data/ref/_분석_이름식_계산없이.md @@ -0,0 +1,143 @@ +# 분석 — 텍스트 수식의 이름 식, 계산 없이도 만들기 + +검토만 · 코드 안 고침. `master_text.py`·`master_formula.py`·`master_copy.py` 읽기와 +실제 데이터(`resources/master_data/로직_*.json`) 전수 확인으로 뒷받침. + +## 0. 사용자 안 + +- 지금: 만약() 조건을 실제로 셈해 걸린 가지만 이름 식에 적음(`named()`의 `만약` 분기). +- 사용자 안: 계산이 안 되면 양쪽 가지를 다 보이고, 계산이 되면 지금처럼 걸린 가지만 보임. + +## ① 이름 식 만드는 자리 — 만약() 말고 계산이 필요한 곳 전수 확인 + +코드를 따라가 보면 `named()`(이름 꼴을 만드는 함수) 안에서 실제 값 계산(`mf.evaluate`)을 +부르는 자리는 딱 하나 — **만약() 조건 판정** 뿐임. 나머지는 계산 없이도 그대로 됨: + +- 요소 이름(석공 노임 같은 것) — 표의 `이름` 칸을 그냥 읽음. 계산 아님. +- 별칭(표 찾기·로직 부르기 이름, QF000421 → 메쌓기인력 같은 것) — `aliases()`가 식 글자를 + 그대로 훑어 별칭을 짓는 것도 계산 아님. 실행 전에 이미 다 지을 수 있음. +- 중간 값·덧줄 이름(증가율·노무비 같은 것) — 그 이름 글자를 그대로 적을 뿐, 값을 몰라도 됨. +- 끝수 — 대상·자리·방법을 적는 한 마디일 뿐, 계산이 아니라 규칙을 읽는 것. + +**그런데 전수로 데이터를 훑어 보니, 만약() 말고 계산이 정말 필요한 자리가 두 곳 더 있음** — +브레인이 짚은 것보다 큼: + +**(가) 원문번호에 `{이름}` 홀이 낀 요소 참조.** 예 — `EQ:{장비}`, `MT:{합판}`, `LB:{용접직종}`, +`MO:휘발유:{지역}`. 이런 자리는 표의 어느 줄을 가리키는지부터 그 홀 값(대개 입력, 가끔 중간 +값)을 알아야 정해짐 — 모르면 이름 대신 `LB000123:{용접직종}` 같은 날 것 키만 보임(지금 +`_elem_name` 이 실패하면 원문 그대로 돌려주는 자리가 이미 있음 — 보기 좋은 이름을 못 만들 +뿐 죽지는 않음). **14개 파일·13가지 홀 이름**(장비·합판·각재·용접직종·지역·직종 등)에서 씀. +확인해 보니 예를 들어 `EQ:{장비}`의 `장비`는 **중간 값**(GC000138 등)이라 홀 하나를 풀려 해도 +그 중간 식을 실제로 셈해야 함 — 입력만 있다고 되는 게 아니라 중간 단계 계산이 필요할 수 있음. + +**(나) 로직을 부르는 호표 줄의 비목(노무비/재료비/경비) 갈래.** 전체 로직 1,354개의 호표 항목 +4,920개 가운데 **990개가 「로직」 종류**임(나머지는 인력 3,255·재료 675). 인력·재료·기계 종류는 +비목이 식 정의에 그대로 박혀 있어(예: "노무비") 계산 없이도 어느 표에 넣을지 바로 앎. +**로직 종류 990개는 예외 없이(990/990) 비목을 안 밝힘** — 불러온 로직 자체의 노무비·재료비· +경비 몫을 실제로 계산해야 그 줄이 세 표 가운데 어디에 얼마씩 들어가는지 정해짐. 이것은 +「알약 + 사칙연산」 검토([[분석-알약-상세줄]])가 상정한 「세 묶음 표」 얼개 자체와 부딪히는 +자리임 — 계산 없이 보이는 이름 식 모드에서는 이 990개 줄을 애초에 세 표로 못 나눔. + +## ② 사용자 안을 넣으면 값 식과 줄이 짝으로 안 맞는 자리 + +`텍스트 수식` 화면(`M01_MasterData_UI_LogicLab_Formula.ts`)을 다시 보면, 「짝」 번호는 +이름글 칸과 값 칸을 나란히 세우는 것이 아니라 — **한 줄(line) 객체 하나가 이름글·글 두 칸을 +이미 같이 담고 있고**, 짝은 그 줄을 가리키는 안정된 이름(마우스오버·클릭으로 같은 줄을 +밝히는 용도)일 뿐임. 그래서 「양쪽 칸이 서로 다른 배열이라 자리가 밀린다」 같은 문제는 +원래 없음. + +진짜 안 맞는 자리는 두 가지임: + +1. **①-(나)의 990개 로직 호출 줄** — 계산이 없으면 그 줄이 노무비 표에 들어갈지 재료비 표에 + 들어갈지 경비 표에 들어갈지부터 못 정함. 지금 코드(`_shares()`)는 계산된 금액이 0이 아닌 + 비목만 걸러 그 표에 넣는 방식이라, 계산 없는 모드에서는 이 필터 자체가 작동을 못 함. + → 걸음 제안: 계산 없는 모드에서는 이런 줄을 세 표에 억지로 나누지 않고, **호표에 적힌 + 원래 차례 그대로 「로직 부르기」 한 줄로**(비목 안 나눔 표시) 보이는 수밖에 없음. +2. **만약() 양쪽 가지를 다 보이는 줄** — 값 칸(글)은 실제 수가 있어야 하므로 계산이 안 되면 + 그 칸 자체가 비게 됨. 한 줄 안에서 이름글만 길어지고 값 칸은 빈칸(또는 「계산 안 됨」 + 한 마디)이 되는 것뿐, 줄 개수·짝은 안 흔들림 — 이 자리는 걱정한 것만큼 문제는 아님. + +## ③ 양쪽 가지를 다 보일 때 글이 얼마나 길어지는지 — 실수로 셈 + +전체 로직 1,354개를 실제로 파싱해 만약() 겹침을 셈: + +| 겹침(한 로직 안 가장 깊은 자리) | 로직 수 | +|---|---| +| 1 | 291 | +| 2 | 74 | +| 3 | 26 | +| 4 | 8 | +| 5 | 1 | +| 6 | 7 | +| 7 | 3 | +| 8 | 2 | +| 14 | 6 | +| 19 | 2 | +| **28(가장 깊음)** | **1** | + +- 만약()을 **하나라도 쓰는 로직 417개**(전체의 31%) · 만약() 등장 총 **3,352번**. +- 대부분(291+74=365개, 88%)은 겹침 1~2로 짧게 끝남 — 조건 하나짜리라 양쪽 다 보여도 + 줄 하나가 두 배쯤 길어지는 정도. +- 꼬리에 겹침이 아주 깊은 것들이 있음 — 가장 깊은 것은 **GC000887(이중보온관 기계부설)**의 + 「부설크레인」 중간 값으로, `만약(관경=='ø20(90)', ..., 만약(관경=='25(90)', ..., 만약(...` + 처럼 **관경 종류마다 다른 장비를 고르는 28겹 사다리꼴** 식임(사실상 switch 문). 지금은 + 계산이 되면 한 줄(예: "부설크레인 = 2104-0015")로 끝나지만, 양쪽 가지를 다 펼치면 이런 + 자리는 최대 **29가지 선택지가 한 줄에 줄줄이 나열**됨 — 화면에 그대로 펼치면 안 읽힘. + → 걸음 제안: 겹침이 일정 수(예: 3~4) 넘는 사다리꼴은 "다 보이기"를 문자 그대로 펼치지 + 말고 "표에서 고를 값(관경별로 다름)" 한 마디로 뭉뚱그리는 예외 규칙이 필요함. + +## ④ 계산이 멈추는 로직 — 이름 식만이라도 보이는지 + +실제로 전체 로직을 시험 입력으로 다시 돌려 확인 — **현재 멈추는 로직은 60개** +(브레인이 든 63개와 조금 다름 — 데이터가 그새 바뀐 듯, 최신 값으로 60개 씀). + +**중요한 발견 — 멈추는 까닭이 거의 다 만약()과 무관함.** 60개를 다 훑어 보면 예외 없이 +"「재료 고르기 … MT0306xx」 값 없음 — 관리자가 채울 값" 또는 "재료 고르기 후보 없음" 꼴 — +즉 **재료 단가를 아직 안 채워서** 멈춤. 만약() 분기 문제가 아니라 데이터 공백 문제. + +실제로 GF000180(집수정)으로 확인 — 호표 줄 **9개** 가운데 재료 하나("MT030712 집수정 +뚜껑")의 값이 없어서 `POST /text` 가 **통째로 실패**함(`ok: false`, 다른 8줄은 전혀 +안 보임 — 지금 화면은 "계산 멈춤" 한 마디만 뜸). 나머지 8줄은 그 재료와 아무 상관 없는데도 +같이 막힘 — 지금 `lines()`가 `mf.run()`(전체 계산)을 맨 먼저 통째로 부르고, 그게 하나라도 +실패하면 이름 식이든 값 식이든 아무것도 못 만드는 구조이기 때문. + +→ **이름 식만이라도 보이려면, 60개 대부분은 만약() 처리와 상관없이 그냥 될 일**임 — 막힌 +재료가 든 그 한 줄만 "값 없음" 표시로 두고, 나머지 8줄은 이름 식(과 계산 가능한 값 식)을 +그대로 보이면 됨. 필요한 것은 `mf.run()`을 맨 앞에서 통째로 부르는 지금 구조를 풀어, +줄마다 따로 계산하고 실패한 줄만 표시를 달리하는 것. + +## ⑤ 2장(알약) 검토와 부딪히는지 + +부딪힘. [[분석-알약-상세줄]]의 알약 목록(별칭 `aliases()`)은 계산 없이 식 글자만 훑어 +짓는 것이라 원래도 계산이 필요 없었음 — 그 점은 그대로 안전함. 하지만: + +- ①-(가) 홀 낀 요소 참조 — 알약 이름도 `_elem_name`/`_base`를 그대로 쓰므로, 계산이 + 안 되면 알약 이름도 똑같이 날 것 키(`LB000123:{용접직종}`)로 떨어짐. 이름 식과 같은 문제. +- ①-(나) 로직 호출 990개의 비목 미정 — 알약 검토가 상정한 "세 묶음(노무비·재료비·경비) + 표를 폭 맞춰 나란히" 얼개 자체가, 계산 없는 이름 식 모드에서는 이 990개 줄을 그 세 표 + 가운데 놓을 자리를 못 정하는 것과 똑같이 부딪힘. + +두 문제 다 하나만 고치면 됨 — 이번 검토의 ⑥ 걸음이 그대로 알약 쪽에도 적용됨. + +## ⑥ 넣을 자리와 걸음 (짧게) + +- `master_text.py`의 `lines()`가 `mf.run()`을 맨 앞에서 전체 통으로 부르는 구조부터 풂 — + 줄마다 따로 계산 시도하고, 실패한 줄만 "계산 안 됨" 표시. +- `named()`의 만약 분기 — 조건 계산이 실패하면(예: 필요한 입력이 없음) 예외로 안 죽고 + 두 가지(참일 때/거짓일 때)를 "(조건) 이면 A 아니면 B" 꼴로 이어 붙이는 길 추가. + 단, ③에서 본 것처럼 겹침이 깊은 사다리꼴(3~4겹 넘음)은 예외로 뭉뚱그림. +- `_elem_name`/`_base` — 홀이 안 풀리면 지금처럼 날 것 키로 물러나는 대신, "무엇을 고르는 + 자리인지"(홀 이름)만이라도 보이는 문구로 다듬음(예: "장비별 손료"). +- 로직 호출 990개 줄 — 계산 없는 모드에서는 세 표로 안 나누고 원래 호표 차례 그대로 + 한 줄로 보임(비목 표시는 "계산 후 확인"). +- 순서 제안: (a) `lines()` 계산-분리 → (b) 만약 두 가지 표시 → (c) 알약 쪽에도 같은 + 뼈대 재사용(⑤). 알약 검토의 세 표 폭 맞춤 작업과 겹치므로 같은 걸음에서 함께 다루는 + 편이 나음. + +## 결론 + +만약()은 문제의 일부일 뿐임. 실제로는 **로직 호출 990개 줄의 비목 미정**(전체의 100%)이 +계산 없는 이름 식을 막는 더 큰 자리이고, **60개 멈춤 로직**은 만약과 거의 무관하게 재료 +단가 공백 때문이며 `lines()`의 "전체 계산 먼저" 구조만 풀면 대부분 저절로 풀림. 만약() +자체는 417개 로직(31%)에서 쓰이고 대개 짧지만(88%가 겹침 1~2), 드물게 28겹까지 가는 +사다리꼴 식이 있어 "양쪽 다 보이기"는 깊이 제한 예외가 필요함.