diff --git a/resources/tester/helper_est_native.cjs b/resources/tester/helper_est_native.cjs index 4a81c6616..e471b9f79 100644 --- a/resources/tester/helper_est_native.cjs +++ b/resources/tester/helper_est_native.cjs @@ -18,6 +18,7 @@ for (const file of [ "native-review.js", "native-resources.js", "native-schedule.js", + "native-issues.js", "native-model.js", "native-c3r.js", "native-exchange.js", diff --git a/resources/tester/test_est_issues.py b/resources/tester/test_est_issues.py new file mode 100644 index 000000000..0bd31b0a9 --- /dev/null +++ b/resources/tester/test_est_issues.py @@ -0,0 +1,26 @@ +from test_est_rea_parity import run + + +def test_data_issues_detect_duplicate_missing_and_mismatched_links_without_modifying_data(): + result = run( + "math", + """(()=>{ + const p=EstNative.empty();p.tables.StuffcDat=[{Code:'A',Name:'sand',Size:'large'}, + {Code:'B',Name:'first'},{Code:'B',Name:'second'}]; + p.tables.HeadMainDat=[{Index:1,Code:'H',Name:'group'},{Index:0,Code:'A',LinkIndex:5,Name:'sand',Size:'large'}]; + p.tables.EstMainDat=[{Code:'A',LinkIndex:5,Name:'stone',Size:'small'}, + {Code:'B',LinkIndex:5,Name:'ambiguous'},{Code:'missing',LinkIndex:5,Name:'missing'}, + {Code:'H',LinkIndex:103,Name:'group'}]; + const before=JSON.stringify(p),issues=EstIssues.scan(p); + return {issues,same:before===JSON.stringify(p)}; + })()""", + ) + assert result["same"] + items = {(row["table"], row["index"], row["message"]) for row in result["issues"]} + assert ("StuffcDat", 1, "코드 중복") in items + assert ("StuffcDat", 2, "코드 중복") in items + assert ("EstMainDat", 0, "연결 품명 차이") in items + assert ("EstMainDat", 0, "연결 규격 차이") in items + assert ("EstMainDat", 1, "연결 코드 중복") in items + assert ("EstMainDat", 2, "연결 자료 없음") in items + assert len(items) == 6 diff --git a/tools/est-test/PLAN.md b/tools/est-test/PLAN.md new file mode 100644 index 000000000..a0fec1e76 --- /dev/null +++ b/tools/est-test/PLAN.md @@ -0,0 +1,234 @@ +## Codex · EST 독립 테스트 앱 (2026-11-04) + +- 2026-11-07: 사용자 지시로 EST 작업 계획과 검증 기록을 공유 PLAN.md에서 이 파일로 이관. 업무 회귀 시험 79개 통과, openpyxl 경고 7건. Git push는 보류. + +- [x] 자료 오류 검색 화면과 해당 행 이동 구현 → 중복·누락 연결·품명·규격 차이 시험. + - 자체 검증: 중복·누락·품명·규격 차이 시험 포함 19개 통과. Edge에서 오류 목록과 내역 행 이동 확인. + +- [x] 계약심사 화면에서 주요심사내용 작성·저장·출력 연결 → 입력·재열기·인쇄 시험. + - 자체 검증: 심사·문서 시험 17개 통과. Edge에서 작성·저장·재열기·인쇄 확인. + +- [x] 계약심사 비목 누락 고정금액·중복 식별 처리 보완 → 잘못된 합계·다중 반영 차단 시험. + - 자체 검증: 고정금액 비목 합계 오류·중복 식별 입력 차단을 포함해 시험 29개 통과, Edge 화면 확인. + +- [x] 직접 작성 수량 수식표 항목 이동 구현 → 수식 참조·저장·실행 취소 시험. + - 자체 검증: 수량·문서 시험 17개 통과. Edge에서 이동 뒤 참조 오류·서버 저장·재열기·실행 취소 확인. + +- [x] 최근 확정 기성의 누계 수량을 예정공정표 진도로 반영 → 연결·범위·기존 일정 보존 시험. + - 자체 검증: 최근 확정 회차·미연결·수량 0·범위 오류·일정 보존 포함 시험 18개 통과, Edge 진도 반영과 실행 취소 확인. + +- [x] 인쇄 서식의 계산 결과를 Excel 표로 내보내기 구현 → 실제 Excel 열기·수치 확인. + - 자체 검증: Edge에서 연차 내역 Excel 다운로드·한글 제목·금액 확인. 요약·오류·수치·입력 검증 포함 문서·Excel 시험 22개 통과(openpyxl 경고 7건). + +- [x] 연차별 개별 내역·배분 금액 출력 구현 → 차수별 계산·수식 오류 시험. + - 자체 검증: 차수별 배분·오류 표시 포함 문서·연차 시험 13개 통과, Edge 연차 내역 미리보기 확인. 업무 회귀 시험 74개 통과(openpyxl 경고 6건). + +- [x] 물가변동의 중복 코드 내역을 당초와 개별 연결 → 계약·적용제외 계산 시험. + - 자체 검증: 중복 내역의 개별 계약 단가·적용제외 포함 시험 24개 통과, Edge에서 계약 단가 80·50 표시 확인. + +- [x] 기성 입력·일괄 적용의 중복 행 식별 차단 → 계산·확정·일괄 적용 시험. + - 자체 검증: 중복 행 계산 및 확정 차단·다른 행 계산 포함 14개 통과, Edge 개별·일괄 입력 차단 확인. + +- [x] 기성 누계수량의 물가변동 연결 보완 → 중복 식별 차단·신규 행 입력 보존 시험. + - 자체 검증: 중복 식별 차단과 신규 행 입력 보존 포함 시험 13개 통과, Edge 기성 누계 불러오기 확인. + +- [x] 행 복사·붙여넣기에서 다른 종류의 자료가 섞여 손상되지 않도록 제어 → 동일 자료 복사·오류 시험. + - 자체 검증: Edge에서 다른 자료 종류의 붙여넣기를 차단하고 동일 자료 복사는 유지하는 것을 확인. + +- [x] 내역 선택 행 위·아래 이동 구현 → 행 식별·소계 보호·취소 시험. + - 자체 검증: 연속 행 이동·소계·식별자 차단 시험 21개 통과, Edge에서 이동·기성 입력 유지·실행 취소 확인. + +- [x] 설계변경 중복 코드 내역의 당초 행 매칭 보완 → 증감·삭제 시험. + - 자체 검증: 같은 코드의 다중 내역과 삭제 행의 당초 금액 분리를 포함한 시험 20개 통과. + +- [x] 설계변경 원가 비목별 당초·변경·증감 화면과 출력 구현 → 삭제·신규·중복 구분 시험. + - 자체 검증: 중복·신규·삭제 및 행별 당초 값 포함 시험 15개 통과, Edge 화면과 인쇄 미리보기 확인. + +- [x] 물가변동 원가 비목별 계약·조정·제외 금액 인쇄 구현 → 계산 결과 시험. + - 자체 검증: 기성·물가변동·문서 시험 21개 통과, Edge 미리보기에서 기성·물가변동 원가와 연차 출력 확인. + +- [x] 기성 원가계산서 인쇄 구현 → 회차별 전회·금회·사정·누계 시험. + - 자체 검증: 확정 및 다음 회차 금액 포함 시험 15개 통과. + +- [x] 물가변동 전용 Excel 입력과 조사 도급액 입출력 구현 → 행 식별, 오류 차단, 계산 반영 시험. + - 자체 검증: Excel 관련 시험 12개 통과, Edge에서 실제 파일 수정과 가져오기 확인. + +- [x] 연차 배분 계산 결과와 수식을 출력하는 서식 구현 → 차수별 계산과 오류 표시 시험. + - 자체 검증: 차수별 금액과 잘못된 수식 오류 표시 포함 시험 11개 통과. + +- [x] 기성 회차와 물가변동 결과 인쇄 서식 구현 → 확정 회차 보존과 계산 결과 시험. + - 자체 검증: 결과 출력 및 확정 회차 보존 시험 포함 18개 통과, Edge 미리보기에서 두 서식 확인. + + +- 2026-11-07 사용자 지시: 동등성 대조와 Git push 보류, CAD 제외 기능 구현 우선. + - 기능 회귀(2026-11-07): 수량·Excel·심사·설계변경·기성·물가변동·연차·공정·이력 관련 60개 통과(28.41초), openpyxl 날짜 API 경고 5건. 원본 동등성 대조는 실행하지 않음. + - [x] 수량산출서 신규 생성·이름 변경·산출 행/항목 추가·삭제 및 내역 반영 → 화면 조작과 JSON 저장/복원 시험. + - 자체 검증(2026-11-07): 수량 화면에서 새 산출서 생성, 항목 추가·품명 변경, `2*3` 계산과 내역 6 반영, 서버 JSON 저장·재열기. Edge 브라우저 오류 0, 이벤트 기능 시험 2개 통과. 설치 원본과의 동등성 대조는 사용자 지시에 따라 수행하지 않음. 신규 산출서/행 구조 변경의 원본 ESTX 쓰기는 미지원. + - [x] 수량산출 행의 순서 변경과 선택 위치 삽입 → 계산 참조 순서·결과 표지 연결 확인. + - 자체 검증(2026-11-07): 이벤트 시험에서 항목 결과 3·9·13 보존, 선언 이전 참조 오류 확인. Edge에서 행 아래 삽입·위로 이동 및 JSON 저장 후 재열기, 항목 결과 3·9 유지·브라우저 오류 0. + - [x] 기존 수량 연결의 변경 및 해제 → 비운 연결이 원래 연결로 되살아나지 않는지 확인. + - 자체 검증(2026-11-07): 기존 LinkCode가 있더라도 TargetCode를 빈 값으로 설정하면 해당 내역 수량을 변경하지 않음. 수량 기능 시험 3개 통과. + - [x] 수식표와 산출서의 내역 반영을 같은 연결 검사로 처리하고 재계산 메뉴에서 선택한 자료를 반영 → 대상 누락·중복·수식 오류 시 전체 변경 차단. + - 자체 검증(2026-11-07): 수식표 참조 합계 8, 선택 산출서 9, 기존 MulCode 보존, 없는 대상의 전체 변경 차단. Edge 재계산 메뉴에서 선택 산출서 9·직접 작성 수식표 8 반영, 브라우저 오류 0. 수량·이력 관련 5개 통과. 다른 프로젝트를 열 때 이전 산출서 선택이 남지 않도록 초기화. + - [x] 예정공정표에 내역 일괄 추가와 금액 가중치 갱신 → 기존 일정·진도 보존 및 중복 방지 시험. + - 자체 검증(2026-11-07): 같은 코드 2행과 코드 없는 1행을 행 식별자로 구분하고 재추가를 방지, 내역 순서 변경 뒤에도 금액을 연결. 일정·진도·이름 유지 및 연결 모호성 차단을 기능 시험. Edge에서 3행 추가·재추가 방지·금액 200/300/400 갱신 및 JSON 저장, 오류 0. 설치 내역의 코드 없는 39행도 공정 추가 가능함을 확인. 원본과의 동등성 대조 미실시. + - [x] 수식표 항목 삭제 후 새 항목 추가 시 중복되지 않는 산출코드 생성 → 삭제·재추가와 참조 계산 시험. + - 자체 검증(2026-11-07): 남은 Q2가 삭제된 Q1을 참조할 때 새 항목을 Q3으로 생성해 참조가 새 항목에 잘못 연결되지 않음을 Edge에서 확인. 수량·공정 기능 시험 9개 통과. + - [x] 설계변경 비교에서 코드가 없는 내역도 품명과 수량·금액을 표시 → 당초·변경 차액과 화면 표시 시험. + - 자체 검증(2026-11-07): 코드 없는 `earthwork` 내역의 당초 100·변경 200·증감 100이 화면에 표시되는지 Edge와 기능 시험으로 확인. 관련 기능 시험 13개 통과·브라우저 오류 0. + - [x] 수량산출서 인쇄에 직접 작성 수식표와 산출서의 실제 수식·계산값·연결을 표시 → 계산 오류와 출력 데이터 시험. + - 자체 검증(2026-11-07): 수식표 2·참조 결과 6, 오류 수식의 계산 오류, 산출서 4+5 결과 9·연결 내역을 출력 데이터로 확인. Edge 인쇄 미리보기에서 두 종류의 산식과 결과 표시·브라우저 오류 0, 수량·설계변경·공정 기능 시험 14개 통과. + - [x] 수량산출과 직접 수식표에서 코드 없는 내역과 중복 코드의 개별 내역 행 연결 → 선택·계산·저장·재열기 시험. + - 자체 검증(2026-11-07): 같은 코드의 두 내역 중 둘째 행과 코드 없는 내역에 각각 6·9를 반영하고 JSON 저장·재열기 및 인쇄에서 대상 확인. 직접 수식표의 코드 없는 행 선택·결과 5 반영·연결 해제, 내역 순서 변경 뒤 식별자 유지, 잘못된 식별자 차단. Edge 오류 0, 기능 시험 15개 통과. + - [x] 연차 차수 위·아래 이동과 중복·기존 참조를 피하는 신규 차수 이름 생성 → 참조 순서 오류·저장 복원 시험. + - 자체 검증(2026-11-07): 기존 2차가 삭제된 1차를 참조하면 새 이름을 3차로 생성. Edge에서 2차를 1차 앞으로 이동했을 때 참조 오류 표시, 변경 순서 저장, 다시 원래 순서로 옮겨 오류 해소 확인. 연차·수량 기능 시험 10개 통과, 브라우저 오류 0. + - [x] 계약심사 화면: 사용자가 심사 수량·비목별 단가를 입력하고 기존 내역/심사액·차액을 비교, 심사 사본 열기와 JSON 저장 → 입력·원가 재계산·취소·저장/복원 시험. 자동 심사율·법적 기준은 정하지 않음. + - 자체 검증(2026-11-07): 일반 단가 행과 고정금액 행을 수정해 원가 포함 기존 1,210→심사 198 계산, 기존 내역 보존·실행 취소·JSON 저장/재열기·독립 ID의 심사 사본 확인. 잘못된 입력·없는 행의 사본 생성 차단. Edge 오류 0, 관련 기능 시험 47개 통과(25.68초). 원본 계약심사 동작 대조는 수행하지 않음. + - [x] 계약심사 결과요약서에 기존액·심사액·차액과 내역별 비교 출력 → 출력 데이터·미리보기 확인. + - 자체 검증(2026-11-07): 기존 200·심사 80·차액 -120 및 코드 없는 내역을 요약서 출력 데이터와 Edge 인쇄 미리보기에서 확인. 심사·문서 관련 8개 통과, 브라우저 오류 0. + - [x] 직접 작성 수식표·예정공정표 Excel 내보내기와 가져오기 → 참조 수식·내역 행 연결·일정·진도 유지 및 잘못된 입력 차단. + - 자체 검증(2026-11-07): Edge에서 Excel 내려받기→openpyxl로 수식·진도 변경→가져오기 및 내역 식별자 보존. 중복 코드·소수자리·진도 오류 차단, Excel·수량·공정 관련 17개 통과. openpyxl 환경의 날짜 API 사용 중단 경고 2건, 실패 0. + - [x] 산출근거의 내부 표지 문자가 Excel 파일을 손상하지 않도록 인코딩·복원 → 원본 표지와 표지처럼 생긴 일반 문자 왕복 확인. + - 자체 검증(2026-11-07): 제어 문자가 포함된 Excel 파일이 XML 파싱에 실패하던 상황을 재현한 뒤, 표지와 일반 문자열 `_x0012_`를 구분해 저장·openpyxl 편집·브라우저 재가져오기 왕복 확인. Edge 오류 0. + - [x] 수량산출서 문서·산출 행·항목의 Excel 내보내기와 편집 후 가져오기 → 표지·내역 연결 보존 및 계산 확인. + - 자체 검증(2026-11-07): 세 Excel 시트 내보내기, 산출 행 2×3→2×4와 품명 수정 후 가져오기, 표지·내역 행 연결·Excel 미표시 속성 보존 및 내역 수량 8 반영을 Edge에서 확인. 누락 시트·잘못된 표지·중복 순서 차단과 빈 원래 필드 유지, 수량·Excel 기능 시험 14개 통과. Edge 오류 0; openpyxl 날짜 API 사용 중단 경고 3건, 실패 0. + - 추가 보완: 기존 `LinkCode`만 있는 항목은 Excel에서 연결을 변경하지 않았을 때 새 연결 필드를 덧붙이지 않고 원래 구조를 유지. + - [x] 수량산출 행 편집 중 결과 표지가 삭제되거나 추가되면 이전 저장 수량이 잘못 적용되지 않도록 차단 → 화면·Excel 편집 후 계산 시험. + - 자체 검증(2026-11-07): 결과 표지가 0개 또는 2개인데 연결 표지가 1개인 행의 계산 오류와 내역 반영 차단, 기존 수량 1 유지. Edge에서도 표지 삭제 후 반영 차단·오류 0, 수량·Excel 기능 시험 15개 통과. + - [x] 계약심사 항목별 검토 사유 입력·저장 및 요약서 출력 → 금액 재계산과 사유 보존 시험. + - 자체 검증(2026-11-07): 심사 단가 변경과 한글 사유 입력 후 JSON 저장·재열기, 심사액 160과 요약서 사유 표시를 Edge에서 확인. 관련 기능 시험 8개 통과, 브라우저 오류 0. + - [x] 계약심사 입력·사유 Excel 내보내기와 수정 후 가져오기 → 내역 행 연결·재계산·입력 검증 시험. + - 자체 검증(2026-11-07): Excel `Review` 시트에서 심사 단가 80→60과 사유를 변경해 가져온 뒤 심사액 120 및 화면 사유 표시 확인. 중복 식별자·잘못된 숫자·식별자 오류 차단, 심사·Excel 기능 시험 12개 통과. Edge 오류 0, openpyxl 날짜 API 경고 4건. + - [x] Excel 계약심사 입력이 존재하지 않거나 중복된 내역을 가리키면 가져오기 자체를 차단 → 다른 표 교체도 함께 취소되는지 확인. + - 자체 검증(2026-11-07): 없는 내역 및 해당 행에서 사용할 수 없는 비목 입력 차단. Edge에서 잘못된 심사 행과 내역 수량 변경을 함께 가져왔을 때 두 변경 모두 적용되지 않음 확인. 심사·Excel 시험 14개 통과, 브라우저 오류 0. + - [x] 계약심사 개별 행의 입력·사유 초기화 → 다른 행 입력과 실행 취소 보존 시험. + - 자체 검증(2026-11-07): 한 행만 초기화해 다른 행의 수치·사유 유지, 마지막 행까지 초기화 시 심사 작업 비우기. Edge 실행 취소로 초기화된 사유 복원, 심사 기능 시험 4개 통과, 브라우저 오류 0. + - [x] 계약심사 고정금액 행의 사유·수량만 변경해도 기존 금액이 유지되도록 처리 → 비목 금액 변경과 구분 시험. + - 자체 검증: 수정 전 문제 재현, 수정 후 금액 유지와 비목 변경 재계산 확인. 관련 시험 16개 통과. + - [x] 연차 차수와 미확정 기성 회차·입력 Excel 편집 → 확정 회차의 계약·누계 보존 및 가져온 업무 계산 시험. + - 자체 검증(2026-11-07): 확정 회차는 내보내기 대상에서 제외하고 기존 계약·누계를 그대로 유지. Edge에서 미확정 금회 수량 1→3, 연차 수식 50%→25%를 Excel로 변경해 가져온 뒤 기성 누계 500·연차 250 확인. 없는 행·확정 회차·중복 ID·잘못된 입력 차단, Excel·기성·연차 시험 22개 통과. Edge 오류 0, openpyxl 날짜 API 경고 5건. + - [ ] 남은 웹 업무 기능을 이어서 구현하고 각 기능의 입력·계산·저장 흐름 확인. + +- [x] ESTX 원본 옵션·공사명 및 기존 BLOB 확장 저장 구현 → 설치 샘플 재읽기와 인덱스·다른 자료 보존 확인. CAD 제외. + - 자체 검증(2026-11-06): 설치 sample.estx에서 한글 공사명·자동계산·절사·자릿수 변경과 BLOB 12,000바이트 확장 저장 후 재읽기, 다른 속성·전체 인덱스·CAD 보존 확인. EST 전용 100개 통과(51.80초). 독립 파서 대조이며 원본 EST에서 파일을 열어보지는 못함. +- [x] WPTools 수량산출서의 기존 서식 구간 안 텍스트 편집 저장 → 실제 수량산출서 샘플 재읽기와 다른 문서 보존 확인. + - 자체 검증(2026-11-06): main.estx의 75개 수량산출서 중 한 문서 편집·재읽기, 나머지 문서·인덱스·CAD 유지, 서식 구간을 가로지르는 편집 거부 확인. EST 전용 102개 통과(70.77초). 원본 EST 직접 실행 비교는 미실시. +- [x] 원본 결과와 기존 계산이 일치하는 수량산출서의 결과 표지·수량 목록 재계산 저장. + - 자체 검증(2026-11-06): main.estx 수량산출서 폭 9→10 변경 시 표지 및 목록 수량 104→116으로 기록·재읽기, 다른 문서·인덱스·CAD 보존. EST 전용 102개 통과(70.78초). 계산 오류·기존 결과 불일치 문서는 저장을 거부하며 원본 EST 실행 검증은 미실시. +- [ ] 서식 구간을 넘는 수량산출서 편집과 목록·연결 변경 지원; 계산 오류나 기존 결과 불일치 문서의 처리 확인. +- [x] 수량산출서의 연속 글자 서식에 걸친 텍스트 편집 저장 → 서식 태그 보존 및 재읽기 검증. + - 자체 검증(2026-11-07): 서로 다른 세 글자 서식에 걸친 텍스트를 변경한 뒤 태그와 재읽기 결과를 대조. 변경 시작 위치의 서식으로 새 텍스트를 저장하며 위첨자·표지를 넘는 임의 편집은 계속 제한. 관련 시험 10개와 EST 전용 120개 통과(77.60초). 원본 EST 실행 비교는 미실시. +- [x] 설치 수량산출서의 실제 글자 서식 경계 편집을 회귀시험으로 보존 → 해당 문서와 태그 재읽기. + - 자체 검증(2026-11-07): main.estx N0000000113의 `27.22 =` 경계를 직접 변경하고 모든 태그와 재읽기 행을 비교. 설치본이 없으면 시험은 건너뜀. 해당 시험 1개 통과(4.13초). 문서 편집기 자료의 재읽기 검증이며 산식 의미 변경과 원본 EST 실행 비교는 아님. +- [x] 수량산출서의 내역 수량 반영에서 실제 내역이 없는 코드와 중복 코드를 차단 → 제목만 존재·중복·정상 연결 시험. + - 자체 검증(2026-11-07): 동일 코드의 상세 행 두 개가 모두 7로 바뀌던 오류를 재현하고 변경 없이 오류 표시하도록 수정. 제목만 존재하는 코드, 제목과 상세가 함께 있는 정상 코드, 여러 연결 중 하나가 없는 경우의 전체 반영 중단을 확인. 관련 시험 1개와 EST 전용 121개 통과(79.70초). +- [x] 한 수량산출서 행에서 글자 서식 경계와 다른 표지 구간을 동시에 편집 → 태그·표지 유지와 재읽기 확인. + - 자체 검증(2026-11-07): 두 서식에 걸친 문구와 별도 결과 표지 숫자를 동시에 수정하는 실패를 재현한 뒤 태그 보존·재읽기 일치 확인. ESTX 내보내기 관련 11개 통과(27.74초); 전체 121개 시험 이후 저장 경로의 이 조합만 추가 수정. +- [x] 기성 회차에서 원가 기호가 없는 여러 항목의 전회 누적을 항목별로 유지 → 설치 샘플의 빈 기호 확인 및 복수 항목 회차 시험. + - 자체 검증(2026-11-07): 설치 sample.estx에서 빈 기호 원가 행 확인. 합성 기성 2회차에서 앞 항목의 전회 200이 뒤 항목의 100으로 덮이던 실패를 재현한 뒤 200/100과 누계 500/250 확인. 기성 7개와 EST 전용 123개 통과(78.90초). 기호가 없으면 항목 이름과 동일 이름의 순서로 대응하므로 회차 사이에 같은 이름 항목을 재배열하면 원본 식별 근거가 부족함. +- [x] 연차 이름이 기준 참조 예약어와 겹쳐 차수를 잘못 참조하는 경우 차단 → 예약어와 정상 차수 시험. + - 자체 검증(2026-11-07): `기준`·`계약`·`계약수량` 이름이 차수 참조 대신 계약값으로 처리되던 상황을 재현하고 오류로 차단. 일반 차수 참조의 잔액 50 확인. 연차·업무 관련 16개 통과(14.08초). 기존에 예약어 이름을 사용한 웹 작업은 차수 이름과 참조를 바꿔야 함. + - 추가 전체 회귀: EST 전용 125개 통과(81.45초). 원격 CODEX 브랜치는 서버의 `CODEX.lock`으로 push가 거부되어 로컬 커밋 보존 중. + - 분석(2026-11-06): REA `0x11167e4`는 `MulCode`를 `0xa911d0`으로 분해한 뒤 수량 문서·항목을 찾고 `GN`을 복사한다. `0xa911d0` 기계어의 구분 문자열은 탭이다. 설치된 24개 ESTX의 내역 테이블에서는 `MulCode`가 채워진 사례가 없어 BLOB 인코딩·신규 할당의 원본 검증은 아직 부족하다. +- [x] 기존 ESTX 기본 수량 연결을 웹에서 표시 → REA의 탭 분리·대상 찾기 조건과 중복 연결 경고를 합성 데이터로 검증. + - 자체 검증(2026-11-06): 탭 분리 ASCII/UTF-16·기본 모드·중복 내역/다른 모드 경고 합성 시험 통과, EST 전용 117개 통과(76.52초). 실제 연결된 ESTX 샘플과 신규 연결 쓰기는 여전히 미확인. +- [x] 기성 원가계산서의 명시적 0원 도급액 보존 → 직접공사비가 양수인 경우와 원가계산서가 없는 경우를 각각 시험. +- [x] 물가변동 계약·제외·조정액 계산에서도 명시적 0원 도급액과 원가계산서 없는 경우를 구분. + - 자체 검증(2026-11-07): 수정 전 0원이 직접공사비로 대체되는 실패 재현, 수정 후 기성·물가변동에서 0원 보존 및 원가계산서 부재 시 직접공사비 대체 확인. 관련 11개와 EST 전용 119개 통과(76.85초). 원본 EST 실행 비교는 미실시. +- [x] 수량산출서 한 줄에서 서로 다른 표지 구간의 텍스트를 함께 수정하는 저장 지원 → 표지·서식 보존과 다중 편집 재읽기 검증. + - 자체 검증(2026-11-06): 설치 main.estx에서 한 줄의 품명·수식을 함께 변경해 모든 WPTools 태그 유지, 전체 ESTX 재읽기와 수량 104→125 반영 확인. EST 전용 115개 통과(77.82초). 같은 구간 안 여러 서식을 가로지르는 편집과 목록·연결 변경은 미완료. +- [x] 변경 없는 JDL 재출력 시 원본 확장 자료 보존, 수정 시 원본 무조건 반환 방지 → 서버 재계산을 거친 왕복과 수정 구분 시험. + - 자체 검증(2026-11-06): 임의 확장 파일이 포함된 JDL 원본 바이트 일치, 저장 ID 부여 후 보존, 이름 변경 후 새 이름으로 변환 및 경고 확인. EST 전용 103개 통과(71.14초). 원본 검사 DLL 인증은 미확인. +- [x] 인쇄 서식 선택 시 원본 서식에서 적용한 여백·행 수가 설정 입력란에도 표시되도록 수정. + - 자체 검증(2026-11-06): Node DOM 모의에서 서식 선택 후 여백 20·행 수 21이 입력란에 반영되는지 확인. 원본 인쇄 배치 비교는 아님. +- [x] JDL 일위대가의 기본 상세 항목 불러오기 → 자원 연결·저장 금액 보존 및 특수 항목 경고 검증. + - 자체 검증(2026-11-06): 합성 JDL에서 자재 연결·수량 2·금액 200 보존 및 특수 플래그 경고, 서버 계산 경로 통과. EST 전용 104개 통과(71.49초). 원본 JDL 실자료·실행 대조는 미실시. +- [x] JDL 기본 일위대가 구성 내보내기 및 불러오기 왕복 → 상세 자원·수량·금액 보존, 특수 구성은 기존 전개 경고 유지. + - 자체 검증(2026-11-06): 합성 자재 일위의 상세 수량·금액 및 내역 참조 왕복, 특수 구성의 전개 경고 확인. EST 전용 105개 통과(72.38초). 원본 JDL 인증·실행 대조는 미실시. +- [x] 해양 자료 산식의 단위·도식·그리스 변수·중괄호 수식 해석 개선 → 실제 행 시험과 원본 저장값 대조. + - 자체 검증(2026-11-06): 해양 오류 95→37건, 저장값 134,159/134,208 일치(기존 134,133); 수치 뒤 중괄호 주석을 산식으로 잘못 읽던 회귀 1건 수정. 측량 80,671/80,682·산림 15,049/15,055·가시설 13,978/13,979 및 오류 수 기존과 같음. EST 전용 110개 통과(73.49초). 누락 변수·모순 부호와 나머지 오류는 미해결. +- [x] 해양 자료의 복합 단위·괄호 설명 산식 추가 처리 → 실제 저장값과 다른 자료 회귀 비교. + - 자체 검증(2026-11-06): 해양 오류 37→22건, 저장값 134,159/134,208 유지. 측량·산림·가시설 대조 결과 변화 없음. 수준면 주석·도식 병기 및 붙은 변수 확장은 저장값 36/69건 차이가 발생해 보류. +- [x] 근사값이 병기된 변수 선언을 계산 값과 설명으로 분리 → 실제 원본 대조에서 기존 값 유지 확인. + - 자체 검증(2026-11-06): `Q1=3.2hr ≒ 0.5일` 선언 및 참조 시험, 해양 오류 22→21건·저장값 134,159/134,208 유지, 측량·산림·가시설 결과 유지. EST 전용 116개 통과(77.02초). +- [x] ESTX에 저장된 인쇄 서식 설정 읽기·미리보기 반영 → 설치 샘플의 서식 수·여백·행 수 및 원본 파일 보존 확인. + - 자체 검증(2026-11-06): 설치 sample의 41개 서식과 프로젝트명·여백·행 수, 인쇄 설정이 포함된 10개 ESTX 읽기, DOM 모의에서 프로젝트 설정 우선 적용 확인. EST 전용 113개 통과(72.97초). 웹 인쇄 설정의 ESTX 쓰기·원본 출력 배치 비교는 미완료. +- [x] 웹에서 변경한 인쇄 서식의 여백과 페이지당 행 수를 ESTX 원본 옵션에 기록하고 다른 필드 보존 검증. + - 자체 검증(2026-11-06): DOM 모의에서 사용자 여백 13·행 수 19 기록, 설치 sample에서 해당 서식 재읽기 및 나머지 서식·압축 내 파일 바이트 보존, 범위 밖 값 거부와 서버 계산 후 기록 유지 확인. EST 전용 114개 통과(73.42초). 원본 EST 실행 검증은 미실시. + +- 2026-11-06 후속 요청 — CAD 편집을 제외한 잔여 기능 구현. 기존 내역·계산·업무 기능을 유지하며 출력/변환과 원본 저장 경로를 확장한다. + - [x] REA와 설치 자료에서 인쇄 서식·XML/JDL·Excel·ESTX 저장 구조 확인 및 지원 범위 명시. + - [x] 전체 자료 Excel 입출력과 출력 서식/페이지 설정을 실제 파일·화면에서 검증. + - [x] DB의 XSD 1.0.5에 따른 XML 입출력·계층/원가/단가 변환, JDL 기본 표 입출력, 동일 구조 ESTX 수정 저장 구현·왕복 검증. 근거 미확인 형식을 완전 호환으로 가장하지 않음. + - 구현: Excel 스칼라 표/자료형과 기존 바이너리 보존, 단가 수정 전파, 코드/수식/중복 검사. XML 작성정보·연결/길이 검사·금액 보존 및 자동계산 해제, UTF-8/CP949/UTF-16 입력. JDLCHK 필드 정의와 EST TAB/ENQ·CP949 처리 경로에서 기본 표/ZIP 생성·읽기, 고정 단가 전개 제한 표시. ESTX 고정 행·비인덱스 필드/BLOB 원가 기록과 재읽기 검산. 재계산이 원본 호표 목록 PkID/인덱스 식별자를 버리던 문제 수정. + - 화면: CAD 제외 서식 이름 40개, 데이터 출력 및 서식별 직접 입력 문서, 용지/방향/여백/글자/행/쪽 번호. 예정공정표 기간·진도·가중치 입력/검사·기간 막대·가중평균, 공종별 동원 분리 출력. JSON 저장/재열기 및 이력 대상. + - 자체 검증(2026-11-06): Edge에서 XML 다운로드→실제 XSD 통과→재열기 금액/상하위 계층/0원 도급액 보존, JDL 다운로드/재열기 직접비·원가 보존, 예정공정 입력/저장 복원, CAD 제외 40개 서식 선택 시 JS 오류 0. Excel 왕복 시 바이너리·소수 유지, 66행 20행/쪽 분할과 쪽 번호 5~8, 본문/설정 저장 재열기 통과. 별도 openpyxl 읽기로 xlsx 구조/자료형 확인. 설치 sample.estx의 수량 변경→수정 저장→독립 재읽기 통과, 모든 .idx 바이트 불변. 원본 EST 실행 검증은 아님. + - [ ] 남은 완전 호환 범위: ESTX 신규 파일/행 증감·키 변경의 인덱스 재생성, WPTools 편집 저장, 기성/연차 원본 별도 업무 파일; JDL 확장 산식/기성·물가 자료와 원본 검사 DLL 인증; 원본과 같은 인쇄 도형/배치 및 기존 산식 잔여 오류. CAD만 제외한 전체 완료로 판정하지 않음. + - [x] 전용 회귀·포맷·700줄 제한·커밋/push 마무리. 검증 서버 종료 완료. + - 자체 검증: EST 전용 전체 99 통과(48.88초). 변경 파일만 prettier/ruff format, git diff --check와 모든 소스 700줄 이하 확인. a5157dd3a 커밋을 CODEX에 push, origin/CODEX와 차이 0·작업 트리 깨끗함 확인. 검증 서버 5175 종료, 이번 일회 UI/분석 스크립트·출력물·전용 시험 저장본 정리. 기존 원본 자료와 앱 data는 수정하지 않음. + +- 2026-11-06 사용자 지정 완료 범위 — 설계변경·기성·물가변동·연차 네 업무. 원본 실행 없이 REA 근거·시나리오·저장 복원으로 구현 완료를 판정하며, 전체 EST/CAD/변환 기능 완료와 구분. 검증 서버는 브라우저 시험 중만 실행하고 종료. + - [x] 설계변경: 당초 불변, 신규·삭제·변경의 수량/금액 비교, 0/1/2 당초 재계산과 저장/취소. + - [x] 기성: 수량·금액·비율 입력, 비목·비율/관급 행·고정 금액, 금회/사정/전회/누계·원가, 회차 확정/수정과 서버 저장 검산. + - [x] 물가변동: 입찰/계약/변동 단가 분리, 등락 분기·조사금액을 분모로 한 조정률, 적용제외 max/자동·수동 및 간접비 포함 적용대가, 입력 제어·저장 복원. + - [x] 연차: 차수 수식과 참조·정수 절사·잔액, 관급/비율/고정 금액, 독립 사본 및 오류 차단·저장 복원. + - 자체 검증(2026-11-06): EST 전용 87개 통과, 이후 추가한 당초 재계산 0/1/2 시험 포함 설계변경 3개 통과(총 88개). Edge에서 신규/삭제 비교·저장 재열기, 기성 금액/사정/누계 원가·확정/이후 회차 해제·서버 결과 변조 재검산, 계약/입찰 파일 순서 연결·자동/수동 제외·조사금액 분모·저장 복원 통과. 연차 성분/잔액·수식 수정·수수료99/관급/안전관리비·사본 독립 ID·저장 재열기 통과, JS 오류 0. 신규/복사 행이 삭제된 계약/기성 행 ID를 재사용하지 않도록 수정. 원본 업무 실행 샘플이 없어 런타임 동등성은 미확인. + - 통합 시험 제한: 기존 spreadsheet_size 빌드가 config/node_modules의 delaunator·@kninnug/constrainautor 누락으로 실패(41 통과 후 1 실패). EST 범위 밖이므로 수정하지 않음. + - [x] 네 업무 전용 회귀와 실제 Edge 조작/저장/취소를 통과하고 변경 파일 포맷·700줄 제한 확인, 커밋/자기 브랜치 push. + - 마무리: 변경 파일만 prettier/ruff format, git diff --check와 소스 700줄 이하 확인. 74ab66b00 커밋을 CODEX에 push 완료. 검증 서버 종료 및 5175 수신 없음 확인. + +- [x] 2026-11-05 연차 관급 수수료: REA f0fcc0의 LinkIndex 57→99와 GN 유지·성분 금액 배분을 반영. 고정 배분액의 저장/반복 계산 및 관급 원가·수수료 제외 옵션을 검증. + - 자체 검증: 기존 57행을 0원으로 만드는 실패를 재현한 뒤 수정. 연차 사본에만 원래 57행임을 보존해 관급 원가의 조달수수료 제외 계산 유지. 합산 제외 행은 원가 제외 상태 보존. 전용 시험 74 통과, 1,361원 모의 계약을 680/681원 배분 및 반복 계산 불변, 40% 변경 시 수수료 12/18·금액 544/817 검증. 원본 업무 실행 대조는 아님. + - Edge 자체 검증: 차수 사본의 99 표시·원래 요율 유지, 원가 반영, 저장/재열기·JS 오류 0. 원본 ID를 복제해 덮어쓰던 위험 제거(차수 파일 ID 별도 생성), 저장된 원본 1,361원·수수료 30 보존 확인. 차수 내역 열기 시 내역서 화면으로 이동. 기존 연차·저장 대기/재시도 회귀 확인. 원본 23파일의 대조 수·해석 오류 수는 직전 결과와 동일해 추가 회귀 없음. + +- [x] 2026-11-05 후속 산근 문법: 연산자 뒤 공백의 참조/선언 구분, 원본 금액 단위, 결과를 감싼 중괄호와 주석형 계산, 수치 범위 조건 구분. 원본 발췌·변경 전파·잘못된 참조 거부 시험 및 원본 전체 대조로 검증. + - 자체 검증: 전용 시험 72 통과. 원본 23파일 재대조에서 측량설계 80,671/80,682 일치·해석 오류 0, 산림토목 15,049/15,055 일치·오류 0, 해양 134,133/134,208 일치·오류 95. 상수공사 중괄호 산식의 저장 표지 1.7과 계산 1.79 차이는 원문 표지 오류 후보로 남김(정상값으로 위장하지 않음). + - REA f250bc/f251d5-f251df의 Extended 누적 후 자릿수 적용을 확인하고 소계의 사전 Currency 4자리 절삭 제거. 실제 수량 0.169776·재료비 98,103.7 재현. Edge에서 치수 편집→소계 0.179496·재료비 103,720.3·내역 1,037,200 전파, 서버 저장/재열기·취소 확인, JS 오류 0. + - 설명에 붙은 변수의 자동 인식은 부호 해석과 수치 대입식의 충돌 때문에 적용 보류. REA 937958/936bd0/9392e0의 중괄호 토큰 경로를 확인했으나 변수 치환까지 증거가 충분하지 않아 기존 연결 규칙을 유지. 기존 전체 동등성 미완료 항목과 별개. + +- 2026-11-05 산근 지정 단가·절사 합계 보완: 원본 f2f2e4→f2ef54 구간 수집과 지정 단가 원문 확인. 결과 없는 단가 행 갱신 보존, 구간/소계에 03 단가 표지 포함, Link62의 합계 표지를 최종 자동합계와 구분. 따옴표 Q1 선언 지원. 앞 성분의 저장 합과 절사 관계가 확인되는 정수 최종합계는 변경 성분에서 재집계. 측량설계 80,659/80,682 일치·오류 5건. 해양 운반비의 결과 없는 하역료 소계 누락을 추가 수정해 신규 불일치 해소. 전용 시험 64 통과, Edge에서 단가 550→600·구간 27.5→30·최종 27→30·내역 270→300 전파 및 저장·취소 확인, JS 오류 0. 저장 대기·재시도 회귀도 통과. 원본 전체 동등성 미완료. + +- 2026-11-05 원본 산근 문법 보완: 가시설·측량설계 원문의 배/번/줄/set/kg/set/㎜ 및 괄호 뒤 체적·면적 단위, 별표 중량 선언의 닫는 별표, 설명 열 분리 후 남은 쉼표 처리. 실제 원문 발췌와 수치 변경 전파 시험 4개 추가, 전체 전용 61 통과. 측량설계 저장값 80,624→80,658/80,682 일치·해석 오류 60→10, 가시설 13,978/13,979 일치·오류 8→4. 기존 소계/비율/구간 편집·취소·저장과 수동계산 저장 복원 브라우저 회귀 통과, JS 오류 0. 범위 조건·누락 참조 및 원본 오류는 임의 값으로 대체하지 않음. + +- 2026-11-05 대용량 실행 취소 보완: 기존 10MB 초과 문서의 이력 누락 제거. 브라우저 gzip으로 최근 8단계 보존, 압축 기능 미지원 시 원문으로 보존. 취소/다시 복원 중 입력·문서 버전이 바뀌면 복원 폐기, 현재 파일 ID 유지. 보존 시험 추가 및 Edge 11MiB 문서 취소/다시·추가 입력·문서 전환 보호 확인, JS 오류 0. 기존 저장 지연/재시도 브라우저 회귀 통과, 전용 시험 57 통과. 전체 동등성은 계속 미완료. + +- 2026-11-05 대용량 당초 확정 보완: 사본의 중복 당초 필드·도면·현재 원천 목록을 제외하고 재계산 입력만 보존. 작업본·원본 압축 자료는 유지. main.estx 확정 JSON 293,074,097→214,621,549바이트로 256MiB 요청 한도 충족. 별도 임시 데이터 경로의 실제 저장 API에서 221,430,352바이트 저장·산근 77,395행·원본 압축 해시 보존·계산 오류 0 확인. 전용 시험 56 통과. 다음 작업: 대용량 문서도 실행 취소를 기록하고 비동기 복원 중 입력/문서 전환을 보호. + +- 2026-11-05 저장 흐름 보완: GN 133→134 입력 후 셀을 벗어나지 않고 Ctrl+S 하면 133이 저장되는 오류 재현 후 수정. 활성 셀 확정·저장 요청 직렬화·요청 시점 사본·문서/수정 버전 확인으로 대기 중 새 입력이나 다른 문서가 이전 응답으로 덮이지 않도록 처리. 첫 저장 전 파일 ID 부여, 취소/다시 실행 시 현재 파일 ID 유지. Edge 요청 지연 시험으로 연속 저장·추가 입력 보존·문서 전환·다른 이름 저장·취소·실패 후 재시도 확인, JS 오류 0. 기존 12화면·당초 비교 저장 복원 회귀도 통과. 계산 시험 54개는 직전 엔진 기준 통과 상태이며 이번 수정은 화면 저장 경로에 한정. + +- 2026-11-05 당초 비교 보완: 별도 웹 확정 사본이 없으면 원본 EstMainDat의 GN_/TC_ 저장값으로 설계변경 증감 표시. 0원 당초와 신규 행을 구분하고 명시적 확정 사본이 있으면 원본 필드보다 우선. 원본 숫자 필드의 잘못된 JSON 형식 거부 추가. 전용 시험 54 통과; Edge에서 당초 100/변경 150/증감 50 표시→저장/재열기→현재값 확정 150 우선→취소 후 100 복원 확인, JS 오류 0. 원본 원가 서식 활성 인덱스·당초 전체 테이블 자동 복원은 임의 확정하지 않음. + +- 2026-11-05 동원·원천 연결 보완: REA 10e56b8/10e6218의 비목 배수를 산근/일위 재귀에 전파. 노무 80%·재료 90% 개별 낙찰률 유지, 하위 호표의 한 성분만 참조할 때 중복 전개 방지, 복수 단위환산 누적. 금액만 입력한 행·비율 경비를 원본 L/M/E/SZZ 코드로 누적하고 시간 환산 불가 경비를 금액으로 보존. 산근 단가는 품명 표지 유무와 관계없이 각 행의 원천 Code/LinkIndex로 조회, 연결 해제 행이 앞 행의 원천을 상속하지 않도록 수정. 전용 시험 52 통과(700줄 제한에 맞춰 연차·동원 시험을 test_est_business.py로 분리). Edge에서 비목별 80/90 적용→소요량 8/9·금액 800/900, 저장 복원 및 기존 소계·연차 조작 확인, JS 오류 0. main.estx 원천 전체 갱신→재계산 오류 0·산근/일위/내역 반복 안정성 확인(2회 13.942초). 원본 실행 수치 대조는 미확인. + +- 2026-11-05 연차 배분 보완: REA f0fcc0/f0f9b8/f1098c의 차수 수식을 수량·각 성분 금액에 독립 적용하고 금액 정수 절사. 단가를 비운 고정 금액 사본으로 생성해 재계산 시 금액 유지, [기준]-[1차]로 절사 잔액 이월. 수량 0·고정 금액, 사본 독립성, 중복 차수명 거부 검증. Edge에서 8원 기준의 1·2차 3/5원→수식 25% 편집 1/7원→차수 사본 열기/저장/재열기 및 원본 불변 확인, JS 오류 0. 전용 시험 47 통과. 원본 업무 실행 대조와 연차 전체 분기 동등성은 미완료. + +- 2026-11-05 산근 연결 보완: REA f250bc(61 소계)·f280f8(58 비목 참조)·f2ef54(62 선택 합계) 경로를 단가 변경 시 다시 계산. 6/7 제어 표지를 표시·편집하고 같은 이전 금액의 서로 다른 행도 독립 집계. f2c680/f2cba8 낙찰 성분 순회·Currency 4자리 및 최종 51/52 행 금액 반영 추가. 결과 표지 없는 자동 합계 식의 NaN과 수정 후 남던 Error 상태 제거. 소계 표지 1,433개 추가해 설치 main.estx 저장값 115,145/115,145 일치·오류 0. 실무 산불 세 파일은 소계 포함 8,411/8,411 일치·원본 괄호 오류 각 1건 유지. 전용 시험 45 통과. Edge에서 단가 100→150 → 산근 소계 300·두 비율 각 15·내역 3,300 전파, 구간 편집/취소/저장 및 12화면·수량 저장 복원 JS 오류 0 확인. 미완료 범위는 계속 남김. + +- 2026-11-05 인쇄 누락 수정: 화면의 100행 페이지만 인쇄하던 동작을 전체 검색 결과/현재 호표와 현재 자료 전체 범위 선택 미리보기로 교체. 내역·일위·산근·기계·원가의 출력 열, 성분 금액과 소수 수량, 오류 및 문서 제목 보존. Edge에서 206행 전체→PDF 6쪽·마지막 행·검색 1행→전체 206행·산근 표지 제거·JS 오류 0 확인; PDF 첫/끝쪽 이미지로 잘림 없음 확인. 계산 회귀 39 통과. 원본 인쇄 양식의 동일성은 미확인. + +- 2026-11-05 추가 구현: 원천/호표 코드 편집 시 작업본 참조와 목록 코드를 함께 갱신, 이전 코드 별칭으로 당초 단가 재계산 유지, 당초 스냅샷 불변·중복 거부·취소 검증. 분수 열 한 칸 공백·가운뎃점·숫자 붙은 변수·min/m2 단위, 음수 {-} 표지와 식 내부 주석·설명 괄호 수정. 원본 TCostOption RTTI CostValueTrunc(+0x34)·MidCostDiget(+0x40), f1df70→f2df14→f254c8 연결 확인 후 가져오기·절사 계산·설정 화면 반영. 해양/산림/가시설 원본 3묶음 회귀 자료 보존. 전용 시험 39 통과. 추가 원본 해양 저장값 133,635/133,710 일치·해석 오류 99건 남음; 조경 93,928/93,932·오류 0. 원본 오류/모드 미확인 및 미구현 기능 있어 완료 처리하지 않음. + +- 2026-11-05 후속 대조: 실무 산불 3파일 DBISAM 재사용 BLOB 꼬리의 할당 공간과 논리 길이 구분 수정. 저장 금액 8,312/8,312 일치하나 공통 원본 괄호 누락식 D0000000194 한 건은 해석 오류로 남김. 직접재료비 별표 구획, 산업안전 관급 조달수수료 제외, Gangub=0 원액 유지, 낙찰·단위환산 후 동원 수량/장비시간 수정. 분수 안의 연산자 공백·ASCII x·주/톤 단위를 처리하고 회귀 시험 보존. 전용 시험 34 통과; Edge에서 자동계산 해제 열기/저장/재열기 금액 유지·원천 복사 코드 중복 방지·설정 두 옵션·수량 연결 및 저장 복원·12화면 JS 오류 0 확인. 추가 설치 원본 23파일의 잔여 차이 분석 중. 완료 판정 아님. + +- 2026-11-05 수량 연동: WPTools 원본 75개 산출서의 글·표지·위첨자 및 개별 표지 정밀도를 가져와 편집·재계산·내역 반영·저장 복원. 449개 수량 중 446개 일치, 3개는 원본 글 산식과 저장 수량 불일치(286↔0.35×1.3×220=100.1, 0↔1×1=1, 138.72↔1.25×2×68×1.02=173.4). 원본 저장값과 재계산값 동시 표시, 원본 실행 미확인으로 원인 단정하지 않음. 수식 해석 오류 0, 회귀 시험 보존. Edge에서 폭 9→12 편집→연결 내역 수량 139→저장/복원 확인. + +- 2026-11-05 계속: 대용량 main.estx의 전체 저장값 113,680/113,680 일치(일위 52,530·기계 17,675·내역 205·산근 표지 전체 23,889·호표 목록 19,381). f1a8c4 코드 문자별 SKind 선택, f3242c LinkIndex68 집계 교체, f1580c Currency 정수 환산, 산근 DigetIndex·복수 표지·Currency 합산 반영. 원본 발췌 900여 행과 설치 원본 자동 대조 시험 추가. 원천 갱신 전체 계산 오류 0 및 재계산 안정성 확인. 전용 시험 22 통과. 원본 실행 비교·CAD·원본 파일 수정 저장 등 남아 있어 완료 판정 아님. + +- 2026-11-04 후속 구현: 이전 축소 데모 대신 원본 테이블 기반 `native-*` 엔진과 표 편집 화면으로 교체. 독립 Node 서버 5175, 로그인·공용 DB 의존 없음. ESTX 읽기(22개 표·17개 옵션·원가 서식 4종), 원본 바이너리 보존, JSON 파일 및 로컬 저장소 보관, 취소·다시 실행 구현. + - 자체 검증: 원본 REA 샘플 275/275(기계 48·일위 41·내역 37·산근 결과 118·호표 8·원가 수식 23). 도급액 고정 반복 차이 324,-32,3,0. 단가 변경 전파 및 반복 재계산 안정성, 기성 사정·전회 누계, 연차 40/60 배분, 동원 전개, 적용제외 간접비 포함 물가조정 시험 추가. 전용 pytest 20 통과. + - 브라우저 자체 검증: Edge에서 수량 편집·취소/다시·저장 다운로드·서버 저장 재조회·새로고침 복원, 업무 화면 12종 열기, 앱 내부 275개 대조 통과. JS 오류 0. 대용량 main.estx(산근 77,395행 등) 추가 대조 진행 중이며 전체 동등성 완료 아님. + - 전체 시험: 41 통과 후 기존 spreadsheet_size 시험이 누락된 delaunator 및 @kninnug/constrainautor 의존성으로 실패. 이 앱 전용 시험과 별개이며 전체 통과로 보고하지 않음. + - 남은 검증/구현: 대용량 산근·일위 저장값 불일치 분석, 설계변경 재계산 0/1/2 경로 상세 검증, 수량 원본 편집기 연결, CAD/VEC0650 편집, 원본 인쇄 서식·Excel/XML/JDL·ESTX 수정 저장. 원본 실행 동등성 미검증. 사용자 요청은 계속 진행하며 완료 처리하지 않음. + +- 사용자 정정: 축소 계산 데모가 아니라 EST와 유사한 화면 및 기능을 갖춘 독립 프로그램. 아래 기록은 이전 데모 검증이며 완료 판정 아님. +- [ ] EST 작업 화면(내역·일위·단가·기계·견적·표준·자재·노임·수량·원가)과 조작 흐름 구현 +- [ ] 분석 근거에 따른 계산·연결과 작업 파일 보존, 주요 업무 기능 구현 및 검증 +- [ ] 원본 미확인 기능과 미구현 범위 명시, 브라우저·계산 시험 결과 기록 + - 진행: 표 중심 화면으로 수정, 수량산출→내역 반영, 기성 수량·사정 누계 시험 기능 추가. 원본 화면 실행 불가, REA 자료로 진행(사용자 확인). + - 자체 확인: 전용 pytest 3 통과; Edge에서 단가 변경, 수량 반영, JSON 저장·열기, 기성 금회·사정 누계 조작 확인. 원본 동등성 미검증. 기계경비·수식 단가산출·설계변경·기성 회차 및 원가·물가변동·ESTX 변환 등 미구현이므로 완료 아님. + +- [x] `tools/est-test/`에 로그인·공용 DB 없는 독립 웹앱: 기초 단가 → 일위대가 → 내역 → 원가 연결과 입력 제어 +- [x] 시험 자료임을 표시하고 JSON 저장·열기 제공; 사용자 입력 요율과 계산 결과 확인 +- [x] 자체 검증 — 전용 pytest 2 통과; Edge 브라우저에서 단가 변경 → 일위대가·내역·원가 전파 및 JSON 저장·열기·초기화 확인. 원본 동등성 미검증, 단가산출 수식·ESTX 변환 및 기성·물가변동은 범위 밖. + - dev 수신 뒤 전체 시험은 9%까지 실패·오류 발생해 중단; 첫 실패 재실행은 41 통과·1 실패(기존 spreadsheet 빌드에서 `delaunator`·`@kninnug/constrainautor` 의존성 누락). 나머지 실패 원인 미확인. + diff --git a/tools/est-test/README.md b/tools/est-test/README.md index 02f0b2937..f032f7c0d 100644 --- a/tools/est-test/README.md +++ b/tools/est-test/README.md @@ -4,6 +4,8 @@ 내역·일위대가·수식 단가산출·기계경비·기초 단가·원가계산서를 원본 테이블 구조로 편집합니다. 수량 연결, 설계변경 당초 보존, 낙찰률, 기성 회차와 사정 누계, 품목조정, 연차 배분, 소요 자원 전개, 예정공정표 화면을 제공합니다. 실행 취소·다시 실행, 검색, 행 편집, JSON 저장·열기, CSV·Excel·조달청 XML·JDL 기본 표 입출력과 브라우저 인쇄를 사용할 수 있습니다. +작업모드의 `자료 오류 검색`은 코드 중복, 연결 자료 누락, 연결된 품명·규격 차이와 계산 오류를 표시합니다. 항목의 `행 열기`로 해당 자료 위치로 이동할 수 있습니다. 품명·규격 차이는 사용자가 확인할 항목으로 표시합니다. + 인쇄 미리보기는 화면의 100행 페이지 제한 없이 검색 결과/현재 호표의 전체 행을 표시합니다. 출력 범위에서 현재 자료의 모든 호표·행도 선택할 수 있습니다. 원본 인쇄 옵션의 41개 항목 중 CAD를 제외한 40개 서식 이름을 선택하며, ESTX에서 가져온 해당 프로젝트의 인쇄 설정을 우선 사용합니다. 내역·원가·호표/총괄·증감·동원·수량·공정은 표 자료로 출력합니다. 표지·갑지·설명서·시방서·심사 문서는 서식별 본문을 직접 입력합니다. 용지·방향·여백·글자 크기·페이지당 행·시작 쪽·업체명을 저장하고 인쇄/PDF로 출력합니다. ESTX 수정 저장은 서식별 여백과 페이지당 행 수를 반영합니다. 다른 웹 인쇄 설정의 ESTX 쓰기와 원본 인쇄 도형·병합·글꼴 배치의 동등성은 지원하지 않습니다. 별도 인쇄 서식으로 기성·물가변동의 내역서와 원가계산서, 연차 배분표와 연차별 내역서, 설계변경 원가 증감표를 선택할 수 있습니다. 기성은 선택한 회차를 출력하고 확정된 회차는 확정 당시 결과를 사용합니다. diff --git a/tools/est-test/index.html b/tools/est-test/index.html index 7cc40bb8f..11d0c9f39 100644 --- a/tools/est-test/index.html +++ b/tools/est-test/index.html @@ -19,6 +19,7 @@ + @@ -114,6 +115,7 @@ > + diff --git a/tools/est-test/native-actions.js b/tools/est-test/native-actions.js index abceb7289..adf5d305f 100644 --- a/tools/est-test/native-actions.js +++ b/tools/est-test/native-actions.js @@ -477,6 +477,7 @@ const EstActions = (() => { EstSchedule.install(); EstExchange.install(); EstBusinessActions.install(); + EstIssues.install(); document.addEventListener("click", async (event) => { try { const marker = event.target.closest("[data-marker]"); diff --git a/tools/est-test/native-app.js b/tools/est-test/native-app.js index b1d0b6754..23cfd2541 100644 --- a/tools/est-test/native-app.js +++ b/tools/est-test/native-app.js @@ -34,6 +34,7 @@ const EstApp = (() => { review: "계약심사", resources: "동원 집계", schedule: "예정공정표", + issues: "자료 오류 검색", drawing: "도면·문서", }; const esc = (value) => diff --git a/tools/est-test/native-extra.js b/tools/est-test/native-extra.js index 158fee9af..8eb05a9cf 100644 --- a/tools/est-test/native-extra.js +++ b/tools/est-test/native-extra.js @@ -20,6 +20,10 @@ const EstExtra = (() => { EstSchedule.render(); return; } + if (state.view === "issues") { + EstIssues.render(); + return; + } const { project, view } = state, { esc, number, byId } = EstApp; let html = ""; diff --git a/tools/est-test/native-issues.js b/tools/est-test/native-issues.js new file mode 100644 index 000000000..bbc17b769 --- /dev/null +++ b/tools/est-test/native-issues.js @@ -0,0 +1,100 @@ +const EstIssues = (() => { + let page = 0; + const grouped = new Set(["HeadMainDat", "CostMainDat", "MachMainDat"]); + const kinds = { + 5: "StuffcDat", + 6: "LaborcDat", + 21: "SilJukDat", + 101: "EstiMateDat", + 103: "HeadMainDat", + 104: "CostMainDat", + 105: "MachMainDat", + }; + function scan(project) { + const issues = [], + sources = new Map(); + for (const [kind, table] of Object.entries(kinds)) { + const codes = new Map(); + (project.tables[table] || []).forEach((row, index) => { + if (!row.Code || (grouped.has(table) && !(Number(row.Index) > 0))) return; + const list = codes.get(String(row.Code)) || []; + list.push({ row, index }); + codes.set(String(row.Code), list); + }); + sources.set(Number(kind), codes); + for (const [code, list] of codes) + if (list.length > 1) + for (const { index } of list) issues.push({ table, index, code, message: "코드 중복" }); + } + for (const table of ["EstMainDat", "HeadMainDat", "MachMainDat"]) { + (project.tables[table] || []).forEach((row, index) => { + if (Number(row.Level) > 0 || Number(row.Index) > 0 || !row.Code) return; + const codes = sources.get(Number(row.LinkIndex)); + if (!codes) return; + const matches = codes.get(String(row.Code)) || []; + if (!matches.length) + issues.push({ table, index, code: row.Code, message: "연결 자료 없음" }); + else if (matches.length > 1) + issues.push({ table, index, code: row.Code, message: "연결 코드 중복" }); + else + for (const field of ["Name", "Size"]) { + const a = row[field], + b = matches[0].row[field]; + if (a && b && EstNative.normalize(a) !== EstNative.normalize(b)) + issues.push({ + table, + index, + code: row.Code, + message: field === "Name" ? "연결 품명 차이" : "연결 규격 차이", + }); + } + }); + } + for (const message of project.calculation?.errors || []) + issues.push({ table: "", index: -1, code: "", message: String(message) }); + return issues; + } + function render() { + const { state, esc, byId, titles } = EstApp, + issues = scan(state.project); + page = Math.max(0, Math.min(page, Math.ceil(issues.length / 100) - 1)); + const rows = issues.slice(page * 100, page * 100 + 100); + byId("work-content").innerHTML = + `
자료 오류 검색${issues.length}건 · ${page + 1}/${Math.max(1, Math.ceil(issues.length / 100))}쪽

연결 품명·규격 차이는 확인이 필요한 항목으로 표시합니다.

${rows.map((item) => ``).join("")}
자료행코드내용이동
${esc(titles[item.table] || item.table || "전체 계산")}${item.index >= 0 ? item.index + 1 : ""}${esc(item.code)}${esc(item.message)}${item.table ? `` : ""}
`; + } + function install() { + document.addEventListener("click", (event) => { + const step = event.target.closest("[data-issue-page]"); + if (step) { + page += Number(step.dataset.issuePage); + render(); + return; + } + const node = event.target.closest("[data-issue-table]"); + if (!node) return; + const table = node.dataset.issueTable, + index = Number(node.dataset.issueRow), + rows = EstApp.state.project.tables[table] || []; + if (!rows[index]) return; + let group = ""; + if (grouped.has(table)) + for (const [code, item] of EstNative.groups(rows)) + if (index >= item.start && index < item.start + item.rows.length) { + group = code; + break; + } + if (grouped.has(table) && !group) { + EstApp.state.notice = "묶음 코드가 중복되거나 해당 행의 묶음이 없어 이동할 수 없습니다."; + EstApp.render(); + return; + } + EstApp.navigate(table, group); + const visible = EstApp.visibleRows(), + position = visible.findIndex((item) => item.index === index); + if (position >= 0) EstApp.state.page = Math.floor(position / 100); + EstApp.state.selection = new Set([index]); + EstApp.render(); + }); + } + return { scan, render, install }; +})(); diff --git a/tools/est-test/server.cjs b/tools/est-test/server.cjs index e09bff232..14c635b26 100644 --- a/tools/est-test/server.cjs +++ b/tools/est-test/server.cjs @@ -53,6 +53,7 @@ const allowed = new Set([ "native-views.js", "native-actions.js", "native-business-actions.js", + "native-issues.js", "native-extra.js", "native-settings.js", "native-report.js",