← 목록
기타 2026-07-12 7KB 읽기 7분

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), JS decodeCIVCommand case 9 readInt(13)→readInt(14).
  • 데모.civ 재직렬화(9명령, 글리프 라인 53자→54자로 1트릿 증가 확인) + 데모_vm.ppm 재렌더.
  • server.한선(JS 동반본)에 CIV_코드포인트폭=14 상수 + U+10FFFF 왕복 자가검증 추가.

D5 [P3] RPN 실행 실증

  • high2rpn.shCIF벡터.한선 전체 재변환 시도 → 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 갱신) → /health 200 확인.
  • v3 CIF 회귀: /encode(4×4 픽셀) → /png/:id?w=8&h=8 200, 유효 PNG.
  • 데모 E2E: 데모.civ(14t 재직렬화본) POST /upload(Content-Type: application/x-civ) → GET /png/:id?w=512&h=512 200 → 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 이내, 기존 감쇠식 반올림 오차 — 결함 아님, 참고로만 기록).