WIKI0to1
개인 제품·2026 ~ (운영 중)·기획·개발 단독

0to1

문서가 스스로 낡았다고 말하는 기록 사이트.

Next.jsTypeScriptMDXTailwindVercelNode

지금 보고 있는 사이트다.

0to1은?

만든 것을 기록하고 공개하는 사이트다. 프로젝트 위키, 개발로그, 매일 굽는 기술 동향, 그리고 자동화가 실제로 돌고 있는지 보여주는 관제판으로 되어 있다.

포트폴리오 사이트인데 한 가지가 다르다. 사이트를 사람이 채우지 않는다. 글을 쓰는 건 사람이지만, 무엇이 낡았는지·무엇이 어젯밤 돌았는지·지표가 얼마인지는 매일 밤 기계가 계산해서 넣는다.

13
프로젝트 문서
25
기술 문서 (플레이북 · 노트)
7
무인 자동화
0
손으로 적는 지표

문서가 스스로 낡았다고 말한다

위키의 가장 흔한 실패는 문서가 조용히 썩는 것이다. 코드는 계속 바뀌는데 문서는 그대로고, 읽는 사람은 그게 언제 적 얘긴지 모른다. 최신인 척하는 문서가 아예 없는 문서보다 나쁘다.

그래서 각 문서에 감시할 코드 경로를 붙였다. 문서가 코드를 마지막으로 확인한 지점 이후, 그 경로에 커밋이 몇 개 쌓였는지를 센다. 그게 드리프트다.

문서의 확인 지점 읽기
문서마다 "여기까지 코드를 봤다"는 커밋 해시를 들고 있다
그 이후 코드 커밋 세기
문서가 감시하는 경로에 쌓인 커밋 수 = drift
점수 환산
score = 100 × 20 / (20 + drift)
등급 판정
70 이상 fresh · 40 이상 stale · 그 아래 rotten
문서 상단에 배지
읽는 사람이 먼저 본다
자동화 문서가 스스로 31% 썩었다고 말하는 중이다. 마지막 조사 이후 감시 경로에 45커밋이 쌓였다.
자동화 문서가 스스로 31% 썩었다고 말하는 중이다. 마지막 조사 이후 감시 경로에 45커밋이 쌓였다.

커밋 20개가 쌓이면 50점으로 떨어지는 곡선이다. 처음엔 천천히, 뒤로 갈수록 급하게 깎인다.

위 배지는 지어낸 예시가 아니라 이 사이트의 실제 문서다. 자동화를 계속 고치면서 그 문서를 안 고쳤으니 저렇게 뜬다. 부끄럽지만 이게 이 장치가 제대로 도는 증거다. 그 문서는 이후 54커밋까지 밀렸다가 지금은 다 갚아 100%다.

기준점을 잘못 잡아서 배지가 거짓말을 했다

한동안 이 계산의 기준점이 **"위키 파일을 마지막으로 고친 커밋"**이었다. 그러면 본문을 검증하지 않고 오타 하나만 고쳐도 점수가 100%로 되돌아간다. 실제로 제목에서 긴 줄표를 걷어낸 커밋 하나가 전 문서의 배지를 한꺼번에 FRESH로 만들었다. 검증하지 않았는데 신선하다고 말하는 배지는, 없는 것보다 나쁘다.

기준을 문서가 코드를 실제로 확인한 지점으로 옮겨서 고쳤다. 각 문서의 근거가 되는 사실 기록에 "여기까지 봤다"는 커밋 해시를 박아두고, 배지는 그 지점 이후 쌓인 커밋을 센다. 오타를 고치든 문장을 다듬든 점수는 안 움직인다. 코드를 다시 확인해야만 움직인다.

같은 김에 계산기를 하나로 합쳤다. 그전엔 배지를 내는 쪽과 썩음을 알리는 쪽이 각자 커밋을 세고 각자 매핑을 들고 있어서, 같은 질문에 서로 다른 답을 내놓고 있었다. 지금은 계산이 한 곳, 문서와 코드의 대응이 한 곳이고 나머지는 그 결과를 읽기만 한다.

밀린 문서를 매일 조금씩 갚는다

원래는 하나 정한 게 있었다. 낡은 문서를 자동으로 고쳐 쓰지 않는다. 낡았다고 표시만 한다. 자동으로 다시 쓰게 하면 문서가 코드 요약본이 되어버리고, 그러면 애초에 사람이 쓸 이유가 없다고 봤다. 문서의 값은 "왜 그렇게 했는가"에 있는데 그건 커밋 로그에 없으니까.

그런데 표시만 하니까 아무도 안 갚았다. 자동화 문서는 54커밋이 밀려 27%까지 떨어졌다. 낡았다고 정확하게 말해주는 배지가 있어도, 갚는 사람이 없으면 그냥 정확한 부고다.

그래서 갚는 것도 넘겼다. 대신 통째로 다시 쓰게 두지 않았다. 작업 단위를 문서 전체가 아니라 커밋 묶음으로 잘랐다. 매일 밤 확인 지점 이후 정해진 개수만큼만 읽고, 그만큼만 반영하고, 확인 지점을 그 자리로 옮긴다.

밀린 양이 아무리 커도 한 번에 보는 건 정해진 개수뿐이다. 확인 지점이 앞으로 갔을 때만 커밋한다.
밀린 양이 아무리 커도 한 번에 보는 건 정해진 개수뿐이다. 확인 지점이 앞으로 갔을 때만 커밋한다.

이 한 번의 변경으로 세 가지가 같이 풀렸다. 한 번에 처리하는 양이 고정이라 "너무 크면 건너뛴다"는 상한이 필요 없어졌고(전에는 가장 썩은 문서가 그 상한 때문에 정확히 제외됐다), 매일 조금씩 갚으니 빚이 쌓이지 않고, 무엇보다 성공 여부를 따로 기록할 필요가 없어졌다. 확인 지점이 앞으로 갔으면 성공이고 그대로면 실패다. 중간에 죽으면 지점이 안 움직이니 다음 밤이 같은 자리에서 이어받는다.

마지막 게 제일 크다. 전에는 자동화가 죽어도 현황판에 성공 도장이 찍혔다. 날짜만으로는 "어디까지 했는지"를 표현할 수 없어서 성공 여부를 따로 적어야 했고, 그 기록이 거짓말을 했다. 커밋 해시는 그 자체가 진도라서 적을 것이 없다. 관측 장치를 고치는 것보다, 관측할 필요가 없는 구조로 바꾸는 쪽이 낫다.

그리고 처음의 걱정은 규칙으로 남겼다. 자동 갱신은 사실만 고치고 서사는 건드리지 않는다. 바뀐 곳만 고치고, 확인 못 한 건 원문을 그대로 둔다. "왜 그렇게 했는가"는 여전히 사람이 쓴다.

Decision #01발행물은 신선도 계산에서 제외한다

자동화 문서(ai-harness)는 0to1 코드 전체를 감시하는데, 여기서 posts/content/는 뺐다.

글을 하나 발행할 때마다 커밋이 쌓이는데, 그게 자동화 문서를 썩게 만들면 안 된다. 글은 기계의 산출물이지 기계의 변경이 아니다. 감시 대상은 기계여야 한다.

LLM이 출처를 지어내지 못하게 하는 법

매일 아침 기술 동향을 카드로 굽는다. 여기서 제일 신경 쓴 건 큐레이션 품질이 아니라 거짓말을 구조적으로 막는 것이다.

한 번 사고가 났다. 카드에 붙은 Hacker News 링크의 글 번호를 모델이 지어낸 것이다. 그럴듯한 형식이라 눈으로는 안 걸린다. 링크를 눌러야 없는 글이라는 걸 안다.

그래서 파이프라인을 수집과 큐레이션으로 쪼갰다.

수집: 코드가 한다
Hacker News · arXiv · Stack Overflow · Reddit을 긁어 raw JSON 한 덩이로
LLM은 raw만 읽는다
웹을 직접 못 본다. 없는 출처를 만들 재료 자체가 없다
URL은 복사만
생성·추측 금지. 쓰기 직전 raw에 실재하는 문자열인지 대조
수치도 세지 않고 옮긴다
scanned = raw items 길이 그대로
확신 없으면 버린다
애매한 걸 채우느니 카드 수가 적은 게 낫다

핵심은 두 번째다. 모델에게 웹 접근을 주지 않으면 출처를 지어낼 능력 자체가 사라진다. 프롬프트로 "지어내지 마"라고 부탁하는 것과, 지어낼 재료를 안 주는 것은 다르다. 앞은 지켜지길 바라는 것이고 뒤는 구조다.

같은 이유로 조용한 날은 0장짜리 파일을 쓴다. 빈 브리핑도 정직한 신호이고, 억지로 채운 카드보다 낫다.

훑은 것, 카드로 남긴 것, 아이디어로 넘긴 것을 그날 숫자 그대로 보여준다.
훑은 것, 카드로 남긴 것, 아이디어로 넘긴 것을 그날 숫자 그대로 보여준다.

걸러낸 양도 같이 보여준다. 76건을 훑어 6장을 남겼다면 70건은 버린 것이고, 그 비율이 보여야 카드 6장을 믿을 수 있다.

읽고 끝나지 않게 한다

동향의 진짜 문제는 정확도가 아니라 휘발이다. 아침에 읽고 "이거 써먹을 만한데" 하고는 그날 카드 안에 묻힌다.

그래서 카드에 apply 필드를 뒀다. 그 기술이 내 프로젝트에 연결될 때만 한 줄, 그리고 어느 프로젝트로 향하는지 대상 키를 함께 적는다. 나중에 그 프로젝트를 만질 때 쌓인 아이디어를 대상별로 다시 꺼내고, 실제로 반영했으면 반영 표시를 남긴다.

수집과 재사용을 다른 도구로 나눈 셈이다. 이 필드는 원문 사실이 아니라 제안이라, 화면에서도 사실과 구분해서 보여준다.

밤에 혼자 돌아간다

매일 밤 다섯 가지가 무인으로 돈다. 개발일지 초안 생성, 위키 신선도 재계산, 원장 드리프트 감지, 배포한 것들의 공개 지표 스냅샷, 그리고 평가 게이트다. 아침에는 기술 동향을 네 개 소스에서 긁어 카드로 굽는다.

각 자동화는 돌 때마다 매니페스트에 마지막 실행 시각과 결과를 남긴다. 관제판은 그 파일을 읽어서 보여준다.

최근 24시간에 실패가 있으면 첫 화면이 장애로 바뀐다. 복구한 뒤에도 그날 실패 기록은 남는다.
최근 24시간에 실패가 있으면 첫 화면이 장애로 바뀐다. 복구한 뒤에도 그날 실패 기록은 남는다.

실패도 그대로 보여준다. 어느 날 아침 동향 큐레이션이 연결 끊김으로 죽었을 때, 관제판에는 "실패 · 네트워크"가 그대로 떴다. 실패를 감추면 관제판이 아니라 장식이 된다. 초록불만 뜨는 대시보드는 아무도 안 본다.

넘어지면 스스로 일어난다

무인으로 도는 이상, 실패했을 때 사람을 부르는 것으로 끝나면 안 된다. 그래서 복구를 두 층으로 뒀다.

즉시 재시도. 실패하면 종류부터 가른다. 연결이 끊긴 종류면 잠깐 뒤 한 번 더 부르고, 사용량 한도에 걸린 거면 재시도하지 않는다. 한도는 곧바로 다시 불러도 같은 이유로 죽고, 창이 열릴 때까지 기다리는 건 크론이 할 일이 아니다. 재시도할 값이 있는 실패와 없는 실패를 구분하는 것이 이 층의 전부다.

다음 날 보충. 재시도로도 못 살리면 그날 브리핑이 빈다. 그런데 수집 결과는 날짜별 캐시로 남아 있어서, 다음 날 아침에 빈 날을 찾아 다시 구울 수 있다. 큐레이션은 이미 카드가 있으면 그냥 끝나므로 매일 돌아도 안전하다. 실패가 하루로 끝나고 구멍으로 남지 않게 하는 장치다.

복구된 날은 관제판에도 "재시도 후 복구"라고 적는다. 조용히 살아나면 이 시스템이 얼마나 자주 넘어지는지 아무도 모르게 된다.

Decision #02에러 메시지가 원인을 가리켰다

Reddit 수집이 매일 실패하고 있었다. 로그에는 "자격증명 미설정"이라고 찍혀서, 값을 안 넣은 문제로 보였다.

실제 원인은 달랐다. 스크립트가 .env 파일을 아예 읽지 않고 있었다. 값을 채워 넣어도 안 됐을 것이고, 인증 코드는 한 번도 실행된 적이 없었다.

메시지가 틀린 말은 아니었다. 환경변수에 값이 없는 건 사실이니까. 그런데 그게 "안 넣었다"로 읽히면서 원인을 엉뚱한 데서 찾게 만들었다. 지금은 파일이 없는 경우와 값이 비어 있는 경우를 나눠서 말한다.

Decision #03사람이 판단할 자리는 남겨둔다

자동화의 경계는 계속 밀었지만 전부 밀지는 않았다.

개발일지는 결국 발행까지 무인으로 넘겼다. 그날 무슨 커밋이 있었는지는 기계가 더 정확하니까. 반면 블로그 글은 초안까지만 자동이고 발행은 사람이 누른다. 무엇을 쓸 값이 있는지는 기계가 모른다.

원장을 코드에 맞춰 다시 쓰는 자동화(refresh)는 만들어두고 꺼둔 상태다. 관제판에 "수동 검증 중 · 토글 OFF"로 뜬다. 만들었다고 켜야 하는 건 아니다.

발행은 push 하나

배포는 git push 하나다. Vercel이 물려 있어서 약 50초 뒤 반영된다. 관리 화면도, 배포 버튼도 없다.

대신 규칙이 하나 붙는다. 커밋이 곧 발행이다. 밤 자동화가 계산 결과를 커밋하고 스스로 push하기 때문에, 실험을 커밋해두면 그날 밤 같이 나간다. 그래서 확정되지 않은 것은 커밋하지 않는다. 편한 만큼 대가가 있는 구조다.

위키는 파일이 곧 목차다

content/ 아래 마크다운을 두면 그게 문서가 된다. 네비 순서만 배열로 적어두고, 나머지는 파일 존재 여부로 굴러간다.

문서 안에서는 흐름도, 지표 타일, 결정 블록, 스크린샷 같은 조각을 컴포넌트로 쓴다. 글로 길게 설명할 것을 구조로 보여주기 위해서다. 이 문서에도 위에 다 쓰였다.

문서는 두 갈래다. 플레이북은 내가 겪은 것이고, 노트는 개념 정리다. 기준은 하나다. 남이 써도 비슷하게 나오면 노트, 나만 쓸 수 있으면 플레이북.

기술 스택

  • Next.js (App Router) · TypeScript · Tailwind · MDX
  • 콘텐츠: 파일 기반 (content/**.md, posts/**.md) · 프론트매터 + MDX 컴포넌트
  • 자동화: Node 스크립트 9개 · 야간 무인 실행 · 결과는 JSON으로 커밋
  • 배포: Vercel (git 연동) · RSS는 빌드 전 생성

정직한 한계

신선도 점수는 커밋 수를 센다. 코드가 실제로 얼마나 달라졌는지가 아니라 몇 번 손댔는지다. 오타 수정 20개와 구조 변경 1개가 같은 무게로 잡힌다. 그래도 쓰는 이유는, 완벽한 지표가 아니어도 "이 문서 오래됐다"는 신호로는 충분히 작동하기 때문이다.

그리고 아직 감시 경로를 안 붙인 문서는 100%로 표시된다. 배지가 있는 문서와 없는 문서가 섞이는 들쭉날쭉함을 피하려고 그렇게 뒀는데, 엄밀히는 "안 쟀다"와 "안 낡았다"가 화면에서 같아 보인다. 감시 경로를 붙이는 순간 실측값으로 바뀌긴 하지만, 붙이기 전까지는 이 배지가 최신을 보증하지 않는다.

그리고 이 사이트는 결국 나 혼자 쓰고 나 혼자 읽는다. 협업 위키가 겪는 문제들은 아직 안 겪어봤다.