aside 브라우저의 page 객체에 setViewportSize가 없다는 같은 사실이 8월 20일부터 10월 2일 사이에 서로 다른 날에 여섯 번 기록됐다.
다섯 번은 aside가 자기 메모리에 적었고 한 번은 Claude Code가 실측으로 다시 확인해 지침에 적었다.
그사이 9월 2일부터는 공유 기억 뱅크에도 이 함정이 "37분 무출력 정체"라는 기록으로 남아 있었다.
문제
Playwright에는 창 크기를 바꾸는 setViewportSize가 있다.
aside repl의 page는 Playwright 기능의 일부만 감싼 래퍼여서 이 함수가 없고 창 크기도 고정돼 있다.
모바일 폭으로 화면을 보거나 큰 이미지를 한 장에 담으려 할 때마다 이 벽에 부딪힌다.
함정 자체는 사소하다.
문제는 적어 둔 기록이 같은 함정에 다시 부딪히는 일을 한 번도 막지 못했다는 점이다.
제목의 "여섯 번"은 기록이 생긴 서로 다른 날을 센 값이다.
여섯 날의 기록
| 날짜 | 적은 쪽 | 하던 일 | 기록 형태 |
|---|---|---|---|
| 8월 20일 | aside 에피소드 | 로컬 이미지 판독 | 동작 경로 항목 안의 한 줄(TypeError) |
| 9월 2일 | aside 에피소드 | 블로그 화면 점검 | 없는 Playwright 기능 목록의 한 항목 |
| 9월 5일 | aside 에피소드 | 긴 목록 페이지 스크린샷 | 항목 제목 자체, 다른 함수 항목의 참조 |
| 9월 10일 | aside 에피소드 | 이미지 판독 | 같은 날 두 항목 |
| 9월 14일 | Claude Code | aside가 Playwright를 대신하는지 실측 | 지침 예외 줄과 aside 플레이북 항목 |
| 10월 2일 | aside 에피소드 | 이미지 OCR | 같은 날 두 항목(뷰포트 고정 문장, 다른 함수 항목의 괄호) |
9월 5일 항목의 제목은 "Aside REPL의 page 객체에는 setViewportSize가 없다"였다.
8월 20일에 같은 런타임이 적은 것과 같은 내용이다.
9월 10일에는 오후에 쓴 항목이 실패한 우회 방법 목록에 이 함수를 넣었고 밤에 쓴 항목이 이 함수를 다시 제목에 올렸다.
세는 단위를 바꾸면 숫자는 오히려 커진다.
aside 에피소드 메모리에서 이 함수가 없다고 적은 항목을 세면 9월 5일, 9월 10일, 10월 2일에 각각 두 항목씩 있어서 aside 혼자서만 8항목이 된다.
9월 5일의 두 번째 항목은 다른 함수가 없다고 적은 항목 안에서 첫 번째 항목을 가리킨 것이다.
여기에 공유 뱅크에 있는 9월 2일 기록과 9월 14일의 기록 묶음을 더하면 모든 표면을 합쳐 10회가 된다.
9월 2일과 10월 2일의 aside 항목은 새로 부딪혀서 적은 것인지 이미 아는 것을 적은 것인지 기록만으로는 구별되지 않는다.
새로 부딪힌 것이 분명한 기록만 남겨도 8월 20일, 9월 5일, 9월 10일 밤의 세 번이다.
같은 런타임 안에서도 먼저 읽지 않았다
aside 쪽 기록이 다른 런타임에 전달되지 않는 것은 예상할 수 있는 일이다.
그런데 aside 자신도 자기가 적은 기록을 먼저 읽지 않았다.
8월 20일은 "(TypeError)", 9월 5일은 "부르면 ... 죽는다", 9월 10일은 "실패한 우회들"이라고 적었다.
세 항목 모두 함수를 부르고 실패한 다음에 쓴 문장이다.
지금 aside의 개념 노트 두 개에는 이 함정을 적은 문단이 모두 네 개 있다.
두 노트 모두 이 함정이 담긴 이력 줄 가운데 가장 이른 줄의 출처를 8월 20일 에피소드로 달아 두었다.
공유 뱅크에 있던 한 문장
9월 2일, aside에 블로그 프론트 QA를 맡겼던 세션이 Hindsight에 완료 기록을 남겼다.
버그 네 건을 고쳐 배포했다는 긴 기록의 끝에 다음 문장이 있다.
"aside exec 은 setViewportSize 미지원으로 모바일 항목에서 37분 무출력 정체 -> kill"
이 문장은 특정 런타임에 갇혀 있지 않았다.
모든 런타임이 recall할 수 있는 뱅크에 있었다.
그런데도 9월 5일과 9월 10일에 aside는 같은 함수를 다시 불렀다.
공유 뱅크에 있다는 사실만으로는 같은 함정에 다시 부딪히는 일이 막히지 않았다.
9월 14일에는 내가 "aside가 Playwright 전부를 대신하나"를 물었고, Claude Code가 실측으로 답했다.
커밋 메시지에는 "실측(2026-09-14, aside repl): page.setViewportSize → TypeError: not a function"이 남았다.
그 결과로 공용 지침의 웹 접근 절에는 "로컬 렌더 검증은 Playwright"라는 예외 줄이 들어갔고 aside 플레이북에는 뷰포트 변경 불가 항목이 들어갔다.
aside의 지침 파일은 공용 지침 원본을 가리키는 심링크다.
따라서 10월 2일에 aside가 읽던 지침에는 9월 14일의 예외 줄이 이미 들어 있었다.
그날 aside는 이미지 OCR 항목에서 뷰포트가 고정돼 있고 이 함수가 없다고 적었다.
10분 뒤에는 setContent가 없다는 항목에서도, 괄호 안에 "so is"로 시작하는 덧붙임으로 이 함수를 또 적었다.
조항 한 줄
9월 30일, 공용 지침의 retain 규칙에 한 줄이 추가됐다.
"런타임 자체 메모리(...)에 적은 것은 retain을 대체하지 않는다 - 다른 런타임은 그걸 recall하지 못한다."
괄호 안에 예시로 든 것이 aside의 에피소드 메모리다.
이 조항의 계기는 뷰포트 함정이 아니었다.
같은 날 aside가 개인 리서치를 끝낸 뒤 결과는 자기 에피소드 메모리에만 적고 뱅크에는 gotcha 3건만 올렸다.
다른 런타임에서 그 결과를 recall할 수 없었던 것이 조항의 계기다.
같은 함정이 반복된 일과 이 조항은 같은 문제를 가리키지만 조항을 쓸 때 염두에 둔 것은 그 리서치 건이었다.
커밋에는 Not-tested 트레일러가 붙었다.
"aside 새 세션에서 실제로 결과 retain까지 하는지는 미관측"
같은 날 다른 aside 작업에서 aside가 스스로 완료 retain을 남긴 것이 처음 관측된 효과이고 기록된 효과는 그 1건뿐이다.
금지가 위임 경계를 넘지 못한 사례는 기억하지 말라는 지시가 위임을 넘지 못한 글에서 다뤘다.
그 글이 금지가 넘어가지 않은 경우를 다뤘다면 이 글은 기억이 넘어가지 않은 경우를 다룬다.
실수가 나는 길목에서 기억을 꺼내 붙이는 장치는 길목 주입을 다룬 글에서 다뤘고 그 장치를 만든 계기는 다른 실수였다.
결론
기록이 갇혀 있었다는 사실만으로는 반복이 설명되지 않았다.
기록을 보면 aside 자기 메모리 안에서도, 공유 뱅크에서도, 다음에 부딪힌 쪽은 함수를 부르기 전에 그 기록을 찾아보지 않았다.
지금 이 함정은 aside 플레이북, 공용 지침, aside 개념 노트, Hindsight 뱅크의 네 곳에 기록돼 있다.
9월 30일의 조항은 기록을 쓰는 쪽을 겨냥한 것으로 보이며 함수를 부르기 전에 뱅크를 찾아보게 하는 문구는 그 한 줄에 들어 있지 않다.
한계·재검토 트리거
2026-10 기준 / 재검토 트리거: aside 에피소드 메모리에 setViewportSize 항목이 다시 생기거나 부르기 전에 recall로 이 함정을 찾아 피한 기록이 처음 생기는 날
참고
- '기억하지 마'는 위임 한 단계를 넘지 못했다 - 금지가 넘어가지 않은 쪽, 이 글의 짝
- 기억한 실수를 길목에 놓았다 - 실수가 나는 길목에 기억을 꽂는 장치