From b656e5944db10bcac611e5c0bd45a7d2dbf394a1 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 12:08:44 +0900 Subject: [PATCH] =?UTF-8?q?knowledge(=EA=B2=BD=EC=9F=81=EC=82=AC):=20STmat?= =?UTF-8?q?e=20=EC=9E=AC=EA=B5=AC=ED=98=84=20=EA=B0=80=EB=8A=A5=EC=84=B1?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=E2=80=94=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=85=8B=20=EC=A0=95=EC=A0=95=C2=B7?= =?UTF-8?q?=EC=9A=94=EC=9C=A8=20=EC=A2=8C=ED=91=9C=20=ED=99=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 문서 주장을 믿지 않고 원본 파일과 직접 대조한 결과. 바로잡은 것 - COSTN.DBF 는 암호화돼 있지 않음. 맛보기 71행·봉화 248행을 그대로 읽음. 암호화된 것은 BDQTY 와 SYSINFO 둘뿐. 단가 네 성분이 평문이라 골든셋을 단가 수준까지 뽑을 수 있음 - TAMT=MAMT+LAMT+SAMT 에 예외가 있음. 59행 중 2행(관급 흄관)이 어긋남. 하드 오류로 막으면 실데이터를 거부하게 됨 - 프로젝트 RATE 표는 4종이 아니라 6종. RATE_A(25x10)·RATE_B(35x10) 추가 발견. 값이 0~1 계수로 성격이 다르며 수공형식 밑수 배분표로 보임 새로 확정한 것 — 통제시험 T1 의 절반을 정적으로 풀었음 - 출력 XLSX 비고 칸의 실제 요율을 프로젝트 RATE 표에서 역추적해 좌표 확정 산재 RATE_R[45,1] · 건강 [46,1] · 연금 [46,6] · 장기요양 [46,11] 고용보험 등급1~7 [45,11..17] · 산안비 [20,17] 율 [20,18] 기초액 간접노무비 [10,1] - 5개 연도 시계열이 실제 법정요율 변천과 일치해 A등급 - RATE_R 행 45~49 가 부속표 영역, 행 0~44 가 규모·기간 행렬임을 가름 판정 — 기초단가 원천(자재 5.7만건·노임·중기·표준시장단가)이 전부 암호화라 STmate 복제는 불가. 계산 엔진은 구현 가능하고 Aislo 목적에는 충분함. 문서 15 신규, 검증 스크립트 5개 추가. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Prk9BCHG1EMAywk9k8wegA --- .../20_분석/00_분석_요약과_읽는법.md | 27 ++- .../20_분석/02_데이터셋과_파일형식.md | 23 ++- .../20_분석/11_CPM_계산코어_정적분석.md | 13 ++ .../12_원가계산_4형식과_RATE표_복원.md | 27 ++- .../STmate 분석/20_분석/13_통제시험_목록.md | 14 +- .../20_분석/15_재구현_가능성_검증.md | 154 ++++++++++++++++++ .../40_스크립트/basedata_readability.py | 45 +++++ .../40_스크립트/costn_invariant_audit.py | 56 +++++++ .../40_스크립트/stc_table_probe.py | 41 +++++ .../40_스크립트/t1_insurance_rows.py | 39 +++++ .../40_스크립트/t1_rate_coordinates.py | 82 ++++++++++ .../경쟁사 프로그램/STmate 분석/README.md | 3 + 12 files changed, 512 insertions(+), 12 deletions(-) create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/basedata_readability.py create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/costn_invariant_audit.py create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/stc_table_probe.py create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/t1_insurance_rows.py create mode 100644 resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/t1_rate_coordinates.py diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md index 3307a757..000c20b8 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/00_분석_요약과_읽는법.md @@ -6,21 +6,26 @@ | 문서 | 용도 | Orca 아티팩트 | |---|---|---| -| 00 분석 요약과 읽는 법 (이 문서) | 전체 인덱스, 결론, Aislo 비교 | https://share.onorca.dev/a/uHEsfWTvedw1 | -| 01 전체 구조 | 실행 기술, 모듈, 파일 흐름, 기능 구조 | https://share.onorca.dev/a/jjxDJTOtRGq7 | -| 02 데이터셋과 파일형식 | DBF 스키마, 프로젝트 패키지, 기준자료, 암호화 경계 | https://share.onorca.dev/a/boO2-Fo4CFNi | -| 03 계산로직과 Aislo 비교 | 확인된 공식, 계층 합산, 단가·제비율 모델, 차이와 권고 | https://share.onorca.dev/a/fyN0SVUu3Oum | -| 04 계산 데이터계보 | 입력 필드 → 계산 → 결과 필드 단계별 추적 | https://share.onorca.dev/a/S1E38cIhGiz6 | -| 05 재구현 판정기준과 근거목록 | 확정등급, 조사 표본, 파이프라인, 중간값 계약 | https://share.onorca.dev/a/8ktCQIIDvMuP | -| 06 규칙1·7 | RATE 좌표, 간접비 순서, 끝전·VAT | https://share.onorca.dev/a/z2v9o5Wfaim0 | -| 07 규칙2·3·4·5 | 직접비 단가, 중기, BDQTY, 자재 채택 | https://share.onorca.dev/a/o0HLxAXG8Lhg | -| 08 규칙6·8·9 | 재계산, 변경설계, 일괄변경 | https://share.onorca.dev/a/z58ZjH9Nu_Pb | +| 00 분석 요약과 읽는 법 (이 문서) | 전체 인덱스, 결론, Aislo 비교 | https://share.onorca.dev/a/jAFkUlfWjAOv | +| 01 전체 구조 | 실행 기술, 모듈, 파일 흐름, 기능 구조 | https://share.onorca.dev/a/YrTXvA_VN7OI | +| 02 데이터셋과 파일형식 | DBF 스키마, 프로젝트 패키지, 기준자료, 암호화 경계 | https://share.onorca.dev/a/dkOGvoT4jO8S | +| 03 계산로직과 Aislo 비교 | 확인된 공식, 계층 합산, 단가·제비율 모델, 차이와 권고 | https://share.onorca.dev/a/CPOaNTIjmPDA | +| 04 계산 데이터계보 | 입력 필드 → 계산 → 결과 필드 단계별 추적 | https://share.onorca.dev/a/j231bE3HQqNw | +| 05 재구현 판정기준과 근거목록 | 확정등급, 조사 표본, 파이프라인, 중간값 계약 | https://share.onorca.dev/a/NbIR-TMqLPjc | +| 06 규칙1·7 | RATE 좌표, 간접비 순서, 끝전·VAT | https://share.onorca.dev/a/U1-yAvd5qfbj | +| 07 규칙2·3·4·5 | 직접비 단가, 중기, BDQTY, 자재 채택 | https://share.onorca.dev/a/c7n8XytHiqGt | +| 08 규칙6·8·9 | 재계산, 변경설계, 일괄변경 | https://share.onorca.dev/a/G21A30euiRNl | | 09 통합 재구현 명세 | 내부 데이터셋, 계산 순서, 호환 어댑터, 골든시험 | https://share.onorca.dev/a/7eULzjbfyZHM | | 10 System 186개 파일 분석장부 | 전 파일별 판독 상태, 실제 형식, 핵심 모듈과 기준자료 구조 | https://share.onorca.dev/a/zHj5IbV4dfnL | | 11 CPM 계산코어 정적분석 | 식 평가, 반올림, 간접비·안전비·변경설계·끝전조정 재구현 명세 | https://share.onorca.dev/a/U6HIpHCbt9XF | | 12 원가계산 4형식과 RATE표 복원 | 일반·수공·실적일반·실적수공 공식, 화면 열, 내부 선택값 | https://share.onorca.dev/a/y-R9TQqgEFfo | | 13 통제시험 목록 | 정적 분석으로 못 가르는 경계를 시험 11개로 분리, 우선순위·완료판정 | https://share.onorca.dev/a/lcmxdrG2SWvE | | 14 최종 분석완료 보고서 | 도달 수준, A등급 확정 목록, 남은 것, 완료 판정 기준, 산출물 | https://share.onorca.dev/a/AmgldP7q_Qzc | +| 15 재구현 가능성 검증 | **무엇을 만들 수 있고 무엇이 막혀 있나** — 층별 확보표, 문서 오류 정정, T1 좌표 확정 | https://share.onorca.dev/a/t6HGy0HlbEBl | + +> **정본은 저장소 파일이다** — `resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/`. +> 위 Orca 링크는 보기용이며, 문서를 지식DB 자리로 옮기면서 주소가 한 번 바뀌었다. +> 09·10·11·12·13·14번 링크는 재발행이 속도제한에 걸려 **아직 옛 주소**다 — 그 여섯은 저장소 파일을 볼 것. 중요: C등급으로 표시한 규칙은 “분석 누락”이 아니라 보유 정적 자료에 입력 전후 대응값이 없거나 레코드가 난독화되어 확정 불가능한 경계다. 문서에는 각 경계를 확정할 STmate 통제 대조시험까지 명시했다. System 폴더는 186/186개 모두 내부 구조까지 판독했으며 미판독 파일은 0개다. @@ -40,6 +45,10 @@ | `JB_R` 35열 확장 시점 | "2020 이후" | **2020-05-27 확정** — 기존 1~20열은 한 셀도 안 바뀜 | 10번 §4 | | `JB_R` 열 의미 | 미상 | **1~5 간접노무비 / 6~10 기타경비** (공종 5개 순서 확정), 21·26 국가유산 | 10번 §4 | | 원가계산 설정 선택축 | 16축 목록 | **83축 전수** — 공통 29 + 형식별 12/11/16/15 | 12번 §10.1-2 | +| `COSTN.DBF` 암호화 | 본문 암호화라고 적음 | **평문 — 읽힘.** 암호화는 `BDQTY`·`SYSINFO` 둘뿐 | 02번, 15번 §3 | +| `TAMT=MAMT+LAMT+SAMT` | 예외 없는 불변조건 | **예외 있음** — 59행 중 2행(관급 흄관) | 11번 §3, 15번 §3 | +| 프로젝트 RATE 표 | 4종 | **6종** — `RATE_A`·`RATE_B` 추가 발견 | 02번, 15번 §3 | +| 보험 요율 좌표 | 미확정 | **A** — 산재·건강·연금·장기요양·고용 등급1~7·산안비 좌표 확정 | 12번 §9.1, 15번 §4 | 분석일: 2026-09-13 대상: `C:\경영정보(주)` diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/02_데이터셋과_파일형식.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/02_데이터셋과_파일형식.md index 45e1ba46..088a6db3 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/02_데이터셋과_파일형식.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/02_데이터셋과_파일형식.md @@ -47,7 +47,9 @@ STini.MEM, COSTN.SMT, PRJLST.SMT - 6개 원천/4개 안: `AMT_11..64`, `PG_11..54` - 표시·분류: `GUN`, `GUN2`, `IFORM`, `ACTTYP`, `EDT_DATE` -본문은 암호화되어 있으나 스키마는 평문이다. memo 내용은 `COSTN.SMT`에 저장된다. +**2026-09-13 정정 — `COSTN.DBF` 본문은 암호화돼 있지 않다.** 맛보기 STC의 71개 레코드를 그대로 읽었다(`B00001 흄관기초 D=800mm M TAMT1=23441 MAMT1=2719 LAMT1=20722 SAMT1=0`). 실무 STC 7건도 같다. 암호화된 것은 `BDQTY.DBF`와 `SYSINFO.DBF` 둘뿐이다. memo 내용은 `COSTN.SMT`에 저장된다. + +이 정정은 재구현 가능성에 크게 작용한다 — **단가의 네 성분이 프로젝트 파일 안에 평문으로 들어 있으므로 골든셋을 단가 수준까지 뽑을 수 있다.** ### `COSTA.DBF` — 별도 단가 자료 @@ -74,6 +76,25 @@ STini.MEM, COSTN.SMT, PRJLST.SMT 15필드. `CODE`, `NAME`, `BQCODE`, `QTY0..9`, `IFORM`, `XCODE`로 구성된다. 맛보기에는 레코드가 없으나 수량 계산식 또는 수량 슬롯을 코드화하는 자리로 보인다. +### `RATE*.DBF` — 프로젝트에 복사된 제비율 표 (6종) + +맛보기 STC에는 **여섯 종**이 들어 있다. 기존 문서가 다루던 넷 말고 `RATE_A`·`RATE_B`가 더 있다. + +| 테이블 | 형태 | 값이 든 행 | 대응 기준파일 | 비고 | +|---|---|---:|---|---| +| `RATE.DBF` | 41행 × 10열 | 37 | `JB_1` | | +| `RATE_M.DBF` | 25행 × 10열 | 11 | `JB_M` | 행자부기준 간접노무비. 값이 `15.0`처럼 **백분율** | +| `RATE_R.DBF` | 50행 × 35열 | 38 | `JB_R` 신형 | | +| `RATE_RA.DBF` | 50행 × 20열 | 27 | `JB_RA` | | +| **`RATE_A.DBF`** | 25행 × 10열 | 21 | **대응 JB 파일 없음** | 값이 `0.642 / 0.232 / 0.270 / 0.875 / 0.912`처럼 **0~1 계수**. 앞 5열만 씀 | +| **`RATE_B.DBF`** | 35행 × 10열 | 35 | **대응 JB 파일 없음** | 같은 0~1 계수를 **10열 모두** 씀 | + +`RATE_A`는 `RATE_M`과 형태가 같지만 **값의 성격이 다르다**(계수 vs 백분율). 전 행이 다르므로 같은 표가 아니다. + +`RATE_B`의 10열은 RATE 편집 화면 `rGrd_RateB`의 숫자열 개수와 정확히 맞는다 — `재 / 직노 / 노 / 재+직노 / 재+노`가 토목·건축 두 열군으로 10개다. 따라서 **`RATE_B`는 수공형식(`S`)의 경비별 밑수 배분 계수표**로 보인다. **등급 B.** + +⚠ **두 표는 맛보기 STC에만 있고 실무 STC 7건에는 없다.** 수공형식을 쓰지 않는 프로젝트에는 만들어지지 않는 것으로 보이며, 이는 **수공형식 재현 시험(T11)의 전제 자료가 실무 표본에 없다**는 뜻이다. + ### `KONGJONG.DBF` — 공종 분류 `CODE`, `NAME`, `SIZE` 세 필드의 작은 분류표다. diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/11_CPM_계산코어_정적분석.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/11_CPM_계산코어_정적분석.md index ce3461fb..bc6a4f19 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/11_CPM_계산코어_정적분석.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/11_CPM_계산코어_정적분석.md @@ -60,6 +60,19 @@ CODE="W" 또는 복합행 → TAMT=MAMT+LAMT+SAMT 따라서 총액을 네 번째 독립 비목으로 저장하거나 계산하면 안 된다. 총액은 세 성분의 합이며, 단일 비목행에서는 해당 성분만 총액과 같고 나머지는 0이다. **등급 A**. +#### ⚠ 실데이터에는 예외가 있다 (2026-09-13 실측) + +맛보기 STC의 `COSTN.DBF` 71행 중 값이 있는 59행을 대조하면 **57행은 맞고 2행이 어긋난다.** + +| CODE | 명칭 | 규격 | `TAMT1` | `MAMT1+LAMT1+SAMT1` | 차이 | +|---|---|---|---:|---:|---:| +| `M00010` | 흄관 | 800mm | 65,880 | 41,608 | **+24,272** | +| `M00011` | 흄관 | 900mm | 83,920 | 53,784 | **+30,136** | + +둘 다 `CODE`가 `M`(자재)이고 흄관 — 관급자재로 다루는 품목이다. 즉 **바이너리의 조건식은 「항상 참인 불변조건」이 아니라 「어긋나면 경고할 검사식」**이며, 관급·비과세처럼 별도로 취급하는 자재에는 예외가 있다. + +**재구현 지침** — 이 관계를 **하드 오류로 막으면 실데이터를 거부하게 된다.** 경고로 두고 `component_sum_exempt` 같은 사유 필드를 함께 저장할 것. 예외의 정확한 조건은 통제시험 **T7**(13번 문서) 대상이다. + ## 4. 공통 계산 함수의 의미 ### 4.1 식 평가 diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/12_원가계산_4형식과_RATE표_복원.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/12_원가계산_4형식과_RATE표_복원.md index c095f6e0..12965fa9 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/12_원가계산_4형식과_RATE표_복원.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/12_원가계산_4형식과_RATE표_복원.md @@ -254,7 +254,32 @@ DBF 필드는 `RATE0..RATE9` 또는 `RATE_01..RATE_35`, 레코드는 고정 25/4 - 2020-05-27 확장으로 **열 21 = 국가유산 간접노무비, 열 26 = 국가유산 기타경비**가 붙었고 기존 1~20열은 한 셀도 바뀌지 않았다. - `JB_RA`는 43개 전 기간 20열 그대로다. 실적형식에는 국가유산 공종이 없다. -**남은 것** — 각 부속표 그리드(고용보험·환경보전·보증수수료 계열)가 `JB_1`/`JB_R`의 몇 번째 행부터 적재되는지. 열 접근이 실행 중 문자열 조립이라 코드 상수로 읽을 수 없으므로, 저장 이벤트 역추적 또는 통제 동적 시험이 필요하다. +### 9.1 확정된 좌표 (2026-09-13, 15번 문서) + +출력 XLSX 「공사원가계산서」 비고 칸에 **실제 쓰인 밑수와 요율이 적혀 있다.** 그 값을 같은 프로젝트의 `RATE_*.DBF`에서 되찾아 좌표를 역추적하고, 실무 7건 교차로 후보가 하나뿐인 자리만 취했다. + +| 항목 | 좌표 | 근거 | +|---|---|---| +| 간접노무비 | `RATE_R[10, 1]` | 2건 유일 | +| 산재보험료 | `RATE_R[45, 1]` | 3건 유일 | +| 건강보험료 | `RATE_R[46, 1]` | 2건 유일 | +| 연금보험료 | `RATE_R[46, 6]` | 시계열 | +| 노인장기요양보험료 | `RATE_R[46, 11]` | 1건 유일 + 시계열 | +| 고용보험료 등급 1~7 | `RATE_R[45, 11..17]` | 4건 유일 + 시계열 | +| 산업안전보건관리비 | `RATE_R[20, 17]` 율 · `[20, 18]` 기초액 | 3건 유일 | + +**시계열이 실제 법정요율 변천과 일치해 A등급이다.** + +| 좌표 | 2019 | 2022 | 2024 | 2025 | 2026 | +|---|---:|---:|---:|---:|---:| +| `[45,1]` 산재 | 3.75 | 3.70 | 3.56 | 3.56 | 3.56 | +| `[46,1]` 건강 | 3.23 | 3.495 | 3.545 | 3.545 | 3.595 | +| `[46,6]` 연금 | 4.5 | 4.5 | 4.5 | 4.5 | 4.75 | +| `[46,11]` 장기요양 | 8.51 | 12.27 | 12.95 | 12.95 | 13.14 | + +⇒ **`RATE_R` 행 45~49는 요율 행렬이 아니라 부속표 영역**이고, 행 0~44가 규모·기간 행렬이다. `[45,11..17]`이 `rGrd_Rate_Kobo`(7행, 등급·요율) 그대로다. + +**남은 것** — `연금보험료`·`일반관리비`·`이윤`·`환경보전비`·`부가가치세`는 같은 값이 표 안 여러 곳에 있어 단독으로는 못 가른다. 그 값만 특이한 숫자로 바꿔 저장하는 통제시험(13번 T1)이 필요하다. 부속표 그리드(환경보전·보증수수료 계열)의 시작 행도 같은 시험 대상이다. ## 10. 계산 설정 입력 diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/13_통제시험_목록.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/13_통제시험_목록.md index 337f580a..e707a4ea 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/13_통제시험_목록.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/13_통제시험_목록.md @@ -28,7 +28,19 @@ | 확정되는 것 | 그리드 → 행렬 좌표의 완전 매핑. `rate_standard()` 기준표를 하드코딩 없이 만들 수 있게 됨 | | 근거 문서 | 12번 §8·§9, 10번 §4 | -이미 잡아 둔 것 — 행은 `0,5,10,…,45` 시작의 **5행 묶음**, `JB_R` 열 1~5=간접노무비·6~10=기타경비(토목/산설(토목)/조경/건축/산설(건축)), 신형 열 21·26=국가유산. **T1은 나머지 부속표의 시작 행만 남긴 시험이다.** +**2026-09-13 — T1 의 절반이 정적으로 풀렸다.** 출력 XLSX 비고 칸의 실제 요율을 프로젝트 `RATE_*`에서 역추적해 다음이 확정됐다(15번·12번 §9.1). + +```text +간접노무비 RATE_R[10, 1] +산재보험료 RATE_R[45, 1] 건강보험료 RATE_R[46, 1] +연금보험료 RATE_R[46, 6] 장기요양 RATE_R[46, 11] +고용보험 등급1~7 RATE_R[45, 11..17] +산업안전보건관리비 RATE_R[20, 17] 율 · [20, 18] 기초액 +``` + +시계열이 실제 법정요율 변천과 맞아 **A등급**이다. 행 45~49가 부속표 영역, 행 0~44가 규모·기간 행렬임도 갈렸다. + +**T1 에 남은 것** — `연금보험료`·`일반관리비`·`이윤`·`환경보전비`·`부가가치세`처럼 **같은 값이 표 안 여러 곳에 있는 항목**과, 환경보전·보증수수료 부속표의 시작 행. 이것들은 그 칸만 특이한 값(예: `99.99`)으로 바꿔 저장해 어디에 앉는지 보는 수밖에 없다. ### T2 — 금액·기간 구간 경계 방향 diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md new file mode 100644 index 00000000..243edaf2 --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/20_분석/15_재구현_가능성_검증.md @@ -0,0 +1,154 @@ +# 재구현 가능성 검증 — 모인 정보로 같은 프로그램을 만들 수 있나 + +검증일: 2026-09-13 +방법: 05~14번 문서의 주장을 믿지 않고, **구현에 꼭 필요한 것을 층별로 세어 원본 파일과 직접 대조**함. +대상: `C:\경영정보(주)` 설치 폴더 186개 + 실무 STC 8건 + STmate 생성 XLSX 29건. **읽기만 함.** + +## 1. 한 줄 답 + +**계산 엔진은 만들 수 있음. 기준자료를 갖춘 완제품은 못 만듦.** + +STmate가 배포하는 **기초단가 원천이 전부 암호화**되어 있어 자재·노임·중기 단가를 한 건도 못 읽음. 반면 **프로젝트 파일(STC) 안에는 단가 결과가 평문으로 들어 있어** 「이 단가를 넣으면 이 내역·이 간접비가 나온다」는 재현은 가능함. + +Aislo 입장에서는 이것으로 충분함 — Aislo는 **자기 기초단가 원천**(노임·자재·유가·환율)을 이미 따로 갖고 있으므로, STmate에서 가져올 것은 **계산 규칙**이지 기초자료가 아님. + +## 2. 층별 확보 상태 + +| 층 | 구현에 필요한 것 | 확보 | 판정 | +|---|---|---|---| +| **1 파일 읽기** | STC = 무암호 ZIP | 8건 모두 암호 없음 | ✅ | +| | 프로젝트 표 18종 스키마·본문 | 16종 평문 | ✅ | +| | `BDQTY.DBF` (수량·할증 상세) | **본문 암호화** | ❌ | +| | `SYSINFO.DBF` | **본문 암호화** | ❌ | +| **2 기초단가 원천** | `JDCODE_M.BSC` 자재 57,580건 | **본문 암호화** | ❌ **치명** | +| | `JDCODE_L.BSC` 노임 460건 | **본문 암호화** | ❌ | +| | `JDCODE_X.BSC` 중기 833건 | **본문 암호화** | ❌ | +| | `JDCODE_Z.BSC` 33,927건 · `GRPCOD_Z` 12,125건 | **본문 암호화** | ❌ | +| | 표준시장단가 `*.CSTA` 4,921~4,961건 × 6 | **본문 암호화** | ❌ | +| | `*.STBSC` 28개 (노임·기계경비 배포) | ZIP 컨테이너, 내부 암호 | ❌ | +| **3 단가 계산** | `COSTN.DBF` 단가 네 성분 | **평문 — 읽힘** | ✅ | +| | `COSTN.SMT` 구성 토큰 | 평문, 문법 문서화됨 | ✅ | +| | 중기 손료 계수(감가상각·정비·관리율) 실제 값 | **어디에도 없음** | ❌ | +| | 자재 6후보 중 자동채택 규칙 | C등급 | ❌ | +| **4 내역** | `BOQ11.DBF` 수량·단가·금액 | 평문 | ✅ | +| | 계층 집계(`SORTCODE`·`ENDCODE`·`ITM_TYP`) | 문서화됨 | ✅ | +| **5 간접비** | 항목 사전 30여 개 | 문서화됨 | ✅ | +| | 형식별 계산 순서 | 네 형식 모두 번호 매겨 복원 | ✅ | +| | 항목별 밑수 공식 | 화면 묶음 제목에서 확정 | ✅ | +| | 요율표 좌표 | **6개 항목 확정** (아래 4장), 나머지 진행 중 | ⚠→✅ | +| | `RATE_A`·`RATE_B` 표 | 이번에 발견, 의미 B등급 | ⚠ | +| **6 반올림** | 내부 함수·음수·절반값 | 은행가 반올림 확정 | ✅ | +| | 출력별 정책 | 확정 | ✅ | +| **7 출력** | `SET_REP.DBF` 75행 × 28열 | 평문 | ✅ | + +## 3. 이번 검증에서 나온 문서 오류 셋 + +기존 문서가 실제와 어긋난 자리를 찾아 고침. + +### ① `COSTN.DBF`는 암호화돼 있지 않음 + +02번이 「본문은 암호화되어 있으나 스키마는 평문」이라 적었으나 **사실이 아님.** 맛보기 71행, 봉화 248행을 그대로 읽음. + +```text +B00001 흄관기초 D=800mm M TAMT1=23,441 MAMT1=2,719 LAMT1=20,722 SAMT1=0 +``` + +**이 정정이 결론을 바꿈** — 단가의 네 성분이 프로젝트 안에 평문으로 있으므로 **골든셋을 단가 수준까지 뽑을 수 있음.** 암호화된 것은 `BDQTY`와 `SYSINFO` 둘뿐임. + +### ② `TAMT = MAMT + LAMT + SAMT` 는 예외가 있음 + +A등급 불변조건으로 적혀 있으나 실데이터에 **59행 중 2행이 어긋남.** + +| CODE | 명칭 | `TAMT1` | `M+L+S` | 차이 | +|---|---|---:|---:|---:| +| `M00010` | 흄관 800mm | 65,880 | 41,608 | +24,272 | +| `M00011` | 흄관 900mm | 83,920 | 53,784 | +30,136 | + +둘 다 관급으로 다루는 자재임. **하드 오류로 막으면 실데이터를 거부하게 됨** — 경고로 두고 사유를 함께 저장할 것. + +### ③ 프로젝트 RATE 표는 넷이 아니라 여섯 + +맛보기 STC에 **`RATE_A`(25×10)·`RATE_B`(35×10)** 가 더 있음. 값이 `0.642 / 0.232 / 0.875` 같은 **0~1 계수**로, 백분율인 다른 표와 성격이 다름. `RATE_B`의 10열은 화면 `rGrd_RateB`의 숫자열 개수(`재/직노/노/재+직노/재+노` × 토목·건축)와 정확히 맞아 **수공형식 경비 밑수 배분표**로 보임. + +⚠ **두 표는 맛보기에만 있고 실무 STC 7건에는 없음** — 수공형식 재현 시험의 전제 자료가 표본에 없다는 뜻임. + +## 4. T1(요율 좌표)을 정적으로 깬 결과 + +**출력 엑셀 「공사원가계산서」의 비고 칸에 쓰인 밑수와 요율이 그대로 적혀 있음.** + +```text +간접노무비 직접노무비 x 14.5% +산재보험료 (직접노무비+간접노무비) x 3.56% +노인장기요양보험료 건강보험료 x 12.95% +이윤 (노무비+경비+일반관리비) x 15% +``` + +이 값을 그 프로젝트의 `RATE_*.DBF` 안에서 되찾아 좌표를 역추적함. 실무 7건 전수 교차로 **후보가 하나뿐인 자리**만 취함. + +| 항목 | 확정 좌표 | 근거 | +|---|---|---| +| 간접노무비 | `RATE_R[10, 1]` | 2건에서 유일 | +| 산재보험료 | `RATE_R[45, 1]` | 3건에서 유일 | +| 건강보험료 | `RATE_R[46, 1]` | 2건에서 유일 | +| 고용보험료 | `RATE_R[45, 17]` | 4건에서 유일 | +| 노인장기요양보험료 | `RATE_R[46, 11]` | 1건에서 유일 | +| 산업안전보건관리비 | `RATE_R[20, 17]` (율), `[20, 18]` (기초액) | 3건에서 유일 | + +### 시계열 교차 검증 — A등급 + +기준파일 `JB_R`의 같은 자리를 연도별로 늘어놓으면 **실제 법정요율 변천과 정확히 일치함.** + +| 좌표 | 2019 | 2022 | 2024 | 2025 | 2026 | 무엇인가 | +|---|---:|---:|---:|---:|---:|---| +| `[45, 1]` | 3.75 | 3.70 | 3.56 | 3.56 | 3.56 | 산재보험료율 | +| `[46, 1]` | 3.23 | 3.495 | 3.545 | 3.545 | 3.595 | 건강보험료율 | +| `[46, 6]` | 4.5 | 4.5 | 4.5 | 4.5 | 4.75 | 연금보험료율 | +| `[46, 11]` | 8.51 | 12.27 | 12.95 | 12.95 | 13.14 | 노인장기요양보험료율 | + +`[45, 11..17]`은 **고용보험 등급 1~7**임. 값이 내림차순이고(2024: `1.57 / 1.30 / 1.13 / 1.06 / 1.03 / 1.02 / 1.01`) 개수가 화면 `rGrd_Rate_Kobo`의 7행과 맞음. 검증한 프로젝트는 모두 `열17`(7등급 이하)을 씀. + +⇒ **`RATE_R`의 행 45~49는 요율 행렬이 아니라 부속표 영역**이고, 행 0~44가 규모·기간 행렬임. + +### 아직 좌표가 안 갈리는 항목 + +`연금보험료(4.5%)`·`일반관리비(6%)`·`이윤(15%)`·`환경보전비(0.8%)`·`부가가치세(10%)`는 **같은 값이 표 안 여러 곳에 있어** 단독으로는 못 가름. 확정하려면 **한 프로젝트에서 그 값만 특이한 숫자로 바꿔 저장**하는 통제시험이 필요함(13번 T1). + +## 5. 그래서 무엇을 만들 수 있나 + +### 지금 자료로 가능한 것 + +1. **STC 읽기·쓰기 어댑터** — 표 16종 평문, ZIP 무암호 +2. **내역 계산기** — 수량 × 단가 → 행 금액 → 계층 집계. 반올림 정책 확정 +3. **간접비 계산기** — 항목 사전·형식별 순서·밑수·반올림 확정, 보험 요율 좌표 6개 확정 +4. **원설계 골든셋 회귀** — 실무 7건의 `BOQ11` + `COSTN` + `RATE_*` + 출력 XLSX를 짝지어 **원 단위 대조** 가능 +5. **변경설계 비교** — 소광 원설계/통합변경/변경1차 세 벌 보유 + +### 지금 자료로 불가능한 것 + +1. **기초단가 배포 체계** — 자재 5.7만 건·노임·중기·표준시장단가를 못 읽음. 암호를 풀지 않는 한 영구 불가 +2. **수량 할증 재현** — `BDQTY` 암호화로 `X_QTY`·`X_HAL` 실값을 못 봄 +3. **중기 시간당 단가 재현** — 손료 계수(감가상각률·정비율·관리비율) 실제 값이 자료에 없음 +4. **자재 자동채택** — 6후보 중 무엇을 고르는지 규칙 없음 +5. **수공형식 검증** — `RATE_A`·`RATE_B`가 실무 표본에 없음 + +## 6. 판정 + +| 물음 | 답 | +|---|---| +| STmate와 **똑같은 프로그램**을 만들 수 있나 | ❌ — 기초단가 원천이 암호화됨 | +| STmate와 **같은 답을 내는 계산 엔진**을 만들 수 있나 | ⚠ 대부분 — 직접비·간접비·반올림은 가능, 중기·할증·자재채택은 불가 | +| STmate 프로젝트 파일을 **읽고 검산**할 수 있나 | ✅ — `BDQTY` 빼고 전부 | +| **Aislo 원가계산에 쓸 규칙**을 얻었나 | ✅ — 밑수·순서·반올림·요율 좌표 확보 | + +**Aislo 목적으로는 필요한 정보가 모였음.** 「STmate 복제」는 애초에 불가능하고 목표도 아님. + +## 7. 다음에 할 것 + +| 순위 | 할 일 | 왜 | +|---:|---|---| +| 1 | **골든셋 회귀 구현** — 실무 7건의 STC + XLSX로 내역·간접비를 원 단위 대조 | 지금 자료만으로 되고, 규칙 확정도를 한 번에 끌어올림 | +| 2 | 남은 요율 좌표(연금·일반관리비·이윤·환경보전비) 확정 | 통제시험 T1 나머지 | +| 3 | 중기 손료 계수를 **법령·품셈에서** 확보 | STmate 자료로는 영구 불가 — 국가 기준으로 대체 | +| 4 | `BDQTY` 대조시험 (T7) | 할증 규칙 | + +3번은 STmate를 뜯어서 얻을 수 없음. `resources/knowledge/technical_info/` 의 **건설기계 경비 산정 기준**으로 가야 함. diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/basedata_readability.py b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/basedata_readability.py new file mode 100644 index 00000000..5260055e --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/basedata_readability.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +"""기준자료를 실제로 읽을 수 있는지 판정. 복호화 시도는 하지 않음 — 읽히나만 봄.""" +import pathlib, struct, sys, io, collections +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") +ROOT = pathlib.Path(r"C:\경영정보(주)\System") + +def probe(p): + try: b = p.read_bytes() + except Exception as e: return "열기실패", 0, 0 + if b[:2] == b"PK": return "ZIP", 0, 0 + if b[:1] not in (b"\x03", b"\x04", b"\x05", b"\x30", b"\xE5", b"\x06", b"\xF5", b"\x8B"): + return "DBF아님", 0, 0 + try: + nrec, hlen, rlen = struct.unpack_from("= 0xA1) + ratio = printable / max(len(rec), 1) + return ("평문" if ratio > 0.85 else "본문암호화"), nrec, n + except Exception: + return "해석실패", 0, 0 + +groups = collections.defaultdict(lambda: collections.Counter()) +detail = collections.defaultdict(list) +for p in sorted(ROOT.rglob("*")): + if not p.is_file(): continue + ext = p.suffix.upper() or "(없음)" + if ext not in (".DBF",".BSC",".STBSC",".CSTA",".JB_R",".JB_RA",".JB_1",".JB_M",".SMT",".MEM"): continue + st, nrec, nfld = probe(p) + groups[ext][st] += 1 + detail[ext].append((p.name, st, nrec, nfld)) + +print("### 기준자료·프로젝트 테이블의 읽힘 상태 (복호화 시도 없음)") +print("%-8s %-5s %s" % ("확장자","개수","판정")) +for ext in sorted(groups): + tot = sum(groups[ext].values()) + print("%-8s %-5d %s" % (ext, tot, dict(groups[ext]))) + +print("\n### 단가 원천으로 쓰이는 대형 기준파일") +for ext in (".BSC", ".CSTA", ".STBSC"): + for nm, st, nrec, nfld in detail.get(ext, [])[:8]: + print(" %-42s %-10s rec=%-7s fld=%s" % (nm[:42], st, nrec or "-", nfld or "-")) diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/costn_invariant_audit.py b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/costn_invariant_audit.py new file mode 100644 index 00000000..6dd9b5da --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/costn_invariant_audit.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +import pathlib, zipfile, struct, sys, io +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") + +def rd(zf, name): + b = zf.read(name) + nrec, hlen, rlen = struct.unpack_from("= 0.005: + bad+=1 + print(" %-8s %-14s %-12s T=%10.0f M+L+S=%10.0f 차=%+.0f" % ( + r[ix["CODE"]], r[ix["NAME"]][:14], r[ix["SIZE"]][:12], T, M+L+S, T-(M+L+S))) +print(" 불일치 %d행" % bad) + +print("\n### 프로젝트 RATE 표 전수 (맛보기)") +import re +for nm in sorted(n for n in Z.namelist() if re.match(r"RATE", n, re.I)): + f2, r2 = rd(Z, nm) + nz = sum(1 for r in r2 if any((x and x not in ("0.0000","0.00","0")) for x in r)) + print(" %-14s %2d행 × %2d열 값이 든 행 %d" % (nm, len(r2), len(f2), nz)) + +print("\n### RATE_A 와 RATE_M 이 같은 표인가") +fa, ra = rd(Z,"RATE_A.DBF"); fm, rm = rd(Z,"RATE_M.DBF") +same = sum(1 for a,b in zip(ra,rm) if a==b) +print(" 행 %d개 중 완전히 같은 행 %d개 → %s" % (len(ra), same, "같은 표 아님" if same= 0xA1) / max(len(rec),1) + return ("평문" if pr > 0.85 else "본문암호화"), nrec, n + except Exception: return "해석실패", 0, 0 + +if stcs: + for s in stcs[:2]: + print("\n### %s" % s.name) + try: + z = zipfile.ZipFile(s) + except Exception as e: + print(" ZIP 열기 실패: %s" % e); continue + enc = any(i.flag_bits & 0x1 for i in z.infolist()) + print(" ZIP 암호: %s 파일 %d개" % ("걸림" if enc else "없음", len(z.infolist()))) + for i in z.infolist(): + if not i.filename.upper().endswith((".DBF",)): continue + try: b = z.read(i) + except Exception as e: print(" %-16s 읽기실패" % i.filename); continue + st, nrec, nf = dbf_state(b) + print(" %-16s %-10s rec=%-6s fld=%s" % (i.filename, st, nrec, nf)) diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/t1_insurance_rows.py b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/t1_insurance_rows.py new file mode 100644 index 00000000..6a998f1f --- /dev/null +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/40_스크립트/t1_insurance_rows.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +import sys, io, pathlib, struct, collections +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") +ROOT = pathlib.Path(r"C:\경영정보(주)\System\ST_BSC") +def rd(p): + b=p.read_bytes(); nrec,hlen,rlen=struct.unpack_from(" bs: bs, best = s, x + if best and bs > 0.55: pairs.append((stc, best, bs)) +print("짝 %d건" % len(pairs)) +for s,x,r in pairs: print(" %.2f %s" % (r, s.stem[:52])) + +coord = collections.defaultdict(collections.Counter) # 항목 -> 좌표 카운트 +uniq = collections.defaultdict(collections.Counter) # 항목 -> 유일히 잡힌 좌표 +for stc, xp, _ in pairs: + try: rates = sheet_rates(xp) + except Exception: continue + if not rates: continue + z = zipfile.ZipFile(stc) + tabs = {} + for n in z.namelist(): + if re.match(r"RATE.*\.DBF$", n, re.I): + try: tabs[n.upper().replace(".DBF","")] = dbf(z,n) + except Exception: pass + for label, v in rates: + found=[] + for tn,M in tabs.items(): + for r,row in enumerate(M): + for c,x in enumerate(row): + if x and abs(x-v) < 1e-6: found.append("%s[%d,%d]"%(tn,r,c+1)) + for f in found: coord[label][f]+=1 + if len(found)==1: uniq[label][found[0]]+=1 + +print("\n=== 유일하게 잡힌 좌표 (다른 후보 없이 딱 하나) ===") +for lab in sorted(uniq): + for k,n in uniq[lab].most_common(): + print(" %-22s → %-16s 프로젝트 %d건에서 유일" % (lab[:22], k, n)) + +print("\n=== 여러 후보 중 모든 프로젝트에 공통인 좌표 ===") +N = len(pairs) +for lab in sorted(coord): + all_hit = [k for k,n in coord[lab].items() if n == max(coord[lab].values()) and n >= 3] + if all_hit and lab not in uniq: + print(" %-22s → %s (각 %d건)" % (lab[:22], ", ".join(all_hit[:5]), max(coord[lab].values()))) diff --git a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md index 72407931..ae9ca5f7 100644 --- a/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md +++ b/resources/knowledge/original/경쟁사 프로그램/STmate 분석/README.md @@ -40,6 +40,7 @@ | 12 | 원가계산 4형식과 RATE표 복원 — **설정 83축** | | 13 | 통제시험 목록 T1~T11 — 아직 못 가른 경계 | | 14 | 최종 분석완료 보고서 | +| 15 | **재구현 가능성 검증** — 무엇을 만들 수 있고 무엇이 막혀 있나 | ## 확정된 굵직한 것 @@ -49,6 +50,8 @@ - 원가계산 **네 형식**(일반·수공·실적일반·실적수공)은 출력 모양이 아니라 **공식 집합이 통째로 다름** - 기준자료 `JB_R` 35열 확장 시점 **2020-05-27**, 기존 1~20열은 한 칸도 안 바뀜 - 설정 **83축** 전수. 화면 순번과 내부값이 **뒤집힌 축 둘** 있음 — 그대로 저장하면 정반대 공식이 걸림 +- 보험 요율의 **표 좌표 확정** — 산재 `RATE_R[45,1]`, 건강 `[46,1]`, 연금 `[46,6]`, 장기요양 `[46,11]`, 고용 등급1~7 `[45,11..17]`. 5개 연도 시계열이 실제 법정요율 변천과 맞음 +- ⚠ **기초단가 원천은 전부 암호화** — 자재 5.7만 건·노임·중기·표준시장단가를 한 건도 못 읽음. 「계산 엔진」은 만들 수 있으나 「기준자료를 갖춘 완제품」은 못 만듦 (15번) ## 원자료 — `30_원자료/`