Harness · 2026-08-06 · Downstream Propagation

ouroboros 배선은 리드에만 있고
하류 7지점은 비어 있었다

문제는 이것이었다. 하네스(harness, AI가 "다 했다"고 넘어가지 못하도록 증거를 강제하는 감시 장치 모음)에 새 요구사항 장치 두 개를 넣었는데, 그 지시가 일을 지휘하는 리드(총괄 AI)의 지시문에만 적혀 있고, 실제 일이 벌어지는 하류에는 전달되지 않았다. 배선(wiring, 규칙을 실제 실행 경로에 연결하는 일)이 리드에서 끊겨 있었던 셈이다. 그래서 하류 7지점의 빈 곳을 수리했다. 독립 검증이 잡아낸 실행 체인 끊김 2건도 닫았다. 하나는 심어 둔 시드(seed, 뒤 단계가 읽도록 미리 심어 두는 출발값)를 아무도 읽지 않는 허공 시드였다. 다른 하나는 새 규칙이 기존 검문과 부딪히는 게이트(gate, 코드를 서버에 올리기 전 자동으로 막아서는 검문소) 충돌이었다. 이 페이지는 그 수리 기록과 기대효과다.

배경 — 무엇을, 왜 전파했나

결론부터 말한다. 규칙을 문서에 적는 것과 실행 경로에 연결하는 것은 다른 일이다. 새로 채택한 장치가 리드의 지시문에만 있으면 어떻게 될까. 계획을 세우는 담당, QA(품질 검사)를 도는 담당, 코드를 막아서는 검문 장치는 그 장치를 모른 채 예전처럼 움직인다. 아래 세 장이 이번 작업의 전체 맥락이다.

The Wiring

ouroboros 배선이란

ouroboros(우로보로스, 자기 꼬리를 무는 뱀)는 오픈소스 AI 에이전트(스스로 도구를 쓰며 일하는 AI) 프레임워크다. 2026-08-06 검토 때 여기서 장치 두 개를 가져왔다. 하나는 요구사항을 목표·제약·용어 세 축으로 적어 두는 "spec 3축"이다(spec은 요구사항 명세). 다른 하나는 대화 도중 요구가 바뀌었는지 매번 확인하는 "의도 전환 체크"다.

2
채택 장치
3
spec 축
The Problem

리드의 지시문에만 있었다

두 장치가 /team 스킬(여러 AI 담당을 지휘해 프로젝트를 완성하는 작업 절차서)의 리드 문구에만 적혀 있었다. 계획을 세우는 담당, QA를 도는 담당, 코드를 올리기 전 막아서는 검문 장치처럼 실제 실행이 벌어지는 지점에는 아무것도 전달되지 않았다.

0
하류 배선
1
리드 문구뿐
This Work

하류 전수 검토와 수리

team(실행 단계 스킬) 쪽 5지점과 init-project(프로젝트 준비 단계 스킬) 쪽 2지점, 합쳐 갭(비어 있던 곳) 7건을 수리했다. 그리고 독립 검증자가 합의된 수용 기준 밖에서 찾아낸 실행 체인 끊김 2건(허공 시드와 게이트 충돌)까지 닫았다. 게이트가 오작동하지 않는다는 것은 grep(문서 전체에서 문구를 찾는 패턴 검색) 3건으로 실증했다.

7
갭 수리
2
체인 끊김
전파 체인 — 시드부터 push 게이트까지

읽는 법: 위에서 아래로 흐른다. init(프로젝트 준비 단계)이 심은 요구사항 시드가 team(실행 단계)으로 넘어가 계획 문서(plan)에 적혀 남고, QA를 거쳐, 마지막 push 게이트(코드를 서버에 올리기 전 자동 검문)까지 이어진다. 붉은 점선 두 곳이 문구만 보면 멀쩡한데 실행이 끊겨 있던 지점이다.

7전파 갭 수리 (team 4 + qa-gen 1 + init 2)
2실행 체인 끊김 발견·수리
7/7독립 검증 수용 기준
3grep 실증 (게이트 비계수)
INIT Goal-normalized intake + ontology 축 신설 (제약은 기존재) .requirements-lock.md + ## Spec 시드 섹션 (가드 무충돌 실측) team-handoff.json goal 객체로 /team에 상속 체인 끊김 #1 — 시드를 읽으라는 지시 0건 (허공 배선) → 수리: §4 시드 로드 지시 (없으면 자체 도출 = 기존 동작) TEAM Phase 0 §4 — spec 3축 목표·제약·용어 + 시드 로드(소비) planner 반환 계약 계획 + spec 3축 + AC-001..N 반환 plan ## Spec 섹션 영속 기준선 — compaction 생존 QA Step 1 §0 전환 체크 (주) fan-out 전 — Spec 부재 시 무음통과 금지 delta spawn 재도출 전환 예외 — 폐기 AC 제거·OBSOLETE 표기 Step 2 fan-out 처음부터 갱신된 TC로 실행 GATE Step 2.5 전단 — 백스톱 Step 1 이후 도착 메시지만 담당 push 게이트 — plan 분모 계수 (심각도·TC-E2E 패턴) OBSOLETE 변형 3종이 전 패턴에서 비계수임을 grep 실증 체인 끊김 #2 — obsolete가 분모에 계수 → 전환 후 push HARD 차단 → 수리: 비계수 표기 계약 (OBSOLETE- 접두 · 심각도 토큰 제거 · 부록 이동) 이번 전파로 추가/수리된 지점 전환 판정의 핵심 지점 (기준선·주지점·게이트) 검증자가 잡은 체인 끊김 (수리 완료) 파랑 = init-project 산출 · 중립 = 기존 장치 그대로
init이 심은 시드가 handoff(단계 사이에 넘겨주는 인계 문서)를 타고 team의 3축이 된다. plan에 적혀 남은 기준선은 전환 체크, 재도출, fan-out, 게이트까지 차례로 흐른다. 붉은 점선 2곳이 "문구는 7/7 통과였는데 실행 경로가 끊겨 있던" 지점이다. 둘 다 수리한 뒤 grep 실증까지 마쳤다.
전파 갭 7건 — 무엇이 없었고 무엇을 넣었나

표에 자주 나오는 용어 셋을 미리 풀어둔다. plan은 이번 작업의 계획을 적어 두는 문서다. compaction(컴팩션)은 AI의 긴 대화가 압축되면서 오래된 내용이 지워지는 일이다. fan-out(팬아웃)은 QA 검사를 여러 하위 AI에게 동시에 뿌려 돌리는 일이다. 일곱 지점 각각에서 무엇이 비어 있었는지는 실제 절차서를 검색해(실측) 확인했다.

지점 없었던 것 (실측) 수리
team 경로 A의 planner(계획 담당) AC(acceptance criteria, 완료로 인정할 수용 기준)와 계획만 돌려주는 반환 계약이었다. spec 3축이 반환 항목에 없어서, planner가 3축을 정리해도 넘어오는 길에 소실됐다 반환 계약에 "spec 3축(목표·제약·용어)"을 돌려주라고 명시했다
team Phase 1의 plan 정본(원본 문서) §4(절차서의 4번 항목) 산출물이 "메모리 컨텍스트(AI가 지금 기억하는 대화 내용)만"이었다. 그래서 기준선이 compaction에 소실되는 구조였다 plan에 ## Spec (목표/제약/용어) 섹션을 반드시 넣게 했다. 디스크에 남는 영속 기준선이다
team Step 1 전환 체크가 Step 2.5(fan-out 이후)에만 있었다. 그래서 전환을 감지했을 때는 이미 QA 한 라운드를 낭비한 뒤였다 fan-out 전에 §0 주 지점을 새로 만들었다. 기존 delta spawn(바뀐 부분만 다시 뽑으려고 띄우는 하위 AI)에 얹었으니 spawn(하위 AI를 새로 띄우는 일) 추가는 0이다
team Step 2.5 재도출(요구가 바뀐 뒤 수용 기준과 검사 항목을 다시 뽑는 일)의 실행 주체와 방법이 적혀 있지 않았다 TC(test case, 요구사항에서 뽑아낸 검사 항목 한 건)를 다시 돌리는 방법을 정했다. Step 2.5는 백스톱(앞 단계가 놓친 전환을 뒤에서 받아내는 안전망)으로 다시 정의했다. delta로 재스폰해 영향을 받는 검사 항목만 다시 실행하도록 구체화했다
qa-scenario-gen delta(바뀐 부분만 다시 뽑는) 모드 "요구가 안 바뀌면 수용 기준도 그대로"라는 규칙만 있었다. 전환 케이스는 지원하지 않았다(append-only, 덧붙이기만 하고 지우지는 못하는 방식뿐) 의도 전환 예외를 새로 만들었다. 폐기된 수용 기준의 매핑은 지우고, 딸린 검사 항목에는 폐기(obsolete) 표기를 하며, 전환 근거가 없으면 발동하지 않는다
init intake(요구 접수 단계)의 goal 스키마(목표 객체의 틀) execution_constraints(실행 제약을 적는 칸)은 이미 있었다. 용어(ontology) 축만 없었다 ontology(용어 정의) 선택 필드를 추가했다. handoff(단계 사이에 넘겨주는 인계 문서)를 통해 /team에 상속된다
init 요구사항 잠금 파일 .requirements-lock.md LOCK 행(기능 하나의 서명을 한 줄로 잠가 두는 행)만 있었다. 프로젝트 수준의 3축 시드는 없었다 ## Spec 헤더 섹션을 넣으라고 지시했다. 이 파일을 지키는 가드(검사기)가 ^LOCK|로 시작하는 행만 읽는다는 것을 실측한 뒤, 충돌 없이 배치했다
검증자가 잡은 체인 끊김 2건 — 문구는 7/7 통과였다

문서에 문구가 있는지 확인하는 검사(문구 검증)와, 그 문구대로 따라가면 실제로 일이 흘러가는지 확인하는 검사(실행 체인 검증)는 다른 검사다. 독립 검증자는 합의된 수용 기준 7개를 전부 통과시켰다. 그러고도 기준 밖에서 배선을 따라가 두 곳의 끊김을 찾았다.

#1 허공 시드 (만드는 쪽만 있고 읽는 쪽이 없었다)

init이 심은 시드를 아무도 안 읽었다

"상속되어 출발점으로 삼는다"는 주장만 있었다. 시드를 읽으라는 소비 지시는 0건이었다

  • init 쪽에는 ontology 필드와 ## Spec 시드 섹션을 만들라는 지시가 있었다 ✓
  • team 쪽은 handoff를 validator(검증 담당)가 확인하는 용도로만 언급했다
  • goal.ontology와 잠금 파일(lock)의 ## Spec 섹션을 읽으라는 지시는 grep으로 찾아도 0건이었다
  • 수리: §4에 시드를 읽어 오라는(소비) 지시를 넣었다. 시드가 없으면 예전처럼 스스로 도출하는 폴백(대체 경로)으로 간다
#2 게이트 충돌 (실제 피해가 날 참이었다)

obsolete(폐기) 표기가 push를 차단할 뻔했다

"폐기한 검사 항목을 plan에 남겨라"는 새 지시가, 게이트가 세는 분모(있어야 할 검사 항목 수)에 그대로 계수됐다

  • 게이트의 분모는 두 수의 합이다. 심각도 등급이 적힌 줄의 수, 그리고 엔드투엔드(처음부터 끝까지 한 흐름으로 돌리는 검사) 항목 헤딩의 수다. 그 헤딩은 다음 패턴으로 시작한다: ^#### TC-E2E-
  • 폐기 검사 항목이 남아 있으면 실제 실행 총계가 plan의 계수보다 작아진다. 그러면 게이트는 exit 2(차단 신호)를 낸다
  • PASS(검사 항목이 통과했다는 판정 표시)를 놓고 이지선다가 됐다. push를 차단하든지 or 실행하지도 않은 검사 항목에 통과 표시를 붙여 거짓 증거를 만들든지
  • 수리: 게이트가 세지 않는 표기 계약을 만들었다. 심각도 토큰을 지우고, 부록으로 옮기고, 이름 앞에 폐기 접두어를 붙인다. 세 변형 모두 세어지지 않음을 grep으로 실증했다. 접두어: OBSOLETE-
이번 라운드의 교훈

문구 검증과 실행 체인 검증은 다른 검사다. 독립 검증자는 수용 기준 7개를 전부 통과시켰다. 그러면서도 기준 밖에서 "이 배선을 따라가면 실제로 무슨 일이 일어나는가"를 추적해 끊김 2건을 찾았다. 하나는 만드는 쪽(생산자)만 있고 읽는 쪽(소비자)이 없는 허공 배선이었다. 다른 하나는 새 계약이 기존 HARD(사람 판단 없이 exit 2로 실제 차단하는 강제 등급) 게이트와 충돌해 push가 차단되는 미래였다. 배선을 더할 때는 항상 생산자와 소비자를 쌍으로 넣어야 한다. 그리고 그 산출물이 통과할 게이트의 파서(문서를 읽어 수를 세는 부분)까지 대조해야 끝난 것이다.

기대효과 — 전파 전후로 무엇이 달라지나
전파 전 실패모드 전파 후 근거
3축이 리드의 메모리에만 있었다. compaction 한 번이면 기준선이 사라지고 전환 판정은 감으로 돌아간다 plan의 ## Spec 섹션이 디스크에 남는 기준선이 된다. 세션이 끊겨도 대조할 수 있다 compaction-governance-decay 규칙(산문으로 적힌 제약은 대화 압축이 지운다는 규칙)이 근거다. 제약이 살아남으면 위반 0% vs 지워지면 38%였다
의도 전환 감지가 Step 2.5에만 있었다. 이미 낡은 검사 항목으로 QA 한 라운드를 다 쓴 뒤에야 다시 도출했다 Step 1의 §0에서 fan-out 전에 감지한다. 첫 실행부터 갱신된 검사 항목으로 돈다 QA fan-out 한 라운드는 하위 AI 3~5기를 돌리는 비용이다. 주 지점을 앞으로 옮기는 데 spawn 추가는 0이었다
의도 전환 뒤 폐기 검사 항목이 게이트 분모에 계수됐다. 결과는 push 차단 또는 거짓 통과 계수 강요, 둘 중 하나였다 세지 않는 표기 계약 덕에 전환이 있던 런(한 번의 실행)도 게이트를 정상 통과한다. 실행하지 않은 검사 항목을 통과로 꾸미는 거짓 증거 없이 그렇다 게이트가 세는 패턴 4개 전부에서 변형 표기가 세어지지 않음을 grep으로 실증했다. 심각도 세 등급(치명·높음·중간)의 토큰과 엔드투엔드 검사 헤딩이 그 패턴이다: CRITICAL/HIGH/MEDIUM TC-E2E
init이 시드를 심어도 team이 읽지 않았다. 프로젝트의 제약과 용어가 런마다 다시 만들어지고 서로 어긋날 위험이 있었다 handoff와 lock 파일의 시드가 team의 3축으로 상속되는 체인이 완성됐다. 프로젝트 수준의 일관성이 생긴다 team SKILL:60(team 스킬 절차서의 60번째 줄)이 이미 handoff를 실행 전제로 읽던 구조였다. 거기에 소비 지시 한 줄만 더했으니 비용은 0이다
정직한 한계

soft-to-hard(사람 판단에 맡기던 규칙을 사용 실적을 본 뒤 자동 검사로 올리는 승격 절차)로 올리기에는 아직 이르다. 여기까지는 문서 계약 + 게이트 grep 실증이다. 실제 /team 런에서 시드 로드, 전환 체크, 폐기 항목 비계수가 발동하는 행동 실증은 아직 없다. 다음 /team 런들이 그 관측 지점이다. plan에 ## Spec 섹션이 실제로 있는지를 자동 차단 게이트로 강제할지도 그 승격 절차로 판단한다. 효과가 없으면 archive(보관함으로 치워 두기)가 정답이라는 원칙은 이 배선에도 똑같이 적용된다.