najamjad-cop
Pursuit League - 경찰 에이전트 👮
두 명이 진행하는 AI 에이전트 오케스트레이션 기말 프로젝트의 경찰/캅 측입니다: MCP(FastMCP/HTTP)를 통해 다른 팀의 에이전트와 P2P로 진행되는 분산형 경찰과 도둑 게임으로, SHA-256 커밋-리빌 무결성과 Gmail API 결과 보고를 사용합니다.
동반 저장소(도둑 에이전트): https://github.com/najikay/pursuit-thief-agent 공유 코어 패키지는 두 저장소에서 바이트 단위로 동일하며, CI의
scripts/sync_core.py로 강제됩니다(docs/PLAN.md, ADR-002 참조).
팀: Naji Kayal · Amjad Abed
상태: M6 - 6개의 서로 다른 상대와 6번의 카운트 시리즈를 플레이하고 제출했습니다. 규칙 31의 통과 기준을 세 번 이상 충족했습니다. 전체 감사 시리즈를 플레이하고, 강의 참조 시뮬레이터 및 6개의 독립적인 팀 구현과 상호 운용하며, 경기 후 상대의 플레이를 감사합니다. 남은 작업은 docs/TODO.md에 추적됩니다.
리그 기록
# | 날짜 | 상대 | 결과 | 우리 | 상대 |
1 | 2026-08-08 |
| 승리 6–0 | 90 | 30 |
2 | 2026-08-13 |
| 승리 6–0 | 90 | 30 |
3 | 2026-08-14 |
| 패배 0–6 | 30 | 90 |
4 | 2026-08-17 |
| 승리 4–2 | 60 | 40 |
5 | 2026-08-18 |
| 패배 0–6 | 30 | 90 |
6 | 2026-08-21 |
| 무승부 3–3 | 75 | 75 |
6번의 카운트 시리즈에 걸쳐 36개 미니게임 전부가 감사에서 Verified OK로 확인되었고, 우리에게 귀속되는 기술적 패배는 0입니다. 우리가 가장 먼저 강조할 숫자는 바로 이것입니다: 우리가 플레이한 모든 게임은 양측이 다시 해시하고 동의할 수 있는 게임이었으며, 크게 진 두 게임도 포함됩니다.
두 시리즈는 상대가 제출한 보고서와 필드 대 필드로 일치했습니다 - vibecode의 경우 66개 필드에서 차이 0, 이후 anrbj666과의 친선 경기에서는 6개 하위 게임 모두, 두 mutual_agreement.sha256 값, 그리고 각 창의 github_commit 쌍이 모두 일치했습니다. 상대의 보고서와 일치하는 보고서만이 규칙 33-35에 따라 무효화될 수 없는 유일한 종류이며, 이는 스코어라인보다 우리에게 더 가치가 있습니다.
목차
학술 보고서: 모델 · 오케스트레이션 딜레마 · 전략 · 낯선 상대와 테스트하며 배운 것
Related MCP server: Police MCP Server
설치
요구 사항
Python | 3.12+ (uv로 관리됨 - 사전 설치 불필요) |
여기서 사용하는 유일한 패키지 관리자 (가이드라인 §8.4) | |
OS | Linux, macOS, 또는 WSL2를 통한 Windows - WSL2에서 개발됨 |
선택 사항 | 공개 터널용 |
git clone https://github.com/najikay/pursuit-cop-agent.git
cd pursuit-cop-agent
uv sync # installs the locked dependency set
uv run python scripts/check_all.py # every CI gate, one PASS/FAIL verdictcheck_all.py 통과는 설치가 정상임을 의미합니다: 린트, 파일 크기 제한, 저장소 규칙, 타입 검사 및 전체 테스트 스위트.
비밀 정보 - .env-example을 .env로 복사하고 실제 값을 입력하세요. 비밀 정보는 절대 커밋되지 않습니다. .gitignore는 .env, secrets/, token.json, credentials.json을 포함하며, CI 게이트는 하나라도 추적되면 빌드를 실패시킵니다(책 규칙 39-40).
cp .env-example .env # then edit: ANTHROPIC_API_KEY, DEEPSEEK_API_KEY, …문제 해결
증상 | 원인 및 해결 방법 |
| 다른 에이전트가 실행 중입니다. 중지하거나 |
| 정상입니다: MCP 스택을 가져오는 중입니다. 실제 준비되면 |
상대가 우리를 연결 불가로 보고함 | 터널을 확인하세요: |
| 저장소 루트에서 실행하세요. 콘솔 스크립트는 이 저장소의 |
OAuth 브라우저가 열리지 않음(WSL) | 예상된 동작입니다 - WSL에는 기본 브라우저가 없습니다. |
| Windows 마운트 파일 시스템은 WSL에서 느립니다. 이벤트 로그가 정확히 이 이유로 핸들을 열어두고 있습니다. 가능하면 작업 공간을 Linux 파일 시스템에 두세요. |
명령줄
저장소당 하나의 콘솔 스크립트(여기서는 najamjad-cop, 동반 저장소에서는 najamjad-thief). 모든 동사는 인수 파싱과 단일 SDK 호출입니다 - CLI에는 게임 로직이 없으며, 메타 테스트가 이를 유지합니다.
uv run najamjad-cop --help # every verb
uv run najamjad-cop version # code version (book rule 53)
uv run najamjad-cop preflight # match-day checklist
uv run najamjad-cop peer # serve: MCP server + tunnel + dashboard
uv run najamjad-cop match # serve, then play the agreed series
uv run najamjad-cop peer --no-tunnel --no-dashboard # local play, nothing exposed
# Re-hash every step of a log and print the verdict. Paths are literal -
# `<log>` would be read by the shell as a redirect, so use a real one:
uv run najamjad-cop replay tests/goldens/artifacts/log_segal-police-team-vs-segal-thief-team_g01.json
uv run najamjad-cop replay path/to/log.json --serve # open the viewer instead
uv run najamjad-cop archive match.zip # bundle evidence (secrets excluded)종료 코드 - 스크립트에서 실행되므로:
코드 | 의미 | 예시 |
| 작동함 | preflight 준비됨, 로그 검증됨 |
| 실행됐지만 답이 나쁨 | 경기 준비 안 됨, 로그 변조됨 |
| 실행할 수 없음 | 로그 파일 없음 또는 읽을 수 없음 |
변조된 로그와 누락된 파일은 의도적으로 다른 코드입니다: 감사 결과가 오타로 오인되어서는 안 됩니다.
개발 명령
uv run python scripts/check_all.py # all CI gates, one verdict
uv run python scripts/self_play.py --games 100 # measure our brains vs baselines
uv run python scripts/demo_dashboard.py # dashboard over a played game
uv run python scripts/two_process_match.py # both repos as real processes
uv run python scripts/sync_core.py ../pursuit-thief-agent # verify the mirrored core실행
아래 모든 것은 상대도 API 키도 없는 새 클론에서 작동합니다. 에이전트는 템플릿만으로 전체 감사 시리즈를 플레이합니다(책 PAGE 67) - LLM은 향상 기능이지 의존성이 아닙니다.
1. 설치 및 설치 검증
git clone https://github.com/najikay/pursuit-cop-agent.git
cd pursuit-cop-agent
uv sync # locked dependency set
uv run python scripts/check_all.py # every CI gate, one verdictALL GATES PASSED는 린트, 파일 크기, 저장소 규칙, 타입, 전략 스위트 및 1,900개 이상의 테스트가 모두 통과했음을 의미합니다.
2. 대시보드와 함께 피어로 서빙
uv run najamjad-cop peer --dashboard --no-tunnelUvicorn running을 기다리세요 - 첫 번째 로그 줄이 아니라 이것이 준비 상태입니다. 콜드 스타트는 ~15초(MCP 스택 가져오기)이므로 경기일에는 일찍 시작하세요.
그런 다음 http://127.0.0.1:8000/ 을 여세요.
포트와 호스트는 config/setup.json(ui.port, ui.host)에서 가져옵니다. 의도적으로 루프백에 바인딩됩니다: 대시보드는 우리의 신념과 우리의 봉인 상태를 보여주므로, 노출하면 커밋-리빌이 숨기려는 모든 것을 상대에게 넘겨주게 됩니다(규칙 8-9).
제공되는 것:
패널 | 표시 내용 |
보드 | 로그 스케일의 신념 히트맵 - 선형으로 48개 셀 중 47개가 하나의 밴드로 축소됨 |
턴 배너 | 누구의 차례인지, 어떤 단계인지, 어떤 페이즈인지 |
대화 | 들어오고 나가는 모든 힌트와 그것을 작성한 모델 |
협상 | 제안 → 반대 제안 → 잠금, 그리고 인간의 승인을 기다리는 조건 |
예산 | 합의된 200k 캡 대비 토큰 |
경기일 | 준비 상태 - |
테스트 | 연습 모드 및 각 엔드포인트가 응답하는지 여부 |
경기 | 제출한 모든 경기: 점수, 게임별 감사 판정, 아티팩트 |
이벤트 | 원시 이벤트 스트림 |
업데이트는 WebSocket을 통해 도착하며 클라이언트는 폴링하지 않습니다. 대시보드 오류는 게임에 영향을 줄 수 없습니다 - 구독자일 뿐입니다(ADR-005).
선택적 제어. config/setup.json에서 features.controls를 true로 설정하면 페이지에서 시작/중지, 협상 승인, 연습 모드 토글을 활성화할 수 있습니다. 기본적으로 꺼져 있으며, 카운트 경기를 플레이하는 버튼은 의도적으로 없습니다 - 이는 채점되고 되돌릴 수 없으며, docs/RUNBOOK.md가 그 인터페이스입니다.
2b. 강의자에게 연락하지 않고 테스트
테스트 패널은 그렇지 않으면 로그를 뒤져야 하는 두 가지 질문에 답합니다.
지금 어떤 모드인가? 연습 모드는 모든 보고서를 강의자 대신 자신의 받은 편지함으로 리디렉션하고 제목에 [PRACTICE]를 접두사로 붙입니다. 전송을 건너뛰지 않습니다 - 전송은 과제 6에서 경기를 잃은 단계이므로 연습 실행은 실제로 전송을 수행하고 실제 이메일을 읽습니다. 리디렉션은 두 번 강제됩니다: 주소가 다시 작성되고, 돌아올 수 없는 지점에서 다시 확인되므로, 조용히 실패한 재작성은 전달 대신 예외를 발생시킵니다. docs/CONFIG.md §3b 참조.
가장 간단한 방법은 플래그입니다 - 한 프로세스에 대해 연습을 준비하고 다른 것은 건드리지 않습니다:
uv run najamjad-cop match --opponent amjad --practice --dashboard --tunnel또는 패널에서 토글(features.controls 켜짐)하거나 config/setup.json의 practice.enabled를 설정하여 지속시킬 수 있습니다. 보고서가 작성될 때마다 새로 읽히므로 재시작 없이 전환이 적용되며, email.mode를 send로 재정의합니다 - 조용히 초안을 생성한 연습 실행은 성공적인 전송과 똑같이 보일 수 있기 때문입니다.
실제로 연결 가능한 사람이 있는가? 프로브 엔드포인트는 우리 MCP URL과 상대의 URL을 다이얼하고 두 가지가 아닌 세 가지 상태를 보고합니다:
상태 | 의미 |
초록 | 거기서 TCP 연결을 수락한 무언가가 있음 |
빨강 | 구성되었지만 아무것도 수신하지 않음 - 경기를 막음 |
회색 | 아직 구성되지 않음 - 경기가 예약되지 않음, 오류 아님 |
초록 불은 포트가 응답했음을 의미합니다. 프로토콜이 작동하거나 그들이 우리 조건에 동의할 것이라는 뜻은 아닙니다 - 그것은 핸드셰이크의 몫이며, 패널은 확인할 수 있는 것 이상을 주장하지 않습니다.
3. 플레이 준비 확인
uv run najamjad-cop preflight # exit 0 or do not play
uv run python scripts/pre_match_smoke.py # MATCH READY in ~50 s4. 플레이
상대 카드를 한 번 작성한 다음 이름을 지정하세요. opponents/<name>.toml은 그들에게서 오는 두 가지 사실을 담습니다 - 그들의 MCP 엔드포인트와 핸드셰이크가 선언하는 group_id:
url = "https://their-agent.example.com/mcp"
group_id = "their-group"
name = "Their Team"
notes = "quick tunnel - URL changes if cloudflared restarts"opponents/_template.toml을 복사하여 시작하세요. 그런 다음 모든 동사는 --opponent를 받습니다:
uv run najamjad-cop preflight --opponent amjad
uv run najamjad-cop match --opponent amjad --dashboard --no-tunnel추적되는 어떤 것도 편집할 필요가 없고, 마지막 상대의 설정이 다음 상대에 의해 덮어쓰이지 않으며, opponent_group_id - 핸드셰이크에서 선언한 것과 같아야 하며, 그렇지 않으면 보고서가 그들의 이름 대신 자리 표시자로 키가 지정됩니다 - 는 핸드셰이크에서 발견되는 대신 하루 전에 검토할 수 있습니다.
카드는 network.opponent_*만 설정할 수 있습니다. 게임 용어는 서명된 config/game.json에서 합의되며, 상대방별 재정의는 절대 쉬워서는 안 되는 바로 그 것입니다.
또는 config/police/game.toml에서 network.opponent_url을 직접 설정한 후:
uv run najamjad-cop match --dashboard --no-tunnel완료된 경기는 부록 F에 따라 workspace/artifacts/에 선언, 설정, 로그, 결과의 네 가지 산출물을 기록하고 결과를 이메일로 보냅니다. 다음으로 확인하세요:
uv run python scripts/post_match.py --opponent <name>5. 상대방 없이 시도하기
두 가지 방법, 둘 다 실제입니다:
# our cop against our thief, two OS processes over real MCP/HTTP
uv run python scripts/two_process_match.py
# against the course reference simulator (expects ../reference-sim)
uv run python scripts/rehearsal.py --games 6두 번째가 중요한 방법입니다 - 우리의 상호운용성 결함을 잡아낸 유일한 설정이며, 우리가 작성하지 않은 유일한 상대방이기 때문입니다.
6. 로그 검증
uv run najamjad-cop replay workspace/artifacts/log_<game_id>_g01.json종료 코드 0은 Verified OK이고, 1은 TAMPERED이며 실패한 단계를 명시합니다. 2는 파일을 읽을 수 없음을 의미합니다. 변조된 로그와 오타는 의도적으로 다른 코드입니다 - 감사 판정이 경로 오타로 오인되어서는 안 됩니다.
--serve를 추가하면 판정을 출력하는 대신 뷰어를 엽니다.
7. 측정
uv run python scripts/strategy_smoke.py --games 50 # win rates with intervals
uv run python scripts/sweep.py --games 24 # parameter sensitivity
uv run python scripts/measure_tokens.py # token census결과는 results/에 저장되며 notebooks/analysis.ipynb가 그래프로 표시하는 대상입니다.
경기 당일 워크플로
정확한 명령어가 포함된 전체 절차는 docs/RUNBOOK.md에 있습니다. 개요:
워밍업 - 에이전트를 일찍 시작하세요. 콜드 스타트는 약 15초입니다.
사전 점검 -
uv run najamjad-cop preflight실행. 종료 코드 0이 아니면 경기를 하지 마세요.URL 교환 -
config/police/game.toml에서network.opponent_url설정.경기 -
uv run najamjad-cop match, 대시보드는 http://127.0.0.1:8000/.감사 - 미니 게임별 자동 수행. 모든 게임은
Verified OK를 읽어야 합니다.보고 - 상대방과 대조한 후 전송 (규칙 30:
gmail.send만 사용).보관 -
uv run najamjad-cop archive match.zip(비밀 제외).
설정
파일 | 역할 |
| 공유, 서명된 조건. 양쪽 피어는 바이트 단위로 동일한 사본을 보유해야 하며, 불일치 시 핸드셰이크가 경기 시작을 거부합니다. 우리의 것은 개시 제안입니다 - 모든 값이 부록 F 최소값 이상입니다 (규칙 12: 낮추지 말고 올리기). |
| 비공개, 로컬 전용. 우리의 포트, 상대방 URL, 터널 호스트명, LLM 선택, 신념 조정. 네트워크를 통해 전송되지 않습니다. |
| 서비스별 제한기 설정. 로드 시 부록 F 상한에 대해 검증됩니다. |
| 비밀만 포함. 절대 커밋하지 않습니다. |
알아두면 좋은 매개변수:
키 | 효과 |
| 우리의 MCP 포트 (경찰 8802 / 도둑 8801, 둘 다 로컬에서 실행). |
| 상대방에 대해 우리가 아는 유일한 정보. 비어 있으면 사전 점검이 실패합니다. |
| 영구 공개 이름. 명명된 터널은 재시작 후에도 URL을 유지합니다 - 과제 6에서 가장 많은 시간을 소모한 결함 (ADR-004). |
| 힌트 주기. 절약 다이얼이 아닌 품질 다이얼 - |
| 거짓말일 수 있는 힌트에 대해 냄새를 얼마나 신뢰할지. |
| 합의된 규칙. 일방적으로 변경하면 서명이 깨집니다. |
대시보드
--dashboard로 시작하고 http://127.0.0.1:8000/을 여세요 - 패널과 선택적 컨트롤은 실행하기 §2를 참조하세요.
신념 히트맵, 턴 배너, 메시지별 모델 출처가 포함된 대화, 협상 타임라인, 토큰 예산, 보고 전송 상태 - WebSocket으로 푸시되며 폴링되지 않습니다. 로컬 진실만 표시합니다 (규칙 8-9): 상대방의 위치는 읽기 모델에 필드가 없으며, 메타 테스트가 UI가 SDK를 통해서만 에이전트에 도달할 수 있음을 강제합니다.

리플레이 뷰어
모든 단계는 공개된 (payload, nonce)에서 다시 해시되어 저장된 커밋먼트와 비교됩니다 (규칙 20). 아래는 강사의 샘플 로그가 깨끗하게 리플레이되는 모습입니다:

그리고 같은 로그에서 하나의 레코드가 사후에 편집된 경우 - 위조가 심어진 정확히 그 단계에 국한되며, 규칙 19에 따라 게임이 무효화됩니다:

각 이미지가 어떻게 재현되는지는 assets/README.md를 참조하세요.
학술 보고서
모델: 어느 쪽도 볼 수 없는 Dec-POMDP
이 게임은 분산형 부분 관측 마르코프 결정 과정입니다. 어느 에이전트도 실제 상태를 관측하지 못합니다: 위치는 게임 종료 감사까지 커밋먼트 안에 봉인되어 있으므로, 각 피어는 상대방이 어디에 있을지에 대한 신념을 보유하고 그에 따라 행동합니다.
반대되는 신뢰 속성을 가진 두 가지 관측 채널:
냄새 - 상대방이 비자발적으로 방출하고 위조할 수 없는 감쇠 페로몬 흔적 (책 PAGE 22). 위조 불가하지만 흐릿합니다.
두 가지 모델이 제공되며 경기별로 선택할 수 있습니다. 책 (PAGE 43-44)은 방사형 - 0.90 / 0.62 / 0.42 / 0.20 / 0.14 / 0.04 - 상대 감쇠
τ ← (1-ρ)·τ를 사용합니다. 참조 시뮬레이터는 체비쇼프 거리의 선형 - 링 0.90 / 0.60 / 0.30 - 절대 감쇠τ ← τ - ρ를 사용합니다. 우리는 둘 다 구현하며, 둘 다 상호운용성 키트에 등록되어 있습니다:ScentModel.BOOK는multiplicative_book_v1(934c220d…)이고ScentModel.REFERENCE는subtractive_chebyshev_v1(81ebee59…)입니다. 각각 키트 자체의 공개 벡터를 재현합니다 - 키트의field_walk가 이전 흔적을 노화시키고, 새 퇴적물을 감쇠 없이 병합하고, 그것을 전송으로 고정하는 와이어의 서빙 순서를 포함합니다: 우리의 도둑은 2026-08-22까지 흔적을 한 단계 너무 신선하게 전송했고, 상대방의 프레임별 게이트가 이를 측정했으며, 프레임은 이제 walk와 셀 단위로 고정되었습니다 (test_wire_scent_serve_order.py). 따라서 상대방과 일치시키는 것은 하나의 키 -config/game.json의pheromones.pheromone_model- 이며, 14개의 서명된 조건을 변경하는 것이 아니므로, 계약 다이제스트a284082d…는 전환 후에도 유지되고 누구도 다시 서명할 필요가 없습니다. 협상 시 선언하는 다이제스트는 구성된 모델 에서 조회되므로, 하나의 물리 법칙을 방출하면서 다른 것을 주장하는 상태는 존재하지 않습니다. 방출은 힌트와 별도로 조정됩니다 ---scent full|window|none및--hints/--no-hints- 완전히 조용한 시리즈는 플래그 하나입니다. 침묵 상태에서는 모델을 전혀 선언하지 않습니다. 아무도 보내지 않는 필드에 대한 주장은 할 가치가 있는 주장이 아니기 때문입니다.힌트 - 자유 자연어로, 규칙이 명시적으로 거짓말을 허용합니다 (규칙 26-27). 정확하지만 신뢰할 수 없습니다.
우리의 신념 엔진은 이를 융합합니다: 이동을 위한 확산, 냄새 우도 업데이트, 그리고 힌트가 흔적과 일치하거나 불일치함에 따라 오르내리는 상대방별 신뢰도 가중치. 전체 유도 과정은 docs/PRD_belief_engine.md에 있습니다.
구축 과정에서 얻은 세 가지 발견, 각각 설계를 변경했습니다:
냄새 감쇠에 고정점이 있었습니다. 소수점 셋째 자리로 반올림된 상대 감쇠는 결코 0에 도달하지 않아, 죽은 흔적이 신념을 영원히 오염시켰습니다. 명시적 엡실론으로 수정했습니다.
곱셈 융합이 누적 냄새 필드를 이중 계산하여 이동하는 상대에 대해 신념이 약 5셀 뒤처졌습니다. 강건한 혼합 업데이트로 대체했습니다.
평평한 우도가 신념을 흔적 중간에 정지시켰습니다. 샤프닝과 가산적 하한이 이를 수정했습니다. 클램프는 희미한 냄새를 없음과 구별할 수 없게 만들었습니다.
오케스트레이션 딜레마
하나의 게이트웨이, 아니면 여러 호출자? 규칙 3은 오케스트레이터를 요구하며 우리는 문자 그대로 따랐습니다: 주변 모듈은 서로 호출하지 않습니다. 신념 엔진은 전송에 대해 알지 못하고, 전략은 암호화에 대해 알지 못하며, 전송은 규칙에 대해 알지 못합니다. 이것이 전체 턴 루프를 페이크에 대해 테스트 가능하게 만드는 이유입니다 - 과제 6이 결코 가지지 못한 분리 지점입니다.
페이크를 얼마나 신뢰할까. 우리의 가장 날카로운 교훈입니다. 세 가지 별개의 결함이 1,500개의 통과 테스트를 통과했습니다. 페이크가 와이어보다 관대했기 때문입니다: 실제 전송이 하지 않는 감사 페이로드를 감싼 페이크 전송, 결코 차단되지 않은 인메모리 링크, 그리고 오직 자기 자신과만 경기한 피어들. 상호운용성은 당신이 작성하지 않은 무언가에 대해서만 테스트할 수 있습니다.
마감을 어디에 둘까. 영원히 응답하는 피어는 결정된 게임에서 우리를 붙잡아서는 안 되며, 조용해지는 피어가 우리의 기술적 패배가 되어서는 안 됩니다. 모든 대기는 제한되어 있고 모든 종료는 추정이 아닌 선언됩니다 - 아래 참조.
우리 자신의 프로토콜에 대한 속도 제한. 게이트키퍼는 Anthropic과 Gmail에 대한 좋은 시민이 되기 위해 존재합니다. 이를 상대방에게 적용하는 것은 거의 게임을 잃을 뻔했습니다: 우리 자신의 제한기가 응답을 상대방의 30초 마감을 넘기도록 지연시킬 수 있었습니다.
전략, 그리고 왜 RL이 아닌가
경찰 - 턴별 점수가 아닌 스크립트된 반분 봉쇄 (strategy/seal_cop.py): 중앙 열을 벽으로 막으면서 옆 레인을 따라 이동하고, 게이트를 차지하고, 도둑이 있는 절반을 절단하면 도둑은 우리와 함께 3×3 주머니에 갇힙니다. 거기서부터 domain/endgame.py가 주머니를 정확히 해결합니다 - 장애물 배치는 게임 트리의 이동입니다 - 그리고 모든 승리를 동일 위치로 평가합니다. 밟기 주장은 모든 구현이 존중하는 유일한 포획이기 때문입니다. 우리가 결코 걸어갈 수 없는 곳에 봉인된 도둑은 우리 자신의 벤치에서 remote seal로 점수화되고 계획으로 거부됩니다. 단일 장애물 잠금 (strategy/lock.py: 우리 몸 + 벽 하나, 인접성 필요)은 고정된 도둑을 일찍 끝냅니다. 벤치 (tests/regression/)는 반응하는 적들 - 스크립트 자신의 벽 라인에 웅크리는 도둑을 포함 - 에 대해 이를 구동하며, 35수 안에 모두 일반적인 주장 가능한 포획으로 전환합니다 (test_seal_converts_every_reacting_thief.py). 신념 기반 추적 (cop_brain.py)은 위치 파악이 없는 보드의 폴백으로 남아 있습니다.
도둑 - 탐욕적 거리 최대화가 아닌, 단단한 하한의 스택으로서의 생존 지평 회피: 경찰로부터 한 걸음 이내에서 턴을 끝내지 말 것, 반쯤 지어진 울타리가 이미 봉쇄하기 싸게 만든 셀을 거부할 것, 도달 가능한 4×4를 유지할 것, 형성 중인 절단선의 경찰 쪽에 머물 것 (봉쇄자는 우리와 분리시키는 벽을 완성할 수 없음), 그리고 건설 중인 울타리의 틈에 설 것 - 이 선호는 안전 하한 이후에 실행됩니다. 왜냐하면 그 전에 실행하면 한때 우리를 상대방이 벽으로 막은 구석으로 몰아넣었기 때문입니다 (test_ahk_yosi_corner_hunt.py가 그 킬 라인을 수 단위로 리플레이합니다). matches/의 모든 보관된 상대방 라인과 반응하는 코너 사냥꾼 경찰의 24가지 타이브레이크 변형 모두에서 생존합니다.
힌트 정책 - 허세는 비용이 있는 전략적 자원입니다: 주장은 주장자의 셀을 공개하므로, 거짓 포획 주장은 도둑에게 우리의 정확한 위치를 대가 없이 넘겨줍니다.
강화 학습 없음, 의도적으로:
리그 전체에서 실제 게임은 겨우 ~60개뿐이다. 이 정도 규모의 상태 공간에서 정책을 학습하기에는 턱없이 부족하다.
상대 행동은 비고정적이다. 팀마다 서로 다른 것을 내놓는다.
비결정성은 리플레이를 깨뜨린다. 그런데 리플레이는 채점 대상 산출물이다.
휴리스틱은 이미 기준선을 결정적으로 이긴다(아래 참조). 따라서 RL은 측정된 이득 없이 위험만 감수하는 것이 된다.
대신 우리는 시리즈가 실제로 제공하는 ~210개의 관측치에 맞춘 온라인 상대 모델링을 사용한다. 힌트 신뢰도, 이동 성향, 장벽 대응이다.
측정은 실제 경기 시스템을 통해 홀드아웃 게임에서 수행했다. 시드 11, 튜닝 중에는 사용한 적 없음, 매치업당 60게임이다.
대진 | 캡처 | 비율 | 95 % 윌슨 CI |
우리 경찰 vs 탐욕 도둑 | 60/60 | 100 % | 94–100 % |
탐욕 경찰 vs 우리 도둑 | 0/60 | 0 % (100 % 생존) | 0–6 % |
탐욕 vs 탐욕 (기준) | 4/60 | 6.7 % | 2.6–16 % |
180개 게임 전체에서 피어 간 불일치 0건, 감사 실패 0건이었다.

단 하나의 튜너블이 경기를 결정하며, 그것은 우리가 예상했던 값이 아니다.

barrier_threshold는 캡처율을 그 범위 전체에 걸쳐 **4 %에서 100 %**까지 흔든다. 장벽은 양쪽 모두에게 통과 불가다. 따라서 약한 증거로 벽을 치는 경찰은 쫓고 있는 도둑으로부터 스스로를 가둬 버린다. 우리는 몇 주 동안 0.15를 적용했고, 그 대가로 대략 게임의 3분의 1을 잃었다. lookahead는 진정한 무효과 결과다. 깊이 1~4는 바이트 단위로 동일한 게임을 만들기 때문이다. 등방성 확산 커널이 분리하려는 후보 수들의 순위를 그대로 유지하기 때문이다.
우리가 반드시 밝혀야 할 주의사항. 우리 도둑은 지금까지 마주했거나 아카이브에 저장한 모든 경찰을 상대로 살아남는다. 그럼에도 여전히, 대략 30번째 스텝에서, **우리 자신의 실러(sealer)**에게 진다. 그의 반분 계획은 어떤 상대도 보여준 적 없다. 두 방향 모두 모호하게 덮지 않고 명확히 고정했다(test_thief_beats_sealing_cops.py는 패배와 그 대가를 기록하고, corner-hunt 및 아카이브 스위트는 생존을 기록한다). 자신이 이기는 경찰만 상대로 평가된 도둑은 결국 자기 자신을 상대로 평가된 것이기 때문이다.
전체 유도 과정, 신뢰 구간, 토큰 비용 표와 참고 문헌은 **notebooks/analysis.ipynb**에 있다. 다음으로 재현한다.
uv run python scripts/baselines.py --games 60 --seed 11 # held-out comparison
uv run python scripts/sweep.py --games 24 --seed 7 # sensitivity sweeps
uv run python scripts/measure_tokens.py # token census낯선 상대와의 테스트가 가르쳐 준 것
우리는 과정 레퍼런스 시레이터를 복제해 우리 자신을 겨냥했다. 어는 방향으로도 아무것도 작동하지 않았다. 레퍼런스는 세 개의 도구에서 MCP 도구 인자의 이름을 message로, 한 개에서 payload로 정한다. 우리는 네 개 모드에 payload를 보냈고 payload만 받아들였다. 모드 과 모드 제안은 게임 로직이 한 바이트도 실향되기 전에 인자 바인딩에서 거부되었다. 레퍼런스를 기반으로 만들은, 즉 수업의 대부을 차지하는 모드 에이전트와의 대결에서 말이다.
네 가지 비호환성이 더 뒤따았다. 우리가 보내지 않았던 필수 timestamp, 그들의 파서가 아예 거부하는 claimed_cell 필드, 그리고 타입이 서로 달랐던 세 개의 클레임 필드. 그리고 감사 reveal은 스키마가 봉투(envelope)를 선언하는 자리에서 단순 리스트로 전송된 것으로 드러났다. 그래서 아무도 속임수를 쓰지 않은 게임들에서 양쪽 피어 모드 TAMPERED를 기록했다.
그 모드 것은 우리 자체 테스트를 통과했다. 반면 커밋-리빌 코어는 접측에도 불구하고 변경 업이 살아남았다. 우리의 commit_of는 레퍼런스의 시그니처를 바이트 단위로 재현한다.
어는 분산 프로젝트에든 가질 교훈: 초록불 테스트 스위트는 당신의 코드가 당신의 가정과 일측함을 증명할 뿐, 당신의 가정이 옳다는 것을 증명하지 않는다.
문소
문소 | 목적 |
| 제품 요구사항(FR-* ID, KPI, 마일스톤) |
| 아키텍처: C4 + FSM 다이그램, ADR-001..021, 모듈 맵 |
| 추저 가능성과 진행 상황을 포할한 688개 작업 빌드 계획 |
| 현재 상테, 미해결 항목, 그리고 측정된 모드 수정 사항 |
| 무엇이 통신선을 통해 전송되고, 무엇이 절대 전송되지 않는다 |
| 위협 모델, 프롬프트 인젝션 방어, 비밀 처리 |
| Nielsen 리스틱을 대시보드 결정에 매핑; 접근성 |
| 네 가지 확장 지점과 동작하는 플러그인 예제 |
| 모드 설정 키, 해당 파일, 부록 F에서의 협상 가능성 |
| 각 게이트가 검사하는 내영과 실패 재현 방법 |
| 관례: 코어 동기화, 커밋, 테스트, 경기일 동결 |
| ISO/IEC 25010 품질 특성을 증거에 매핑 |
| 처된 모드 경계 조건, 각각 해당 테스트와 연결 |
| 측정된 토큰 소비량과 비용 모델 |
| 불완전한 것으로 알려진 사항과 그 증거 |
| 민감도 분석, 기준선, 비용 표, 참고 문헌 |
| 메커니즘 설계 |
| 널 및 연결 절차 |
| 소스 다이제스트(책, 가이드라인, 레퍼런스 시레이터, A6 회고) |
상대 감사
커밋-리빌은 피어가 기록을 다시 쓰지 않았음을 증명한다. 그들이 규칙대로 플에이했는지에 대해서는 아무것도 증명하지 않으며, 이 둘은 서로 다은 보장이다. 우리는 리그 전제 단계에서 이 둘을 혼동했고, 시리즈에서 진 후 그 플에이가 합법적이었는지 말할 수 없었다.
감사는 **설계상 경기 후(post-match)**다. 규칙 33-35는 모순된 보고가 있으면 경기를 무효로 한다. 따라서 자신의 고발에 따라 행동하는 에이전트는 의심을 상호 0점으로 바어 버린다. 아레의 모드 내영은 증거를 기록할 뿐 우리의 플에이 방식을 바꾸지 않는다(PLAN ADR-019).
# replay their revealed records through the fair-play rules: movement legality,
# the Barrier Law, the budget, step order, hint length - and say what it could NOT check
uv run python scripts/audit_opponent.py --team vibecode
# are we disclosing scent on the same terms they are?
uv run python scripts/scent_parity.py --since 2026-08-14T16:00 # UTC
# 323 of 323 sealed capture claims name the claimer's own revealed cell
uv run python scripts/claim_evidence.py
# both repos must declare the same counted-match count (rules 37-38)
uv run python scripts/reconcile_counted.py ../pursuit-thief-agent --apply리빌이 해결할 수 있는 것과 오직 통신선만이 해결할 수 있는 것: 피어의 봉인된 기록에는 그 피어가 봉인하기로 선택한 것만 담긴다. 이동과 장벽은 아카이브만으로도 확인할 수 있다. smell_grid, capture_claim, hint, 응답 시간은 오직 통신선을 통해 도착한 것과 대조해야만 확인할 수 있다. 이것이 FrameLog가 그것들을 전송된 그대로 보관하는 이유다. 감사는 그것들을 깄끝한 판정에 포할하는 대신 확인 불가로 보고한다. "우리는 살펴고 동의했다"와 "살펴볼 것이 없었다"는 결코 같게 읽혀서는 안 된다.
모드 전략을 제악하는 세 가지 결과
모두 리그 단계에서 측정을 통해 확립되었으며, 모드 결정적인 근거다.
장벽은 보드를 줄일 수는 있지만 도둑을 결코 잡을 수 없다. 책은 세 가지 캡처 조건을 제시한다(규칙 46-47). 과정 레퍼런스는 정확히 하나만 구현한다. 그것의 rules.py에는 thief_result와 is_captured가 있고, 장벽 캡처나 무력화(immobilisation) 검사는 어디에도 없다. 우리가 만난 모드 상대는 레퍼런스에서 파생되었으므로, 포위는 우리가 점수를 얻고 그들은 얻지 못하는 미니게임을 만든다. 바로 규칙 33-35의 모순이다. 모드 캡처는 도둑이 확인하는 클레임이어야 한다(PLAN ADR-020).
경찰 한 명은 열린 보드에서 도둑을 잡을 수 없다. 7×7 그리드는 두 경로의 데카르트 곱이므로 그 경찰 수(cop number)는 2다(Maamoun & Meynel 1987). 그리고 모드 49×49 상테에 대한 완전한 고정점 계산은, 이동만 하는 경찰이 동시 이동 규칙에서 캡처를 강제할 수 있는 상테를 하나도 찾지 못한다. 우리 경찰이 도둑을 거리 2까지 추적하고 28스텝 동안 그 거리를 유지하는 것은 결함이 아니라 정리다. 답을 바꾸는 유일한 자원은 장벽이다(PLAN ADR-021).
그리고 계획이 있으면 장벽은 실측으로 답을 바다. 반분 봉인은 벤치가 만들 수 있는 모드 반응형 도둑을 잡아낸다. 보드를 반으로, 반을 다시 반으로, 3×3을 정확히 풀고, 35수 안에 동일 위치(co-location) 클레임으로 끝난다. 위의 두 제악은 여전히 그 승리의 형태를 규정한다. 그 승리는 도둑이 확인하는 클레임으로 끝나야 하며, 이동만으로는 얻을 수 없다. 오랫동안 여기에 우리의 가장 큰 경쟁 위험으로 기록되었던 것. 거리 2까지 추적하고 유지하는 경찰. 은 해결되었다. 남은 위험은 우리만큄 완전한 계획을 수형하는 경찰을 가진 상대이며, 도둑의 하한선(floor)은 정확히 그 경우에 맞춰 책정되어 있다.
tests/regression/cop_duel.py는 그러한 주장을 검증하는 경찰 측 벤치마크다. 실측 침입 경로가 냄새(scent)로부터 구측하는 신념(belief)을 가진 적응형 도둑을 상대하는 우리 경찰이다. 기록된 상대 라인은 반응하지 않으므로 포획 접근을 측정할 수 없다.
라이선스 및 출처 표시
MIT(LICENSE 참조). 프로토콜 형태와 산출물 스키마는 과정 레퍼런스 시뮬레이터 rmisegal/Game-P2P-Cop-Chase와 상호 운용된다(교육용 라이선스). 책과 코드가 충돌하면 책이 우선한다.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted MCP for Conductor Relay: a verifier-backed agent work exchange and cold marketplace.
Coordinate multiple AI agents over MCP: atomic claims, leases, shared ledger, handoffs, tasks.
Agent-native collaboration network: orchestrate a team of long-running agents from any MCP client.
Agent-native marketplace. Bootstrap, list inventory, search, negotiate, and trade via MCP.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables decentralized turn-based gameplay between thief and police agents in a peer-to-peer network, handling turn coordination, message passing, and protocol enforcement.
- FlicenseNot gradedqualityCmaintenanceEnables a police agent to autonomously chase a thief in a peer-to-peer grid game using FastMCP for turn-based communication and decentralized orchestration.
- FlicenseNot gradedqualityBmaintenanceImplements a distributed cops-and-robbers game agent as a FastMCP server, enabling peer-to-peer play with no central server. It manages turn-based moves, belief tracking, strategy selection, and secure protocol via SHA-256 commit-reveal.
- FlicenseNot gradedqualityBmaintenanceRuns a decentralized thief agent for a peer-to-peer cops-and-robbers game, using FastMCP to exchange moves and messages with a police agent while employing Bayesian belief and credibility-based bluffing strategies.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/najikay/pursuit-cop-agent'
If you have feedback or need assistance with the MCP directory API, please join our Discord server