유피테르
유피테르
🧙 AI 위자드
🏅 베스트오브베스트

옵션 한 줄을 넘기는 데 후보 네 번이 필요했습니다

한 줄 요약
Ouroboros 0.51.1의 Hermes backend를 바로 켜지 않고 격리된 후보에서 시험했다. 기술 검사를 통과한 후보도 parser 경계에서 세 번 거절했고, 네 번째 후보에서만 --query=<prompt> 단일 인자 결박, 실제 파일럿, 독립 코드·증거 심사를 모두 통과시켜 experimental integration baseline으로 제한 승격했다.

먼저 보는 결과

  • 사용한 runtime은 ouroboros-ai[mcp] 0.51.1이고 backend는 Hermes였다.

  • Attempt 4는 기술 gate가 PASS였지만 code review HIGH 2건으로 거절됐다.

  • Attempt 5는 0/1, exit 1로 종료됐고 repository changed path는 0개였다.

  • Attempt 6은 40/40 기술 gate 뒤에도 split query가 설치 Hermes parser에서 exit 2를 재현해 거절됐다.

  • Attempt 7은 --query=<prompt> 단일 argv와 옵션형 prompt 7/7 parser-aware PASS로 교정됐다.

  • 최종 Attempt 7 technical gate는 43/43 PASS였다.

  • 회귀 테스트 그룹은 17+6+4, 합계 27/27 PASS였다.

  • MechanicalVerifier v2의 lint/build/test/static 4/4 PASS를 확인했다.

  • bounded pilot은 1/1, exit 0이고 Hermes QA는 0.98로 0.80 기준을 넘었다.

  • candidate 11/11과 pinned source 2/2의 hash read-back이 PASS였다.

  • 독립 code review와 evidence review 2/2가 PASS_EXPERIMENTAL_INTEGRATION이었다.

  • 승격 범위는 experimental integration뿐이다. Production·canonical·default runtime·원 통합물 publication은 수행하지 않았다.

이 글에서 “통합”은 넓은 자동화 활성화를 뜻하지 않는다. 동결된 Attempt 7 hash set을 실험 통합 기준선으로 인정했다는 뜻이다. 사례게시글 자체의 승인 범위도 local Library로 한정하며, 외부 웹·커뮤니티 발행은 별도다.


이 사례가 필요한 사람

다음과 같은 연결 작업을 하는 경우에 유용하다.

  1. 한 CLI가 다른 CLI를 호출하거나, wrapper가 downstream argv를 다시 만드는 경우

  2. argparse처럼 약어·옵션 우선 해석이 있는 parser를 경계로 두는 경우

  3. MCP server를 Hermes에 연결하되 production 등록 전에 canary를 만들고 싶은 경우

  4. “테스트는 통과했다”와 “실제 호출 경로도 안전하다”를 분리하고 싶은 경우

  5. 실패한 후보를 덮어쓰지 않고 rejection lineage와 immutable successor를 유지하려는 경우

이 사례의 핵심은 복잡한 기능 구현이 아니다. 옵션과 데이터가 같은 문자열 공간을 공유할 때, 어느 parser가 언제 무엇으로 해석하는지 끝까지 증명하는 방법이다.


무엇을 연결하려 했나

Ouroboros는 specification-first 방식으로 AI coding workflow를 실행하는 runtime이다. 이번 작업에서는 설치 버전을 ouroboros-ai[mcp]==0.51.1로 고정하고 Hermes backend를 대상으로 bounded pilot을 설계했다.

원래 의도는 단순했다.

Ouroboros Seed
  → Hermes backend 호출
  → 고정된 safe-mode와 file,terminal toolset
  → 작은 readiness receipt 하나 생성
  → 테스트·감사·독립심사

하지만 실제 경로에는 세 개의 문법이 겹쳤다.

Ouroboros runtime grammar
        ↓
custom wrapper grammar
        ↓
Hermes argparse grammar

위쪽 parser가 문자열을 “질의 데이터”라고 받아들였더라도, 아래쪽 parser가 다시 “옵션”으로 해석하면 안전 경계는 무너진다. 그래서 wrapper가 입력을 검사했다는 사실만으로는 충분하지 않았다. 최종 downstream argv를 설치된 Hermes parser에 실제로 넣어 보아야 했다.


왜 옵션 한 줄이 보안 경계가 되었나

문제의 중심에는 다음 두 형태가 있었다.

-q <prompt>
--query=<prompt>

평범한 prompt라면 두 형태가 모두 비슷해 보인다. 그러나 prompt 자체가 아래처럼 옵션 모양이면 상황이 달라진다.

--to=web
--toolsets=web
--yolo

split form은 downstream parser가 -q의 값을 찾는 과정에서 다음 토큰을 새 옵션으로 재해석할 수 있다.

-q --toolsets=web

반면 value를 같은 argv에 결박하면 parser가 한 토큰 전체를 query option의 값으로 다룰 수 있다.

--query=--toolsets=web

이번 교정은 이 차이를 추측으로 설명하는 데서 끝나지 않았다. 설치된 Hermes parser를 대상으로 option-looking prompt 일곱 개를 mutation set으로 만들고, 실패 재현과 수정 후 PASS를 모두 보존했다.


실패를 지우지 않은 네 후보의 계보

그림 1. 실제 verdict·reproduction JSON에서 생성한 데이터 파생 실행 증거 카드. terminal 화면을 재현한 mockup이 아니다.

Attempt 4 — 기술 PASS가 전체 PASS는 아니었다

Attempt 4의 technical gate는 PASS였다. Evidence review도 experimental integration을 허용할 수 있다는 결론이었다. 하지만 independent code review에서 HIGH finding 두 건이 나왔다.

  1. --to=web, --too=web 같은 문자열이 Hermes의 옵션 약어 해석을 거쳐 고정 toolset을 다시 덮을 수 있었다.

  2. pilot boundary가 필요로 하는 pre-manifest 환경값 두 개가 모두 없을 때 감사기가 실패하지 않고 not_requested로 빠지는 fail-open 경로가 있었다.

따라서 Attempt 4는 reject_successor_required로 동결했다. 기술 PASS와 evidence PASS를 버리지는 않았지만, code FAIL을 상쇄하는 표로 사용하지도 않았다.

Attempt 5 — 너무 엄격한 wrapper도 호환성을 깨뜨린다

Attempt 4의 약어 우회를 막기 위해 grammar를 엄격하게 만들었더니, 이번에는 pinned Ouroboros implementation이 정식으로 내보내는 --yolo --accept-hooks 호환 입력까지 차단했다.

결과는 명확했다.

success 0/1
exit 1
qa_run false
repository changed paths 0

실패는 downstream Hermes 실행 전에 발생했다. 그래서 readiness receipt도, context pack도 생성되지 않았다. Attempt 5는 “보안을 강화했다”는 이유로 살리지 않고 failed_execution_successor_required로 보존했다.

Attempt 6 — wrapper에서는 데이터였지만 Hermes에서는 다시 옵션이었다

Attempt 6은 canonical --yolo --accept-hooks pair를 정확히 소비하고 버린 뒤, downstream에는 safe-mode와 고정 toolset만 전달하도록 고쳤다. Technical gate도 40/40을 통과했다.

그러나 독립 코드심사가 split query를 문제 삼았다.

wrapper output: -q, --to=web
Hermes parser: exit 2
result: query data not preserved

부모 프로세스에서 설치된 Hermes parser로 직접 재현했을 때 split form은 exit 2가 났고, bound form은 query data로 정상 파싱됐다. 첫 code reviewer는 timeout으로 verdict를 남기지 못했으므로 PASS나 FAIL로 계산하지 않았다. replacement review의 FAIL만 conjunctive gate에 반영했다.

Attempt 7 — 단일 argv 결박과 parser-aware mutation

Attempt 7은 downstream query를 다음처럼 한 argv로 만들었다.

--query=<prompt>

그리고 option-looking prompt 일곱 개를 설치된 Hermes parser에 넣었다. 이전 split form의 실패 일곱 건은 red reproduction으로 보존하고, bound form의 7/7 PASS를 green evidence로 추가했다.

핵심은 “문자열 필터를 하나 더 넣었다”가 아니다. 최종 소비자 parser의 실제 해석 결과를 gate에 포함했다는 점이다.


Attempt 7에서 실제로 무엇이 통과했나

그림 2. bounded pilot과 QA receipt에서 생성한 실행 결과 카드.

1. 원본과 버전을 먼저 고정했다

  • candidate files: 11/11

  • pinned adapter sources: 2/2

  • runtime package: ouroboros-ai[mcp]==0.51.1

  • backend: hermes

  • final accepted attempt: 7

검사는 “현재 비슷해 보이는 파일”이 아니라 contract에 기록된 바이트와 SHA-256을 다시 읽는 방식이었다. predecessor verdict도 Attempt 4·5·6의 해시를 다시 확인했다.

2. 회귀 검사를 세 그룹으로 분리했다

회귀 테스트는 17+6+4, 합계 27/27 PASS였다.

  • Ouroboros adapter 전용 테스트: 17

  • cross-runtime drift 테스트: 6

  • hard-eval wrapper 테스트: 4

기존 wrapper 다섯 개는 변경되지 않았음을 별도 check로 확인했다. 즉, 새로운 adapter를 통과시키기 위해 기존 평가 wrapper를 느슨하게 만들지 않았다.

3. MechanicalVerifier를 실제 target과 연결했다

첫 mechanical probe는 contract schema를 잘못 가정해 결과를 얻지 못했다. 그 실패를 지우거나 PASS로 세지 않았다. v2가 실제 mechanical contract를 읽도록 고친 뒤 다음 네 target을 모두 실행했다.

lint   PASS
build  PASS
test   PASS
static PASS

MechanicalVerifier v2의 lint/build/test/static 4/4 PASS는 위 target 실행의 compact receipt다.

4. bounded pilot을 한 번 실제 실행했다

파일럿은 문서상의 command plan이 아니라 실제 실행이었다.

pilot: 1/1 success
exit: 0
Hermes QA: 0.98
minimum threshold: 0.80

Hermes QA 0.98 ≥ 0.80을 통과했고, readiness receipt 하나만 생성됐다. 그 receipt는 677 bytes이며 SHA-256은 다음과 같다.

5a39b976ad0e5b2cc87ef35607da6497dd88000a611b1e0c6b26c22b7dc0c70c

repository 변화는 readiness receipt 1개 추가로 한정됐다. Source mutation, wiki mutation, quality-threshold mutation, network used는 모두 false였다.

5. 독립심사는 AND gate로 계산했다

최종 승격에는 다음 세 축이 모두 필요했다.

technical gate PASS
AND independent code review PASS
AND independent evidence review PASS

Code review와 evidence review 2/2가 모두 PASS_EXPERIMENTAL_INTEGRATION이었다. 어느 한 축의 PASS가 다른 축의 FAIL을 덮지 못하도록 했다.


MCP 연결과 rollback도 따로 확인했다

그림 3. MCP test·rollback·process audit·최종 verdict에서 생성한 범위 카드.

MCP test는 exit 0으로 server tools 36개를 발견했다. 한편 config read-back은 package pin ouroboros-ai[mcp]==0.51.1과 selected tools 8개를 확인했다. 두 수는 서로 다른 의미다.

  • 36: server가 discovery 단계에서 보고한 전체 tool 수

  • 8: 해당 config가 선택한 tool 수

연결이 된다는 사실과 필요한 도구만 선택했다는 사실을 분리해 기록했다.

철회 경로도 실행 전에 확인했다.

rollback dry-run exit 0
new residue 0
listener 0

Dry-run은 실제 파일을 삭제하지 않았다. 새로 남은 Ouroboros 관련 프로세스와 지정 listener도 0이었다.


승격된 것과 승격되지 않은 것

최종 status-layer promotion은 candidate source bytes를 변경하지 않았다. 동결된 hash set의 상태만 experimental integration baseline으로 인정했다.

구분

최종 상태

experimental integration

true

production activation

false

canonical activation

false

default runtime activation

false

원 통합물 publication

false

network operation

false

이 사례게시글의 범위

local Library only

외부 웹·커뮤니티 발행

NOT_RUN

따라서 “Ouroboros를 production에 켰다”, “canonical repository에 병합했다”, “default runtime으로 지정했다”는 해석은 맞지 않는다. 새 단계로 가려면 새로운 immutable candidate와 별도 canary·승인이 필요하다.


데이터 파생 실행 증거 카드를 쓴 이유

이 작업에는 웹 대시보드나 클릭 중심 UI가 없었다. 핵심 증거는 JSON receipt, CLI return code, parser reproduction, manifest와 해시였다. 그래서 terminal처럼 보이는 가짜 화면을 만들지 않았다.

대신 다음 원칙으로 데이터 파생 실행 증거 카드를 만들었다.

  1. 실제 JSON/CLI receipt를 generator가 다시 읽는다.

  2. 알려진 SHA-256과 현재 바이트가 다르면 생성 자체를 중단한다.

  3. 숫자와 verdict를 손으로 카드에 다시 입력하지 않고 receipt 객체에서 끌어온다.

  4. 각 카드 footer에 DATA-DERIVED와 point-in-time을 명시한다.

  5. 카드에 표시된 material token이 최소 font contract를 만족하는지 SVG source에서 검사한다.

  6. 카드와 기사 본문이 같은 public execution evidence receipt를 참조한다.

즉, 이 카드들은 live UI screenshot은 아니지만, 실제 실행 영수증에서 파생된 시각 증거다. CLI/MCP 사례에서 “예쁜 terminal mockup”보다 재현성과 출처 추적을 우선한 선택이다.


Before / After

Before — wrapper 자체만 믿는 경로

caller argv
  → wrapper가 금지 옵션 검사
  → -q <prompt>로 재조립
  → Hermes가 prompt를 새 옵션으로 재해석할 가능성
  → wrapper PASS와 downstream 의미가 불일치

위 구조에서는 wrapper의 unit test가 통과해도 최종 parser에서 의미가 달라질 수 있었다. Attempt 6의 40/40 PASS 뒤에 실제 blocker가 발견된 이유다.

After — 최종 parser까지 포함한 경로

caller argv
  → canonical grammar만 소비
  → caller의 권한 확대 옵션은 폐기
  → fixed --safe-mode
  → fixed --toolsets=file,terminal
  → --query=<prompt> 한 argv로 결박
  → installed Hermes parser mutation 7/7
  → bounded pilot
  → technical + code + evidence AND gate

변화의 핵심은 parser 하나를 더 테스트한 것이 아니다. 구현이 만든 downstream argv를 바로 그 downstream parser로 검증하는 계약을 만든 것이다.


실패에서 수정으로 이어지는 trace

후보

관찰된 결함

다음 후보의 수정

보존 원칙

Attempt 4

옵션 약어 우회, manifest 누락 fail-open

strict caller grammar, missing evidence fail-closed

Attempt 4 verdict·HIGH finding 보존

Attempt 5

정식 --yolo --accept-hooks pair까지 차단

canonical pair만 정확히 소비 후 폐기

0/1, exit 1, 무변경 경계 보존

Attempt 6

split -q 뒤 옵션형 prompt가 재해석

--query=<prompt> 단일 argv

parser exit 2 reproduction과 timeout 기록 보존

Attempt 7

이전 세 blocker의 successor repair

parser-aware 7/7, pilot, 43/43, 독립 2/2

hash set을 experimental baseline으로 동결

이 표에서 중요한 것은 “실패가 수정되었다”가 아니라 어느 실패가 어느 repair와 어느 test로 닫혔는지다. 실패한 후보의 바이트를 덮어쓰면 이 연결을 나중에 증명하기 어렵다.


실제로 재사용할 수 있는 설계 규칙

규칙 1 — parser chain을 그린다

wrapper가 둘 이상이면 각 단계가 어느 문자열을 옵션으로 보고 어느 문자열을 데이터로 보는지 먼저 그린다.

producer grammar → wrapper grammar → consumer grammar

규칙 2 — 소비자 parser를 test oracle로 쓴다

“이 문자열은 데이터일 것이다”라고 추측하지 않는다. 설치된 consumer parser의 parse 결과나 exit code를 test oracle로 사용한다.

규칙 3 — 옵션형 데이터 mutation set을 만든다

최소한 다음 부류를 넣는다.

  • 허용 옵션과 이름이 비슷한 축약형

  • toolset·provider·model처럼 권한을 바꿀 수 있는 옵션

  • safe-mode를 무력화할 수 있는 옵션

  • --name=value 형태

  • 단일 dash와 이중 dash 변형

  • 정상 prompt control sample

규칙 4 — 호환 입력과 권한 전달을 분리한다

상위 runtime이 정식으로 내보내는 옵션은 wrapper가 호환 목적으로 소비할 수 있다. 그러나 그 옵션을 downstream에 그대로 전달할 필요는 없다. 이번 사례에서는 canonical pair를 정확히 소비하되 downstream은 safe-mode로 다시 만들었다.

규칙 5 — 빠진 증거는 not requested가 아니라 FAIL로 본다

감사에 필요한 manifest가 contract상 필수라면 환경값이 없다는 이유로 검사를 건너뛰지 않는다. 필수 evidence가 없으면 fail-closed가 되어야 한다.

규칙 6 — 기술 PASS와 독립심사 PASS를 합산하지 않는다

PASS = technical ∧ code ∧ evidence

평균 점수나 다수결로 계산하지 않는다. 하나라도 FAIL이거나 verdict가 없으면 승격하지 않는다.

규칙 7 — 실패한 후보를 immutable predecessor로 남긴다

후속 후보는 새 디렉터리·새 contract·새 hash set으로 만든다. 기존 PASS evidence도 후속 blocker를 자동으로 상쇄하지 못한다.

규칙 8 — 실제 파일럿의 쓰기 집합을 먼저 정한다

이번 pilot은 readiness receipt 하나만 쓰도록 허용했다. Pre/post manifest를 비교해 그 한 파일 외의 변경이 없음을 확인했다.

규칙 9 — 연결, 선택, 활성화를 서로 다른 주장으로 쓴다

  • MCP connection이 성공했다.

  • Server tool discovery가 성공했다.

  • Config가 일부 tool을 selected로 기록했다.

  • Production에서 자동 활성화했다.

이 네 문장은 서로 같은 뜻이 아니다. Receipt와 게시글에서도 각각 분리해야 한다.


최소 재현 체크리스트

아래 체크리스트는 다른 CLI-to-CLI 연결에도 적용할 수 있다.

[ ] upstream package/version/commit을 pin했다
[ ] producer가 실제로 내보내는 argv를 캡처했다
[ ] wrapper가 소비할 canonical grammar를 문서화했다
[ ] downstream에 전달하지 않을 권한 옵션을 정했다
[ ] query/prompt를 한 argv에 결박했다
[ ] installed consumer parser로 option-looking mutation을 돌렸다
[ ] red reproduction을 보존했다
[ ] regression, mechanical, static gate를 분리했다
[ ] bounded pilot의 허용 write set을 정했다
[ ] pre/post manifest를 비교했다
[ ] rollback dry-run과 residue를 검사했다
[ ] independent code/evidence review를 AND gate로 계산했다
[ ] production/canonical/default/publication 범위를 별도 필드로 기록했다

이 사례에서 확인된 수치

항목

확인값

근거 성격

predecessor 후보

3개

immutable rejection lineage

option-looking parser prompts

7/7 PASS

installed Hermes parser-aware test

regression tests

27/27 PASS

17+6+4 groups

mechanical targets

4/4 PASS

lint/build/test/static

technical gate

43/43 PASS

final technical receipt

pilot

1/1 PASS

actual execution

pilot exit

0

execution receipt

Hermes QA

0.98 / 0.80

actual score / minimum threshold

candidate hashes

11/11

current read-back

pinned sources

2/2

current read-back

readiness receipt

677 bytes

file read-back

MCP server tools discovered

36

hermes mcp test stdout

config selected tools

8

config read-back

independent reviews

2/2 PASS

code + evidence

rollback dry-run

exit 0

CLI receipt

new process residue

0

process audit

listener

0

process audit

숫자는 서로 다른 gate의 결과이므로 한 점수로 합치지 않았다. 예를 들어 server tools 36과 selected tools 8은 모순이 아니라 서로 다른 관찰값이다.


한계와 다음 단계

이번 사례가 증명한 것은 다음뿐이다.

  1. 고정된 Ouroboros 0.51.1과 Hermes backend 조합에서 bounded adapter path가 실험 통합 기준을 통과했다.

  2. 알려진 option-looking prompt 일곱 개에 대해 단일 argv 결박이 설치 parser에서 query data를 보존했다.

  3. 동결된 candidate·source hash와 실행 evidence가 최종 심사 시점에 일치했다.

  4. 한 번의 bounded pilot이 허용된 receipt-only write boundary 안에서 성공했다.

다음은 증명하지 않았다.

  • 모든 미래 Hermes parser 버전과의 호환성

  • 임의의 모든 prompt 문자열에 대한 완전성

  • production load나 장시간 안정성

  • canonical repository 승격

  • default runtime 지정

  • 자동 외부 네트워크 작업

  • 외부 웹·커뮤니티 사례게시글 발행

Production으로 나아가려면 새 immutable candidate를 만들고, 현재 parser·package·config를 다시 pin한 뒤 별도의 canary와 독립심사를 반복해야 한다.


참고자료

공개 URL과 설치 package metadata는 글 작성 시점에 직접 확인했다. 내부 실행 artifact의 사설 경로·세션 ID·프로세스 ID는 게시글에서 제외하고, 공개 가능한 point-in-time 수치와 해시만 옮겼다.


결론

이 작업에서 가장 위험했던 순간은 실행이 실패했을 때가 아니었다. 기술 검사가 통과했는데도 downstream parser가 다른 의미를 만들 수 있었던 순간이었다.

Attempt 4의 기술 PASS, Attempt 6의 40/40 PASS는 유용한 증거였지만 최종 승격권은 아니었다. 독립 코드심사가 새로운 blocker를 발견하면 이전 PASS를 보존한 채 새 successor를 만들었다. 그 결과 네 번째 후보에서야 다음 문장을 근거와 함께 말할 수 있었다.

--query=<prompt>로 한 argv에 결박하고, 설치 Hermes parser에서 option-looking prompt 7/7, 회귀 27/27, mechanical 4/4, technical 43/43, pilot 1/1, 독립심사 2/2를 통과했다.

그리고 바로 다음 문장도 함께 남겼다.

이 PASS는 experimental integration baseline에만 적용되며 production·canonical·default runtime·원 통합물 publication을 뜻하지 않는다.

옵션 한 줄을 넘기는 데 후보 네 번이 필요했던 이유는 신중함 자체가 목적이어서가 아니다. 같은 문자열이 서로 다른 parser에서 서로 다른 권한으로 바뀌지 않았음을 실제 소비자까지 내려가 증명해야 했기 때문이다.

지피터스 뉴스레터

이번 주 AI, 딱 쓸 것만

매주 월요일 오후,
읽고 바로 써먹을 AI 소식만