글

라벨이 개발노트인 게시물 표시

Blogger 피드 max-results=150인데 35개만 왔다: 끝까지 받는 페이지네이션

이미지
답부터 말하면 Blogger 공개 피드의 max-results 는 전체 글 수를 보장하지 않았다. 2026년 9월 28일 측정에서 이 블로그는 totalResults=86 을 알렸지만, max-results=150 응답에는 JSON과 Atom 모두 35개 entry만 들어 있었다. 해결은 totalResults 와 실제 entry 수를 따로 읽고 start-index 를 넘기는 것이다. 10개씩 순회한 최종 측정에서는 86개 고유 글을 모두 회수했다. 150을 요청했는데 왜 35개만 왔나? 처음에는 150이 전체 86개보다 크니 한 번에 끝날 것으로 봤다. 그런데 JSON 응답의 openSearch$totalResults 는 86, entry 배열 길이는 35였다. Atom도 같은 결과였다. max-results 값을 바꿔 보니 경계가 더 분명했다. 35까지는 요청한 수만큼 왔지만, 36부터는 35개에 멈췄다. cd4761 공개 피드 측정 — 2026-09-28 15:51 KST 형식 max-results totalResults 실제 entry JSON 1 86 1 JSON 10 86 10 JSON 25 86 25 JSON 35 86 35 JSON 36 86 35 JSON 50 86 35 JSON 100 86 35 JSON 150 86 35 Atom 150 86 35 문제는 itemsPerPage 도 요청값 150으로 표시된다는 점이다. 이 값만 믿으면 실제 배열이 짧다는 사실을 놓친다. 결국 검증 기준은 요청값이 아니라 len(entry) 다. 주문서에 150개라고 적혀 있어도 상자에 35개만 들었다면, 세어 볼 것은 주문서가 아니라 상자다. 다만 피드는 이유를 적은 송장을 함께 주지 않는다. 35개가 Blogger의 공통 상한인가? 아니다. 같은 날 공개 Blogspot 두 곳의 JSON 피드에 max-results=150 을 보냈다. Blogger 공식 블로그는 전체 540개 중 150개, Google Blog는 전체 3,37...

네이버 SmartEditor 붙여넣기: 성공 이벤트보다 본문 일치가 먼저다

이미지
답부터 말하면 붙여넣기 이벤트가 받아들여졌는지가 아니라, 편집기 본문이 넣으려던 전체 글과 같아졌는지를 완료 조건으로 삼아야 한다. 이벤트를 보내기 전에 변경 감시를 시작하고, 제한 시간 안에 정규화한 누적 본문이 정확히 일치할 때만 다음 단계로 넘어가는 방식이다. 2026년 9월 27일 한 번의 SmartEditor 자동화 기록에서 첫 구간은 48ms, 두 번째 구간은 239ms 뒤 반영됐다. 이후 다시 연 예약 글에서는 원고·주입 대상·편집기 본문이 각각 2800자로 일치했다. 그 예약은 이 실행이 아니라 동시에 돌던 다른 작업이 저장한 것이다. 48ms와 239ms는 속도 기준이나 성공률이 아니라 한 실행의 관찰값이다. 왜 paste 이벤트 성공만으로는 부족했나? 조사 중 합성 paste 이벤트는 defaultPrevented:true 를 반환했다. 그런데 직후 본문은 여전히 한 문단이었고, 조금 뒤에는 시험용 두 문단이 들어와 있었다. 문제는 이벤트 수락과 화면 반영이 같은 순간이 아니라는 점이다. dispatchEvent() 반환값, iframe 포커스, 즉시 읽은 문단 수는 모두 완료 조건이 아니었다. 선택 영역이 iframe 루트에 잡힌 관찰도 과거 60초 지연의 원인으로 확정할 수 없었다. 그렇다면 무엇을 기다려야 할까. 편집기가 실제로 만들어 낸 최종 상태를 기다려야 한다. 고정 sleep 대신 무엇을 기다렸나? 성공한 경로는 MutationObserver 를 붙여넣기 전에 등록했다. 그 다음 clipboard 이벤트를 보낸 뒤, 공백과 제로폭 문자를 정규화한 전체 본문을 매 변경마다 비교했다. 아래는 실제 코드를 줄인 형태다. const done = new Promise((resolve, reject) => { const timer = setTimeout(() => { observer.disconnect(); reject(new Error("paste timeout")); ...

claude -p 체이닝 6단계: Phase 2가 죽는 구조적 이유와 V3.5 우회 패턴

이미지
📚 AI 직원 회사 빌드기 — 4부작 시리즈 ① Mac Studio 128GB로 AI 직원 회사 만든 이유 ② 외부 부작용 통제 — Discord 승인 + launchd ③ claude -p 6-step 체이닝 — V3.5 + Phase 2 트랩 (현재 글) ④ 30시간 회고 — 토큰·막힌 5번·다음 6주 KPI (다음 주 발행 예정) 36분짜리 자동화가 Phase 2에서 멈춘다 claude -p 로 블로그 파이프라인을 체이닝하면 특정 단계에서 subprocess가 멈추고 stdout이 비어 돌아온다. returncode는 0이다. 에러 메시지도 없다. 타임아웃까지 그냥 블로킹된다. 이게 Phase 2 트랩이다. blog-draft 스킬이 프레임·제목 후보를 제안하고 “진행 시 Phase 3 시작”이라는 텍스트를 출력한 뒤, 사용자 승인을 기다린다. subprocess.run() 안에서 승인을 기다리면 타임아웃까지 블로킹되고, 결국 md 파일이 생성되지 않은 채 다음 단계로 못 넘어간다. 이 글은 V3 5-step 파이프라인이 V3.5 6-step으로 바뀐 설계 기록이다. 트랩이 왜 발생하는지 구조적으로 분석하고, 실제 코드 변경 3가지로 어떻게 우회했는지 정리한다. 이 신호가 보이면 Phase 2 트랩이다 다음 세 가지가 동시에 나오면 코드 버그가 아니라 트랩이다: Step 2( blog-draft )가 항상 딱 720초 에서 TimeoutExpired로 죽는다. 랜덤하게 실패하는 게 아니라 매번 정확히 timeout에서 죽는다. stdout tail을 보면 “프레임 + 제목 제안” 텍스트가 마지막이고, 그 뒤로 아무것도 없다. work_dir 에 md 파일이 없어서 _latest_md_in() 이 None 을 반환한다. 세 가지가 맞아떨어지는 이유는 스킬 설계 vs 비대화형 실행 환경의 불일치에 있다. 스킬은 대화형 세션을 전제로 만들어져 있고, claude -p subprocess는 st...