fix(est-test): preserve JDL percent totals

This commit is contained in:
2026-11-10 06:26:03 +09:00
parent ae31ac00fb
commit d1c6806024
6 changed files with 41 additions and 8 deletions
+21
View File
@@ -142,3 +142,24 @@ def test_jdl_fixed_unit_percent_exports_a_consistent_quantity():
assert result["part"]["F_MPRICE"] == result["part"]["F_MCOST"] == 10
assert result["row"]["GC"] == 10
assert result["total"] == 20
def test_jdl_estimate_percent_quantity_and_fixed_amount_round_trip():
project = json.loads((ROOT / "tools/est-test/sample.json").read_text(encoding="utf-8"))
for table in project["tables"]:
project["tables"][table] = []
script = """const fs=require('fs'),j=require('./tools/est-test/jdl.cjs'),a=require('./tools/est-test/archive.cjs');
const p=JSON.parse(fs.readFileSync(0,'utf8')),blank=structuredClone(p);
p.tables.StuffcDat=[{Code:'M',Name:'material',GC:200,TC:200}];
p.tables.EstMainDat=[{Code:'M',Name:'rate',Unite:'%',LinkIndex:5,GN:10,GU:200,GC:20,TC:20},
{Name:'fixed',Unite:'%',CalcIndex:1,GC:30,TC:30},{LinkIndex:54}];
const out=j.output(p),files=a.unpack(out.bytes),parts=j.parse('mainpart.txt',files.get('mainpart.txt')),
back=j.read(out.bytes,blank);
process.stdout.write(JSON.stringify({parts,rows:back.tables.EstMainDat}));"""
result = json.loads(
subprocess.check_output(
["node", "-e", script], input=json.dumps(project).encode(), cwd=ROOT
)
)
assert [part["F_QQTY"] for part in result["parts"]] == [10, 100]
assert [row["TC"] for row in result["rows"] if not row.get("Level")] == [20, 30, 50]
+1 -1
View File
@@ -567,7 +567,7 @@ def fixture(path):
]
stride = 25 + sum(width + 1 for _, _, width in fields)
data = bytearray(512 + 768 * len(fields) + stride)
data[8:24] = bytes.fromhex("068abe8e592364cb403d71d2e3bc64d0")
data[8:25] = bytes.fromhex("068abe8e592364cb403d71d2e3bc64d001")
struct.pack_into("<IHH", data, 41, 1, stride, len(fields))
start = 512 + 768 * len(fields)
offset = 25
+10
View File
@@ -423,6 +423,15 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD
- 백그라운드 상태 감시 및 자동 알림: `tools/est-test/monitor.cjs`를 통해 15초 주기로 `orca.exe` CLI(`shell: false`, timeout 4~5s)를 호출하여 CODEX 워크트리의 안티그래비티 작업 상태와 EST 5175 서버 헬스를 조회하고, 상태 변경 시에만 `monitor.log`에 기록(최대 512KB 순환). 안티그래비티 완료/대기 전이 시 Codex Orchestration Run(`run_cdb1558b9280`)으로 단발성 자동 알림(`status`/`messageId=msg_2c7bca748f91`)이 실제 전달됨을 확인(중복 폭주 방지 플래그 적용, 민감 환경변수 미기록, 재시작/자동지시 없음).
## Codex · EST 독립 테스트 앱 (2026-11-04)
- [x] JDL 내역의 퍼센트 수량을 가져오기·내보내기에서 같은 기준으로 계산하고 고정 금액 왕복을 검증한다.
- 자체 검증: 일반 내역 10%×200=20, 고정 내역 100%×30=30을 출력·재가져와 합계 50 유지. JDL·업무·오류 검사 61개 통과. 원본 JDL 검사기 통과 여부는 미확인.
- [x] 서명 강화 이후 ESTX 시험 파일의 엔진 서명을 실제 17바이트 형식에 맞추고 실패한 저장 시험을 다시 확인한다.
- 자체 검증: 실제 ESTX 저장·수량 편집 시험 41개 중 39개 통과, 합성 파일 서명 누락으로 실패한 2개는 시험 자료 수정 후 재실행 통과. 손상 서명 거부 시험도 통과. 원본 프로그램 실행 시험은 아님.
- [x] 시작 명령이 자동 갱신 감시를 사용하고 접속 주소 안내가 실제 바인딩과 일치하는지 확인한다.
- 자체 검증: 시작 명령이 감시 프로그램을 실행하도록 변경, 감시 재시작 시험 1개 통과. 기존 서버의 테일스케일 주소 HTTP 200과 감시 프로세스 확인. 시작 명령 자체의 별도 실행 시험은 하지 않음.
- [x] 비목 합계 수식에 뒤따르는 숫자 대입식을 구분하고 앞선 비목·변수 변경 전파와 원본 회귀를 확인한다.
- 자체 검증: 비목 100→120과 변수 5→4 변경 시 합계 20→30 전파. 설치 ESTX 24개 비교에서 산식 오류 14→13건, 저장 결과 일치 114,379→114,381건, 파일별 일치 감소 없음. 원본 실행 비교는 미실시.
@@ -504,6 +513,7 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD
- 자체 검증: 설치 main.estx의 미참조 목록 삭제 후 나머지 목록·산출 행·전체 인덱스 보존 및 재읽기, 문서 표지와 숨겨진 원본·현재 내역 연결에 의한 삭제 거부 확인. 코드가 없는 기존 목록 항목도 이름 수정 가능함을 실제 파일로 확인. 관련 회귀 35개 및 최종 추가·삭제 보호 5개, 기존 코드 누락 호환 1개와 원본·현재 연결 보호 3개 통과. 원본 EST 실행 검증은 하지 못함.
- [ ] 설치된 JDL 검사 DLL의 호출 규약과 결과를 조사해 생성 파일 검사에 활용한다.
- 진행: 32비트 DLL의 `GetDLLVersion` 호출은 1.03을 반환. `IsCertifiedJDL`은 디렉터리 인자를 받는 경로로 확인했으며, 기본 내보내기 파일을 임시 폴더에 풀어 호출한 결과 하위 바이트 0. `JDLCheck`는 한 문자열 인자의 stdcall 경로로 확인했으나 임시 자료 호출이 15초 안에 끝나지 않아 별도 프로세스를 종료했다. 반환 의미와 화면 없이 완료하는 방법은 미확인이며 인증 실패나 검사 성공으로 단정하지 않는다.
- 추가 조사(2026-11-10): DLL의 `JDLCheck`(0x4e4ae8)는 검사 시작 시 `GetJDLAnnouncement`(0x4e58f8)를 호출하며, 이 함수에 `http://www.g2b.go.kr:8081/emptyFile/jdldll.html` 주소가 들어 있다. 해당 주소는 이 PC에서 5초 제한 요청 시 시간 초과됐다. 이전 검사 지연의 유력 원인이지만 호출 중단 위치를 확인하지 못해 확정하지 않는다. 원본 DLL 수정이나 우회 없이 검사 결과를 얻는 방법은 미확인.
- [x] 기존 수량산출서 이름을 원본 제목 표에 저장한다. 기존 문서·목록·인덱스 보존과 실제 파일 재읽기를 검증한다.
- 자체 검증: 설치 main.estx에서 이름 변경 후 재읽기와 문서·목록·인덱스 불변 확인. 제목 표가 따로 수정된 충돌을 거부하는 시험과 숨겨진 연결 보호 시험 통과. 원본 EST 실행 검증은 하지 못함.
- [x] 원본 수량 목록이 비어 있는 기존 산출서에도 항목 추가를 지원하고 실제 파일로 재읽기·기존 서식 보존을 검증한다.
+1 -1
View File
@@ -1,6 +1,6 @@
# EST 독립 웹앱
`start.cmd`를 실행한 뒤 **http://127.0.0.1:5175** 로 접속합니다. Node.js가 필요하며 별도 패키지 설치는 없습니다. Aislo 서버·로그인·DB와 연결하지 않습니다.
`start.cmd`를 실행한 뒤 테일스케일에서 **http://100.65.141.15:5175** 로 접속합니다. 소스 변경은 감시해 서버를 자동으로 다시 시작합니다. Node.js가 필요하며 별도 패키지 설치는 없습니다. Aislo 서버·로그인·DB와 연결하지 않습니다. 다른 주소에서 수신하려면 실행 전에 `EST_TEST_HOST` 환경변수를 설정합니다.
파일 열기에서 ESTX 작업 파일과 EBKX 백업 파일을 읽을 수 있습니다. EBKX를 연 작업도 JSON으로 보관하며 원본 파일을 덮어쓰지 않습니다.
+7 -5
View File
@@ -225,7 +225,8 @@ function output(project) {
!key ||
num(row.CalcIndex) === 1 ||
num(row.CalcIndex) === 3 ||
Math.abs(gn * (m + l + e) - num(row.TC)) > 0.000001
Math.abs((gn / (["%", "%"].includes(row.Unite) ? 100 : 1)) * (m + l + e) - num(row.TC)) >
0.000001
) {
key = source(0, {
Code: "LITERAL" + ++serial,
@@ -237,7 +238,7 @@ function output(project) {
JC: row.JC,
SC: row.SC,
});
gn = 1;
gn = ["%", "%"].includes(row.Unite) ? 100 : 1;
m = num(row.GC);
l = num(row.NC);
e = num(row.JC) + num(row.SC);
@@ -638,9 +639,10 @@ function read(bytes, project) {
LinkIndex: source.kind,
CalcIndex: 0,
};
row.GC = Math.trunc(row.GN * row.GU);
row.NC = Math.trunc(row.GN * row.NU);
row.JC = Math.trunc(row.GN * row.JU);
const quantity = row.GN / (["%", "%"].includes(row.Unite) ? 100 : 1);
row.GC = Math.trunc(quantity * row.GU);
row.NC = Math.trunc(quantity * row.NU);
row.JC = Math.trunc(quantity * row.JU);
row.SC = 0;
row.TC = row.GC + row.NC + row.JC;
row.TU = row.GU + row.NU + row.JU;
+1 -1
View File
@@ -1,4 +1,4 @@
@echo off
cd /d "%~dp0"
node server.cjs
node watch-server.cjs
pause