한 줄 요약

FableLayer의 Fail-closed Gates는 “증거 없으면 무조건 차단”을 기본값으로 삼는 셸 스크립트 검문소 묶음으로, 마크다운 명세만으로는 절대 통과할 수 없도록 라이선스·성능주장·런타임·렌더·퍼블리시·완전성을 각각 별도 exit 코드로 막는다. 왜 배우나: 하네스에서 “통과는 어렵게, 실패는 안전하게”라는 게이트 설계 원칙을 가장 작고 읽을 수 있는 형태로 보여주기 때문이다.

그림

flowchart TD
  V["verify_fablelayer.sh<br/>마스터 게이트 (OR 집계)"] --> S{"필수 문서 존재?<br/>REQUIREMENTS/README/LICENSE 등"}
  S -->|없음| F1["fail structure (RC=1)"]
  S -->|있음| G

  subgraph G["서브게이트 (각각 HARD)"]
    L["license_gate.sh<br/>FL7 / exit 2"]
    P["perf_claim_gate.sh<br/>FL9 / exit 2"]
    B["bench_integrity_gate.sh<br/>FL6 / exit 2"]
    C["completeness_gate.sh<br/>FL13 / exit 3"]
    R["render_gate.sh<br/>FL18 / exit 2"]
    RT["runtime_gate.sh<br/>FL20 / exit 2"]
  end

  G --> PUB{"mode = publish?"}
  PUB -->|예| PG["publish_gate.sh<br/>FL15 / exit 2<br/>승인토큰 AND 전체green"]
  PUB -->|아니오| AGG
  PG --> AGG["RC 집계 (하나라도 비0 = FAIL)"]
  G --> AGG
  AGG -->|"RC=0"| OK["VERIFY PASS"]
  AGG -->|"RC!=0"| FAIL["VERIFY FAIL:실패목록"]

  PRE["preflight_gate.sh<br/>FL17 / exit 4<br/>(루트 단독점유 확인)"] -.선행.-> V

쉽게 풀기

공항 보안 검색대를 떠올리면 된다. FableLayer는 결과물(프롬프트 제품)을 세상에 내보내기 전에 여러 검문대를 통과시킨다.

  • “Fail-closed(실패 시 닫힘)“는 검문대 직원이 애매하면 무조건 막는다는 뜻이다. 증거가 없으면 “아마 괜찮겠지”가 아니라 “통과 불가”가 기본값이다. 평소 소프트웨어는 에러 나면 그냥 넘어가는 경우가 많은데, 여기서는 반대다.
  • 검문대는 7개 정도 있고 각각 다른 것을 검사한다. 짐 안에 베낀 남의 프롬프트가 있는지(license), “Opus랑 동급 95%“같은 근거 없는 자랑이 있는지(perf), 벤치 결과에 원자료와 한계 고백이 붙어 있는지(bench), 필요한 부품이 다 들어있는지(completeness), 설정 파일이 진짜 열리는지(render), 코드가 실제로 돌아가는지(runtime)를 본다.
  • 가장 엄격한 검문대는 출국심사(publish)다. 여기는 “다른 모든 검문대가 초록불”이고 “사람이 직접 승인 도장(APPROVED)을 찍은” 두 조건을 동시에 만족해야만 외부 배포를 허용한다.
  • 핵심 트릭 하나: runtime/completeness 게이트는 “마크다운 설명서만 써놓고 다 했다”고 우기는 걸 막는다. 실제 파이썬 파일이 컴파일되고 import되고 CLI가 실행돼야 통과한다. 설명서는 짐이 아니라 진짜 작동하는 물건만 통과시키는 셈이다.

단계로 보면: (1) preflight로 작업 폴더가 내 것인지 먼저 확인 → (2) verify가 필수 문서를 점검 → (3) 6개 서브게이트를 차례로 실행 → (4) publish 모드면 승인+전체초록 추가 확인 → (5) 하나라도 비0이면 전체 실패.

핵심 정리

각 게이트의 책임과 실패 코드를 한눈에 본다. exit 코드가 게이트마다 다른 이유는 마스터가 어떤 게이트가 막았는지 구분하기 위해서다.

게이트막는 것(요지)exit 코드
license_gate (FL7)유출 프롬프트 복사 지시문·전문, LICENSE/NOTICE/ATTRIBUTION 누락, 비AGPL2
perf_claim_gate (FL9)bench 근거 없는 수치 성능주장, capability/procedure 구분 누락2
bench_integrity_gate (FL6)RESULTS.md·원자료(json)·재현스크립트·한계 섹션 누락2
completeness_gate (FL13)모드별 필수 디렉터리/파일 누락, 알 수 없는 mode3
render_gate (FL18)깨진 JSON 매니페스트, 실행 불가 CLI, README의 죽은 bench 링크2
runtime_gate (FL20)syntax/import 오류, CLI 서브커맨드 실패, 단위테스트 실패2
publish_gate (FL15)승인토큰 부재 또는 전체 게이트 비초록 상태에서의 외부 배포2
preflight_gate (FL17)루트가 타 프로젝트/에이전트 점유 상태4

실제 예시

성능주장 게이트의 핵심 로직. “수치 + 성능 키워드”가 동시에 있으면서 근거/정직성 마커가 없으면 차단한다.

# /home/seunghyeong/harness-fablelayer/gates/perf_claim_gate.sh
# unbacked perf claim lines: number (NN% or N점) + perf keyword,
# lacking bench ref / honesty marker / price-table context
bad=$(grep -nIE '([0-9]{2}%|[0-9]+ *점)' $FILES 2>/dev/null \
      | grep -iE 'similar|동률|동등|능가|opus|fable|품질|quality|절감|saving|cheaper|score|점수|상회|tie' \
      | grep -ivE 'bench/|\[bench|target|목표|미검증|추정|aspirational|claim-only|한계|limitation|noise|노이즈|예시|example|\$[0-9]|/1M|입력|출력|input \$|output \$|price|단가' )
if [ -n "$bad" ]; then
  echo "PERF FAIL(2): unbacked performance claim(s):"
  printf '%s\n' "$bad"
  RC=2
fi
# capability vs procedure distinction must be present
if ! grep -liE 'capability' $FILES >/dev/null 2>&1; then
  echo "PERF FAIL(2): README missing 'capability' (non-transfer) framing"; RC=2
fi

마크다운만으로는 통과 못 하게 만드는 런타임 게이트(GATE-04/05 해소). 실제 파이썬이 돌아야 한다.

# /home/seunghyeong/harness-fablelayer/gates/runtime_gate.sh
if [ -d fablelayer ]; then
  if ! python3 -m compileall -q fablelayer >/dev/null 2>&1; then
    echo "RUNTIME FAIL(2): syntax error in fablelayer/"; RC=2
  fi
  for f in fablelayer/*.py; do
    base="$(basename "$f" .py)"; [ "$base" = "__init__" ] && continue
    if ! python3 -c "import fablelayer.$base" >/dev/null 2>&1; then
      echo "RUNTIME FAIL(2): import fablelayer.$base"; RC=2
    fi
  done
  if [ -f fablelayer/cli.py ]; then
    for sub in "--help" "status"; do
      if ! python3 -m fablelayer.cli $sub >/dev/null 2>&1; then
        echo "RUNTIME FAIL(2): cli $sub non-zero"; RC=2
      fi
    done
  fi
fi

이중 조건 출국심사(publish). 승인토큰 AND 전체 게이트 초록을 모두 만족해야 한다.

# /home/seunghyeong/harness-fablelayer/gates/publish_gate.sh
approved=0
[ "$APPROVAL" = "--approved" ] && approved=1
if ls "$ROOT"/runs/*/APPROVED >/dev/null 2>&1; then approved=1; fi
if [ "$approved" -ne 1 ]; then
  echo "PUBLISH FAIL(2): no approval token (FL15) — external publish/push/marketplace blocked"; RC=2
fi
# all gates must be green
if ! bash "$GATES_DIR/verify_fablelayer.sh" "$ROOT" --mode all >/dev/null 2>&1; then
  echo "PUBLISH FAIL(2): verify_fablelayer not green — cannot publish"; RC=2
fi

요약 & 셀프체크

  • 7개+1개 게이트는 모두 set -u로 시작하는 fail-closed 셸 스크립트이며, 게이트별로 exit 2/3/4를 달리 써서 마스터가 어떤 검문이 막았는지 구분한다.
  • runtime/completeness 게이트가 실제 파이썬 컴파일·import·CLI·테스트를 요구하므로 마크다운 명세만으로는 절대 통과할 수 없다.
  • publish_gate만 유일하게 “사람 승인(APPROVED) + 전체 게이트 초록”이라는 이중 AND 조건을 걸어 외부 배포를 봉인한다.

셀프체크:

  1. license_gate, completeness_gate, preflight_gate의 실패 exit 코드는 각각 무엇이며 왜 서로 다르게 두었는가?
  2. perf_claim_gate가 “절감 30%“라는 문장을 통과시키려면 같은 줄에 어떤 종류의 단서가 있어야 하는가?
  3. publish_gate가 verify를 --mode all로 다시 부르는데도 무한루프가 생기지 않는 이유는?

연결

FL_개요 · _분석축_루브릭