2026-09-15
날짜는 UTC 기준으로 나눴습니다(9월 22일부터는 한국 시간 기준). 커밋은 커미터 시각(committer date), PR은 생성·병합 시각으로 분류했습니다. 목록은 2026-10-06 KST에 GitHub에서 다시 조회해 보강했습니다. 공개 저장소의 기본 브랜치 활동만 포함합니다.
요약 (AI 작성)
maru의 성능을 진단으로 판 날입니다. 큰 출력에서 tick이 크게 떨어지던 원인을 불공정 mutex 기아로 진단하고 리더가 청크 경계마다 메인에게 코어 락 차례를 넘기게 했으며(#3746), 빈 출력 신호는 코어 락 없이 지나가게 해 전체 잠금의 60%를 없앴습니다(§12.9, #3759). kitty 이미지 base64·zlib 해제와 f=100 PNG 디코드도 리더가 락 밖에서 하게 했습니다(#3754, #3774). CoreText는 grid run 캐시로 CTLine 생성을 건너뛰어 3 pane 스크롤이 19.5Hz에서 56.3Hz로 올랐고(#3769), CTLine 비용의 정체(합자 6배, 폴백 탐색 run당 약 110µs)는 진단만 하고 착수는 보류했습니다(§10.9). session-host는 데몬 할당자의 스택 포획을 꺼 host CPU를 50%에서 14%로 내리고(#3751), 할당자 자신이던 host 메모리 증가와 재접속 창 크래시를 고쳤으며(#3745), daemon이 뜰 때 죽은 host의 1.0GB rollback 사본과 업그레이드 이미지를 거두게 했습니다(#3772).
병합 편집기는 세 판의 대응표를 세워 Result를 따라 굴리고(S3b-M, #3744), 고르기 줄을 판으로 옮기며(S3b-3c, #3748), 세 판에 caret을 세웠습니다(S3b-3b, #3750). 헤더 밴드의 ↓·↑와 F7/⇧F7로 파일 안 다음·이전 충돌 구간을 오가게 했고(S5, #3777), selection이 없으면 IME 조합도 받지 않게 해 조합 글자가 Result 첫 줄에 뜨던 자리를 막았습니다(#3761). 소스 컨트롤은 마커가 없어진 충돌 행에 「+」를 되돌리고(S4, #3755), 「모두 스테이지」가 마커가 남은 충돌 파일을 비켜 가게 했습니다(S4b, #3758). 에이전트 아카이브는 이어하기가 모델도 되살리게 했습니다(#3747).
터미널은 tmux 안 터미널 브라우저가 화면을 박스 문자로 덮던 것을 고치고(#3752), 같은 id 재전송 동안 옛 이미지를 완료까지 보여 주며(#3765), host가 보낸 이미지가 어느 칸에서 사라지는지 세는 진단을 붙였습니다(#3756). 전날 열린 아카이브 스모크 CI #3743이 병합됐고, 테스트는 벽시계 단언을 전수 조사해 시간 대신 차례·모양으로 바꿨습니다(#3753, #3762).
hwpjs는 EMF를 넓혔습니다(41커밋). 클리핑과 RegionData·path 그리기, extended flood fill과 gradient fill, bit·stretch·masked·parallelogram block transfer와 DIB·alpha blend·transparent 전송, layout mode와 linked font, 색 관리·색 보정 상태, comment envelope를 파싱하고, EMF+ 레코드 스트림·comment·object·image effect를 검증하며 SETICMMODE·SETLAYOUT·SETLINKEDUFIS 확장을 받아들였습니다. @ohah/pdf는 겉모습 없는 글상자 주석(/FreeText)과 겉모습 없는 주석을 규격의 기본 모양으로 그리고, 라디오 묶음이 하나만 켜지게 했으며, 겹치던 파싱 다섯 벌을 한 벌로 줄였습니다. ohah.github.io에는 8월 17일 누락분 보강과 문서 표현 정정이 들어갔습니다.
공개 커밋 126개, 해당일 생성 또는 병합된 PR 35개를 정리했습니다. PR 생성 34개·병합 35개는 같은 PR이 양쪽에 포함될 수 있습니다.
커밋
ohah/hwpjs
- feat(emf): assemble emf plus object payloads
- feat(emf): validate emf plus image effects
- feat(emf): validate emf plus object records
- feat(emf): validate emf plus comments
- feat(emf): validate emf plus record streams
- feat(emf): parse public comments
- feat(emf): parse comment envelopes
- feat(emf): parse color adjustment state
- feat(emf): parse palette color correction
- fix(emf): accept color match extensions
- fix(emf): accept SETLINKEDUFIS extensions
- fix(emf): accept SETLAYOUT extensions
- fix(emf): accept SETICMMODE extensions
- feat(emf): parse image color management mode
- feat(emf): parse pixel format records
- feat(emf): parse forced font mapping
- feat(emf): parse target color matching
- fix(emf): preserve justification extensions
- feat(emf): parse linked font identifiers
- feat(emf): parse layout mode records
- feat(emf): parse transparent bitmap transfers
- feat(emf): parse alpha blend transfers
- feat(emf): parse stretched DIB transfers
- feat(emf): parse scanline bitmap transfers
- feat(emf): parse parallelogram block transfers
- feat(emf): parse masked block transfers
- feat(emf): parse stretch block transfers
- feat(emf): parse bit block transfers
- feat(emf): parse gradient fill records
- feat(emf): parse extended flood fill
- feat(emf): parse path drawing records
- feat(emf): parse RegionData drawing records
- feat(emf): parse clipping selection records
- feat(emf): parse fixed clipping records
- fix(emf): unify header payload parsing
- fix(emf): unify EOF palette parsing
- fix(emf): accept trailing extended pen data
- fix(emf): isolate trailing bitmap brush data
- test(emf): lock font record extent semantics
- fix(emf): isolate trailing poly record data
- fix(emf): accept trailing color space data
ohah/maru
- feat(editor): S5 — 헤더 밴드의 ↓·↑ 와 F7/⇧F7 로 파일 안 다음/이전 충돌 구간을 오간다
- docs(editor): S5 — 파일 안 다음/이전 충돌 구간을 헤더 밴드의 ↓·↑ 와 F7/⇧F7 로 (VS Code 실측: 버튼만 있고 키는 없다)
- docs(present): §10.9 CTLine 비용의 정체 — 합자 6배·폴백 캐스케이드 run당 ~110µs (진단만, 착수 보류)
- perf(terminal): f=100 PNG 도 락 밖에서 디코드한다 — IHDR 만 엿보고 자리를 잡고, payload 버퍼는 복사 없이 옮겨 되돌린다
- fix(session-host): tick 의 partial_timeout 네 자리에 이름을 붙인다 — 126 번이 「무엇인지 모름」이었다
- test(session-host): add CR6d candidate authority reducer
- docs(session-host): define CR6d candidate window evidence
- fix(agent-turn): turnIndexPath 가
~/.cache/maru를 부모까지 만든다 - fix(session-host): daemon 이 뜰 때 죽은 host 의 rollback 사본·업그레이드 이미지와 7 일 지난 로그를 거둔다
- fix(build): wire PNG codec into focused app roots
- docs(session-host): retire stale CR2e status and size copies
- docs(present): §10.8 run 캐시 실측(예측 실험)과 구현 방법의 적대적 검증 5회를 기록한다
- perf(coretext): grid run 캐시 — run 내용 키로 CTLine 생성을 건너뛴다 (§10.8)
- docs(present): §10.8 grid run 캐시 설계(doc-first) +
MARU_FT_SPLIT진단 훅으로 잰 멀티 pane 실측 - feat(diag): grid shaping 을 단계별로 재고 run 반복률을 시뮬레이션한다 — §10.7 run 캐시 진단
- docs(plans): 3-way 병합 행을 계약 §5 의 현재로 맞춘다 — S3·S4 가 전부 섰고 미결은 §7 ⑦ 뿐
- test(session-host): account for recovery event fixture
- fix(session-host): name deferred invalidation close site
- test(session-host): close partial pressure product gate
- fix(session-host): isolate partial screen pressure
- docs(session-host): define partial batch pressure isolation
- fix(editor): 판 블록을 여백 안쪽에 세우고 배경은 가장자리까지 덮는다 — 4px 넘침·띠 (S3b-2 정정)
- docs(editor): 판 블록은 여백 안쪽에 선다 — 병합 갈래가 바깥 사각을 넘겨 4px 넘치던 자리
- fix(session-host): 픽셀을 안 실으면 placement 도 안 싣는다 — 계측이 「떨어짐」과 「미투영」을 못 가렸다
- fix(terminal): 같은 id 재전송 동안 옛 이미지를 완료까지 보여 준다 — #3754 가 만든 프레임마다 깜빡임
- test(agent-turn): 실제 AppSession 판정자가 빈 HOME 에서 죽고 세션을 새지 않게 한다
- fix(agent-turn): 턴 스냅샷 임시 index 를 창이 닫힐 때 지우고, 오래된 형제는 워커가 쓸어 낸다
- docs(gallery): 「남은 결정」이 이미 내려진 결정을 붙들고 있었다
- fix(editor): 조합 거절을 확정과 같은 술어로 — 조합 중에도, 범위 선택은 시작에서 (적대적 2~4회차)
- fix(editor): selection 이 없으면 조합(IME)도 받지 않는다 — 판 초점에서 조합 글자가 Result 첫 줄에 뜨던 자리
- docs(editor): selection 이 없으면 조합도 없다 — 판 초점에서 조합 글자가 Result 첫 줄에 뜨던 자리
- docs(session-host): §12.2 이미지 대조 계측 — 어디를 세고 어떻게 남기며 무엇을 못 보나
- feat(diag): 이미지 흐름 요약줄을 5 초마다 항상 남긴다 — 침묵이 «계측 부재» 로 읽히지 않게
- test(session-host): std_environ_view 판정자가 자기 모듈의 규칙을 어기던 자리를 고친다
- fix(diag): blob 없는 placement 의 계수기를 제품이 실제로 타는 자리로 옮긴다
- test: 기계에 달린 판정 둘을 더 걷는다 — 신호를 키우고, 훑는 폭을 세어서 정한다
- test(session-host): poll owner 판정자를 짧은 소켓 루트로 옮긴다 — 워크트리에서 19개가 죽었다
- perf(runtime): 빈 출력 신호는 코어 락 없이 지나간다 — 폭포에서 tick당 16.6회, 전체 잠금의 60% 였던 헛 잠금
- feat(diag): 메인의 코어 락을 호출 지점별로 센다 — §12.9 P4-3 인벤토리 실측과 방법의 적대적 검증
- feat(scm): 「모두 스테이지」가 마커가 남은 충돌 파일을 비켜 간다 (S4b)
- docs(scm): 「모두 스테이지」가 마커가 남은 충돌 파일을 비켜 간다 (S4b) — add -A 의 pathspec 제외는 unmerged 를 못 지킨다(실측)
- fix(host): 패닉 사유를 stderr 잠금보다 먼저 쓴다 — 안 그러면 사유가 통째로 사라진다
- fix(session-host): 화면이 가리키는 이미지만 투영하고, 예산을 넘으면 이미지를 포기한다
- fix(renderer): placeholder 셀을 텍스트로 넘기지 않는다 — 이미지가 없어도 빈 칸이다
- fix(terminal): placeholder 해독을 한 곳이 소유하고, 가시성 판정이 어느 이미지인지 본다
- perf(terminal): kitty 이미지 base64·zlib 해제를 리더가 락 밖에서 한다 (§13.8)
- docs(io-render): §13.8 — kitty 이미지 디코드를 락 밖으로 옮기는 설계와 실측 (doc-first, 사용자 결정 (a))
- feat(diag): kitty 이미지 전송이 락 아래에서 쓴 시간을 단계별로 잰다 — §13.7 «긴 보유» 진단
- test(session-host): std_environ_view 판정자의 순서 의존을 없앤다
- feat(diag): host 가 보낸 이미지가 앱의 어느 칸에서 사라지는지 센다
- feat(scm): 마커가 없어진 충돌 행에 «+» 가 돌아온다 — add 가 곧 완료다 (S4)
- docs(scm): §7 ⑤ 를 답한다 — 「다음 충돌 파일」이 아니라 «완료» 가 없었다 (S4)
- test: 판정자 셋이 «기계를 재고» 있었다 — 시간 대신 차례·모양으로
- perf(session-host): 데몬 할당자의 스택 포획을 끈다 — host CPU 50%→14%, 누수 탐지는 그대로
- feat(editor): 세 판에 caret 이 선다 — «초점» 은 판 caret + Result selection 없음 (S3b-3b)
- docs(editor): S3b-3b 를 공격한 결과 — «초점» 이 새 축이고, 나가면 Result 를 굴린다
- fix(agent-archive): 세션 id 도 같은 argv 토큰 규칙을 지난다 — 인용은 셸로부터만 지켜 준다
- feat(editor): 고르기 줄을 «판» 으로 옮긴다 — VS Code 의 배치를 마커 모델 위에서 (S3b-3c)
- docs(editor): S3b-3c 를 «마커 모델 위의 VS Code 배치» 로 적는다 — 그리고 상태 모델을 §7 에 미결로
- test(agent-archive): 합성 모델 줄을 fixture 에 넣어 «제품 경로»가 필터를 판정하게 한다
- test(agent-archive): 모델 상한이 표시용 절단선 안이라야 한다는 판정자
- feat(agent-archive): 이어하기가 «모델»도 되살린다 — Opus 세션이 기본 모델로 떨어지던 것
- fix(session-host): unsetenv 뒤 첫 std.log 가 호스트를 죽이던 자리 — std 의 환경 조각을 갱신한다
- refactor(session-host): attached 판정 중복을 isLive 한 곳으로 모은다
- fix(session-host): 멈춘 pane 추적이 여럿 걸리면 경고를 영영 안 띄웠다
- feat(session-host): 조용히 멈춘 pane 을 로그로 찾을 수 있게 한다
- fix(session-host): 재접속 창에서 유지보수 틱이 은퇴한 attachment 를 펌프해 앱이 죽었다
- fix(session-host): host 메모리가 단조 증가하던 자리는 할당자 자신이었다
- perf(io): 리더가 청크 경계마다 메인에게 코어 락 차례를 넘긴다 (CoreHandoff)
- feat(diag): 코어 락 경합을 두 방향으로 잰다 — 메인
lockCore대기와 리더core.write보유를 SLOW 줄에 싣는다 - docs(io-render): 코어 락 «짧은 보유 ≠ 짧은 대기» — 불공정 mutex 기아 진단을 §13 으로 세우고 §3·§5·§12.1 을 정정한다
- fix(macos): 합성 휠이 «그 기계의 주 화면 높이»만큼 빗나가 떨어졌다
- fix(macos): 스모크 판정이 «그 기계의 화면 크기»에 달려 있었다
- ci: 아카이브 스모크를 CI 가 돌린다 — 손으로 안 돌리면 안 도는 게이트였다
- feat(editor): 세 판의 «대응표» 를 세우고 Result 를 따라 굴린다 (S3b-M)
- docs(editor): 세 판의 «대응표» 를 S3b-3b 앞에 끼운다 — 견적을 고쳐 적는다
ohah/ohah.github.io
- fix(docs): hwpjs 공백 기간(3/21~9/4)·maru 기간 표현·SSH 절 제목 정정
- docs: 8/17 누락분 보강 — 당일 오후 커밋 133건·PR 47건
- fix(docs): pdf 배경 — 출처를 "농구 기록 서비스"로 잘못 추측한 것 정정, 비공개 저장소 이름 가림
ohah/pdf
- refactor: 겹치던 파싱 다섯 벌을 한 벌로 (−4,708 바이트)
- feat: 겉모습 없는 글상자 주석(/FreeText)을 그린다
- feat: 세로쓰기 자리(/W2·/DW2), 입력 칸 틀(/MK·/BS), 목록 첫 항목(/TI)
- feat: /Interpolate 와 /Matte
- feat: 겉모습 없는 주석을 규격의 기본 모양으로 그린다
- feat: 라디오 묶음은 하나만 켜진다
PR (해당일 생성/머지)
상태는 조회 시점 기준입니다. merged는 아래 대상 브랜치에 병합됐다는 뜻이며, 기능 브랜치 병합과 main 반영을 구분합니다. 같은 PR이 생성일과 병합일 양쪽 기록에 나타날 수 있습니다.