CIF-V 적대감사 결함 5건 수리 (D1~D5)
개요
CIFV_SPEC.md v1.0(§2/§3/§5 교정 직후) SSOT를 기준으로, 한선씨 정본(CrownyOS/crownyc/libs/CIF벡터.한선)과 JS(crowny-image/server.js) 양 렌더러 사이 적대감사에서 나온 결함 5건을 전부 닫음. 최종 재컴파일+전체 테스트 재실행+서버 재기동+데모 E2E 프로브까지 완료.
결함별 조치
D1 [P2] 직선 알고리즘 발산 + JS 구멍
- 스펙 §5 "축주도 스팬, 버트 캡"으로 양쪽 통일.
- 한선씨:
half = thick/2(자연반올림, 짝수두께에서 반올림 방향 착오)를half = CIF벡터_몫(thick-1, 2)(floor)로 교정. - JS
civDrawLine을 거리-파라미터 perp-offset 방식에서 한선씨와 동일한 축주도 정수 스팬(x-driven/y-driven,civFillRectImpl재사용)으로 전면 재작성. - 검증: 데모 직선(50,450)→(460,430) 두께3 — 시작/중간/끝 3점 VM=JS 완전 일치(diff=0), 50~460 전 컬럼 연속성 검사 양쪽 gap=0.
D2 [P2] 글리프 y앵커 78px 발산 + 채움 5.6배
crownyc.c:1141 fb_fill_glyph_v4정독: 앵커(x,y)=글리프 박스 좌상단, 베이스라인by = oy + 0.80×size,sc = size/EM, 4×4 슈퍼샘플 AA(SS=4, 커버리지 0..16→알파).- JS
civDrawGlyph: 기존엔 (x,y)를 베이스라인으로 오인(0.8×size 오프셋 누락) + AA 없는 하드 스캔라인 채움 → 신규civFillPolygonsAA()(4×4 슈퍼샘플, nonzero winding, 알파블렌드)로 교체, 베이스라인 오프셋 추가. - CIFV_SPEC.md §4.4에 정확 수식(앵커·스케일·AA) 기록.
- 검증: VM PPM vs JS PNG bbox 최암픽셀 좌표 거리=0px, 근검정 픽셀수 비율 0.992(기준 0.5~2.0).
D3 [P3] CIF벡터_로드 읽기() 64KB 절단
CIF벡터_로드를버퍼파일읽기(874)전체 로드 + 개행(10) 스캔 +버퍼잘라(줄 단위, exclusive 끝오프셋)+버퍼문자열+즉시버퍼해제로 재작성(헬퍼CIF벡터_로드_처리줄분리).- 부수 발견:
CIF벡터_저장도CIF벡터_직렬화()가 통짜 VM 문자열(65535B 캡)을 만들어 대형 문서에서 저장 시점에 조용히 절단됨 —쓰기()+덧쓰기()로 헤더/명령을 줄 단위로 디스크에 쓰도록 재작성(둘 다 고쳐야 D3 검증이 실제로 의미있었음). - 검증: 합성 문서(사각형 1600개) 저장 → 파일 크기 73,686바이트(>70KB) → 로드 → 명령수 1600/1600 정확 일치, 필드(x=0, x=1599) 정확 디코딩.
D4 [P3] 코드포인트 13t→14t
- 스펙(§3/§4)은 이미 14t로 교정돼 있었음. 실제 코드 3곳 교정: 한선씨 인코더(
CIF벡터_명령직렬화op9), 한선씨 디코더(CIF벡터_명령디코딩op9), JSdecodeCIVCommandcase 9readInt(13)→readInt(14). - 데모.civ 재직렬화(9명령, 글리프 라인 53자→54자로 1트릿 증가 확인) + 데모_vm.ppm 재렌더.
server.한선(JS 동반본)에CIV_코드포인트폭=14상수 + U+10FFFF 왕복 자가검증 추가.
D5 [P3] RPN 실행 실증
high2rpn.sh로CIF벡터.한선전체 재변환 시도 → hanseonc_rpn 변수 영역 한도(1000개, 9000~9999) 초과로 컴파일 불가(D3의 상태 스레딩 버퍼 로드/저장 재작성이 필요 변수를 늘려, 기존엔 아슬아슬하게 안쪽이던 전체 라이브러리+가져오기 합산 변수수가 한도를 넘음). 이 변수 한도 자체는 5건 결함 범위 밖(사전 존재 아키텍처 제약) — 코드를 줄여 억지로 맞추는 대신 사실대로 기록.- 실행 실증은 과제 지시대로 셀프컨테인드 스모크로 우회:
tests/CIF벡터_스모크.한선(가져오기 없음, top-level 변수 8개) 신설 →hanseonc_high로 로직 검증(4/4 PASS) →high2rpn.sh로 RPN 변환 → hanseonc_rpn 단독 컴파일 성공 →crownyc run실행 → 4/4 PASS(트릿인코딩↔디코딩 양수/음수/영 3건 + 색 인코딩↔디코딩 1건). libs/CIF벡터.rpn.한선은 14t/D1/D3 반영해 재생성(소스 동기화 참고용으로 갱신) — 파일 헤더에 "단독 컴파일 안 됨" 알려진 제약 명시.
마무리 (전체 재검증)
- 한선씨 재컴파일:
libs/CIF벡터.한선컴파일 클린(경고0). - 전체 테스트 재실행:
tests/CIF벡터_테스트.한선52/52 PASS(D3/D4 반영 후에도 무회귀). server.한선동반 갱신 + 컴파일/실행 검증(정수/색9 왕복 + 신규 직선절반값/코드포인트14t 자가검증 전부 OK).- 서버 재기동: 기존 PID(44310) kill →
nohup node server.js동일 방식 재기동(신규 PID 48810,/tmp/crowny-image-test.pid갱신) →/health200 확인. - v3 CIF 회귀:
/encode(4×4 픽셀) →/png/:id?w=8&h=8200, 유효 PNG. - 데모 E2E:
데모.civ(14t 재직렬화본)POST /upload(Content-Type: application/x-civ) →GET /png/:id?w=512&h=512200 → Python/PIL로 9개 프로브 전부 PASS(기존 7 배경/그라디언트/원/사각형/다각형/경로/선형그라 + 직선 3점 + 글리프 bbox 최암픽셀).
관련 파일
/Users/ef/crowny-image/CIFV_SPEC.md— §4.4 글리프 정확 수식 추가/Users/ef/CrownyOS/crownyc/libs/CIF벡터.한선— D1(직선 half floor)/D3(버퍼기반 로드+저장)/D4(14t) 수정/Users/ef/CrownyOS/crownyc/libs/CIF벡터.rpn.한선— 14t/D1/D3 반영 재생성(단독 컴파일 불가 — 알려진 제약 헤더 기록)/Users/ef/CrownyOS/crownyc/tests/CIF벡터_테스트.한선— 기존 52 테스트(무회귀 확인)/Users/ef/CrownyOS/crownyc/tests/CIF벡터_스모크.한선/.rpn.한선— D5 신규 셀프컨테인드 RPN 스모크(4/4 PASS)/Users/ef/crowny-image/server.js— D1(civDrawLine 재작성)/D2(civFillPolygonsAA 신설+civDrawGlyph 앵커수정)/D4(readInt 14) 수정/Users/ef/crowny-image/server.한선— D1/D4 자가검증 추가/Users/ef/crowny-image/samples/데모.civ,데모_vm.ppm— 14t 재직렬화+재렌더
잔여 이슈
- hanseonc_rpn 1000변수 영역 한도:
CIF벡터.한선(+가져오기 "문자열.한선") 전체를 통짜 RPN 변환하면 컴파일러 아키텍처 상수(9000~9999 영역, 1000슬롯)를 넘어 단독 컴파일이 안 됨. D3 수리가 필요로 한 변수 증가가 기존 여유분을 다 써버림. 컴파일러 자체 변수테이블 확장은 이번 5건 결함 범위 밖 — 후속 세션에서 hanseonc_rpn.c 변수테이블 크기 상수를 늘리거나, CIF벡터.한선을 여러 작은 RPN 모듈로 쪼개는 리팩터가 필요하면 별도 작업으로 진행. - 방사그라디언트(op2) VM 216 vs 스펙 기대212 diff=4(허용치 10 이내, 기존 감쇠식 반올림 오차 — 결함 아님, 참고로만 기록).