2026-09-05
요약 (AI 작성)
hwpjs 가 Zig 로 다시 시작한 날입니다. Rust 코드를 legacy/ 에 보관하고 Zig 워크스페이스를 초기화한 뒤, CFB 컨테이너의 모듈러 Zig 리더를 세우고 검색·검증 계약을 통일하고 리더 경계를 반복 감사로 굳혔으며, hwp5 의 DocInfo 속성과 버전별 ID 매핑, 바이너리·폰트 리소스를 개수 검증과 함께 파싱했습니다. @ohah/pdf 는 문서를 잇달아 열면 앞 문서의 마스크 그림이 나오던 것, /CalRGB 를 안 옮기고 16비트 그림을 안 그리던 것, 무색 무늬(/PaintType 2)의 색을 무시하던 것, 타일 무늬 간격과 그림 키울 때 뭉개기(pdf.js 맞대기로 잡았다), 내보낸 PDF 에 모듈 이름이 새던 것(/Subtype /core.Form)을 고치고, 문서 다시 쓰기(apply)를 떼어 12,525줄을 10,859줄로 줄였습니다. zerolist 에는 ZeroList 통합과 Android 배치 최적화 검증 PR 이 열렸습니다.
maru 는 소스 컨트롤 감시자를 «실제로 심고»(RW2c) 적대적 검증 13회에서 결함 열을 잡았습니다. 편집기는 위/아래로 커서 추가(⌥⌘↑/⌥⌘↓, §3.2b)와 열/블록 선택(⌥드래그·⇧⌥드래그·⇧⌥⌘ 방향키, §3.2a)을 얻었고, 원격 파일 트리 설계를 열어 RF1 순수 층(목록 wire 와 (host, path) root 키)을 놓았습니다. claude 진행 상태줄을 화면에서 다시 읽게 했고(esc to interrupt 가 사라졌다), 종류를 모르는 running 에이전트를 claude 로 그리지 않습니다.
테스트 인프라를 크게 손봤습니다 — 시간을 태우던 픽스처 넷 189초→2.7초, imports.zig 판정자의 되풀이 파싱 100초→39초, release adapter 판정자 84개를 모드당 두 바이너리로 모아 CI 컴파일 45·129회→2·4회, 세션을 닫을 때 안 읽힌 master 출력을 버려 pty teardown 4,077ms→15ms.
커밋
ohah/hwpjs
- feat(hwp5): parse DocInfo properties and version-aware ID mappings
- feat(cfb): add strict validation and editable v3/v4 writer
- test(cfb): correct reproduction fixtures and document spec gaps
- feat(hwp5): parse binary and font resources with count validation
- feat(hwp5): parse DocInfo tabs numbering bullets and styles
- docs: remove unused agent setup templates
- fix(cfb): enforce shared search and validation contracts
- docs: replace agent persona files with Zig guidance
- fix(cfb): match legacy result shapes and header diagnostics
- fix(cfb): harden reader boundaries with repeatable audits
- fix(cfb): align writer budgets and parse failure state
- feat(hwp5): add bounded header and record parsing foundation
- feat(cfb): implement modular Zig reader
- chore: archive Rust and initialize Zig workspace
- test(cfb): close boundary coverage gaps and centralize storage rules
ohah/maru
- feat(session-host): retain durable preparation outputs
- test(session-host): require durable preparation handoff
- docs(session-host): define durable preparation handoff
- feat(file-tree): 원격 파일 트리 설계를 열고 RF1 순수 층을 놓는다 — 목록 wire 와 (host, path) root 키
- perf(boundary): imports.zig 판정자가 같은 소스를 되풀이해 파싱·토큰화·읽던 것을 기억한다
- feat(session-host): enforce live release phase order
- test(session-host): require live release phase order
- docs(session-host): define live release phase order
- feat(remote-watch): 헬퍼가 목록을 말한다 — list 서브커맨드(판 3)와 실물 왕복 게이트 (RF2a)
- build: test-macos-only 는 두 모드 루프 안의 판정자를 Debug 로만 돈다 — check-boundaries 와 같은 규칙
- build: release adapter 판정자 84개를 모드당 두 바이너리로 모은다 — CI 컴파일 45·129회 → 2·4회
- feat(session-host): own stage3 preparation commit
- test(session-host): require stage3 preparation product
- docs(session-host): define stage3 preparation ownership
- fix(pty): 세션을 닫을 때 안 읽힌 master 출력을 버려 바쁜 자식의 exit 가 막히지 않게 한다 — teardown 4,077ms → 15ms
- perf(test): 느린 판정자 셋의 시간을 줄인다 — 실패 주입 조기 종료·fail-stop 병렬 대기
- docs(editor): 대소문자 변환과 캡처 훅을 계획에 기록한다 — 「계약 안」 편집 보조 여섯이 닫혔다
- fix(session-host): retain durable evidence on close
- test(session-host): require retained evidence close
- docs(session-host): separate retained evidence close
- feat(session-host): 복원이 어느 단계에서 죽었는지 남긴다 — 이름만으론 후보가 여럿이었다
- feat(session-host): handoff 디코드가 어디서 깨졌는지 남긴다
- fix(mobile): 가로에서 키보드를 올리면 격자가 키바 밑에 깔렸다
- feat(mobile): 세로 잠금을 풀고 회전하면 격자를 다시 잡는다
- feat(session-host): hand off release aggregate atomically
- test(session-host): require atomic aggregate handoff
- docs(session-host): define atomic aggregate handoff
- style(agent):
zig fmt를 적용한다 — CI 의 fmt-check 가 잡았다 - fix(agent): 스피너 프레임에
·를 더한다 — 목록은 원리상 불완전하다 - fix(agent): 스피너 프레임을 실측 다섯으로 좁힌다 — 추정과
⏺를 뺀다 - fix(agent): claude 진행 상태줄을 화면에서 다시 읽는다 —
esc to interrupt가 사라졌다 - feat(session-host): fd 슬롯 예약이 왜 실패했는지 남긴다 — 단계 이름만으론 다섯 갈래였다
- fix(agent): codex 진행 줄에서
working요구를 뺀다 —Waiting을 놓쳤다 - docs(scm): §11.9 열린 질문 넷을 실측으로 닫는다
- feat(session-host): 창이 왜 안 돌아왔는지, poison 이 어디서 났는지 남긴다
- fix(status-bar): 종류를 모르는 running 에이전트를 claude 로 그리지 않는다
- feat(mobile): 키바 줄 수를 «폭이» 정한다 — 가로에서 한 줄, 본문 9줄→11줄
- fix(agent): C2 의 chrome 근거에 출력 조건을 건다 — 정반대를 요구하는 두 사고를 가른다
- fix(agent): C2 의 「무거운 조건」을 시간에서 근거의 질로 바꾼다
- feat(session-host): reopen durable preparation semantics
- test(session-host): require preparation semantic reopen
- docs(session-host): define preparation semantic reopen
- feat(session-host): adopt reauthenticated current drafts
- test(session-host): require current draft adoption
- docs(session-host): define current draft adoption
- fix(agent): fixture 와 판정자 진단에서 한글 리터럴을 뺀다 — i18n 원장이 잡았다
- test(agent): 실제 화면 fixture 로 규칙을 전수 잠근다 — 손으로 쓴 문자열은 실측과 어긋난다
- feat(session-host): verify same-run attestation bundles
- test(session-host): require local attestation bundle verification
- docs(session-host): define local attestation bundle verification
- feat(session-host): promote baseline evidence durably
- test(session-host): require durable evidence handoff
- docs(session-host): define durable evidence handoff
- feat(scm): 실은 감시자를 «실제로 심는다» (RW2c)
- refactor(mobile): 「키보드 겹침은 두 번 빼지 않는다」를 코어 한 곳으로
- fix(scm): 감시자의 rev-list 는 군더더기였다 — for-each-ref 가 이미 덮는다
- feat(session-host): wire candidate attestation bundles
- test(session-host): require candidate bundle command wiring
- docs(session-host): define candidate bundle command wiring
- feat(agent): 화면이 provider 를 못 읽으면 스스로 말한다 — §1.2 의 화면 쪽 대칭
- feat(session-host): adopt candidate attestation bundles
- test(session-host): require candidate bundle adoption
- docs(session-host): define candidate bundle adoption
- docs(agent): 오늘 바뀐 계약과 판정자를 문서에 맞춘다
- docs(agent): 레퍼런스 소스 실측을 남긴다 — 규칙의 데이터화·region 어휘·ASCII 프레임
- fix(scm): 원격 pane 의 cwd 를 한 규칙으로 모은다 — 전면 TUI 구간에 도크가 홈을 봤다 (RS6)
- test(app-session): 시간을 태우던 픽스처 넷을 고친다 — IG2-a·IG2 적대적·ES21·ES22
- ci: check-boundaries 를 자기 러너로 갈라 잰다
- test(agent): C2 의 제품 배선을 판정자로 잠근다 — 두 줄이 끊겨도 아무도 몰랐다
- feat(smoke): 편집기 판을 찍을 수 있게 한다 —
--hold-editor-ms(§2m.113) - feat(mobile): 시스템 다크/라이트를 따라간다 — 데스크톱 F2-9 를 잇는다
- test(agent): 종류 전환에서 리셋 호출을 잠근다 — AK1 이 남긴 마지막 공백
- docs(scm): 원격 트랙 진행 서술을 실제 그물에 맞춘다
- docs(mobile): 적대적 검증이 열을 찾았다 — 넷은 방금 내가 만든 것이다
- docs(mobile): 오늘 붙인 것 셋과 «없어진 일» 하나를 문서에 맞춘다
- feat(session-host): fd 슬롯을 «누가» 쥐고 있는지 남긴다 — 비었다던 자리가 점유였다
- fix(app-session): 원격 SCM 픽스처를 호스트 PTY 로 보낸다
- feat(session-host): reopen release aggregate safely
- test(session-host): require aggregate reopen binding
- docs(session-host): define aggregate reopen binding
- docs(agent): 스피너 프레임 근거를 900 회 관측으로 갱신한다 — 표본이 결론을 바꿨다
- feat(session-host): execute aggregate process phases
- test(session-host): require aggregate process boundary
- docs(session-host): define aggregate process boundary
- test(agent): 종류 전이 리셋을 판정자로 잠근다 — 열셋 중 하나만 잠겨 있었다
- feat(editor): 편집기가 글자를 한 색으로 그렸다 — 규칙을 중립으로 올려 두 호스트가 같은 것을 쓴다 (§2m.112)
- docs(scm): ②c 완료 표기와 감시자 시한 주석을 실측에 맞춘다
- fix(session-host): raise 3b source scan budget
- test(session-host): require durable 3b source scan
- docs(session-host): define 3b scanner budget
- feat(editor): 위/아래로 커서 추가 —
⌥⌘↑/⌥⌘↓(§3.2b) - test(image-gallery): 크게 보기의 「빈 띠」 단언을 출처 줄까지 포함해 다시 쓴다
- feat(image-gallery): 격자와 크게 보기에 이미지 출처를 표시한다
- feat(image-gallery): 같은 메시지에 붙은 여러 장에 순번을 매긴다
- feat(image-gallery): 라벨 접두와 자리 나누기를 순수 계산으로 둔다
- docs(image-gallery): 라벨이 «누가 넣었나»부터 말하도록 계약을 정한다
- feat(editor): 괄호 짝으로 점프 —
⇧⌘\(§3.9c) - feat(mobile): 세션 목록에 스크롤바 — 흐르게 됐으니 어디쯤인지 말한다
- fix(mobile): 스크롤이 드러낸 결함 넷을 고치고 판정자를 아홉으로
- fix(mobile): 세션 목록이 안 흘렀다 — 창에 안 들어가는 세션에 닿을 수가 없었다
- fix(scm): RW2c 의 설치 경로를 굳힌다 — 적대적 검증 13 회에서 결함 열
ohah/pdf
- fix: 문서를 잇달아 열면 앞 문서의 마스크 그림이 나왔다
- test: 쓰는 쪽 타입 추론을 React·Vue·Svelte 까지 못 박는다
- test: pdf.js 에게도 제 연장을 준다 — JPX·JBIG2·ICC wasm
- fix: /CalRGB 를 옮기지 않았고 16비트 그림을 안 그렸다
- docs: 폼 XObject 설명이 낡았다 — 그리지 않는다고 적혀 있었다
- refactor: pdf.zig 에서 네 덩이를 떼어 낸다 (14,549 → 12,525줄)
- refactor: 문서 다시 쓰기(apply)를 떼어 낸다 (12,525 → 10,859줄)
- fix: 쪽 크기를 쓰레기 값만 걸러 내고 문서대로 쓴다
- fix: 내보낼 이름을 소스에서 뽑는다 — 손목록과 어긋나 있었다 (SSOT)
- refactor: 표의 처음 크기를 선언 한 곳으로 (SSOT)
- fix: 목차를 담을 자리를 잡고 쓴다 — 메모리 앞자리를 밟고 있었다
- refactor: 남은 여덟 덩이를 떼어 낸다 (10,859 → 7,489줄)
- test: 아직 없는 기능을 미리 못 박는다 (빈틈 견본 6개)
- chore: 죽은 것 셋 치움
- refactor: 가장 깊던 두 조각을 함수로 — 깊이 11 → 9·8
- refactor: scanResources 를 자원 갈래 여섯으로 가름
- test: 규격의 빈 곳을 겨눈 견본 열둘과 그 생성기
- fix: 혼합 모드 이름을 앞머리만 보고 골라 ColorDodge·ColorBurn 이 죽었다
- fix: 무색 무늬(/PaintType 2)가 준 색을 무시했다
- fix: 새 견본으로 잡은 셋 — /Decode·2·4비트 그림·Separation
- fix: 그림자 /Extend 와 인라인 그림의 줄임 필터
- test: enc-aes256 견본을 우리 writer 로 다시 만든다
- refactor: 2~3개짜리 묶음 17개도 구조체로
- refactor: 남은 전역 17묶음도 구조체로 — 최상위 이름 371 → 207
- docs: 묶으면서 잃은 주석 두 덩이 되살림
- refactor: 앞머리가 같던 전역 15묶음을 구조체로
- refactor: 접근 함수 이름이 제각각이던 표 22벌도 Table(T) 로
- refactor: 늘어나는 표를 Table(T) 하나로 접다
- test: 만든 PDF 의 구조를 스스로 검사하는 상시 시험 추가
- fix: DeviceCMYK 색과 표본 함수 사이값 — pdf.js 맞대기로 잡은 둘
- test: pdf.js 와 그림을 맞대는 시험을 더한다
- perf: JPEG IDCT 를 정수로, DC 만 남은 칸은 건너뛴다
- fix: Type3 글꼴의 제 자원을 훑는다 — 글리프 안 그림·투명도
- fix: 타일 무늬 간격과 그림 키울 때 뭉개기 — pdf.js 맞대기로 잡은 둘
- fix: JBIG2 — 아무것도 안 가리키는 글자 사전이 앞 글자를 물려받았다
- fix: 글꼴 캐시 열쇠가 바이트의 1%만 보고 있었다
- fix: 내보낸 PDF 에 모듈 이름이 새어 나갔다 — /Subtype /core.Form
- test: 우리가 만든 PDF 를 pdf.js 로 열어 본다