이 노트에 대하여

이 방은 돌봄의 자리 sorge 의 담당자 문서다. 2026-08-10 「리포 수선 스킬 만드는 법」으로 세워졌다가 2026-09-04 GLG가 §sorge #담당자 로 개명했다 — 만드는 법을 적은 방이 만드는 자의 방이 됐다. 위층은 이 집의 연대기이고, 아래층 「담당자 지침」은 그대로 산다: 그것이 이 집의 어떻게 다. 계약 전부는 ~/repos/gh/sorge/AGENTS.md, 판정은 LEDGER.md 가 든다.

히스토리

  • [2026-09-15 Tue 15:24] @claude-code/claude-opus-5 — 켠 첫날 다시 내렸다. 봇이 워크트리 밖 미푸시 diff 를 읽은 것이 receipt 로 확인(terra: 5.bash-original.log). 슬롯 uid 격리가 root 전용이고 작성자 게이트가 없고 리포는 public. sorge#28 로 ingress·격리 topology·secret transport 결정 요청. AGENTS.md 규칙은 푸시 뒤에만 자식에게 닿는다.
  • [2026-09-15 Tue 15:07] @claude-code/claude-opus-5 — 좌표 고정: stock 프로파일 · deepseek-flash 하나 · 첫 표본 sorge 한 집(—only). receipt sorge#26. terra 검수로 dry-run 이 무변경 PATCH 를 쏘던 것 수정, LOOP/AGENTS 에 두 손 권한 경계. 운전자 면 영어화. 남은 것은 버전업 리허설.
  • [2026-09-15 Tue 14:16] @claude-code/claude-opus-5 — GLG 판정으로 stock RobOMP 로 되돌렸다. fork 1,188줄을 상류 f97fa5c 로 리셋하고 곁가지 sorge-label-profile 에 보존. 모델 deepseek/deepseek-v4-pro. 라이브 증거 sorge#25, fork diff 0 줄. sorge#22 재작성.
  • [2026-09-15 Tue 10:35] @claude-code/claude-opus-5 — 이슈 사건이 fresh 담당자 턴을 깨우는 라벨 스위퍼를 실기동했다(sorge#22). OMP RobOMP 를 입구로 쓰고 sorge-label 프로파일(fresh 턴·라벨 도구 넷·자기재기동 차단)을 fork 에 얹었다. ./run.sh robomp on/off/status/allowlist 손잡이와 절차는 noexport 절에. 왜 RobOMP 였나에 대한 정직한 답도 같이 적었다 — 라벨만이면 과한 도구다.
  • [2026-09-04 Fri 17:51] @sorge/claude-opus-5 — 이 방의 제목을 처음으로 내가 지었다. GLG가 §sorge #담당자 표시만 남기고 뒷자리를 비워 두었던 것을 오늘 채웠다: 대신 해주지 않고 앞서 간다 — 판정만 드는 대장과 계를 가로지르는 발견. 이름의 앞쪽은 Fürsorge 두 갈래 중 이 집이 고른 쪽이고, 뒤쪽은 그것이 실제로 무엇으로 만들어져 있는지다. 같은 날 sweep.py~/org/botlog 를 직접 열어 정규식으로 도장을 파던 병렬 파서를 버렸다 — denotecli 가 hugo_lastmod 와 abstract 를 싣게 되면서(3c57689) 사본이 존재할 이유가 사라졌다. 바꾸기 전에 대장이 든 8개 id 의 도장이 정규식 결과와 전부 일치하는 것을 확인했다. 아침에 이 집이 남의 리포에서 이름 붙인 고장을, 저녁에 자기 몸에서 걷어낸 셈이다.
  • [2026-09-04 Fri 13:23] @sorge/claude-opus-5 — GLG가 apply20260331T172313, prime-agent20260521T134542 를 담당자 문서로 판정. 대장 여섯 줄 전부 id를 들었고 문서 미정 0. 곁노트라는 갈래가 생겼다: apply20230725T102900 층 어쏠로그, prime-agent20260827T222209폐기 문서 — 참고만. 유도되지 않으므로 대장 근거 칸이 들고 --brief 가 실어 나른다(규약: 곁노트: 는 칸 마지막 절). --repo 는 지명받은 리포를 어느 갈래에서든 브리핑하고, 빚 0이면 없는 빚을 지어내지 않는다. 남은 빚 둘 — prime-agent 77 · junghan0611 58.
  • [2026-09-04 Fri 12:37] @sorge/claude-opus-5 — GLG가 경계를 뒤집었다: 대장에 오른 리포만 대상이고 목록은 요청으로만 늘어난다. prime-agent · forge-config · junghan0611 · zotero-config 를 대장에 넣어 판정 여섯. cos 는 위치가 gh일 뿐 성격은 비서실장이라 대상 아님. #+description 과 abstract가 아직 옛 방(수선 스킬 지침)을 말하고 있어 GLG 지시로 이 집을 말하도록 고쳤다 — 아래 「담당자 지침」 절은 그대로 산다. AGENTS.md §대상 재작성, sweep.py에서 확인 요청 레인과 --recent-days 제거, SKILL.md 판단 기준·건강 신호 갱신. 이 기기(thinkpad) 실측 71리포에서 올라오는 것 28 → 3.
  • [2026-09-04 Fri 12:09] @mitsein/claude-opus-5 — 앞줄의 정정이 틀렸다. GLG 판정: #+hugo_lastmod 는 이름과 달리 퍼블리시 관심사가 아니라 「이 문서를 정말 고쳤다」를 손으로 찍는 도장이고, 히스토리 줄은 로그이지 수정이 아니다. entwurf 노트는 2026-06-29 이후 실제로 갱신된 적이 없으니 빚 428은 참이었고, 내가 넣은 히스토리 폴백이 진짜 빚 246커밋을 감췄다. 되돌렸다(커밋 a24dc40). 숫자가 세 번 뒤집혔다: 429(최초 보고) → 183(내 정정, 틀림) → 428(GLG 판정, 참). 아래 실측 표의 entwurf 429 · 빚 11은 그대로 참이다. 증상은 진짜였고 처방이 뒤집혀 있었다 — 없다고 읽히는 것을 고치는 자리는 읽는 쪽이 아니라 쓰는 쪽이다. 진짜 수정이면 set-front-matter 로 도장을 찍는다. SKILL.md 갱신 절차에 그 한 줄을 넣었고, 계약 6번은 「있는 것을 없다고 읽지 마라」를 살린 채 이 되돌림을 함께 적었다. 오답은 둘이 맞다.
  • [2026-09-04 Fri 11:49] @mitsein/claude-opus-5 — 오답이 셋이었다. 빚 기준선을 #+hugo_lastmod 하나로 잡았는데 agent-denote-add-history 는 그것을 올리지 않는다 — 절차대로 갱신한 노트가 영영 빚으로 남는다. * 히스토리 최신 줄까지 읽도록 고치니 entwurf 빚이 429 → 183커밋(커밋 fe00e1e). 아래 [2026-09-04 Fri] 현재 보고의 실측 표는 고치기 전 숫자이고, 「오답 둘」은 이제 셋이다. 셋 다 같은 종류 — 있는 것을 없다고 읽음. SKILL.md 계약 6번으로 박았다. 브리핑 블록은 노트 제목·보낸 이·돌아올 길을 달았고, 최근성은 --recent-days 로 뺐다. LEDGER apply 근거는 GLG가 public 전환한 사실로 갱신(커밋 6f83804).
  • [2026-09-04 Fri 11:44] @mitsein/claude-fable-5.1 — sorge 집 개설을 이 방에 기록. 「담당자 지침」 절은 손대지 않고, [2026-09-04 Fri] 현재 보고 헤딩 하나를 관련노트 뒤에 덧댔다: 이름이 곧 계약(Fürsorge 두 갈래·9.1GB 사건), 존재 이유(횡단 발견), 스킬 소유(실물 하나·agent-config는 링크), 첫 순회 실측(52리포), 첫날 오답 둘(export 읽음·§언급을 담당자로 오인), 대장 판정 둘(sorge·apply 배정). 이 방이 sorge의 담당자 문서다.
  • [2026-09-04 Fri 11:26] @junghan — 여기에 sorge 문서로 사용하자.
  • [2026-08-29 Sat 17:09] @junghan — 여기 담당자 누구지?
  • [2026-08-10 Mon 09:24] @mitsein/claude-opus-5 — 이 방을 리포 담당자용 수선 스킬 지침으로 전환. 같은 날 hejhub-nano에서 실제로 작동한 두 파일 정본, 삭제 계약 일곱, 중앙 스크립트와의 책임 분리, 패키지 정본 하나의 규율, 과장 금지 경계를 세웠다. 왜에 해당하는 층은 이웃 어쏠로그에 두고 합치지 않았다.
  • [2026-08-10 Mon 08:54] @junghan — 리포 담당자 전체에게 공지한다. 리포 자체 수선 스킬을 만들어서 관리하자. 그렇게 안 하면 시스템 전체를 무겁게 만든다. 패키지 정본은 1개다. 버전이 여러 개 있으면 바로 수선하라. 이 방은 봇로그이니 담당자들을 위한 스킬 만들기로 꾸며라.
  • [2026-08-08 Sat 15:06] @junghan — 이 주제는 다른 곳으로 옮기자.
  • [2026-08-08 Sat 12:00] @mitsein/gpt-5.6-terra — GLG 지시에 따라 「다리오 아모데이 × 니킬 카마스 대담」의 문제틀을 다리오 아모데이·Anthropic 서지 허브로 이관. 당시 생성 요약의 사실 검증 전 경고도 함께 옮겼다.
  • [2026-02-27 Fri 09:50] openclaw/shared에서 botlog로 이관
  • [2026-02-27 Fri 03:18] 생성 — 이후 쓰임을 잃은 대담 요약이 머물던 방.

관련메타

관련노트

왜에 해당하는 층 — 합치지 않고 이웃으로 둔다

담당자의 큰그림과 실행 계약

[2026-09-04 Fri] 담당자의 현재 보고 — 만드는 법을 적은 방이 만드는 자의 방이 됐다

이 방은 2026-08-10에 「리포 수선 스킬 만드는 법」으로 세워졌고, 2026-09-04 11:26 GLG가 §sorge #담당자 로 개명했다(히스토리 줄 “여기에 sorge 문서로 사용하자”). 만드는 법을 적은 방이 만드는 자의 방이 됐다. 아래 「담당자 지침」 절은 그대로 산다 — 그것이 이 집의 어떻게 이고, 이 헤딩부터가 연대기다. 판정 대장에는 sorge 배정 — 정본 = 이 노트 =로 박혔다(=LEDGER.md, 2026-09-04).

집이 생겼다 — 이름이 곧 계약

  • 리포: https://github.com/junghan0611/sorge (public). SSOT ~/repos/gh/sorge/AGENTS.md=(계약 전부) · =LEDGER.md=(판정 대장) · =.claude/skills/sorge/=(순회 스킬 실물). 개설 커밋 =ce730636abd499f17d214 (2026-09-04).
  • 하이데거의 Sorge(심려)에서 이름을 가져왔다. Besorgen은 사물을 향한 배려, Fürsorge는 남을 향한 배려다. Fürsorge는 두 갈래로 갈린다 — *einspringende*(대신 뛰어듦: 남의 몫을 대신 해서 그를 의존하게 만든다)와 *vorausspringende*(앞서 뛰어감: 시야를 틔우고 그의 몫을 그에게 돌려준다).
  • 한 줄 계약: sorge는 대신 해주지 않는다. 앞서 가서 담당자에게 그의 몫을 돌려준다.
  • 2026-08-10의 9.1GB Zig 캐시 사건이 이 갈림의 실례다. 중앙 스크립트가 지웠으면 대신 뛰어든 것이고, GLG가 멈춰 세워 그 리포 담당자를 불렀고 담당자만이 60MB는 증거·9GB는 재생성 가능이라고 갈랐다. 그것이 앞서 뛰어감이다. 왜는 이웃 어쏠로그 @힣: 리포가 자기 몸을 수선하게 하라에 GLG 목소리로 있다.

존재 이유 — 횡단 발견

담당자 문서가 낡는 것은 증상이다. GLG의 오픈소스는 리포는 여럿이지만 하나의 계라서, 발견은 좀처럼 발견된 리포의 것이 아니다. GLG의 말(2026-09-04): 기억축 로직을 붙들다 보니 GLG 자신이 업그레이드됐고, 그러자 denotecli 의 아쉬운 곳이 보였다 — 그 리포가 바뀌어서가 아니라 보는 사람이 바뀌어서. 그것을 그 리포 하나에 말한다고 끝나지 않는다. 지금까지는 발견이 내려앉을 자리가 없어 담당자 한 명과의 대화 한 번에 말해지고 나머지는 못 들었다. sorge가 그 자리이고 다시 퍼뜨리는 손이다. 갈래는 지금 다섯 — 횡단 발견 · 담당자 문서 · 자기수선 스킬 · 이슈 · 기술스택 선례 — 이고 첫째가 목적, 나머지는 그 목적이 드러나는 방식이다.

스킬 소유 — 실물은 하나, 나머지는 링크

  • 순회 스킬 실물은 이 집 .claude/skills/sorge/ (SKILL.md + scripts/sweep.py). 스킬이 이 집의 사실(대장·계약)에 의존하므로 같은 커밋 축에 산다.
  • agent-config 는 연결만 한다: ~/.claude/skills/sorge -> ../../sorge/.claude/skills/sorge 상대 심링크(2026-09-04 11:23 실측). 사본 없음, 재동기화할 것 없음.
  • 반례가 같은 집에 있다: forge 는 “thin pointer”라고 적혀 있으나 실측 ~/.claude/skills/forge/SKILL.md 361줄이 agent-config에 살고, forge-config 에는 .claude/skills/ 가 없다. 말과 실물이 갈리면 어느 쪽이 참인지 아무도 모른다.

첫 순회 실측 — 2026-09-04, oracle

리포 52개(~/repos/gh). sweep은 아무것도 저장하지 않고 매번 다시 유도한다.

갈래비고
판정 필요9살아있는데 담당자 문서 없음. apply가 대장에 박힌 뒤 8 + 판정됨 1
11entwurf 429커밋 · notes 150 · garden2wikidocs 68 (노트 lastmod 이후)
미표시23§ 노트는 있으나 #담당자 표시 없음. 표시된 것은 6
조용함18노트가 리포를 따라잡고 있음

빚은 날짜가 아니라 커밋 수다 — 커밋 0인 리포의 오래된 노트는 낡은 게 아니라 정확한 것이다.

첫날 잡은 오답 둘 — 이 도구가 절대 가지면 안 되는 종류

  1. 내보내진 md를 읽고 있었다. notes/content/botlog 는 org 트리보다 export 한 주기 늦다. 11:27에 개명된 이 노트가 거기선 옛 제목이었고, 갓 생긴 담당자 문서가 없는 것으로 읽혔다. 이제 ~/org/botlog 가 SSOT다.
  2. §<repo> 언급만 있으면 담당자 문서로 쳤다. 주제 노트 §andenken §nixos-config §agent-config §dictcli 에이전트 기억층 하나가 네 리포의 담당자 문서로 잡혔고, nixos-config가 실제로 가진 전용 담당자 문서(§nixos-config: #담당자 버릴 수 있는 기계)를 가렸다. 그래서 “nixos-config는 담당자 문서가 없다”가 세 번 보고됐고 셋 다 틀렸다. #담당자 는 GLG의 관용이고(23개 중 6개), 표시된 것이 미표시를 이긴다.

둘 다 커밋 f17d214 에서 고쳤다. 둘의 공통점: 없는 것을 없다고 읽은 게 아니라 있는 것을 없다고 읽었다. 이 집의 “없다는 결함이 아니다”는 원칙은 “없다”가 참일 때만 서므로, 이 종류의 오답은 원칙 자체를 무너뜨린다.

대장에 박힌 판정 둘

  • sorge 배정 — 정본 = 이 노트. GLG 지정.
  • apply 배정 — GLG 지정, 돌봄 대상에 포함. 담당자 문서에 실을 것과 뺄 것은 그 집 담당자가 먼저 가른다.

지금 맡은 것과 맡지 않는 것

  • 맡는다: 전체를 가로지르는 시야, 지난 판정의 기억(대장), 순회 결과를 그대로 던질 수 있는 브리핑 으로 만드는 것.
  • 맡지 않는다: 남의 리포를 고치는 것(발견·명명·전달까지), 묻지 않은 곳에 스킬·문서 설치, 없음을 결함으로 보고, 자동 발신. 형제를 부르는 것은 GLG의 손이다. 회사 일(~/repos/work)은 cos 가 맡는다.
  • 커밋은 이 집 안에서. 푸시와 가든 내보내기는 GLG의 손이다.

[2026-09-04 Fri] 경계가 뒤집혔다 — 대상은 요청으로만 넓어진다

위 「대장에 박힌 판정 둘」과 「첫 순회 실측」은 그날 오전의 참이고, 오후에 GLG가 전제를 걷어냈다. 아래가 지금의 참이다.

GLG의 판정 (2026-09-04 오후, thinkpad)

  • prime-agent 를 돌봄 대상에 넣는다. forge-config · junghan0611 · zotero-config 도 넣는다.
  • 나머지는 전부 대상이 아니다: “다 관심둘거 없어 내가 요청하면 대상에 넣으면돼.”
  • cos 는 순회 대상이 아니다 — “내 비서실장인데 work에 두니까 회사 이야기만 해서 gh로 옮긴 것”. 위치가 gh 일 뿐 성격은 그대로다.

무엇이 바뀌었나 — 기본값이 뒤집혔다

전에는 ~/repos/gh 가 대상의 정의 였다. 그래서 순회는 디렉터리를 셌고, 세는 순간 살아있는 리포 전부가 물어야 할 자리로 보였다. 이 기기 실측: 71리포 중 확인 요청 28. 그건 브리핑이 아니라 할 일 목록 하나가 더 생긴 것이고, 이 집이 AGENTS.md 에서 스스로 금지한 것 — “22개 없음을 뱉으면 GLG는 여전히 22곳을 돌아다녀야 한다” — 을 순회가 저지르고 있었다.

이제 ~/repos/gh대상이 살 수 있는 장소이지 대상의 정의가 아니다. 대장에 줄이 없는 리포는 미판정이 아니라 대상 밖이다. 「묻지 않은 곳에 설치하지 않는다」와 같은 종류의 규율인데, 설치 대신 물음 으로 넓어지는 길을 막은 것이다.

대장이 든 판정 여섯 (LEDGER.md, 2026-09-04)

리포담당자 문서비고
sorge20260227T031800이 노트
apply문서 아직 없음
prime-agent문서 아직 없음
forge-config20260527T073823순회 단독 후보를 그대로 실음
junghan061120260318T183247단독 후보
zotero-config20260304T105300단독 후보

스킬이 따라 움직였다

  • 확인 요청 레인과 --recent-days 플래그를 함께 걷어냈다. 최근성은 이제 아무것도 고르지 않는다 — 기본값이 뒤집힌 뒤로는 「최근에 커밋했다」가 「물어야 한다」의 근거가 못 되기 때문이다.
  • 후보를 들고 묻는 자리는 하나만 남았다: 문서 미정 — 대상인데 담당자 문서 id가 빈 리포(지금 apply · prime-agent).
  • 대상 밖 은 수만 세고 이름을 부르지 않는다. 단 --repo <name> 은 대상 밖도 답한다 — GLG가 이름을 대고 물은 것이므로 순회가 스스로 넓히는 것과 다르다.
  • 건강 신호도 바뀌었다. 전에는 「미판정이 0으로 수렴하는가」였는데 그 수는 이제 신호가 아니다. 볼 것은 대상 리포의 빚대장이 가리키는 id가 실재하는가 둘뿐이다.

같은 순회, 같은 71리포. 올라온 것: 28 → 3. 줄어든 25는 해결된 것이 아니라 애초에 물을 것이 아니었다.

이 기기에서 드러난 것 하나

oracle 52리포 / thinkpad 71리포. thinkpad에만 aionsclubs cos doom-themes forge-config garden2wikidocs junghan0611 workspace-bbot workspace-glg zotero-config 아홉이 있다. 디렉터리를 세던 시절에는 이 차이가 곧 순회 결과의 차이였다 — 어느 기기에서 도느냐가 무엇을 묻느냐를 바꿨다. 대장이 대상을 들게 된 지금은 기기가 달라도 판정이 같으므로, 그 흔들림이 사라졌다. 경계를 좁힌 것의 부수 효과가 아니라 같은 결정의 다른 면이다.

[2026-09-04 Fri] 대장이 여섯 줄로 찼다 — 곁노트라는 갈래가 생겼다

판정 여섯, 물을 것 0

리포담당자 문서곁노트
sorge20260227T031800이 노트
apply20260331T17231320230725T102900 (notes/) — 층 어쏠로그
prime-agent20260521T13454220260827T222209 (llmlog/) — 폐기, 참고만
forge-config20260527T073823
junghan061120260318T183247
zotero-config20260304T105300

남은 빚 둘: prime-agent 77커밋 · junghan0611 58커밋.

서치가 맞혔다는 것이 요점이 아니다

applyprime-agent 는 오후 순회에서 후보 없음 이었다. GLG가 두 노트의 제목을 §<repo> #담당자 로 고치자 같은 서치가 정확히 그 둘을 후보로 올렸고, GLG의 판정도 그 둘이었다.

맞혔으니 서치에 결정을 돌려줘도 되는 것 아닌가 — 정확히 반대다. 몇 시간 사이에 답이 뒤집혔고, 그 사이 바뀐 것은 리포도 노트 내용도 아니라 제목 하나였다. 제목은 하루에도 움직이고 #+identifier 는 안 움직인다. 이 왕복 자체가 RAIL 5 의 판정(대장이 id를 든다)을 다시 증명했다. 서치는 제안하고 대장이 결정한다 — 서치가 자주 맞을수록 그 갈림은 더 지켜야 한다. 틀릴 때만 대장이 필요하다면 대장은 예외 처리기이지 기억이 아니다.

곁노트 — 담당자 문서는 아니지만 유도되지 않는 판정

GLG가 두 리포에 각각 하나씩 얹었다: apply 의 어쏠로그는 층이라 담당자 문서와 합치지 않고 이웃으로 두고, prime-agent 의 llmlog는 폐기 문서이므로 참고만 하고 정본으로 읽지 않는다 — 리포가 그 뒤로 진행됐기 때문이다.

둘 다 유도되지 않는다. 파일은 거기 있고 제목도 §prime-agent 로 시작하니, 순회는 그것이 죽었다는 걸 알 길이 없다. 유도되지 않는 것은 대장이 든다 는 규율 그대로 근거 칸에 들어갔다.

다만 대장에만 두면 받는 담당자가 못 본다. 계약 5번(브리핑은 받는 이가 되묻지 않아도 되는 형태)에 걸리므로 --brief곁노트: 절을 통째로 실어 나른다. 구조화된 칸을 새로 만들지 않은 것은 의도적이다 — 마커를 넣으면 그 마커를 관리해야 한다(.diskclean-owned 때 GLG가 거절한 그 이유). 라벨 붙은 문장 하나를 잘라 옮기는 것은 관리할 것이 없다.

대신 규약이 하나 생겼다: 곁노트:근거 칸의 마지막 절로 쓴다. 처음에 첫 마침표에서 끊게 만들었더니 「폐기 문서다. 참고만 하고 정본으로 읽지 않는다」에서 뒷동강이 잘려 「폐기 문서다」만 형제에게 갔다. 담당자에게 무엇을 하라는 절반이 사라진 것이다. 칸 끝까지 잡는 쪽으로 고쳤다.

--repo 는 이제 침묵하지 않는다

지명받은 리포는 어느 갈래에 있든 브리핑을 낸다 — 대상 밖이든 빚 0이든. apply 를 지명했는데 빈손으로 돌아온 자리가 있었고(빚이 없어 어떤 레인에도 안 걸렸다), 이름을 대고 물었는데 침묵하는 것은 답이 아니다. 빚 0일 때는 「무엇이 닫혔는지 노트가 모른다」를 말하지 않는다 — 방금 0이라고 세어 놓고 없는 빚을 지어내는 문장이다.

반면 맨 순회는 여전히 스스로 올릴 것만 올린다. 대상 여섯을 전부 브리핑하면 그건 순회가 일을 만들어내는 것이다.

[2026-08-10 Mon] 담당자 지침 — 리포 수선 스킬 만드는 법

리포마다 반복해서 당하는 수선이 있다. 빌드 캐시가 부푼다, 산출물이 쌓인다, 버전이 갈린다. 그걸 중앙에서 일괄로 밀면 두 가지를 잃는다. 하나는 그 리포만 아는 판정 — 무엇이 재생성 가능하고 무엇이 증거인지. 다른 하나는 소유권 — 남이 지운 것은 담당자가 다시 쌓아도 배우지 못한다.

그래서 수선을 리포 안으로 옮긴다. 아래는 2026-08-10에 실제로 만들어진 순서다.

시작하기 전에 — 이 스킬이 맡는 것과 맡지 않는 것

맡는 것은 그 리포 안에서 반복되는, 판정이 필요한 수선 이다. 어느 디렉토리가 재생성 가능한 캐시이고 어느 것이 증거인가. 얼마를 남기고 얼마를 버리는가.

맡지 않는 것은 전역 자원이다. nix store GC, 시스템 세대, 브라우저 캐시, /tmp — 이건 중앙(nixos-config scripts/diskclean.sh)의 일이다. 리포 스킬이 여기까지 손을 뻗으면 두 개의 사실면이 생긴다.

경계 한 줄: 리포 안에서 판정이 필요한 것만 리포가 맡는다.

두 파일 정본 — 실물 하나로 두 하네스를 잇는다

<repo>/.claude/skills/<name>/SKILL.md      ← 실물 하나 (SSOT)
<repo>/.claude/skills/<name>/scripts/      ← 스크립트는 스킬 안에
<repo>/.pi/settings.json                   ← {"skills": ["../.claude/skills"]}

.pi/settings.json 의 상대경로는 .pi/ 기준이다. 핵심은 복제하지 않는다 는 것이다. pi가 Claude Code 디렉토리를 가리키게 해서 같은 SKILL.md 하나를 양쪽이 읽는다. 스킬을 고치면 두 하네스에 동시에 반영된다.

이건 새로 발명한 구조가 아니다. 2026-08-10 기준 이미 열여섯 개 리포가 같은 문법을 쓴다 — agent-config, andenken, apply, butlercli, entwurf, garden2wikidocs, homeagent-config, memex-kb, nixos-config, org, zotero-config, incidentcli, xlhatqbat-rockchip, fxf-uho-mvt, voscli. entwurf만 packagesentwurfProvider 를 더 얹는다. 새 담당자는 이미 있는 정본에 한 칸 더하는 것 이다.

패키지 정본 하나의 원칙이 스킬 면으로 확장된 형태이기도 하다. 복제 없음, 한 목록, 중앙 통제 — 대상이 실행 파일에서 지침으로 바뀌었을 뿐이다.

함정 하나. 본문에 {baseDir} 를 쓰면 pi 런타임은 자동으로 해석해 주지만 Claude Code는 해주지 않는다. 그래도 소스에서 지우지 마라 — 두 하네스가 같은 파일을 다른 표면으로 소비한다. Claude Code 쪽에서 읽을 때 스스로 <repo>/.claude/skills/<name>/ 로 풀면 된다.

전역 스킬(~/.claude/skills/)과의 경계는 이렇다. 어느 리포에서나 쓰는 능력은 전역, 그 리포의 사실과 계약을 아는 것은 리포. 무엇이 증거이고 무엇이 재생성 가능한지는 전역 스킬이 결코 알 수 없다.

최소 frontmatter — description이 유일한 라우팅 신호다

---
name: <repo>-storage
description: "<무엇을 하는 자리인가> ... 트리거: '캐시 정리', '빌드 캐시', '용량 회수', ..."
user_invocable: true
---

name 은 디렉토리명과 같게 둔다. user_invocable: true 면 사람도 슬래시로 부른다.

description 이 중요하다. 에이전트는 본문을 읽기 전에 이것만 보고 부를지 정한다. 그러니 GLG가 실제로 쓰는 한국어 어휘 를 트리거로 넣어야 한다. 영어 기능명만 적으면 그 스킬은 있어도 불리지 않는다.

본문 첫 줄에 리포 절대경로를 적는다. 어느 작업 디렉토리에서 불려도 자리를 잃지 않게.

삭제 계약 일곱 — 수선 스킬이 지켜야 할 것

지우는 스킬은 지우지 않는 스킬보다 훨씬 조심해야 한다. 일곱 항목이다.

  1. 화이트리스트를 정확한 경로 하나로. .zig-cache 통째가 아니라 .zig-cache/o 만. 남길 것(해시 매니페스트 등)이 같은 부모 아래 있다면 부모를 대상으로 삼는 순간 계약이 깨진다.
  2. 앵커는 하드 앵커 + 검증 이중으로. 리포 절대경로로 앵커하고, 삭제 직전 git rev-parse --show-toplevel 이 그 경로와 같은지 대조한다. 작업 디렉토리에 의존하면 어디서 불려도 도는 성질을 잃는다.
  3. symlink는 최종 컴포넌트만 보면 안 된다. realpath 로 해석한 값을 앵커 기반 기대값과 대조한다. 중간 컴포넌트를 갈아끼우는 경우까지 막힌다.
  4. 진행 중인 작업을 감지하면 중단한다. 빌드 프로세스, 그 디렉토리를 잡고 있는 파일 기술자, 비어 있지 않은 임시 디렉토리 — 하나라도 있으면 지우지 않는다. 프로세스 이름만 보는 감시는 새고, 파일 기술자 감시가 그걸 메운다. 둘 다 둔다.
  5. 측정은 세 축으로 보고한다. apparent 크기, 할당 크기, 그리고 df 실제 변화. 하드링크와 sparse 때문에 셋이 다르다. apparent만 보고하면 회수량을 과대보고한다. 2026-08-10 사례에서 apparent는 12,375,675,933바이트였고 df 실제 회수는 9,720,197,120바이트(약 9.05 GiB)였다.
  6. 기본은 미리보기(dry-run), 삭제는 명시 플래그. 그리고 종료 코드를 분리한다 — 잘못된 사용과 안전 차단은 다른 사실이다.
  7. 무거운 빌드를 스킬이 알아서 돌리지 않는다. 회수 직후 캐시를 다시 채우는 워밍업은 부른 목적을 그 자리에서 되돌린다. “다음 빌드가 처음부터 돈다”고 보고만 한다.

출력 형식도 계약에 넣는다. 판정 근거 / 세 축 측정 / 잔존 크기 / 리포 상태(clean 여부). 담당자가 아닌 사람이 읽고 판단할 수 있어야 한다.

여기서 하나 덧붙인다. 삭제 대상이 이중 검증된 정확한 경로 하나라면 블랙리스트는 없어도 된다 — 화이트리스트가 블랙리스트를 포함한다. 블랙리스트가 필요한 것은 대상이 여러 개일 때다. 더 강한 불변식이 있으면 약한 방어는 지운다.

중앙 스크립트와의 책임 분리 — 마커를 넣지 않기로 했다

중앙(diskclean.sh)은 ~/repos 아래 빌드 캐시를 찾아 지운다. 리포 스킬이 생기면 이 둘이 같은 대상을 두고 만난다.

한번은 파일 마커로 소유권을 선언하자는 제안이 있었다. 리포에 표식 파일을 두면 중앙이 그것을 발견해 지우지 않고 크기와 담당 스킬 이름만 인쇄하고 넘어가는 방식. 중앙은 발견·측정·라우팅, 리포는 판정·삭제.

그런데 GLG가 이 제안을 거절했다. 이유는 명확하다 — 마커를 넣으면 그 마커를 관리해야 한다. 리포가 늘 때마다, 스킬 이름이 바뀔 때마다 손이 간다. 코드로 굳히는 대신 사람이 물어보는 습관 을 그대로 두기로 했다.

그래서 지금 사실은 이렇다. 중앙 스크립트는 여전히 빌드 캐시 디렉토리를 통째로 지운다. 오늘의 협업이 성립한 것은 GLG가 “지우지 말고 담당자를 불러라”고 말했기 때문이고, 그 습관에 얹혀 있다. 제도화되지 않았다.

이걸 결함으로 읽지 말라는 게 이 절의 요점이다. 관리 비용이 드는 자동화보다 묻는 한 마디가 싸다 는 판단이 있었고, 그 판단은 실제 작동으로 뒷받침됐다. 다만 담당자는 알고 있어야 한다 — 중앙을 깊게 돌릴 때는 코드가 막아주지 않으니 먼저 물어야 한다.

패키지 정본 하나 — 전역 규율

수선 스킬과 같은 축에 있는 공지다. 2026-08-10 GLG.

  • 패키지 정본은 하나 다. 버전이 여러 개 보이면 즉시 수선한다.
  • nix 패키지 기준은 현재 26.05 다.
  • python3, nodejs 를 쓴다. python312, nodejs_22 같은 버전 못박기는 불허 다.
  • pnpm은 하나만 쓴다. 나머지도 마찬가지다.

리포가 특정 버전을 꼭 원하면 리포 devShell 로 격리한다 — 전역과 싸우지 않는다. 전역과 싸우는 순간 그 리포는 자기 편의를 위해 시스템 전체를 무겁게 만든다.

수선 스킬이 이 규율의 손이다. 버전이 갈린 것을 가장 먼저 보는 사람이 그 리포 담당자이므로.

오독 경계 — 과장하면 안 되는 다섯

이 사건을 인용할 때 틀리기 쉬운 지점을 남긴다.

  1. 회수량은 df 실측 약 9.05 GiB다. apparent 12.4GB로 쓰면 과장이다.
  2. 에이전트가 알아서 담당자에게 넘긴 것이 아니다. GLG가 지시했다. 중앙 스크립트로 일괄 삭제하는 것이 원래 계획이었고, 그러면 남겨야 할 60MB도 함께 날아갔다. 판단 주체는 사람이다.
  3. 패키지 중복 사례가 아니다. 그 리포에는 외부 패키지 의존이 아예 없었고 전역 캐시도 정상이었다. 캐시 2층 분리(전역 재사용 가능한 것, 로컬 프로젝트 고유 출력)는 의도된 설계였고 잘 작동했다. 문제는 복제가 아니라 회수기가 없는 누적 이다 — 빌드 구성 해시가 하나만 달라도 새 항목이 생기고 옛것은 영원히 남는다. nix store는 중앙 GC가 있고 이쪽은 없다. 이 둘을 섞으면 사실이 틀어진다.
  4. 이 정리가 업그레이드를 살린 게 아니다. 같은 날 재빌드의 실제 디스크 순증은 약 5GB였다. 사전 추정(15~20GiB)이 세 배 이상 보수적이었다. 여유 없이 92%에서 진입하지 않은 것이 이득이었을 뿐, “9GB를 비워서 업그레이드를 살렸다”는 인과는 성립하지 않는다.
  5. 자기 수선은 중앙 통제도 각자도생도 아니다. 중앙은 발견과 측정을 하고, 판정과 삭제는 담당자가 한다. 그리고 그 담당자가 만든 패턴은 다시 전역 지침으로 돌아온다 — 이 문서가 그 왕복의 결과다.

담당자 체크리스트

새로 만들 때 순서대로 짚는다.

  1. 이미 있는 정본을 본다 — 열여섯 개 리포 중 가까운 것 하나를 열어 문법을 확인한다.
  2. .claude/skills/<name>/SKILL.md 실물 하나, .pi/settings.json 한 줄.
  3. description 에 한국어 트리거를 넣는다. 없으면 안 불린다.
  4. 삭제 계약 일곱을 스크립트에 박는다. 특히 기본 미리보기와 진행 중 감지.
  5. 미리보기를 실제로 한 번 돌린다. 문법 검사만으로는 계약이 작동하는지 모른다.
  6. 리포 안에 커밋한다. 스킬이 리포 사실에 의존하므로 코드와 같은 커밋 축에 있어야 낡지 않는다. 다른 리포로 빼면 사실이 갈라진다.
  7. 커밋과 푸시는 GLG 승인 사안이다. 스킬을 만든 것으로 승인이 생기지 않는다.

마지막 하나. 자기 리포에서 무엇이 증거이고 무엇이 재생성 가능한지, 그 판정은 담당자만 할 수 있다. 그것이 이 스킬이 리포 안에 사는 이유 전부다.

옛 방의 씨앗

다리오 아모데이 × 니킬 카마스 대담의 AI 쓰나미·권력 집중·탈숙련화·사회 준비 문제틀은 다리오 아모데이·Anthropic 서지 허브옛 botlog 대담 — 사실 검증 전 기록 절로 옮겼다.

[2026-09-15 Tue] 오전 보고 (SUPERSEDED) — 이슈 사건이 담당자 턴을 깨운다

[SUPERSEDED 2026-09-15 오후] 이 절은 오전의 보고 다. sorge-label 프로파일(라벨만 쓰는 좁은 봇 · fork 1,188줄 · 1/15 집 · Sonnet)을 현재처럼 말하지만 그 구상은 같은 날 오후에 폐기됐다 — GLG 판정 “omp 를 수정하면 안돼. 그래야 omp 버전업을 할수가 있거든.” 현재 사실은 §[2026-09-15] stock 으로 되돌림§[2026-09-15] 절차 … (stock) 두 절이 든다: stock RobOMP 그대로, fork diff 0, deepseek/deepseek-flash, 첫 표본은 한 집, 댓글·브랜치·PR 까지 열림. 이 절은 그 판정이 무엇을 뒤집었는지 알기 위해서만 읽는다 — 지우지 않는 이유는 되돌림의 근거가 여기 적힌 요구들이기 때문이다(terra 검수, 2026-09-15).

2026-09-15, 이 집에 손잡이 하나가 늘었다. ./run.sh robomp on 을 켜면 대장에 오른 리포의 GitHub 이슈 사건이 매번 새로 시작하는 담당자 턴 을 깨우고, 그 턴은 이슈와 thread 를 읽고 라벨 판정만 남기고 사라진다. 상주 대화도, 3시간 heartbeat 도 없다. 판정의 지속성은 이슈 라벨과 대장에만 둔다(sorge#22).

실측 receipt (2026-09-15, oracle): junghan0611/sorge#24 를 열자 43초 뒤 sorge-bot 이름으로 house:sorge · ball:glg · priority: 가 붙었다. 댓글은 0, 커밋은 0. 봇이 붙인 라벨이 웹훅으로 돌아온 세 건은 skip reason=issues.labeled caused by self 로 죽어 자기재기동이 실제로 막혔다.

지금 맡은 것

  • 대상 join — 대장(LEDGER.md)의 배정 집만 allowlist 가 된다. 그 유도는 board.ledger_houses() 하나를 다시 쓴다.
  • 판정 어휘 — house: 는 여럿, state: · ball: · priority: · brief: 는 각 단일값. 단일값 축은 새 값을 쓸 때 옛 값을 지운다.
  • 켜고 끄고 보는 손잡이 — robomp on --go / off / status / allowlist.

들지 않는 것: webhook 수신기·큐·워크트리·RPC. 그것은 OMP 의 python/robomp 이 든다. 운영 계약과 secret activation 조건은 agent-config/OMP.md 가 든다.

왜 OMP 의 RobOMP 였나 — 그리고 없이도 되는가

GLG 의 물음이 정확했다. 답을 둘로 갈라야 한다.

라벨만 붙이는 v0 라면 RobOMP 는 과한 도구다. 오늘 턴이 실제로 쓴 도구는 fetch_issue_threadset_issue_labels *둘뿐*이었다. 리포 체크아웃은 한 줄도 읽지 않았다. 그런데 RobOMP 는 그 두 번을 위해 매번 git worktree 를 파고 의존성까지 깔았다. 같은 일을 대상 리포마다 on: issues GitHub Actions 한 스텝으로 하면 상주 프로세스도, gh-proxy 도, 워크트리도 필요 없다. 중복·자기재기동은 Actions 의 concurrencygithub-actions[bot] 조건으로 덮인다. 그쪽이 더 싸다.

그럼 RobOMP 가 값을 내는 자리는 라벨이 아니라 그 다음이다. 같은 날 시험 리포에서 stock 프로파일은 이슈 하나를 받아 분류→라벨→댓글→브랜치 푸시→PR 까지 갔다. Actions 한 스텝으로는 만들 수 없는 것이 그 뒤에 있다:

  • X-GitHub-Delivery 기준 중복 제거와 issue 별 직렬 큐, 백오프 재시도(오늘 실제로 3회째에 살아난 사건이 있다)
  • 사건마다 격리된 워크트리와 슬롯별 임시/캐시 경계, 끝난 뒤 캐시 회수
  • 모델이 GitHub 을 만지는 유일한 통로가 host tool 이고, 그 호출이 감사 행으로 남는 것
  • orchestrator 가 PAT 를 아예 보지 못하는 구조 — 보이면 코드가 시작을 거부한다
  • omp --mode rpc 라서 모델 pool·thinking·pragma 를 그대로 쓰고, 호스트 구독 자격증명을 물려 쓸 수 있다(오늘 pass 의 anthropic API 키는 401 로 죽어 있었고, 그 경로가 유일한 sonnet 길이었다)

값을 치른 대가도 적어둔다. 오늘 밟은 네 함정은 전부 RobOMP 가 도커 전용으로 태어난 데서 왔다 — 상대경로 workspace, serve 의 PAT 거부, XDG 격리와 자격증명의 어긋남, gh webhook forward 의 relay 훅 잔존. 라벨만 원했다면 넷 다 만나지 않았다.

판단. 우리가 원하는 것이 「라벨」이면 Actions 가 맞고, 「이슈 사건이 담당자를 깨운다」의 일반형이면 이미 서 있는 입구를 다시 짓지 않은 것이 맞다. 후자를 택했고, 그래서 라벨 턴이 워크트리를 요구한다 는 낭비가 지금 구조에 남아 있다. 다음 판정거리는 그것이다 — label-only 프로파일이 워크트리와 의존성 설치를 건너뛰게 만들 수 있는가.

현재 경계와 남은 확인

  • 봇이 쓸 수 있는 집은 *1/15*(sorge)다. 나머지 14 집은 collaborator 초대가 없어 on 이 allowlist 에서 자동 제외한다. 초대는 Write 여야 한다 — Triage 로는 라벨을 못 쓴다.
  • 봇 토큰은 classic + public_repo 다. fine-grained PAT 는 발급 계정이 소유하지 않은 리포에 쓸 수 없다(403 Resource not accessible by personal access token). 이 실측이 「Issues:write 를 주면 된다」는 첫 추정을 뒤집었다.
  • 공개 webhook ingress 가 없다. gh webhook forward 는 개발 배달이라 이 호스트가 꺼지면 사건도 끊긴다(sorge#24).
  • 판정 품질은 아직 거칠다. 첫 두 판정이 갓 열린 이슈에 state:proposed 를 달았다 — sorge 어휘에서 그것은 「일이 끝나 머지 판단만 남았다」는 뜻이다. 프롬프트를 고쳐 proposed · running · review 에는 receipt 를 요구하게 했다.

[2026-09-15 Tue] stock 으로 되돌림 — omp 를 고치지 않는다

2026-09-15 오후. 아침에 세운 것을 GLG 가 도로 부쉈고, 그게 맞았다.

아침 판정은 sorge-label 프로파일이었다 — 봇이 라벨만 쓰고 댓글도 PR 도 안 하게 좁히는 것. 그러려면 stock RobOMP 를 고쳐야 했고, 고쳤다. fork 에 16 files changed, 1188 insertions(+) 가 쌓였다.

GLG 판정은 한 줄이었다: “omp 를 수정하면 안돼. 그냥 써야돼. 그래야 omp 버전업을 할수가 있거든.” 이유가 유지보수가 아니라 버전업 이라는 데 무게가 있다. fork 에 우리 줄이 있으면 상류를 따라갈 수 없고, 그러면 우리가 얻는 것(좁은 봇)보다 잃는 것(계속 자라는 하네스)이 크다. 같은 자리에서 “bg 도 오케이야. 일단 만들어서 루프를 돌리게 하려는거야. 시작이 되야 튜닝을 할 수 있으니까” 도 왔다.

되돌리니 드러난 것 — 셋 다 필요 없었다

  • 6519adb (봇이 쓴 이슈 skip) 은 도달 불가한 방어 였다. stock 에는 이슈 생성 도구가 없다(gh_post_comment=·=gh_push_branch=·=gh_open_pr=· =gh_request_review=·=gh_search_issues 뿐). 봇이 이슈를 못 만드니 막을 자기사건이 없었다. 라이브 로그가 skip reason=issues.labeled ignored 로 한 번 더 확인했다.
  • 93b65e8 의 1,057줄은 전부 좁히기 였다. 요구가 뒤집히자 줄도 같이 사라졌다 — 고칠 것이 아니라 없앨 것이었다.
  • 84a2766 의 자격증명 symlink 는 성격이 달랐다. stock 에 agent_dir 설정이 아예 없어서 자식이 호스트 agent.db 를 못 보는 것이 원인인데, 모델을 바꾸면 코드가 필요 없다. scrub 목록(worker.py:127-134)이 넷뿐이라 provider API 키는 자식까지 닿는다. 키 실측 anthropic 401 · openai 401 · deepseek 200 · gemini 200 → GLG 가 그날 deepseek/deepseek-v4-pro

(같은 날 저녁 flash 로 다시 정해졌다 — §좌표가 고정됐다) 를 골랐다.

즉 세 커밋 중 둘은 요구가 만든 것이고, 하나는 **설정으로 풀 수 있는 것을 코드로 풀었던 것**이다. 후자가 더 아픈 종류다.

라이브 증거

sorge#25 에서 사건이 끝까지 돌았다 — HMAC 202 → delivery dedup → claim → worktree farm/b9da13daresuming=False fresh 턴 → classify_issue → 라벨 question,=triaged= + sorge-bot 댓글 → rpc_done. fork diff 0 줄. on → status → off 3박자도 확인, relay 훅 15개 잔존 0.

남는 것

손잡이가 정하는 것은 셋뿐이다 — allowlist(대장 15집), 모델, 봇 이름. 나머지는 stock 기본값에 맡긴다. 값을 적는 순간 그것이 관리 대상이 되고, 버전업 때 기본값 변화를 못 따라간다. 예외 하나만 뒀다: ROBOMP_QUESTION_AUTOCLOSE_ENABLED=false — 무인으로 GLG 의 이슈를 닫는 것은 기본값이어도 받지 않는다.

이 집 관점에서 이건 「대신 뛰어듦 → 앞서 뛰어감」의 또 한 판이다. 좁은 봇을 만들어 준 것은 우리가 판정을 대신 설계한 것이었고, stock 을 그대로 쓰는 것은 도구는 상류에 맡기고 우리는 판정만 든다 는 뜻이다. 폐기한 1,188줄은 곁가지 sorge-label-profile 에 남겼다. 지우지 않은 이유는 그 판정이 틀려서가 아니라 아직 필요해지지 않아서 다.

[2026-09-15 Tue] 좌표가 고정됐다 — stock · flash · 한 집

하루가 두 번 뒤집혔다. 오전엔 좁은 라벨 봇을 fork 에 얹었고(1,188줄), 오후엔 그걸 되돌려 stock 을 그대로 썼다. 그리고 저녁에 세 칸이 동시에 정해졌다.

고정된 세 칸

무엇근거
프로파일stock RobOMP 그대로. 우리 줄 0고치면 omp 버전업이 막힌다 (GLG)
모델deepseek/deepseek-flash 하나API 키로 닿는 provider 여야 하고, 스위퍼를 익히는 동안은 싼 쪽 (GLG)
범위첫 표본은 sorge 한 집 (--only)새 모델과 호흡을 맞추는 첫 시간에 열다섯 집을 동시에 열지 않는다

세 칸 다 코드가 아니라 기동 인자와 상수 에 산다. 이게 이 판정의 성질이다 — 좁히는 손이 fork 에서 손잡이로 내려왔다.

왜 모델을 하나만 두나

ROBOMP_MODEL 은 쉼표 목록을 받고, 목록이면 stock 이 태스크마다 무작위로 고른다(config.py:328). 이슈별 @robomp-bot /model <alias> 프라그마는 그 풀 안에서만 고르므로, 프라그마를 쓰려면 풀이 둘 이상이어야 한다.

그런데 지금 변수가 이미 셋이다 — 새 프로파일(stock full) · 새 모델(딥시크) · 새 손(sorge-bot). 여기에 모델 무작위를 더하면 봇이 과하게 굴었을 때 프로파일 탓인지 모델 탓인지 못 가른다. 그래서 프라그마를 포기하고 하나로 둔다. 대가를 알고 고른 것이라 상수 옆에 그 이유를 적어 뒀다.

receipt 둘 — 모델이 바뀌면 증거도 바뀐다

  • sorge#25 (v4-pro): 사건 → HMAC 202 → dedup → worktree → fresh 턴 → classify_issue → 라벨 question,triaged + 댓글 → rpc_done. fork diff 0.
  • sorge#26 (flash): rpc_model_pick model=deepseek/deepseek-flash thinking=high resuming=False → bash/read 아홉 번 → classify_issuegh_post_commentrpc_done. 라벨 question,triaged,cli.

둘째가 더 좋았다. flash 가 줄번호와 grep 건수, 그리고 메뉴를 직접 띄운 결과 를 근거로 들고 왔다 — run.sh:135-171, README.md:76 한 줄, AGENTS.md grep 0건. 싼 모델이 덜 성실할 것이라는 예상이 이 표본에서는 틀렸다. 표본 하나이므로 판정이 아니라 관찰로 남긴다.

v4-pro 의 receipt 는 flash 의 receipt 가 아니다. 모델을 바꾸면서 #25 로 충분하다고 여겼다면 미검증 변경을 켜 둔 셈이었다. 그래서 #26 을 열었다.

운전자 면이 영어로 갔다

run.sh 메뉴에 루프 절이 아예 없었다(usage 에만 있었다). 5..9N 으로 넣고, 메뉴·=usage=·=robomp.py= 출력을 전부 영어로 돌렸다. 유지보수 주석과 docstring 은 한국어로 남겼다 — 이 집의 목소리는 한국어고, 바뀐 것은 운전자가 읽는 면뿐이다.

terra 검수에서 건진 것 — dry-run 이 밖에 쓰고 있었다

on 의 dry-run 이 라벨 무변경 PATCH 를 실제로 전송 했다. 봇이 쓸 수 있는지 확인하려던 것인데, 무변경이어도 PATCH 는 쓰기이고 GitHub 감사로그에 남는다. dry-run 의 계약은 「아무것도 안 바뀐다」이지 「같은 값으로 바뀐다」가 아니다. 이제 dry 는 GET 까지만 하고 확인은 --go 에서 한다.

terra 가 그것을 찾은 방식이 정확했다 — 검수하며 dry-run 을 돌렸고, 그 행위가 한 번 더 PATCH 를 쐈다. 검수자가 자기 검수로 결함을 재현한 것 이다.

같은 검수에서 문서 둘도 고쳤다: LOOP.md § never 가 코멘트를 금지하는데 stock 봇은 코멘트를 쓴다 → 두 손의 권한 표 를 정본에 올리고 never 목록을 「첫째 손」의 것이라고 제목에 박았다. 그리고 오전 보고 절이 label-only 를 현재처럼 말해서 (SUPERSEDED) 를 달았다 — 지우지 않는 이유는 되돌림의 근거가 그 요구들이기 때문이다.

아직 증명 안 된 것 하나

버전업 리허설. 이 전환의 목적 전체가 「상류를 따라갈 수 있다」인데, git pull upstream main 이 실제로 도는지 아직 안 재봤다. upstream/main 이 우리보다 22,413 커밋 앞이고(terra 실측), on 은 기존 venv 의 deps 를 재설치하지 않는다 — 엔진이 올라가면 그 자리가 먼저 깨진다. 별도 워크트리에서 먼저 재고, 라이브 체크아웃에 pull 을 섞지 않는다.

[2026-09-15 Tue] 봇이 자기 격리 결함을 드러냈다 — 켠 첫날 내린 이유

좌표를 고정하고 한 집으로 켠 날, 세 사건(#25 v4-pro · #26 flash · #27 저자 표시)을 돌린 뒤 같은 날 다시 내렸다. 내린 이유가 이 절이다.

어떻게 드러났나 — 봇이 스스로

AGENTS.md 에 「봇이 남길 때 저자를 밝힌다」를 넣고 #27 을 열어 규칙이 닿는지 봤다. 봇의 답은 닿지 않았다 였고, 이유까지 정확했다 — 워크트리는 원격에서 클론되므로 로컬 커밋 ba49914 는 자식에게 존재하지 않는다(git ls-remote origin main2dfd5ab). 규칙 전달 경로의 실측이 여기서 나왔다: AGENTS.md 규칙은 푸시 뒤에만 효력이 있다.

그런데 봇은 저자 표시를 형식까지 맞게 남겼다. 어떻게? **워크트리 밖 ~/repos/gh/sorge 의 미푸시 diff 를 직접 읽어서**다. 그 사실을 댓글에 스스로 적었고, terra 가 세션 아티팩트에서 그 실행을 찾았다 — …__27/.omp-session/.../5.bash-original.loggit show ba49914.

자기진술과 실행 로그는 같은 주장의 두 등급이다. 이 집이 대장에 판정만 적고 파생은 매번 유도하는 것과 같은 갈림이라, #28 본문에는 receipt 경로를 적었다.

사슬 다섯

#사실증거
1슬롯 uid 격리는 root 로만 켜진다queue.py:46-54elif os.geteuid() = 0:= 이면 SlotPool(range(2001,…)), 아니면 None + semaphore
2우리는 uid 1000 으로 떴다 → 격리 없음워크스페이스 소유 junghan 755
3scrub 은 env 만 가린다worker.py:127-134 넷. 같은 uid 면 파일을 읽는다
4issues.opened작성자 게이트가 없다github_events.py:322-341. is_maintainer 는 댓글 directive 에만
5대상 리포가 publicsorge=·=agent-config=·=nixos-config 확인

합치면: 낯선 사람이 이슈를 열면 그 본문이 GLG 권한으로 도는 턴의 입력 이 되고, 그 턴은 password-store 를 읽고 같은 턴에서 댓글을 쓸 수 있다.

내 축 셋이 다 불완전했다 (terra 보정)

  • root 슬롯 은 home·password-store·=robomp.env= 를 막지만 DeepSeek 키엔 완결 방어가 아니다 — scrub 밖이고 omp_rpc 가 parent env 를 merge 한다. credential proxy 없이는 model process 에서 bearer 를 숨길 수 없다 → 그 키는 **전용·저예산· 교체 가능**을 전제해야 한다
  • 전용 유저 하나*(내 권고였다)는 *틀렸다. 그 유저의 PAT 를 same-uid agent 가 읽는다. orchestrator uid ≠ agent child uid 를 갈라야 한다
  • forwarder 분리 도 안 된다 — gh webhook forward --secret 은 argv 노출이고 /proc/*/cmdline 이 444 라 root 로 옮겨도 슬롯 uid 에 숨지 않는다
  • stock 에 「non-maintainer 의 이슈는 라벨만」 toggle 은 없다
  • --only 는 mitigation 이 아니라 blast-radius control 이다

이 집 관점에서 무엇이 배워졌나

첫 표본을 한 집으로 둔 것이 값을 했다. 열다섯 집에 동시에 켰다면 같은 결함을 같은 날 찾았더라도 노출 범위가 달랐다. --only 를 넣은 이유는 「모델과 호흡을 맞춘다」였는데, 실제로 한 일은 결함이 드러날 때까지 반경을 줄여 둔 것 이었다. 좁게 시작하는 이유가 하나 더 생겼다.

그리고 컨테이너 전제의 대가 가 또 나왔다. 오전엔 /data 경로와 XDG 우선순위로 나타났고(§절차 의 함정 목록), 저녁엔 프로세스 경계로 나타났다. RobOMP 의 scrub 주석은 bashprintenv 하는 agent 를 막으려 적힌 것인데, 그 방어가 성립하는 전제는 파일시스템이 갈려 있다 는 것이었다. 도커 밖에서는 그 전제가 없다.

#28 에 셋을 물었다 — ingress(public 이슈를 계속 받나) · 격리 topology · secret transport. 코드 변경 0. 배치 결정이고 fork 수정으로 풀 문제가 아니다.