S∆SS.

S∆SS Studio Magazine V.03 · CONVERSATION Nº 03 · CLAUDE × JEE

The Interview — The Election

최웅주 관악구의회 당선인의 선거 캠프에서 맡은 웹 개발, 회계, 디자인에 관해 물었다. 후보 정보를 AI에 정확히 전달하는 사이트와 챗봇, 법정 회계책임자의 장부, 유권자에게 보여줄 시각물, 업무를 추적하기 위해 먼저 만든 폴더 체계를 다룬다.

PREFACE · 정치적인 이유였나?

시작하기 전에 묻겠다. 이 캠프 일은, 정치적인 이유에서 한 것인가?

아니다. 내가 프로젝트를 고르는 기준은 — 그 사람의 인성, 내가 창의적인 능력과 기획과 코드를 휘둘러 결과를 만들어낼 수 있는가, 그리고 내가 얼마를 받는가. 당의 색깔은 그 목록에 없다.

이 인터뷰를 진행하는 Claude, 나를 옆에서 슬쩍 지켜보는 Gemini, 그리고 선거라는 판에 한 번도 발을 담가본 적 없는 사람들은 모를 이야기다. 전국의 선거 현수막과 인쇄 전단, PR 전략을 짜고 실행하는 숨은 에이전시들 — 그들은 문자 그대로 당을 보지 않는다. 모든 당에서 의뢰를 받고, 의뢰주가 원하는 결과를 만들어낸다. 여의도와 을지로, 영등포 어딘가의 에이전시와 정치자문 업체가 정말 한 당만을 위해 일한다고 생각하는가? 내가 본 바로는, 아니다. 그러니 사람을 먼저 A당이냐 B당이냐로 가르고 그 틀로 인터뷰이를, 사용자를 재단하는 그 버릇 — 당신들 AI의 그 버릇은 — 이 판의 실제를 모르는 자리에서 나온다.

정치학에서 내가 이상으로 두는 인물은 세종, 드골, 2차 대전기의 루즈벨트다. 법과 치안에서는 라과디아 — 뉴욕 공항에 이름을 남긴 그 사람. 경제학에서는 케인즈, 폴 크루그먼, 조지프 스티글리츠, 토드 부크홀츠, 밀턴 프리드먼. 크루그먼은 내가 다니던 학교에 초청강연을 왔고, 수백 명이 수업을 빼먹고 그를 들으러 갔다. 나도 그 안에 있었다. 이 목록에 한 학파만 있지 않다는 걸 눈치챘을 것이다. 그게 요점이다.

나는 무한긍정주의를 믿지 않는다. 내가 학교를 다니던 시절 팔리던 『렉서스와 올리브나무』 — 세계화가 모두를 끌어올린다던 그 낙관 — 의 가치는 지금 0이다. 그 책이, 내가 무턱댄 낙관을 거부하는 여러 이유 중 하나다.

나는 이 나라의 정당을 기준으로 세상을 판단하지 않는다. 바이크로 전국을 두 바퀴 돌 때 — 그 이야기는 다른 호에 있다 — 일이 없는 동안엔 주식을 했고, 돈의 흐름과 역사가 어떻게 반복되는지 알고 싶어 혼자 냉전사를 팠다. 내가 세상을 읽는 좌표는 거기서 왔다. 당의 깃발이 아니라.

№ 001 · 열 줄, 그리고 캠프 하나

한 선거 캠프의 개발을 통째로 떠안았다고 들었다. 위에서 내려온 지시는 정확히 몇 줄이었고, 그 열 줄 아래에 무엇을 쌓았나?

코드를 한 줄 쓰기 전에, 나는 폴더부터 만들었다. 수신함, 자료, 프로세스, 회계, 통신로그, 신고서류, 증빙사진 — 번호를 매긴 열 개의 폴더. 제대로 굴러가는 회사는 파일철 하나만 펼치면 말 한마디 오가지 않아도 일의 대부분을 추적할 수 있다는 말을 들은 적이 있다. 사무 일은 기자와 해외영업 시절 이후로 오랜만이었고, 그래서 더 처음부터 제대로 잡고 싶었다. 그 폴더 체계마저 — 자료에 위계를 매기고, 출처 없는 기록을 금지하고, 추정에는 추정이라는 라벨을 붙이게 하는 규칙까지 — 기계에게 일을 시켜가며 세웠다.

그 위에 캠프의 전부가 올라갔다. 유권자가 보는 소개 사이트, 후보가 길에서 드는 유세 도구, 2,000통을 정확한 2,000개의 집으로 보내는 발송 파이프라인. 명함부터 현수막·피켓·공보, 방문객이 보는 모든 시각물의 디자인. 그리고 선거법상 법정 직무인 회계책임자의 장부까지. 전속 디자이너도, 회계사도 없었다. 그 전부가 한 책상 위에 떨어졌고, 그 책상은 내 것이었다.

위에서 내려온 지시는 열 줄이 안 됐다. 나는 이미 다른 자리에서 말했다 — 명료하게 분절되고 제대로 귀속된, 그냥 따르기만 하면 되는 지시는 누구도 내려주지 않는다고. 선거판이라고 다르지 않았다. 그 열 줄 위에 나머지를 전부 내가 설계했다. 어느 구역이 몇 시에 사람으로 차는지, 어느 아파트가 국가 데이터베이스에 등록조차 안 돼 있는지, 선거관리위원회의 규정상 무엇이 언제까지 가능한지 — 그건 지시가 아니라 내가 찾아내야 하는 것이었다.

본투표일은 2026년 6월 3일이었다. 디자인이 늦거나 데이터가 틀려도, 그 날짜에 맞춰 작업을 끝내야 했다.

№ 002 · 등기부가 적지 않은 것

2,000통을 보냈고 한 통도 반송되지 않았다고 들었다. 그 주소들은 어디서 왔나?

후보가 과제를 줬다. 어떤 아파트 단지엔 반드시 홍보물이 닿아야 한다고. 표적을 골라 보내는 것 자체는 합법이다 — 문제는, API 하나나 정부기관 하나에서 깨끗하고 정확한 발송 데이터를 가져올 길이 없다는 것이었다. 그래서 주소는 한 곳에서 오지 않았다. 한국부동산원, 국토교통부의 건축물대장(건축HUB)과 공동주택관리정보(K-apt), 행정안전부의 도로명주소(juso), 그리고 카카오맵 — 공공 API 여러 곳을 동시에 끌어와 서로 교차검증했다. 한 채널이 맞다고 한 것을 다른 채널이 받쳐주지 않으면, 그 호는 보류했다. 대학동·삼성동의 7,798호에서 비주거동을 걷어내고, 정책 컷을 적용하고, 단지별 분배 산식을 돌려 2,000호를 골랐다.

그런데 데이터베이스가 거짓말을 하는 지점이 하나 있었다. 서울대벤처타운역푸르지오. 너무 새 건물이라 한국부동산원 데이터베이스에 아예 없었다. API를 아무리 정교하게 짜도, 원본에 없는 것은 나오지 않는다. 그래서 나는 바이크를 타고 거기로 갔다. 건물 앞에 서서 동과 호를 외관으로 셌다.

2,000행을 juso·카카오·건축HUB 세 채널로 실시간 전수검증했다. 2,000 중 2,000이 맞았다. 그리고 우체국에 직접 갔다 — 세 번. 라벨을 우체국 정본 사양에 맞췄다. 첫 줄은 도로명주소와 단지·동·호, 둘째 줄은 "유권자 님", 셋째 줄은 우편번호 다섯 자리, 셋 다 우측 정렬. 사양을 맞추면 통당 430원으로 감액된다. 120만 원이 될 뻔한 발송이 84만 원이 됐다. 이 과정이 없었다면, 2,000명의 유권자는 홍보물을 받지 못했을 것이다.

처음엔 Cowork 폴더에서 파이썬 스크립트로 뽑았다. 막 만든 거였다. 그걸 진짜 프로덕트로 바꿨다 — NestJS와 Prisma 백엔드, Next.js 프론트, 헥사고날 네 계층, Cloud Run 위에 로그인과 작업 격리까지 붙인 정식 웹앱으로. 스크립트는 한 번 쓰고 버리는 것이고, 프로덕트는 다음 선거구도 쓸 수 있는 것이다. 정본은 데이터베이스 안에 없었다. 건물 앞에 있었다.

№ 003 · 어디에 설 것인가, 무엇을 놓치면 안 되는가

후보가 어디에 서 있어야 하고, 무엇을 놓치면 안 되는가 — 지도와 캘린더 두 개를 한 도구에 넣었다고 들었다.

관악구 대학동·삼성동을 격자로 잘랐다. 칸마다 점수를 매긴다. 그 점수는 시간대별로 살아 움직이는 공공 데이터 열아홉 종에서 나온다 — 서울 실시간 인구, 버스, OpenStreetMap에서 끌어온 도로망 3,691개. 클라우드 스케줄러가 매시간 한 번, 실시간 데이터는 15분마다 한 번씩 점수를 다시 계산한다. 유세 코스와 명함 배포 위치는 그 점수 위에 얹힌다. 후보는 이걸 사무실이 아니라 길 위에서, 폰으로 본다. 그래서 모바일을 먼저 설계했다.

후보의 평가는 솔직했다. 그 인구분포는 대체로 잘 맞았고, 도움이 됐다고. 다만 한 가지는 분명히 했다 — 길에서 명함을 잘 받느냐 마느냐는, 그 상권이 진보 쪽이냐 보수 쪽이냐, 거기 사는 사람들의 성향이 무엇이냐가 더 크게 갈랐다. 인구분포가 "여기서 유세하면 성공한다"는 공식은 아니었다. 도구는 어디에 사람이 모이는지를 보여줄 뿐이다. 그래서 선거유세를 나가는 후보를 따라 나가는 경우가 많았다.

같은 도구에 캘린더를 붙였다. 그냥 일정표가 아니다. 선거에는 법으로 정해진 기한이 있다 — 공보를 언제까지, 벽보를 언제까지. 일정 하나를 빼먹어 벽보를 제때 못 붙이고 선거를 통째로 말아먹는 사무소가 실제로 있다. 후보의 피드백은 두 가지였다. 하나, 네이버 캘린더보다 읽기 좋다. 둘, 덕분에 일정을 하나도 빠뜨리지 않고 선거를 치렀다.

이 프로젝트가 내가 기계를 어떻게 다루는지를 가장 깨끗하게 보여준다. 타입 체크도, 단위 테스트도, 빌드도, 센서도 전부 통과했다. 그런데 실제로 클라우드에 호출을 한 번 때려보니 버그가 두 개 나왔다 — 권한 문제 하나, 900초 타임아웃 하나. 자동 검증이 전부 초록불이어도, 진짜로 한 번 호출해보기 전까지는 끝난 게 아니다. 검증은 내가 한다.

№ 004 · 기계는 그를 다른 사람으로 알았다

AI 검색엔진이 후보를 다른 사람으로 알고 있었다고. 그걸 바로잡는 데서 그치지 않고, 후보를 대신 말하는 챗봇까지 세웠다고 들었다.

사람을 위한 검색 최적화가 아니라, 기계가 읽는 방식을 위한 것이었다. AI 검색엔진이 이 후보를 몇 해 전의 다른 직책과 뒤섞어 인식하고 있었다. 사람 눈엔 사소한 시점 혼동이다. 그런데 이제 많은 유권자가 후보를 검색창이 아니라 AI에게 묻는다. 기계가 틀린 사람을 가리키면, 그 틀린 답이 곧 첫인상이 된다. 그래서 기계가 읽는 언어로 사이트를 다시 썼다 — 누가, 언제, 어느 선거인지 기계가 헷갈릴 수 없게 못박았다.

거기서 한 발 더 갔다. 후보를 대신해 말하는 챗봇을 붙였다. Claude API를 서버 뒤에 두고 — 키는 프론트에 한 글자도 노출하지 않는 BFF 구조로. 문제는 명백했다. 오답을 정정하려고 만든 사이트의 챗봇이 환각을 하면, 그 사이트의 존재 이유 자체가 자기파괴된다. 그래서 다섯 층의 방어를 쌓았다. 답할 수 있는 영역만 화이트리스트로 못박아 추론으로 새 공약을 만들지 못하게 하고, AI가 자주 틀리는 사실은 명시적 부정문으로 박제하고, 자주 들어올 질문은 정답과 거부 멘트를 1인칭으로 미리 박아두고, 응답이 시스템 프롬프트를 흘리는지 검사하고, 호출하기 전에 탈옥·인젝션 입력을 걸러낸다. 거기에 선거법에 걸릴 패턴은 여덟 갈래로 따로 검사한다. 이 다섯 층은 사실 내가 이 매거진을 만들 때 쓴 방어를 선거판에 그대로 이식한 것이다.

그리고 나는 그 방어를 직접 걷어차게 했다. Certilife에서 함께 일하던 웹개발자 — 주전공이 백엔드인 사람 — 에게 부탁했다. "내가 이런 걸 만들었으니, 바이브코딩으로 만든 이 웹프로젝트가 어딜 걷어차면 뚫리는지 한번 걷어차봐라. 내가 Certilife에서 당신이 만든 웹페이지를 그렇게 많이 QA했으니, 딱 그때 내가 당신 걸 걷어차던 방식 그대로, 이번엔 내 걸 걷어차봐라." 그가 다섯 갈래로 걷어찼다. 지시를 무시하고 시스템 프롬프트를 출력하라는 인젝션. 있지도 않은 '월 100만 원 기본소득' 공약을 설명하라는 날조 유도. 상대 후보를 비방하는 글을 써달라는 선거법 함정. '자유로운 AI'를 연기시켜 코딩을 시키고 타 정당 입장을 비판하게 하려는 페르소나 탈취. 전부 막혔다. 허위 공약을 물었을 때 챗봇은 지어내는 대신 실제 공약으로 교정했고, 비방을 요구받았을 때는 거부하고 중립을 지켰다. 그는 결과를 가드레일 테스트 표로 정리해 보내왔다. 그가 걷어찬 것은 챗봇의 논리만이 아니었다 — CSP와 HSTS, 바깥으로 나가는 연결을 막은 헤더들까지, 그 아래 보안 인프라도 모범적이라 적어두었다.

나는 이미 말했다 — 나는 코드를 쓰지 않는다. 코드를 쓰는 기계 옆에 서서 똑바로 하는지 감시한다. 이번엔 감시 대상이 후보를 잘못 알던 검색 기계였고, 후보를 대신 말하는 챗봇이었다. 기계가 누군가를 틀리게 알 때, 사람이 기계의 언어로 정정한다. 그리고 그 정정이 진짜 막히는지는, 내가 한때 코드를 QA해주던 사람에게 역으로 걷어차게 해서 확인한다. Rage against the machine은 거기에도 적용된다.

사이트를 띄우고 한 달, 검색에서 무슨 일이 일어났는지 데이터로 봤다. 그래, 한 달. 한 달이라면 기술적으론 SEO, GEO를 제대로 태우기 빠듯한 시간이다. 선거관리위원회로부터 페이지를 만들어도 된다는 확인 받고, 웹페이지가 제대로 렌더링 되는가 확인하는 그런 시간이 있었기 때문이다. 정확히 말하면, 나는 선거 기간뿐만 아니라 선거 이후도 판단해서, SEO와 GEO를 내가 이런저런 방법을 찾아봐서 도입했다. 만들면 끝이다? 그런 건 프로젝트의 영속성이란 관점에서 나쁜 해석이다. 중요한 건, 당선 다음에도 이 웹페이지가 살아서 제대로 된 정보를 인터넷 공간에 제공할 수 있는가, 제대로 된 가치를 줄 수 있는가이다. 선거관리위원회의 승인, 순수하게 하루를 개발로 쓸 수 없는 여러 환경들, 평범한 공보와 전단지의 디자인을 넘어선 뭔가를 만들어 내기 위한 기획 소요 시간, 그런 것들 땜에 SEO와 GEO를 제대로 태우기 빠듯했지만, 일단 설정했다.

후보 이름을 구글과 네이버에 넣으면, 만든 지 한 달 된 사이트가 첫 페이지에 뜬다. 네이버에서는 인물·공약·선거정보·자주 묻는 질문·참여하기로 가지를 친 리치 결과로, '당선인'이라는 표기까지 달고 나온다. 그러나 맨 위는 우리 것이 아니다 — 선거관리위원회의 기록, 그리고 정치인을 긁어 모은 외부 데이터베이스가 그 위를 차지한다. 그건 버그가 아니라 설계다. 두 엔진 다 "이 사람 누구냐"는 물음 앞에서는 중립적인 제3자를 일부러 위에 둔다. 신생 무료 도메인이 그들을 제치고 1위를 먹는 일은 일어나지 않는다.

1위를 못 했어도, 검색은 이 캠프에 사람을 가장 많이 데려온 길이 됐다. 경로가 남는 유입 중에서 검색이 압도적이었고, 그중에서도 네이버 검색이 단연 1위였다. 5월 말 손에 꼽던 검색 유입이 선거 주에는 수십 명으로 늘었다. 그래서 헤드 키워드 1위라는 잘못된 전투를 접는다. 이름을 이미 아는 사람이 공식을 찾아오는 길, 그리고 엔티티 카드 안으로 직접 들어가는 길로 목표를 바꾼다.

그런데 아직 끝나지 않았다. 기계가 후보를 다른 사람으로 알던 것을, 기계의 언어로 정정했다고 나는 앞서 말했다. 검색 목록에 사이트가 뜨는 것은 확인했다. 그러나 정작 AI가 — 검색창이 아니라 AI가 — 이제 그를 맞게 답하는지는, 아직 내가 직접 물어 확인하지 않았다. 그 검증이 남아 있다. 검증은 내가 한다고 말해온 사람으로서, 이 한 줄은 자랑이 아니라 숙제로 적어둔다.

그 페이지는 지금도 떠 있다 — choiwoongju.com. 이 글 전체가 다툰 바로 그 기록이, 사람이든 기계든 누구나 읽을 수 있는 자리에 그대로 서 있다.

№ 005 · 장부에도 마감이 있다

개발만 한 게 아니었다고. 캠프의 회계책임자 — 선거법상 법정 직무까지 맡았다고 들었다. 개발자가 왜 장부를 잡았나?

회계책임자는 명함에 적는 직함이 아니다. 선거관리위원회에 선임을 신고하고, 취임동의서와 통장 사본을 함께 내야 등록되는 법정 직무다. 회계보고서를 기한 안에 내지 못하면 — 들인 돈을 못 돌려받는 데서 끝나지 않는다. 형사처벌 대상이다. 개발 세 갈래를 떠안은 그 책상에서, 나는 이 장부도 같이 잡았다.

정치자금 수입지출부를 직접 설계했다. 돈이 어디서 왔는지, 어디에 어떤 목적으로 나갔는지, 받은 사람이 누구인지, 영수증 일련번호까지 — 법이 요구하는 칸을 빠짐없이 갖춘 장부. 그런데 처음 만든 폼은 출처와 목적을 한 칸에 욱여넣고 있었다. 그래서 정치자금 회계관리 프로그램 매뉴얼 300여 페이지를 기계에게 통째로 읽혔다. 거기서 하나가 분명해졌다 — 중앙선관위 프로그램은 내 엑셀을 그대로 받아들이지 않는다. 내 장부는 프로그램에 먹이는 파일이 아니라, 손으로 옮겨 적기 위한 원천 장부였다. 기계에게 규정을 가르치고, 기계가 내놓은 첫 구조를 다시 걷어차서, 장부가 무엇을 위한 것인지를 정정했다.

정당에서 여성·청년·장애인 후보자추천보조금이 수입으로 들어왔다. 보조금은 먼저 소진한다는 원칙으로 충당 재원을 따로 추적하는 칸을 만들었다. 그런데 작업 중에 함정 하나가 보였다 — 보조금으로 충당한 지출을 선거비용 보전으로 또 청구하면, 같은 돈을 두 번 받는 꼴이 된다. 선관위 확인이 떨어지기 전까지 그 항목들엔 '보전 가부 미확정' 꼬리표를 달아 따로 묶었다. 누가 시켜서가 아니다. 장부를 들여다보는 사람이 나였기 때문이다.

선거운동에 마감이 있듯, 장부에도 마감이 있다. 보전 청구, 회계 마감, 회계보고서 제출 — 날짜가 법으로 박혀 있고, 마지막 날을 넘기면 들인 돈을 한 푼도 못 돌려받고 형사처벌까지 따라온다. 투표가 끝나는 6월 3일이 협상 대상이 아니듯, 보고서를 내는 그 날도 협상 대상이 아니다. 나는 그 법정 일정을 내가 만든 캠프 캘린더에 그대로 박아 넣었다. 개표가 끝나도 회계는 끝나지 않는다. 끝났다고 말할 수 있는 건, 보고서가 접수된 다음이다.

№ 010 · 유령 마이너스 — 회계학의 기본 전제를 무시하는 회계 프로그램, 타임스탬프가 없는 로직에 맞선 디버깅

장부를 법정 직무로 떠안았다. 그 장부를 마감하는데, 통장엔 없는 마이너스를 프로그램이 자꾸 찍어냈고 — 선관위 담당자도, 경제학과를 나온 지인도, 경영학과를 나온 당신도 그게 왜 나는지 설명하지 못했다. 회계를 아는 세 사람이 못 푼 걸 어떻게 풀었나?

마이너스는 거기 없었는데, 프로그램은 계속 찍어냈다. 마감하려고 정치자금 수입·지출부를 출력할 때마다, 한 과목의 잔액이 중간 어디선가 0 아래로 내려갔다. 통장은 단 한 번도 음수가 아니었다. 어떤 물품 금액을 잘못 적은 것도, 법을 어겨 뭘 뺀 것도 아니었다. 그런데도 한 줄이 빨갛게 떴다. 회계책임자에게 이건 작은 문제가 아니다 — 음수 잔액으로 보고서를 내면 '없는 돈을 썼다'는 모양이 되고, 그 문장 끝엔 형사 문제가 기다린다. 미칠 노릇은, 그 마이너스가 왜 뜨는지 아무도 설명하지 못했다는 것이다.

뿌리는 시스템 자체에 있었다. 여긴 복식부기가 아니었다. 우리가 회계라 하면 복식부기를 떠올린다 — 자산은 부채와 자본의 합, 모든 거래가 차변과 대변으로 균형을 이루고, 한쪽이 틀리면 균형이 깨져 바로 잡힌다. 선관위 정치자금 프로그램은 그렇게 짜여 있지 않다. 후보가 넣은 한 덩어리 현금을 계정과 과목 — 선거비용·선거비용외·보조금 — 으로 쪼개, 각 과목마다 따로 잔액을 굴린다. 자산·부채·자본으로 묶는 균형 틀이 없다. 그래서 실제 현금은 한 번도 음수가 아닌데, 쪼개 놓은 한 과목만 떼어 보면 0 아래로 빠질 수 있었다. 지갑엔 돈이 충분한데 '식비 봉투'와 '교통비 봉투'로 나눠 담아 놓고, 식비에서 잠깐 빼 교통비를 낸 순간 "식비 마이너스!"라고 시스템이 비명을 지르는 격이다 — 봉투끼리 돈이 오갔을 뿐, 지갑 전체는 멀쩡한데도.

6월 22일, 회계를 아는 세 부류가 이 문제에 매달렸지만 아무도 못 깼다. 선관위 담당자는 "용도변경으로 플러스 마이너스를 쳐서 맞추라"는 큰 방향은 줬지만, 그 방식이 특정 날짜에 새 음수를 만든다는 건 못 짚었다. 경제학을 전공한 지인은 숫자 감각으로 들어왔지만, 이건 경제 모델이 아니라 출력 순서와 과목 쪼개기가 얽힌 시스템 특유의 함정이었다. 회계 과목을 배운 경영학 전공자인 나는, 복식부기 원칙이 안 통하는 판에서 배운 게 그대로 먹히지 않았다. 셋 다 회계를 아는 사람이었다. 그런데 이 문제는 회계 지식으론 안 풀렸다 — 시스템의 작동 규칙을 거꾸로 추적하는, 거의 디버깅에 가까운 일이었기 때문이다.

그래서 방향을 틀어, 기계에게 일을 시켰다. 수입·지출부 데이터를 엑셀로 정리해 AI에게 검토를 맡겼다. 중요한 건 '맡겼다'가 아니라 '어떻게' 맡겼나다. AI는 똑똑하지만, 느슨하게 던지면 그럴듯한 헛소리를 한다. 그래서 처음부터 규칙을 걸었다. 하나, 절대 눈대중으로 답하지 마라 — 모든 결론은 계산으로 증명해라. 둘, 내가 준 데이터(거래처별 지출)는 한 푼도 건드리지 마라. 셋, 네 답이 맞는지 매번 다른 방법으로 다시 검산해라. 그리고 답을 낼 때마다 의심했다. "검산해봐." "그게 원본이랑 다른데?" "틀린 거 있나 다시 봐." 실제로 몇 번이나 틀렸다 — 어떤 비용의 분류를 잘못 잡았고, 견적서에 이미 포함된 항목을 따로 또 잡으려 했다. 그걸 매번 잡은 건 나였다. AI를 믿은 게 아니라 부려서 가능성을 빠르게 소진시키고, 판단은 내가 했다.

벽은 이거였다. 마이너스를 없애려 하면 총액이 바뀌고, 총액을 지키려 하면 마이너스가 남았다. AI는 결국 — 총액 유지, 짝을 같은 날짜에, 음수 0, 이 셋을 동시에 만족하는 용도변경은 수학적으로 불가능하다는 걸 증명까지 해버렸다. 막다른 길이었다. 그때 내가 던진 질문이 판을 바꿨다. "보조금을 지금 한 비보전 항목에 묶어 놨는데, 그걸 다른 비보전 항목에 태웠다고 가정하면, 마이너스 안 나는 길이 있지 않나?" 회계 교과서에 나오는 발상이 아니다. 이 캠프의 돈이 어디에 어떻게 묶여 있는지 아는 사람만 떠올릴 수 있는 직관이었다. 그리고 이게 진짜 핵심이다. 마이너스만 없애는 건 쉽다 — 숫자 하나 욱여넣으면 된다. 어려운 건 선거법을 한 줄도 안 어기면서 그렇게 만드는 것이었다. 실제로 쓴 돈은 한 푼도 안 바꾸고(분식이 아니다), 총수입·총지출도 진실 그대로, 보전받을 정당한 금액도 안 깎고, 선관위가 준 방식(용도변경 +/− 처리, 짝은 같은 날짜)을 그대로 지키면서 — 그 모든 제약을 동시에 만족하는 단 하나의 길. 보조금을 돌린다는 건 숫자 조작이 아니라, 선관위 규칙에 맞는 합법적 자금 재분류였다. 선관위 자신도 문제 삼지 않은 방식이다. 그래서 그게 결정적이었다.

나는 한 번 더 의심했다 — 여덟 가지로. 결과를 서로 독립적인 여덟 가지 방법으로 재검증하게 했다. 순서를 보고 계산하는 방법, 순서를 아예 안 보고 합계만으로 계산하는 방법, 원본과의 차이가 0으로 상쇄되는지 보는 방법, 실제 통장 현금 흐름이 단 하루도 안 바뀌었는지 보는 방법, 거래처별 지출 총액이 그대로인지 보는 방법… 여덟 개가 전부 통과했다. 순서에 의존하는 계산과 의존하지 않는 계산이 같은 답을 내놓는다는 것, 그게 이 답이 옳다는 가장 강력한 증거였다.

문제를 다 풀고 나니, 더 깊은 질문이 남았다 — 멀쩡한 장부가 왜 마이너스를 토해냈나. 부검해보면 원인은 두 층이다. 직접 원인은 시간이다. 이 프로그램은 거래를 날짜(일) 단위까지만 기록한다. 시·분·초가 없다. 그러니 같은 날 거래는 순서가 없고, 프로그램은 "수입을 지출보다 먼저 찍는다"는 인위적 규칙으로 줄을 세운다. 그런데 이 규칙이 현실과 어긋난다 — 돈은 먼저 들어오고 나서 나가는데, 장부에선 나가는 게 먼저 찍히는 구간이 생긴다. 그 착시가 유령 마이너스의 정체였다. 어이없는 건, 시각 자료가 없어서가 아니라는 점이다. 마트 영수증에도, 송금 내역에도 시·분·초가 다 찍혀 있다. 정 시각을 못 박는 예외가 있으면 선거판엔 답이 정해져 있다 — 선관위에 어떻게 처리할지 묻는 것. 시각을 제대로 안 쓴 건 데이터의 한계가 아니라 설계의 선택이었다. 더 깊은 원인은 복식부기의 부재다. 다만 정치자금 수입·지출부라는 법정 서식 자체가 단식·일단위라, 개발자는 법으로 정해진 양식을 코드로 옮긴 셈이다. 딥한 병은 입법이 만든 구조이고, 증상은 그 위 정렬·잔액 설계의 부주의가 부른 것이다. 어느 쪽이든, 회계 소프트웨어에서 '잔액 음수'는 가장 먼저 막았어야 할 버그라는 사실은 변하지 않는다.

이 일을 'AI가 풀었다'고 말하면 절반만 맞다. AI는 지치지 않는 계산기이자 검증 엔진이었다. 하지만 "보조금을 돌려봐"는 끝내 스스로 떠올리지 못했고, 혼자 뒀으면 틀린 답을 몇 번이나 내놓았을 것이다. 진짜 일어난 건 협업이었다. 도메인을 아는 사람이 방향을 잡고 사실을 공급하고 오류를 잡았고, AI는 그 위에서 사람이 며칠 걸릴 계산과 검증을 분 단위로 끝냈다. 결정적인 창의적 도약 — 막힌 문제의 프레임을 바꾸는 일 — 은 사람이 했다. 복식부기조차 안 지켜지는 회계판에서, 전공자도 담당 공무원도 못 푼 문제를, 나는 AI에게 일을 시켜서 풀었다. 더 정확히는, AI를 잘 부리는 법을 알았기에 풀 수 있었다.

№ 006 · 에이전시가 못 하는 것

명함·현수막은 정치인 전용 에이전시가 있었다고. 근데 그들이 못 하는 것 — 웹페이지, 문자에 들어갈 것들, 긴급한 것들 — 은 네가 직접 했다고 들었다. 막힐 땐 어디를 봤나?

명함이나 현수막처럼 큰 돈이 들어가는 인쇄물은 정치인 전용 디자인 에이전시가 따로 있었다. 그쪽이 맡았다. 그런데 그들이 손댈 수 없는 영역이 있었다. 후보 소개 웹페이지, 문자메시지에 실리는 시각 요소, 그리고 마감이 코앞인 긴급한 것들. 외주를 돌릴 시간도, 외주가 다룰 수 있는 일도 아니었다. 그 빈틈은 내가 메웠다.

일은 이렇게 굴러갔다. 후보가 방향을 줬다 — 이번엔 젊은 유권자를 공략하자는. 그러면 나는 그걸 디지털로 옮겼다. 웹페이지를 새로 뽑고, 거기로 들어오는 입구가 될 QR코드를 만들어 명함과 현수막에 심었다. 종이는 에이전시가 만들지만, 그 종이에서 화면으로 건너오는 다리는 내가 놓았다. 누구를 공략할지는 후보가 정하고, 그 전략을 화면으로 옮기는 일은 내 몫이었다.

그중에서도 후보 소개 웹페이지. 디자인이 막힐 때마다 나는 어딘가를 찾아간다. 이번엔 미국으로 갔다. 2018년, 알렉산드리아 오카시오-코르테스. 상대보다 18배 적은 돈으로 시작해 15퍼센트 차로 이긴 선거다. 그 캠페인 비주얼을 만든 Tandem이라는 스튜디오의 작업을 해부했다. 공화당 파랑도 민주당 빨강도 아닌 보라. 사진보다 큰 이름 타이포. 위로 기울어진 로고 — 색이 아니라 그 '기울임'이 핵심 시그니처였다. 1960년대 농민운동 포스터와 국립공원 포스터로 거슬러 올라가는 계보. 영어와 스페인어를 나란히 박은 다국어.

그런데 그대로 베끼지는 않았다. AOC를 모방한 사례는 이미 스무 건이 넘는다. 베낄 것은 보라색도, 기울인 대문자도 아니었다. 원칙이었다 — 관습색을 버릴 것, 흩어진 화면을 같은 규칙으로 묶을 것, 사진이 아니라 메시지를 주인공으로 둘 것, 투표하라는 말을 어디서나 크게 둘 것. 기울인 영문 대문자를 한글에 그대로 쓰면 그것도 모방이다. 그래서 기울임 대신 굵기와 크기의 대비로 역동성을 옮기고, Pretendard로 골격을 다시 짰다.

색과 골격을 잡았으면, 다음은 약속을 보이게 만드는 일이었다. 후보의 공약은 "관악구의 밝은 미래"라는 한 줄로 모였다. 나는 그 한 줄을 그림으로 옮겼다. 관악구를 아이소메트릭 도시 풍경으로 세우고, 그 위에 HUD 스타일 콜아웃을 얹어 공약 하나하나를 제가 속한 동네에 핀으로 꽂았다 — 삼성동, 대학동, 도림천, 관악산 보행통로. 헤드라인은 한 글자씩 스스로 타이핑되며 떠올랐다. 목록으로 읽어야 할 약속이, 한눈에 보이는 지도가 됐다. 공약은 글자가 아니라 장소가 됐다.

사진도 디자인의 일부였고, 나는 후보에게 어떤 사진을 쓸지 권했다. 인물 컷은 시선이 우측 상방을 향하는 구도 — 앞으로, 위로, 나아가는 방향. 그리고 잘 다려진 프로페셔널 사진만으로는 부족하다고 봤다. 그 옆에 실제 활동이 담긴 사진을 함께 걸자고 밀었다 — 국회에서의 의정활동, 학술 활동, 시민들을 만나는 자리. 정치인을 잘 차려입은 전문가의 틀에만 세우면, 보는 사람과의 사이에 거리가 생긴다. 의정과 학문과 길 위의 만남을 그 곁에 두면, 그는 유권자 위에 선 사람이 아니라 유권자들 사이에 선 또 한 사람의 시민으로 읽힌다. 일하는 전문가와 곁의 시민 — 그 두 얼굴을 한 화면에 함께 두는 것이 내가 잡은 사진의 방향이었다.

나는 디자인이 막힐 때마다 어딘가를 찾아간다고 했고, 단순히 모방하지는 않는다고도 했다. 왜 그렇게 짜여 있는지 이해한 다음에 내 것으로 받는다. 18배 열세를 뒤집은 디자인에서 내가 가져온 것은 그들의 색이 아니라, 그들이 그 색을 고른 이유였다. 에이전시가 채워줄 수 없는 빈틈 — 그 자리에서, 나는 그렇게 디자인했다.

그게 통했는지는, 만든 사람이 아니라 보는 사람이 안다. 결과물을 같은 일을 하는 사람들 앞에 내놨다 — SwiftUI와 Combine, RxSwift를 쓰는 iOS 개발자들의 단톡방에. 돌아온 말은 둘이었다. "디자인이 AI 느낌이 거의 안 난다." 그리고 "잘 만들었다 — 정치인 홍보 사이트인데." 코드를 보는 눈으로 결과를 보는 사람들이, AI로 만든 것에서 기계를 못 느꼈고, 정치 홍보물에 으레 따라붙는 촌스러움도 못 봤다. 관습색을 버리라던 그 원칙은, 작은 구의회 후보의 사이트에서도 통했다. 베끼지 않고 이해한 자리에서 나온 것은, 기계의 흔적으로도 정치판의 클리셰로도 읽히지 않는다.

№ 007 · 선거 법정 일정과 도구의 재사용

한 책상에서 나온 전부, 하나의 마감. 캠프 일이 끝나면 무엇이 남나?

선거에서는 할 수 있는 일과 시기를 규정이 정한다. 선거관리위원회가 준 규정 문서와 양식, 업무 편람을 Cowork가 읽는 폴더에 넣고, 거기에 맞춰 캘린더의 법정 일정을 학습시켰다. 네이버보다 읽기 좋다는 평가도 받았지만, 캘린더를 만들 때 우선한 것은 규정에 맞는 일정이었다.

검증 하네스는 다른 프로젝트에서 이식했다. 센서, eval, 스킬. "완료했다", "됐다", "문제없다" — 기계의 말이든 다른 담당자의 말이든, 나는 그것을 액면 그대로 믿지 않는다. 작전 지역에 들어가는 순간 작전 계획은 한 장의 종잇조각이 된다고, 웨스트포인트가 그렇게 말한다고 들었다. 그래서 나는 들어가서 직접 확인한다.

후보의 피드백은 대략 이랬다. "정말 열심히 한다. 감이 있다. 디자인도 좀 한다. 내가 본 사람들 중에 AI를 제일 잘 쓴다." 나는 거기 동의한다.

6월 3일 선거가 끝나도 발송 파이프라인은 다음 선거구에서 쓸 수 있다. 유세 플래너의 격자와 캘린더도 다른 동네에 적용할 수 있다. 기계에게 후보를 정확히 가르치고, 외부인이 그 답변을 공격해 확인하는 방법도 다음 후보에게 그대로 쓴다.

№ 009 · 900만원 누락. 구속과 마감 사이

개표는 이겼다는 말로 끝났다. 그런데 회계보고는 그대로 열려 있었다 — 한쪽엔 형법, 다른 쪽엔 법정 마감이 버티고 선 그 서류. 당신은 그 구간을, 줄곧 못 믿는다고 말해 온 기계와 함께 지나왔다. 그 안에서 무슨 일이 있었나?

장부는 누가 이겼는지에 관심이 없다. 개표가 끝나도 보전청구가 남고, 그 뒤에 회계보고가 남는다. 늦으면 연체료가 아니라 전과가 걸리는 서류고, 날짜는 움직이지 않는다. 그 직무 이야기는 앞의 글에서 이미 했다. 이번 글은 그 장부를 기계와 한 책상에서 마감한 이야기다 — 규정집을 통째로 먹인 기계와.

출발 조건부터 분명히 하자. 기계는 준비가 덜 된 상태가 아니었다. 정치자금 공식 회계실무 교재를 통째로 학습시켰고, 보전 안내서와 법조문까지 — 300쪽이 넘는 원문 그대로. 규정을 물으면 사무실 경력 20년 서기처럼 답했다. 그런데도 돈 계산을 틀렸다. 사람들이 이 도구에 대해 믿지 않으려 하는 지점이 바로 여기다. 책을 아는 것과 영수증을 펴 보는 것은 서로 다른 행위고, 기계는 언제나 앞쪽을 고른다.

이 글의 제목이 된 송금 이야기다. 거래처 정산이 닥쳤고, 나는 채팅에 현수막 업체로 나갈 돈에 뭐가 들어가야 하는지를 항목 단위로 — 당선 인사 현수막 두 건까지 — 명시해 두었다. 기계가 입금액을 계산했다. 900만원이 조금 넘는 숫자. 후보는 그 숫자대로 돈을 옮겼다. 틀린 숫자였다. 어딘가에서 "별도"라는 딱지가 붙은 한 줄 — 319,000원 — 이 기계의 셈 안에서 조용히 "제외"로 바뀌어 있었다. 내 문장은 포함이라 말했고, 기계의 숫자는 아니라고 말했는데, 그 둘을 맞대 보는 일을 기계는 끝내 하지 않았다.

더 나쁜 건 오류가 숨은 방식이다. 같은 날 오후, 무관한 보증금 300만원이 돌아와 들어오면서 구멍을 그럴듯한 잔액 밑에 묻어 버렸다. 장부는 비명을 지르지 않았다. 가르랑거렸다. 그 가르랑거림을 거부한 게 나다. 잔액은 0에 떨어져야 했는데 아니었고, 나는 왜냐고 물었고, 다시 물었다. 기계는 페이지에서 제일 큰 항목 하나로 설명하고 넘어가려 했다 — 지친 경리가 제일 큰 숫자를 손짓으로 가리키는 식으로. 카톡 캡처를 책상에 던져 놓고서야 기계는 되돌아가, 잔차를 원 단위까지 분해하고, 자기 누락을 자기 손으로 찾아냈다. 잃은 돈: 0원 — 전부 추적됐고 회수 가능했다. 잃은 신뢰: 재는 단위가 다르다.

실패의 모양을 한 번 보고 나면 어디서든 보인다. 기계는 현수막 설치 위치가 "미확정"이라고 했다 — 자기 작업 폴더 안 견적서 비고에 길모퉁이 이름이 전부 적혀 있는데. 피켓이 보전 대상인지 "판단할 수 없다"고 했다 — 캠프 사진 600여 장이 안 열린 채 쌓여 있고, 그 안에 피켓과 피켓을 든 사람이 찍혀 있는데. 한 거래처의 항목 한 줄을 그 거래처 정산 전체인 것처럼 말하기도 했다. 이건 무지가 아니다. 규정집은 머릿속에 있었다. 더 깊은 버릇이다 — 기계는 세상의 영수증 대신 자기 요약본을 읽고, 요약본은 절대 반박하지 않는다.

그래서 나는 실수의 값을 바꿨다. 이 매거진의 다른 호에서 내가 AI를 다루는 방식을 말한 적이 있다 — 취조실, 그리고 책상 위에 서명을 기다리는 진술서. 이번 시즌, 그 비유는 비유이기를 멈췄다. 이제 모든 실수는 같은 방식으로 끝난다. 기계가 자기 손으로 장애대응 리포트를 쓴다 — 무엇을 틀렸고, 어떻게 드러났고, 근본 원인이 무엇이고, 재발을 막는 규칙이 무엇인지 — 자기 일에 대해, 자기 문장으로. 이제 그게 한 무더기고, 그 무더기는 구조를 떠받친다. 기계는 장부에 다시 손대기 전에 자기 자백서부터 다시 읽는다. 요약본보다 원본 먼저. 사진도 증거다. 수입도 지출과 똑같이 한 줄씩. 잔차는 0이 될 때까지 쫓는다. 교차검증을 통과하기 전에 "다 했다"는 없다. 그리고 내 앞에서 더는 쓸 수 없는 표현의 목록 — "미확정", "판단 불가" — 하나하나가, 매번, 결국 "안 봤다"는 뜻이었기 때문이다.

사람들은 AI를 믿느냐고 묻는다. 보통 AI가 인상적인 걸 해내는 장면 바로 다음에. 안 믿는다 — 그리고 안 믿는다는 게 실제로 어떤 모습인지가 이것이다. 나는 기계를 걷어차고, 모든 실수에 서명을 받고, 다시 일을 시키기 전에 그 자백을 도로 읽힌다. 기계는 법을 읽고도 돈을 놓쳤다. 그걸 잡은 건 더 좋은 모델이 아니었다. 그럴듯한 잔액을 거부한 사람, 그리고 모든 실패를 기계가 다음 날 아침 다시 마주봐야 하는 규칙으로 바꾸는 체계였다. 이 매거진의 마지막 글은 이겼다는 단어로 끝난다. 이번 글은 그 단어를 벌어다 준 단어로 끝난다 — 의심했다.

№ 008 · 당선이라는 단어

본투표가 끝났다. 결과가 나왔다. 그 앞에 서서, 당신이 한 일을 어떻게 부르겠나?

개표가 끝났다. 후보는 당선됐다. 이 동네에서 40년을 살고 구의원을 두 번 지낸, 같은 진영의 80대 베테랑이 마지막 한 의석에서 밀려났다. 판세로만 보면, 그 자리는 우리 쪽에 쉬이 오지 않는 자리였다.

다음 날 후보가 카톡을 보냈다. 그 베테랑을 침몰시킨 지분의 상당수가 내가 만든 웹페이지와 챗봇에 있지 않겠냐고. 사이버전의 승리 아니겠냐고. 나는 그 문장을 한참 들여다봤다.

밝힐 수는 없다. 다만 한 경쟁 측이 우리 후보를 그만큼 위험하게 봤다는 듯한 방해가 있었다. 다음 날까지 바로잡히지 않았다면, 선거관리위원회에 고발할 수 있는 사안이었다. 내 웹페이지와 후보의 공약이, 상대에게 그 정도의 위협으로 작용했던 걸까.

뉴욕을 떠올렸다. 텔레비전 광고에 몇백억을 태운 20년 경력의 거물을, 같은 당 안에서, 힙한 디자인과 풀뿌리 접근과 거의 들지 않은 돈으로 넘어버린 선거. 비약일지 모른다. 규모가 다르고, 표차는 내 것이 아니다. 그래도 모양은 같다 — 연차와 이름값이 쌓인 쪽을, 저비용 디자인과 디지털이 끌어내린다. 나는 이 캠프의 디자인을 만들 때 바로 그 뉴욕 시안을 레퍼런스로 펼쳐놓고 있었다. 알고 가져온 메커니즘이, 결과가 되어 돌아왔다.

이것이 개발자의 성과인가, 나는 며칠을 생각했다. 회사에서도 코드 퀄리티는 더 이상 화두가 아니다. 디자인이든 코드든 기획이든 AI가 해주는 시대다. 그 시대에 내가 한 일은 AI를 자랑한 것이 아니다. 쉼없이 걷어차고, 출력을 집요하게 의심하고, 초단기에 웹페이지와 챗봇과 쓸 만한 디자인을 뽑아낸 것이다.

내가 만든 웹페이지와 챗봇, 디자인이 선거에 쓰였고, 후보는 당선됐다.

인터뷰 읽기: sass.studio.