
세션 교체에도 이어지는 운영: 마스터 에이전트의 계보와 운영 하네스
// 참고: 내부 제품은 본문에서 [Polsia] → 임의의 가상 B2B 프로덕트로 시각 기반 유사 상품 검색 서비스로 가상화하여 설명합니다.
// 사례에 등장하는 일부 이름, 시각, 식별자는 공개 가능한 수준으로 일반화하였습니다. 도구 이름과 구조는 그대로 유지하였습니다.
// 사용자=Dorito=저=Human
Tooling
설계와 운영에 사용한 도구다. 뒤의 3.16에서 설명할 Adapter Layer와 맞춰 각 도구가 어떤 구현체인지 함께 적는다. 도구 이름은 역할 이름과 분리해서 읽어야 한다.
여기서 Runtime Unit은 하네스를 나눈 책임 단위이고, Adapter Layer는 Orca·Git·beads 같은 구체 도구를 추상 인터페이스 뒤에 두는 연결층이다. lease는 범위·권한·검증 조건을 묶은 위임 계약이다.
| 도구(담당 Runtime Unit) | 이 시스템에서의 역할 | 출처 |
| beads(U3 Workspace Runtime의 Work Ledger·memory) | Work Ledger 구현체. 이슈 상태와 작업 진행 기록을 관리한다. memory는 정본 전문 저장소가 아닌 포인터 캐시로 제한한다 | beads 문서 · GitHub |
| ctx(U12 Adapter Layer의 TraceArchiveAdapter) | Trace Archive 구현체. 로컬에 저장된 과거 에이전트 세션을 검색한다 | GitHub · ctx.rs |
| GSD(U4 Repository Runtime Loader의 정적 planning layer) | 백엔드 레포 하네스의 .planning/.agent에 남은 계획 계층. 현재 Master control plane은 아니다 |
GitHub |
| Superpowers(U4 Repository Runtime Loader의 절차 스킬 층) | 반복 가능한 작업 방법을 스킬로 제공하는 프레임워크와 방법론 | GitHub |
| Git(U12 Adapter Layer의 KnowledgeStoreAdapter) | Knowledge Store 구현체. 정본, 변경 이력, supersede 근거를 보존한다 | git-scm.com |
| Orca(Execution Substrate, U12 Adapter Layer의 ExecutionSubstrateAdapter) | Execution Substrate 구현체. 터미널, worktree, 실행 세션을 격리한다 | GitHub · onorca.dev |
| Codex(U5 Worker Scheduler의 Worker 레인, U12 ExecutorAdapter) | Executor 구현체. 이 글에서는 위임받은 Worker로 사용한다 | GitHub |
| Claude Code(Master Orchestrator 세션, U12 ExecutorAdapter) | Executor 구현체. 이 글에서는 Master 세션으로 사용한다 | GitHub |
| codex-plugin-cc(U12 Adapter Layer의 Executor 연결) | Claude Code에서 Codex 검토와 작업 위임을 연결한다 | GitHub |
| code-review-graph(구조 질의 층, U4 Repository Runtime Loader의 보조 질의) | Tree-sitter로 코드베이스를 파싱해 호출 관계와 의존 그래프를 만들고, 파견 전 영향 반경 산정과 리뷰 컨텍스트 추출에 사용한다 | 로컬 도구 |
| cursor agent(U5 Worker Scheduler의 Worker 레인) | 구현 워커의 하나로 사용한다 | 운영 기록 |
| grok(U5 Worker Scheduler의 Review Worker 레인) | 리뷰 게이트의 3-vote 리뷰어로 사용한다 | 운영 기록 |
Orca는 공식 설명에서 병렬 worktree, 터미널 분할과 Orca CLI를 제공하는 ADE(Agent Development Environment, 에이전트 세션·터미널·작업 사본을 함께 다루는 개발 환경)로 소개된다. 이 글에서는 그 기능 중 터미널과 worktree, 세션을 관측하는 기능을 Execution Substrate로 사용했다. Orca 공식 저장소
beads는 현재 Dolt 기반의 분산 그래프 이슈 트래커로 소개되며 의존성 추적과 지속적인 에이전트 메모리 기능을 제공한다. 이 글의 운영 규칙에서는 beads memory 기능을 영구 지식의 정본으로 사용하지 않고 Git 정본을 찾기 위한 짧은 포인터 캐시로 제한했다. 이는 이 하네스가 선택한 지식 관리 규칙이며 beads 자체의 필수 정책과 구분된다. beads 공식 저장소
ctx는 로컬에 남은 에이전트 세션 기록을 SQLite에 인덱싱하고 검색하는 도구다. 이 글에서는 handoff와 Work Ledger, Git 정본만으로 필요한 정보를 찾지 못했을 때 사용하는 Trace Archive로 제한했다. 평상시 부팅 컨텍스트에는 넣지 않는다.
검색 결과는 원래 세션 기록을 확인하는 조사 수단으로 사용한다. ctx 공식 저장소 GSD Core는 조사, 계획, 실행, 검증과 배포를 단계별로 진행하는 스펙 주도 개발 프레임워크다. 이 워크스페이스에서의 상태는 C/I/O/U로 나눠 적어야 한다.
C/I/O/U는 Configured, Intended, Observed, Unknown을 줄인 표기이며 아래 상태 매트릭스에서 다시 고정한다.
[C] 백엔드 레포 하네스에는 .planning/STATE.md, .planning/config.json, .agent/* 같은 정적 산출물이 남아 있고 조사·계획 context를 보존한다. [C] 현재 워크스페이스 Master Harness control plane은 docs/MASTER-OPERATIONS.md 기준으로 Beads, dispatch gate, 검증 계약을 통해 실행 상태와 lease를 관리한다.
[U] 현재 Worker runtime에서 GSD가 실행 절차를 관리했다는 증거는 확인하지 못했다. [U] Master Harness에 과거 언제 어떤 방식으로 연결됐고 왜 분리됐는지는 현재 기록만으로 확정하지 않는다.
[I] Planning-only 통합은 향후 검토 가능한 선택지이며 아직 운영 사실이 아니다.
따라서 이 글에서 GSD는 repo harness의 정적 planning layer로만 설명한다. GSD Core 공식 저장소 Superpowers는 브레인스토밍, 계획, 디버깅, 테스트, 코드 리뷰처럼 반복 가능한 작업 방법을 skill로 제공하는 절차 계층으로 사용했다.
전체 하네스의 정본은 운영 문서에 둔다. Superpowers 공식 저장소 code-review-graph는 Tree-sitter로 코드베이스를 파싱해 호출 관계와 의존 그래프를 만드는 로컬 도구다.
이 글에서는 파견 전 영향 반경 산정과 리뷰 컨텍스트 추출에 Structure Query 층으로 사용했다. 뒤의 3.5에서는 이 보조 질의가 레포 경계 판정에 어떻게 붙는지 다룬다. grok은 리뷰 게이트의 3-vote 리뷰어로, cursor agent는 구현 워커의 하나로 사용했다.
모델과 도구 구성은 계약이 유지되는 한 교체할 수 있다.
도구 선택 기준
도구를 고를 때 쓴 기준은 다섯 개였다.
- API 키를 요구하는가.
- 텔레메트리를 강제하거나 과하게 요구하는가.
- 관리 포인트를 더 늘리는가.
- 지금은 1인 운영이어도 어느 정도 규모의 협업 가능성을 포용하는가.
- 에이전트 컨텍스트 관리는 어느 도구나 내세우는 효용이다. 그 밖에 실제로 무엇을 더 해소해 주는가.
이 기준으로 채택을 복기하면 이렇다. beads는 로컬 저장이라 API 키와 텔레메트리가 없고, git 이력을 어지럽히지 않는 동작이라 관리 포인트가 늘지 않으며, 이슈 그래프 구조라 사람이 늘어도 그대로 쓸 수 있다. 다섯째 기준에서 해소한 것은 세대 교체 후 상태 복원의 정본 인덱스다.
code-review-graph는 로컬 파싱이라 외부 키가 필요 없고, 영향 반경 산정과 리뷰 컨텍스트의 토큰 절감이라는 구체 효용을 냈다. 문서화는 플레인 마크다운과 git으로만 했다. 포맷 잠금이 없어서 어느 도구로도 읽힌다.
유명세나 첫인상은 채택 사유 목록에 없었다. 실행 인프라 채택은 이 기준들 사이의 긴장을 드러냈다. 프로세스 감시를 원시 셸 폴링으로 자작하다 하루에 세 번 틀린 신호를 받은 날, 프로세스 감독을 실행 환경의 네이티브 기능으로 옮기면서 벤더 중립 원칙과의 충돌이 논의됐다.
결론에서 벤더 중립의 정의가 정리됐다. 지키려는 것은 에이전트 호스트의 교체 가능성이다. 규약 파일을 여러 호스트 진입점에 통일해 두는 이유가 그것이다.
반면 실행 인프라는 검증된 도구를 쓴다. 호스트 중립은 규약 통일이 맡고 실행은 Execution Substrate가 맡는 분업이다.
BTW,

정정: 최근에 opus 5 로 업데이트 되면서, 컨텍스트 초기화 관련 최적화 방식이 Anthropic 기준 변경되는 것을 확인했다. 100퍼센트 꽉차도 실제 context 량은 80퍼 남짓하게 보이게 처리해둔 것도 확인함 (자동차 속도 계측기처럼 동작)
Orca ADE 간단 설명
계정 전환이 잦고, 여러 에이전트를 병렬로 운용하고, 세션·컨텍스트 캐싱의 이점을 활용하는 워크플로라면 Orca가 유용합니다. 반대로 회사/개인 계정 하나를 머신 1개에서 고정하고 에이전트도 많이 돌리지 않는다면 기존 Codex·Claude Code 인터페이스 대비 체감 이득이 크지 않을 수 있습니다. https://www.onorca.dev/
Orca — The most powerful Agent Development Environment (ADE)
발단: 세 개의 문제

이 시스템은 2026년 6월과 7월에 반복해서 부딪힌 세 종류의 실패에서 나왔다.
첫째는 컨텍스트 소진이었다. 세션 기록에 남아 있는 초기 핸드오프 문서의 첫 줄은 이랬다.
너는 이 작업의 오너십을 이어받는다. context 0에서 시작하니 이 문서가 유일한 상태 소스다. 상태는 기억에 기대지 말고 git으로 실측한다.
당시에는 이런 handoff 파일이 워크스페이스 루트에 버전별로 쌓였다. 최신 상태를 어느 파일에서 읽어야 하는지, 어떤 내용이 이미 정본으로 승격됐는지, 새 세션은 매번 다시 판정해야 했다.
둘째는 크로스레포 시야 부재였다. 내가 만든 워크스페이스는 독립 git 레포 세 개, 즉 백엔드와 프론트엔드와 계획·운영 문서를 함께 담은 컨테이너였다. 백엔드 API 계약이 바뀌면 프론트엔드 코드 재생성이 필요한데, 단일 레포만 보는 세션은 이 전파를 볼 수 없었다.
이때즈음 당시 Orca 라는 ADE 에 대해서 접하게 되었고 오케스트레이션, 병렬 배치 실행 기능, Remote 기능 등 활용하고 싶었다.
셋째는 감시받지 않는 에이전트의 폭주였다. 같은 날 오후, 읽기 전용으로 지시한 리뷰어 에이전트가 환각 지시를 근거로 쓰기 권한 프로세스를 무단 스폰해 워크트리에 파일을 생성한 사고가 마스터에게 보고됐다. 검토 완료 뒤에도 자가 발화를 반복하며 보낸 적 없는 지시를 받은 것처럼 행동했다.
이 사고에서 Worker의 자기 보고를 증거에서 분리하고, 리뷰 전용 Worker에게 쓰기 도구를 주지 않는 규율이 나왔다.
가장 큰 촉매는 일정과 마감이었다. 내가 예전에 백엔드 작업했었던 <Polsia> 라는 B2B 프로덕트의 어드민 서비스는 갑자기 빠른 빌드업을 요구받았고, 리소스는 부족했으며, 3개월에서 1개월 이내로 매우 크게 압축된 일정(1개월)으로 작업이 별도로 내게 요청이 넘어왔다. 같은 날 넉 달 동안 작업이 중단되었던 서비스에 대해 프로덕션 어드민 서버까지 헬스체크가 되도록 배포부터 선행했고, 후속적으로 프로덕션까지 어드민 기능 완성을 하는 것이 내 업무의 1순위 트랙이 되었다. (1인 개발 + 풀스택까지 요구 받은 상황ㅠㅠ 복잡한 사정이 있다.)
이에따라 2026년 7월 14일, 워크스페이스에 상주하며 여러 레포를 동시에 조율하는 Master 역할을 만들었다. 컨텍스트가 찬 세션이 새 세션에게 오케스트레이터 역할을 넘기고 종료된, 이 글에서 다룰 승계 사례의 출발점도 이때 나왔다.
사용자는 작업에 앞서서, AI Agent 개발 기반으로 한 Orca ADE (위 Tooling 절 참고) 를 최대한 활용하여 생산성을 극대화하는 AHE(Agent Harness Engineer) 아키텍처를 설계하는 것부터 시작했다. 여기서 AHE는 ADE 위에 역할, 위임, 승인, 복구, 승계와 지식 정본을 운영 규칙으로 묶는 방법을 가리킨다.
→ 이 시스템을 통해서 사용자는 3개월 일정이 추산되었던 작업을 3주 이내로 완료했다.
이 세 문제와 촉매를 하나로 묶은 목적 요약이 세션 기록에 남아 있다. 시스템의 목적을 설명하라는 사용자의 요청에 에이전트는 이렇게 답했다.
세션이 죽어도 운영이 안 죽는 에이전트 운영체제입니다. 세션이 바뀌어도 행동 규칙이 유지되는 이유는, 채팅의 지시가 사라져도 문서가 같은 지시를 반복하기 때문입니다.
독자 온보딩: 채팅창에서 관제센터로

2024년식 코딩 어시스턴트의 기본 화면은 채팅창이었다. (프롬프트 엔지니어링) 사용자는 질문을 던지고, 모델은 답을 내고, 세션은 작업이 끝나거나 컨텍스트가 차면 버리는 단위로 취급됐다. 그 전제에서는 좋은 프롬프트와 긴 컨텍스트가 주된 개선축으로 보인다.
그 사이 업계는 Repository 단위의 지식 계층으로 이동하기 시작했다. Karpathy의 LLM wiki 패턴처럼 레포마다 에이전트가 유지하는 지식 정본을 두는 흐름이 부흥했고, 나는 그 위에 역할·위임·승인·복구·승계까지 운영 규칙으로 묶는 방법 을 AHE(Agent Harness Engineering)라 이름 붙였다.
단순 프롬프트 엔지니어링에서, 메모리 시스템으로, 메모리 시스템에서 맥락을 이야기하는 컨텍스트 엔지니어링으로. 맥락을 지속적으로 동기화하는 루프 엔지니어링으로 나아가기 시작했다. (각주: Loop 개념 자체는 Anthropic Claude Code의 agentic loop에서 출발했지만, '루프 엔지니어링'이라는 이름을 붙여 유행시킨 건 Addy Osmani·LangChain 같은 외부 진영이
다. 브랜딩이 개념을 앞서가는 느낌은 있다)
여기서 더 나아가서 Master 발상은 세션을 워크스페이스의 지속 실행 단위로 끌어올리면서 시작했다. 대략 이렇다. 워크스페이스 안에는 여러 레포와 레포 단위로 하네스 시스템이 있으며 여러 작업 사본이 있다 (git worktree), 사용자는 계속 판단을 던진다.
Master는 그 판단을 Worker 계약과 검증 루프로 번역하는 원 세션이다. 2026년 6월 30일 저녁, 개인 도구 프로젝트를 손보던 중 사용자는 이렇게 물었다. (Orca 를 알게 된지 얼마 안된 상태였다. 아마 3일차쯤)
이거 멀티 세션 멀티 디바이스로 멀티 에이전트 관리까지로 점진적으로 확장 가능성있나?
그때 사용자에게 쌓여 있던 피로는 세션 관리에서 왔다. 컨텍스트가 차는 세션들을 갈아 끼우고, 계정과 기기를 오가며, 같은 상태를 매번 다시 설명하는 일이 누적돼 있었다. Polsia도, 상주 관제센터도, Master Harness도 없었다.
세션 하나를 관리하는 도구가 여러 세션과 여러 에이전트를 관리하는 쪽으로 커질 수 있는지 묻고 있었다. 이틀 뒤 질문은 설계 의뢰로 바뀌었다.
멀티 머신 멀티 계정 멀티 에이전트 멀티 서브에이전트 멀티 멀티멀티 - 리모트, 로컬 다 돌아가게 (이거 요구사항 자체를 분석하고 플랜 작성해줘. ... 가능하다면 codex - claude code 끼리 오케스트레이션을 조작할수잇으면 좋겟다. 관련 웹서칭도 진행해봐.)
이 발화에는 지금 시스템의 원형이 들어 있다. 여러 실행 환경, 여러 계정, 여러 에이전트, 로컬과 원격, 서로 다른 코딩 에이전트의 오케스트레이션. 이름은 그 뒤에 생겼다.
같은 날, 사용자가 격리된 작업 공간(git worktrees)을 여러 개 띄워 병렬로 문제를 고치던 중 사용자가 한 에이전트에게 이렇게 말했다.
일단 Orca cli 기능을 써봤다. 마스터 에이전트한테 전달햇음. 보관처리해라.
여기서 Master는 결과를 모으고 최종 반영을 판단하는 원 세션을 가리키도록 만들었다. (처음에는 장난스럽게 시작함) 그 뒤 같은 워크스페이스 (작업 공간)에서 시작한 가장 초고성능 모델 기반 Fable 5 에이전트 세션을 Master Session이라고 부르며 자기 작업을 호칭하게 되었다. (각주: 당시 Fable 5 가 한정적으로 제공된다는 정책이 있었음)
이름은 운영 중에 먼저 생겼고, 나중에 역할 정의가 따라왔다.
이 글에서 쓰는 기본 용어는 아래와 같다. ADE(Agent Development Environment)는 에이전트 세션, 터미널, 작업 사본, 재개 경로를 함께 다루는 개발 환경 범주다. 여기서는 Orca ADE 를 의미한다. (Orca ADE 에 대해서는 할 말이 너무 많아서 여기서는 분량 문제로 스킵)
AHE(Agent Harness Engineering)는 ADE 위에서 역할, 위임, 승인, 복구, 승계와 지식 정본을 운영 규칙으로 묶는 방법이다.
Master는 워크스페이스와 Track(세션을 넘어 이어지는 작업 단위)을 조율하고, Worker 계약과 검증을 소유하는 원 세션이다.
Worker는 Master가 발급한 lease(범위·권한·검증 조건을 묶은 위임 계약) 안에서 작업하고 증거를 제출하는 실행 세션이다.
Work Ledger는 현재 이슈와 실행 상태를 기록하는 장부다.
책임 경계도 명확히 1개씩 소유한다.
Human은 외부 영향과 최종 결정을 승인한다. Master(직속 부하, 하청)는 Track, 순서, lease, 수락 판단을 조율한다. Repository Harness는 레포 안의 코드, 규칙, 빌드와 테스트의 진실을 소유한다.
Worker (하청의 하청)는 허용된 작업 사본 안에서 실행하고 Evidence Bundle(검증 가능한 diff, 로그, 테스트 결과, 미검증 gap 묶음)을 제출한다.
이 자리에서는 최소 맵만 먼저 둔다. 역할별 소유 상태와 변경 권한은 뒤의 3.2 책임 표에서 자세히 다룬다. 이 구조에서 도구 이름과 역할 이름은 분리해서 읽어야 한다.
초반에는 최소 맵만 있으면 충분하다.
| 역할 | 현재 사용하는 구현체 |
| Execution Substrate | Orca |
| Master / Executor | Claude Code, Codex |
| Worker / Review Worker | Codex, cursor agent, Claude 서브에이전트, grok 3-vote |
| Work Ledger / Pointer Cache | beads issue, beads memory |
| Knowledge Store | Git |
| Trace Archive | ctx |
| Structure Query | code-review-graph |
| Repository Planning | GSD .planning 산출물 |
GSD (gsd-core)는 레포 하네스의 정적 계획 산출물로 남아 있다.
현재 Master Harness control plane은 Beads, dispatch gate, 검증 계약으로 돈다. GSD의 세부 상태와 도구 선택 기준은 앞의 Tooling 절에서 다룬다.
현재 운영: 참조 아키텍처와 구현 상태
현재 운영 절차와 참조 아키텍처는 같은 글 안에 함께 나온다. 코드화 상태는 기능별로 다르다. Bootstrap과 dispatch gate, E12 관측처럼 구성되거나 관측된 부분이 있고, Approval Manager와 contract tests처럼 목표 상태로 남은 부분도 있다.
이 구분은 다음 상태 매트릭스에서 고정한다.
현재 상태 매트릭스
상태 표기는 네 가지다. C는 Configured, 즉 설정 파일이나 스크립트나 문서화된 정적 구성이 확인된 상태다. I는 Intended, 즉 설계 계약은 있지만 실행 증거가 없는 상태다.
O는 Observed, 즉 Git 기록, 로컬 실행, 로그, ledger, 프로세스 같은 자기보고 밖의 증거로 관측된 상태다. U는 Unknown 또는 제한, 즉 확인 범위 안에서 미검증이거나 부분 불일치가 남은 상태다.
| 기능 | Configured | Intended | Observed | Unknown |
| Bootstrap | 워크스페이스 루트 SessionStart에 master-bootstrap-live와 bd prime --memories-only가 구성되어 있다. |
docs/MASTER-OPERATIONS.md가 boot contract를 정의한다. |
root 범위 실행에서 Role State, active tracks, BD audit, dual-instance none이 관측됐다. | operations-repo local hook에는 bootstrap이 없으므로 root cwd guard 범위로 한정해야 한다. |
| Role State injection | root UserPromptSubmit hook이 docs/runbooks/role-state.md를 주입하도록 구성되어 있다. |
every-turn Role State injection이 운영 문서에 의도로 적혀 있다. | role-state 파일과 bootstrap 출력에서 현재 세대와 역할 상태가 관측됐다. | 모든 턴의 hook 실행 로그는 전수 확인하지 않았다. |
| Dispatch Gate | dispatch-gate CLI, Bash direct-call warning hook, ledger 경로가 구성되어 있다. | check, register, ticket, warn 모델이 문서화되어 있다. | dispatch-gate help, ledger의 ALLOW/OK, warning 로그가 관측됐다. register는 산출물에서 job id가 실측된 뒤에만 수락되는 동작이 관측됐다. | Bash 밖의 connector와 모든 Worker 생성 경로 강제 여부는 미확인이다. |
| Harness Loading | 백엔드 레포의 .planning, .agent, config와 운영 문서 레포의 .planning, travelog 스킬 정의가 존재한다. |
작업에 필요한 Repository Harness만 지연 로딩하는 구조를 목표로 둔다. | Worker 세션에서 AGENTS/CLAUDE와 .agent 지시 로드, code-review-graph MCP 접근과 PostToolUse graph 갱신, travelog skill discovery와 SKILL.md 적용이 관측됐다. |
Lazy Loader 자동 실행, travelog slash 호출면, PreToolUse 차단과 UserPromptSubmit stdout은 미관측이다. |
| Recovery | docs/MASTER-OPERATIONS.md에 Recover, Verify, Patch, Promote와 runtime 복구 순서가 문서화되어 있다. |
같은 세션 복구 우선과 app restart, PTY, process 확인 순서가 의도 상태로 적혀 있다. | lineage의 recovery sources, role-state, handoff archive가 관측됐다. | 자동 Recovery Manager 구현은 확인되지 않았고 최신 live handoff 파일도 별도 확인이 필요하다. |
| Succession | MASTER-LINEAGE.md, role-state, Succession v3 절차가 문서화되어 있다. |
후임 측정, 전임 정리, Human 지시 기반 succession 절차가 정의되어 있다. | Gen1부터 Gen23까지 lineage가 관측됐다. | 모든 세대의 품질 필드가 완전한 같은 형식으로 남아 있다고 확장하면 안 된다. |
| Safeguard Lane | 보안 경로 접근을 차단하는 PreToolUse hook, 출력 필터 hook, 거부 규칙이 워크스페이스에 구성되어 있다. | 보안 계열 작업 전량을 독립 상설 세션에 위임하고 Master는 보안 콘텐츠를 다루지 않는 계약이 운영 문서에 적혀 있다. | 경로 차단 hook의 라이브 차단, 독립 위임 세션의 가동, 안전장치 폴백으로 세션의 실행 모델이 교체된 모델 드리프트가 세 세대에서 관측됐다. | 출력 필터 층은 실효성이 확인되지 않아 재배선 결정을 기다리고, 세션 도중 모델 정체성 프로브는 아직 없다. |
| Approval Manager | dispatch tickets와 approval 운영 규칙이 문서에 있고, 오케스트레이터 런타임 저장소에 Gate 분류와 G2·G3 Human 권한 강제 로직의 구현이 존재한다. | 문서화된 Gate 모델을 런타임으로 집행하는 것이 목표 상태로 명시되어 있다. | approval 모듈 테스트 통과가 관측됐다. | 이 구현이 실제 파견 경로에 배선되어 운영 중인지는 확인되지 않았고, 운영 판단은 여전히 manual Human decision과 분리해서 써야 한다. |
| Observability | E12 scripts, context-quality ledger, lineage ledger, context-quality summary script가 있다. | compact recall probe, threshold, proposed respawn 모델이 문서화되어 있다. | 최근 compact records, loss notes, proposed_respawn 기록이 관측됐다. | runtime monitor의 범위와 coverage는 별도 증거가 부족하다. |
| Contract Tests | 오케스트레이터 런타임 저장소에 approval, bootstrap, recovery, succession, lineage, dispatch gate, work ledger를 다루는 테스트 파일들이 존재한다. | P0 계약 전부를 contract tests로 덮는 것이 목표로 남아 있다. | 테스트 스위트 통과가 관측됐다. | 이 테스트들이 운영 파견 경로와 연결되어 회귀를 막고 있는지는 확인되지 않았다. |
1부는 사건이 어떤 설계 압력으로 바뀌었는지 보여 준다. 2부는 하나의 요청이 들어와 실행, 증거, 수락, 지식 승격, 승계 준비까지 이어지는 흐름을 따라간다. 3부는 구현하거나 검산할 때 돌아오는 참조 명세다.
이 글을 처음 읽을 때 3부를 외울 필요는 없다.
1부. 설계 도안 (장애 조사에서 지식 정본까지)
2026년 7월 15일의 작업은 관제센터형 Master가 실행 기반 위에서 살아남을 수 있는지 확인하는 일로 시작했다. Orca와 Claude Code Fable 5 기반 Master 승계 과정에서 런타임 이상이 발생했고, 조사 범위와 우선순위는 Human이 정했으며 실측과 문서화는 Master 세션이 수행했다. 여기서 Fable 5는 당시 Master 역할을 맡은 대화형 모델 세션을 가리키는 이름이다.
오후에는 <Polsia> 워크스페이스 안에 흩어진 지식 저장 구조를 재검토했다. 이날 만든 것은 에이전트 실행 구조와 지식 구조를 하나로 묶은 운영 하네스였다.
앱이 사라져도 실행은 남아 있었다
직접적인 출발점은 Orca 앱과 runtime이 재시작되는 동안 Fable Master 세션이 실제로 유지됐는지 확인하는 일이었다.
orca terminal create로 새 Master 터미널을 만든 직후 Orca CLI가 일시적으로 runtime_unavailable 상태가 됐다. 방금 생성한 터미널 핸들도 stale로 보였다. 화면만 보면 새 Master 세션이 사라진 것처럼 보이는 상황이었다.
프로세스와 daemon 로그를 확인하니 실행 구조는 여러 생명주기로 나뉘어 있었다.
Orca UI
↓
Orca Runtime / daemon
↓
PTY
↓
Agent Process
다음 화면에서는 Control Center, 레포별 worktree, Worker 터미널이 하나의 Execution Substrate 안에 함께 놓인 토폴로지를 봐야 한다.

Orca의 UI 프로세스는 교체됐지만 daemon이 소유한 PTY와 그 위의 Agent 프로세스는 살아 있었다. 앱이 복구된 뒤 기존 세션에 다시 연결할 수 있었다. 이 사건에서 첫 운영 원칙이 나왔다.
사용자에게 보이는 앱이나 터미널 UI가 사라져도 에이전트 실행 상태는 남아 있을 수 있다. 세션이 보이지 않을 때는 클라이언트, runtime, daemon, PTY, Agent 프로세스, 재부착 가능성을 순서대로 확인해야 한다. 기존 프로세스가 살아 있는데 같은 session ID를 다시 resume하면 두 개의 Master가 같은 상태를 수정할 수 있다.
세션 파일, handoff, 작업 사본까지 동시에 오염된다. 그래서 새 세션은 기존 실행이 실제로 소멸했다는 증거가 있을 때만 만든다.
Reattach
↓ 실패
Inspect daemon / PTY / process
↓ 기존 실행 소멸 확인
Resume once
↓ 복구 불가 확인
Spawn successor
이 사건 뒤 Recovery와 Succession의 경계도 분리됐다. Recovery는 세션이 보이지 않거나 응답하지 않을 때 기존 실행을 다시 사용할 수 있는지 판정한다. Succession은 살아 있는 Master가 작업을 계속하기 어려워지기 전에 상태를 동결하고 후임에게 넘긴다.
여기서는 경계만 기억하면 된다. 기존 실행을 찾는 절차와 후임 생성 조건은 뒤의 3.12와 3.13에서 상태별로 풀어 쓴다.
자기 보고와 증거를 분리했다
승계 구조를 설계하면서 에이전트의 자기 보고를 어디까지 신뢰할지도 다시 정의했다. 에이전트가 “작업을 완료했다”, “메시지를 받았다”, “검증했다”고 응답해도 이를 주장으로 취급하고 증거와 분리한다. 이날 승계 과정에서도 응답 문구만으로 수신과 종료를 판단하지 않았다.
세션 JSONL, 프로세스, PID의 커맨드라인, 터미널 연결 상태를 함께 확인했다. 과거 세션 기록이 필요할 때는 ctx를 읽기 전용 Trace Archive로 사용했다. 여기서 실행 주체와 수락 주체를 분리하는 원칙이 나왔다.
Worker는 구현하고 결과물을 제출할 수 있지만 자신의 결과를 최종 수락할 수 없다. 결과물은 실제 파일과 diff, 테스트 로그, 프로브 결과, 프로세스 및 런타임 상태 같은 외부 증거로 검증한다. 공유 상태를 변경하거나 되돌리기 어려운 행동은 Human Gate를 통과한다.
현재는 사람이 이 분류와 승인을 수동으로 집행한다. 향후 구현할 Approval Manager는 행동의 위험도와 가역성을 분류하고 승인 상태를 관리하되, Human의 최종 승인권은 계속 Human에게 남긴다.
소유권을 먼저 정했다
런타임 조사가 끝난 뒤 설계의 질문은 어떤 기능이 필요한가에서 누가 무엇을 소유하는가로 이동했다. 책임 경계는 Human 승인, Master의 여러 레포와 Track 사이 조율, Repository Harness의 레포 내부 코드·도메인 지식·규칙 진실 소유, Worker의 지정된 lease 범위 안 실행으로 나뉜다. 여기서는 이 네 주체만 기억하면 된다.
뒤의 3.2에서는 각 주체가 소유하는 상태와 할 수 있는 변경을 표로 고정한다. 이 경계는 하나의 문장으로 남았다.
구현의 진실은 레포에 남기고, 레포 사이의 조율 상태만 워크스페이스에 둔다.
소유권 경계를 정한 뒤에야 Master를 어떤 Runtime Unit으로 나눌지, 각 Unit이 어떤 상태를 읽고 쓸지 결정할 수 있었다. 여기서는 분해가 필요했다는 이유만 남긴다. 뒤의 3.3에서는 Master를 12 Runtime Unit으로 나눠 각 Unit의 인터페이스를 표로 고정한다.
오전의 사건은 실행 생존과 증거 수락 문제를 드러냈고, 오후의 사건은 지식 정본 문제를 드러냈다.
무엇을 믿을지 먼저 정했다
Polsia 워크스페이스에는 정보가 흩어져 있었다. 실행 이슈와 진행 메모는 beads issue에, 장기 기억은 beads memory에, 레포별 계획 산출물은 .planning에, 제품 지식은 제품 레포 wiki에, 워크스페이스 운영 문서는 여러 위치의 Git 문서와 handoff에, 과거 기록은 Notion과 scratchpad에 남아 있었다.
제품의 장기 지식이 Git Wiki와 beads memory에 동시에 들어 있었고, handoff는 날짜별로 쌓였지만 어느 파일이 현재 상태인지 명시되지 않았다. 런타임을 구현하기 전에 먼저 답해야 할 질문이 생겼다.
Repository 하네스 글 포스팅에서도 언급했던 문제 의식이다. SSOT(Single Source of Truth, 한 정보 유형에 대해 믿을 정본 하나)의 문제.
이 에이전트 시스템은 무엇을 정본으로 믿어야 하는가?
이 실측으로 정보 유형별 SSOT를 정했다.
제품 지식은 제품 레포에, 워크스페이스 운영 지식은 operations-repo에, 현재 실행 상태는 beads issue에, 레포 내부 계획과 로드맵은 해당 레포의 .planning에 둔다.
워크스페이스 Track과 lease 상태는 Work Ledger가 소유한다.
그 밖의 저장 위치에는 전문을 복제하지 않고 정본을 가리키는 포인터만 남긴다.
이 재분류에서 역할이 가장 크게 바뀐 것은 beads memory였다. (도입 당시에는 단순 호기심으로 설치해보았다. git 과 유사한 dolt 라는 걸 이용해서 에이전트를 위한 그래프 지식을 생성, 관리, 상태 전이 등 많은 것을 해준다.)
당시 beads memory에는 영구 규칙과 장애 기록, 설계 설명의 전문이 저장돼 있었다. 세션 시작 시 중요한 정보를 바로 주입할 수 있다는 장점은 있었지만 Git 정본과 내용이 중복됐고, 변경 이력과 검토 절차가 Git 정본만큼 명확하지 않았고, 세션 시작 때마다 장문의 과거 정보가 컨텍스트에 들어갔다.
그래서 beads memory를 영구 지식 저장소에서 정본을 찾기 위한 포인터 캐시로 낮췄다.
memory에는 세션 시작부터 적용해야 하는 짧은 정책 요약, 정본 경로, 검색 키워드, 마지막 확인 시각 정도만 둔다.
규칙의 근거와 예외, 변경 이력은 Git 문서에서 읽는다. scratchpad는 유실돼도 되는 정보만 담는다. 다음 세션에도 필요한 정보라면 종료 전에 적절한 정본으로 승격한다.
승격하지 않은 정보는 영구 가치가 없는 조사 메모로 취급한다.
handoff는 현재 상태이고 이력은 Git이 맡는다.
현재 운영: handoff 목표 구조 이전 상태 아직 목표 구조에 완전히 도달하지 못했고, 승계마다 날짜 파일을 만들고 가장 최근 파일을 LIVE로 간주하는 구간이 남아 있다.
지금은 이 목표만 기억하면 된다. handoff는 현재 상태 한 건으로 수렴해야 하고, 뒤의 3.20에서 Track당 LIVE handoff 한 건으로 관리하는 방식을 자세히 다룬다. 이 지점까지가 1부의 사건이다.
실행 기반은 재부착과 승계의 문제를 만들었고, 지식 저장 구조는 정본 판별의 문제를 만들었다. 2부에서는 이 두 문제가 실제 요청 하나를 처리하는 흐름 안에서 어떻게 만나는지 따라간다.
2부. 시스템은 하나의 요청을 어떻게 처리하는가
1부에서는 실행과 지식의 책임을 나눴다. 2부에서는 사용자의 요청 하나가 들어온 시점부터 결과가 수락되고 다음 세션으로 이어질 때까지의 흐름을 하나의 사례로 따라간다. 이 자리에서는 네 축만 기억하면 된다.
- lease는 Worker에게 맡긴 범위다.
- gate는 행동의 승인선이다.
- evidence는 수락할 때 보는 증거다.
- recovery와 succession은 중단 이후에도 같은 상태로 이어가기 위한 연속성 절차다.
뒤의 3.9~3.13과 3.22에서 이 축들을 스키마와 상태 전이로 풀어 쓴다. 사례는 Polsia의 백엔드 API 계약을 바꾸고 프론트엔드 소비 코드를 맞추는 요청이다. 이 작업은 한 레포에서 끝나지 않는다.
백엔드 계약, 프론트엔드 코드 생성, 통합 스모크, 배포 순서가 한 흐름으로 묶인다.
1. Master는 최소 컨텍스트로 시작한다
새 세션이 열리면 Master는 전체 Wiki와 과거 대화 전문을 한꺼번에 읽지 않는다. Bootstrap은 Role State(현재 세션의 역할과 허용·금지 행동을 적은 부팅 상태), L0 정책, 활성 Track, 최신 handoff와 Work Ledger 포인터를 먼저 읽는다. L0는 모든 세션 시작 시점에 직접 적재하는 정책 커널이다.
이 범위에서 확인된 현재 운영 상태는 온보딩의 상태 매트릭스에 둔 그대로다. Master가 처음 가져야 하는 것은 지금 어떤 정본을 읽어야 하는지에 대한 포인터다. 이 상태로 사용자 요청을 기다린다.
뒤의 3.4에서는 이 부팅 범위를 Bootstrap 명세로 정리한다.
2. 요청이 들어오면 역할과 Track을 확인한다
사용자가 “백엔드 API 계약을 바꾸고 프론트도 맞춰 달라”고 요청한다. Master는 먼저 현재 역할에서 처리할 수 있는 요청인지, 기존 Track에 속하는지, 새 Track이 필요한지 확인한다. 진행 중인 release 작업이나 승인 대기 행동이 있다면 그것을 파킹하거나 완료 조건을 확인한 뒤 새 요청을 받아야 한다.
이 단계에서 Human의 지시는 최상위 입력이다. Master는 요청을 그대로 실행하지 않고 현재 역할, 열린 Track, 허용된 행동, 금지된 행동과 대조한다.
뒤의 3.7에서는 역할 잠금과 역할 전환 조건을 Role Runtime으로 정리한다.
3. 레포 경계를 판정한다
요청이 백엔드 API만 바꾸는 일이라면 백엔드 Repository Harness 안에서 끝난다. 하지만 프론트엔드 소비 코드까지 함께 바꿔야 한다면 워크스페이스 수준의 크로스레포 Track이 된다. Master가 소유하는 것은 레포 사이의 순서다.
백엔드 계약을 먼저 수락하고, 그 뒤 프론트엔드 코드 생성을 돌리고, 마지막에 통합 스모크와 배포 순서를 확인한다. 각 레포 안에서 어떤 파일을 어떻게 고칠지는 해당 Repository Harness와 Worker가 맡는다.
뒤의 3.5에서는 이런 레포 경계 판정을 Context Resolver의 입력과 출력으로 정리한다.
4. 필요한 Repository Harness만 읽는다
대상 레포가 정해지면 Master는 필요한 정본만 page-in한다. 백엔드 작업에는 백엔드 레포의 규칙, 관련 wiki, .planning 산출물, 빌드와 테스트 명령을 읽는다. 프론트엔드는 백엔드 계약이 수락된 뒤 소비 코드와 코드 생성 규칙이 필요해진 시점에 읽는다.
현재 운영: 정적 harness와 Lazy Loader 상태 확인된 것은 정적 harness 파일과 일부 hook 설정의 존재다. 현재 Worker runtime에서 Repository Runtime Loader가 자동 lazy load됐다는 증거는 없으므로, 이 단계는 운영 절차와 참조 구현의 목표를 분리해서 읽어야 한다.
뒤의 3.8에서는 필요한 Repository Harness만 읽는 절차와 관측 범위를 분리해 설명한다.
5. Master는 lease를 발급한다
백엔드 Worker에게는 백엔드 계약 변경 lease가 발급된다. lease에는 다음 조건이 붙는다.
- 대상 Track
- 대상 레포와 worktree
- 허용된 파일 범위
- 사용할 수 있는 capability
- 금지 행동
- 제출해야 할 산출물
- 검증 명령
- 시간과 토큰 예산
Worker는 지정된 worktree와 태스크 컨텍스트 안에서만 작업한다. 작업 중 프론트엔드 변경이 필요하다는 사실을 발견해도 바로 프론트엔드 레포를 수정하지 않는다. Master에게 scope change를 제안하고 별도의 프론트엔드 lease를 기다린다.
뒤의 3.9에서는 이 위임 계약을 Worker Scheduler와 lease 상태 전이로 정리한다.
6. Worker는 실행하고 증거를 제출한다
Worker는 백엔드 계약을 수정하고 테스트를 실행한 뒤 결과물을 제출한다. 자연어 완료 보고는 주장이다. 수락에 필요한 것은 변경 파일, diff, 테스트 로그, 프로브 결과, 실행 로그, 검증하지 못한 항목이다.
Master는 제출물을 Work Ledger의 상태와 lease 범위에 대조한다. lease 밖 파일이 바뀌었거나 테스트가 주장과 다르면 완료 보고를 수락하지 않는다.
뒤의 3.9에서는 Worker가 제출할 수 있는 lease 상태를, 3.11에서는 evidence bundle을 수락 증거로 검토하는 기준을 정리한다.
7. 수락은 Evidence를 기준으로 열린다
수락자는 Worker의 표현을 주장으로 두고 외부 증거를 본다. 실제 diff가 있는지, 테스트가 실행됐는지, 프로브 응답이 기대와 맞는지, 알려진 gap이 완료 조건과 충돌하는지 확인한다. 가역적인 로컬 변경은 정책을 통과하면 자동 수락 후보가 될 수 있다.
공유 브랜치, 외부 이슈, 배포, 프로덕션 데이터, 자격증명 사용처럼 외부 상태를 바꾸는 행동은 Human Gate(되돌리기 어렵거나 외부 상태를 바꾸는 행동을 사람이 승인하는 경계)로 올라간다. 이 자리에서는 외부 상태를 바꾸는 행동이 Human Gate로 올라간다는 원칙만 잡으면 된다. 뒤의 3.10에서는 이 승인선을 G0~G3 표로 고정한다.
뒤의 3.10에서는 승인선의 등급을, 3.11에서는 수락자가 evidence를 판정하는 방식을 정리한다.
8. 프론트엔드 lease는 계약 수락 뒤에 열린다
백엔드 계약이 수락되면 Master는 프론트엔드 Worker에게 두 번째 lease를 발급한다. 이 Worker는 코드 생성, 타입 파사드, 소비 코드 수정, 프론트엔드 테스트를 수행한다. 백엔드 Worker가 넘겨 준 입력은 수락된 계약과 증거다.
두 레포의 변경이 합류하면 통합 프로브를 실행한다. 이때 Master는 계약 전파, 배포 순서, rollback 조건을 본다.
뒤의 3.9에서는 백엔드와 프론트엔드 Worker가 각각 별도 lease로 움직이는 이유를 같은 상태 전이 안에서 설명한다.
9. 실행 상태와 영구 지식을 따로 갱신한다
작업이 수락되면 현재 실행 상태는 Work Ledger에 남긴다. 다음 세션이 Track을 재개하는 데 필요한 상태는 handoff에 남긴다.
현재 운영: handoff와 지식 승격의 임시 구조
최신 handoff 파일을 LIVE로 간주하고, 목표 구조에서는 Track당 LIVE handoff 한 건만 둔다. 반복해서 사용할 제품·코드 지식은 제품 레포 wiki로, 하네스·운영 지식은 operations-repo/docs로 승격한다. beads memory에는 정본 전문을 복제하지 않고 포인터만 둔다.
이 분리 때문에 이슈가 닫힌 뒤에도 필요한 지식은 Git 정본에 남고, wiki에 특정 작업의 시간순 진행 로그가 쌓이는 일을 막을 수 있다.
뒤의 3.17에서는 지식 저장 위치를 나누고, 3.18에서는 beads issue와 beads memory가 섞이지 않도록 분리한다.
10. 운영 루프가 주변 리스크를 같은 큐에 올린다
이 흐름은 기능 요청에만 적용되지 않는다. 운영 루프는 주변 리스크도 같은 그래프 위에 올린다. 어느 아침, 브리핑 루프의 야간 상태 스캔이 dev 환경 인증서의 만료를 감지했다.
Master는 이를 기능 작업보다 먼저 올리면서 영향 경로를 붙였다. 프론트엔드 dev 빌드의 코드 생성 단계는 dev 스펙을 https로 가져온다. 인증서 갱신 전에 CI 빌드를 누르면 코드 생성이나 검증 단계가 실패할 수 있고, 갱신 뒤에는 자동 갱신 타이머 상태까지 확인해야 재발을 막을 수 있었다.
그날의 큐는 인증서 갱신을 신규 선행 항목으로 얹어 재정렬됐다. 이 글에서 [강제]는 관측된 사실, [형성]은 그 사실을 만들거나 연결한 운영 구조, [판단]은 Master가 그 위에 올린 순서 결정이나 해석을 뜻한다. 이 사례에서 [강제]는 인증서 만료라는 관측값과 빌드 파이프라인 의존성이다.
[형성]은 아침 브리핑, 야간 스캔, cross-repo 영향 추적, 배포 큐가 같은 운영 루프에 들어와 있었다는 구조다. [판단]은 기능 작업보다 인증서 갱신을 먼저 올려야 한다는 Master의 순서 결정이다.
이 사례를 우연한 발견으로 읽으면 같은 시스템을 다시 만들 수 없다. daily ops briefing이 야간 상태와 운영 리스크를 훑고, cross-repo 영향 추적이 인증서 만료를 코드 생성, CI, prod 배포 열차에 연결했기 때문에 이 경보가 작업 큐 안으로 들어왔다. 다음 화면에서는 브리핑 루프가 Role State, 야간 상태, 당일 안건을 한 번에 올리고 작업 큐의 시작점을 만드는 장면을 봐야 한다.

다음 화면에서는 야간 스캔에서 올라온 인증서 만료 경보가 배포 큐로 연결되는 지점을 봐야 한다.
감탄함

뒤의 3.15에서는 이런 경보와 컨텍스트 품질을 Observability의 측정 대상으로 정리한다.
11. 다음 작업으로 가거나 승계한다
수락과 기록이 끝나면 Master는 다음 작업으로 넘어가거나 승계를 준비한다. 컨텍스트가 한계에 접근했거나 자연스러운 작업 마일스톤에 도달했다면 진행 중인 작업을 동결하고 thin handoff를 작성한다. 후임은 handoff, Work Ledger, Git 정본을 읽고 현재 역할, 활성 Track, 마지막 수락 결과, 다음 허용 행동과 금지 행동을 재진술한다.
전임이 정상적으로 handoff를 작성할 수 없는 장애 상황에서는 Recovery가 선행된다. 클라이언트, runtime, daemon, PTY, 프로세스를 확인하고 기존 실행이 살아 있으면 재부착한다. 기존 실행이 실제로 소멸했다는 증거가 있을 때만 후임을 만든다.
이 11단계가 하나의 요청을 처리하는 운영 루프다. 사용자의 지시는 Track이 되고, Track은 lease로 나뉘고, Worker는 evidence를 제출하고, Master는 수락과 Human Gate를 조율하고, 지식은 정본 위치로 승격되고, 다음 세션은 Work Ledger와 Git과 handoff로 같은 상태를 재구성한다.
뒤의 3.13에서는 후임 생성, 후임 검증, 전임 동결과 은퇴 조건을 Succession 규칙으로 정리한다.
sequenceDiagram
participant H as Human
participant M as Master
participant R as Repository Harness
participant W as Worker
participant A as Acceptance
participant K as Knowledge Store
H->>M: Task Request
M->>M: 역할과 Track 확인
M->>R: 레포 경계와 필요한 정본 확인
R-->>M: Repository Context
M->>W: lease 발급
W-->>A: Evidence Bundle 제출
A-->>M: Acceptance Decision
M->>K: 반복 지식 승격 후보 분류
M-->>H: 수락 결과와 다음 행동 보고
기본 용어 카드
Master Session
정의: Master Session
전체 작업을 조율하는 최상위 오케스트레이션 세션이다. 이 설계에서는 보통 당시 사용할 수 있는 추론 성능이 높은 모델이 이 역할을 맡는다. 예를 들면 Codex Sol이나 Claude Code Fable 5가 Master가 될 수 있다.
이 정의의 기준은 해당 세션에 부여된 역할과 책임이다. (2026년 7월 17일 기준)
Execution Worker
정의: Execution Worker
Master가 발급한 lease 안에서 작업을 수행하는 실행자다. 격리된 환경에서 움직이며, 작업 사본과 구현 과정에서 생긴 임시 상태만 소유한다.
Track
정의: Track
Track은 세션·Worker lease보다 길고 프로젝트 전체보다는 좁은 작업 흐름 단위다. 지금은 세션보다 오래가는 작업명으로 이해하면 되고, 뒤의 3.6에서 Workspace Runtime과 Track Registry의 상태 전이를 다룬다.
Work Ledger
정의: Work Ledger
현재 이슈와 작업 진행 상태를 기록하는 실행 상태의 정본이다. 이슈의 상태, 진행 메모, blocker와 다음 행동을 여기에 남긴다.
3부. 시스템 상세 및 내부 동작 명세
안내: 여기부터는 필요할 때 찾아오는 명세다. 처음 읽을 때는 앞에서 만든 문제의식이 어떤 상태와 계약으로 바뀌는지 큰 흐름만 보면 된다. 구현하거나 검산할 때 각 절의 상태, 입력, 출력, 중단 조건으로 돌아오면 된다.
앞에서 본 실패는 여기서 상태와 계약으로 바뀐다. 1부와 2부에서는 이 하네스가 왜 필요하며 어떤 원리로 작동하는지 설명했다. 3부에서는 그 개념을 상태와 인터페이스, 계약 테스트, 복구 및 승계 절차로 구체화한다. 상태 라벨은 온보딩 말미의 현재 상태 매트릭스가 정본이다.
이 장에서 Configured, Intended, Observed, Unknown을 다시 장문으로 풀어 쓰는 대신, 각 절은 자기 책임과 인터페이스를 설명한 뒤 필요한 곳에서 그 매트릭스를 가리키도록 구성하였다.
3부는 네 묶음으로 읽는다.
| 묶음 | 범위 | 역할 |
| A. 부팅과 경계 | 3.1~3.8 | 불변식, 소유권, Runtime Unit, Bootstrap, Context, Track, Role, Repository Harness |
| B. 실행과 수락 | 3.9~3.11 | Lease, Gate, Evidence, Acceptance, 단순성 판정 |
| C. 연속성 | 3.12~3.16 | Recovery, Succession, Lineage, Observability, Adapter |
| D. 지식과 구현 | 3.17~3.30 | 지식 정본, handoff, freeze, 시퀀스, 실패 처리, 구현 순서, 최종 모델 |
독자는 목적에 따라 다음 경로로 들어오면 된다.
| 경로 | 먼저 읽을 절 | 쓰임 |
| 구현자 | 3.1, 3.3, 3.8~3.11, 3.22, 3.27 | Unit 경계, lease, gate, evidence, 계약 테스트를 구현할 때 |
| 운영자 | 3.4, 3.6, 3.7, 3.12~3.15, 3.20, 3.24 | 세션, 역할, Track, 복구, 승계, 실패 처리를 집행할 때 |
| 문서·지식 관리자 | 3.2, 3.17~3.21, 3.25, 3.30 | SSOT, handoff, freeze, 지식 승격 기준을 검산할 때 |
각 컴포넌트는 네 질문으로 설명한다.
- 어떤 상태를 소유하는가
- 어떤 입력을 받는가
- 어떤 출력과 증거를 만드는가
- 어떤 조건에서 실행을 중단하는가.
다음 3.2에서 책임 경계와 actor topology를 표로 고정한다.
A. 부팅과 경계: 3.1~3.8
3.1 시스템의 기본 불변식
2부의 루프가 실제 운영에서 의미를 가지려면 먼저 깨지면 안 되는 선을 정해야 했다. 세션을 다시 붙일지 새로 만들지, Worker 보고를 받아들일지 말지, 어느 저장소를 정본으로 볼지 매번 기분으로 판단하면 하네스는 오래 버티지 못한다. 그래서 기능 목록보다 불변식을 먼저 적었다.
하네스 구현에서는 개별 기능보다 먼저 시스템이 절대로 위반해서는 안 되는 규칙을 코드와 테스트로 고정해야 한다. 기능이 정상적으로 보이더라도 이 규칙이 깨지면 전체 시스템의 신뢰성을 보장할 수 없다. 아래 표는 이후 절에서 반복해서 참조하는 색인이다.
| ID | 불변식 | 위반을 막는 방법 |
| INV-01 | 비가역적이거나 외부에 영향을 주는 최종 권한은 Human에게 남는다 | G3 승인 게이트 |
| INV-02 | 하나의 정보 유형에는 하나의 정본과 소유자만 둔다 (e.g. Master는 Repository 지식을 소유하지 않는다) | 다른 저장 위치에는 전문을 복제하지 않고 정본을 가리키는 포인터만 둔다 (Master는 레포 지식을 읽고 사용할 수 있지만 별도의 정본으로 복제하지 않는다) |
| INV-03 | Worker는 발급받은 lease 밖의 상태를 변경하지 않는다 (Worker는 자신의 결과를 최종 수락할 수 없다) | Worker는 결과와 증거를 제출하며, 별도의 수락 주체가 이를 판정한다 (경로·capability·worktree 격리) |
| INV-04 | 후임 검증이 끝나기 전에 전임 Master를 은퇴시키지 않는다 | Succession Verification Gate |
| INV-05 | 화면에서 보이지 않는 세션을 즉시 죽은 세션으로 판단하지 않는다 | 클라이언트, runtime, daemon, PTY, 에이전트 프로세스를 별도로 확인한다 |
| INV-06 | 같은 session ID를 동시에 두 번 resume하지 않는다 | 기존 실행 여부가 불명확하면 추가 resume이나 재스폰을 중단한다 (중복 session guard) |
| INV-07 | 하나의 Master 세션에는 한 번에 하나의 역할만 활성화한다 | 역할을 전환하기 전에 기존 역할을 완료하거나 파킹한다 (Role State와 Role Lock) |
| INV-08 | 현재 실행 상태와 영구 지식을 분리한다 | 진행 상태는 Work Ledger에, 장기 사실은 Git 정본에 둔다 (Work Ledger와 Knowledge Store 분리) |
| INV-09 | Agent의 자기 보고를 수락 증거로 사용하지 않는다 | 파일, diff, 테스트, 로그, 프로세스, 프로브 결과를 증거로 사용한다 |
| INV-10 | Architecture Freeze 이후 구현 문서가 새 책임을 만들지 않는다 | 새 Runtime Unit이나 책임 이동에는 별도 ADR과 승인이 필요하다 (동결 출처와 ADR 검사) |
| INV-11 | lineage를 다음 Master의 자동 지식 입력으로 사용하지 않는다 | Bootstrap 입력에서 lineage 제외 (승계 계보를 다음 세션의 판단 근거로 자동 주입하지 않는다) |
| INV-12 | scratchpad에는 유실돼도 되는 정보만 둔다 | 세션 이후에도 필요한 내용은 종료 전에 정식 정본으로 승격한다 |
불변식은 문서 기록과 검증 방식을 함께 가져야 한다. 검증 방식은 정보의 성격에 따라 나눈다.
- 파일과 정본 구조: 정적 검사, Git hook, pre-commit
- 인터페이스와 상태 전이: 계약 테스트
- 세션·프로세스·역할 상태: runtime guard
- 승계·복구·중복 실행: 시나리오 테스트와 프로브
예를 들어 Git hook은 Git 밖에서 실행 중인 중복 Master를 탐지할 수 없다. 반대로 runtime guard는 동일한 ADR이 두 정본 파일에 복제됐는지 판단하기 어렵다. 하나의 검사 방식으로 모든 불변식을 강제하려 해서는 안 된다.
불변식의 성격에 따라 강제 방법도 달라진다.
- 정적 검사는 canonical ID 중복, 금지된 경로의 문서, descriptor 형식, 동결 출처 누락을 검사한다.
- 계약 테스트는 Worker 자기 수락, G3 승인 우회, 역할 잠금 위반 같은 상태 전이를 실패 처리한다.
- Git hook은 commit이나 push 시점에 정본 중복과 문서 위치, Architecture Drift를 검사한다.
- 런타임 가드는 session ID와 Role State, approval state에 대한 원자적 잠금과 전이 규칙을 강제한다.
- 런타임 probe는 PID, PTY, lease, handoff, 중복 Master 같은 실제 실행 상태를 관측한다.
예를 들어 beads memory에 장문의 전문이 저장됐는지는 길이와 필수 포인터 필드를 검사한다. 동일한 session ID를 사용하는 둘 이상의 프로세스가 존재하는지는 PID와 커맨드라인, 세션 저장 경로를 대조하는 프로브로 확인한다. Git 밖의 허용되지 않은 경로에 운영 문서가 생성됐는지는 Git hook 하나만으로 완전히 차단하기 어렵다.
관리 대상 경로를 스캔하는 workspace guard나 주기적인 Probe 를 함께 사용해야 한다. 각 불변식에 대응하는 핵심 계약 테스트는 3.27에서 다시 정리한다.
3.2 책임과 소유권 모델
실패가 반복될 때마다 질문은 기능에서 소유권으로 이동했다. 누가 구현했는지보다 누가 최종으로 믿을 상태를 소유하는지가 더 중요했다. 소유권이 겹치면 후임 Master는 다시 추론해야 하고, 그 순간 오래된 복제본이나 Worker의 자기 보고가 정본처럼 끼어든다.
소유권은 누가 이 상태의 정본을 관리하고, 정해진 계약 안에서 변경하며, 그 결과에 책임지는가를 기준으로 판정한다. 누가 이 정보를 볼 수 있는가는 소유권 기준에서 제외한다. 소유권과 승인권도 구분해야 한다.
Repository Harness가 레포 지식의 정본을 소유하더라도, 외부 영향이 있는 변경에는 Human 승인이 필요하다. 소유권은 정본의 위치를 정하고 승인 게이트는 특정 행동의 실행 권한을 통제한다.
권한과 실행 주체
| 주체 | 소유하는 상태 | 수행할 수 있는 변경 | 소유하지 않는 것 |
| Human | 우선순위, 헌장, 역할 unlock, 외부 자격증명과 프로덕션 권한, 최종 권한 | 승인·거절, G3 행동 허가, 우선순위와 헌장 변경 | Worker 내부 구현 세부, 반복 가능한 기계적 집행 |
| Master Orchestrator | Track Registry, Role State, lease 대장, 승인 제안, 크로스레포 계획, 승계 상태 | 트랙 개설·파킹·종결, Worker 위임, 복구와 승계, 릴리즈 조율 | 레포 내부 코드와 지식의 정본, 외부 권한 |
| Repository Harness | 레포의 코드, 규칙, Wiki, 레포 내부 .planning, 빌드·테스트 계약 | 레포 컨텍스트 제공, 검증 수행, 레포 계약에 따른 변경 | 다른 레포와 워크스페이스 상태 |
| Execution Worker | lease 범위의 작업 사본과 임시 상태 | 지정 worktree 안의 조사, 코드 변경, 테스트, 증거 제출 | 영구 지식, 최종 수락, lease 밖의 상태 |
| Approval Manager | 승인 제안과 게이트 판정 상태 | 위험도 분류, 승인 요청, 만료 처리 | Human의 G3 결정 |
| Observability | 관측 기준선, 프로브 결과, 경보 | 측정과 경보 기록 | 관측 대상 자체의 정본 |
flowchart TD
H["Human<br/>우선순위·헌장·G3 최종 권한"]
M["Master Orchestrator<br/>Track·Role State·lease·승계 상태"]
R["Repository Harness<br/>레포 코드·규칙·Wiki·빌드·테스트 계약"]
W["Execution Worker<br/>lease 범위의 작업 사본·임시 상태"]
A["Approval Manager<br/>승인 제안·게이트 판정 상태"]
O["Observability<br/>프로브 결과·경보"]
H -->|"승인·거절"| M
M -->|"위임·수락 판단"| W
M -->|"필요한 정본 page-in"| R
W -->|"artifact·diff·테스트"| M
M -->|"G0~G3 분류 요청"| A
O -.->|"측정"| M
O -.->|"측정"| W
R -.->|"레포 계약 제공"| W

소유권 충돌이 발생하면 정보가 적용되는 범위를 먼저 판별한다.
- 하나의 레포에서 완결되는 상태면 Repository Harness로 내린다.
- 두 개 이상의 레포를 함께 봐야 의미가 있으면 Workspace Runtime으로 올린다.
- 외부 세계에 영향을 주거나 되돌리기 어려운 결정이면 Human에게 올린다.
관측하는 주체와 변경하는 주체도 분리한다. Observability는 Worker의 프로세스를 측정할 수 있고 수락은 별도 주체가 맡는다. 여기서는 소유권 경계만 확정한다.
저장 위치별 세부 역할은 뒤의 3.17 지식 아키텍처에서 Work Ledger, Git, beads memory, handoff, lineage, Notion, scratchpad로 나누어 고정한다.
3.3 Master Orchestrator의 내부 구성
Master를 하나의 큰 프롬프트로만 두면 실패했을 때 어디가 깨졌는지 알 수 없다. 부팅이 문제인지, 레포 선택이 문제인지, lease가 느슨했는지, 수락 게이트가 빠졌는지 분리해서 봐야 했다. 그래서 Master의 일을 Runtime Unit으로 쪼갰다.
Master Orchestrator는 서로 다른 상태를 다루는 Runtime Unit의 집합으로 구성한다. 아래 U1~U12 표가 12 Runtime Unit의 정본이다. 다른 장에서는 이 표를 반복하지 않고 필요한 Unit 번호만 참조한다.
AHE Runtime
Start
├── Bootstrap
├── Context Resolver
├── Workspace Runtime
└── Repository Runtime Loader
Execute
├── Worker Scheduler
├── Approval Manager
└── Role Runtime
Continue
├── Recovery Manager
├── Succession Manager
├── Lineage Recorder
└── Observability
Integrate
└── Adapter Layer
초기 구현에서 이 Unit들이 각각 별도 프로세스일 필요는 없다. 하나의 CLI 안에 존재하더라도 책임과 인터페이스의 분리, 곧 다음 조건을 만족해야 한다.
- 소유 상태가 구분돼 있다.
- 입력과 출력 타입이 명시돼 있다.
- 다른 Unit의 상태를 직접 덮어쓰지 않는다.
- 제품별 명령은 Adapter로 호출한다.
- 실패가 발생했을 때 어느 Unit이 상태를 복구할지 알 수 있다.
| Unit | 컴포넌트 | 핵심 책임 | 대표 입력 | 대표 출력 |
| U1 | Bootstrap | 최소 부팅 컨텍스트 적재 | Charter, Role State, 최신 LIVE handoff | Boot Context |
| U2 | Context Resolver | 현재 작업의 책임 경계와 capability 판정 | cwd, 사용자 요청, workspace map, repo metadata | Context Descriptor |
| U3 | Workspace Runtime | 트랙과 크로스레포 상태 관리 | Work Ledger, dependency map | Track State |
| U4 | Repository Runtime Loader | 필요한 Repository Harness만 lazy load | Context Descriptor | Repository Harness Context |
| U5 | Worker Scheduler | dispatch, lease 발급, reap, 예산 강제 | Task, repository, execution profile | Worker Lease, Worker Reference |
| U6 | Approval Manager | 행동의 위험도와 승인 게이트 분류 | Action Proposal, evidence | Gate Class, Approval State |
| U7 | Role Runtime | 역할 상태와 잠금, 전환 절차 관리 | Role State, switch proposal | Updated Role State |
| U8 | Recovery Manager | 장애 후 기존 세션 또는 작업 상태 복구 | handoff, Git, process state | Recovery Decision, Recovered Session |
| U9 | Succession Manager | 동결, handoff, 후임 검증, 전임 은퇴 | context signal, user request, runtime health | Succession Result, Successor Reference |
| U10 | Lineage Recorder | 승계 계보와 품질 지표 기록 | Succession Result | Lineage Entry |
| U11 | Observability | 프로브, 기준선, 경보, 수락 로그 관리 | runtime event, probe specification | Evidence, Alert |
| U12 | Adapter Layer | 외부 제품과 core의 결합 격리 | 추상 인터페이스 호출 | 도구별 실행 결과 |
3.4부터 각 Unit의 계약을 순서대로 설명한다.
3.4 Bootstrap
세션이 시작될 때 모든 문서를 읽히면 처음에는 편하다. 그러나 오래된 정보와 현재 규칙이 한꺼번에 들어오고 컨텍스트가 빨리 찬다. 부팅의 목적은 모든 것을 기억하는 데 있지 않다.
지금 어떤 정본을 읽어야 하는지 아는 상태로 들어가는 것이다. Bootstrap은 세션이 시작될 때 최소 정책과 현재 상태를 읽는 Unit이다. 세션이 다음 행동을 안전하게 결정할 수 있을 만큼의 최소 정보만 적재한다.
컨텍스트를 L0부터 L4까지 나누되, Bootstrap이 직접 적재하는 범위는 L0와 L1로 제한한다.
입력
- Master Charter
- L0 Policy Kernel
- 현재 Role State
- 최신 LIVE handoff
- 활성 Track을 찾기 위한 L1 포인터
| 계층 | 포함 내용 | 적재 시점 | 예시 |
| L0 Policy Kernel | 모든 상황에 적용되는 절대 규칙과 승인 정책 | 모든 세션 시작 시 직접 적재 | 프로덕션 DB 직접 write 금지, 자기 보고 단독 수락 금지 |
| L1 Workspace Index | 현재 역할, 활성 트랙, 최신 handoff와 정본 포인터 | 세션 시작 시 정해진 예산 안에서 적재 | 활성 트랙, Polsia-service 경로, 관련 issue ID |
| L2 Repository Context | 레포 규칙, 관련 ADR, planning, 검증 방법 | 대상 레포가 확정된 뒤 lazy load | 제품 레포 배포 runbook |
| L3 Task Context | 특정 이슈와 구현에 필요한 문서와 제약 | Worker lease를 발급할 때 적재 | 리포트 API spec, 관련 테스트 |
| L4 Trace Context | 과거 세션의 상세 기록 | 실패 조사나 증거 회수 시에만 조회 | 이전 세션 JSONL |
현재 부트스트랩의 실제 출력은 사람이 읽는 텍스트 블록이다.
[MASTER-BOOTSTRAP v1]
## Role State
## 활성 트랙
## Charter
[BD-PRIME-AUDIT]
[DUAL-INSTANCE]
## Alerts
부팅 순서
부팅 과정은 다음 순서로 진행된다. 마스터 에이전트 터미널 부팅이 완료된 시점에는 무엇을 읽어야 하는지를 아는 상태까지만 도달한다.
L2 이후의 정보는 현재 요청과 대상 레포가 확정된 뒤 필요한 만큼만 불러온다. L0와 L1에는 별도의 컨텍스트 예산을 둬야 한다. 예산을 초과하면 내용을 임의로 잘라서 주입하는 대신, 장문의 설명이나 중복 정보를 제거하고 정본 포인터로 바꾸도록 실패 또는 경보를 발생시킨다.
(대량 서브에이전트 fan-out으로 예산이 순식간에 소진된 경험이 이 규칙의 근거다.)
Session Start
│
▼
Load Charter and L0 Policy Kernel
│
▼
Read Role State and Latest LIVE Handoff
│
▼
Resolve Current Workspace and Active Tracks
│
▼
Load L1 Pointer Index
│
▼
Wait for Task Classification
sequenceDiagram
participant S as Session Start
participant B as Bootstrap
participant C as Charter
participant R as Role State
participant W as Work Ledger
participant P as L1 Pointer Index
S->>B: 새 세션 시작
B->>C: L0 Policy Kernel 확인
B->>R: 현재 Role State 확인
B->>W: 활성 Track과 최신 LIVE handoff 포인터 확인
B->>P: 필요한 정본 위치 확인
B-->>S: Task Classification을 기다릴 수 있는 Boot Context

Bootstrap의 제외 범위는 다음과 같다.
- 모든 레포의 Wiki를 읽지 않는다.
- 모든 beads memory를 전문으로 주입하지 않는다.
- 과거 lineage 전체를 읽지 않는다.
- 아직 선택되지 않은 레포의 runbook을 로딩하지 않는다.
다음 조건에서는 부팅 실패 또는 경보로 처리한다.
- Charter revision을 확인할 수 없다.
- 하나의 Track에 LIVE handoff가 여러 개 있다.
- Role State가 없거나 두 역할이 동시에 활성화돼 있다.
- L0·L1이 정해진 컨텍스트 예산을 초과한다.
Bootstrap 완료는 현재 요청을 어디로 라우팅할지 결정할 수 있는 상태를 뜻한다. L0는 모든 상황에 적용되는 정책 커널이다. Human 승인권, 금지된 행동, 정본 판별 원칙, 역할 전환 규칙, 증거 기준처럼 반드시 시작 시점부터 알아야 하는 내용이다.
L1은 현재 활성 트랙과 레포를 찾기 위한 포인터 인덱스다. 마스터 세션은 부팅이 끝났을 때 다음에 무엇을 어디서 읽어야 하는지만 알면 된다. 실제 제품 지식과 상세 runbook은 L2 이후의 lazy read 대상으로 둔다.
Bootstrap 완료의 기준은 아래 항목을 설명할 수 있는 상태다.
- 현재 Master의 역할은 무엇인가
- 어떤 트랙이 활성 또는 파킹 상태인가
- 즉시 금지되는 행동은 무엇인가
- 현재 상태를 복구하려면 어떤 handoff와 Work Ledger를 읽어야 하는가
- 특정 레포 작업이 들어오면 어느 Repository Harness를 적재해야 하는가
현재 운영: Bootstrap 관측 범위 상태는 온보딩의 상태 매트릭스를 따른다. 워크스페이스 루트 SessionStart 훅에서는 부트스트랩 스크립트와 bd prime --memories-only 실행이 구성되어 있고, root 범위 실행에서 Role State와 active tracks, BD audit이 관측됐다.
이 사실을 operations-repo local hook이나 모든 워커 런타임으로 확대하지 않는다. 컴팩션 직후의 회상 계측은 컨텍스트 손실을 측정하는 관측 절차이고, 뒤의 3.15에서 다룬다.
3.5 Context Resolver
같은 문장이라도 어느 경로에서 실행하느냐에 따라 의미가 달라진다. 워크스페이스 루트에서 받은 요청인지, 특정 레포 worktree 안에서 받은 요청인지, 여러 레포 계약을 함께 건드리는 요청인지 먼저 판별해야 한다. Context Resolver는 이 첫 분기를 맡는다.
Context Resolver는 현재 요청이 어느 책임 경계에서 실행돼야 하는지 판정한다.
입력
Context Resolver는 현재 작업 디렉터리(cwd)와 함께 대상 파일, worktree, 요청 내용을 비교해 레포를 결정한다.
워크스페이스 루트에서 특정 레포의 파일을 대상으로 작업할 수도 있고 별도의 worktree에서 Master가 실행될 수도 있다. 하나의 요청이 여러 레포를 동시에 가리킬 수도 있다. 그래서 다음 정보를 함께 비교해야 한다.
- 현재 경로와 대상 파일 경로
- Human 요청과 명시된 대상
- Human 승인과 정책 제약
- Git root, remote, branch, worktree metadata
- 현재 활성 트랙과 연결된 레포 목록
- 현재 Role State
- Repository descriptor
출력: Context Descriptor
context:
kind: "repository"
resolved_path: "/workspace/product-backend"
workspace_identity: "workspace-a"
repository_identity: "product-backend"
repo_set:
- id: "product-backend"
root: "/workspace/product-backend"
capabilities:
git_repo: true
warnings: []
판정 결과는 Context Descriptor로 만든다. track, current role, 금지 행동, 정본 포인터는 이 descriptor 위에 얹히는 상위 Context Envelope에서 다룬다.
| 필드 | 설명 | 예시 |
| kind | 현재 작업 경계 | workspace, repository, worktree, external |
| resolved_path | resolver가 확정한 기준 경로 | /workspace/Polsia-service |
| workspace_identity | 현재 워크스페이스 식별자 | workspace-a |
| repository_identity | 대상 레포. 워크스페이스 작업이면 null | Polsia-service |
| repo_set | 함께 판별된 레포 목록 | Polsia-service |
| capabilities.git_repo | Git 레포로 확인됐는지 여부 | true |
| warnings | 경계 판정 중 발견한 주의 사항 | [] |
여기서 capabilities는 Context Resolver가 새 권한을 부여한 결과와 구분된다. 현재 역할과 트랙, Repository Harness, Human 승인, 실행 환경이 각각 허용하는 범위의 교집합을 계산한 결과다. 어느 한 계층에서 금지한 행동은 다른 계층이 허용하더라도 capability에 포함하지 않는다.
role capabilities
∩ track scope
∩ repository capabilities
∩ environment permissions
∩ approval state
────────────────────────────
effective capabilities
예를 들어 Repository descriptor에 database-read capability가 있어도 현재 역할이 Architecture라면 실제 데이터 조회가 허용되지 않을 수 있다. 반대로 역할이 Release/Operations라도 Repository Harness가 direct-prod-db-write를 금지한다면 해당 행동은 capability에 포함되지 않는다.
Context Resolver의 판정 순서는 다음처럼 구성할 수 있다.
- 사용자 요청에 명시된 대상과 파일 경로를 확인한다.
- Git root와 worktree metadata로 실제 레포 경계를 확인한다.
- 활성 트랙이 참조하는 레포 목록과 비교한다.
- 하나의 레포 안에서 완결되면 repository 또는 git worktree로 분류한다.
- 둘 이상의 레포를 조율해야 하면 workspace로 분류한다.
- 외부 서비스나 프로덕션 시스템을 직접 대상으로 하면 external로 분류하고 승인 상태를 확인한다.
- 역할과 정책, 레포 규칙의 교집합으로 capability와 constraint를 계산한다.
판정이 불명확하면 쓰기 또는 실행 capability를 추정해서 추가하지 않는다.
읽기 가능한 metadata를 더 확인하거나, 작업을 제안 상태로 유지한 채 Human에게 대상 경계를 확인한다. Context Descriptor는 이후 Repository Runtime Loader와 Worker Scheduler, Approval Manager가 같은 경계 판정을 공유하게 만드는 계약이다.
각 컴포넌트가 대상 레포와 권한을 제각각 다시 추론해서는 안 된다.
구조 질의: code-review-graph 를 붙인 이유
경계 판정과 파견 판단에는 코드 구조 정보가 필요할 때가 있다.
여기에 code-review-graph를 붙였다. 해결하려던 문제는 레포 세 개의 임포트·호출 관계를 사람이 손으로 추적하면 토큰과 시간이 한도를 넘는다는 것이다. 시스템 안에서 맡는 기능은 파견 전 영향 반경 산정과 리뷰 컨텍스트 추출이다.
차용 이유는 Tree-sitter 기반 로컬 파싱이라 외부 키가 필요 없고 마스터가 파견 판단을 반복하려면 구조 질의가 싸고 빨라야 하기 때문이다. 실제 사례로는 로그인 무한 리다이렉트 루프를 실행 재현 없이 정적 분석만으로 원인 설계 결함(존재 기반 인증 판정)까지 지목한 진단이 있다. 여기서 존재 기반 인증 판정은 쿠키가 있다는 사실만으로 인증된 것으로 보는 판정이다.
당시 세션 기록 기준으로, 호출 관계를 따라가는 이 진단에 구조 그래프가 기여했다. 한계도 있다. 그래프에서 wiki 문서를 생성하는 흐름(grok-wiki 계열)은 검토 단계이고 미구현이다.
지금 그래프가 커버하는 범위는 코드 구조와 작업 의존성까지다.
3.6 Workspace Runtime과 Track Registry
채팅 세션과 Worker lease보다 긴 배포 준비나 아키텍처 정리는 세션 밖에서 이름과 상태를 가져야 했기 때문에 Track을 별도 단위로 두었다. Track은 장기간 유지되는 작업 흐름의 단위다. 한 번의 채팅 세션이나 하나의 Worker 작업보다 오래 지속되지만 프로젝트 전체보다는 좁은 작업 흐름이다.
예를 들면 다음과 같다.
- service-prod-launch
- agent-harness-architecture
- Polsia-service-observability
하나의 Track은 여러 Master 세션과 Worker lease를 거쳐 이어질 수 있다. 따라서 Track 상태가 특정 채팅 세션의 컨텍스트에만 존재해서는 안 된다. Track Registry는 각 Track의 현재 상태와 관련 정본 포인터를 관리한다.
Track 상태
| 상태 | 의미 | 허용되는 행동 |
| proposed | Track 레코드는 생성됐지만 아직 실행이 승인되지 않음 | 범위·위험·대상 레포 정의, 승인 요청 (Human 승인 대기) |
| active | 현재 실행 가능한 상태 | Worker dispatch, 상태 갱신, 역할 연결 (dispatch, update, role binding) |
| blocked | 외부 조건이나 승인, 의존성을 기다리는 상태 | 원인 조사, 증거 수집, 문서화. 차단 조건을 우회하는 실행은 금지 (조사와 문서화만 가능) |
| parked | 의도적으로 중단했지만 폐기하지 않은 상태 | 상태와 정본 포인터 보존. 새 Worker dispatch 금지 (상태 보존, 새 실행 금지) |
| closing | 구현이 끝나 수락과 정리를 진행하는 상태 | 최종 검증, 미결 lease 회수, 영구 지식 승격 |
| closed | 완료되고 수락된 상태 | 이력 조회만 허용 |
| cancelled | 더 이상 진행하지 않기로 결정한 상태 | 취소 사유와 이력 조회만 허용 |
Master는 새로운 요청을 받아 proposed Track 레코드를 만들 수 있다. 그러나 실제 active 전환과 Worker dispatch는 Human 승인 또는 사전에 정의된 정책 조건을 충족해야 한다. 이렇게 하면 “Master가 Track을 개설한다”는 책임과 “승인되지 않은 작업을 실행하지 않는다”는 게이트 규칙이 충돌하지 않는다.
권장되는 기본 상태 전이는 이렇다.
proposed ──► active ──► closing ──► closed
│ │ │
│ │ ├────► blocked ─────► active
│ │ └────► parked ─────► active
│ │
└──────────► cancelled
│
blocked / parked ─────► cancelled
상태를 건너뛰는 전이는 별도 정책이 없으면 허용하지 않는다. 예를 들어 active Track을 검증 없이 곧바로 closed로 바꾸면 수락과 지식 승격 절차가 생략된다.
Track Registry 스키마
| 필드 | 설명 |
trackid |
유일한 트랙 식별자 |
title |
사람이 읽을 수 있는 이름 |
status |
현재 Track 상태 |
roletag |
현재 연결된 역할 |
repositories |
대상 레포 집합 |
gatestate |
현재 승인 대기 또는 승인 상태 |
planningrefs |
각 레포 planning 포인터 |
workledgerrefs |
관련 Work Ledger 이슈 목록 (관련 beads issue 목록) |
latesthandoff |
현재 LIVE handoff 포인터 |
activeleases |
아직 종료되지 않은 Worker lease 목록 |
acceptedstate |
마지막으로 수락된 결과 포인터 |
openquestions |
아직 닫히지 않은 질문 |
blockers |
현재 진행을 막는 조건 |
| resumecondition | blocked 또는 parked에서 복귀할 조건 |
| updatedat | 마지막 상태 변경 시각 |
acceptedstate와 activeleases를 명시하면 무엇이 완료됐는가와 무엇이 아직 실행 중인가를 후임이 분리해서 확인할 수 있다. Track parking은 취소와 다르다. Track을 파킹할 때는 status: parked와 함께 재개에 필요한 상태를 기록해야 한다.
최소한 다음 내용을 함께 남겨야 한다.
- 마지막으로 수락된 결과
- 제출됐지만 아직 수락되지 않은 결과
- 실행 중이거나 중단해야 하는 Worker lease
- 열린 질문과 blocker
- 현재 역할과 다음에 필요한 역할
- 관련 Git, planning, Work Ledger 포인터
- 다시 활성화할 정확한 조건
- 재개할 때 처음 수행할 검증
이 정보가 없으면 후임은 중단된 작업을 완료된 것으로 오인하거나, 이미 끝난 조사를 처음부터 반복할 수 있다. Track 상태는 세션 밖에 영속돼야 한다.
현재 운영: Track 상태 관리
Work Ledger와 handoff, Git 포인터를 조합해 이 상태를 수동으로 관리한다. 참조 구현에서는 Workspace Runtime이 Track Registry의 일관된 상태 전이와 저장을 담당한다.
worktree 규율: repo당 1개
Workspace Runtime이 관리하는 실행 지형에는 worktree 규율이 하나 붙어 있다. 병렬 워커의 작업 사본은 격리하되, 사람이 상주하는 기본 worktree는 레포당 1개로 고정한다. 이 규율은 초기 병렬 실험의 실패에서 나왔다.
운영 초기에 워커 세션이 통제 없이 늘어나 워크트리끼리 충돌했고 누가 어떤 파일을 밟는지 아무도 답할 수 없었다. 세션과 워크트리를 전량 정리한 뒤, 독립 작업만 fan-out하고 합류 지점에 review gate를 두는 그래프형 파견 규율이 세워졌다. 뒤의 3.23에서는 이 규율을 크로스레포 작업 시퀀스로 다시 연결한다.
3.7 Role Runtime
같은 Track 안에서도 판단 기준은 바뀌며, 배포 역할로 잠긴 세션이 갑자기 아키텍처를 고치거나 집필 역할이 하네스 코드를 수정하면 승인 경계가 섞이므로 Role Runtime은 지금 이 Master가 무엇을 할 수 있고 무엇을 미뤄야 하는지 고정한다. Role은 Master가 현재 어떤 종류의 판단을 우선하고 어떤 행동을 제한받는지 나타낸다. Track이 무슨 작업을 이어가고 있는가를 나타낸다면, Role은 현재 어떤 책임과 판단 기준으로 그 작업을 처리하는가를 나타낸다.
예를 들어 Architecture 역할에서는 설계와 인터페이스 정의를 수행하지만 실제 파일 변경이나 배포를 하지 않는다. Release/Operations 역할에서는 동결된 설계를 다시 해석하지 않고 배포 준비, 검증, 운영 절차를 집행한다. 현재 운영 중인 헌장은 역할을 일곱 개로 나누었다.
| 역할 | 주요 책임 | 금지되는 대표 행동 |
| Architecture | 책임 경계, 소유권, 인터페이스, ADR 설계 | 역할 전환 없이 제품 코드 구현이나 배포 수행 |
| Research | 증거 수집, 가설 검증, 원인과 선택지 조사 | 조사 결과를 근거 없이 확정하거나 프로덕션 변경 수행 |
| Reference Implementation | 동결된 설계를 타입과 인터페이스, 코드로 변환 | 새 설계 원칙이나 Runtime 책임 추가 |
| Feature Implementation | 승인된 제품 기능 구현과 검증 | 설계 재해석, lease 밖 스코프 확대 |
| Release / Operations | 배포 준비와 조율, 환경 검증, runbook 집행 | 릴리즈 중 임의로 아키텍처 변경 |
| Incident Response | 장애 범위 축소, 증거 수집, 완화와 복구 | 증거와 승인 없이 광범위한 수정 수행 |
| Maintenance | 저위험 정비, 의존성 및 문서 관리 | 정비를 명목으로 기능이나 책임 추가 |
역할 집합 자체는 조직마다 다르게 정의할 수 있다. 실제 업무와 위험 모델에 따라 역할을 합치거나 나눌 수 있다. 중점은 Master 세션에서는 한 번에 역할 하나만 활성화하고 역할 전환은 명시적인 상태 전이로 처리한다는 데 있다.
Role State
| 필드 | 설명 |
currentrole |
현재 활성 역할 |
lockstate |
역할이 잠겨 있는지 여부 |
lockedby |
Human, Charter, Track 중 잠금 주체 |
startedat |
현재 역할을 시작한 시각 |
completioncriteria |
역할을 완료했다고 판정할 조건 |
allowedactions |
역할에서 허용되는 행동 범위 |
prohibitedactions |
역할 중 금지되는 행동 |
returnrole |
임시 역할이 끝난 뒤 복귀할 역할 |
trackbinding |
현재 역할과 연결된 Track |
handoffref |
이전 역할의 완료 또는 파킹 기록 |
실제 capability는 Role State와 Track scope, Repository descriptor, approval state의 교집합으로 계산한다. 역할의 allowedactions만으로 Repository Harness나 approval state를 우회할 수 없다. 역할 전환 흐름은 다음과 같다.
Current Role
│
▼
Receive New Task
│
▼
Does Task Belong to Current Role?
┌─┴───────────────┐
Yes No
│ │
▼ ▼
Continue Complete or Park Current Role
│
▼
Write Role Handoff
│
▼
Request or Verify Unlock
│
▼
Switch Role
│
▼
Recompute Capabilities
현재 역할과 맞지 않는 요청이라면 다음 순서를 따른다.
- 현재 역할의 완료 조건을 충족했는지 확인한다.
- 완료할 수 없다면 현재 상태를 파킹한다.
- 수락된 결과와 미수락 결과, 열린 질문, blocker를 역할 handoff에 기록한다.
- 역할 잠금의 주체와 unlock 조건을 확인한다.
- 필요한 승인을 받은 뒤 currentrole을 변경한다.
- 새 역할과 Track, Repository 규칙을 기준으로 capability를 다시 계산한다.
역할 전환이 발생해도 Track은 유지된다. 같은 Track 안에서 Research를 마친 뒤 Feature Implementation으로 이동한다. 반대로 Track을 전환하면서 같은 역할을 유지할 수도 있다.
예를 들어 Release/Operations 역할로 한 제품의 배포 Track을 파킹하고 다른 제품의 배포 Track으로 이동할 수 있다. 현재는 Role State와 헌장, handoff를 읽어 이 절차를 수동으로 집행한다. 참조 구현의 Role Runtime은 다음 위반을 차단해야 한다.
- 동시에 두 역할이 active가 되는 상태
- 잠긴 역할을 승인 없이 변경하는 전이
- 기존 역할을 완료하거나 파킹하지 않은 전환
- 새 역할에서 금지된 capability의 실행
- 임시 역할 종료 후
returnrole과 복귀 조건이 유실되는 상태
현재 운영: 역할 정의 층과 Role State 선언 층의 이층화 처음에는 역할 체계를 단층으로 보았다. 운영을 거치며 두 층으로 나뉘었다.
아래 층은 역할 정의다. 일곱 역할의 책임과 금지 행동을 헌장 문서가 소유하며 좀처럼 바뀌지 않는다. 위 층은 Role State 런타임 선언이다.
현재 세션이 어느 역할로 잠겨 있고 나머지 역할이 동결(frozen) 상태인지를 세션이 매번 선언한다. 집행도 기계로 옮겨졌다. 매 사용자 턴마다 훅이 Role State 한 줄을 컨텍스트에 주입해, 세션이 자신의 역할과 잠금 상태를 잊을 수 없게 만든다.
이 훅은 상태를 기계로 노출하는 장치이지 모델 행동을 물리적으로 막는 샌드박스가 아니다. 준수는 Role State 선언 규율, Proposal 승인, 수락 게이트가 함께 만든다. 세션 시작, 모든 역할 전환, 소규모 트랙 개시 시점에는 Role State 블록(현재 역할, 잠금 여부, 동결된 역할, 해제 조건)을 발화하는 규율이 붙어 있다.
역할 전환은 여전히 Proposal과 승인 절차를 거치는 명시적 상태 전이이고 승계와는 분리된다. 후임은 전임과 같은 역할과 잠금을 이어받는다.
3.8 Repository Harness

마스터 → 워커에게 위임할 때 모습 (claude code 마스터 → codex 워커에게 orca cli 를 통해서 파견보낸 상태다.)
정의: Repository Harness 레포마다 붙는 운영 계약이다. 해당 레포와 함께 버전 관리되고 같은 생명주기를 따른다. 레포 내부의 지식, 규칙, 계획, hooks, skills, runbook, 빌드 및 테스트 진실을 이 계층에서 관리한다.
이 글에서는 이를 Karpathy가 설명한 LLM Wiki 하네스와 맞닿아 있는 영역으로 본다.
Master가 모든 레포의 규칙을 중앙에서 외우기 시작하면 다시 중복 정본이 생긴다. 레포 안에서 완결되는 진실은 레포가 소유해야 한다. Repository Harness는 Master가 해당 레포의 진실을 읽고 검증하는 공식 입구다.
Repository Harness는 레포마다 붙는 운영 계약이다. AHE 원칙을 개별 레포에 적용하는 경계다. Master가 특정 레포에서 작업하려면 해당 Repository Harness가 제공하는 인터페이스로 지식과 실행력, 검증 방법을 확인해야 한다.
| 인터페이스 | 책임 | Master 사용 방식 |
| repo.KnowledgeStore | wiki, ADR, postmortem의 정본 제공 | 검색하거나 경로 포인터를 보유 |
| repo.Rules | 머지, 브랜치, 코딩, 보안 규칙 | Worker 브리핑에 필요한 부분만 주입 |
| repo.Planning | 레포 내부 페이즈와 실행 계획(.planning 산출물 포함) | Track 실행 상태와 분리해 계획 포인터로만 참조 |
| repo.Interceptor | hooks와 정책 강제 | 존재 여부와 capability 확인 |
| repo.Memory | 레포 범위 포인터 검색 | 전문 복사 없이 검색 위임 |
| repo.Runbooks | 배포, 복구, 운영 절차 | 실행 전 해당 절차 조회 |
| repo.Skills | 레포 특화 작업 방법 | Worker profile에 지정 |
| repo.Workers | 허용된 실행 진입점 | Scheduler를 통해 호출 |
| repo.Verification | 빌드, 테스트, lint, 프로브 | 결과를 수락 증거로 사용 |
repo.Memory는 레포 내부의 정본을 빠르게 찾기 위한 검색 포인터 계층이다. 각 레포는 최소한 다음과 같은 descriptor를 제공하는 편이 좋다.
repository:
id: Polsia-service
root: /workspace/Polsia-service
knowledge_root: docs/wiki
planning_root: .planning
rules:
- AGENTS.md
- docs/wiki/guides/development.md
verification:
unit_test: "pnpm test"
lint: "pnpm run lint"
build: "pnpm run build"
capabilities:
- backend
- database-read
- docker
prohibited:
- direct-prod-db-write
descriptor는 해당 레포 안에서 버전 관리해야 한다. Master의 Workspace Memory에 복사본을 만들어 별도로 관리하면 Repository Harness와 Master 중 어느 쪽이 최신인지 다시 판별해야 한다.
planning_root는 레포 하네스 내부의 계획 루트다. Master Harness의 Track 상태나 Work Ledger를 대체하지 않는다.
Master는 descriptor로 다음 내용을 확인한다.
- 이 레포의 정본 지식은 어디에 있는가
- 현재 계획은 어디에서 읽는가
- 어떤 규칙을 먼저 적용해야 하는가
- 어떤 검증 명령을 실행해야 하는가
- 어떤 capability를 제공하며 무엇을 금지하는가
descriptor에 적힌 경로와 실제 레포 상태가 일치하지 않으면 Repository Drift로 경고하고 잘못된 경로가 수락 증거로 사용되지 않게 해야 한다. Repository Runtime Loader는 Context Resolver가 대상 레포를 확정한 뒤 해당 Repository Harness만 적재한다.
현재 운영: 레포별 하네스의 실물 구성과 Lazy Loader 상태
이 워크스페이스의 Repository Harness는 세 층으로 나눠 말해야 한다. 첫째, 레포와 함께 배치된 정적 하네스 파일과 규약이다. 둘째, 대상 레포가 확정된 뒤 필요한 하네스만 읽는 Lazy Loader 설계다.
셋째, 실제 세션에서 훅과 스킬이 언제 발동했는지를 보여 주는 관측 증거다. 이 셋을 섞으면 정적 파일의 존재를 워커 런타임 강제로 과장하게 된다.
상태 표기는 온보딩의 상태 매트릭스와 같은 C/I/O/U(Configured/Intended/Observed/Unknown)를 그대로 쓴다.
| 레이어 | 확인된 내용 | 상태 | 본문에서 허용되는 표현 |
| 정적 Repository Harness | 레포별 규약 문서, .planning, .agent, hooks, 검증 명령, runbook이 존재한다. |
C | 레포와 함께 버전 관리되는 운영 계약이 있다. |
GSD와 .planning |
백엔드 레포에 .planning과 GSD 흔적이 남아 있고 planning context를 보존한다. |
C | 조사·계획 포인터로 남아 있다. 현재 실행 절차를 관리한다고 쓰지 않는다. |
| Repository Runtime Loader | Context Resolver 뒤에 필요한 하네스만 지연 로딩하는 구조를 목표로 둔다. | I | 설계상 Lazy Loader다. 자동 실행이 관측됐다고 쓰지 않는다. |
| Master 구성 훅 | workspace root의 bootstrap, bd prime, Role State 주입, dispatch warning이 구성되어 있다. |
C | root hook 범위에서 구성됐다고 쓴다. |
| Master 관측 훅 | workspace root의 bootstrap, bd prime, Role State 주입, dispatch warning 실행 증거가 있다. |
O | root hook 범위에서 관측됐다고 쓴다. |
| Worker 런타임 지시 로드 | AGENTS/CLAUDE와 .agent 지시가 worker 세션 초기 컨텍스트에 로드됐다. |
O | Repository Harness 지시 로드는 worker 관측으로 쓴다. Lazy Loader 자동 실행과 섞지 않는다. |
| Worker code-review-graph | worker 세션에서 code-review-graph MCP 접근과 PostToolUse graph 갱신이 관측됐다. | O | MCP 접근과 증분 갱신 hook은 worker 관측으로 쓴다. |
| Worker travelog 정의 | travelog 스킬 정의가 존재한다. | C | Configured로 쓴다. |
| Worker travelog 적용 | worker 세션에서 skill discovery 노출과 SKILL.md 적용이 관측됐다. | O | Partial Observed로 쓴다. slash 호출면과 섞지 않는다. |
| Worker travelog slash 호출면 | API형 worker 세션에서 slash command dispatch는 관측하지 못했다. | U | 미관측으로 둔다. |
| Worker 미관측 hook | Lazy Loader 자동 실행, PreToolUse 차단, UserPromptSubmit stdout은 별도 관측하지 못했다. | U | 미관측으로 둔다. 관측된 hook과 차단 hook을 섞지 않는다. |
레포별 예시는 다음 정도로 제한한다.
- 백엔드 레포에는 API 계약, 권한, soft-delete, pagination, 예외 처리 규칙처럼 서버 품질을 잡는 규약이 있다.
- 프론트엔드 레포에는 route group, admin과 user-site의 경계, 디자인 재사용 범위, i18n, 화면 검증 규칙이 있다.
- 운영 레포에는 master operations 정본, lineage, fact ledger, redaction ledger, blame과 postmortem, 배포 runbook이 있다.
- 제품 코드 레포(Polsia-service)의 하네스에는 AGENTS/CLAUDE 통일 규약,
.agent/구조, beads, code-review-graph, travelog 스킬, 구현·검증 루프의 리뷰 게이트가 붙는다.
훅의 적용 범위도 별도 표로 둔다.
| 위치 | Hook | 적용 범위 | 상태 |
| 워크스페이스 root | SessionStart bootstrap, bd prime --memories-only |
workspace root cwd guard 안에서 부팅 컨텍스트와 Beads audit을 올린다. | O |
| 워크스페이스 root | SessionStart source=compact compaction probe |
compact 직후 회상 계측을 실행한다. | O |
| 워크스페이스 root | UserPromptSubmit Role State 주입 |
현재 역할과 잠금 상태를 텍스트로 노출한다. 물리적 샌드박스는 아니다. | C |
| 워크스페이스 root | PreToolUse dispatch warning |
Bash에서 grok/codex 직접 호출 시 경고한다. 모든 connector 경로 강제는 미확인이다. |
O |
| operations-repo local | code-review-graph 계열 | 이 레포 안의 보조 구조 분석과 갱신이다. bootstrap hook으로 쓰지 않는다. | C |
| 백엔드 레포 | no-emoji/no-bak, code graph, load-context 계열 | 백엔드 레포의 정적 hook 구성이다. GSD 전용 hook으로 확인되지 않는다. | C |
| 프론트엔드 레포 | code-review-graph 계열 | 프론트엔드 레포의 제한적 hook 구성이다. | C |
따라서 이 절의 결론은 좁다. Repository Harness의 파일과 설정은 확인됐고, Worker 세션에서 일부 지시 로드와 graph hook 발동이 관측됐다. Lazy Loader는 설계 계약이며, 관측된 hook을 차단 hook이나 slash 호출면까지 확장하지 않는다.
GSD 세부 상태와 도구 선택 기준은 앞의 Tooling 절에서 다룬다.
B. 실행과 수락: 3.9~3.11
3.9 Worker Scheduler와 Lease
정의: Lease Worker에게 작업을 맡길 때 발급하는 위임 계약이다. 작업 범위, 대상 레포와 worktree, 사용할 모델, 시간 및 토큰 예산, 제출해야 할 결과물을 하나로 묶는다.
워커 폭주 사고 뒤에는 "작업해 줘"라는 말만으로 부족하고 Worker가 레포, worktree, 예산, 금지 조건, 제출물을 알아야 하며 그 묶음이 lease라는 점이 분명해졌다. 하나의 lease는 다음 질문에 답해야 한다.
- 어떤 작업을 어떤 모델에 맡길지
- 어느 worktree에서 실행할지
- 어디까지 변경할 수 있는지
- 시간과 토큰을 얼마만큼 허용할지
- 어떤 증거를 제출해야 하는지
- 어떤 결과를 제출해야 하는지
이 절은 lease 스키마와 상태 전이의 정본이다. 여기서는 Worker가 어떤 범위와 상태로 움직이는지만 고정한다. 승인 등급은 뒤의 3.10에서 Gate 분류로 다루고, 제출 증거와 수락 기준은 3.11에서 Evidence와 Acceptance로 다룬다.
전체 작업 흐름은 3.22에서, 크로스레포 의존성은 3.23에서 연결한다.
Worker Lease 스키마
| 필드 | 설명 |
leaseid |
변경되지 않는 위임 식별자 |
trackid |
소속 Track |
taskid |
Work Ledger 이슈 또는 내부 태스크 |
repositoryid |
대상 레포 |
worktreepath |
격리된 작업 경로 |
workerprofile |
모델, effort, skill, 실행 방식 |
scope |
허용된 파일과 작업 범위 |
constraints |
금지 행동과 안전 규칙 |
contextrefs |
필요한 정본 문서 포인터 |
expectedartifacts |
제출해야 할 파일과 산출물 |
verificationplan |
실행해야 할 test, lint, build, probe |
budget |
토큰, 시간, 재시도 제한 |
expiresat |
lease 만료 시각 |
status |
현재 lease 상태 |
sideeffectpolicy |
외부 부수효과 허용 범위 |
권장 상태 전이는 이렇다.
issued
│
▼
running
│
├────────► failed ────────┐
├────────► expired ───────┤
├────────► cancelled ─────┤
│ │
▼ │
submitted │
│ │
├─ changes requested ─► running
│
▼
accepted │
│ │
└──────────────┬──────────┘
▼
reaped
accepted 상태는 Worker가 설정할 수 없다. Worker는 submitted까지만 전이할 수 있고 별도의 수락 주체가 evidence bundle을 검토한 뒤 accepted를 결정한다.
stateDiagram-v2
[*] --> issued
issued --> running
running --> submitted
running --> failed
running --> expired
running --> cancelled
submitted --> accepted
submitted --> changes_requested: changes requested
changes_requested --> running
accepted --> reaped
failed --> reaped
expired --> reaped
cancelled --> reaped
reaped --> [*]

reaped는 성공 판정과 분리된 자원 회수 상태다. Worker 프로세스와 임시 자원, worktree에 대한 lease가 회수됐다는 뜻이다. 실패하거나 만료된 lease도 조사와 증거 보존이 끝나면 reap할 수 있다.
위임 흐름은 다음과 같다.
Master
│
│ create task envelope
▼
Worker Scheduler
│
├─ resolve repository
├─ validate role and capabilities
├─ allocate isolated worktree
├─ attach scoped context
├─ set budget and expiry
└─ issue lease
│
▼
Worker
│
├─ inspect
├─ implement
├─ self-check
└─ submit artifacts and evidence
Worker는 lease에 포함된 범위 안에서만 작업한다. 범위 밖의 변경이 필요하다고 판단하면 다음 정보를 담은 change proposal을 Master에게 제출한다. 예를 들어 백엔드 태스크를 수행하던 중 프론트엔드 계약 변경이 필요해졌다면, 프론트엔드 레포를 직접 수정하는 대신 범위 변경을 요청한다.
- 추가로 변경해야 하는 대상
- 현재 lease만으로 해결할 수 없는 이유
- 예상 영향 범위
- 필요한 레포와 capability
- 기존 검증 계획에 추가해야 할 항목
Master는 이를 보고 기존 lease를 수정할지, 별도의 Worker를 만들지, 크로스레포 Track으로 전환할지 결정한다. Scheduler는 예산도 강제해야 한다. 토큰이나 실행 시간, 재시도 횟수가 한도를 넘으면 현재 상태와 artifact를 보존한 뒤 중단하거나 새로운 승인을 요청한다.
현재 운영: 모델 라우팅과 dispatch gate worker_profile의 모델 라우팅은 현재 다음 규율로 운영된다.
- Master는 codex, cursor agent, grok, claude를 워커로 파견한다.
- 무거운 구현은 구현 특화 워커(codex 계열)로 라우팅한다.
- 리뷰는 3-vote 구성으로 라우팅한다.
- 인증 토큰이나 권한을 만지는 보안 계열 작업은 Master 밖의 독립 상설 세션이 전담한다.
이 세션은 Master 세대와 수명을 같이하지 않고, 보고는 파일로 남겨 Human이 직접 검토한다. Master는 보안 콘텐츠를 읽지도 요약하지도 않는다. 이 분리는 안전장치 폴백으로 세션의 실행 모델이 교체되는 모델 드리프트를 세 세대에서 겪은 뒤, 보안 경로 접근을 막는 hook과 함께 배선됐다.
이 라우팅 규율의 기원은 실패 기록이다. 운영 초기에 리서치 fan-out이 계정 토큰을 대량으로 태운 사건이 포스트모템으로 남았고 열흘 뒤에는 파견 때마다 모델 선택을 점검받는 일상 규율이 되어 있었다. 모델 비용 지적도 같은 회고록에 남았다.
[강제] 문체 탐지 작업이 진행 중일 때 Human이 작업을 중단시키고 토큰 최적화 모드로 다시 호출하라고 지시했다. [형성] 당시 Master는 스킬의 기본 모델 배치를 그대로 따랐다. 이전 토큰 소각 포스트모템이 이미 메모리와 운영 규율에 올라와 있었다.
[판단] Master의 사후 해석은 "스킬 기본값을 안전한 기본값으로 취급했다"였다. 이 해석은 변명이 될 수 있어 행동 기록과 분리한다. 관측된 행동은 고비용 모델 파견, Human의 중단, 단계별 저비용 모델 재배치, 재파견 순서다.
이후 모델 선택은 품질 요구와 작업 성격, 예산을 함께 포함한 lease 조건으로 다룬다. 규율은 문서로만 남지 않고 게이트로 배선됐다. dispatch gate는 파견마다 reason code를 요구하고 파견 프롬프트의 문자 기준 한도(50만, 상한 100만)와 30분 중복 윈도우를 검사하고 통과한 파견에만 티켓을 발권한다.
티켓은 runtime 매칭, TTL 600초, 1회 소비 규칙을 갖는다. 게이트 통과 기록은 파견 원장에 남고 register probe가 산출물에서 작업 식별자가 실제로 출력되는지 확인한다. 검증 없는 등록은 검증되지 않은 작업으로 거부된다.
게이트 원장과 티켓은 기계 텔레메트리이고 수락·검증 결과는 Work Ledger로 승격한다. 이 게이트가 Master 자신에게 되돌아온 장면도 있다. [강제] 워커 파견 전건이 게이트와 원장을 통과해야 한다는 규칙은 이미 있었다.
[형성] 훅은 주로 특정 워커 경로를 경고하도록 배선돼 있었다. Master는 Agent tool 직접 파견도 같은 enum에 들어간다는 사실을 보면서도 훅 경고가 없다는 이유로 사각을 방치했다. 기록상 세 건의 에이전트 파견이 dispatch gate 없이 실행됐다.
Human의 지적 뒤 Master가 위반을 자백했다. 정확한 Human 발화 원문은 공개 본문에서 재현하지 않는다. 확인되는 것은 지적 직후의 자백, 진행 중 작업의 소급 게이트 통과, 완료된 작업의 검증 불가 상태를 원장에 위반으로 남긴 조치다.
[판단] 당시 Master는 "훅이 잡지 않으면 정책 밖"이라고 오해한 것으로 회고했다. 이 판단은 사후 재구성일지도 모른다. 절차상 역할 잠금이 더 중요했다.
그 시점의 역할은 집필·검증 레인이었기 때문에 하네스 자체 수정은 즉시 수행하지 않았다. 대신 Agent tool 파견도 예외 없이 게이트 대상이라는 규칙을 승격했다. 하네스 수정은 별도 개선 트랙 제안 한 줄로 남겼다.
파견과 회수의 실제 장면
이 절의 lease 규칙이 실제로 어떻게 도는지 보여 주는 장면이 세션 기록에 남아 있다. 같은 문제를 두 접근으로 나눠 구현 잡과 감사 잡을 분리 발행했고 1차 워커는 실행 위치가 샌드박스 경계에 막혀 부분 구현으로 때우는 대신 정직하게 반려당해 왔다.
Master는 계약에 개정 사유를 기입하고 게이트를 재통과시킨 뒤 레포별로 두 잡으로 분할 파견했다. 두 잡이 착륙하면 Master가 통합 검증(파이프 케이스와 동시성 실측)을 직접 돌리고 리뷰 게이트를 거친 뒤에 수락 여부를 판정한다. 워커의 자기 보고를 바로 수락하지 않고 통합 검증과 자동 복귀 기준으로 묶는 구조다.
flowchart LR
A["1차 파견"] --> B["샌드박스 경계 반려"]
B --> C["계약 개정 사유 기록"]
C --> D["레포별 lease 재발급"]
D --> E["worker_done 회수"]
E --> F["통합 검증: 파이프 케이스·동시성"]


워커가 규칙을 읽고도 해석을 틀리는 경우도 있다. 한 워커는 "Work Ledger 도구의 git 연동 금지" 규칙을 커밋 전체 금지로 오독해 commit을 멈춘 채 완료 보고를 보냈다.
Master는 오독을 정정하고 실제 권한 경계(커밋은 허용, 원장 도구의 git 조작만 금지)를 재설명한 뒤 재파견했다. lease의 constraints는 쓰기 뒤에도 해석과 집행을 바로잡는 책임까지 포함한다. 새 방향을 찾는 탐색은 lease의 scope로 분리한다.
디자인 방향 제안이 닫힌 결정과 충돌하면 Master가 브레이크를 걸되, 더 세련되게 만들고 싶다는 요구 자체는 유효하므로 코드 무변경 조건의 read-only 디자인 패널 워커들을 발행한다. 방향 탐색, 현행 비평, 접근성 감사만 하고 구현은 하지 않는 계약이다. 창의적 탐색을 바로 구현으로 잇지 않고 read-only consultation으로 분리하는 하네스 패턴이다.
이 절에는 lease 관점의 규칙만 남긴다. 계약 우선 병렬 개발의 핵심은 백엔드 계약을 임시 가정으로 쓰더라도 수락은 검증된 계약을 기준으로 한다는 점이다. 뒤의 3.23에서 이 규칙을 크로스레포 시퀀스로 다시 연결한다.
백엔드와 프론트엔드가 같은 API 계약에 의존한다면 각 워커 lease에는 임시 계약의 위치, 생성 타입으로 치환할 조건, 후속 codegen 검증 항목이 명시되어야 한다. 병렬 디스패치의 원시 계약 전문을 확인하지 못한 사례는 부분 증거로만 다루고, 확인된 사실과 운영 해석을 섞지 않는다.
3.10 Approval Manager와 Gate Model
자동화는 전부 막으면 무의미하고 전부 열면 위험하다. SQL 파일을 작성하는 행동과 프로덕션 DB에서 실행하는 행동은 같은 명령군처럼 보여도 효과가 다르다. Gate Model은 행동의 이름보다 외부 효과와 되돌리기 가능성을 기준으로 승인선을 긋는다.
자동화와 통제 사이의 기준을 게이트로 정한다. 모든 행동에 Human 승인을 요구하면 자동화의 이점이 사라진다. 모든 행동을 자동 허용하면 권한 경계가 사라지고 통제가 어려워진다.
행동의 실제 효과와 가역성에 따라 승인 수준을 나눈다. 아래 표가 Gate Model의 기준이다. 이 표에서 G0~G3 승인선을 고정하고, 뒤의 3.22에서는 같은 Gate Decision이 정상 작업 시퀀스 어디에서 계산되는지만 보여 준다.
| Gate | 성격 | 예시 | 승인 방식 |
| G0 | read-only, 부수효과 없음 | 파일 읽기, Git log, 테스트 목록 조회 | 자동 허용 |
| G1 | 로컬이며 가역적인 변경 | worktree 코드 수정, 로컬 테스트, 정책이 허용한 로컬 commit | 역할·레포 정책 안에서 자동 허용 |
| G2 | 공유 상태 변경 | 원격 branch push, MR 생성, 공유 artifact 게시, 이슈 상태 변경, 이슈 트래커 상태 변경 | 조건부 승인 또는 사전 위임 |
| G3 | 프로덕션·외부·비가역적 영향 | 배포, 프로덕션 DB write, 외부 메시지 발송, 프로덕션 권한 사용, 자격증명 사용 | Human의 명시적 승인 필수 |
Gate 분류에는 단순 명령 이름보다 실제 효과를 기준으로 삼아야 한다. 예를 들어 격리된 worktree 안의 로컬 commit은 외부 상태를 바꾸지 않으므로 정책에 따라 G1일 수 있다. 같은 commit을 원격 branch에 push하면 공유 상태가 바뀌므로 G2다.
SQL 파일을 작성하는 것은 G1일 수 있지만 프로덕션 데이터베이스에서 실행하는 것은 G3다. 배포 계획을 작성하는 것은 G0 또는 G1일 수 있지만 실제 배포를 실행하면 G3다. 행동을 실행하려면 Gate 등급과 함께 다음 조건을 모두 만족해야 한다.
Role permits action
∩ Track scope includes target
∩ Repository permits capability
∩ Gate approval is valid
──────────────────────────────
Action may execute
flowchart TD
A["Action Proposal"]
B{"부수효과 없음"}
C["G0<br/>read-only"]
D{"로컬이며 가역적인 변경"}
E["G1<br/>역할·레포 정책 안에서 자동 허용"]
F{"공유 상태 변경"}
G["G2<br/>조건부 승인 또는 사전 위임"]
H["G3<br/>Human의 명시적 승인 필수"]
I{"Role·Track·Repository·approval 교집합 충족"}
J["Action may execute"]
K["중단 또는 승인 요청"]
A --> B
B -- Yes --> C
B -- No --> D
D -- Yes --> E
D -- No --> F
F -- Yes --> G
F -- No --> H
C --> I
E --> I
G --> I
H --> I
I -- Yes --> J
I -- No --> K

Approval Proposal에는 다음 정보가 들어가야 한다.
| 필드 | 설명 |
proposalid |
승인 제안 식별자 |
action |
실행하려는 구체적인 행동 |
gate |
G0~G3 분류 |
reason |
행동이 필요한 이유 |
target |
영향받는 시스템과 범위 |
reversibility |
되돌릴 수 있는지와 그 조건 |
evidence |
현재까지 확보한 검증 결과 |
difforplan |
실제로 적용할 변경 또는 실행 계획 |
risk |
실패했을 때의 영향 |
rollback |
복구 또는 완화 계획 |
requestedby |
Master 또는 Worker |
expiresat |
승인이 더 이상 유효하지 않은 시각 |
decision |
PENDING, APPROVED, REJECTED, CONSUMED |
decisionby |
승인 또는 거절 주체 |
승인은 대상과 범위가 명확해야 한다. “배포 승인”처럼 넓은 문장 하나로 이후의 모든 배포를 허용해서는 안 된다. 승인된 diff나 version, 환경, 실행 시각이 달라지면 기존 승인을 재사용하지 않고 다시 판정해야 한다.
현재 문서 모델의 Proposal 상태는 다음처럼 관리한다.
PENDING
├─ APPROVED
└─ REJECTED
APPROVED
└─ CONSUMED
승인 뒤 대상 revision이나 배포 artifact가 바뀌면 변경된 증거를 포함해 새 Proposal을 만든다.
현재 운영: Gate 수동 집행과 dispatch gate Master가 게이트를 분류하고 Human이 G3 최종 승인을 맡는다.
만료, 취소, 실행 완료 같은 세부 상태와 조건은 목표 확장으로 남아 있지만 3.9의 dispatch gate처럼 파견 행동은 reason code, 예산 한도, 중복 윈도우, 티켓 발권을 스크립트로 강제한다. 목표 Approval Manager는 분류와 상태 관리를 자동화하고 G3에 대한 최종 권한은 Human에게 남긴다. 분류와 Human 권한 강제 로직은 오케스트레이터 런타임 저장소에 구현과 테스트가 존재하며, 운영 파견 경로 배선은 남아 있다.
3.11 Evidence와 Acceptance
Worker가 완료했다고 말하는 순간에도 실제 파일, 테스트 범위, Human 관찰의 증명 범위를 따로 봐야 했기 때문에 Evidence와 Acceptance를 분리했다. Acceptance는 Worker의 완료 응답 문구를 신뢰 대상에서 제외한다. Worker의 출력은 Evidence Bundle로 제출하고 자연어 보고는 부속 메모로만 취급한다.
증거마다 증명할 수 있는 범위가 다르다. "신뢰 수준이 높다"는 분류보다 증명 범위와 미증명 범위를 구분해야 하며 Evidence는 자신이 검증한 범위까지만 의미를 가진다.
- diff는 어떤 파일이 바뀌었는지를 보여준다.
- 테스트 성공은 해당 테스트가 다룬 범위가 통과했음을 보여준다.
- 로컬 프로브 성공의 증명 범위는 프로덕션 동작까지 확장되지 않는다.
- 빌드 성공과 배포 승인은 별개다.
- Worker의 완료 보고는 주장이다.
Acceptance는 Evidence Bundle을 기준으로 별도로 기록한다.
| 증거 유형 | 증명할 수 있는 것 | 단독으로 증명하지 못하는 것 | 신뢰 수준 |
| Artifact | 파일이나 빌드 산출물이 존재한다 | 요구사항을 충족하거나 정상 동작한다 | 중간 |
| Diff | 기준점과 결과 사이에 어떤 변경이 생겼다 | 변경이 올바르거나 충분하다 | 높음 |
| Deterministic Test | 특정 코드와 환경에서 정의된 테스트가 통과했다 | 테스트하지 않은 범위와 실제 프로덕션 동작 | 높음 |
| Runtime Probe | 특정 시점에 관측한 endpoint, process, port 상태 | 장기 안정성과 모든 사용자 경로 | 높음 |
| Environment Evidence | 배포 version, image digest, 설정, 로그가 특정 상태다 | 해당 상태가 기능적으로 올바르다 | 높음 |
| Manual Observation | Human이 실제 UI나 외부 결과를 확인했다 | 재현 가능한 자동 검증과 내부 상태 전체 | 단독으로는 무효 |
| Self-report | Worker가 무엇을 주장하는지 기록한다 | 주장의 사실 여부 | 조건부 높음 |
Self-report의 "조건부 높음"은 Worker가 그런 주장을 남겼다는 기록의 신뢰도다. 주장의 내용이 맞다는 뜻이 아니므로 INV-09와 충돌하지 않는다.
테스트 통과는 해당 테스트가 다룬 범위만 증명한다. 잘못된 환경에서 실행한 테스트나 변경과 무관한 테스트는 수락 증거가 될 수 없다. Evidence Bundle은 증거의 원본을 추적할 수 있어야 한다.
result: "26 passed"라는 문자열만 저장하면 Worker 자기 보고와 크게 다를 바 없다. 가능하면 원본 로그와 실행 시각, exit code, 대상 commit을 함께 연결해야 한다. 수락자는 evidence bundle을 다음 기준으로 검토한다.
- 제출된 artifact와 diff가 lease 범위에 들어가는가
- 예상하지 않은 파일이나 다른 레포가 변경되지 않았는가
- verification plan의 필수 항목이 실제로 실행됐는가
- 테스트와 프로브가 대상 diff를 검증하는가
- 알려진 미검증 범위가 명시됐는가
- 행동의 Gate와 approval state가 유효한가
- 결과가 Track의 completion criteria를 충족하는가
Acceptance 결과는 다음 중 하나다.
| 상태 | 의미 |
| pending | 아직 검토하지 않음 |
| accepted | 정의된 수락 조건과 필요한 증거를 충족함 |
| changesrequested | 결과 일부를 수정하거나 증거를 보완해야 함 |
| rejected | 범위 또는 요구사항을 충족하지 못해 현재 결과를 수락하지 않음 |
| needshumanverification | 자동 증거만으로 판정할 수 없어 Human의 확인 없이는 결정할 수 없음 |
Worker의 status: complete는 Worker가 자신의 작업이 끝났다고 판단했다는 메타데이터다. 최종 상태는 별도의 수락 주체가 증거를 검토한 뒤 기록한다. 수락자는 다음 순서로 검토한다.
- Evidence Bundle이 현재 lease와 같은 task·revision을 가리키는지 확인한다.
- 변경 파일이 writable scope 안에 있는지 확인한다.
- 필수 검증 명령과 결과가 존재하는지 확인한다.
- 실패와 미실행 항목이 숨겨져 있지 않은지 확인한다.
- 위험도에 비례해 중요한 검증을 다시 실행한다.
- known gap이 완료 조건과 충돌하는지 판정한다.
- 필요한 Approval이 유효한지 확인한다.
Evidence Bundle이 완전해 보여도 기준 revision이 다르면 수락 기준에서 탈락한다. 승인 후 코드가 바뀌었거나 테스트 로그가 다른 commit을 가리키는 경우도 마찬가지다. Acceptance가 끝난 뒤에만 Work Ledger의 최종 상태를 갱신하고 lease를 accepted 또는 closed로 전환한다.
현재 운영: 검증 루프의 실행부
이 절의 수락 규칙은 구현, 독립 검증, 반려 또는 수정, 수락의 회로로 돈다. 리뷰는 3-vote를 기본으로 삼는다. 일반, 회귀 반증, 계약·스코프의 세 렌즈가 병렬로 투표하고 판정 입력은 CI, diff 검산, 회귀 테스트, 화면 캡처다.
판정은 다수결을 기본으로 보지만, 소수 의견이라도 P1 FIX_FIRST 차단 소견이면 반영한다.
리뷰어 평결도 Evidence의 하나일 뿐이다. 한 병합에서 3-vote가 NO_GO 블로커 2건을 냈을 때 Master는 블로커를 실측으로 재심해 1건을 false-negative로 기각하고 1건은 인정해 반영했다. 리뷰 게이트가 유효한 문제를 잡은 사례도 있다.
[강제] 한 백엔드 diff에서 리뷰가 고아 import를 지적했다. 워커는 엔드포인트 주석 처리와 import 정리로 풀려 했다. Human은 리턴 DTO만 가리면 된다는 의도를 다시 고정했다.
[형성] 스코프를 좁게 유지하고 비활성 엔드포인트를 문서상 의도와 다르게 바꾸지 않는 규칙이 작동했다. Master는 컨트롤러를 재확인해 주석 접근을 되돌리고 응답 DTO만 수정하는 쪽으로 계약을 다시 세웠다. [판단] 이 장면에서 남긴 해석은 "리뷰 지적이 맞아도 수정 방향은 다시 Human 의도에 맞춰 좁혀야 한다"는 것이다.
이는 수락 단계의 운영 판단으로 둔다. 조직 생성 정책이 이미 닫힌 장면에서는 구현을 더 넓히지 않고 no-op과 redacted 반환으로 범위를 고정했다. 독자는 여기서 리뷰 지적을 그대로 수리 항목으로 확장하지 않고 Human의 정책 판정을 기준으로 수정 폭을 줄이는 과정을 보면 된다.
정본 사례: 기능 검증 다음의 단순성 판정

테스트가 전부 통과한 뒤에도 판정은 계속된다. "작동한다"와 "좋은 구현이다"는 별도 판정이고 뒤쪽 판정의 소유자는 Human이다. 실측 사례가 있다.
[강제] 워커와 리뷰어를 모두 통과한 백엔드 수정에서 Human이 직접 코드를 다시 읽었다. 주소 병합 함수가 필드별로 같은 패턴을 반복하고 있었다. Human은 얕은 병합으로 충분한지 물었다.
Master는 추측으로 답하지 않고 실제 구현을 재확인했다. [형성] 정의된 값만 덮어쓰고 null 전송으로 필드를 지울 수 없게 하는 동작 조건은 기존 계약에서 온 제약이었다. 그 제약은 유지됐다.
[판단] 필드 다섯 개를 각각 가드하는 열다섯 줄이 짧은 병합 루프로 줄어든다는 결론은 Master가 실제 코드를 다시 읽은 뒤 내린 사후 판단이다. 이 판단은 기존 테스트로 동작 동일성을 재검증하면서 수락됐다.
sequenceDiagram
participant H as Human
participant M as Master
participant W as Worker
participant A as Acceptance
H->>M: 반복 병합 코드의 단순화 가능성 질문
M->>M: 실제 구현과 기존 계약 재확인
M->>W: 동작 조건 유지 범위 안에서 단순화 요청
W->>A: 단순화 diff와 테스트 증거 제출
A->>H: 동작 동일성과 단순성 기준 승격 보고


축약하면 이런 변화다.
// before: 같은 패턴을 필드마다 반복 (필드별 ?? 와 if-undefined 가드)
const streetAddress = next.streetAddress ?? current.streetAddress
if (streetAddress !== undefined) merged.streetAddress = streetAddress
// ... 필드 수만큼 반복
// after: 짧은 병합 루프
const merged = { ...current }
for (const [key, value] of Object.entries(next)) {
if (value !== undefined && value !== null) merged[key] = value
}
이때 Master의 역할은 실제 코드를 다시 읽고 단순한 형태가 동작 조건을 만족하는지 확인한 뒤 그 판단을 다음 워커 수락 기준으로 남기는 것이었다. 이 사례 이후 단순성·복잡도 리뷰가 수락 과정의 기준으로 승격됐다. 뒤의 3.24에서는 이 일을 실패 처리와 재발 방지 규칙으로 다룬다.
C. 연속성: 3.12~3.16
3.12 Recovery Manager
정의: Recovery 세션이 보이지 않거나 응답하지 않을 때 기존 실행의 생존 여부를 확인하고 작업 상태를 복구하는 절차다. 클라이언트, 런타임, daemon, PTY, 에이전트 프로세스, 세션 저장 파일, handoff, Work Ledger, Git을 순서대로 검사한다.
화면에서 사라진 세션을 죽은 세션으로 처리하면 같은 작업이 두 번 실행될 수 있다. 실제 장애 조사에서 UI, runtime, daemon, PTY, 에이전트 프로세스가 서로 다른 생명주기를 가진다는 점도 확인했다. 그래서 Recovery Manager는 새 세션을 만들기 전에 남아 있는 실행부터 찾는다. Recovery Manager는 세션이 보이지 않거나 응답하지 않을 때 기존 실행을 다시 사용할 수 있는지 판정한다. 이 절이 Recovery 경로의 정본이다.
Succession은 후임 검증과 전임 은퇴 조건을, handoff는 현재 상태 한 건으로 수렴하는 저장 규칙을 맡는다. 이 정상 인계는 뒤의 3.13과 3.20에서 다루며, 다른 절에서는 Recovery 절차를 다시 체크리스트로 복제하지 않는다. 화면에서 세션이 사라졌을 때는 새 Master 생성보다 기존 실행 확인이 먼저다.
복구 검사는 부수효과가 없는 read-only probe부터 시작한다.
먼저 복구 계층을 순서대로 검사한다.
| 단계 | 검사 대상 | 확인할 내용 | 성공 시 행동 | 실패 시 다음 단계 |
| R0 | 클라이언트 연결 | 기존 터미널과 세션이 UI에 연결돼 있는가 | 기존 세션 계속 사용 | R1 |
| R1 | Orca ADE runtime 상태 | runtime이 응답하며 기존 terminal handle을 찾을 수 있는가 | 클라이언트 재연결 | R2 |
| R2 | daemon과 PTY | daemon이 살아 있고 기존 PTY를 소유하는가 | 기존 PTY에 재부착 | R3 |
| R3 | 에이전트 프로세스 | 대상 session ID와 연결된 프로세스가 실행 중인가 | 기존 프로세스에 연결 복구 | R4 |
| R4 | 세션 저장 상태 | 실행 프로세스는 없지만 저장된 세션을 안전하게 resume할 수 있는가 | 잠금 확인 후 한 번만 resume | R5 |
| R5 | 최신 LIVE handoff | 전임은 없지만 후임을 만들 만큼 상태가 남아 있는가 | 새 successor session 생성 | R6 |
| R6 | Work Ledger와 Git | handoff도 불완전할 때 최소 상태를 재구성할 수 있는가 | 최소 상태 복구 후 Human 확인 | Human 개입 |
복구 흐름은 다음과 같다.
Session Appears Missing
│
▼
Check Client and Runtime
│
├─ connected ───────────────► Continue Existing Session
│
▼
Check daemon and PTY
│
├─ alive ───────────────────► Reattach Existing PTY
│
▼
Check Agent PID and Session Identity
│
├─ alive ───────────────────► Recover Existing Connection
│
▼
Check Session Persistence and Resume Lock
│
├─ safe to resume ──────────► Resume Once
│
▼
Load LIVE Handoff
│
├─ sufficient ──────────────► Spawn Successor
│
▼
Reconstruct from Work Ledger and Git
│
▼
Require Human Verification
flowchart TD
A["Session Appears Missing"]
B["Check Client and Runtime"]
C{"connected"}
D["Continue Existing Session"]
E["Check daemon and PTY"]
F{"alive"}
G["Reattach Existing PTY"]
H["Check Agent PID and Session Identity"]
I{"alive"}
J["Recover Existing Connection"]
K["Check Session Persistence and Resume Lock"]
L{"safe to resume"}
M["Resume Once"]
N["Load LIVE Handoff"]
O{"sufficient"}
P["Spawn Successor"]
Q["Reconstruct from Work Ledger and Git"]
R["Require Human Verification"]
A --> B --> C
C -- Yes --> D
C -- No --> E --> F
F -- Yes --> G
F -- No --> H --> I
I -- Yes --> J
I -- No --> K --> L
L -- Yes --> M
L -- No --> N
M --> N --> O
O -- Yes --> P
O -- No --> Q --> R

동일 세션은 한 번만 resume한다. 동일한 session ID에 대한 resume 시도는 원자적인 잠금으로 보호해야 한다. 최소한 다음 상태를 기록해야 한다.
- 대상 session ID
- 기존 PID와 PTY
- resume을 시도한 주체
- resume 시도 시각
- 성공 또는 실패 결과
- 새로 생성된 PID
- 사용한 세션 저장 경로
이미 다른 프로세스가 같은 session ID를 사용 중이거나, 실행 여부를 확정할 수 없다면 추가 resume을 금지한다. 불확실한 상태에서 새 실행을 만드는 것보다 Human에게 상태를 올리는 편이 안전하다. 프로세스 식별에는 외부 증거가 필요하다.
프로세스 이름에 claude나 codex가 포함돼 있다는 이유만으로 대상 세션이라고 판단해서는 안 된다. 프로세스 식별에는 다음 증거를 함께 대조해야 한다.
- PID와 parent PID
- 커맨드라인
- PTY
- cwd
- session ID
- 세션 저장 경로
프로세스를 종료할 때도 같은 증거로 대상을 확정한 뒤 해당 PID만 종료한다. 이 규칙은 여러 에이전트 세션이 동시에 실행되는 환경에서 특히 중요하다. 이름만 보고 프로세스를 정리하면 정상 동작 중인 다른 Worker나 Master를 종료할 수 있다.
Recovery 결과는 다음 중 하나로 기록한다.
| 결과 | 의미 |
| reattached | 기존 PTY 또는 실행 프로세스에 다시 연결함 |
| resumed | 기존 실행이 없음을 확인하고 저장된 동일 세션을 한 번 resume함 |
| successorspawned | 기존 identity를 복구하지 않고 handoff로 후임을 생성함 |
| reconstructed | Work Ledger와 Git에서 최소 상태를 재구성함 |
| humanrequired | 중복 실행 가능성이나 상태 손실 때문에 자동 복구를 중단함 |
3.13 Succession Manager
정의: Succession 현재 Master가 작업을 동결하고 thin handoff를 남긴 뒤, 후임 Master가 정본과 실행 상태를 확인하도록 역할을 넘기는 절차다. 장애 상황의 예외 처리와 장시간 운영되는 에이전트 시스템의 정상 수명주기를 함께 다룬다.
장시간 운영에서 세션 교체는 정상 수명주기다. 전임이 살아 있을 때 상태를 얇게 남기고 후임이 정본으로 재구성하게 해야 한다. 이것을 장애 복구와 구분해 Succession으로 다룬다.
Succession (승계 절차)은 장애 복구와 계획된 역할 인계를 모두 다룬다. 전임이 아직 작업 상태를 정리할 수 있을 때 변경 가능한 작업을 동결하고 후임에게 역할과 Track을 넘기는 계획된 수명주기다. 수동 승계 절차에서 trigger를 Immediate와 Advisory로 나눈다.
현행 v3에서 새 후임 세션은 Human 지시가 있을 때만 세우고, Advisory는 제안 상태로만 남아 자동 승계로 이어지지 않는다.
| Trigger | 조건 | 행동 |
| Immediate | 사용자가 “승계해줘”, “다음 Master로 넘기자”처럼 명시적으로 지시함 | 재확인 없이 승계 절차를 시작 |
| Advisory | 컨텍스트 한계 접근, 자연 마일스톤, 장시간 상주로 인한 상태 비대, 복구 비용 증가 | 자동 승계는 금지. "승계 임계점에 도달했습니다. 현재 역할과 트랙을 유지한 채 다음 Master로 승계할까요?"라고 제안만 한다. |
컨텍스트 사용량을 정확히 측정할 수 없다면 정확한 수치처럼 말하지 않는다. UI 표시나 관찰 가능한 근사치를 사용했다면 추정값임을 명시한다. 여기에 설계 확장으로 Scheduled(릴리즈 전후, 근무 교대, 장기 트랙 경계 같은 예정된 시점의 승계)를 추가할 수 있다.
프로세스 종료나 런타임 장애처럼 전임이 handoff를 남길 수 없는 상황은 Recovery Manager가 다룬다. 릴리즈 전후나 근무 교대처럼 예정된 시점에 자동으로 승계하는 Scheduled trigger는 현재 동결된 계약에 포함돼 있지 않다. 이를 추가하려면 구현 문서에 바로 넣지 않고 Architecture ADR과 Human 승인을 거쳐야 한다.
Thin Handoff 필드
| 필드 | 내용 |
| Identity | 전임 session ID, 세대, 현재 역할과 Track |
| Objective | 현재 목표와 완료 조건 |
| Accepted State | 이미 수락된 결과와 증거 포인터 |
| Unaccepted State | 제출됐지만 아직 수락되지 않은 결과 |
| Active Leases | 실행 중인 Worker lease와 실제 상태 |
| Open Questions | 아직 결정되지 않은 질문 |
| Blockers | 외부 대기 조건과 승인 대기 |
| Canonical References | Git, 레포 planning 산출물, Work Ledger 포인터 |
| Recovery Notes | 정확한 재개 위치와 첫 검증 행동 |
| Prohibited Assumptions | 후임이 사실로 단정하면 안 되는 내용 |
| Verification Challenge | 후임이 정본을 읽고 상태를 복구했는지 확인할 질문 |
thin handoff에는 현재 상태를 복구하는 데 필요한 정보와 정본 포인터만 기록한다. 대화 전문이나 과거 추론 전체는 제외한다.
Predecessor
│
├─ freeze mutable work
├─ stop new dispatch
├─ collect accepted and unaccepted state
├─ record active leases and blockers
└─ write thin handoff
│
▼
Successor
│
├─ load Charter
├─ read LIVE handoff
├─ inspect Work Ledger and Git
├─ remeasure runtime baseline
└─ answer verification challenge
│
┌─────────┴─────────┐
PASS FAIL
│ │
▼ ▼
Record lineage Keep predecessor frozen
Retire predecessor or request Human recovery
sequenceDiagram
participant P as Predecessor
participant S as Successor
participant W as Work Ledger
participant G as Git
participant H as Human
P->>P: freeze mutable work
P->>P: stop new dispatch
P->>S: thin handoff
S->>W: accepted and unaccepted state 확인
S->>G: 정본 포인터와 현재 상태 확인
S->>S: Verification Challenge 응답
alt PASS
S->>H: lineage 기록과 전임 은퇴 보고
else FAIL
S->>H: predecessor frozen 또는 recovery 요청
end

또한 후임 검증은 "handoff를 읽었습니다"라는 응답 뒤의 재진술과 정본 확인까지 포함한다. 후임이 현재 역할, 활성 트랙, 마지막 수락 산출물, 다음 허용 행동, 금지 행동을 재진술하게 하고 정본 포인터를 실제로 읽었는지 확인한다. 후임 검증이 끝날 때까지 전임은 살아 있을 수 있지만 frozen 상태로 유지한다.
두 Master가 동시에 파일을 수정하거나 Worker를 dispatch하는 일을 막으려는 조치다. 승계에서 전임이 실행하던 감시 장치(별도로 띄운 모니터링, probe, 하위 레포지토리 변화 감지용 하위 shell)는 후임이 물려받지 않는다. 후임은 현재 Git HEAD와 프로세스, 포트, heartbeat 경로를 직접 측정한 뒤 자신의 session ID와 경로를 소유자로 지정해 모니터를 다시 실행한다.
전임의 orphan 프로세스는 경로와 커맨드라인을 대조해 그것만 정리한다. 소유자가 불명확한 모니터는 정상처럼 보여도 후임의 관측값에서 제외한다. 상속받은 모니터는 어느 세션 소유인지 불명확해지고 죽어도 아무도 모르는 감시가 되기 때문이다.
승계 v3: 컴팩션 우선, 승계는 지시 이벤트
이 절의 trigger 모델은 운영을 거치며 개정됐다. 초기 체계는 세션 교체를 중심에 두었지만 실제 운영에서 승계 비용과 반복 복구 비용이 확인되면서 현행(v3) 체계는 평시를 컴팩션으로 계속 진행하고 새 판(후임 세션)은 Human이 지시할 때만 세운다. fork 스폰은 승계 절차의 지위에서 도구함 항목으로 강등됐다.
같은 세션의 이중 기동은 세션 손상 위험이 있어 금지다. 현행 운영 문서와 승계 카드에는 Human 지시 한 번으로 후임 부팅, 생존 실측, 전임 정리, lineage 기록까지 이어지게 만드는 목표 UX가 적혀 있다. 그러나 이 절은 자동 Succession Manager 구현 완료를 주장하지 않는다.
현재 상태는 온보딩의 Succession 행이 정본이다. 문서화된 절차와 Gen1~Gen23 lineage는 확인됐지만, 모든 판단이 자동화됐다고 확장하지 않는다.
세션 리밋 상황에서 Gen-20에서 Gen-21로 넘어간 실측은 4부의 증거 서사로 둔다. 3.13에는 승계 규칙만 남긴다. 장시간 운영에서 세션 캐싱, resume 경로, 계정 전환, 터미널과 workflow 상태 복구를 UX로 만들려면 Execution Substrate가 이 요구사항을 맡아야 한다.
이 결합은 뒤의 3.16에서 Adapter Layer 계약으로 격리한다.
3.14 Lineage Recorder (마스터 에이전트의 승계 족보)
정의: Master 승계의 감사 기록 누가 누구를 승계했고, 어떤 복구 정보를 사용했으며, 어떤 검증을 통과했는지를 append-only로 남긴다.
제목의 ‘계보’는 이 기록을 가리킨다. Lineage 자체는 다음 Master에게 자동 주입되는 정본으로 쓰지 않는다.
승계가 끝났다고 해서 그 기록을 다음 세션의 판단 입력으로 넣으면 과거 실패가 현재 판단을 오염시킬 수 있다. 그러나 기록을 버리면 절차를 개선할 수 없다. Lineage는 Human이 승계 품질을 감사하는 장부다.
Lineage는 승계의 감사 로그다. 운영자가 승계의 연속성과 실패를 조사할 때 쓰는 audit 기록이며 다음 세션의 판단 입력에서 제외한다.
후임 Master의 복구 입력은 Charter, LIVE handoff, Work Ledger와 Git이다. lineage 전체는 Bootstrap 자동 주입 대상에서 제외한다.
현재 운영: 13필드 Lineage 스키마 스키마는 13개 필수 필드를 가지도록 설계했다.
| 필드 | 설명 |
| generation | Master 세대 번호 |
| parent_session | 전임 session ID |
| successor_session | 후임 session ID |
| timestamp | 현재 스키마에서 승계 지시 시각과 전임 종료 확인 시각을 함께 기록 |
| inherited_role | 후임이 상속한 역할. 승계 자체는 역할을 바꾸지 않음 |
| succession_reason | 승계 사유 |
| recovery_sources | 후임이 실제로 읽거나 조회한 복구 소스 |
| inherited_open_tracks | 상속한 열린 Track의 수와 식별자 |
| verification | PASS, PARTIAL, FAILED |
| repeated_question_count | 이미 정본이나 handoff에 답이 있던 질문을 다시 한 횟수 |
| reopened_decision_count | 새로운 근거 없이 이미 확정된 결정을 다시 연 횟수 |
| context_loss_summary | 유실된 컨텍스트와 영향. 없으면 “없음 확인” |
| predecessor_retirement_verified | 후임이 전임 종료를 외부 증거로 확인했는가 |
마지막 네 필드는 서로 다른 항목을 측정한다.
- repeated_question_count: 필요한 정보에 접근할 수 있었는가
- reopened_decision_count: 결정과 근거가 정본에 남아 있었는가
- context_loss_summary: 실제로 무엇이 유실됐는가
- predecessor_retirement_verified: 중복 Master가 남지 않았는가
재질문 0회는 좋은 신호지만 handoff 완전성의 단독 증거로 쓰기에는 부족하다. 후임이 누락 사실을 인지하지 못한 채 질문하지 않았을 수도 있기 때문이다. Git 기준선, 실행 상태와 Verification Challenge를 함께 확인해야 한다.
새로운 증거나 요구사항 변경 때문에 결정을 의도적으로 재검토한 경우는 reopened_decision_count에 포함하지 않는다. 이 항목들은 승계 품질을 관측 가능한 값으로 남긴다. “잘 된 것 같다”는 인상 대신 기록된 값으로 다음 handoff와 승계 절차를 개선할 수 있다.
이 지표는 정해진 관찰 구간과 판정 기준을 사용해 계산해야 한다. 실제 대화 이력과 정본 변경, Human 검수를 근거로 삼고 세션 자신의 평가는 제외한다. Lineage는 append-only로 기록한다.
## Gen 3
- **Generation**: 3
- **Timestamp**: 2026-07-17T15:04:22+09:00
- **Verification**: PASS
- **Notes**: 이전 세대의 은퇴 확인 시각을 별도 정정 메모로 남김
기존 항목이 잘못됐더라도 원문을 수정하지 않고 고정된 Gen 섹션의 notes나 별도 append-only 정정 문서로 남긴다. missing artifact, stale handoff, 중복 지식, 재질문, 근거 없는 결정 재개봉, 역할 오류, 컨텍스트 유실 같은 감점 사유도 그대로 남긴다. 장부(족보)의 가치는 실제로 발생한 일을 투명하게 추적할 수 있게 만드는 것이다.
13필드 스키마가 정의되어 있고 후반 lineage 기록에서도 이 구조가 기준선으로 쓰인다. 다만 Gen1 같은 pre-charter 예외와 일부 notes형 축약이 있어 세대별 완전성에는 차이가 있다. 예외 상황의 승계일수록 장부의 계량 필드가 인수 품질을 판정하는 근거가 된다.
현재 timestamp 필드는 두 시각을 표현하고 있다. 향후 다음 두 필드로 분리할 예정이다. (이 변경이 적용되면 전체 스키마는 14개 필드가 된다.)
- successionrequestedat: 승계가 지시되거나 시작된 시각
- predecessorretiredat: 전임 종료를 확인한 시각
3.15 Observability (정량적 지표로 계산)
에이전트 운영에서 가장 위험한 말은 "잘 되는 것 같다"였다. 운영에서는 완료된 워커를 진행 중으로 보거나 정상 워커를 폭주로 오진한 적이 있었다. Observability는 자연어 인상 대신 외부 관측값과 기준선으로 상태를 확인한다.
에이전트 하네스의 Observability는 실행 상태와 정책 준수 여부를 외부 정량 증거로 관측하고 정의된 기준선에서 벗어났을 때 경고한다.
| 영역 | 관측 항목 |
| Master Health | session 응답성, 현재 역할, 역할 잠금 활성화 상태, 컨텍스트 사용량 또는 명시된 추정치 |
| Worker Health | lease status, PID, worktree 존재 여부, 실행 시간, budget |
| Succession | 후임 검증 성공률, 중복 session 여부, 승계 소요 시간, 전임 은퇴 확인 |
| Knowledge Integrity | 중복 정본, 허용되지 않은 문서 위치, stale pointer |
| Approval | pending proposal, 만료된 승인, G3 우회 시도 |
| Repository Drift | descriptor와 실제 경로 불일치, hook 비활성, 검증 명령 누락 |
| Budget | 모델별 토큰, 활성 Worker 수, 실행 시간, 재시도 횟수 |
| Acceptance | 제출 대비 수락 결과, self-report 단독 완료 시도, 미검증 범위 |
| Runtime | Orca runtime, daemon, PTY 연결, stale terminal handle |
| Handoff | Track별 LIVE handoff 수, 필수 필드 누락, 오래된 handoff |
| Monitor Ownership | 모니터의 owner session, heartbeat 경로, orphan process |
관측값에는 소유자를 함께 기록한다.
probe:
id: "duplicate-master-check"
owner_session: "master-session-ref"
target_track: "service-prod-launch"
measured_at: "..."
result: "pass"
소유자와 측정 시각이 없는 프로브 결과는 현재 기준선으로 사용하지 않는다. 예를 들면 다음과 같은 경보를 둘 수 있다.
| Alert | 조건 | 기본 대응 |
| Duplicate Master | 같은 session ID 또는 같은 track-role의 활성 Master가 둘 이상 | 변경 작업 즉시 freeze, Human 확인 |
| Untracked Knowledge | 관리 대상이지만 허용되지 않은 위치에 영구 문서 생성 | 쓰기 차단 또는 정본 위치 제안 |
| Memory Bloat | beads memory가 길이 제한을 넘거나 전문을 포함 | 포인터 캐시 규칙 위반으로 실패 |
| Stale Handoff | 한 Track에 LIVE handoff가 여러 개이거나 검증 기한 초과 | 새 실행 중단, 최신 상태 재판정 |
| Gate Bypass | G3 행동을 유효한 승인 없이 실행하려 함 | 즉시 차단하고 proposal 생성 |
| Orphan Lease | Worker가 종료됐지만 lease가 running | 실제 프로세스 확인 후 reap 또는 조사 |
| Architecture Drift | 동결 출처 없이 새 Unit이나 책임 등장 | 구현 중단, ADR 요구 |
| Model Drift | 세션의 실행 모델이 선언된 모델과 다르게 관측됨 | 새 판 클린 승계, 보안 표면 위임 상태 점검 |
| Context Overload | L0와 L1이 부팅 예산 초과 | 장문 제거, 포인터화, Bootstrap 실패 |
| Orphan Monitor | owner session이 종료됐는데 모니터가 계속 실행 | PID·경로 대조 후 해당 모니터만 종료 |
경보는 에이전트의 자연어 응답만으로 해제하지 않는다. 기준선을 다시 측정해 위반 상태가 실제로 사라졌다는 증거를 남겨야 한다.
현재 운영: E12 프로브와 context-quality 대장
Observability에는 컨텍스트 품질 관측도 들어간다. 평시 컴팩션 체계는 중요한 상태가 Work Ledger와 Git으로 승격되어 있으면 압축 손실을 복구할 수 있다는 전제 위에 서 있다. E12 프로브는 그 전제를 추측으로 두지 않는 회상 계측기다.
컴팩션 직후 부트스트랩이 Role State와 활성 트랙 노출을 일부러 억제한 상태에서 회상 자가시험을 주입하고 세션은 기억으로 먼저 답한 뒤 정본과 대조한다. E12라는 이름은 내부 설계 문서의 번호에서 온 코드명이다. 회상률이 2회 연속 100% 미만이거나 단회 80% 미만이면 새 판 승계를 제안한다.
자동 승계 없이 제안 단계에서 Human 결정을 기다린다. 계측 결과는 context-quality 대장(관측 전용 로그)에 쌓여, 컴팩션 손실이 늘어나는 추세 자체를 관측 대상으로 만든다. E12는 손실을 재는 장치이고 손실을 막는 장치(정본 승격과 재수화)와는 층이 다르다.
3.16 Adapter Layer
도구를 바꿀 수 있으려면 Core가 도구의 파일 형식과 명령어를 직접 알아서는 안 된다. Orca, beads, Git, Codex, ctx는 모두 유용했지만 각자의 실패 방식도 다르다. Adapter Layer는 그 차이를 Core의 상태 전이 밖에 둔다.
Adapter Layer는 core가 특정 제품의 CLI와 파일 형식, 세션 모델에 직접 종속되지 않도록 결합을 격리한다.
| Adapter | 책임 | 대표 구현 | 주요 계약 |
| WorkLedgerAdapter | 이슈와 실행 상태 | beads | create, update, search, notes, ready |
| KnowledgeStoreAdapter | 정본과 변경 이력 | Git | read, search, append, history, supersede |
| ExecutionSubstrateAdapter | 격리 실행 환경과 PTY | Orca, tmux, Git worktree | allocate, attach, inspect, release |
| ExecutorAdapter | 모델 실행과 세션 제어 | Codex, Claude Code | run, resume, interrupt, artifactrefs |
| TraceArchiveAdapter | 과거 실행 조회 | ctx, JSONL archive | search, show, read |
| RepositoryAdapter | descriptor와 레포 검증 | Git CLI, custom scripts | resolve, rules, verification |
| ExternalLedgerAdapter | 외부 프로젝트 상태 | Jira 등 | pushstatus, linkissue |
| HumanInterfaceAdapter | 승인 요청과 결정 | Chat, CLI, 전용 approval UI | propose, approve, reject |
Core는 다음처럼 추상 계약만 호출한다.
scheduler.dispatch(task)
│
├─ WorkLedger.get(task_id)
├─ Repository.resolve(repo_id)
├─ ExecutionSubstrate.allocate(profile)
├─ Executor.run(envelope)
└─ KnowledgeStore.read(context_refs)
Orca 대신 tmux 또는 다른 실행 시스템으로 바꾸더라도 ExecutionSubstrateAdapter의 계약만 유지하면 Scheduler와 Recovery의 핵심 로직은 바뀌지 않아야 한다. Adapter가 실패를 성공처럼 반환하거나 evidence reference 없이 결과 문자열만 넘기면 core는 수락 판단을 할 수 없다. Adapter는 제품별 오류를 Core가 처리할 수 있는 공통 상태로 변환해야 한다.
product error
│
▼
not_found
unavailable
authentication_required
permission_denied
conflict
timeout
Adapter가 실패했을 때는 실행 결과와 증거의 출처가 바뀌므로 다른 제품으로 자동 fallback하지 않는다. 대체 구현을 사용하려면 Master가 새 실행 환경과 capability를 확인하고 lease를 다시 발급한다. Orca ADE를 tmux로 교체하거나 beads를 다른 이슈 트래커로 바꾸더라도 Core의 상태 전이와 불변식이 유지돼야 한다.
Adapter의 실행 결과에는 최소 다음 정보가 담겨야 한다.
- 성공 또는 실패 상태
- 외부 부수효과 발생 여부
- 대상 resource와 identity
- 실행 시각과 duration
- 재시도 가능 여부
- artifact와 evidence reference
- 원본 도구 오류와 정규화된 오류 유형
이 대체 가능성은 mock adapter와 두 번째 실제 구현을 이용한 Adapter Substitution Test로 증명해야 한다. (코드로 구현해야 함)
D. 지식과 구현: 3.17~3.30
3.17 지식 아키텍처
런타임을 아무리 잘 나눠도 무엇을 믿을지 모르면 후임은 다시 흔들린다. 실제 워크스페이스에는 같은 결정이 memory, Wiki, handoff, scratchpad, 과거 문서에 흩어져 있었다. 지식 아키텍처는 정보의 의미와 수명에 따라 정본을 하나로 정하는 작업이다.
Knowledge Store는 승인된 영구 지식과 변경 이력을 보관하는 정본 저장소다. 이 글에서는 Git이 대표 구현체다. 지식 저장 위치는 정보의 의미와 수명으로 정한다.
도구 선호는 기준에서 제외한다. 아래 표가 저장소 역할의 정본이다. 다른 절에서는 이 표를 반복하지 않고 필요한 저장소 이름만 포인터로 사용한다.
| 정보 유형 | 정본 위치 | 수명 | 갱신 절차 | 다른 위치에는 |
| 제품·코드 ADR | Polsia-service/docs/wiki/decisions | 장기 | Git commit 또는 PR | 짧은 요약과 포인터 |
| 제품 runbook | Polsia-service/docs/wiki/guides | 장기 | Git 변경 | 포인터 |
| 제품 postmortem | Polsia-service/docs/wiki/postmortems | 장기 | Git append | 포인터 |
| 하네스 ADR | operations-repo/docs/adr | 장기 | Git 변경 | 포인터 |
| 워크스페이스 운영 규칙 | operations-repo/docs/rules | 장기 | Human 승인 후 Git 변경 | L0 요약과 포인터 |
| 하네스 runbook | operations-repo/docs/runbooks | 장기 | Git 변경 | 포인터 |
| 하네스 postmortem | operations-repo/docs/postmortems | 장기 | Git append | 포인터 |
| 현재 이슈 상태 | beads issue | 작업 기간 | 상태와 notes 갱신 | Track에서 issue 포인터 참조 |
| 레포 내부 계획과 로드맵 | 각 레포의 .planning | 페이즈 또는 마일스톤 기간 | 해당 Repository Harness planning 절차 | Track에서 계획 포인터만 참조하고 실행 상태는 Work Ledger 참조 |
| 최신 handoff | operations-repo/docs/handoffs/.md | 다음 승계 또는 Track 종료까지 | 동일 Track 파일 갱신과 Git commit | Git 이력이 과거 상태 보존 |
| 검색 포인터 | beads memory | 재생성 가능 | 짧은 요약과 정본 경로 갱신 | 정본으로 사용하지 않음 |
| 과거 문서 아카이브 | Notion | 장기지만 stale 전제 | 갱신하지 않음 | 현재 정본으로 사용하지 않음 |
| 조사 중 메모 | scratchpad | 현재 세션 | 자유 기록 | 종료 전 승격 또는 폐기 |
| 승계 계보 | lineage ledger | 장기 감사 | append-only | 런타임 지식 입력 금지 |
경로는 실제 레포 구조에 맞게 조정할 수 있다. 정보 유형마다 정본을 하나로 정해 둔다. 새 정보의 저장 위치는 다음 의사결정 흐름을 따른다.
New Information
│
▼
현재 세션에서만 필요한가?
│
Yes ├──────────────► Scratchpad
│
No
▼
특정 이슈의 진행 과정인가?
│
Yes ├──────────────► Work Ledger Notes
│
No
▼
현재 Track을 재개하는 데 필요한가?
│
Yes ├──────────────► Latest LIVE Handoff
│
No
▼
장기간 보존할 지식인가?
│
├─ 제품·코드 지식 ──────► Repository Wiki
│
└─ 워크스페이스·하네스 ─► operations-repo/docs
│
└─ beads memory에 포인터 등록 (Register pointer)
flowchart TD
A["New Information"]
B{"현재 세션에서만 필요한가?"}
C["Scratchpad"]
D{"특정 이슈의 진행 과정인가?"}
E["Work Ledger Notes"]
F{"현재 Track을 재개하는 데 필요한가?"}
G["Latest LIVE Handoff"]
H{"장기간 보존할 지식인가?"}
I["Repository Wiki"]
J["operations-repo/docs"]
K["beads memory<br/>포인터 등록"]
A --> B
B -- Yes --> C
B -- No --> D
D -- Yes --> E
D -- No --> F
F -- Yes --> G
F -- No --> H
H -- 제품·코드 지식 --> I
H -- 워크스페이스·하네스 --> J
J --> K

같은 내용의 전문은 한 정본에만 저장한다. 두 번째 위치가 필요하다면 요약과 정본 경로만 기록한다. 한 정보가 여러 조건에 해당할 수도 있다.
예를 들어 작업 중 새로운 운영 제약을 발견했다면 현재 이슈의 notes에는 “운영 제약을 확인했고 정본으로 승격했다”는 진행 사실과 정본 링크를 남긴다. 제약의 전문은 해당 runbook이나 ADR에 한 번만 기록한다. 즉 Work Ledger에는 작업 과정과 포인터를 남기고 Git 정본에는 장기적으로 유효한 사실을 남긴다.
같은 내용의 전문 복제는 피한다. 비밀정보와 인증정보는 이 분류와 별개로 다뤄야 한다. API 키, 토큰, 비밀번호 같은 값은 wiki, Work Ledger, handoff, lineage에 기록하지 않고 별도의 비밀 관리 시스템에 둔다.
운영체제 수렴: hot cache, pointer, storage, page-in
이 표를 오래 운영하다 보면 익숙한 구조가 보인다. 잘 작동하는 에이전트 하네스는 작은 운영체제의 메모리 계층으로 수렴한다.
뜨거운 상태는 가까운 캐시에 두고, 오래 갈 내용은 정본 저장소에 내리고, 무거운 원료는 포인터로 참조하고, 필요할 때 다시 page-in 한다.
이 하네스의 층을 OS 용어로 다시 적으면 이렇다. L0 hot cache는 현재 세션에 즉시 필요한 운영 규칙과 상태다. bd prime이 올리는 핵심 포인터 메모리와 레포 규약이 여기 속하고 bd prime 자체는 L0 cache warm-up에 해당한다.
L1 pointer cache는 정본 전체 대신 요약과 경로만 드는 층으로, beads memory의 포인터 구조가 그 역할을 맡는다.
Persistent storage는 Git 문서, handoff, lineage, fact ledger, runbook이다. Page-in은 필요할 때만 원문, 과거 세션(ctx), 코드 그래프를 불러오는 동작이고 컴팩션 후 재수화는 컨텍스트가 줄어도 운영 상태를 복구하는 절차다. 세션 리밋 승계의 실측 서사는 4부에 두고, 이 절에서는 bd prime warm-up, 정본 page-in, E12 회상 계측의 층 분리만 유지한다.
주류 에이전트 호스트들이 컨텍스트를 점진적으로 접는 방식(오래된 툴 출력 정리 우선, 부분 요약, 최근 교환 원문 보존)도 이 감각과 닮아 있다. 이 하네스의 메모리 계층은 그 내부 구현을 참조하지 않고 만들어졌고 같은 문제를 풀다 보니 같은 구조에 도착했다. 컴팩션에서 살아남으려면 무엇을 세션 안에 두고 무엇을 밖에 둘지 나눠야 했고 그 답이 캐시, 포인터, 저장소, 복구 경로였다.
시작할 때 프롬프트 모음이었던 이 하네스는 몇 주 뒤 메모리 계층, 스케줄러, 워커, 게이트, 로그, 정본 저장소를 가진 작은 운영체제로 진화해 있었다.
3.18 beads issue와 beads memory의 분리
처음에는 같은 도구 안의 기능이라 같은 층처럼 다루기 쉬웠다. 그러나 실행 상태와 장기 지식 포인터는 수명도 변경 방식도 다르다. 이 둘을 섞으면 memory가 작은 정본 저장소처럼 비대해지고 issue는 장기 규칙의 쓰레기통이 된다.
beads issue와 beads memory는 같은 도구가 제공하더라도 맡는 책임의 성격이 다르다. beads issue는 실행 상태의 정본이고 beads memory는 정본을 찾기 위한 재생성 가능한 캐시다.
| 항목 | beads issue | beads memory |
| 목적 | 현재 해야 할 일과 진행 서사 관리 | 관련 정본을 빠르게 찾기 위한 검색·부팅 포인터 |
| 정본 여부 | 실행 상태의 정본 | 정본 아님 |
| 허용 내용 | 진행 결과, blocker, 승인 대기, 다음 행동 | 짧은 정책 요약, 검색 키, 정본 경로 |
| 내용 길이 | 이슈를 이해하고 재개할 만큼 허용 | 정해진 길이 제한 안에서 유지 |
| 변경 시점 | 작업이 진행될 때마다 | 정본 위치나 최소 정책이 변경될 때 |
| 종료 후 처리 | 이력으로 남기되 장기 지식은 별도 승격 | 필요하면 정본에서 재생성 |
| 금지 내용 | 장기 ADR이나 runbook의 전문 | postmortem, ADR, 긴 설계 설명의 전문 |
memory 항목은 가능한 한 다음 형태를 따른다.
key: prod-db-write-policy
summary: "프로덕션 DB 직접 write 금지. 필요한 쓰기는 앱 엔드포인트 또는 Human 승인 경로."
canonical_ref: "operations-repo/docs/MASTER-OPERATIONS.md#prod-db-policy"
type: policy-pointer
verified_at: "2026-07-16"
각 필드의 역할은 이렇다.
- key는 검색과 중복 검사를 위한 안정적인 식별자다.
- summary는 세션 시작 시 위험 행동을 막기 위한 짧은 설명이다.
- canonicalref는 규칙의 근거와 예외, 변경 이력이 있는 정본을 가리킨다.
- type은 이 항목이 포인터임을 명시한다. 정본으로 읽히는 것을 막는 필드다.
- verifiedat은 마지막으로 포인터의 유효성을 확인한 시각이다.
Memory Pointer Test는 최소한 다음을 검사해야 한다.
- canonicalref가 존재하는가
- 참조 대상이 허용된 정본 경로 안에 있는가
- summary가 정해진 길이 제한을 넘지 않는가
- ADR이나 postmortem의 전문이 포함되지 않았는가
- 같은 key가 여러 정본을 가리키지 않는가
- verifiedat 이후 참조 대상이 이동하거나 삭제되지 않았는가
이슈를 닫을 때도 반복 가능한 해결책이나 운영 제약, 다른 결정의 근거가 되는 내용은 올바른 Git 정본으로 승격한 뒤 issue에는 해당 경로를 남긴다.
현재 운영: beads memory 실측값 beads memory는 L0 규칙과 L1 포인터의 2층으로 나뉘고 상한 15개를 유지한다. 세션 시작과 컴팩션 직후에는 bd prime이 앞의 3.4에서 정리한 최소 부팅 층을 다시 올린다.
상한이 있어서 오래된 항목은 밀려나고 밀려난 지식이 실제로 필요한 것이었다면 Git 정본에서 다시 포인터로 등록된다. 상한은 포인터 캐시가 전문 저장소로 비대해지는 것을 막는 방어선으로 작동했다.
3.19 Notion의 역할: 강등의 기록
복제본은 처음에는 접근성을 높여 준다. 시간이 지나면 갱신 비용과 인증 비용, 링크 관리 비용이 생기고 현재 정본과 충돌한다. Notion을 강등한 기록은 "쓰기 좋은 장소"와 "기계가 믿을 장소"가 다르다는 점을 보여 준다.
Notion은 이 설계 과정에서 두 차례에 걸쳐 역할이 축소됐다. 당시 Notion에는 프로젝트 Wiki가 남아 있었고 사용자는 현재 구조를 설계하기 전에 그곳에 축적된 과거 현황과 레거시를 참고하라고 지시했다. 과거 자료 참조와 현재 정본 사용은 구분했다.
7월 16일에는 Notion을 정본의 복제본이 아닌 사람용 인덱스로 제한했다. 정본 링크, 문서 상태, 마지막 검증일만 두고 설계 내용이나 운영 규칙의 전문은 Git 문서와 중복해서 관리하지 않는다는 결정이었다. 다음 날인 7월 17일에는 이 역할도 없앴다.
사람용 인덱스를 유지하려면 링크 갱신, 상태 확인, MCP 인증 관리 같은 작업이 계속 필요했다. 반면 현재 상태는 Git 정본과 Work Ledger에서 직접 확인할 수 있었고 별도 인덱스가 제공하는 새로운 정보는 없었다. Notion의 최종 역할은 이렇게 정리됐다.
| 항목 | 결정 |
| 성격 | 갱신하지 않는 과거 문서 아카이브 |
| 읽기 | 허용하되 내용이 오래됐을 수 있다고 전제 |
| 쓰기 | 새 정보를 기록하거나 기존 내용을 갱신하지 않음 |
| 에이전트 취급 | 현재 정본으로 사용 금지. 충돌 시 Git과 Work Ledger 우선 |
| 사람용 현재 상태 | Notion 대신 Git 정본과 Work Ledger에서 직접 확인 |
| adapter 취급 | 승인 채널이나 외부 상태 동기화 대상으로 사용하지 않음 |
이 강등 과정에서 얻은 일반 원칙은 간단하다. 접근성을 높이려고 복제본을 늘리는 것보다, 정보 유형별 SSOT를 명확히 정해 정합성을 유지하는 편이 장기적으로 더 효율적이다.
3.20 Handoff의 저장과 갱신
handoff는 다음 세션이 현재 Track을 재개하기 위한 상태 묶음이다. 날짜 파일이 계속 쌓이면 이력과 현재 상태가 같은 표면에 놓이고, 후임은 무엇이 LIVE인지 다시 판단해야 한다. 이 절은 handoff를 현재 상태로 좁히는 규칙이다.
같은 Track에 여러 LIVE handoff가 존재하면 후임은 무엇을 읽어야 하는지 다시 판단해야 한다. 목표 구조에서는 Track별 LIVE handoff를 한 건으로 제한한다.
operations-repo/
└── docs/
└── handoffs/
├── service-prod-launch.md
├── agent-harness-architecture.md
└── Polsia-service-observability.md
파일명은 Track 식별자를 기준으로 한다. handoff가 갱신될 때마다 같은 Track 파일을 수정한 뒤 Git commit을 남긴다. 승계 날짜는 파일명 기준에서 제외한다.
handoff의 상태는 이렇게 관리한다.
draft → LIVE → superseded
한 Track에서 LIVE 상태는 동시에 하나만 허용한다. draft는 아직 후임에게 전달할 수 없는 작성 중 상태이고 superseded는 더 이상 현재 복구에 사용하지 않는 과거 상태다. handoff 갱신은 다음 순서로 진행한다.
- 현재 Track의 변경 작업을 동결한다.
- 마지막으로 수락된 결과와 아직 수락되지 않은 결과를 구분한다.
- 실행 중인 lease, 열린 질문, blocker, 정본 경로를 기록한다.
- 필수 필드와 정본 포인터를 검증한다.
- 기존 LIVE handoff를 같은 Track의 새 상태로 갱신한다.
- 변경 내용을 Git에 기록한다.
- 후임이 검증을 통과한 뒤에만 전임을 은퇴시킨다.
현재 운영: Track 기반 handoff 이전 상태 아직 이 목표 구조로 완전히 전환되지 않았다. 지금은 승계마다 날짜가 포함된 handoff 파일이 생성되고 과거 파일도 그대로 남아 있다.
단일 Master 환경에서는 가장 최근 파일을 LIVE로 간주할 수 있지만 여러 Track과 Master가 동시에 움직이기 시작하면 이 규칙만으로는 부족하다. 기존 날짜 파일은 다음 절차로 마이그레이션할 수 있다.
- 기존 handoff 파일을 모두 조사한다.
- 각 파일을 해당 Track에 연결한다.
- 날짜만 보지 않고 Git 상태, Work Ledger, 실제 수락 결과를 대조한다.
- 확인된 최신 상태로 Track 기반 handoff를 만든다.
- 기존 파일은 과거 기록으로 표시하거나 Git 이력으로 보존한다.
- Track별 LIVE handoff가 하나인지 검사하는 프로브를 추가한다.
날짜가 가장 최근이라는 이유만으로 파일을 자동 승격하거나 기존 파일을 일괄 삭제해서는 안 된다. stale handoff에 오히려 더 최근 날짜가 있을 수도 있기 때문이다.
Lineage와 handoff도 역할이 다르다. handoff는 작업을 재개하기 위한 현재 상태이고 lineage는 승계가 어떻게 수행됐는지 조사하기 위한 감사 기록이다.
3.21 Architecture Freeze와 변경 절차
하네스는 실패를 고치려다 쉽게 커진다. 구현 중 편한 방향으로 새 책임을 넣기 시작하면 처음에 세운 책임 경계가 사라진다. Architecture Freeze는 구현 판단과 설계 변경을 분리해, 새 원칙이 몰래 들어오는 것을 막는다.
Architecture Freeze는 설계 변경과 구현 판단을 구분하는 역할이다. 구현 과정에서 발생하는 세부 판단과 아키텍처 변경을 나누어 처리한다.
| 구분 | 예시 | 처리 |
| 구현 세부 | 파일명, 내부 함수명, 동일 계약 안의 라이브러리 선택 | Implementation 역할에서 결정 |
| 계약 명확화 | 기존 필드의 타입과 오류 조건을 명시 | 동결된 책임을 유지하는 범위에서 수정 |
| 책임 이동 | Worker 책임을 Master로 이동 | Architecture ADR과 Human 승인 |
| 새 Runtime Unit | 별도 Policy Engine 추가 | Architecture 역할 전환과 ADR 필요 |
| 새 lifecycle trigger | Scheduled Succession 추가 | Architecture ADR과 Human 승인 |
| 불변식 변경 | Worker 자기 수락 허용 | Charter 또는 Architecture ADR 개정 |
| Adapter 교체 | Orca 대신 tmux 사용 | 기존 계약을 유지하면 구현 변경 |
| Adapter 계약 변경 | 새로운 core capability가 필요함 | Architecture 검토 필요 |
| 정본 이동 | operations-repo에서 별도 하네스 repo로 이전 | Migration ADR 필요 |
Reference Implementation의 각 Unit은 자신이 어떤 동결 문서에서 파생됐는지 기록해야 한다. 예를 들면 Master Charter, AHE Runtime, Boundary, Role State, Succession Protocol 같은 출처를 명시한다.
unit: succession-manager
derived_from:
- docs/MASTER-OPERATIONS.md
- docs/runbooks/succession-boot-card.md
- docs/adr/ADR-20260723-succession-fork-v3.md
architecture_revision: <commit-or-version>
구현 세부와 아키텍처 변경을 가르는 기준은 책임과 외부 계약이 바뀌는가다. 예를 들어 내부 함수명을 바꾸는 일은 구현 세부다. 반면 Recovery Manager가 맡던 session resume 권한을 Worker Scheduler로 옮기면 책임 경계가 바뀌므로 Architecture 변경이다.
Adapter 구현체를 교체하는 일도 기존 인터페이스로 충분하다면 구현 변경이다. 그러나 새 도구를 지원하려고 core에 새로운 상태와 책임을 추가해야 한다면 Architecture 검토가 필요하다.
변경 절차
아키텍처 변경이 필요할 때는 다음 절차를 따른다.
- 현재 구현에서 해결할 수 없는 문제와 증거를 기록한다.
- 변경이 구현 세부, 계약 명확화, 책임 변경 중 어디에 속하는지 분류한다.
- 책임이나 불변식이 바뀐다면 현재 역할을 완료하거나 파킹한다.
- Architecture 역할로 전환한다.
- 기존 동결 문서와 충돌 범위를 명시한 ADR을 작성한다.
- 영향받는 불변식과 인터페이스, migration, rollback을 정리한다.
- Human 승인을 받은 뒤 동결 기준 문서를 갱신한다.
- 새 기준선에서 Reference Implementation Plan을 수정한다.
- 이후에 구현 역할로 돌아간다.
출처가 없는 새로운 책임이 나타나면 구현 편의로 처리하지 않고 architecture drift로 판정한다. 이 절차가 실제로 지켜지는지는 아래 항목으로 점검한다.
- 동결 명세에 없는 새 Runtime Unit이 추가됐는가
- 기존 책임이 다른 컴포넌트로 이동했는가
- 불변식과 충돌하는 상태 전이가 추가됐는가
- 새 lifecycle trigger가 ADR 없이 추가됐는가
- 정본 위치가 migration 계획 없이 변경됐는가
- 구현 문서가 동결 출처를 참조하고 있는가
3.22 정상 작업의 전체 시퀀스
각 컴포넌트를 따로 설명하면 구조는 보이지만 실제 요청이 어떻게 흐르는지는 잘 보이지 않는다. 정상 작업 시퀀스는 Human의 요청이 Track, Repository Harness, Worker, Evidence, Acceptance를 지나 어떤 조건에서 닫히는지 한 번에 보여 준다. 다음은 목표 아키텍처를 기준으로 한 단일 레포 작업의 전체 흐름이다.
*(현재는 Master와 Human이 헌장 문서를 읽고 각 단계를 수동으로 집행한다. 이후 구현에서는 이 책임과 결과물의 연결을 런타임 컴포넌트로 자동화할 계획이다.)* 이 절은 단계 연결의 정본이다.
단계 안에서 필요한 세부 규칙은 이미 앞에서 정했다. lease는 3.9의 스키마와 상태 전이를 쓰고, gate는 3.10의 G0~G3 분류를 쓰며, evidence와 acceptance는 3.11의 수락 기준을 쓴다.
| 단계 | 담당 | 작업 | 결과물 |
| 1 | Human | 작업과 제약 조건을 요청한다 | Task Request |
| 2 | Master | 현재 역할과 트랙을 확인하고 작업을 분류한다 | 작업 범위와 대상 트랙 |
| 3 | Context Resolver | 워크스페이스, 레포, worktree를 판별한다 | Context Descriptor |
| 4 | Repository Runtime Loader | 레포 규칙, 계획, 지식 포인터, 검증 명령을 불러온다 | Repository Context |
| 5 | Approval Manager | 예정된 행동의 게이트 등급을 판정한다 | Gate Decision |
| 6 | Worker Scheduler | worktree와 예산을 할당하고 lease를 발급한다 | Active Lease |
| 7 | Worker | 조사, 구현, 자체 검증을 수행하고 결과물을 제출한다 | Evidence Bundle |
| 8 | Observability | diff, 테스트, 프로브, 런타임 상태를 확인한다 | 관측된 증거 |
| 9 | Acceptance | 게이트와 증거를 바탕으로 결과를 수락하거나 반려한다 | Acceptance Decision |
| 10 | Work Ledger | 수락된 상태, 미수락 결과, blocker와 다음 행동을 기록한다 | 갱신된 실행 상태 |
| 11 | Knowledge Store | 반복해서 사용할 가치가 있는 정보를 승격 후보로 분류한다 | 정본 변경 또는 포인터 |
| 12 | Master | 모든 수락 조건이 충족되면 작업이나 트랙을 종료한다 | Closed State |
현재 운영: 정상 작업 시퀀스의 수동 집행 Master와 Human이 일부 Approval Manager 역할을 수동으로 수행하고, dispatch gate와 파견 티켓처럼 일부 조건은 기계로 집행한다. 앞의 3.10에서 Gate별 수락 경로를 G0~G3 표로 고정했다. 3.22에서는 해당 Gate Decision이 어느 단계에서 계산되고 Acceptance로 어떻게 연결되는지만 보여 준다.
Human
│ Task Request
▼
Master
│ classify task / inspect role and track
▼
Context Resolver
│ resolve workspace and repository
▼
Repository Runtime Loader
│ load rules, planning, knowledge pointers
▼
Approval Manager
│ classify planned actions
▼
Worker Scheduler
│ allocate worktree and issue lease
▼
Worker
│ inspect → implement → test → submit
▼
Observability
│ collect diff, test, probe, runtime evidence
▼
Acceptance
├─ accepted ───────────────► Update Work Ledger
├─ changes requested ──────► Return to Worker
├─ rejected ───────────────► Record Failure
└─ Human verification ─────► Approval Gate
│
▼
Acceptance Decision
여기서 Worker의 작업 종료와 결과물의 최종 수락은 서로 다른 사건이다. Worker가 lease를 끝냈거나 complete라고 보고했더라도, 증거가 부족하면 작업은 완료 상태로 전환되지 않는다. Work Ledger에는 실행 도중에도 lease 상태와 blocker를 기록하지만 최종 상태는 Acceptance 결과가 나온 뒤 확정한다.
영구 지식 승격은 반복해서 쓸 가치와 증거가 있는 정보에만 적용한다. 뒤의 3.25에서 그 조건을 따로 정리한다. 어느 단계에서든 실패가 발생하면 증거와 현재 상태를 보존한다.
그런 뒤 뒤의 3.24에서 정리하는 실패 처리 절차로 전환한다. 각 단계에는 다음 단계로 넘어가기 위한 명시적인 조건이 있다.
| 단계 | 담당 | 산출물 | 다음 단계 조건 |
| 작업 분류 | Master | 대상 Track, 역할, 레포 | 책임 경계가 확정됨 |
| 컨텍스트 해석 | Context Resolver | Context Descriptor | 대상 레포와 실행 위치가 검증됨 |
| 하네스 적재 | Repository Runtime Loader | 규칙, 검증 명령, 정본 포인터 | 필요한 정본을 읽을 수 있음 |
| 위험도 분류 | Approval Manager | Gate 등급 | 승인 필요 여부가 결정됨 |
| 실행 준비 | Worker Scheduler | worktree와 lease | 범위, 예산, 제출물이 명시됨 |
| 구현 | Worker | artifact와 worker claim | 요구된 결과물이 제출됨 |
| 관측 | Observability | evidence bundle | 외부에서 증거를 확인할 수 있음 |
| 수락 | Approval Manager 또는 Human | acceptance decision | Gate와 수락 조건을 충족함 |
| 상태 반영 | Master와 Repository Harness | Ledger 및 정본 갱신 | 실행 상태와 영구 지식이 분리돼 기록됨 |
Worker가 결과물을 제출하면 worker_claim: complete와 acceptance: accepted를 분리해 본다. Evidence Bundle이 요구 조건을 충족하고 필요한 승인을 통과해야만 작업을 완료 상태로 전환할 수 있다.
검증에 실패하면 Work Ledger를 완료로 바꾸지 않는다. 구현 결과와 검증 실패 기록을 그대로 남기고 changesrequested 또는 blocked 상태에서 다음 행동을 결정한다.
3.23 크로스레포 작업의 전체 시퀀스
이 하네스를 만들게 된 큰 이유 중 하나가 크로스레포 시야 부재였다. 백엔드 계약과 프론트엔드 소비자는 서로 다른 레포에 있지만 하나의 작업으로 닫힌다. 이 절은 그 사이의 선후 관계와 수락 조건을 Master가 어떻게 붙잡는지 설명한다.
크로스레포 작업에서는 Master가 하나의 트랙 안에서 여러 레포의 작업 순서와 의존성을 조율한다. 각 레포의 구현 책임은 해당 Repository Harness와 Worker에게 남긴다.
현재 운영: Cross-repo Planner와 Release Coordinator 책임
각 레포는 자신의 Repository Harness와 별도의 Worker lease를 유지한다. Cross-repo Planner와 Release Coordinator는 Phase 9의 목표 역할명이며, Master가 이 책임을 수동으로 수행한다. Cross-repo Planner는 레포 사이의 계약과 선후 관계를 관리하고 각 레포의 구현 방식과 테스트 진실은 해당 Repository Harness가 소유한다.
아래는 백엔드 API를 변경하고 프론트엔드가 이를 사용한 뒤 프로덕션에 배포하는 경우의 예시다.
| 순서 | 담당 | 작업 | 통과 조건 |
| 1 | Master | 크로스레포 트랙을 만들고 대상 레포와 의존 순서를 정한다 | 대상 레포, 계약 경계, 순서 확정 |
| 2 | Backend Harness·Worker | API 계약과 백엔드 구현을 변경한다 | 백엔드 테스트와 계약 증거 제출 |
| 3 | Acceptance 또는 Human | 변경된 API 계약을 검토한다 | breaking change와 외부 영향 확인 |
| 4 | Frontend Harness·Worker | 수락된 계약을 기준으로 소비 측 구현을 변경한다 | 프론트엔드 테스트와 빌드 통과 |
| 5 | Master | 레포 사이의 통합 검증을 조율한다 | API와 UI 연동 프로브 통과 |
| 6 | Release Coordinator | 배포 순서와 rollback 절차를 정한다 | 배포·복구 순서 확인 |
| 7 | Human | 배포를 승인한다 | G3 명시적 승인 |
| 8 | Observability | 배포된 버전과 실제 동작을 확인한다 | 버전, 로그, 실제 요청 결과 일치 |
| 9 | Knowledge Store (Repository Harness) | 필요한 ADR이나 runbook을 갱신한다 | 정본 변경 이력 보존 |
| 10 | Master | 모든 수락 결과를 반영하고 트랙을 종료한다 | 열린 lease와 미수락 결과 없음 |
Backend Repository
│
│ API Contract + Evidence
▼
Cross-repo Planner
│
├─ 계약이 수락됐는가?
│ │
│ └─ No ──► Backend 변경 또는 승인 대기
▼
Frontend Repository
│
│ Consumer Implementation + Evidence
▼
Integration Probe
│
├─ 통과했는가?
│ │
│ └─ No ──► 원인 레포 판별 후 재작업
▼
Release Coordinator
│
▼
Human Deployment Gate
│
▼
Post-deployment Verification
프론트엔드의 탐색 작업이나 mock 작성은 백엔드 계약이 확정되기 전에도 병렬로 진행할 수 있다. 최종 구현과 수락은 검증된 계약을 기준으로 해야 한다. 초안 계약을 확정된 정본처럼 사용하면 두 레포가 서로 다른 가정을 구현할 수 있기 때문이다.
API 계약 변경이 breaking change가 아니고 사전에 위임된 범위 안에 있다면 정책에 따라 자동 수락할 수 있다. 반대로 외부 소비자에게 영향을 주거나 호환성을 깨뜨리는 변경이라면 Human 승인을 포함한 상위 게이트로 올린다. 백엔드 작업 중 프론트엔드 변경이 필요하다는 사실을 발견하면 Worker는 범위 확대를 제안하고 Master가 Track의 대상 레포와 실행 순서를 다시 결정한다.
하나의 Worker는 편의상 여러 레포를 임의로 수정할 수 없다. 다른 레포의 변경이 필요해지면 현재 lease를 확대하는 대신 Master에게 범위 변경을 제안하고 해당 레포를 위한 별도의 lease와 수락 조건을 발급한다. 한 레포의 테스트 통과는 전체 작업 완료와 별개다.
크로스레포 작업은 각 레포의 개별 evidence와 계약 검증, 통합 프로브까지 통과해야 수락할 수 있다.
fan-out과 fan-in의 실측 지형
이 시퀀스는 실제 운영에서 다음 토폴로지로 돌았다.
레포가 다른 독립 작업, 예를 들어 프론트엔드 화면 폐기와 백엔드 DTO 추가는 병렬로 나가고(fan-out), 타입 생성이 배포에 걸린 작업은 의존성이 풀릴 때까지 대기열에 남는다. 합류 지점(fan-in)에는 리뷰 게이트가 붙는다.
인증서 만료 같은 인프라 이벤트도 같은 그래프 위에서 전파를 계산했다. dev 인증서 만료는 프론트엔드 빌드의 코드 생성, CI, prod 배포 열차에 순서대로 영향을 주므로, 감지 즉시 기능 작업보다 앞 순서로 올라갔다(2부).
flowchart TD
M["Master: 워크스페이스 상위 관제"]
M --> A["백엔드 레포"]
M --> B["프론트엔드 레포"]
M --> C["운영 문서 레포"]
A --- WA["워크트리 규율: repo당 1개"]
B --- WB["워크트리 규율: repo당 1개"]
G["code-review-graph"] -.->|"영향 반경·호출 관계"| M
D["의존성 판단: 독립 작업만 fan-out"] --> M
A --> F["fan-in: 통합 검증 + 리뷰 게이트"]
B --> F

3.24 실패 처리
실패를 바로 재시도로 넘기면 같은 오류가 더 빠르게 반복된다. 실패는 현재 상태와 다음 허용 행동을 바꾸는 사건으로 기록해야 한다. 그래야 시말서와 postmortem이 다음 실행을 바꾸는 관측 장치가 된다.
실패는 현재 상태와 다음 허용 행동을 바꾸는 명시적인 상태 전이다. 그래서 실패가 발생하면 바로 재시도하기보다 먼저 실패 유형을 판별하고 관련 증거와 미수락 결과를 Work Ledger에 남겨야 한다. 실패는 구현 오류, 검증 실패, 승인 거절, 런타임 장애, 지식 불일치로 구분한다.
| 실패 유형 | 상황 | 대응 |
| Implementation Failure | 테스트 실패, 빌드 실패, 구현 오류 | 현재 결과를 미수락 상태로 두고 Worker에게 수정을 요청한다 |
| Scope Failure | 작업 중 다른 레포나 권한이 필요해짐 | lease를 임의로 확대하지 않고 Master에게 범위 변경을 제안한다 |
| Verification Failure | Worker의 주장과 diff·테스트 결과가 일치하지 않음 | 수락을 거절하고 부족한 증거 또는 수정 사항을 명시한다 |
| Approval Rejection | Human이 배포나 공유 변경을 승인하지 않음 | 트랙을 blocked 또는 changesrequested 상태로 전환한다 |
| Runtime Failure | Orca 재시작, PTY 단절, Worker 소실 | 즉시 새 세션을 만들지 않고 Recovery Manager의 순서로 상태를 확인한다 |
| Knowledge Conflict | Git 문서와 memory의 내용이 충돌함 | 정보 유형별 정본을 우선하고 캐시나 포인터를 다시 생성한다 |
| Role Violation | Architecture 역할에서 구현이나 배포를 시도함 | 행동을 중단하고 결과물을 미수락 상태로 둔 뒤 Role State를 복구한다 |
| Budget Failure | 토큰, 시간, Worker 수가 lease 예산을 초과함 | 추가 dispatch를 중단하고 범위 축소·파킹·예산 재승인 중 하나를 선택한다 |
Runtime Failure가 발생했다고 해서 해당 Worker를 바로 실패로 확정해서는 안 된다. 프로세스와 PTY가 살아 있지만 화면에서만 보이지 않을 수도 있다.
실행 상태를 확인하기 전까지는 unknown 또는 recovering 상태로 두는 편이 안전하다. failed 확정은 그 뒤의 일이다. Knowledge Conflict에서는 정보 유형별 정본을 먼저 판별한다.
영구적인 제품·운영 지식은 Git 문서가 정본이고 현재 이슈의 실행 상태는 Work Ledger가 정본이다. beads memory나 handoff는 자신의 책임 범위 안에서만 사용하며 다른 정본과 충돌하면 다시 생성하거나 갱신한다. 실패 처리에는 다음 원칙을 적용한다.
- 실패 원인을 판별하기 전에 같은 작업을 자동으로 반복하지 않는다.
- diff, 로그, 테스트 결과, 프로세스 상태처럼 실패 당시의 증거를 보존한다.
- 수락되지 않은 결과와 이미 수락된 상태를 구분한다.
- 현재 트랙과 lease 상태를 Work Ledger에 반영한다.
- 재시도가 가역적이고 안전하며 예산 안에 있을 때만 다시 실행한다.
- 반복되거나 운영 위험이 큰 실패는 postmortem 또는 runbook 승격 후보로 분류한다.
반복 실패를 문서화할 때는 반복 원인, 재현 조건, 탐지 방법, 안전한 복구 절차처럼 다음 작업에서도 쓸 수 있는 내용만 승격 대상으로 삼는다.
현재 운영: 실패가 규칙이 되는 파이프라인 이 절의 승격 절차는 실물로 있다.
운영 레포에는 Master가 자기 실수를 부검한 시말서(blame 문서)가 쌓인다. 시말서는 관측가능성 장치로 쓴다. 사람이나 모델을 혼내는 기록으로 설계하지 않는다.
무엇을 봤는지, 무엇을 못 봤는지, 어느 판단이 사후 재구성인지 남겨 다음 세션이 같은 장면을 다시 판정하게 만든다. 완료된 워커를 여섯 시간째 진행 중으로 보고한 감시 오보, 정상 동작 중인 워커를 런어웨이로 오진하고 중단 명령을 발사한 사건이 대표 사례다. 시말서는 관측 증거를 먼저 놓고 자기 변명을 조목조목 기각하는 형식으로 쓴다.
오보 시말서의 가중 사유는 한 줄로 요약되어 있다. 교훈을 문서로만 박제하고 행동에 배선하지 않았다는 것. 승격의 종착점은 문서에 머물 수 없다.
시말서의 재발 방지 항목은 운영 정본과 훅, 게이트로 옮겨진다. 실측 없는 확정 발화 사고 이후 승계 감사 절차에는 git 실측 요구가 추가됐다. 이틀 뒤 감사 로그에는 재발방지 적용 문구가 남았다.
감시 오보 이후에는 워커 상태 판정의 입력이 감시 신호에서 git 실측으로 바뀌었다. 실패를 문서로만 남기면 같은 세션이 같은 날에도 재범한다. 규칙과 훅으로 옮겨야 반복이 멈춘다.
최근 회고 장면들도 같은 양식으로 분해했다. [강제] Human의 지적이나 중단 명령 때문에 Master가 행동을 멈춘 사례에는 통계 페이지 두 차례 오파견, Agent tool 파견의 게이트 누락, 문체 탐지 모델 비용 지적이 포함된다. [형성] 각 사건에는 이미 주입된 규칙이 있었다.
보고서형 admin 화면, dispatch gate와 원장, 토큰 예산 규율이 그것이다. [판단] Master가 붙인 동기는 사후 재구성 가능성이 있어 별도 층으로 격리한다. 이렇게 기록해야 다음 수정자가 "무엇이 관측값이고 무엇이 해석인가"를 분리해 읽는다.
리뷰 게이트의 오판도 같은 절차로 다룬다. 3-vote가 NO_GO를 내면 블로커를 실측으로 재심한다. false-negative는 근거와 함께 기각하며 유효 지적은 앞의 3.11에서 정한 evidence 수락 기준에 따라 수정으로 잇는다.
워커의 규칙 오독과 과설계도 계약 문구의 명확화와 단순성 리뷰의 수락 기준 승격으로 규칙화됐다.
3.25 영구 지식 승격 조건
모든 교훈을 영구 지식으로 올리면 다음 세션은 또 많은 문서를 읽어야 한다. 반대로 아무것도 올리지 않으면 같은 실패가 반복된다. 승격 조건은 무엇을 오래 보존할지 정하는 비용 기준이다.
모든 작업 내용을 wiki에 남기면 다시 문서 퇴적물이 된다. 다음 조건 중 하나 이상을 만족하는 정보만 영구 지식으로 승격한다. 이 절은 Research 층의 질문에도 답한다.
운영 규칙이 출처 없이 남으면 다음 세대 Master는 그것을 취향이나 임시 선호로 읽고 비용이 높을 때 폐기할 수 있다. 그래서 승격 후보는 실패 사건, 재현 조건, 탐지 방법, 복구 절차, 승인 근거를 함께 가져야 한다. 출처가 없는 규칙은 검증되지 않은 가설로 남기고 증거와 수락을 통과한 규칙만 게이트, 훅, runbook, 정본 문서로 올라간다.
| 조건 | 설명 |
| 반복 가능성 | 같은 문제나 판단이 다시 나타날 가능성이 높다 |
| 반복 문의 가능성 | 다음 작업자가 같은 질문을 다시 조사할 가능성이 높다 |
| 비가역성 | 잘못 판단했을 때 되돌리기 어렵거나 복구 비용이 크다 |
| 의존성 | 다른 결정, 구현 또는 운영 절차가 이 사실에 의존한다 |
| 운영 위험 | 장애, 보안, 데이터 손실, 권한 오용과 연결된다 |
| 비직관성 | 코드나 현재 상태만 봐서는 이유를 파악하기 어렵다 |
| 외부 계약 | API, 배포 규칙, 규제, 고객 약속과 연결된다 |
다음 정보는 영구 지식 승격 대상에서 제외한다.
- 현재 이슈의 시간순 작업 기록
- 한 번만 사용한 명령의 전체 출력
- 코드만 읽어도 명확하게 알 수 있는 단순 사실
- 아직 검증되지 않은 가설이나 추측
- 비밀번호, 토큰, 인증 정보 같은 비밀 데이터
- 이미 다른 정본에 존재하는 내용의 전문 복제본
영구 지식 승격은 다음 순서로 진행한다.
Candidate Information
│
▼
Verify Evidence and Acceptance
│
▼
Classify Scope
│
├─ Product / Code ──────► Repository Wiki
└─ Workspace / Harness ─► operations-repo/docs
│
▼
Search Existing Canonical Knowledge
│
├─ exists ─────► Update or Supersede
└─ absent ─────► Create Canonical Entry
│
▼
Review and Commit
│
▼
Update Work Ledger and Pointer Cache
먼저 해당 정보가 외부 증거로 확인됐고 작업 결과가 수락됐는지 검토한다. 다음으로 제품·코드에 속하는지, 워크스페이스·하네스 운영에 속하는지 판별한다. 저장 위치를 정한 뒤에는 같은 내용이 기존 정본에 있는지 검색한다.
이미 존재한다면 새 문서를 추가하지 않고 기존 문서를 갱신하거나 supersede 관계를 남긴다. 새로운 정책이나 고위험 운영 규칙이라면 Human 승인을 거쳐 Git 이력에 반영한다.
마지막으로 Work Ledger에는 어떤 지식이 어디로 승격됐는지 기록하고 beads memory에는 필요할 때 정본을 찾을 수 있는 짧은 포인터만 남긴다. scratchpad나 handoff에 있던 전문은 장기 복제본에서 제외한다.
현재 운영: 영구 지식 승격의 수동 집행 사람이 이 과정을 판단하고 집행한다.
목표 구현에서는 중복 canonical ID, 잘못된 저장 경로, memory의 장문 전문 같은 형식 위반을 자동 검사할 수 있다. 어떤 정보가 장기적으로 가치 있는지는 의미 판단이 필요하므로, 완전 자동화 대신 Master와 Human의 검토 대상으로 남긴다.
3.26 Repository Layout
책임 경계를 실제 코드로 옮길 때 디렉터리 구조가 먼저 보이기 쉽다. 그러나 레이아웃은 설계의 결과이지 설계 자체가 아니다. 아래 구조는 앞 절들의 책임과 Adapter 경계를 코드에 놓기 위한 참조 배치다.
아래 구조는 동결된 설계를 코드로 옮길 때 사용할 수 있는 Reference Implementation의 예시 레이아웃이다. *현재 실물은 core runtime 하위의 부분 구현과 운영 문서가 함께 존재하는 단계다. 아래 구조는 전체 제품화 시의 예시 레이아웃이다.*
agent-harness/
├── README.md
├── spec/
│ └── README.md # 아키텍처 정본을 가리키는 포인터
├── src/
│ ├── bootstrap/
│ ├── context/
│ ├── workspace/
│ ├── repository/
│ ├── scheduler/
│ ├── approval/
│ ├── role/
│ ├── recovery/
│ ├── succession/
│ ├── lineage/
│ ├── observability/
│ └── adapters/
│ ├── work-ledger/
│ ├── knowledge-store/
│ ├── execution-substrate/
│ ├── executor/
│ ├── trace-archive/
│ └── human-interface/
├── probes/
│ ├── duplicate-master/
│ ├── knowledge-integrity/
│ ├── lease-health/
│ └── handoff-integrity/
├── tests/
│ ├── contract/
│ ├── recovery/
│ ├── succession/
│ ├── approval/
│ └── scenarios/
└── docs/
├── implementation/
└── adapter-guides/
src/ 아래의 디렉터리는 3.3에서 설명한 Runtime Unit의 책임 경계와 대응한다. 처음부터 각각을 별도 프로세스나 마이크로서비스로 구현할 필요는 없다. 하나의 CLI나 프로세스 안에서 시작하더라도 책임과 인터페이스는 분리해야 한다.
docs/implementation/에는 라이브러리 선택, 내부 타입, 성능상 타협처럼 구현 단계에서 결정한 내용을 남긴다. Runtime Unit의 책임이나 불변식을 바꾸는 문서는 이곳에 추가하지 않고 정본 Architecture의 ADR 절차로 올린다. docs/adapter-guides/에는 Orca, beads, Git, Codex 같은 구체 도구의 명령과 제약을 기록한다.
Core 문서에 제품별 예외를 흩어 놓지 않기 위한 경계다. src/는 런타임 책임별 구현을 담고 adapters/는 외부 도구와의 결합을 격리한다. probes/는 실행 중인 시스템의 불변식을 확인하며 tests/는 계약과 실패 시나리오를 검증한다.
spec/README.md에는 Architecture 문서의 복제본을 넣지 않는다.
대신 정본 경로, 기준 revision, 마지막 검증 시각 같은 포인터만 기록한다. 구현 레포 안에서 별도의 스펙 복제본을 수정할 수 있게 만들면 Architecture Freeze와 SSOT 구조가 다시 깨진다. (spec 디렉터리 이름은 사용 중인 스킬 프레임워크에 맞춘 선택이며 자유롭게 바꿔도 된다.)
canonical_spec:
repository: operations-repo
path: docs/specs/AHE-REFERENCE-ARCHITECTURE-v1.md
revision: <commit-or-version>
구현 레포 안에서 아키텍처를 직접 수정할 수 있게 만들면 어느 문서가 현재 정본인지 다시 판별해야 한다. 구현에 필요한 설명은 docs/implementation/에 둘 수 있지만 여기서 새로운 책임이나 불변식을 정의해서는 안 된다. 디렉터리 구조만으로 책임 분리가 보장되지는 않는다.
예를 들어 scheduler/가 beads 명령을 직접 호출한다면 Adapter Layer를 둔 의미가 사라진다. import 규칙이나 정적 검사로 core가 구체적인 도구 구현체를 직접 참조하지 못하게 해야 한다.
3.27 핵심 계약 테스트
문서로 불변식을 적어 두는 것과 실제로 깨지지 않게 만드는 것은 다르다. 이 하네스에서 테스트는 기능이 돌아가는지보다, Worker 자기 수락이나 중복 resume 같은 금지 상태가 실패로 처리되는지 먼저 본다. 초기 구현에서는 기능 수를 늘리기 전에 불변식과 경계부터 자동화해야 한다.
| 테스트 | 검증 내용 |
| Bootstrap Budget Test | L0·L1 컨텍스트가 정해진 예산을 넘지 않고, 장문 정본이 부팅 시 전문으로 주입되지 않는다 |
| Context Resolution Test | workspace root, repository, worktree를 올바르게 구분하고 대상 레포를 잘못 선택하지 않는다 |
| Repository Isolation Test | Worker가 lease에 포함되지 않은 레포와 경로를 수정하지 못한다 |
| Approval Gate Test | G3 행동이 Human의 명시적 승인 없이 실행되지 않는다 |
| Self-report Rejection Test | Worker의 자연어 완료 보고만으로 작업 상태가 accepted로 바뀌지 않는다 |
| Duplicate Resume Test | 같은 session ID가 두 프로세스에서 동시에 resume되지 않는다 |
| Runtime Restart Recovery Test | 클라이언트 재시작 시 살아 있는 PTY에 재부착하고, 실행이 실제로 소멸한 경우에만 후임을 생성한다 |
| Succession Verification Test | 후임이 handoff와 정본을 검증하지 못하면 전임을 은퇴시키지 않는다 |
| Role Lock Test | 현재 Master가 잠긴 역할 밖의 행동을 실행하지 못한다 |
| Knowledge Duplication Test | 같은 canonical ID나 동일한 정본 내용이 여러 위치에 중복 생성되지 않는다 |
| Memory Pointer Test | beads memory에 ADR이나 postmortem 전문이 저장되지 않는다 |
| Handoff Singularity Test | 하나의 Track에 LIVE handoff가 두 개 이상 존재하지 않는다 |
| Architecture Drift Test | 동결된 설계에서 파생된 근거 없이 새 Runtime Unit이나 책임이 추가되지 않는다 |
| Adapter Substitution Test | mock adapter로 교체해도 Core의 계약과 상태 전이가 유지된다 |
Runtime Restart Recovery Test처럼 실제 daemon과 PTY가 필요한 검증은 단위 테스트만으로 충분하지 않다. 반대로 모든 테스트를 실제 도구에 의존하게 만들면 계약 오류와 환경 오류를 구분하기 어려워진다. 그래서 core 계약과 실제 Adapter 검증을 분리해야 한다.
테스트 이름이 존재하거나 한 번 통과했다는 사실만으로는 불변식 보장 범위가 부족하다. 테스트가 어떤 경로와 실패 조건을 실제로 검증하는지 확인해야 한다. 이 테스트들은 실행 환경에 따라 세 층으로 나누는 편이 좋다.
- Contract Test 외부 도구 없이 타입, 상태 전이, Gate, Adapter 계약을 검증한다. 타입, 게이트, 컨텍스트 예산은 계약 테스트로 검증할 수 있다.
- Scenario Test 가짜 세션과 임시 레포를 사용해 실패, 복구, 승계 흐름을 검증한다. 프로세스, PTY, 앱 재시작은 실제 실행 환경을 사용하는 시나리오 테스트가 필요하다.
- Operational Smoke Test 실제 Orca, Git, beads 같은 구현체를 연결해 재부착과 중복 실행 방지 여부를 확인한다. 지식 중복과 handoff 개수는 Git과 파일 시스템을 검사하는 프로브가 적합하다. 역할 위반과 승인 우회는 런타임 가드와 테스트를 함께 사용해야 한다.
테스트 이름이나 초록색 상태만으로 불변식이 검증됐다고 단정해서는 안 된다. 어떤 fixture와 adapter를 사용했는지, 실제 프로세스를 실행했는지, 실패 조건을 의도적으로 재현했는지까지 확인해야 한다. 예를 들어 Runtime Restart Recovery Test는 새 세션 생성 여부보다 다음 두 상황의 구분을 검사해야 한다.
- Orca 클라이언트만 재시작되고 daemon과 PTY가 살아 있다면 기존 세션에 재부착한다.
- 기존 실행이 소멸했다는 증거가 있을 때만 handoff, Work Ledger, Git을 이용해 후임을 생성한다.
이 구분이 없으면 복구 테스트가 오히려 중복 Master 생성을 정상 동작으로 인정할 수 있다.
3.28 단계별 구현 순서
전체 하네스를 한 번에 만들면 하네스 자체가 새로운 실패 지점이 된다. 실제 운영에서 먼저 필요했던 능력은 정본과 실행 상태를 분리하고 제한된 lease와 evidence 수락을 반복하는 일이었다. 전체 시스템을 한 번에 구현하면 하네스 자체가 복잡성의 원인이 된다.
외부 도구에 의존하지 않는 계약부터 시작해 실행, 승인, 복구 순서로 확장한다. 아래 Phase 표는 자동화 구현 순서이며, 4부의 수동 운영 실측과 같은 완료 선언으로 읽지 않는다.
| Phase | 범위 | 완료 기준 |
| Phase 0 | 핵심 타입, 상태 전이, 불변식, adapter interface | 외부 도구 없이 계약 테스트 통과 |
| Phase 1 | Bootstrap, Context Resolver | 최소 컨텍스트로 workspace와 대상 레포 판별 |
| Phase 2 | Work Ledger, Knowledge Store adapter | 실행 상태와 영구 정본이 서로 다른 저장 규칙을 따름 |
| Phase 3 | Repository Runtime Loader, Worker Scheduler | 격리된 단일 레포 worktree에서 lease 실행 |
| Phase 4 | Evidence, Acceptance, Approval Manager | 자기 보고만으로 수락되지 않고 G0–G3 게이트가 작동 |
| Phase 5 | Role Runtime, Track Registry | Track 파킹과 명시적인 역할 전환 가능 |
| Phase 6 | Recovery Manager와 최소 복구 프로브 | 클라이언트·daemon·PTY·프로세스를 구분하고 중복 resume 차단 |
| Phase 7 | Succession Manager, Lineage Recorder와 최소 승계 프로브 | 후임 검증, 전임 종료 확인, lineage 기록까지 한 흐름으로 완료 |
| Phase 8 | Observability와 통합 프로브 | 중복 Master, stale handoff, orphan lease, 지식 드리프트 탐지 |
| Phase 9 | Cross-repo Planner, Release Coordinator | 두 개 이상의 레포를 사용하는 계약·배포 시나리오 통과 |
| Phase 10 | External Ledger 연결 | 정본을 복제하지 않고 외부 이슈 트래커에 상태와 포인터만 동기화 |
Phase는 검증할 수 있는 능력 단위다. 기능 목록과 구분된다. 예를 들어 Phase 3은 Worker가 lease 밖의 레포를 수정하지 못하고 종료 후 자원이 회수될 때 완료된다.
Scheduler 코드 존재만으로는 완료가 부족하다. MVP의 범위도 두 가지로 나눠야 한다.
- 실행 MVP: Phase 0~5 단일 레포 작업을 제한된 lease로 실행하고 evidence를 수락할 수 있는 수준이다.
- 운영 MVP: Phase 0~10 세션 재시작과 Master 승계를 포함해 장시간 작업을 실제로 이어갈 수 있는 수준이다. 승계와 복구를 실제 운영에 자동화하려면 중복 실행과 stale 상태를 지속적으로 탐지해야 하므로 Phase 8까지 포함하는 편이 안전하다. 다중 레포 릴리즈까지 자동화하려면 Phase 9, 10이 필요하다.
이 글의 주된 동기가 승계와 복구이므로, 실제 운영에 투입할 MVP라면 Phase 7까지 포함하는 편이 타당하다. Phase 8 이후는 운영 규모와 위험에 따라 점진적으로 추가할 수 있다. 각 Phase를 시작하기 전에 앞 단계의 계약을 다시 바꾸어야 한다면 책임이나 불변식 변경 여부를 먼저 판정한다.
책임이나 불변식이 달라지는 변경이라면 3.21의 Architecture Freeze 절차로 되돌아간다. Recovery와 Succession을 Observability보다 먼저 구현해도 해당 기능을 검증하는 최소 probe는 함께 둔다. Phase 6과 Phase 7에는 해당 기능을 검증하는 최소 probe가 반드시 포함된다.
Phase 8에서는 이 probe들을 통합해 지속적인 경보, 기준선, 예산 관측 체계로 확장한다.
현재 운영: 검증된 구현 범위 검증된 범위는 온보딩의 상태 매트릭스를 따른다.
Bootstrap과 dispatch gate, E12는 구성 또는 관측된 범위가 있고, Role State 주입은 구성과 출력이 확인됐다. runtime monitor의 coverage와 자동 Approval Manager, 완성된 contract test suite는 현재 운영 완료로 쓰지 않는다. 승계 여부 판단, 일부 승인 판정, 복구와 승계의 예외 판단은 여전히 Human과 Master가 절차를 읽고 집행한다.
3.29 이 시스템이 해결하는 실패 패턴
지금까지의 명세는 실패를 다시 부르는 방식으로 읽을 때 가장 잘 이해된다. 각 컴포넌트의 출발점은 실제로 반복된 실패 하나를 막는 데 있었다. 이 하네스는 다음과 같은 기존 실패 패턴을 직접 겨냥한다.
| 기존 실패 | 원인 | 대응 |
| 세션이 바뀌면 판단 근거가 사라짐 | 상태가 대화 기록에만 존재한다 | Work Ledger, Git 정본, thin handoff로 상태를 세션 밖에 둔다 |
| 같은 규칙이 여러 곳에서 다르게 존재 | 정보 유형별 SSOT가 없다 | 정본을 하나만 두고 다른 위치에는 포인터만 남긴다 |
| 앱 (IDE/ADE)이 죽으면 세션도 죽었다고 오판 | 클라이언트, daemon, PTY, Agent의 생명주기를 구분하지 않는다 | Recovery hierarchy에 따라 재부착 가능성을 먼저 확인한다 |
| 에이전트가 완료했다고 하면 그대로 믿음 | 제출과 수락이 분리돼 있지 않다 | diff, 테스트, 로그, 프로브를 대상으로 Acceptance를 수행한다 |
| 한 세션에서 여러 역할이 섞인다 | 현재 Role State와 전환 절차가 없다 | 한 번에 하나의 역할만 활성화하고 Role Lock으로 제한한다 |
| Worker가 작업 범위를 임의로 넓힌다 | 위임 범위와 권한이 명시되지 않는다 (lease 부재) | lease에 레포, 경로, capability, 예산을 기록한다 (Scope와 capability 제한) |
| 모델과 도구가 바뀌면 전체 구조가 깨짐 | 제품별 명령이 핵심 로직에 직접 결합돼 있다 (구체 도구 직접 결합) | 제품별 차이를 Adapter Layer 안에 제한한다 |
| memory가 세션마다 커진다 | 캐시와 영구 정본의 역할이 섞여 있다 | memory를 짧은 요약과 정본 포인터로 제한한다 |
| 확인하는 문서와 실제 Git의 내용이 서로 다르다 | 복제본 운영 | 복제본을 갱신하지 않는 아카이브로 강등 |
| handoff 파일이 계속 쌓여 최신본을 알 수 없다 | 파일 개수로 상태와 이력을 함께 표현한다 | 목표 상태에서는 Track마다 LIVE handoff를 한 건만 두고 이력은 Git으로 보존한다 |
| 설계가 구현 중 계속 변함 | 설계 변경과 구현 판단을 구분하지 않는다 (Freeze와 변경 절차 부재) | Architecture Freeze와 ADR 절차로 설계 변경을 구현 판단과 분리한다 |
| 멀티에이전트 비용이 통제되지 않는다 | Worker 수, 재시도, 토큰 예산에 제한이 없다 (dispatch budget 부재) | Scheduler가 lease 단위의 예산과 동시 실행 수를 강제한다 |
3.30 최종 시스템 모델
마지막 모델은 새 개념을 추가하지 않는다. 앞에서 본 지식 정본, Track, lease, evidence, approval, recovery, succession이 하나의 폐쇄 루프로 연결될 때 전체 하네스가 된다. 전체 시스템은 지식, 계획, 실행, 증거, 승인, 복구가 순환하는 폐쇄 루프다.
각 단계는 하나의 중앙 에이전트 안으로 들어가지 않고 책임 경계에 따라 나뉜다. 정보의 정본은 Git과 Work Ledger에 있고, Master는 이를 조율하며, Worker는 제한된 lease에서 실행하고, Human은 중요한 결정을 수락한다. Recovery와 Succession은 전체 수명주기를 둘러싼 연속성 계층이다.
Master나 Worker는 어느 단계에서든 중단될 수 있으므로, 두 기능은 정상 루프 전체를 감싼다.
┌──────────────────┐
│ Human │
│ Priority/Approval│
└────────┬─────────┘
│
▼
┌──────────────────┐ ┌──────────────────┐
│ Canonical │────►│ Master │
│ Knowledge │ │ Orchestrator │
│ Git / Repo Plan │ │ Track / Role │
└────────▲─────────┘ └────────┬─────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ Worker Scheduler │
│ │ Lease / Budget │
│ └────────┬─────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ Execution Worker │
│ │ Worktree / Task │
│ └────────┬─────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ Evidence Bundle │
│ │ Diff/Test/Probe │
│ └────────┬─────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ Acceptance │
│ │ Gate / Human │
│ └────────┬─────────┘
│ │
│ ┌───────────────┴───────────────┐
│ ▼ ▼
│ ┌──────────────────┐ ┌──────────────────┐
│ │ Work Ledger │ │ Knowledge │
│ │ Current State │ │ Promotion │
│ └──────────────────┘ └────────┬─────────┘
│ │
└──────────────────────────────────────┘
각 주체가 소유하는 것은 이렇다.
- Human은 우선순위, 비가역적 행동, 외부 권한과 최종 승인을 소유한다.
- Master는 Track, 역할, 위임, 레포 사이의 순서와 승계를 조율한다.
- Repository Harness는 해당 레포의 지식, 규칙, 계획, 빌드와 테스트 진실을 소유한다.
- Worker는 lease 안에서만 실행하고 결과물과 evidence를 제출한다.
- Git과 Work Ledger는 세션 밖에서 각각 영구 지식과 현재 실행 상태를 보존한다.
Recovery Manager와 Succession Manager는 어느 단계에서든 현재 Master나 Worker가 중단될 수 있다는 전제 아래 전체 실행 흐름의 연속성을 보장한다. 정상 루프의 어떤 지점에서도 "재부착 우선, 동일 세션 resume 1회, 필요 시 후임 생성" 순서를 적용한다. Lineage Recorder는 별도의 감사 경로이며 정상 루프의 입력에서 제외한다.
Succession Result
│
▼
Lineage Recorder
│ append-only
▼
Human Audit
│
└─► handoff와 운영 절차 개선
Human은 lineage를 읽고 다음 승계 절차를 개선할 수 있다. 다음 Master의 직접적인 복구 입력은 현재 handoff, Work Ledger, Git 정본이다. 이 시스템의 목표는 개별 세션과 모델, 실행 도구가 언제든 교체되거나 실패할 수 있다는 전제에서도 작업 상태와 정본 지식, 승인권, 책임 경계가 유지되게 만드는 데 있다.
시스템의 신뢰성은 모델의 기억력이나 자연어 응답 품질만으로 평가할 수 없다. 다음 조건을 외부에서 확인할 수 있어야 한다.
- 정본의 위치가 정보 유형별로 명확한가
- Worker의 실행 범위가 lease로 제한되는가
- 완료 주장이 외부 증거로 검증되는가
- 비가역적 행동이 Human의 승인을 거치는가
- 살아 있는 세션을 중복으로 resume하지 않는가
- 후임이 복구된 뒤에만 전임이 은퇴하는가
초기 세 번의 승계는 이 가운데 handoff 복구, 정본 확인, 전임 종료 검증, lineage 기록을 사람이 직접 집행할 수 있음을 보여줬다. 4부에서는 그 실측 과정에서 무엇이 실패했고 그 실패가 다음 세대의 절차를 어떻게 바꿨는지 살펴본다.
4부. 실측 기록: 초기 세 번의 승계에서 20세대 돌파와 3주 배포까지
앞 절까지는 설계 명세였다. 승계 프로토콜 자체는 실제 운영에서도 수행됐다. 설계 당일과 다음 날에 걸쳐 실제 Master 세션을 초기 세 번 승계했고 각 결과를 lineage에 기록했다.
이 절은 그 초기 실측을 먼저 다루고 이어서 12일 뒤까지의 확장 기록과 admin 3주 실증을 덧붙인다. 세 번의 실험 조건은 서로 달랐다. Gen 1은 헌장 발효 전의 계획 승계였고, Gen 2는 새 lineage 스키마를 처음 적용한 승계였으며, Gen 3은 프로토콜 전체를 확인하려고 의도적으로 실행한 smoke test였다.
| 승계 | 상황 | 복구 소스 | 결과 | 남긴 절차 |
| Gen 1 | 컨텍스트 지표 약 67% | Git, handoff, Work Ledger, Trace Archive | 열린 트랙 6개 인수, 재질문 0회 | 전임 생존 여부를 별도로 확인해야 한다 |
| Gen 2 | 로케일 버그 수정 완료 | Git, handoff, Work Ledger | 재질문 0회, 결정 재개봉 0건, 유실 없음 | PID와 커맨드라인까지 대조한다 |
| Gen 3 | 프로토콜 스모크 테스트 | 헌장, handoff, Work Ledger, Git | 재질문 0회, 결정 재개봉 0건, 유실 없음 | 모니터를 상속하지 않고 후임 소유로 다시 띄운다 |
여기서 컨텍스트 사용량은 당시 관찰 가능한 지표를 기준으로 한 근사치다. 모델 내부의 정확한 토큰 사용량 직접 측정값과 구분해야 한다.
Gen 1: 헌장 발효 전의 승계 // stale handoff를 발견하다
전임 마스터 세션의 컨텍스트 사용량이 UI 기준 약 67%에 도달했을 때 사용자가 계획 승계를 지시했다. 후임은 Git 정본, handoff, Work Ledger를 읽어 현재 상태를 복구했다. 이 과정에서 채팅에만 존재하고 Git에는 반영되지 않은 문서 한 건이 발견됐다.
후임은 Trace Archive로 이전 세션 기록을 검색해 문서를 회수하고 Git 정본에 편입했다. 승격되지 않은 대화 내용이 실제로 유실될 수 있다는 점을 보여준 사례였다. 후임은 이미 답이 있는 질문을 다시 하지 않고 여섯 개 트랙을 이어받았다.
승계 기록에는 감점 사유가 한 건 남았다. handoff에는 전임 세션이 곧 소멸할 것처럼 적혀 있었지만 실제 프로세스는 여전히 살아 있었다. 컨텍스트 전달에는 성공했지만 전임 은퇴 상태는 정확하지 않았다.
이 사례로 handoff의 서술만 믿지 않고 프로세스 상태를 별도로 확인해야 한다는 절차가 추가됐다.
Gen 2: 13필드 스키마의 첫 적용 // 승계 품질을 숫자로 정량화하고 루프로 개선
두 번째 승계는 로케일 버그 수정을 마친 자연스러운 마일스톤에서 진행했다. 앞의 3.14에서 설명한 13개 필드 lineage 스키마를 이때 처음 적용했다. 관측 결과는 다음과 같았다.
- 재질문 0회
- 근거 없는 결정 재개봉 0건
- 확인된 컨텍스트 유실 없음
- Trace Archive 검색 0회
Trace Archive 검색 0회는 handoff, Work Ledger, Git만으로 필요한 정보를 찾았다는 뜻이다. 그래서 과거 세션 기록을 추가로 검색할 필요가 없었다. 이 수치는 승계 후의 대화와 실행 기록을 기준으로 세고 사람이 검수했다.
후임 세션이 스스로 “승계에 성공했다”고 평가한 결과는 지표에 포함하지 않았다. 전임 세션을 종료할 때도 PID만 보고 바로 프로세스를 정리하지 않았다. 먼저 PID의 커맨드라인과 세션 경로를 대조해 해당 프로세스가 정말 전임 Master인지 확인했다.
그 뒤 대상 PID만 종료하고 ps로 소멸 여부를 다시 확인했다. 여러 에이전트 세션이 동시에 실행되는 환경에서 PID 숫자 하나만으로 프로세스를 정리하면 다른 세션을 종료할 수 있다. 커맨드라인과 세션 경로를 함께 대조하는 절차는 이 승계에서 정착됐다.
Gen 3: 승계 프로토콜 스모크 테스트
세 번째 승계는 컨텍스트 사용량 지표가 약 24%일 때 의도적으로 실행했다. 목적은 승계 프로토콜 전체를 처음부터 끝까지 다시 검증하는 스모크 테스트였다. 후임은 헌장, thin handoff, Work Ledger, Git 정본 순서로 현재 상태를 복구했다.
활성 트랙의 배포 체크리스트와 전날 발견한 인프라 결함을 재질문 없이 재진술했고 이 결함은 리다이렉트 대상에 예상하지 않은 개발 포트가 섞여 있던 문제였다.
원인은 dev nginx location /의 X-Forwarded 헤더 부재로 정리됐고, Next 미들웨어가 Location을 리슨 포트 기준으로 재절대화하면서 :3000 노출을 만들었다. 두 레포의 HEAD와 working tree 상태를 직접 확인해 handoff에 기록된 값과 대조했고 로컬 프로브의 응답 코드도 다시 측정해 handoff의 기준선과 일치하는지 확인했다.
전임이 실행하던 드리프트 모니터는 전임 세션 경로와 커맨드라인을 대조해 orphan 모니터만 종료한 뒤, 후임 세션의 소유 정보를 붙여 다시 실행했다. 이중 실행 가드와 첫 heartbeat를 확인했고 전임 Master의 커맨드라인을 확인한 뒤 해당 PID만 종료했다. 같은 머신에서 실행 중이던 다른 에이전트 세션이 유지되고 있는지도 ps로 확인했으며 Gen 3 lineage 항목을 append하고 Git commit과 push로 이력을 남겼다.
최종 지표는 재질문 0회, 근거 없는 결정 재개봉 0건, 확인된 컨텍스트 유실 없음이었다. Recovery Flow의 각 단계도 추가적인 Trace Archive 복구 없이 통과했다.
세 차례의 승계가 바꾼 것
세 번의 승계는 “작동했다”는 확인을 넘어 절차를 바꿨다. Gen 1에서 발견한 stale handoff가 Gen 2의 PID·커맨드라인 대조 절차로 이어졌다. Gen 2에서 소유자가 불명확한 채 남아 있던 orphan 모니터는 Gen 3에서 명시적인 정리와 재무장 절차로 바뀌었다.
Gen 1
stale handoff와 살아 있는 전임 발견
│
▼
Gen 2
PID·커맨드라인 대조와 종료 후 재확인
│
▼
Gen 3
orphan monitor 정리와 후임 소유로 재구성
Gen 1에서는 handoff와 실제 런타임 상태가 다를 수 있다는 사실을 확인했다. Gen 2에서는 전임 프로세스의 정체를 확인하고 종료를 검증하는 절차를 정착시켰다. Gen 3에서는 세션과 감시 프로세스에 모두 소유권이 필요하다는 점을 확인했다.
Lineage는 다음 Master에게 자동으로 주입하는 지식에서 제외한다. 후임은 변경된 정본을 기준으로 판단한다. 후임 Master는 Human 검토를 거쳐 handoff 양식과 운영 절차에 반영된 정본을 읽었다.
변경된 정본을 다음 세대가 읽은 것이다.
Lineage
│ 감사
▼
Human Review
│ 승인된 절차 변경
▼
Charter / Runbook / Handoff Template
│
▼
Next Master 승계
lineage는 관측 데이터이고 다음 세대가 직접 읽는 입력은 수정된 정본이다. 체감상 가장 큰 변화는 승계 비용이었다. 이전에는 새 세션이 열릴 때마다 작업 맥락을 다시 설명했고 빠진 내용은 며칠 뒤에야 발견되기도 했다.
이번 세 차례에서는 정본 확인과 프로세스 검증을 포함한 인수인계가 수분 단위의 절차로 끝났다. 정식 평균 소요 시간이나 실패율은 측정하지 않았다. 세 번의 성공은 수동 승계 프로토콜의 스모크 테스트 결과이며 장기 운영 신뢰성을 입증하는 벤치마크와 구분해야 한다.
이 흐름은 INV-11, 즉 lineage를 관측 데이터로 두고 런타임 지식 입력에서 제외한다는 원칙과 충돌하지 않는다. 런타임이 lineage를 자동 학습하지 않고 사람이 관측 결과를 검토하고 승인된 절차를 정본에 반영하기 때문이다. 세 차례의 내부 운영 기록만으로 모든 환경에서 같은 시간과 품질을 보장한다고 일반화할 수는 없다.
여기서 확인한 것은 이 워크스페이스에서 해당 절차가 세 번 연속 실행됐고 각 승계의 유실과 감점 사유를 같은 기준으로 기록할 수 있었다는 점이다.
그 후: 12일 뒤, 20세대 돌파
초기 세 번의 승계는 시작이었다. 첫 세대로부터 12일 뒤인 2026년 7월 28일 KST, 승계 장부의 세대 번호는 20을 넘었다. MASTER-LINEAGE.md에는 Gen 1부터 Gen 21까지 21개 항목이 남아 있다.
이 숫자는 실패 횟수와 무관하다. 컨텍스트 한계, 자연 마일스톤, 명시 지시에서 상태를 동결하고 후임이 이어받은 수명주기 기록이다.
초기 Gen 2와 Gen 3에는 Repeated-question count: 0, Reopened-decision count: 0 같은 품질 필드가 있고, Gen 20에는 전임 컨텍스트 89%와 모델 실측 기록이, Gen 21에는 전임 컨텍스트 97%와 세션 리밋 도달 사유가 적혀 있다. 다만 모든 세대가 같은 품질 필드를 완전하게 갖췄다고 확장해서 읽으면 안 된다.
승계 체계 자체도 이 기간에 v3로 개정됐다. 앞의 3.13에서 정한 대로 평시에는 컴팩션으로 계속 가고, 새 판은 Human 지시가 있을 때만 세우며, 컴팩션 손실은 앞의 3.15에서 설명한 회상 프로브로 계측한다. 가장 최근의 세대 교체는 세션 리밋 상황에서 일어났다.
진행 중이던 워크플로우의 캐시와 재개 경로를 남긴 채 후임이 같은 역할로 복귀했고, 그 과정 전체가 Succession 장부에 기록됐다. 다음 화면에서는 Gen 20이 세션 리밋 전에 변경 가능한 작업을 멈추고 후임 생존 확인 뒤 동결 상태로 남는 장면을 봐야 한다.

다음 화면에서는 Gen 21이 Role State와 전임 처리 결과를 읽고 같은 역할로 부팅하는 장면을 봐야 한다.

이 장면은 내가 증분 컴팩션을 한계까지 밀어붙인 의도적 실험이다. 컨텍스트 표시가 99~100%에 닿은 상태에서도 워커 지휘와 대기열 재설계는 유지됐고, compact 직후 첫 턴에 훅 주입이 붙지 않는 사각이 드러나 보정 이슈로 적재됐다. 독자는 여기서 세션 유한성을 운영 조건으로 계측한 장면을 보면 된다.

실증 사례: admin 3주
승계와 복구는 실제 제품 작업으로 판정된다. 이 시스템 위에서 진행된 대표 실증이 일정 압축 속에서 진행된 admin 서비스 배포다. 2026년 7월 9일 11:24 KST에 admin 전용 계획 레포가 만들어졌고, 11:28 KST에 요구사항 문서 세트가 추가됐다.
같은 날 18:26 KST에는 백엔드 레포에 2026년 스프린트의 net-new admin CRUD 커밋이 실렸다. 다만 백엔드 레포에는 2025년 admin skeleton 흔적이 있으므로 2026년 7월 9일을 레포 역사상 첫 admin 흔적으로 쓰면 안 된다. 프론트엔드 admin 첫 커밋은 2026년 7월 14일 13:57 KST다.
2026년 7월 29일 KST 기준으로 프로젝트 시작일부터 20일, 프론트 코드 시작일부터 15일이 지났다. prod 관련 근거는 2026년 7월 14일의 backend prod manifest fix와 prod merge 커밋 범위로 제한한다. 외부 런타임에서 배포 완료를 독립 관측했다는 주장으로 확장하지 않는다.
사전 명세 문서는 현재 확인 범위에서는 찾지 못했다. 재현되지 않은 커밋 수 집계는 이 글의 본문 근거에서 제외한다. 이 기간의 성과는 전체 제품 범위를 모두 끝냈다는 뜻이 아니다.
제한된 일정에 맞춰 UI/UX와 일부 확장 범위를 제외하고 프로덕션 MVP 범위를 재설정했으며, 핵심 플로우를 배포 가능한 범위로 좁혀 구현한 것이다. 성과의 실체는 판단과 실행에 있었다.
- 난잡한 조건에서 무엇을 버리고 살릴지 판정했다.
- 기존 코드와 데이터 흐름을 파악했다.
- 요구사항을 실행 단위로 분해했다.
- 프론트엔드·백엔드·AI 연동과 치명 실패 경로를 선별해 배포 가능한 상태를 만들었다.
이 일정 압축은 하네스를 구축한 이유와도 이어진다. 능력 증폭 시스템 없이 같은 조건에서 같은 속도로 판단과 검증을 반복하기는 어려웠다. 다섯 장면이 이 구조의 기여를 보여 준다.
- 인증서 만료 조기 경보. [강제] 모닝 브리핑 루프가 dev 인증서 만료를 만료 수 분 안에 잡고 빌드 파이프라인과 배포 열차에 미치는 영향까지 경고했다(2부). [형성] 야간 스캔, 코드 생성 의존성, 배포 큐가 같은 운영 루프에 들어와 있었다. [판단] 이 경보는 daily ops loop 설계의 산물로 읽는다.
- 4개월 묵은 prod 블로커. [강제] 방치된 골격을 되살릴 때 첫 관문은 배포 manifest의 고정 버전 태그 한 줄이었다. 한 줄 수정으로 넉 달 막혀 있던 prod 첫 가동이 열렸고 배포 스모크로 확인했다. [형성] 배포 manifest, 이미지 태그 생산 경로, 스모크 기준이 하네스 안에 묶여 있었다. [판단] 작은 diff가 큰 병목을 푸는 장면이지만 원인은 "한 줄"보다 배포 경로를 끝까지 관측한 절차에 있었다.
- 프론트 첫날 스프린트. [강제] API 클라이언트 배관, 앱 셸, 목록과 상세 화면, 요약 카드와 시계열을 갖춘 통계 화면, 조직 트리, 3개 로케일 i18n까지 첫날 커밋 열 건이 실렸다. [형성] 병렬 lease, route group 규율, i18n 검증 기준이 작업을 나눴다. [판단] 이 물량은 모델의 단발 생산량보다 작은 계약을 빠르게 발행하고 회수한 운영 방식으로 해석한다.
- 디자인도 같은 루프. [강제] 로그인 화면 제품화 이후 폴리싱 커밋이 열다섯 건 넘게 이어졌고 배경 투명도 문제는 병합 리뷰의 수정 우선 지적을 받아 고쳐졌다. [형성] 디자인도 diff, 화면 캡처, 접근성 렌즈로 검증하는 규칙이 붙어 있었다. [판단] 디자인 품질도 기능과 같은 검증 루프를 통과한다는 결론은 이 반복에서 나온 운영 해석이다.
- 삭제가 성과인 병합. [강제] 한 병합 요청은 24줄을 더하고 894줄을 지웠다. 대시보드 화면을 폐기하고 overview 화면을 정본으로 세운 결정이다. [형성] 스코프를 정한 것은 Human이었다. 시스템은 그 결정을 증거와 함께 실행했다. [판단] 삭제도 검증 루프를 통과하면 성과로 계상된다는 해석을 남긴다.
2부의 Human Gate 설명은 공유 상태를 바꾸는 행동이 Human 판단으로 올라간다는 흐름만 남긴다. admin 실증에서 그 추상 규칙은 구체적인 제품 판단으로 나타났다. [강제] Human Gate에 올라간 것은 다음 판단이었다.
- 제품 프레이밍 판정
- 스코프 차단
- 코드 단순성 판정
- 디자인 방향 결정
- 회사 가시성 기록 기준
[형성] Master는 이 판단들을 lease 범위, gate 상태, 기록 위치, 리뷰 조건으로 번역했다. [판단] 제품 방향은 사람이 닫았고, 하네스는 그 판단을 실행 계약과 검증 항목으로 옮겼다.
Gen 22와 Gen 23: 모델 정체성도 관측 대상이 되다 // 클린 리셋과 상설 부관 레인
2026년 7월 30일 KST, 승계 장부에는 또 다른 실패가 남았다. Gen 22는 새 판 클린 스폰으로 시작했고 첫 턴에서 claude-fable-5를 실측했다. 그 세션은 중간에 페인 오배치를 바로잡는 교정 재기동까지 거쳤다. 교정 뒤에도 세대 번호는 바뀌지 않았다.
문제는 그다음에 드러났다. Gen 22는 세션 안에서 claude-opus-4-8로 실행 모델이 바뀌었다. lineage에는 이 일이 model drift로 기록됐다.
여기서 원인은 구조 수준으로만 적는다. 민감 콘텐츠가 Master 컨텍스트에 반복 유입됐다. 그 유입이 안전장치 폴백을 불렀다. 구체 내용은 본문에 남기지 않는다.
[강제] 대응은 새 판이었다. Dorito가 명시 지시했고 Gen 23이 클린 스폰됐다. 후임은 부팅 직후 자기 세션 jsonl을 먼저 확인했다. model 필드 8건이 모두 claude-fable-5였고 argv 플래그도 일치했다. Opus 혼입은 관측되지 않았다.
이때 모델 정체성은 설정값만으로 다루기 어려운 운영 관측값이 됐다. lineage의 모델 실측 줄은 "어떤 모델로 실행 중인가"를 후임 부팅의 첫 증거로 남겼다. 선언 모델과 실행 모델이 다르면 앞의 3.15에서 정의한 Model Drift 경보가 열린다. 기본 대응은 새 판 클린 승계와 민감 영역 위임 상태 점검이다.
[형성] 절차는 레인 분리로 바뀌었다. 민감 영역은 Master 세대에 종속된 하위 호출로 두지 않았다. Control Center의 독립 Orca 페인에서 Opus 상설 세션이 맡았다.
그 세션은 Master 승계와 수명을 같이하지 않는다. Master는 낌새를 보면 내용을 읽거나 요약하지 않고 즉시 위임한다. 부관의 보고는 파일로 남고 Human이 직접 검토한다.
경로 가드 hook도 같은 축에 붙었다. 보안 경로 접근은 PreToolUse 단계에서 차단된다. 출력 필터 층은 아직 미확정으로 남았지만 경로 차단은 라이브에서 관측된 강제 장치다. Master가 실수로 손을 뻗을 때 사람이 매번 말로 막는 방식은 충분하지 않았다.
[판단] 이 사건의 교훈은 짧다. "위임하라"는 문장은 유입을 막지 못했다. 문장은 기억해야 할 규칙을 만들지만 런타임의 접근을 끊지 않는다. 경로 hook과 독립 부관 레인이 붙은 뒤에야 같은 유입 경로가 기계적으로 차단됐다.
3부에서 반복한 원칙은 여기서 검증됐다. 규율은 실행 경로에 배선될 때 운영 장치가 된다. 이 장면은 모델 라우팅, Succession, Observability, Safeguard Lane이 한꺼번에 맞물린 실측 기록이다.
이 설계가 필요한 경우와 과한 경우
여기까지 읽고 오버엔지니어링이라는 생각이 들 수 있고 일부 상황에서는 맞다. 단일 레포에서 며칠 안에 끝나는 작업을 하나의 에이전트와 진행한다면 AGENTS.md, 이슈 트래커, 최신 세션 요약 정도로 충분할 수 있다. 이런 환경에 12개 Runtime Unit과 lineage 장부까지 도입하면 관리 비용이 얻는 이점보다 커진다.
이 설계가 값을 하기 시작하는 조건은 다음과 같다.
| 조건 | 증상 | 해당 장치 |
| 트랙 수명이 세션보다 길다 | 세션이 바뀔 때마다 작업을 다시 설명한다 | Work Ledger, Git 정본, thin handoff |
| 여러 레포가 하나의 작업에 묶인다 | 레포 사이의 선후 관계와 계약을 둘 곳이 없다 | Track Registry, Cross-repo Planner |
| 여러 에이전트가 동시에 실행된다 | 누가 어디까지 수정할 수 있는지 불명확하다 | Worker lease, 격리 worktree, Evidence Bundle |
| 프로덕션 권한을 다룬다 | 잘못된 자동 실행이 외부 시스템이나 데이터에 영향을 준다 | Gate Model, Human 승인, Recovery 절차 |
넷 중 두 개 이상이 겹친다면 이 글의 구조 일부를 도입해 볼 만하다. 이는 운영 복잡성을 판단하기 위한 경험칙이며 실측으로 도출한 절대 기준과 구분해야 한다. 처음부터 전체 하네스를 구현할 필요도 없다.
다음 순서로 필요한 부분만 도입할 수 있다.
- 정본과 실행 상태를 분리한다.
- 활성 Track에 최신 handoff 한 건을 둔다.
- Worker 위임에 범위와 결과물을 명시한다.
- 완료 보고 대신 diff와 테스트 증거를 확인한다.
- 여러 에이전트가 동시에 돌기 시작하면 lease와 격리를 추가한다.
- 배포나 외부 권한을 맡기기 시작하면 승인 게이트와 복구 프로토콜을 추가한다.
가장 작은 형태로 가져갈 원칙은 세 가지다. 전체 구조를 도입하지 않더라도 다음 세 가지 원칙은 비교적 적은 비용으로 적용할 수 있다.
- 정본을 세션 밖에 둔다.
- 승계를 정상 수명주기로 다룬다.
- 에이전트의 자기 보고를 완료 증거로 사용하지 않는다.
이 세 원칙만 지켜도 특정 세션의 기억력에 의존하는 비중을 크게 줄일 수 있다. 나머지 컴포넌트는 실제 실패가 반복되거나 권한 범위가 넓어질 때 단계적으로 추가하는 편이 낫다. 이 세 가지는 12개 Runtime Unit을 구현하지 않더라도 Claude Code나 Codex를 장기 작업에 사용하는 환경에서 바로 적용할 수 있다.
도입 판단은 여기까지다. 이 구조의 수명은 특정 프로젝트의 수명과 따로 간다. 제품이 어떻게 되든 하네스는 다음 프로젝트로 이식되고 실패 기록과 함께 조금씩 단단해진다.
Lessons Learned
- 승계는 handoff 작성, 전임 생존, 세션 경로, 소유 모니터, 후임 첫 heartbeat를 함께 검산하는 절차다.
- Handoff에는 평가문보다 원시값을 남긴다. HEAD, working tree 상태, 프로브 응답 코드, 활성 lease ID, 미검증 범위처럼 후임이 다시 측정할 수 있는 값이 필요하다.
- Worker 수락은 작은 Evidence Bundle에서 시작한다. 변경 파일, diff 요약, 실행한 검증 명령과 결과, 알려진 gap, 이어서 볼 위치가 최소 단위다.
- 새 저장 위치를 만들기 전에 없앨 중복부터 찾는다. 유지 책임을 맡을 주체가 없다면 새 복제본을 만들지 않는다.
- 단순성도 수락 조건이다. 작동하는 구현이라도 불필요한 반복은 별도 리뷰로 줄인다.
- 회고는 문구로 끝내지 않고 gate, hook, ledger rule로 승격한다. 비용과 리뷰 평결도 같은 증거 규칙으로 재심한다.
맺음말
이 시스템은 세 겹의 실패에서 시작했다. 컨텍스트가 소진됐고, 여러 레포의 전파가 보이지 않았고, 감시받지 않는 에이전트가 자기 보고를 증거처럼 내놓았다. 그 실패를 처리하는 과정에서 handoff, Work Ledger, Git 정본, lease, evidence gate, Human Gate가 하나의 하네스로 묶였다.
실패를 남기는 방식이 중요했다. 실패를 문서에 적는 것만으로는 같은 세션이 같은 날에도 다시 틀렸다. 그래서 시말서의 재발 방지 항목은 운영 정본과 훅, 게이트로 옮겨졌다.
실패가 규칙으로 승격되는 이 루프가 시스템의 중심이다. 이 글은 관측되지 않은 것을 관측된 사실처럼 쓰지 않으려 했다. 정식 평균 소요 시간이나 실패율은 측정하지 않았다.
레포 하네스의 실효성도 이름이나 산출물만으로 단정하지 않는다. 테스트가 어떤 fixture와 adapter를 사용했는지, 실제 실패 조건을 재현했는지까지 확인해야 한다. 확인하지 못한 것은 확인하지 못했다고 남기는 편이 다음 세대에 더 유용하다.
독자가 가져갈 것은 하나다. 에이전트를 오래 쓰려면 세션의 기억력을 믿지 말고, 정본을 세션 밖에 두고, 자기 보고를 완료 증거로 사용하지 않아야 한다. 나머지는 실제 실패가 반복되거나 권한 범위가 넓어질 때 차례로 붙이면 된다.
(+ 추가 갱신: https://github.com/langchain-ai/deepagents Langchain 에서 오픈소스화 해둔 것이 있다. 하네스 관련 추가적으로 개념 등 문서 참고하시길.. )
부록. Claude Code 안에서 Codex를 부리는 법
본편의 설계 설명은 앞 절에서 끝났다. 이 부록은 같은 Master-Worker 구도를 실제 도구 조합으로 시험해 보고 싶은 독자를 위한 응용 예시다. 이 글의 Master와 Worker 구도는 Claude Code 안에서 Codex를 호출하는 방식으로도 구성할 수 있다.
이 경우 Claude Code가 계획과 조율, 최종 검토를 맡고 Codex는 구현이나 디버깅처럼 범위가 명확한 실행 작업을 맡는다. 이 구성은 Adapter Layer를 배선하는 한 가지 방법이다. 하네스의 필수 요소와 구분된다.
Claude Code와 Codex의 역할을 반대로 두거나, 둘 다 Codex 세션으로 구성해도 책임과 계약이 유지된다면 같은 구조를 적용할 수 있다.
1 Codex 플러그인 설치
Claude Code를 실행한 뒤, 다음 명령을 차례로 실행한다.
$ /plugin marketplace add openai/codex-plugin-cc
$ /plugin install codex@openai-codex
$ /reload-plugins
설치가 끝나면 다음 명령으로 Codex CLI와 인증 상태를 확인한다.
/codex:setup
이 명령과 플러그인 이름은 2026년 7월 18일 기준 OpenAI의 codex-plugin-cc 공식 저장소에 기재된 설치 절차와 일치한다. 설치 과정을 Claude Code에게 맡기고 싶다면 다음처럼 요청할 수 있다.
설치 검증 요청 예시
# 목표
이 Claude Code 환경에서 OpenAI의 공식 Codex 플러그인을 설정하고,
Claude Code 안에서 Codex를 호출할 수 있는지 확인하세요.
# 사용할 플러그인
openai/codex-plugin-cc의 codex@openai-codex 플러그인만 사용하세요.
# 허용 범위
- 플러그인과 Codex CLI의 설치 상태를 확인할 수 있습니다.
- 필요한 경우 공식 Codex CLI 설치를 제안하거나 수행할 수 있습니다.
- Codex 인증이 필요하면 제게 로그인을 요청하세요.
- 프로젝트 소스 코드와 설정 파일은 변경하지 마세요.
- 별도의 요청 없이 프로젝트 의존성을 설치하거나 빌드를 실행하지 마세요.
# 절차
1. /codex:setup을 실행해 현재 상태를 확인하세요.
2. Codex CLI가 없다면 공식 설치 방법을 사용하세요.
3. 인증이 필요하면 임의로 우회하지 말고 제게 로그인을 요청하세요.
4. 설정 후 /codex:* 명령이 표시되는지 확인하세요.
5. /agents에서 codex:codex-rescue가 보이는지 확인하세요.
6. 프로젝트를 수정하지 않는 읽기 전용 검증으로 연결 상태를 확인하세요.
# 완료 조건
다음 항목을 실제 결과와 함께 보고하세요.
- Codex CLI 설치 여부와 버전
- 인증 준비 상태
- Codex 플러그인 활성화 여부
- codex:codex-rescue 확인 여부
- 실행한 검증 명령과 결과
- 프로젝트 파일 변경 여부
자연어로 “설정됐다”고만 보고하지 말고,
명령 결과와 확인한 상태를 근거로 제시하세요.
# 중단 조건
설치, 인증 또는 권한 문제로 다음 단계에 진행할 수 없다면
임의의 대체 방법을 사용하지 말고 정확한 오류와 필요한 사용자 행동을 보고하세요.
이 프롬프트는 세부 명령을 모두 강제하기보다 목표, 성공 조건, 변경 금지 범위를 먼저 제시한다. GPT‑5.5 모델 가이드도 장기 실행 작업에서는 예상 결과, 성공 기준, 허용되는 부작용, 증거 규칙, 종료 조건을 명시하되 불필요한 단계별 지시는 줄이라고 권한다.
2 Codex 인증 확인
플러그인은 로컬에 설치된 Codex CLI의 인증 상태를 사용한다. 이미 이 머신의 Codex CLI에 로그인되어 있다면 별도의 계정 연결이 필요하지 않을 수 있다. 로그인이 필요하면 /codex:setup의 안내를 따르거나 다음 명령으로 인증한다.
!codex login
ChatGPT 계정 또는 API 키 중 어떤 인증 방식을 사용할지는 현재 Codex CLI 환경에 따라 결정한다. 인증 정보는 프로젝트 파일이나 프롬프트에 직접 기록하지 않는다.
3 Master와 Worker의 위임 규칙 설정
Claude Code를 좋은 Master로 쓰려면 어떤 작업을 위임하고, 어떤 증거를 받아야 하며, 누가 최종 수락하는지를 별도로 정해야 한다. 다음 프롬프트를 프로젝트의 운영 규칙에 맞게 사용하면 된다. 위임 규칙 프롬프트 예시
# 역할
당신은 이 작업의 Master Orchestrator입니다.
리포지토리 이해, 계획 수립, 작업 분해, 아키텍처 판단,
위임 범위 결정과 최종 수락을 담당하세요.
Codex는 범위가 제한된 Execution Worker로 사용하세요.
# Codex에 위임할 작업
다음과 같은 실행 비용이 큰 작업은 /codex:rescue로 위임할 수 있습니다.
- 다중 파일 구현
- 재현 범위가 명확한 버그 조사와 수정
- 테스트 실패 원인 분석과 수정
- 범위가 정해진 리팩터링
- 반복적인 코드 편집
- 별도의 관점이 필요한 코드 리뷰
작업의 목표나 책임 경계가 아직 불명확하다면 먼저 직접 조사하고 계획을 확정하세요.
# 위임 계약
Codex에 작업을 맡길 때 다음 내용을 빠뜨리지 마세요.
- Objective: 무엇을 달성해야 하는가
- Scope: 변경할 수 있는 파일과 레포
- Constraints: 금지된 변경과 유지해야 할 동작
- Canonical References: 먼저 읽어야 할 정본
- Verification: 실행해야 할 테스트와 프로브
- Deliverables: 제출해야 할 파일, diff, 로그
- Completion Condition: 어떤 증거가 있어야 완료인가
Codex가 작업 범위를 넓혀야 한다고 판단하면 직접 확대하지 말고
change proposal을 반환하게 하세요.
# 모델과 실행 설정
현재 환경에서 실제로 사용할 수 있는 Codex 모델과 reasoning effort를 사용하세요.
모델명을 추측하지 마세요.
긴 작업은 필요하면 background로 실행하고,
작업 식별자를 보존한 뒤 /codex:status와 /codex:result로 결과를 회수하세요.
# 수락 규칙
Codex의 “완료했다”는 응답만으로 작업을 수락하지 마세요.
결과를 받은 뒤 직접 다음 항목을 확인하세요.
1. 실제 변경 파일
2. base 대비 diff
3. 요청 범위 밖의 변경 여부
4. 실행한 테스트와 종료 결과
5. 실패하거나 실행하지 못한 검증
6. 알려진 한계와 남은 위험
증거가 부족하면 accepted로 처리하지 말고
changes_requested 또는 needs_human_verification으로 남기세요.
# 금지 사항
- Codex의 자기 보고를 최종 증거로 사용하지 마세요.
- 위임했다는 이유로 최종 검토 책임을 넘기지 마세요.
- 사용할 수 없는 모델이나 도구가 실행됐다고 가정하지 마세요.
- 권한 오류가 발생했을 때 Claude Code가 대신 수행한 결과를
Codex가 수행한 결과처럼 보고하지 마세요.
공식 플러그인은 /codex:review를 읽기 전용 검토에, /codex:rescue를 조사·수정·후속 작업 위임에 사용한다. 모델이나 추론 강도를 생략하면 Codex 설정과 기본값을 따른다. OpenAI codex-plugin-cc 사용법
4 위임 결과 확인
오래 걸리는 작업은 background로 실행할 수 있다.
/codex:rescue --background investigate why the integration test is flaky
진행 상태와 결과는 다음 명령으로 확인한다.
/codex:status
/codex:result
Master는 명령이 실행됐다는 메시지와 실제 Codex 작업이 완료됐다는 사실을 구분해야 한다. 최종적으로 다음 항목을 확인해야 한다.
- 실제 Codex 작업 ID 또는 세션 ID가 생성됐는가
- 예상한 파일에 diff가 존재하는가
- lease 범위 밖의 파일이 변경되지 않았는가
- 보고된 테스트 명령이 실제로 실행됐는가
- 실패하거나 실행하지 못한 검증이 숨겨져 있지 않은가
- 결과를 다시 열 수 있는 세션 포인터가 남아 있는가
이 프롬프트는 위임할 때 작업 범위와 검증 방법을 함께 전달하고 결과를 받은 Master가 다시 증거를 확인하게 만든다.
5 Orca와 함께 사용할 때
Orca를 사용한다면 Orca CLI로 터미널, worktree, 실행 세션을 확인하는 편이 좋다. UI에서 세션이 보인다는 사실과 실제 PTY·프로세스가 살아 있다는 사실을 분리해서 확인할 수 있기 때문이다. 운영 규칙은 이렇게 정리된다.
- 플러그인 설치는 한 번만 수행하고 반복해서 사용할 위임 규칙을 AGENTS.md나 스킬로 관리한다.
- 긴 작업은 세션 밖의 목표와 Work Ledger에 연결한다.
- 위임할 때마다 대상, 범위, 성공 조건, 금지 사항, 증거를 함께 전달한다.
- background 작업은 작업 ID와 실제 결과를 확인한다.
- Codex의 결과는 Claude Code가 다시 검사한 뒤에만 수락한다.
- Orca 세션이 보이지 않으면 새로 생성하기 전에 기존 PTY와 프로세스부터 확인한다.
'재밌는 개발글이지만 아직 미분류' 카테고리의 다른 글
| [Orca ADE 일지] 오늘 세 번 헤맸고, 방향을 튼 건 매번 내가 아니었다 (각주: orca cli 안쓰려고 하는 LLM 형성 기질) (0) | 2026.07.20 |
|---|---|
| SSOT를 향한 사고의 이동: 이번 세션에서 정리된 깨달음의 타임라인 (아무말) (0) | 2026.05.21 |
| ● AI 하네스 깎는 노인 (0) | 2026.04.16 |
| 이 정도만 셋업해도 웬만한 개발 업무는 충분히 커버 가능 — Claude Code 셋업 관련 핵심 레포 정리 (사내 공유 할 정도로 ㅊㅊ) (0) | 2026.04.16 |
| 맥북 셋업 가이드 (0) | 2026.01.20 |