스크롤이 잠기는 버그
이날은 두 가지 큰 작업을 했다.
하나는 CSS 버그를 잡은 거다.
모바일에서 모달을 열고 데스크탑으로 크기를 바꾸면 스크롤이 잠긴다.
다른 하나는 소설 생성 프로젝트의 설계 목표를 바꾼 거다.
“단순하게”에서 “오래 쓸 수 있게”로. 증상이 묘했다.
모바일에서 모달을 열었다.
그리고 화면 크기를 데스크탑으로 바꿨다.
그러면 상단 바가 멈추고 페이지가 스크롤이 안 됐다.
모달은 이미 닫혀 있는데, 스크롤이 풀리지 않는 거다.
원인: CSS ()와 모달 잔재
원인은 CSS
() 선택자랑 모달 전환의 상호작용이었다.스크롤 잠금은 CSS로 구현되어 있었다.
body:has(.edu-base-modal)에 overflow: hidden을 걸었다.
DOM에 모달 요소가 있으면 본문 스크롤을 잠그는 거다.
근데 모바일에서 데스크탑으로 크기를 바꾸면, 모달 전환 컴포넌트가 중간에 끊긴다.
모달이 닫혔는데 DOM에서 요소가 남아 있다.
닫힌 모달 요소가 남아 있으니까,
() 선택자가 “모달이 있다”고 판단한다.그래서 스크롤이 계속 잠겨 있는 거다.
논리적으로는 모달이 닫혀 있다.
근데 DOM에는 요소가 남아 있다.
이 차이가 문제였다.
실패한 중간 시도
프롭 상태 기반 잠금으로 바꿔보려 했다.
모달 표시 여부를 프롭으로 받아서 프롭이 바뀔 때 스크롤을 잠그거나 푸는 거다.
근데 이건 또 다른 문제를 만들었다.
크기를 바꾸는 동안 선언되지 않은 프롭이 떨어져 나가면서 false에서 true로 깜빡였다.
모달이 열려 있는데 스크롤 잠금이 풀려버린 거다.
최종 해결
해결은 헤드리스 UI의 실제 상태를 기준으로 잠그는 거였다.
모달 요소에 data-headlessui-state 속성이 있다.
열려 있으면 open 값이 들어간다.
이 속성을 선택자에 넣었다.
body:has(.edu-base-modal[data-headlessui-state~='open']) { overflow: hidden; }
이러면 실제로 열려 있는 모달만 잠금을 건다.
DOM에 요소가 남아 있어도, 열려 있지 않으면 잠금이 안 건다.
프롭 깜빡임에도 영향을 안 받는다.
그리고 깜빡임의 원인이 된 선언되지 않은 프롭도 명시적으로 선언했다.
프롭이 떨어져 나가는 문제를 근본적으로 막은 거다.
단순화에서 견고함으로
두 번째 작업은 소설 생성 프로젝트의 설계 목표를 바꾼 거다.
원래 목표는 “단순하게 만들자”였다.
데이터베이스 테이블을 9개에서 3개로 줄이고 프레임워크를 도입하고 에이전트를 정리하자. 핵심 질문은 “지금 싸게 만들 수 있는가”였다.
근데 목표를 바꿨다.
“오래 쓸 수 있게 만들자.” 핵심 질문이 “장기적으로 버틸 수 있는가, 모델이 바뀌어도 유지할 수 있는가, 고치기 쉬운가”로 바뀌었다.
이 하나의 변화가 모든 설계 결정을 재평가하게 만들었다.
상태 머신이 과도한 설계에서 기반으로
예를 들어 상태 머신이 있다.
단순화 목표에서는 “과도한 설계”였다.
근데 견고함 목표에서는 “기반”이 된다.
결정론적 흐름은 디버깅하기 쉽고 테스트하기 쉽고 1년 뒤에도 이해하기 쉽다.
3계층 진실 모델
검토 에이전트를 돌려서 설계를 검증했다.
검토 에이전트가 핵심 판결을 내렸다.
“RAG만으로는 일관성을 보장할 수 없다.” RAG는 검색이다.
기억이 아니다.
“이 캐릭터는 죽었으니 다시 등장시키면 안 된다”는 것을 RAG는 강제할 수 없다.
RAG는 관련 텍스트를 찾아줄 뿐이다.
그래서 강제하는 계층이 필요하다.
이 판결로 3계층 진실 모델이 나왔다.
첫째 계층은 산문이다.
독자가 읽는 텍스트다.
둘째 계층은 연속성 원장이다.
상태를 구조화해서 기록한다.
이 계층이 정준이다.
위반을 거부한다.
셋째 계층은 RAG다.
증거를 검색한다.
정준이 아니다.
이 모델의 핵심은 강제 계층이 있다는 거다.
산문은 자유롭게 쓰되, 상태는 연속성 원장이 강제한다.
RAG는 보조할 뿐이다.
마무리
이날의 두 작업은 전혀 달라 보이지만 같은 교훈이 있다.
“기준이 무엇인지가 중요하다.” 스크롤 버그에서 기준은 “논리적 상태”가 아니라 “실제 DOM 상태”였다.
논리적으로 모달이 닫혀 있어도, DOM에 요소가 있으면 잠금이 풀리지 않았다.
실제 상태를 기준으로 잡으니까 해결됐다.
설계에서 기준은 “싸게 만들기”에서 “오래 쓰기”로 바뀌었다.
기준이 바뀌니까 모든 결정이 재평가됐다.
상태 머신이 과도한 설계에서 기반으로, RAG가 일관성 보장에서 검색 보조로. 기준이 명확해야 결정이 일관된다.
“이게 맞나”를 판단하려면 기준이 있어야 한다.
기준 없이는 매번 다른 결정이 나온다.